commit a197de945629bb9ab6dd58a089b287c2ddfce197 Author: Christian Anetzberger Date: Thu Jan 22 20:23:51 2026 +0100 initial diff --git a/.venv/bin/Activate.ps1 b/.venv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/.venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/.venv/bin/activate b/.venv/bin/activate new file mode 100644 index 0000000..0524eb3 --- /dev/null +++ b/.venv/bin/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# You cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past locations. Without forgetting + # past locations the $PATH changes we made may not be respected. + # See "man bash" for more details. hash is usually a builtin of your shell + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +# on Windows, a path can contain colons and backslashes and has to be converted: +case "$(uname)" in + CYGWIN*|MSYS*|MINGW*) + # transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW + # and to /cygdrive/d/path/to/venv on Cygwin + VIRTUAL_ENV=$(cygpath /Users/christiananetzberger/development/stepanalyser_web/.venv) + export VIRTUAL_ENV + ;; + *) + # use the path as-is + export VIRTUAL_ENV=/Users/christiananetzberger/development/stepanalyser_web/.venv + ;; +esac + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/"bin":$PATH" +export PATH + +VIRTUAL_ENV_PROMPT='(.venv) ' +export VIRTUAL_ENV_PROMPT + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="("'(.venv) '") ${PS1:-}" + export PS1 +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/.venv/bin/activate.csh b/.venv/bin/activate.csh new file mode 100644 index 0000000..0254fe6 --- /dev/null +++ b/.venv/bin/activate.csh @@ -0,0 +1,27 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. + +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV /Users/christiananetzberger/development/stepanalyser_web/.venv + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/"bin":$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = '(.venv) '"$prompt" + setenv VIRTUAL_ENV_PROMPT '(.venv) ' +endif + +alias pydoc python -m pydoc + +rehash diff --git a/.venv/bin/activate.fish b/.venv/bin/activate.fish new file mode 100644 index 0000000..2f863ad --- /dev/null +++ b/.venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV /Users/christiananetzberger/development/stepanalyser_web/.venv + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/"bin $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) '(.venv) ' (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT '(.venv) ' +end diff --git a/.venv/bin/ezdxf b/.venv/bin/ezdxf new file mode 100755 index 0000000..de8272a --- /dev/null +++ b/.venv/bin/ezdxf @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from ezdxf.__main__ import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/f2py b/.venv/bin/f2py new file mode 100755 index 0000000..c9e2f46 --- /dev/null +++ b/.venv/bin/f2py @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from numpy.f2py.f2py2e import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/flask b/.venv/bin/flask new file mode 100755 index 0000000..dc33f94 --- /dev/null +++ b/.venv/bin/flask @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from flask.cli import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/fonttools b/.venv/bin/fonttools new file mode 100755 index 0000000..f24c739 --- /dev/null +++ b/.venv/bin/fonttools @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from fontTools.__main__ import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/numpy-config b/.venv/bin/numpy-config new file mode 100755 index 0000000..ee4465a --- /dev/null +++ b/.venv/bin/numpy-config @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from numpy._configtool import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/pip b/.venv/bin/pip new file mode 100755 index 0000000..52f5981 --- /dev/null +++ b/.venv/bin/pip @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/pip3 b/.venv/bin/pip3 new file mode 100755 index 0000000..52f5981 --- /dev/null +++ b/.venv/bin/pip3 @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/pip3.12 b/.venv/bin/pip3.12 new file mode 100755 index 0000000..52f5981 --- /dev/null +++ b/.venv/bin/pip3.12 @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/pyftmerge b/.venv/bin/pyftmerge new file mode 100755 index 0000000..73c166d --- /dev/null +++ b/.venv/bin/pyftmerge @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from fontTools.merge import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/pyftsubset b/.venv/bin/pyftsubset new file mode 100755 index 0000000..1ee3a7f --- /dev/null +++ b/.venv/bin/pyftsubset @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from fontTools.subset import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/bin/python b/.venv/bin/python new file mode 120000 index 0000000..11b9d88 --- /dev/null +++ b/.venv/bin/python @@ -0,0 +1 @@ +python3.12 \ No newline at end of file diff --git a/.venv/bin/python3 b/.venv/bin/python3 new file mode 120000 index 0000000..11b9d88 --- /dev/null +++ b/.venv/bin/python3 @@ -0,0 +1 @@ +python3.12 \ No newline at end of file diff --git a/.venv/bin/python3.12 b/.venv/bin/python3.12 new file mode 120000 index 0000000..a3f0508 --- /dev/null +++ b/.venv/bin/python3.12 @@ -0,0 +1 @@ +/opt/homebrew/opt/python@3.12/bin/python3.12 \ No newline at end of file diff --git a/.venv/bin/ttx b/.venv/bin/ttx new file mode 100755 index 0000000..b4d9a5e --- /dev/null +++ b/.venv/bin/ttx @@ -0,0 +1,7 @@ +#!/Users/christiananetzberger/development/stepanalyser_web/.venv/bin/python3.12 +import sys +from fontTools.ttx import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libXau.6.0.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libXau.6.0.0.dylib new file mode 100755 index 0000000..5b2714b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libXau.6.0.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlicommon.1.1.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlicommon.1.1.0.dylib new file mode 100755 index 0000000..e28ee69 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlicommon.1.1.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlidec.1.1.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlidec.1.1.0.dylib new file mode 100755 index 0000000..5fadd50 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libbrotlidec.1.1.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libfreetype.6.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libfreetype.6.dylib new file mode 100755 index 0000000..2eb1bc2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libfreetype.6.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libharfbuzz.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libharfbuzz.0.dylib new file mode 100755 index 0000000..94885ee Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libharfbuzz.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libjpeg.62.4.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libjpeg.62.4.0.dylib new file mode 100755 index 0000000..973498c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libjpeg.62.4.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblcms2.2.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblcms2.2.dylib new file mode 100755 index 0000000..2e1e7d3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblcms2.2.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblzma.5.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblzma.5.dylib new file mode 100755 index 0000000..301c32f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/liblzma.5.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libopenjp2.2.5.2.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libopenjp2.2.5.2.dylib new file mode 100755 index 0000000..f96b99d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libopenjp2.2.5.2.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libpng16.16.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libpng16.16.dylib new file mode 100755 index 0000000..76efc54 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libpng16.16.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libsharpyuv.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libsharpyuv.0.dylib new file mode 100755 index 0000000..8bd6ea5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libsharpyuv.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libtiff.6.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libtiff.6.dylib new file mode 100755 index 0000000..4456e99 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libtiff.6.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebp.7.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebp.7.dylib new file mode 100755 index 0000000..c237b33 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebp.7.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpdemux.2.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpdemux.2.dylib new file mode 100755 index 0000000..8b7f945 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpdemux.2.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpmux.3.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpmux.3.dylib new file mode 100755 index 0000000..5707189 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libwebpmux.3.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libxcb.1.1.0.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libxcb.1.1.0.dylib new file mode 100755 index 0000000..6e8a8a0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libxcb.1.1.0.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/.dylibs/libz.1.3.1.dylib b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libz.1.3.1.dylib new file mode 100755 index 0000000..8c7eec5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/.dylibs/libz.1.3.1.dylib differ diff --git a/.venv/lib/python3.12/site-packages/PIL/BdfFontFile.py b/.venv/lib/python3.12/site-packages/PIL/BdfFontFile.py new file mode 100644 index 0000000..bc1416c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/BdfFontFile.py @@ -0,0 +1,133 @@ +# +# The Python Imaging Library +# $Id$ +# +# bitmap distribution font (bdf) file parser +# +# history: +# 1996-05-16 fl created (as bdf2pil) +# 1997-08-25 fl converted to FontFile driver +# 2001-05-25 fl removed bogus __init__ call +# 2002-11-20 fl robustification (from Kevin Cazabon, Dmitry Vasiliev) +# 2003-04-22 fl more robustification (from Graham Dumpleton) +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1997-2003 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + +""" +Parse X Bitmap Distribution Format (BDF) +""" +from __future__ import annotations + +from typing import BinaryIO + +from . import FontFile, Image + +bdf_slant = { + "R": "Roman", + "I": "Italic", + "O": "Oblique", + "RI": "Reverse Italic", + "RO": "Reverse Oblique", + "OT": "Other", +} + +bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"} + + +def bdf_char( + f: BinaryIO, +) -> ( + tuple[ + str, + int, + tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]], + Image.Image, + ] + | None +): + # skip to STARTCHAR + while True: + s = f.readline() + if not s: + return None + if s[:9] == b"STARTCHAR": + break + id = s[9:].strip().decode("ascii") + + # load symbol properties + props = {} + while True: + s = f.readline() + if not s or s[:6] == b"BITMAP": + break + i = s.find(b" ") + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") + + # load bitmap + bitmap = bytearray() + while True: + s = f.readline() + if not s or s[:7] == b"ENDCHAR": + break + bitmap += s[:-1] + + # The word BBX + # followed by the width in x (BBw), height in y (BBh), + # and x and y displacement (BBxoff0, BByoff0) + # of the lower left corner from the origin of the character. + width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split()) + + # The word DWIDTH + # followed by the width in x and y of the character in device pixels. + dwx, dwy = (int(p) for p in props["DWIDTH"].split()) + + bbox = ( + (dwx, dwy), + (x_disp, -y_disp - height, width + x_disp, -y_disp), + (0, 0, width, height), + ) + + try: + im = Image.frombytes("1", (width, height), bitmap, "hex", "1") + except ValueError: + # deal with zero-width characters + im = Image.new("1", (width, height)) + + return id, int(props["ENCODING"]), bbox, im + + +class BdfFontFile(FontFile.FontFile): + """Font file plugin for the X11 BDF format.""" + + def __init__(self, fp: BinaryIO) -> None: + super().__init__() + + s = fp.readline() + if s[:13] != b"STARTFONT 2.1": + msg = "not a valid BDF file" + raise SyntaxError(msg) + + props = {} + comments = [] + + while True: + s = fp.readline() + if not s or s[:13] == b"ENDPROPERTIES": + break + i = s.find(b" ") + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") + if s[:i] in [b"COMMENT", b"COPYRIGHT"]: + if s.find(b"LogicalFontDescription") < 0: + comments.append(s[i + 1 : -1].decode("ascii")) + + while True: + c = bdf_char(fp) + if not c: + break + id, ch, (xy, dst, src), im = c + if 0 <= ch < len(self.glyph): + self.glyph[ch] = xy, dst, src, im diff --git a/.venv/lib/python3.12/site-packages/PIL/BlpImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/BlpImagePlugin.py new file mode 100644 index 0000000..b9cefaf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/BlpImagePlugin.py @@ -0,0 +1,488 @@ +""" +Blizzard Mipmap Format (.blp) +Jerome Leclanche + +The contents of this file are hereby released in the public domain (CC0) +Full text of the CC0 license: + https://creativecommons.org/publicdomain/zero/1.0/ + +BLP1 files, used mostly in Warcraft III, are not fully supported. +All types of BLP2 files used in World of Warcraft are supported. + +The BLP file structure consists of a header, up to 16 mipmaps of the +texture + +Texture sizes must be powers of two, though the two dimensions do +not have to be equal; 512x256 is valid, but 512x200 is not. +The first mipmap (mipmap #0) is the full size image; each subsequent +mipmap halves both dimensions. The final mipmap should be 1x1. + +BLP files come in many different flavours: +* JPEG-compressed (type == 0) - only supported for BLP1. +* RAW images (type == 1, encoding == 1). Each mipmap is stored as an + array of 8-bit values, one per pixel, left to right, top to bottom. + Each value is an index to the palette. +* DXT-compressed (type == 1, encoding == 2): +- DXT1 compression is used if alpha_encoding == 0. + - An additional alpha bit is used if alpha_depth == 1. + - DXT3 compression is used if alpha_encoding == 1. + - DXT5 compression is used if alpha_encoding == 7. +""" + +from __future__ import annotations + +import abc +import os +import struct +from enum import IntEnum +from io import BytesIO +from typing import IO + +from . import Image, ImageFile + + +class Format(IntEnum): + JPEG = 0 + + +class Encoding(IntEnum): + UNCOMPRESSED = 1 + DXT = 2 + UNCOMPRESSED_RAW_BGRA = 3 + + +class AlphaEncoding(IntEnum): + DXT1 = 0 + DXT3 = 1 + DXT5 = 7 + + +def unpack_565(i: int) -> tuple[int, int, int]: + return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3 + + +def decode_dxt1( + data: bytes, alpha: bool = False +) -> tuple[bytearray, bytearray, bytearray, bytearray]: + """ + input: one "row" of data (i.e. will produce 4*width pixels) + """ + + blocks = len(data) // 8 # number of blocks in row + ret = (bytearray(), bytearray(), bytearray(), bytearray()) + + for block_index in range(blocks): + # Decode next 8-byte block. + idx = block_index * 8 + color0, color1, bits = struct.unpack_from("> 2 + + a = 0xFF + if control == 0: + r, g, b = r0, g0, b0 + elif control == 1: + r, g, b = r1, g1, b1 + elif control == 2: + if color0 > color1: + r = (2 * r0 + r1) // 3 + g = (2 * g0 + g1) // 3 + b = (2 * b0 + b1) // 3 + else: + r = (r0 + r1) // 2 + g = (g0 + g1) // 2 + b = (b0 + b1) // 2 + elif control == 3: + if color0 > color1: + r = (2 * r1 + r0) // 3 + g = (2 * g1 + g0) // 3 + b = (2 * b1 + b0) // 3 + else: + r, g, b, a = 0, 0, 0, 0 + + if alpha: + ret[j].extend([r, g, b, a]) + else: + ret[j].extend([r, g, b]) + + return ret + + +def decode_dxt3(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]: + """ + input: one "row" of data (i.e. will produce 4*width pixels) + """ + + blocks = len(data) // 16 # number of blocks in row + ret = (bytearray(), bytearray(), bytearray(), bytearray()) + + for block_index in range(blocks): + idx = block_index * 16 + block = data[idx : idx + 16] + # Decode next 16-byte block. + bits = struct.unpack_from("<8B", block) + color0, color1 = struct.unpack_from(">= 4 + else: + high = True + a &= 0xF + a *= 17 # We get a value between 0 and 15 + + color_code = (code >> 2 * (4 * j + i)) & 0x03 + + if color_code == 0: + r, g, b = r0, g0, b0 + elif color_code == 1: + r, g, b = r1, g1, b1 + elif color_code == 2: + r = (2 * r0 + r1) // 3 + g = (2 * g0 + g1) // 3 + b = (2 * b0 + b1) // 3 + elif color_code == 3: + r = (2 * r1 + r0) // 3 + g = (2 * g1 + g0) // 3 + b = (2 * b1 + b0) // 3 + + ret[j].extend([r, g, b, a]) + + return ret + + +def decode_dxt5(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]: + """ + input: one "row" of data (i.e. will produce 4 * width pixels) + """ + + blocks = len(data) // 16 # number of blocks in row + ret = (bytearray(), bytearray(), bytearray(), bytearray()) + + for block_index in range(blocks): + idx = block_index * 16 + block = data[idx : idx + 16] + # Decode next 16-byte block. + a0, a1 = struct.unpack_from("> alphacode_index) & 0x07 + elif alphacode_index == 15: + alphacode = (alphacode2 >> 15) | ((alphacode1 << 1) & 0x06) + else: # alphacode_index >= 18 and alphacode_index <= 45 + alphacode = (alphacode1 >> (alphacode_index - 16)) & 0x07 + + if alphacode == 0: + a = a0 + elif alphacode == 1: + a = a1 + elif a0 > a1: + a = ((8 - alphacode) * a0 + (alphacode - 1) * a1) // 7 + elif alphacode == 6: + a = 0 + elif alphacode == 7: + a = 255 + else: + a = ((6 - alphacode) * a0 + (alphacode - 1) * a1) // 5 + + color_code = (code >> 2 * (4 * j + i)) & 0x03 + + if color_code == 0: + r, g, b = r0, g0, b0 + elif color_code == 1: + r, g, b = r1, g1, b1 + elif color_code == 2: + r = (2 * r0 + r1) // 3 + g = (2 * g0 + g1) // 3 + b = (2 * b0 + b1) // 3 + elif color_code == 3: + r = (2 * r1 + r0) // 3 + g = (2 * g1 + g0) // 3 + b = (2 * b1 + b0) // 3 + + ret[j].extend([r, g, b, a]) + + return ret + + +class BLPFormatError(NotImplementedError): + pass + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] in (b"BLP1", b"BLP2") + + +class BlpImageFile(ImageFile.ImageFile): + """ + Blizzard Mipmap Format + """ + + format = "BLP" + format_description = "Blizzard Mipmap Format" + + def _open(self) -> None: + self.magic = self.fp.read(4) + + self.fp.seek(5, os.SEEK_CUR) + (self._blp_alpha_depth,) = struct.unpack(" tuple[int, int]: + try: + self._read_blp_header() + self._load() + except struct.error as e: + msg = "Truncated BLP file" + raise OSError(msg) from e + return -1, 0 + + @abc.abstractmethod + def _load(self) -> None: + pass + + def _read_blp_header(self) -> None: + assert self.fd is not None + self.fd.seek(4) + (self._blp_compression,) = struct.unpack(" bytes: + return ImageFile._safe_read(self.fd, length) + + def _read_palette(self) -> list[tuple[int, int, int, int]]: + ret = [] + for i in range(256): + try: + b, g, r, a = struct.unpack("<4B", self._safe_read(4)) + except struct.error: + break + ret.append((b, g, r, a)) + return ret + + def _read_bgra(self, palette: list[tuple[int, int, int, int]]) -> bytearray: + data = bytearray() + _data = BytesIO(self._safe_read(self._blp_lengths[0])) + while True: + try: + (offset,) = struct.unpack(" None: + if self._blp_compression == Format.JPEG: + self._decode_jpeg_stream() + + elif self._blp_compression == 1: + if self._blp_encoding in (4, 5): + palette = self._read_palette() + data = self._read_bgra(palette) + self.set_as_raw(data) + else: + msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}" + raise BLPFormatError(msg) + else: + msg = f"Unsupported BLP compression {repr(self._blp_encoding)}" + raise BLPFormatError(msg) + + def _decode_jpeg_stream(self) -> None: + from .JpegImagePlugin import JpegImageFile + + (jpeg_header_size,) = struct.unpack(" None: + palette = self._read_palette() + + assert self.fd is not None + self.fd.seek(self._blp_offsets[0]) + + if self._blp_compression == 1: + # Uncompressed or DirectX compression + + if self._blp_encoding == Encoding.UNCOMPRESSED: + data = self._read_bgra(palette) + + elif self._blp_encoding == Encoding.DXT: + data = bytearray() + if self._blp_alpha_encoding == AlphaEncoding.DXT1: + linesize = (self.size[0] + 3) // 4 * 8 + for yb in range((self.size[1] + 3) // 4): + for d in decode_dxt1( + self._safe_read(linesize), alpha=bool(self._blp_alpha_depth) + ): + data += d + + elif self._blp_alpha_encoding == AlphaEncoding.DXT3: + linesize = (self.size[0] + 3) // 4 * 16 + for yb in range((self.size[1] + 3) // 4): + for d in decode_dxt3(self._safe_read(linesize)): + data += d + + elif self._blp_alpha_encoding == AlphaEncoding.DXT5: + linesize = (self.size[0] + 3) // 4 * 16 + for yb in range((self.size[1] + 3) // 4): + for d in decode_dxt5(self._safe_read(linesize)): + data += d + else: + msg = f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}" + raise BLPFormatError(msg) + else: + msg = f"Unknown BLP encoding {repr(self._blp_encoding)}" + raise BLPFormatError(msg) + + else: + msg = f"Unknown BLP compression {repr(self._blp_compression)}" + raise BLPFormatError(msg) + + self.set_as_raw(data) + + +class BLPEncoder(ImageFile.PyEncoder): + _pushes_fd = True + + def _write_palette(self) -> bytes: + data = b"" + assert self.im is not None + palette = self.im.getpalette("RGBA", "RGBA") + for i in range(len(palette) // 4): + r, g, b, a = palette[i * 4 : (i + 1) * 4] + data += struct.pack("<4B", b, g, r, a) + while len(data) < 256 * 4: + data += b"\x00" * 4 + return data + + def encode(self, bufsize: int) -> tuple[int, int, bytes]: + palette_data = self._write_palette() + + offset = 20 + 16 * 4 * 2 + len(palette_data) + data = struct.pack("<16I", offset, *((0,) * 15)) + + assert self.im is not None + w, h = self.im.size + data += struct.pack("<16I", w * h, *((0,) * 15)) + + data += palette_data + + for y in range(h): + for x in range(w): + data += struct.pack(" None: + if im.mode != "P": + msg = "Unsupported BLP image mode" + raise ValueError(msg) + + magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2" + fp.write(magic) + + fp.write(struct.pack(" mode, rawmode + 1: ("P", "P;1"), + 4: ("P", "P;4"), + 8: ("P", "P"), + 16: ("RGB", "BGR;15"), + 24: ("RGB", "BGR"), + 32: ("RGB", "BGRX"), +} + + +def _accept(prefix: bytes) -> bool: + return prefix[:2] == b"BM" + + +def _dib_accept(prefix: bytes) -> bool: + return i32(prefix) in [12, 40, 52, 56, 64, 108, 124] + + +# ============================================================================= +# Image plugin for the Windows BMP format. +# ============================================================================= +class BmpImageFile(ImageFile.ImageFile): + """Image plugin for the Windows Bitmap format (BMP)""" + + # ------------------------------------------------------------- Description + format_description = "Windows Bitmap" + format = "BMP" + + # -------------------------------------------------- BMP Compression values + COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5} + for k, v in COMPRESSIONS.items(): + vars()[k] = v + + def _bitmap(self, header=0, offset=0): + """Read relevant info about the BMP""" + read, seek = self.fp.read, self.fp.seek + if header: + seek(header) + # read bmp header size @offset 14 (this is part of the header size) + file_info = {"header_size": i32(read(4)), "direction": -1} + + # -------------------- If requested, read header at a specific position + # read the rest of the bmp header, without its size + header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4) + + # ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1 + # ----- This format has different offsets because of width/height types + # 12: BITMAPCOREHEADER/OS21XBITMAPHEADER + if file_info["header_size"] == 12: + file_info["width"] = i16(header_data, 0) + file_info["height"] = i16(header_data, 2) + file_info["planes"] = i16(header_data, 4) + file_info["bits"] = i16(header_data, 6) + file_info["compression"] = self.RAW + file_info["palette_padding"] = 3 + + # --------------------------------------------- Windows Bitmap v3 to v5 + # 40: BITMAPINFOHEADER + # 52: BITMAPV2HEADER + # 56: BITMAPV3HEADER + # 64: BITMAPCOREHEADER2/OS22XBITMAPHEADER + # 108: BITMAPV4HEADER + # 124: BITMAPV5HEADER + elif file_info["header_size"] in (40, 52, 56, 64, 108, 124): + file_info["y_flip"] = header_data[7] == 0xFF + file_info["direction"] = 1 if file_info["y_flip"] else -1 + file_info["width"] = i32(header_data, 0) + file_info["height"] = ( + i32(header_data, 4) + if not file_info["y_flip"] + else 2**32 - i32(header_data, 4) + ) + file_info["planes"] = i16(header_data, 8) + file_info["bits"] = i16(header_data, 10) + file_info["compression"] = i32(header_data, 12) + # byte size of pixel data + file_info["data_size"] = i32(header_data, 16) + file_info["pixels_per_meter"] = ( + i32(header_data, 20), + i32(header_data, 24), + ) + file_info["colors"] = i32(header_data, 28) + file_info["palette_padding"] = 4 + self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"]) + if file_info["compression"] == self.BITFIELDS: + masks = ["r_mask", "g_mask", "b_mask"] + if len(header_data) >= 48: + if len(header_data) >= 52: + masks.append("a_mask") + else: + file_info["a_mask"] = 0x0 + for idx, mask in enumerate(masks): + file_info[mask] = i32(header_data, 36 + idx * 4) + else: + # 40 byte headers only have the three components in the + # bitfields masks, ref: + # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx + # See also + # https://github.com/python-pillow/Pillow/issues/1293 + # There is a 4th component in the RGBQuad, in the alpha + # location, but it is listed as a reserved component, + # and it is not generally an alpha channel + file_info["a_mask"] = 0x0 + for mask in masks: + file_info[mask] = i32(read(4)) + file_info["rgb_mask"] = ( + file_info["r_mask"], + file_info["g_mask"], + file_info["b_mask"], + ) + file_info["rgba_mask"] = ( + file_info["r_mask"], + file_info["g_mask"], + file_info["b_mask"], + file_info["a_mask"], + ) + else: + msg = f"Unsupported BMP header type ({file_info['header_size']})" + raise OSError(msg) + + # ------------------ Special case : header is reported 40, which + # ---------------------- is shorter than real size for bpp >= 16 + self._size = file_info["width"], file_info["height"] + + # ------- If color count was not found in the header, compute from bits + file_info["colors"] = ( + file_info["colors"] + if file_info.get("colors", 0) + else (1 << file_info["bits"]) + ) + if offset == 14 + file_info["header_size"] and file_info["bits"] <= 8: + offset += 4 * file_info["colors"] + + # ---------------------- Check bit depth for unusual unsupported values + self._mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None)) + if self.mode is None: + msg = f"Unsupported BMP pixel depth ({file_info['bits']})" + raise OSError(msg) + + # ---------------- Process BMP with Bitfields compression (not palette) + decoder_name = "raw" + if file_info["compression"] == self.BITFIELDS: + SUPPORTED = { + 32: [ + (0xFF0000, 0xFF00, 0xFF, 0x0), + (0xFF000000, 0xFF0000, 0xFF00, 0x0), + (0xFF000000, 0xFF00, 0xFF, 0x0), + (0xFF000000, 0xFF0000, 0xFF00, 0xFF), + (0xFF, 0xFF00, 0xFF0000, 0xFF000000), + (0xFF0000, 0xFF00, 0xFF, 0xFF000000), + (0xFF000000, 0xFF00, 0xFF, 0xFF0000), + (0x0, 0x0, 0x0, 0x0), + ], + 24: [(0xFF0000, 0xFF00, 0xFF)], + 16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)], + } + MASK_MODES = { + (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX", + (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR", + (32, (0xFF000000, 0xFF00, 0xFF, 0x0)): "BGXR", + (32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)): "ABGR", + (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA", + (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA", + (32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR", + (32, (0x0, 0x0, 0x0, 0x0)): "BGRA", + (24, (0xFF0000, 0xFF00, 0xFF)): "BGR", + (16, (0xF800, 0x7E0, 0x1F)): "BGR;16", + (16, (0x7C00, 0x3E0, 0x1F)): "BGR;15", + } + if file_info["bits"] in SUPPORTED: + if ( + file_info["bits"] == 32 + and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]] + ): + raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])] + self._mode = "RGBA" if "A" in raw_mode else self.mode + elif ( + file_info["bits"] in (24, 16) + and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]] + ): + raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])] + else: + msg = "Unsupported BMP bitfields layout" + raise OSError(msg) + else: + msg = "Unsupported BMP bitfields layout" + raise OSError(msg) + elif file_info["compression"] == self.RAW: + if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset + raw_mode, self._mode = "BGRA", "RGBA" + elif file_info["compression"] in (self.RLE8, self.RLE4): + decoder_name = "bmp_rle" + else: + msg = f"Unsupported BMP compression ({file_info['compression']})" + raise OSError(msg) + + # --------------- Once the header is processed, process the palette/LUT + if self.mode == "P": # Paletted for 1, 4 and 8 bit images + # ---------------------------------------------------- 1-bit images + if not (0 < file_info["colors"] <= 65536): + msg = f"Unsupported BMP Palette size ({file_info['colors']})" + raise OSError(msg) + else: + padding = file_info["palette_padding"] + palette = read(padding * file_info["colors"]) + grayscale = True + indices = ( + (0, 255) + if file_info["colors"] == 2 + else list(range(file_info["colors"])) + ) + + # ----------------- Check if grayscale and ignore palette if so + for ind, val in enumerate(indices): + rgb = palette[ind * padding : ind * padding + 3] + if rgb != o8(val) * 3: + grayscale = False + + # ------- If all colors are gray, white or black, ditch palette + if grayscale: + self._mode = "1" if file_info["colors"] == 2 else "L" + raw_mode = self.mode + else: + self._mode = "P" + self.palette = ImagePalette.raw( + "BGRX" if padding == 4 else "BGR", palette + ) + + # ---------------------------- Finally set the tile data for the plugin + self.info["compression"] = file_info["compression"] + args = [raw_mode] + if decoder_name == "bmp_rle": + args.append(file_info["compression"] == self.RLE4) + else: + args.append(((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3)) + args.append(file_info["direction"]) + self.tile = [ + ( + decoder_name, + (0, 0, file_info["width"], file_info["height"]), + offset or self.fp.tell(), + tuple(args), + ) + ] + + def _open(self) -> None: + """Open file, check magic number and read header""" + # read 14 bytes: magic number, filesize, reserved, header final offset + head_data = self.fp.read(14) + # choke if the file does not have the required magic bytes + if not _accept(head_data): + msg = "Not a BMP file" + raise SyntaxError(msg) + # read the start position of the BMP image data (u32) + offset = i32(head_data, 10) + # load bitmap information (offset=raster info) + self._bitmap(offset=offset) + + +class BmpRleDecoder(ImageFile.PyDecoder): + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + rle4 = self.args[1] + data = bytearray() + x = 0 + dest_length = self.state.xsize * self.state.ysize + while len(data) < dest_length: + pixels = self.fd.read(1) + byte = self.fd.read(1) + if not pixels or not byte: + break + num_pixels = pixels[0] + if num_pixels: + # encoded mode + if x + num_pixels > self.state.xsize: + # Too much data for row + num_pixels = max(0, self.state.xsize - x) + if rle4: + first_pixel = o8(byte[0] >> 4) + second_pixel = o8(byte[0] & 0x0F) + for index in range(num_pixels): + if index % 2 == 0: + data += first_pixel + else: + data += second_pixel + else: + data += byte * num_pixels + x += num_pixels + else: + if byte[0] == 0: + # end of line + while len(data) % self.state.xsize != 0: + data += b"\x00" + x = 0 + elif byte[0] == 1: + # end of bitmap + break + elif byte[0] == 2: + # delta + bytes_read = self.fd.read(2) + if len(bytes_read) < 2: + break + right, up = self.fd.read(2) + data += b"\x00" * (right + up * self.state.xsize) + x = len(data) % self.state.xsize + else: + # absolute mode + if rle4: + # 2 pixels per byte + byte_count = byte[0] // 2 + bytes_read = self.fd.read(byte_count) + for byte_read in bytes_read: + data += o8(byte_read >> 4) + data += o8(byte_read & 0x0F) + else: + byte_count = byte[0] + bytes_read = self.fd.read(byte_count) + data += bytes_read + if len(bytes_read) < byte_count: + break + x += byte[0] + + # align to 16-bit word boundary + if self.fd.tell() % 2 != 0: + self.fd.seek(1, os.SEEK_CUR) + rawmode = "L" if self.mode == "L" else "P" + self.set_as_raw(bytes(data), (rawmode, 0, self.args[-1])) + return -1, 0 + + +# ============================================================================= +# Image plugin for the DIB format (BMP alias) +# ============================================================================= +class DibImageFile(BmpImageFile): + format = "DIB" + format_description = "Windows Bitmap" + + def _open(self) -> None: + self._bitmap() + + +# +# -------------------------------------------------------------------- +# Write BMP file + + +SAVE = { + "1": ("1", 1, 2), + "L": ("L", 8, 256), + "P": ("P", 8, 256), + "RGB": ("BGR", 24, 0), + "RGBA": ("BGRA", 32, 0), +} + + +def _dib_save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + _save(im, fp, filename, False) + + +def _save( + im: Image.Image, fp: IO[bytes], filename: str | bytes, bitmap_header: bool = True +) -> None: + try: + rawmode, bits, colors = SAVE[im.mode] + except KeyError as e: + msg = f"cannot write mode {im.mode} as BMP" + raise OSError(msg) from e + + info = im.encoderinfo + + dpi = info.get("dpi", (96, 96)) + + # 1 meter == 39.3701 inches + ppm = tuple(int(x * 39.3701 + 0.5) for x in dpi) + + stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3) + header = 40 # or 64 for OS/2 version 2 + image = stride * im.size[1] + + if im.mode == "1": + palette = b"".join(o8(i) * 4 for i in (0, 255)) + elif im.mode == "L": + palette = b"".join(o8(i) * 4 for i in range(256)) + elif im.mode == "P": + palette = im.im.getpalette("RGB", "BGRX") + colors = len(palette) // 4 + else: + palette = None + + # bitmap header + if bitmap_header: + offset = 14 + header + colors * 4 + file_size = offset + image + if file_size > 2**32 - 1: + msg = "File size is too large for the BMP format" + raise ValueError(msg) + fp.write( + b"BM" # file type (magic) + + o32(file_size) # file size + + o32(0) # reserved + + o32(offset) # image data offset + ) + + # bitmap info header + fp.write( + o32(header) # info header size + + o32(im.size[0]) # width + + o32(im.size[1]) # height + + o16(1) # planes + + o16(bits) # depth + + o32(0) # compression (0=uncompressed) + + o32(image) # size of bitmap + + o32(ppm[0]) # resolution + + o32(ppm[1]) # resolution + + o32(colors) # colors used + + o32(colors) # colors important + ) + + fp.write(b"\0" * (header - 40)) # padding (for OS/2 format) + + if palette: + fp.write(palette) + + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))]) + + +# +# -------------------------------------------------------------------- +# Registry + + +Image.register_open(BmpImageFile.format, BmpImageFile, _accept) +Image.register_save(BmpImageFile.format, _save) + +Image.register_extension(BmpImageFile.format, ".bmp") + +Image.register_mime(BmpImageFile.format, "image/bmp") + +Image.register_decoder("bmp_rle", BmpRleDecoder) + +Image.register_open(DibImageFile.format, DibImageFile, _dib_accept) +Image.register_save(DibImageFile.format, _dib_save) + +Image.register_extension(DibImageFile.format, ".dib") + +Image.register_mime(DibImageFile.format, "image/bmp") diff --git a/.venv/lib/python3.12/site-packages/PIL/BufrStubImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/BufrStubImagePlugin.py new file mode 100644 index 0000000..0ee2f65 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/BufrStubImagePlugin.py @@ -0,0 +1,76 @@ +# +# The Python Imaging Library +# $Id$ +# +# BUFR stub adapter +# +# Copyright (c) 1996-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from typing import IO + +from . import Image, ImageFile + +_handler = None + + +def register_handler(handler: ImageFile.StubHandler | None) -> None: + """ + Install application-specific BUFR image handler. + + :param handler: Handler object. + """ + global _handler + _handler = handler + + +# -------------------------------------------------------------------- +# Image adapter + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC" + + +class BufrStubImageFile(ImageFile.StubImageFile): + format = "BUFR" + format_description = "BUFR" + + def _open(self) -> None: + offset = self.fp.tell() + + if not _accept(self.fp.read(4)): + msg = "Not a BUFR file" + raise SyntaxError(msg) + + self.fp.seek(offset) + + # make something up + self._mode = "F" + self._size = 1, 1 + + loader = self._load() + if loader: + loader.open(self) + + def _load(self) -> ImageFile.StubHandler | None: + return _handler + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if _handler is None or not hasattr(_handler, "save"): + msg = "BUFR save handler not installed" + raise OSError(msg) + _handler.save(im, fp, filename) + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(BufrStubImageFile.format, BufrStubImageFile, _accept) +Image.register_save(BufrStubImageFile.format, _save) + +Image.register_extension(BufrStubImageFile.format, ".bufr") diff --git a/.venv/lib/python3.12/site-packages/PIL/ContainerIO.py b/.venv/lib/python3.12/site-packages/PIL/ContainerIO.py new file mode 100644 index 0000000..0035296 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ContainerIO.py @@ -0,0 +1,121 @@ +# +# The Python Imaging Library. +# $Id$ +# +# a class to read from a container file +# +# History: +# 1995-06-18 fl Created +# 1995-09-07 fl Added readline(), readlines() +# +# Copyright (c) 1997-2001 by Secret Labs AB +# Copyright (c) 1995 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +from typing import IO, AnyStr, Generic, Literal + + +class ContainerIO(Generic[AnyStr]): + """ + A file object that provides read access to a part of an existing + file (for example a TAR file). + """ + + def __init__(self, file: IO[AnyStr], offset: int, length: int) -> None: + """ + Create file object. + + :param file: Existing file. + :param offset: Start of region, in bytes. + :param length: Size of region, in bytes. + """ + self.fh: IO[AnyStr] = file + self.pos = 0 + self.offset = offset + self.length = length + self.fh.seek(offset) + + ## + # Always false. + + def isatty(self) -> bool: + return False + + def seek(self, offset: int, mode: Literal[0, 1, 2] = io.SEEK_SET) -> None: + """ + Move file pointer. + + :param offset: Offset in bytes. + :param mode: Starting position. Use 0 for beginning of region, 1 + for current offset, and 2 for end of region. You cannot move + the pointer outside the defined region. + """ + if mode == 1: + self.pos = self.pos + offset + elif mode == 2: + self.pos = self.length + offset + else: + self.pos = offset + # clamp + self.pos = max(0, min(self.pos, self.length)) + self.fh.seek(self.offset + self.pos) + + def tell(self) -> int: + """ + Get current file pointer. + + :returns: Offset from start of region, in bytes. + """ + return self.pos + + def read(self, n: int = 0) -> AnyStr: + """ + Read data. + + :param n: Number of bytes to read. If omitted or zero, + read until end of region. + :returns: An 8-bit string. + """ + if n: + n = min(n, self.length - self.pos) + else: + n = self.length - self.pos + if not n: # EOF + return b"" if "b" in self.fh.mode else "" # type: ignore[return-value] + self.pos = self.pos + n + return self.fh.read(n) + + def readline(self) -> AnyStr: + """ + Read a line of text. + + :returns: An 8-bit string. + """ + s: AnyStr = b"" if "b" in self.fh.mode else "" # type: ignore[assignment] + newline_character = b"\n" if "b" in self.fh.mode else "\n" + while True: + c = self.read(1) + if not c: + break + s = s + c + if c == newline_character: + break + return s + + def readlines(self) -> list[AnyStr]: + """ + Read multiple lines of text. + + :returns: A list of 8-bit strings. + """ + lines = [] + while True: + s = self.readline() + if not s: + break + lines.append(s) + return lines diff --git a/.venv/lib/python3.12/site-packages/PIL/CurImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/CurImagePlugin.py new file mode 100644 index 0000000..85e2145 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/CurImagePlugin.py @@ -0,0 +1,75 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Windows Cursor support for PIL +# +# notes: +# uses BmpImagePlugin.py to read the bitmap data. +# +# history: +# 96-05-27 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import BmpImagePlugin, Image +from ._binary import i16le as i16 +from ._binary import i32le as i32 + +# +# -------------------------------------------------------------------- + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"\0\0\2\0" + + +## +# Image plugin for Windows Cursor files. + + +class CurImageFile(BmpImagePlugin.BmpImageFile): + format = "CUR" + format_description = "Windows Cursor" + + def _open(self) -> None: + offset = self.fp.tell() + + # check magic + s = self.fp.read(6) + if not _accept(s): + msg = "not a CUR file" + raise SyntaxError(msg) + + # pick the largest cursor in the file + m = b"" + for i in range(i16(s, 4)): + s = self.fp.read(16) + if not m: + m = s + elif s[0] > m[0] and s[1] > m[1]: + m = s + if not m: + msg = "No cursors were found" + raise TypeError(msg) + + # load as bitmap + self._bitmap(i32(m, 12) + offset) + + # patch up the bitmap height + self._size = self.size[0], self.size[1] // 2 + d, e, o, a = self.tile[0] + self.tile[0] = d, (0, 0) + self.size, o, a + + +# +# -------------------------------------------------------------------- + +Image.register_open(CurImageFile.format, CurImageFile, _accept) + +Image.register_extension(CurImageFile.format, ".cur") diff --git a/.venv/lib/python3.12/site-packages/PIL/DcxImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/DcxImagePlugin.py new file mode 100644 index 0000000..f67f27d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/DcxImagePlugin.py @@ -0,0 +1,80 @@ +# +# The Python Imaging Library. +# $Id$ +# +# DCX file handling +# +# DCX is a container file format defined by Intel, commonly used +# for fax applications. Each DCX file consists of a directory +# (a list of file offsets) followed by a set of (usually 1-bit) +# PCX files. +# +# History: +# 1995-09-09 fl Created +# 1996-03-20 fl Properly derived from PcxImageFile. +# 1998-07-15 fl Renamed offset attribute to avoid name clash +# 2002-07-30 fl Fixed file handling +# +# Copyright (c) 1997-98 by Secret Labs AB. +# Copyright (c) 1995-96 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image +from ._binary import i32le as i32 +from .PcxImagePlugin import PcxImageFile + +MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then? + + +def _accept(prefix: bytes) -> bool: + return len(prefix) >= 4 and i32(prefix) == MAGIC + + +## +# Image plugin for the Intel DCX format. + + +class DcxImageFile(PcxImageFile): + format = "DCX" + format_description = "Intel DCX" + _close_exclusive_fp_after_loading = False + + def _open(self) -> None: + # Header + s = self.fp.read(4) + if not _accept(s): + msg = "not a DCX file" + raise SyntaxError(msg) + + # Component directory + self._offset = [] + for i in range(1024): + offset = i32(self.fp.read(4)) + if not offset: + break + self._offset.append(offset) + + self._fp = self.fp + self.frame = -1 + self.n_frames = len(self._offset) + self.is_animated = self.n_frames > 1 + self.seek(0) + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + self.frame = frame + self.fp = self._fp + self.fp.seek(self._offset[frame]) + PcxImageFile._open(self) + + def tell(self) -> int: + return self.frame + + +Image.register_open(DcxImageFile.format, DcxImageFile, _accept) + +Image.register_extension(DcxImageFile.format, ".dcx") diff --git a/.venv/lib/python3.12/site-packages/PIL/DdsImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/DdsImagePlugin.py new file mode 100644 index 0000000..a57e4ae --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/DdsImagePlugin.py @@ -0,0 +1,575 @@ +""" +A Pillow loader for .dds files (S3TC-compressed aka DXTC) +Jerome Leclanche + +Documentation: +https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt + +The contents of this file are hereby released in the public domain (CC0) +Full text of the CC0 license: +https://creativecommons.org/publicdomain/zero/1.0/ +""" + +from __future__ import annotations + +import io +import struct +import sys +from enum import IntEnum, IntFlag +from typing import IO + +from . import Image, ImageFile, ImagePalette +from ._binary import i32le as i32 +from ._binary import o8 +from ._binary import o32le as o32 + +# Magic ("DDS ") +DDS_MAGIC = 0x20534444 + + +# DDS flags +class DDSD(IntFlag): + CAPS = 0x1 + HEIGHT = 0x2 + WIDTH = 0x4 + PITCH = 0x8 + PIXELFORMAT = 0x1000 + MIPMAPCOUNT = 0x20000 + LINEARSIZE = 0x80000 + DEPTH = 0x800000 + + +# DDS caps +class DDSCAPS(IntFlag): + COMPLEX = 0x8 + TEXTURE = 0x1000 + MIPMAP = 0x400000 + + +class DDSCAPS2(IntFlag): + CUBEMAP = 0x200 + CUBEMAP_POSITIVEX = 0x400 + CUBEMAP_NEGATIVEX = 0x800 + CUBEMAP_POSITIVEY = 0x1000 + CUBEMAP_NEGATIVEY = 0x2000 + CUBEMAP_POSITIVEZ = 0x4000 + CUBEMAP_NEGATIVEZ = 0x8000 + VOLUME = 0x200000 + + +# Pixel Format +class DDPF(IntFlag): + ALPHAPIXELS = 0x1 + ALPHA = 0x2 + FOURCC = 0x4 + PALETTEINDEXED8 = 0x20 + RGB = 0x40 + LUMINANCE = 0x20000 + + +# dxgiformat.h +class DXGI_FORMAT(IntEnum): + UNKNOWN = 0 + R32G32B32A32_TYPELESS = 1 + R32G32B32A32_FLOAT = 2 + R32G32B32A32_UINT = 3 + R32G32B32A32_SINT = 4 + R32G32B32_TYPELESS = 5 + R32G32B32_FLOAT = 6 + R32G32B32_UINT = 7 + R32G32B32_SINT = 8 + R16G16B16A16_TYPELESS = 9 + R16G16B16A16_FLOAT = 10 + R16G16B16A16_UNORM = 11 + R16G16B16A16_UINT = 12 + R16G16B16A16_SNORM = 13 + R16G16B16A16_SINT = 14 + R32G32_TYPELESS = 15 + R32G32_FLOAT = 16 + R32G32_UINT = 17 + R32G32_SINT = 18 + R32G8X24_TYPELESS = 19 + D32_FLOAT_S8X24_UINT = 20 + R32_FLOAT_X8X24_TYPELESS = 21 + X32_TYPELESS_G8X24_UINT = 22 + R10G10B10A2_TYPELESS = 23 + R10G10B10A2_UNORM = 24 + R10G10B10A2_UINT = 25 + R11G11B10_FLOAT = 26 + R8G8B8A8_TYPELESS = 27 + R8G8B8A8_UNORM = 28 + R8G8B8A8_UNORM_SRGB = 29 + R8G8B8A8_UINT = 30 + R8G8B8A8_SNORM = 31 + R8G8B8A8_SINT = 32 + R16G16_TYPELESS = 33 + R16G16_FLOAT = 34 + R16G16_UNORM = 35 + R16G16_UINT = 36 + R16G16_SNORM = 37 + R16G16_SINT = 38 + R32_TYPELESS = 39 + D32_FLOAT = 40 + R32_FLOAT = 41 + R32_UINT = 42 + R32_SINT = 43 + R24G8_TYPELESS = 44 + D24_UNORM_S8_UINT = 45 + R24_UNORM_X8_TYPELESS = 46 + X24_TYPELESS_G8_UINT = 47 + R8G8_TYPELESS = 48 + R8G8_UNORM = 49 + R8G8_UINT = 50 + R8G8_SNORM = 51 + R8G8_SINT = 52 + R16_TYPELESS = 53 + R16_FLOAT = 54 + D16_UNORM = 55 + R16_UNORM = 56 + R16_UINT = 57 + R16_SNORM = 58 + R16_SINT = 59 + R8_TYPELESS = 60 + R8_UNORM = 61 + R8_UINT = 62 + R8_SNORM = 63 + R8_SINT = 64 + A8_UNORM = 65 + R1_UNORM = 66 + R9G9B9E5_SHAREDEXP = 67 + R8G8_B8G8_UNORM = 68 + G8R8_G8B8_UNORM = 69 + BC1_TYPELESS = 70 + BC1_UNORM = 71 + BC1_UNORM_SRGB = 72 + BC2_TYPELESS = 73 + BC2_UNORM = 74 + BC2_UNORM_SRGB = 75 + BC3_TYPELESS = 76 + BC3_UNORM = 77 + BC3_UNORM_SRGB = 78 + BC4_TYPELESS = 79 + BC4_UNORM = 80 + BC4_SNORM = 81 + BC5_TYPELESS = 82 + BC5_UNORM = 83 + BC5_SNORM = 84 + B5G6R5_UNORM = 85 + B5G5R5A1_UNORM = 86 + B8G8R8A8_UNORM = 87 + B8G8R8X8_UNORM = 88 + R10G10B10_XR_BIAS_A2_UNORM = 89 + B8G8R8A8_TYPELESS = 90 + B8G8R8A8_UNORM_SRGB = 91 + B8G8R8X8_TYPELESS = 92 + B8G8R8X8_UNORM_SRGB = 93 + BC6H_TYPELESS = 94 + BC6H_UF16 = 95 + BC6H_SF16 = 96 + BC7_TYPELESS = 97 + BC7_UNORM = 98 + BC7_UNORM_SRGB = 99 + AYUV = 100 + Y410 = 101 + Y416 = 102 + NV12 = 103 + P010 = 104 + P016 = 105 + OPAQUE_420 = 106 + YUY2 = 107 + Y210 = 108 + Y216 = 109 + NV11 = 110 + AI44 = 111 + IA44 = 112 + P8 = 113 + A8P8 = 114 + B4G4R4A4_UNORM = 115 + P208 = 130 + V208 = 131 + V408 = 132 + SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 189 + SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190 + + +class D3DFMT(IntEnum): + UNKNOWN = 0 + R8G8B8 = 20 + A8R8G8B8 = 21 + X8R8G8B8 = 22 + R5G6B5 = 23 + X1R5G5B5 = 24 + A1R5G5B5 = 25 + A4R4G4B4 = 26 + R3G3B2 = 27 + A8 = 28 + A8R3G3B2 = 29 + X4R4G4B4 = 30 + A2B10G10R10 = 31 + A8B8G8R8 = 32 + X8B8G8R8 = 33 + G16R16 = 34 + A2R10G10B10 = 35 + A16B16G16R16 = 36 + A8P8 = 40 + P8 = 41 + L8 = 50 + A8L8 = 51 + A4L4 = 52 + V8U8 = 60 + L6V5U5 = 61 + X8L8V8U8 = 62 + Q8W8V8U8 = 63 + V16U16 = 64 + A2W10V10U10 = 67 + D16_LOCKABLE = 70 + D32 = 71 + D15S1 = 73 + D24S8 = 75 + D24X8 = 77 + D24X4S4 = 79 + D16 = 80 + D32F_LOCKABLE = 82 + D24FS8 = 83 + D32_LOCKABLE = 84 + S8_LOCKABLE = 85 + L16 = 81 + VERTEXDATA = 100 + INDEX16 = 101 + INDEX32 = 102 + Q16W16V16U16 = 110 + R16F = 111 + G16R16F = 112 + A16B16G16R16F = 113 + R32F = 114 + G32R32F = 115 + A32B32G32R32F = 116 + CxV8U8 = 117 + A1 = 118 + A2B10G10R10_XR_BIAS = 119 + BINARYBUFFER = 199 + + UYVY = i32(b"UYVY") + R8G8_B8G8 = i32(b"RGBG") + YUY2 = i32(b"YUY2") + G8R8_G8B8 = i32(b"GRGB") + DXT1 = i32(b"DXT1") + DXT2 = i32(b"DXT2") + DXT3 = i32(b"DXT3") + DXT4 = i32(b"DXT4") + DXT5 = i32(b"DXT5") + DX10 = i32(b"DX10") + BC4S = i32(b"BC4S") + BC4U = i32(b"BC4U") + BC5S = i32(b"BC5S") + BC5U = i32(b"BC5U") + ATI1 = i32(b"ATI1") + ATI2 = i32(b"ATI2") + MULTI2_ARGB8 = i32(b"MET1") + + +# Backward compatibility layer +module = sys.modules[__name__] +for item in DDSD: + assert item.name is not None + setattr(module, f"DDSD_{item.name}", item.value) +for item1 in DDSCAPS: + assert item1.name is not None + setattr(module, f"DDSCAPS_{item1.name}", item1.value) +for item2 in DDSCAPS2: + assert item2.name is not None + setattr(module, f"DDSCAPS2_{item2.name}", item2.value) +for item3 in DDPF: + assert item3.name is not None + setattr(module, f"DDPF_{item3.name}", item3.value) + +DDS_FOURCC = DDPF.FOURCC +DDS_RGB = DDPF.RGB +DDS_RGBA = DDPF.RGB | DDPF.ALPHAPIXELS +DDS_LUMINANCE = DDPF.LUMINANCE +DDS_LUMINANCEA = DDPF.LUMINANCE | DDPF.ALPHAPIXELS +DDS_ALPHA = DDPF.ALPHA +DDS_PAL8 = DDPF.PALETTEINDEXED8 + +DDS_HEADER_FLAGS_TEXTURE = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT +DDS_HEADER_FLAGS_MIPMAP = DDSD.MIPMAPCOUNT +DDS_HEADER_FLAGS_VOLUME = DDSD.DEPTH +DDS_HEADER_FLAGS_PITCH = DDSD.PITCH +DDS_HEADER_FLAGS_LINEARSIZE = DDSD.LINEARSIZE + +DDS_HEIGHT = DDSD.HEIGHT +DDS_WIDTH = DDSD.WIDTH + +DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS.TEXTURE +DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS.COMPLEX | DDSCAPS.MIPMAP +DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS.COMPLEX + +DDS_CUBEMAP_POSITIVEX = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEX +DDS_CUBEMAP_NEGATIVEX = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEX +DDS_CUBEMAP_POSITIVEY = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEY +DDS_CUBEMAP_NEGATIVEY = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEY +DDS_CUBEMAP_POSITIVEZ = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEZ +DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_NEGATIVEZ + +DXT1_FOURCC = D3DFMT.DXT1 +DXT3_FOURCC = D3DFMT.DXT3 +DXT5_FOURCC = D3DFMT.DXT5 + +DXGI_FORMAT_R8G8B8A8_TYPELESS = DXGI_FORMAT.R8G8B8A8_TYPELESS +DXGI_FORMAT_R8G8B8A8_UNORM = DXGI_FORMAT.R8G8B8A8_UNORM +DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = DXGI_FORMAT.R8G8B8A8_UNORM_SRGB +DXGI_FORMAT_BC5_TYPELESS = DXGI_FORMAT.BC5_TYPELESS +DXGI_FORMAT_BC5_UNORM = DXGI_FORMAT.BC5_UNORM +DXGI_FORMAT_BC5_SNORM = DXGI_FORMAT.BC5_SNORM +DXGI_FORMAT_BC6H_UF16 = DXGI_FORMAT.BC6H_UF16 +DXGI_FORMAT_BC6H_SF16 = DXGI_FORMAT.BC6H_SF16 +DXGI_FORMAT_BC7_TYPELESS = DXGI_FORMAT.BC7_TYPELESS +DXGI_FORMAT_BC7_UNORM = DXGI_FORMAT.BC7_UNORM +DXGI_FORMAT_BC7_UNORM_SRGB = DXGI_FORMAT.BC7_UNORM_SRGB + + +class DdsImageFile(ImageFile.ImageFile): + format = "DDS" + format_description = "DirectDraw Surface" + + def _open(self) -> None: + if not _accept(self.fp.read(4)): + msg = "not a DDS file" + raise SyntaxError(msg) + (header_size,) = struct.unpack(" None: + pass + + +class DdsRgbDecoder(ImageFile.PyDecoder): + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + bitcount, masks = self.args + + # Some masks will be padded with zeros, e.g. R 0b11 G 0b1100 + # Calculate how many zeros each mask is padded with + mask_offsets = [] + # And the maximum value of each channel without the padding + mask_totals = [] + for mask in masks: + offset = 0 + if mask != 0: + while mask >> (offset + 1) << (offset + 1) == mask: + offset += 1 + mask_offsets.append(offset) + mask_totals.append(mask >> offset) + + data = bytearray() + bytecount = bitcount // 8 + dest_length = self.state.xsize * self.state.ysize * len(masks) + while len(data) < dest_length: + value = int.from_bytes(self.fd.read(bytecount), "little") + for i, mask in enumerate(masks): + masked_value = value & mask + # Remove the zero padding, and scale it to 8 bits + data += o8( + int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255) + ) + self.set_as_raw(data) + return -1, 0 + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode not in ("RGB", "RGBA", "L", "LA"): + msg = f"cannot write mode {im.mode} as DDS" + raise OSError(msg) + + alpha = im.mode[-1] == "A" + if im.mode[0] == "L": + pixel_flags = DDPF.LUMINANCE + rawmode = im.mode + if alpha: + rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF] + else: + rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000] + else: + pixel_flags = DDPF.RGB + rawmode = im.mode[::-1] + rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF] + + if alpha: + r, g, b, a = im.split() + im = Image.merge("RGBA", (a, r, g, b)) + if alpha: + pixel_flags |= DDPF.ALPHAPIXELS + rgba_mask.append(0xFF000000 if alpha else 0) + + flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PITCH | DDSD.PIXELFORMAT + bitcount = len(im.getbands()) * 8 + pitch = (im.width * bitcount + 7) // 8 + + fp.write( + o32(DDS_MAGIC) + + struct.pack( + "<7I", + 124, # header size + flags, # flags + im.height, + im.width, + pitch, + 0, # depth + 0, # mipmaps + ) + + struct.pack("11I", *((0,) * 11)) # reserved + # pfsize, pfflags, fourcc, bitcount + + struct.pack("<4I", 32, pixel_flags, 0, bitcount) + + struct.pack("<4I", *rgba_mask) # dwRGBABitMask + + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0) + ) + ImageFile._save( + im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))] + ) + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"DDS " + + +Image.register_open(DdsImageFile.format, DdsImageFile, _accept) +Image.register_decoder("dds_rgb", DdsRgbDecoder) +Image.register_save(DdsImageFile.format, _save) +Image.register_extension(DdsImageFile.format, ".dds") diff --git a/.venv/lib/python3.12/site-packages/PIL/EpsImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/EpsImagePlugin.py new file mode 100644 index 0000000..f31b1c1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/EpsImagePlugin.py @@ -0,0 +1,478 @@ +# +# The Python Imaging Library. +# $Id$ +# +# EPS file handling +# +# History: +# 1995-09-01 fl Created (0.1) +# 1996-05-18 fl Don't choke on "atend" fields, Ghostscript interface (0.2) +# 1996-08-22 fl Don't choke on floating point BoundingBox values +# 1996-08-23 fl Handle files from Macintosh (0.3) +# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4) +# 2003-09-07 fl Check gs.close status (from Federico Di Gregorio) (0.5) +# 2014-05-07 e Handling of EPS with binary preview and fixed resolution +# resizing +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1995-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import os +import re +import subprocess +import sys +import tempfile +from typing import IO + +from . import Image, ImageFile +from ._binary import i32le as i32 +from ._deprecate import deprecate + +# -------------------------------------------------------------------- + + +split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$") +field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$") + +gs_binary: str | bool | None = None +gs_windows_binary = None + + +def has_ghostscript() -> bool: + global gs_binary, gs_windows_binary + if gs_binary is None: + if sys.platform.startswith("win"): + if gs_windows_binary is None: + import shutil + + for binary in ("gswin32c", "gswin64c", "gs"): + if shutil.which(binary) is not None: + gs_windows_binary = binary + break + else: + gs_windows_binary = False + gs_binary = gs_windows_binary + else: + try: + subprocess.check_call(["gs", "--version"], stdout=subprocess.DEVNULL) + gs_binary = "gs" + except OSError: + gs_binary = False + return gs_binary is not False + + +def Ghostscript(tile, size, fp, scale=1, transparency=False): + """Render an image using Ghostscript""" + global gs_binary + if not has_ghostscript(): + msg = "Unable to locate Ghostscript on paths" + raise OSError(msg) + + # Unpack decoder tile + decoder, tile, offset, data = tile[0] + length, bbox = data + + # Hack to support hi-res rendering + scale = int(scale) or 1 + width = size[0] * scale + height = size[1] * scale + # resolution is dependent on bbox and size + res_x = 72.0 * width / (bbox[2] - bbox[0]) + res_y = 72.0 * height / (bbox[3] - bbox[1]) + + out_fd, outfile = tempfile.mkstemp() + os.close(out_fd) + + infile_temp = None + if hasattr(fp, "name") and os.path.exists(fp.name): + infile = fp.name + else: + in_fd, infile_temp = tempfile.mkstemp() + os.close(in_fd) + infile = infile_temp + + # Ignore length and offset! + # Ghostscript can read it + # Copy whole file to read in Ghostscript + with open(infile_temp, "wb") as f: + # fetch length of fp + fp.seek(0, io.SEEK_END) + fsize = fp.tell() + # ensure start position + # go back + fp.seek(0) + lengthfile = fsize + while lengthfile > 0: + s = fp.read(min(lengthfile, 100 * 1024)) + if not s: + break + lengthfile -= len(s) + f.write(s) + + device = "pngalpha" if transparency else "ppmraw" + + # Build Ghostscript command + command = [ + gs_binary, + "-q", # quiet mode + f"-g{width:d}x{height:d}", # set output geometry (pixels) + f"-r{res_x:f}x{res_y:f}", # set input DPI (dots per inch) + "-dBATCH", # exit after processing + "-dNOPAUSE", # don't pause between pages + "-dSAFER", # safe mode + f"-sDEVICE={device}", + f"-sOutputFile={outfile}", # output file + # adjust for image origin + "-c", + f"{-bbox[0]} {-bbox[1]} translate", + "-f", + infile, # input file + # showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272) + "-c", + "showpage", + ] + + # push data through Ghostscript + try: + startupinfo = None + if sys.platform.startswith("win"): + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + subprocess.check_call(command, startupinfo=startupinfo) + out_im = Image.open(outfile) + out_im.load() + finally: + try: + os.unlink(outfile) + if infile_temp: + os.unlink(infile_temp) + except OSError: + pass + + im = out_im.im.copy() + out_im.close() + return im + + +class PSFile: + """ + Wrapper for bytesio object that treats either CR or LF as end of line. + This class is no longer used internally, but kept for backwards compatibility. + """ + + def __init__(self, fp): + deprecate( + "PSFile", + 11, + action="If you need the functionality of this class " + "you will need to implement it yourself.", + ) + self.fp = fp + self.char = None + + def seek(self, offset, whence=io.SEEK_SET): + self.char = None + self.fp.seek(offset, whence) + + def readline(self) -> str: + s = [self.char or b""] + self.char = None + + c = self.fp.read(1) + while (c not in b"\r\n") and len(c): + s.append(c) + c = self.fp.read(1) + + self.char = self.fp.read(1) + # line endings can be 1 or 2 of \r \n, in either order + if self.char in b"\r\n": + self.char = None + + return b"".join(s).decode("latin-1") + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"%!PS" or (len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5) + + +## +# Image plugin for Encapsulated PostScript. This plugin supports only +# a few variants of this format. + + +class EpsImageFile(ImageFile.ImageFile): + """EPS File Parser for the Python Imaging Library""" + + format = "EPS" + format_description = "Encapsulated Postscript" + + mode_map = {1: "L", 2: "LAB", 3: "RGB", 4: "CMYK"} + + def _open(self) -> None: + (length, offset) = self._find_offset(self.fp) + + # go to offset - start of "%!PS" + self.fp.seek(offset) + + self._mode = "RGB" + self._size = None + + byte_arr = bytearray(255) + bytes_mv = memoryview(byte_arr) + bytes_read = 0 + reading_header_comments = True + reading_trailer_comments = False + trailer_reached = False + + def check_required_header_comments() -> None: + """ + The EPS specification requires that some headers exist. + This should be checked when the header comments formally end, + when image data starts, or when the file ends, whichever comes first. + """ + if "PS-Adobe" not in self.info: + msg = 'EPS header missing "%!PS-Adobe" comment' + raise SyntaxError(msg) + if "BoundingBox" not in self.info: + msg = 'EPS header missing "%%BoundingBox" comment' + raise SyntaxError(msg) + + def _read_comment(s: str) -> bool: + nonlocal reading_trailer_comments + try: + m = split.match(s) + except re.error as e: + msg = "not an EPS file" + raise SyntaxError(msg) from e + + if not m: + return False + + k, v = m.group(1, 2) + self.info[k] = v + if k == "BoundingBox": + if v == "(atend)": + reading_trailer_comments = True + elif not self._size or (trailer_reached and reading_trailer_comments): + try: + # Note: The DSC spec says that BoundingBox + # fields should be integers, but some drivers + # put floating point values there anyway. + box = [int(float(i)) for i in v.split()] + self._size = box[2] - box[0], box[3] - box[1] + self.tile = [("eps", (0, 0) + self.size, offset, (length, box))] + except Exception: + pass + return True + + while True: + byte = self.fp.read(1) + if byte == b"": + # if we didn't read a byte we must be at the end of the file + if bytes_read == 0: + if reading_header_comments: + check_required_header_comments() + break + elif byte in b"\r\n": + # if we read a line ending character, ignore it and parse what + # we have already read. if we haven't read any other characters, + # continue reading + if bytes_read == 0: + continue + else: + # ASCII/hexadecimal lines in an EPS file must not exceed + # 255 characters, not including line ending characters + if bytes_read >= 255: + # only enforce this for lines starting with a "%", + # otherwise assume it's binary data + if byte_arr[0] == ord("%"): + msg = "not an EPS file" + raise SyntaxError(msg) + else: + if reading_header_comments: + check_required_header_comments() + reading_header_comments = False + # reset bytes_read so we can keep reading + # data until the end of the line + bytes_read = 0 + byte_arr[bytes_read] = byte[0] + bytes_read += 1 + continue + + if reading_header_comments: + # Load EPS header + + # if this line doesn't start with a "%", + # or does start with "%%EndComments", + # then we've reached the end of the header/comments + if byte_arr[0] != ord("%") or bytes_mv[:13] == b"%%EndComments": + check_required_header_comments() + reading_header_comments = False + continue + + s = str(bytes_mv[:bytes_read], "latin-1") + if not _read_comment(s): + m = field.match(s) + if m: + k = m.group(1) + if k[:8] == "PS-Adobe": + self.info["PS-Adobe"] = k[9:] + else: + self.info[k] = "" + elif s[0] == "%": + # handle non-DSC PostScript comments that some + # tools mistakenly put in the Comments section + pass + else: + msg = "bad EPS header" + raise OSError(msg) + elif bytes_mv[:11] == b"%ImageData:": + # Check for an "ImageData" descriptor + # https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577413_pgfId-1035096 + + # Values: + # columns + # rows + # bit depth (1 or 8) + # mode (1: L, 2: LAB, 3: RGB, 4: CMYK) + # number of padding channels + # block size (number of bytes per row per channel) + # binary/ascii (1: binary, 2: ascii) + # data start identifier (the image data follows after a single line + # consisting only of this quoted value) + image_data_values = byte_arr[11:bytes_read].split(None, 7) + columns, rows, bit_depth, mode_id = ( + int(value) for value in image_data_values[:4] + ) + + if bit_depth == 1: + self._mode = "1" + elif bit_depth == 8: + try: + self._mode = self.mode_map[mode_id] + except ValueError: + break + else: + break + + self._size = columns, rows + return + elif bytes_mv[:5] == b"%%EOF": + break + elif trailer_reached and reading_trailer_comments: + # Load EPS trailer + s = str(bytes_mv[:bytes_read], "latin-1") + _read_comment(s) + elif bytes_mv[:9] == b"%%Trailer": + trailer_reached = True + bytes_read = 0 + + if not self._size: + msg = "cannot determine EPS bounding box" + raise OSError(msg) + + def _find_offset(self, fp): + s = fp.read(4) + + if s == b"%!PS": + # for HEAD without binary preview + fp.seek(0, io.SEEK_END) + length = fp.tell() + offset = 0 + elif i32(s) == 0xC6D3D0C5: + # FIX for: Some EPS file not handled correctly / issue #302 + # EPS can contain binary data + # or start directly with latin coding + # more info see: + # https://web.archive.org/web/20160528181353/http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf + s = fp.read(8) + offset = i32(s) + length = i32(s, 4) + else: + msg = "not an EPS file" + raise SyntaxError(msg) + + return length, offset + + def load(self, scale=1, transparency=False): + # Load EPS via Ghostscript + if self.tile: + self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency) + self._mode = self.im.mode + self._size = self.im.size + self.tile = [] + return Image.Image.load(self) + + def load_seek(self, pos: int) -> None: + # we can't incrementally load, so force ImageFile.parser to + # use our custom load method by defining this method. + pass + + +# -------------------------------------------------------------------- + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes, eps: int = 1) -> None: + """EPS Writer for the Python Imaging Library.""" + + # make sure image data is available + im.load() + + # determine PostScript image mode + if im.mode == "L": + operator = (8, 1, b"image") + elif im.mode == "RGB": + operator = (8, 3, b"false 3 colorimage") + elif im.mode == "CMYK": + operator = (8, 4, b"false 4 colorimage") + else: + msg = "image mode is not supported" + raise ValueError(msg) + + if eps: + # write EPS header + fp.write(b"%!PS-Adobe-3.0 EPSF-3.0\n") + fp.write(b"%%Creator: PIL 0.1 EpsEncode\n") + # fp.write("%%CreationDate: %s"...) + fp.write(b"%%%%BoundingBox: 0 0 %d %d\n" % im.size) + fp.write(b"%%Pages: 1\n") + fp.write(b"%%EndComments\n") + fp.write(b"%%Page: 1 1\n") + fp.write(b"%%ImageData: %d %d " % im.size) + fp.write(b'%d %d 0 1 1 "%s"\n' % operator) + + # image header + fp.write(b"gsave\n") + fp.write(b"10 dict begin\n") + fp.write(b"/buf %d string def\n" % (im.size[0] * operator[1])) + fp.write(b"%d %d scale\n" % im.size) + fp.write(b"%d %d 8\n" % im.size) # <= bits + fp.write(b"[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1])) + fp.write(b"{ currentfile buf readhexstring pop } bind\n") + fp.write(operator[2] + b"\n") + if hasattr(fp, "flush"): + fp.flush() + + ImageFile._save(im, fp, [("eps", (0, 0) + im.size, 0, None)]) + + fp.write(b"\n%%%%EndBinary\n") + fp.write(b"grestore end\n") + if hasattr(fp, "flush"): + fp.flush() + + +# -------------------------------------------------------------------- + + +Image.register_open(EpsImageFile.format, EpsImageFile, _accept) + +Image.register_save(EpsImageFile.format, _save) + +Image.register_extensions(EpsImageFile.format, [".ps", ".eps"]) + +Image.register_mime(EpsImageFile.format, "application/postscript") diff --git a/.venv/lib/python3.12/site-packages/PIL/ExifTags.py b/.venv/lib/python3.12/site-packages/PIL/ExifTags.py new file mode 100644 index 0000000..39b4aa5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ExifTags.py @@ -0,0 +1,381 @@ +# +# The Python Imaging Library. +# $Id$ +# +# EXIF tags +# +# Copyright (c) 2003 by Secret Labs AB +# +# See the README file for information on usage and redistribution. +# + +""" +This module provides constants and clear-text names for various +well-known EXIF tags. +""" +from __future__ import annotations + +from enum import IntEnum + + +class Base(IntEnum): + # possibly incomplete + InteropIndex = 0x0001 + ProcessingSoftware = 0x000B + NewSubfileType = 0x00FE + SubfileType = 0x00FF + ImageWidth = 0x0100 + ImageLength = 0x0101 + BitsPerSample = 0x0102 + Compression = 0x0103 + PhotometricInterpretation = 0x0106 + Thresholding = 0x0107 + CellWidth = 0x0108 + CellLength = 0x0109 + FillOrder = 0x010A + DocumentName = 0x010D + ImageDescription = 0x010E + Make = 0x010F + Model = 0x0110 + StripOffsets = 0x0111 + Orientation = 0x0112 + SamplesPerPixel = 0x0115 + RowsPerStrip = 0x0116 + StripByteCounts = 0x0117 + MinSampleValue = 0x0118 + MaxSampleValue = 0x0119 + XResolution = 0x011A + YResolution = 0x011B + PlanarConfiguration = 0x011C + PageName = 0x011D + FreeOffsets = 0x0120 + FreeByteCounts = 0x0121 + GrayResponseUnit = 0x0122 + GrayResponseCurve = 0x0123 + T4Options = 0x0124 + T6Options = 0x0125 + ResolutionUnit = 0x0128 + PageNumber = 0x0129 + TransferFunction = 0x012D + Software = 0x0131 + DateTime = 0x0132 + Artist = 0x013B + HostComputer = 0x013C + Predictor = 0x013D + WhitePoint = 0x013E + PrimaryChromaticities = 0x013F + ColorMap = 0x0140 + HalftoneHints = 0x0141 + TileWidth = 0x0142 + TileLength = 0x0143 + TileOffsets = 0x0144 + TileByteCounts = 0x0145 + SubIFDs = 0x014A + InkSet = 0x014C + InkNames = 0x014D + NumberOfInks = 0x014E + DotRange = 0x0150 + TargetPrinter = 0x0151 + ExtraSamples = 0x0152 + SampleFormat = 0x0153 + SMinSampleValue = 0x0154 + SMaxSampleValue = 0x0155 + TransferRange = 0x0156 + ClipPath = 0x0157 + XClipPathUnits = 0x0158 + YClipPathUnits = 0x0159 + Indexed = 0x015A + JPEGTables = 0x015B + OPIProxy = 0x015F + JPEGProc = 0x0200 + JpegIFOffset = 0x0201 + JpegIFByteCount = 0x0202 + JpegRestartInterval = 0x0203 + JpegLosslessPredictors = 0x0205 + JpegPointTransforms = 0x0206 + JpegQTables = 0x0207 + JpegDCTables = 0x0208 + JpegACTables = 0x0209 + YCbCrCoefficients = 0x0211 + YCbCrSubSampling = 0x0212 + YCbCrPositioning = 0x0213 + ReferenceBlackWhite = 0x0214 + XMLPacket = 0x02BC + RelatedImageFileFormat = 0x1000 + RelatedImageWidth = 0x1001 + RelatedImageLength = 0x1002 + Rating = 0x4746 + RatingPercent = 0x4749 + ImageID = 0x800D + CFARepeatPatternDim = 0x828D + BatteryLevel = 0x828F + Copyright = 0x8298 + ExposureTime = 0x829A + FNumber = 0x829D + IPTCNAA = 0x83BB + ImageResources = 0x8649 + ExifOffset = 0x8769 + InterColorProfile = 0x8773 + ExposureProgram = 0x8822 + SpectralSensitivity = 0x8824 + GPSInfo = 0x8825 + ISOSpeedRatings = 0x8827 + OECF = 0x8828 + Interlace = 0x8829 + TimeZoneOffset = 0x882A + SelfTimerMode = 0x882B + SensitivityType = 0x8830 + StandardOutputSensitivity = 0x8831 + RecommendedExposureIndex = 0x8832 + ISOSpeed = 0x8833 + ISOSpeedLatitudeyyy = 0x8834 + ISOSpeedLatitudezzz = 0x8835 + ExifVersion = 0x9000 + DateTimeOriginal = 0x9003 + DateTimeDigitized = 0x9004 + OffsetTime = 0x9010 + OffsetTimeOriginal = 0x9011 + OffsetTimeDigitized = 0x9012 + ComponentsConfiguration = 0x9101 + CompressedBitsPerPixel = 0x9102 + ShutterSpeedValue = 0x9201 + ApertureValue = 0x9202 + BrightnessValue = 0x9203 + ExposureBiasValue = 0x9204 + MaxApertureValue = 0x9205 + SubjectDistance = 0x9206 + MeteringMode = 0x9207 + LightSource = 0x9208 + Flash = 0x9209 + FocalLength = 0x920A + Noise = 0x920D + ImageNumber = 0x9211 + SecurityClassification = 0x9212 + ImageHistory = 0x9213 + TIFFEPStandardID = 0x9216 + MakerNote = 0x927C + UserComment = 0x9286 + SubsecTime = 0x9290 + SubsecTimeOriginal = 0x9291 + SubsecTimeDigitized = 0x9292 + AmbientTemperature = 0x9400 + Humidity = 0x9401 + Pressure = 0x9402 + WaterDepth = 0x9403 + Acceleration = 0x9404 + CameraElevationAngle = 0x9405 + XPTitle = 0x9C9B + XPComment = 0x9C9C + XPAuthor = 0x9C9D + XPKeywords = 0x9C9E + XPSubject = 0x9C9F + FlashPixVersion = 0xA000 + ColorSpace = 0xA001 + ExifImageWidth = 0xA002 + ExifImageHeight = 0xA003 + RelatedSoundFile = 0xA004 + ExifInteroperabilityOffset = 0xA005 + FlashEnergy = 0xA20B + SpatialFrequencyResponse = 0xA20C + FocalPlaneXResolution = 0xA20E + FocalPlaneYResolution = 0xA20F + FocalPlaneResolutionUnit = 0xA210 + SubjectLocation = 0xA214 + ExposureIndex = 0xA215 + SensingMethod = 0xA217 + FileSource = 0xA300 + SceneType = 0xA301 + CFAPattern = 0xA302 + CustomRendered = 0xA401 + ExposureMode = 0xA402 + WhiteBalance = 0xA403 + DigitalZoomRatio = 0xA404 + FocalLengthIn35mmFilm = 0xA405 + SceneCaptureType = 0xA406 + GainControl = 0xA407 + Contrast = 0xA408 + Saturation = 0xA409 + Sharpness = 0xA40A + DeviceSettingDescription = 0xA40B + SubjectDistanceRange = 0xA40C + ImageUniqueID = 0xA420 + CameraOwnerName = 0xA430 + BodySerialNumber = 0xA431 + LensSpecification = 0xA432 + LensMake = 0xA433 + LensModel = 0xA434 + LensSerialNumber = 0xA435 + CompositeImage = 0xA460 + CompositeImageCount = 0xA461 + CompositeImageExposureTimes = 0xA462 + Gamma = 0xA500 + PrintImageMatching = 0xC4A5 + DNGVersion = 0xC612 + DNGBackwardVersion = 0xC613 + UniqueCameraModel = 0xC614 + LocalizedCameraModel = 0xC615 + CFAPlaneColor = 0xC616 + CFALayout = 0xC617 + LinearizationTable = 0xC618 + BlackLevelRepeatDim = 0xC619 + BlackLevel = 0xC61A + BlackLevelDeltaH = 0xC61B + BlackLevelDeltaV = 0xC61C + WhiteLevel = 0xC61D + DefaultScale = 0xC61E + DefaultCropOrigin = 0xC61F + DefaultCropSize = 0xC620 + ColorMatrix1 = 0xC621 + ColorMatrix2 = 0xC622 + CameraCalibration1 = 0xC623 + CameraCalibration2 = 0xC624 + ReductionMatrix1 = 0xC625 + ReductionMatrix2 = 0xC626 + AnalogBalance = 0xC627 + AsShotNeutral = 0xC628 + AsShotWhiteXY = 0xC629 + BaselineExposure = 0xC62A + BaselineNoise = 0xC62B + BaselineSharpness = 0xC62C + BayerGreenSplit = 0xC62D + LinearResponseLimit = 0xC62E + CameraSerialNumber = 0xC62F + LensInfo = 0xC630 + ChromaBlurRadius = 0xC631 + AntiAliasStrength = 0xC632 + ShadowScale = 0xC633 + DNGPrivateData = 0xC634 + MakerNoteSafety = 0xC635 + CalibrationIlluminant1 = 0xC65A + CalibrationIlluminant2 = 0xC65B + BestQualityScale = 0xC65C + RawDataUniqueID = 0xC65D + OriginalRawFileName = 0xC68B + OriginalRawFileData = 0xC68C + ActiveArea = 0xC68D + MaskedAreas = 0xC68E + AsShotICCProfile = 0xC68F + AsShotPreProfileMatrix = 0xC690 + CurrentICCProfile = 0xC691 + CurrentPreProfileMatrix = 0xC692 + ColorimetricReference = 0xC6BF + CameraCalibrationSignature = 0xC6F3 + ProfileCalibrationSignature = 0xC6F4 + AsShotProfileName = 0xC6F6 + NoiseReductionApplied = 0xC6F7 + ProfileName = 0xC6F8 + ProfileHueSatMapDims = 0xC6F9 + ProfileHueSatMapData1 = 0xC6FA + ProfileHueSatMapData2 = 0xC6FB + ProfileToneCurve = 0xC6FC + ProfileEmbedPolicy = 0xC6FD + ProfileCopyright = 0xC6FE + ForwardMatrix1 = 0xC714 + ForwardMatrix2 = 0xC715 + PreviewApplicationName = 0xC716 + PreviewApplicationVersion = 0xC717 + PreviewSettingsName = 0xC718 + PreviewSettingsDigest = 0xC719 + PreviewColorSpace = 0xC71A + PreviewDateTime = 0xC71B + RawImageDigest = 0xC71C + OriginalRawFileDigest = 0xC71D + SubTileBlockSize = 0xC71E + RowInterleaveFactor = 0xC71F + ProfileLookTableDims = 0xC725 + ProfileLookTableData = 0xC726 + OpcodeList1 = 0xC740 + OpcodeList2 = 0xC741 + OpcodeList3 = 0xC74E + NoiseProfile = 0xC761 + + +"""Maps EXIF tags to tag names.""" +TAGS = { + **{i.value: i.name for i in Base}, + 0x920C: "SpatialFrequencyResponse", + 0x9214: "SubjectLocation", + 0x9215: "ExposureIndex", + 0x828E: "CFAPattern", + 0x920B: "FlashEnergy", + 0x9216: "TIFF/EPStandardID", +} + + +class GPS(IntEnum): + GPSVersionID = 0 + GPSLatitudeRef = 1 + GPSLatitude = 2 + GPSLongitudeRef = 3 + GPSLongitude = 4 + GPSAltitudeRef = 5 + GPSAltitude = 6 + GPSTimeStamp = 7 + GPSSatellites = 8 + GPSStatus = 9 + GPSMeasureMode = 10 + GPSDOP = 11 + GPSSpeedRef = 12 + GPSSpeed = 13 + GPSTrackRef = 14 + GPSTrack = 15 + GPSImgDirectionRef = 16 + GPSImgDirection = 17 + GPSMapDatum = 18 + GPSDestLatitudeRef = 19 + GPSDestLatitude = 20 + GPSDestLongitudeRef = 21 + GPSDestLongitude = 22 + GPSDestBearingRef = 23 + GPSDestBearing = 24 + GPSDestDistanceRef = 25 + GPSDestDistance = 26 + GPSProcessingMethod = 27 + GPSAreaInformation = 28 + GPSDateStamp = 29 + GPSDifferential = 30 + GPSHPositioningError = 31 + + +"""Maps EXIF GPS tags to tag names.""" +GPSTAGS = {i.value: i.name for i in GPS} + + +class Interop(IntEnum): + InteropIndex = 1 + InteropVersion = 2 + RelatedImageFileFormat = 4096 + RelatedImageWidth = 4097 + RelatedImageHeight = 4098 + + +class IFD(IntEnum): + Exif = 34665 + GPSInfo = 34853 + Makernote = 37500 + Interop = 40965 + IFD1 = -1 + + +class LightSource(IntEnum): + Unknown = 0 + Daylight = 1 + Fluorescent = 2 + Tungsten = 3 + Flash = 4 + Fine = 9 + Cloudy = 10 + Shade = 11 + DaylightFluorescent = 12 + DayWhiteFluorescent = 13 + CoolWhiteFluorescent = 14 + WhiteFluorescent = 15 + StandardLightA = 17 + StandardLightB = 18 + StandardLightC = 19 + D55 = 20 + D65 = 21 + D75 = 22 + D50 = 23 + ISO = 24 + Other = 255 diff --git a/.venv/lib/python3.12/site-packages/PIL/FitsImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/FitsImagePlugin.py new file mode 100644 index 0000000..4846054 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/FitsImagePlugin.py @@ -0,0 +1,152 @@ +# +# The Python Imaging Library +# $Id$ +# +# FITS file handling +# +# Copyright (c) 1998-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import gzip +import math + +from . import Image, ImageFile + + +def _accept(prefix: bytes) -> bool: + return prefix[:6] == b"SIMPLE" + + +class FitsImageFile(ImageFile.ImageFile): + format = "FITS" + format_description = "FITS" + + def _open(self) -> None: + assert self.fp is not None + + headers: dict[bytes, bytes] = {} + header_in_progress = False + decoder_name = "" + while True: + header = self.fp.read(80) + if not header: + msg = "Truncated FITS file" + raise OSError(msg) + keyword = header[:8].strip() + if keyword in (b"SIMPLE", b"XTENSION"): + header_in_progress = True + elif headers and not header_in_progress: + # This is now a data unit + break + elif keyword == b"END": + # Seek to the end of the header unit + self.fp.seek(math.ceil(self.fp.tell() / 2880) * 2880) + if not decoder_name: + decoder_name, offset, args = self._parse_headers(headers) + + header_in_progress = False + continue + + if decoder_name: + # Keep going to read past the headers + continue + + value = header[8:].split(b"/")[0].strip() + if value.startswith(b"="): + value = value[1:].strip() + if not headers and (not _accept(keyword) or value != b"T"): + msg = "Not a FITS file" + raise SyntaxError(msg) + headers[keyword] = value + + if not decoder_name: + msg = "No image data" + raise ValueError(msg) + + offset += self.fp.tell() - 80 + self.tile = [(decoder_name, (0, 0) + self.size, offset, args)] + + def _get_size( + self, headers: dict[bytes, bytes], prefix: bytes + ) -> tuple[int, int] | None: + naxis = int(headers[prefix + b"NAXIS"]) + if naxis == 0: + return None + + if naxis == 1: + return 1, int(headers[prefix + b"NAXIS1"]) + else: + return int(headers[prefix + b"NAXIS1"]), int(headers[prefix + b"NAXIS2"]) + + def _parse_headers( + self, headers: dict[bytes, bytes] + ) -> tuple[str, int, tuple[str | int, ...]]: + prefix = b"" + decoder_name = "raw" + offset = 0 + if ( + headers.get(b"XTENSION") == b"'BINTABLE'" + and headers.get(b"ZIMAGE") == b"T" + and headers[b"ZCMPTYPE"] == b"'GZIP_1 '" + ): + no_prefix_size = self._get_size(headers, prefix) or (0, 0) + number_of_bits = int(headers[b"BITPIX"]) + offset = no_prefix_size[0] * no_prefix_size[1] * (number_of_bits // 8) + + prefix = b"Z" + decoder_name = "fits_gzip" + + size = self._get_size(headers, prefix) + if not size: + return "", 0, () + + self._size = size + + number_of_bits = int(headers[prefix + b"BITPIX"]) + if number_of_bits == 8: + self._mode = "L" + elif number_of_bits == 16: + self._mode = "I;16" + elif number_of_bits == 32: + self._mode = "I" + elif number_of_bits in (-32, -64): + self._mode = "F" + + args: tuple[str | int, ...] + if decoder_name == "raw": + args = (self.mode, 0, -1) + else: + args = (number_of_bits,) + return decoder_name, offset, args + + +class FitsGzipDecoder(ImageFile.PyDecoder): + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + value = gzip.decompress(self.fd.read()) + + rows = [] + offset = 0 + number_of_bits = min(self.args[0] // 8, 4) + for y in range(self.state.ysize): + row = bytearray() + for x in range(self.state.xsize): + row += value[offset + (4 - number_of_bits) : offset + 4] + offset += 4 + rows.append(row) + self.set_as_raw(bytes([pixel for row in rows[::-1] for pixel in row])) + return -1, 0 + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(FitsImageFile.format, FitsImageFile, _accept) +Image.register_decoder("fits_gzip", FitsGzipDecoder) + +Image.register_extensions(FitsImageFile.format, [".fit", ".fits"]) diff --git a/.venv/lib/python3.12/site-packages/PIL/FliImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/FliImagePlugin.py new file mode 100644 index 0000000..dceb839 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/FliImagePlugin.py @@ -0,0 +1,174 @@ +# +# The Python Imaging Library. +# $Id$ +# +# FLI/FLC file handling. +# +# History: +# 95-09-01 fl Created +# 97-01-03 fl Fixed parser, setup decoder tile +# 98-07-15 fl Renamed offset attribute to avoid name clash +# +# Copyright (c) Secret Labs AB 1997-98. +# Copyright (c) Fredrik Lundh 1995-97. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import os + +from . import Image, ImageFile, ImagePalette +from ._binary import i16le as i16 +from ._binary import i32le as i32 +from ._binary import o8 + +# +# decoder + + +def _accept(prefix: bytes) -> bool: + return ( + len(prefix) >= 6 + and i16(prefix, 4) in [0xAF11, 0xAF12] + and i16(prefix, 14) in [0, 3] # flags + ) + + +## +# Image plugin for the FLI/FLC animation format. Use the seek +# method to load individual frames. + + +class FliImageFile(ImageFile.ImageFile): + format = "FLI" + format_description = "Autodesk FLI/FLC Animation" + _close_exclusive_fp_after_loading = False + + def _open(self): + # HEAD + s = self.fp.read(128) + if not (_accept(s) and s[20:22] == b"\x00\x00"): + msg = "not an FLI/FLC file" + raise SyntaxError(msg) + + # frames + self.n_frames = i16(s, 6) + self.is_animated = self.n_frames > 1 + + # image characteristics + self._mode = "P" + self._size = i16(s, 8), i16(s, 10) + + # animation speed + duration = i32(s, 16) + magic = i16(s, 4) + if magic == 0xAF11: + duration = (duration * 1000) // 70 + self.info["duration"] = duration + + # look for palette + palette = [(a, a, a) for a in range(256)] + + s = self.fp.read(16) + + self.__offset = 128 + + if i16(s, 4) == 0xF100: + # prefix chunk; ignore it + self.__offset = self.__offset + i32(s) + self.fp.seek(self.__offset) + s = self.fp.read(16) + + if i16(s, 4) == 0xF1FA: + # look for palette chunk + number_of_subchunks = i16(s, 6) + chunk_size = None + for _ in range(number_of_subchunks): + if chunk_size is not None: + self.fp.seek(chunk_size - 6, os.SEEK_CUR) + s = self.fp.read(6) + chunk_type = i16(s, 4) + if chunk_type in (4, 11): + self._palette(palette, 2 if chunk_type == 11 else 0) + break + chunk_size = i32(s) + if not chunk_size: + break + + palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette] + self.palette = ImagePalette.raw("RGB", b"".join(palette)) + + # set things up to decode first frame + self.__frame = -1 + self._fp = self.fp + self.__rewind = self.fp.tell() + self.seek(0) + + def _palette(self, palette, shift): + # load palette + + i = 0 + for e in range(i16(self.fp.read(2))): + s = self.fp.read(2) + i = i + s[0] + n = s[1] + if n == 0: + n = 256 + s = self.fp.read(n * 3) + for n in range(0, len(s), 3): + r = s[n] << shift + g = s[n + 1] << shift + b = s[n + 2] << shift + palette[i] = (r, g, b) + i += 1 + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + if frame < self.__frame: + self._seek(0) + + for f in range(self.__frame + 1, frame + 1): + self._seek(f) + + def _seek(self, frame: int) -> None: + if frame == 0: + self.__frame = -1 + self._fp.seek(self.__rewind) + self.__offset = 128 + else: + # ensure that the previous frame was loaded + self.load() + + if frame != self.__frame + 1: + msg = f"cannot seek to frame {frame}" + raise ValueError(msg) + self.__frame = frame + + # move to next frame + self.fp = self._fp + self.fp.seek(self.__offset) + + s = self.fp.read(4) + if not s: + msg = "missing frame size" + raise EOFError(msg) + + framesize = i32(s) + + self.decodermaxblock = framesize + self.tile = [("fli", (0, 0) + self.size, self.__offset, None)] + + self.__offset += framesize + + def tell(self) -> int: + return self.__frame + + +# +# registry + +Image.register_open(FliImageFile.format, FliImageFile, _accept) + +Image.register_extensions(FliImageFile.format, [".fli", ".flc"]) diff --git a/.venv/lib/python3.12/site-packages/PIL/FontFile.py b/.venv/lib/python3.12/site-packages/PIL/FontFile.py new file mode 100644 index 0000000..1e0c1c1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/FontFile.py @@ -0,0 +1,134 @@ +# +# The Python Imaging Library +# $Id$ +# +# base class for raster font file parsers +# +# history: +# 1997-06-05 fl created +# 1997-08-19 fl restrict image width +# +# Copyright (c) 1997-1998 by Secret Labs AB +# Copyright (c) 1997-1998 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import os +from typing import BinaryIO + +from . import Image, _binary + +WIDTH = 800 + + +def puti16( + fp: BinaryIO, values: tuple[int, int, int, int, int, int, int, int, int, int] +) -> None: + """Write network order (big-endian) 16-bit sequence""" + for v in values: + if v < 0: + v += 65536 + fp.write(_binary.o16be(v)) + + +class FontFile: + """Base class for raster font file handlers.""" + + bitmap: Image.Image | None = None + + def __init__(self) -> None: + self.info: dict[bytes, bytes | int] = {} + self.glyph: list[ + tuple[ + tuple[int, int], + tuple[int, int, int, int], + tuple[int, int, int, int], + Image.Image, + ] + | None + ] = [None] * 256 + + def __getitem__(self, ix: int) -> ( + tuple[ + tuple[int, int], + tuple[int, int, int, int], + tuple[int, int, int, int], + Image.Image, + ] + | None + ): + return self.glyph[ix] + + def compile(self) -> None: + """Create metrics and bitmap""" + + if self.bitmap: + return + + # create bitmap large enough to hold all data + h = w = maxwidth = 0 + lines = 1 + for glyph in self.glyph: + if glyph: + d, dst, src, im = glyph + h = max(h, src[3] - src[1]) + w = w + (src[2] - src[0]) + if w > WIDTH: + lines += 1 + w = src[2] - src[0] + maxwidth = max(maxwidth, w) + + xsize = maxwidth + ysize = lines * h + + if xsize == 0 and ysize == 0: + return + + self.ysize = h + + # paste glyphs into bitmap + self.bitmap = Image.new("1", (xsize, ysize)) + self.metrics: list[ + tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]] + | None + ] = [None] * 256 + x = y = 0 + for i in range(256): + glyph = self[i] + if glyph: + d, dst, src, im = glyph + xx = src[2] - src[0] + x0, y0 = x, y + x = x + xx + if x > WIDTH: + x, y = 0, y + h + x0, y0 = x, y + x = xx + s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0 + self.bitmap.paste(im.crop(src), s) + self.metrics[i] = d, dst, s + + def save(self, filename: str) -> None: + """Save font""" + + self.compile() + + # font data + if not self.bitmap: + msg = "No bitmap created" + raise ValueError(msg) + self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG") + + # font metrics + with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp: + fp.write(b"PILfont\n") + fp.write(f";;;;;;{self.ysize};\n".encode("ascii")) # HACK!!! + fp.write(b"DATA\n") + for id in range(256): + m = self.metrics[id] + if not m: + puti16(fp, (0,) * 10) + else: + puti16(fp, m[0] + m[1] + m[2]) diff --git a/.venv/lib/python3.12/site-packages/PIL/FpxImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/FpxImagePlugin.py new file mode 100644 index 0000000..c1927bd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/FpxImagePlugin.py @@ -0,0 +1,255 @@ +# +# THIS IS WORK IN PROGRESS +# +# The Python Imaging Library. +# $Id$ +# +# FlashPix support for PIL +# +# History: +# 97-01-25 fl Created (reads uncompressed RGB images only) +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import olefile + +from . import Image, ImageFile +from ._binary import i32le as i32 + +# we map from colour field tuples to (mode, rawmode) descriptors +MODES = { + # opacity + (0x00007FFE,): ("A", "L"), + # monochrome + (0x00010000,): ("L", "L"), + (0x00018000, 0x00017FFE): ("RGBA", "LA"), + # photo YCC + (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"), + (0x00028000, 0x00028001, 0x00028002, 0x00027FFE): ("RGBA", "YCCA;P"), + # standard RGB (NIFRGB) + (0x00030000, 0x00030001, 0x00030002): ("RGB", "RGB"), + (0x00038000, 0x00038001, 0x00038002, 0x00037FFE): ("RGBA", "RGBA"), +} + + +# +# -------------------------------------------------------------------- + + +def _accept(prefix: bytes) -> bool: + return prefix[:8] == olefile.MAGIC + + +## +# Image plugin for the FlashPix images. + + +class FpxImageFile(ImageFile.ImageFile): + format = "FPX" + format_description = "FlashPix" + + def _open(self): + # + # read the OLE directory and see if this is a likely + # to be a FlashPix file + + try: + self.ole = olefile.OleFileIO(self.fp) + except OSError as e: + msg = "not an FPX file; invalid OLE file" + raise SyntaxError(msg) from e + + if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": + msg = "not an FPX file; bad root CLSID" + raise SyntaxError(msg) + + self._open_index(1) + + def _open_index(self, index: int = 1) -> None: + # + # get the Image Contents Property Set + + prop = self.ole.getproperties( + [f"Data Object Store {index:06d}", "\005Image Contents"] + ) + + # size (highest resolution) + + self._size = prop[0x1000002], prop[0x1000003] + + size = max(self.size) + i = 1 + while size > 64: + size = size // 2 + i += 1 + self.maxid = i - 1 + + # mode. instead of using a single field for this, flashpix + # requires you to specify the mode for each channel in each + # resolution subimage, and leaves it to the decoder to make + # sure that they all match. for now, we'll cheat and assume + # that this is always the case. + + id = self.maxid << 16 + + s = prop[0x2000002 | id] + + bands = i32(s, 4) + if bands > 4: + msg = "Invalid number of bands" + raise OSError(msg) + + # note: for now, we ignore the "uncalibrated" flag + colors = tuple(i32(s, 8 + i * 4) & 0x7FFFFFFF for i in range(bands)) + + self._mode, self.rawmode = MODES[colors] + + # load JPEG tables, if any + self.jpeg = {} + for i in range(256): + id = 0x3000001 | (i << 16) + if id in prop: + self.jpeg[i] = prop[id] + + self._open_subimage(1, self.maxid) + + def _open_subimage(self, index: int = 1, subimage: int = 0) -> None: + # + # setup tile descriptors for a given subimage + + stream = [ + f"Data Object Store {index:06d}", + f"Resolution {subimage:04d}", + "Subimage 0000 Header", + ] + + fp = self.ole.openstream(stream) + + # skip prefix + fp.read(28) + + # header stream + s = fp.read(36) + + size = i32(s, 4), i32(s, 8) + # tilecount = i32(s, 12) + tilesize = i32(s, 16), i32(s, 20) + # channels = i32(s, 24) + offset = i32(s, 28) + length = i32(s, 32) + + if size != self.size: + msg = "subimage mismatch" + raise OSError(msg) + + # get tile descriptors + fp.seek(28 + offset) + s = fp.read(i32(s, 12) * length) + + x = y = 0 + xsize, ysize = size + xtile, ytile = tilesize + self.tile = [] + + for i in range(0, len(s), length): + x1 = min(xsize, x + xtile) + y1 = min(ysize, y + ytile) + + compression = i32(s, i + 8) + + if compression == 0: + self.tile.append( + ( + "raw", + (x, y, x1, y1), + i32(s, i) + 28, + (self.rawmode,), + ) + ) + + elif compression == 1: + # FIXME: the fill decoder is not implemented + self.tile.append( + ( + "fill", + (x, y, x1, y1), + i32(s, i) + 28, + (self.rawmode, s[12:16]), + ) + ) + + elif compression == 2: + internal_color_conversion = s[14] + jpeg_tables = s[15] + rawmode = self.rawmode + + if internal_color_conversion: + # The image is stored as usual (usually YCbCr). + if rawmode == "RGBA": + # For "RGBA", data is stored as YCbCrA based on + # negative RGB. The following trick works around + # this problem : + jpegmode, rawmode = "YCbCrK", "CMYK" + else: + jpegmode = None # let the decoder decide + + else: + # The image is stored as defined by rawmode + jpegmode = rawmode + + self.tile.append( + ( + "jpeg", + (x, y, x1, y1), + i32(s, i) + 28, + (rawmode, jpegmode), + ) + ) + + # FIXME: jpeg tables are tile dependent; the prefix + # data must be placed in the tile descriptor itself! + + if jpeg_tables: + self.tile_prefix = self.jpeg[jpeg_tables] + + else: + msg = "unknown/invalid compression" + raise OSError(msg) + + x = x + xtile + if x >= xsize: + x, y = 0, y + ytile + if y >= ysize: + break # isn't really required + + self.stream = stream + self._fp = self.fp + self.fp = None + + def load(self): + if not self.fp: + self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"]) + + return ImageFile.ImageFile.load(self) + + def close(self) -> None: + self.ole.close() + super().close() + + def __exit__(self, *args: object) -> None: + self.ole.close() + super().__exit__() + + +# +# -------------------------------------------------------------------- + + +Image.register_open(FpxImageFile.format, FpxImageFile, _accept) + +Image.register_extension(FpxImageFile.format, ".fpx") diff --git a/.venv/lib/python3.12/site-packages/PIL/FtexImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/FtexImagePlugin.py new file mode 100644 index 0000000..5acbb49 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/FtexImagePlugin.py @@ -0,0 +1,115 @@ +""" +A Pillow loader for .ftc and .ftu files (FTEX) +Jerome Leclanche + +The contents of this file are hereby released in the public domain (CC0) +Full text of the CC0 license: + https://creativecommons.org/publicdomain/zero/1.0/ + +Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001 + +The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a +packed custom format called FTEX. This file format uses file extensions FTC +and FTU. +* FTC files are compressed textures (using standard texture compression). +* FTU files are not compressed. +Texture File Format +The FTC and FTU texture files both use the same format. This +has the following structure: +{header} +{format_directory} +{data} +Where: +{header} = { + u32:magic, + u32:version, + u32:width, + u32:height, + u32:mipmap_count, + u32:format_count +} + +* The "magic" number is "FTEX". +* "width" and "height" are the dimensions of the texture. +* "mipmap_count" is the number of mipmaps in the texture. +* "format_count" is the number of texture formats (different versions of the +same texture) in this file. + +{format_directory} = format_count * { u32:format, u32:where } + +The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB +uncompressed textures. +The texture data for a format starts at the position "where" in the file. + +Each set of texture data in the file has the following structure: +{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } } +* "mipmap_size" is the number of bytes in that mip level. For compressed +textures this is the size of the texture data compressed with DXT1. For 24 bit +uncompressed textures, this is 3 * width * height. Following this are the image +bytes for that mipmap level. + +Note: All data is stored in little-Endian (Intel) byte order. +""" + +from __future__ import annotations + +import struct +from enum import IntEnum +from io import BytesIO + +from . import Image, ImageFile + +MAGIC = b"FTEX" + + +class Format(IntEnum): + DXT1 = 0 + UNCOMPRESSED = 1 + + +class FtexImageFile(ImageFile.ImageFile): + format = "FTEX" + format_description = "Texture File Format (IW2:EOC)" + + def _open(self) -> None: + if not _accept(self.fp.read(4)): + msg = "not an FTEX file" + raise SyntaxError(msg) + struct.unpack(" None: + pass + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == MAGIC + + +Image.register_open(FtexImageFile.format, FtexImageFile, _accept) +Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"]) diff --git a/.venv/lib/python3.12/site-packages/PIL/GbrImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/GbrImagePlugin.py new file mode 100644 index 0000000..93e89b1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GbrImagePlugin.py @@ -0,0 +1,103 @@ +# +# The Python Imaging Library +# +# load a GIMP brush file +# +# History: +# 96-03-14 fl Created +# 16-01-08 es Version 2 +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# Copyright (c) Eric Soroos 2016. +# +# See the README file for information on usage and redistribution. +# +# +# See https://github.com/GNOME/gimp/blob/mainline/devel-docs/gbr.txt for +# format documentation. +# +# This code Interprets version 1 and 2 .gbr files. +# Version 1 files are obsolete, and should not be used for new +# brushes. +# Version 2 files are saved by GIMP v2.8 (at least) +# Version 3 files have a format specifier of 18 for 16bit floats in +# the color depth field. This is currently unsupported by Pillow. +from __future__ import annotations + +from . import Image, ImageFile +from ._binary import i32be as i32 + + +def _accept(prefix: bytes) -> bool: + return len(prefix) >= 8 and i32(prefix, 0) >= 20 and i32(prefix, 4) in (1, 2) + + +## +# Image plugin for the GIMP brush format. + + +class GbrImageFile(ImageFile.ImageFile): + format = "GBR" + format_description = "GIMP brush file" + + def _open(self) -> None: + header_size = i32(self.fp.read(4)) + if header_size < 20: + msg = "not a GIMP brush" + raise SyntaxError(msg) + version = i32(self.fp.read(4)) + if version not in (1, 2): + msg = f"Unsupported GIMP brush version: {version}" + raise SyntaxError(msg) + + width = i32(self.fp.read(4)) + height = i32(self.fp.read(4)) + color_depth = i32(self.fp.read(4)) + if width <= 0 or height <= 0: + msg = "not a GIMP brush" + raise SyntaxError(msg) + if color_depth not in (1, 4): + msg = f"Unsupported GIMP brush color depth: {color_depth}" + raise SyntaxError(msg) + + if version == 1: + comment_length = header_size - 20 + else: + comment_length = header_size - 28 + magic_number = self.fp.read(4) + if magic_number != b"GIMP": + msg = "not a GIMP brush, bad magic number" + raise SyntaxError(msg) + self.info["spacing"] = i32(self.fp.read(4)) + + comment = self.fp.read(comment_length)[:-1] + + if color_depth == 1: + self._mode = "L" + else: + self._mode = "RGBA" + + self._size = width, height + + self.info["comment"] = comment + + # Image might not be small + Image._decompression_bomb_check(self.size) + + # Data is an uncompressed block of w * h * bytes/pixel + self._data_size = width * height * color_depth + + def load(self): + if not self.im: + self.im = Image.core.new(self.mode, self.size) + self.frombytes(self.fp.read(self._data_size)) + return Image.Image.load(self) + + +# +# registry + + +Image.register_open(GbrImageFile.format, GbrImageFile, _accept) +Image.register_extension(GbrImageFile.format, ".gbr") diff --git a/.venv/lib/python3.12/site-packages/PIL/GdImageFile.py b/.venv/lib/python3.12/site-packages/PIL/GdImageFile.py new file mode 100644 index 0000000..88b87a2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GdImageFile.py @@ -0,0 +1,102 @@ +# +# The Python Imaging Library. +# $Id$ +# +# GD file handling +# +# History: +# 1996-04-12 fl Created +# +# Copyright (c) 1997 by Secret Labs AB. +# Copyright (c) 1996 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + + +""" +.. note:: + This format cannot be automatically recognized, so the + class is not registered for use with :py:func:`PIL.Image.open()`. To open a + gd file, use the :py:func:`PIL.GdImageFile.open()` function instead. + +.. warning:: + THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This + implementation is provided for convenience and demonstrational + purposes only. +""" +from __future__ import annotations + +from typing import IO + +from . import ImageFile, ImagePalette, UnidentifiedImageError +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._typing import StrOrBytesPath + + +class GdImageFile(ImageFile.ImageFile): + """ + Image plugin for the GD uncompressed format. Note that this format + is not supported by the standard :py:func:`PIL.Image.open()` function. To use + this plugin, you have to import the :py:mod:`PIL.GdImageFile` module and + use the :py:func:`PIL.GdImageFile.open()` function. + """ + + format = "GD" + format_description = "GD uncompressed images" + + def _open(self) -> None: + # Header + assert self.fp is not None + + s = self.fp.read(1037) + + if i16(s) not in [65534, 65535]: + msg = "Not a valid GD 2.x .gd file" + raise SyntaxError(msg) + + self._mode = "L" # FIXME: "P" + self._size = i16(s, 2), i16(s, 4) + + true_color = s[6] + true_color_offset = 2 if true_color else 0 + + # transparency index + tindex = i32(s, 7 + true_color_offset) + if tindex < 256: + self.info["transparency"] = tindex + + self.palette = ImagePalette.raw( + "XBGR", s[7 + true_color_offset + 4 : 7 + true_color_offset + 4 + 256 * 4] + ) + + self.tile = [ + ( + "raw", + (0, 0) + self.size, + 7 + true_color_offset + 4 + 256 * 4, + ("L", 0, 1), + ) + ] + + +def open(fp: StrOrBytesPath | IO[bytes], mode: str = "r") -> GdImageFile: + """ + Load texture from a GD image file. + + :param fp: GD file name, or an opened file handle. + :param mode: Optional mode. In this version, if the mode argument + is given, it must be "r". + :returns: An image instance. + :raises OSError: If the image could not be read. + """ + if mode != "r": + msg = "bad mode" + raise ValueError(msg) + + try: + return GdImageFile(fp) + except SyntaxError as e: + msg = "cannot identify this image file" + raise UnidentifiedImageError(msg) from e diff --git a/.venv/lib/python3.12/site-packages/PIL/GifImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/GifImagePlugin.py new file mode 100644 index 0000000..284128c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GifImagePlugin.py @@ -0,0 +1,1159 @@ +# +# The Python Imaging Library. +# $Id$ +# +# GIF file handling +# +# History: +# 1995-09-01 fl Created +# 1996-12-14 fl Added interlace support +# 1996-12-30 fl Added animation support +# 1997-01-05 fl Added write support, fixed local colour map bug +# 1997-02-23 fl Make sure to load raster data in getdata() +# 1997-07-05 fl Support external decoder (0.4) +# 1998-07-09 fl Handle all modes when saving (0.5) +# 1998-07-15 fl Renamed offset attribute to avoid name clash +# 2001-04-16 fl Added rewind support (seek to frame 0) (0.6) +# 2001-04-17 fl Added palette optimization (0.7) +# 2002-06-06 fl Added transparency support for save (0.8) +# 2004-02-24 fl Disable interlacing for small images +# +# Copyright (c) 1997-2004 by Secret Labs AB +# Copyright (c) 1995-2004 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import itertools +import math +import os +import subprocess +import sys +from enum import IntEnum +from functools import cached_property +from typing import IO, TYPE_CHECKING, Any, List, Literal, NamedTuple, Union + +from . import ( + Image, + ImageChops, + ImageFile, + ImageMath, + ImageOps, + ImagePalette, + ImageSequence, +) +from ._binary import i16le as i16 +from ._binary import o8 +from ._binary import o16le as o16 + +if TYPE_CHECKING: + from . import _imaging + + +class LoadingStrategy(IntEnum): + """.. versionadded:: 9.1.0""" + + RGB_AFTER_FIRST = 0 + RGB_AFTER_DIFFERENT_PALETTE_ONLY = 1 + RGB_ALWAYS = 2 + + +#: .. versionadded:: 9.1.0 +LOADING_STRATEGY = LoadingStrategy.RGB_AFTER_FIRST + +# -------------------------------------------------------------------- +# Identify/read GIF files + + +def _accept(prefix: bytes) -> bool: + return prefix[:6] in [b"GIF87a", b"GIF89a"] + + +## +# Image plugin for GIF images. This plugin supports both GIF87 and +# GIF89 images. + + +class GifImageFile(ImageFile.ImageFile): + format = "GIF" + format_description = "Compuserve GIF" + _close_exclusive_fp_after_loading = False + + global_palette = None + + def data(self) -> bytes | None: + s = self.fp.read(1) + if s and s[0]: + return self.fp.read(s[0]) + return None + + def _is_palette_needed(self, p: bytes) -> bool: + for i in range(0, len(p), 3): + if not (i // 3 == p[i] == p[i + 1] == p[i + 2]): + return True + return False + + def _open(self) -> None: + # Screen + s = self.fp.read(13) + if not _accept(s): + msg = "not a GIF file" + raise SyntaxError(msg) + + self.info["version"] = s[:6] + self._size = i16(s, 6), i16(s, 8) + self.tile = [] + flags = s[10] + bits = (flags & 7) + 1 + + if flags & 128: + # get global palette + self.info["background"] = s[11] + # check if palette contains colour indices + p = self.fp.read(3 << bits) + if self._is_palette_needed(p): + p = ImagePalette.raw("RGB", p) + self.global_palette = self.palette = p + + self._fp = self.fp # FIXME: hack + self.__rewind = self.fp.tell() + self._n_frames: int | None = None + self._seek(0) # get ready to read first frame + + @property + def n_frames(self) -> int: + if self._n_frames is None: + current = self.tell() + try: + while True: + self._seek(self.tell() + 1, False) + except EOFError: + self._n_frames = self.tell() + 1 + self.seek(current) + return self._n_frames + + @cached_property + def is_animated(self) -> bool: + if self._n_frames is not None: + return self._n_frames != 1 + + current = self.tell() + if current: + return True + + try: + self._seek(1, False) + is_animated = True + except EOFError: + is_animated = False + + self.seek(current) + return is_animated + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + if frame < self.__frame: + self.im = None + self._seek(0) + + last_frame = self.__frame + for f in range(self.__frame + 1, frame + 1): + try: + self._seek(f) + except EOFError as e: + self.seek(last_frame) + msg = "no more images in GIF file" + raise EOFError(msg) from e + + def _seek(self, frame: int, update_image: bool = True) -> None: + if frame == 0: + # rewind + self.__offset = 0 + self.dispose: _imaging.ImagingCore | None = None + self.__frame = -1 + self._fp.seek(self.__rewind) + self.disposal_method = 0 + if "comment" in self.info: + del self.info["comment"] + else: + # ensure that the previous frame was loaded + if self.tile and update_image: + self.load() + + if frame != self.__frame + 1: + msg = f"cannot seek to frame {frame}" + raise ValueError(msg) + + self.fp = self._fp + if self.__offset: + # backup to last frame + self.fp.seek(self.__offset) + while self.data(): + pass + self.__offset = 0 + + s = self.fp.read(1) + if not s or s == b";": + msg = "no more images in GIF file" + raise EOFError(msg) + + palette: ImagePalette.ImagePalette | Literal[False] | None = None + + info: dict[str, Any] = {} + frame_transparency = None + interlace = None + frame_dispose_extent = None + while True: + if not s: + s = self.fp.read(1) + if not s or s == b";": + break + + elif s == b"!": + # + # extensions + # + s = self.fp.read(1) + block = self.data() + if s[0] == 249 and block is not None: + # + # graphic control extension + # + flags = block[0] + if flags & 1: + frame_transparency = block[3] + info["duration"] = i16(block, 1) * 10 + + # disposal method - find the value of bits 4 - 6 + dispose_bits = 0b00011100 & flags + dispose_bits = dispose_bits >> 2 + if dispose_bits: + # only set the dispose if it is not + # unspecified. I'm not sure if this is + # correct, but it seems to prevent the last + # frame from looking odd for some animations + self.disposal_method = dispose_bits + elif s[0] == 254: + # + # comment extension + # + comment = b"" + + # Read this comment block + while block: + comment += block + block = self.data() + + if "comment" in info: + # If multiple comment blocks in frame, separate with \n + info["comment"] += b"\n" + comment + else: + info["comment"] = comment + s = None + continue + elif s[0] == 255 and frame == 0 and block is not None: + # + # application extension + # + info["extension"] = block, self.fp.tell() + if block[:11] == b"NETSCAPE2.0": + block = self.data() + if block and len(block) >= 3 and block[0] == 1: + self.info["loop"] = i16(block, 1) + while self.data(): + pass + + elif s == b",": + # + # local image + # + s = self.fp.read(9) + + # extent + x0, y0 = i16(s, 0), i16(s, 2) + x1, y1 = x0 + i16(s, 4), y0 + i16(s, 6) + if (x1 > self.size[0] or y1 > self.size[1]) and update_image: + self._size = max(x1, self.size[0]), max(y1, self.size[1]) + Image._decompression_bomb_check(self._size) + frame_dispose_extent = x0, y0, x1, y1 + flags = s[8] + + interlace = (flags & 64) != 0 + + if flags & 128: + bits = (flags & 7) + 1 + p = self.fp.read(3 << bits) + if self._is_palette_needed(p): + palette = ImagePalette.raw("RGB", p) + else: + palette = False + + # image data + bits = self.fp.read(1)[0] + self.__offset = self.fp.tell() + break + s = None + + if interlace is None: + msg = "image not found in GIF frame" + raise EOFError(msg) + + self.__frame = frame + if not update_image: + return + + self.tile = [] + + if self.dispose: + self.im.paste(self.dispose, self.dispose_extent) + + self._frame_palette = palette if palette is not None else self.global_palette + self._frame_transparency = frame_transparency + if frame == 0: + if self._frame_palette: + if LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS: + self._mode = "RGBA" if frame_transparency is not None else "RGB" + else: + self._mode = "P" + else: + self._mode = "L" + + if not palette and self.global_palette: + from copy import copy + + palette = copy(self.global_palette) + self.palette = palette + else: + if self.mode == "P": + if ( + LOADING_STRATEGY != LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY + or palette + ): + self.pyaccess = None + if "transparency" in self.info: + self.im.putpalettealpha(self.info["transparency"], 0) + self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) + self._mode = "RGBA" + del self.info["transparency"] + else: + self._mode = "RGB" + self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) + + def _rgb(color: int) -> tuple[int, int, int]: + if self._frame_palette: + if color * 3 + 3 > len(self._frame_palette.palette): + color = 0 + return tuple(self._frame_palette.palette[color * 3 : color * 3 + 3]) + else: + return (color, color, color) + + self.dispose = None + self.dispose_extent = frame_dispose_extent + if self.dispose_extent and self.disposal_method >= 2: + try: + if self.disposal_method == 2: + # replace with background colour + + # only dispose the extent in this frame + x0, y0, x1, y1 = self.dispose_extent + dispose_size = (x1 - x0, y1 - y0) + + Image._decompression_bomb_check(dispose_size) + + # by convention, attempt to use transparency first + dispose_mode = "P" + color = self.info.get("transparency", frame_transparency) + if color is not None: + if self.mode in ("RGB", "RGBA"): + dispose_mode = "RGBA" + color = _rgb(color) + (0,) + else: + color = self.info.get("background", 0) + if self.mode in ("RGB", "RGBA"): + dispose_mode = "RGB" + color = _rgb(color) + self.dispose = Image.core.fill(dispose_mode, dispose_size, color) + else: + # replace with previous contents + if self.im is not None: + # only dispose the extent in this frame + self.dispose = self._crop(self.im, self.dispose_extent) + elif frame_transparency is not None: + x0, y0, x1, y1 = self.dispose_extent + dispose_size = (x1 - x0, y1 - y0) + + Image._decompression_bomb_check(dispose_size) + dispose_mode = "P" + color = frame_transparency + if self.mode in ("RGB", "RGBA"): + dispose_mode = "RGBA" + color = _rgb(frame_transparency) + (0,) + self.dispose = Image.core.fill( + dispose_mode, dispose_size, color + ) + except AttributeError: + pass + + if interlace is not None: + transparency = -1 + if frame_transparency is not None: + if frame == 0: + if LOADING_STRATEGY != LoadingStrategy.RGB_ALWAYS: + self.info["transparency"] = frame_transparency + elif self.mode not in ("RGB", "RGBA"): + transparency = frame_transparency + self.tile = [ + ( + "gif", + (x0, y0, x1, y1), + self.__offset, + (bits, interlace, transparency), + ) + ] + + if info.get("comment"): + self.info["comment"] = info["comment"] + for k in ["duration", "extension"]: + if k in info: + self.info[k] = info[k] + elif k in self.info: + del self.info[k] + + def load_prepare(self) -> None: + temp_mode = "P" if self._frame_palette else "L" + self._prev_im = None + if self.__frame == 0: + if self._frame_transparency is not None: + self.im = Image.core.fill( + temp_mode, self.size, self._frame_transparency + ) + elif self.mode in ("RGB", "RGBA"): + self._prev_im = self.im + if self._frame_palette: + self.im = Image.core.fill("P", self.size, self._frame_transparency or 0) + self.im.putpalette("RGB", *self._frame_palette.getdata()) + else: + self.im = None + self._mode = temp_mode + self._frame_palette = None + + super().load_prepare() + + def load_end(self) -> None: + if self.__frame == 0: + if self.mode == "P" and LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS: + if self._frame_transparency is not None: + self.im.putpalettealpha(self._frame_transparency, 0) + self._mode = "RGBA" + else: + self._mode = "RGB" + self.im = self.im.convert(self.mode, Image.Dither.FLOYDSTEINBERG) + return + if not self._prev_im: + return + if self._frame_transparency is not None: + self.im.putpalettealpha(self._frame_transparency, 0) + frame_im = self.im.convert("RGBA") + else: + frame_im = self.im.convert("RGB") + + assert self.dispose_extent is not None + frame_im = self._crop(frame_im, self.dispose_extent) + + self.im = self._prev_im + self._mode = self.im.mode + if frame_im.mode == "RGBA": + self.im.paste(frame_im, self.dispose_extent, frame_im) + else: + self.im.paste(frame_im, self.dispose_extent) + + def tell(self) -> int: + return self.__frame + + +# -------------------------------------------------------------------- +# Write GIF files + + +RAWMODE = {"1": "L", "L": "L", "P": "P"} + + +def _normalize_mode(im: Image.Image) -> Image.Image: + """ + Takes an image (or frame), returns an image in a mode that is appropriate + for saving in a Gif. + + It may return the original image, or it may return an image converted to + palette or 'L' mode. + + :param im: Image object + :returns: Image object + """ + if im.mode in RAWMODE: + im.load() + return im + if Image.getmodebase(im.mode) == "RGB": + im = im.convert("P", palette=Image.Palette.ADAPTIVE) + if im.palette.mode == "RGBA": + for rgba in im.palette.colors: + if rgba[3] == 0: + im.info["transparency"] = im.palette.colors[rgba] + break + return im + return im.convert("L") + + +_Palette = Union[bytes, bytearray, List[int], ImagePalette.ImagePalette] + + +def _normalize_palette( + im: Image.Image, palette: _Palette | None, info: dict[str, Any] +) -> Image.Image: + """ + Normalizes the palette for image. + - Sets the palette to the incoming palette, if provided. + - Ensures that there's a palette for L mode images + - Optimizes the palette if necessary/desired. + + :param im: Image object + :param palette: bytes object containing the source palette, or .... + :param info: encoderinfo + :returns: Image object + """ + source_palette = None + if palette: + # a bytes palette + if isinstance(palette, (bytes, bytearray, list)): + source_palette = bytearray(palette[:768]) + if isinstance(palette, ImagePalette.ImagePalette): + source_palette = bytearray(palette.palette) + + if im.mode == "P": + if not source_palette: + source_palette = im.im.getpalette("RGB")[:768] + else: # L-mode + if not source_palette: + source_palette = bytearray(i // 3 for i in range(768)) + im.palette = ImagePalette.ImagePalette("RGB", palette=source_palette) + + used_palette_colors: list[int] | None + if palette: + used_palette_colors = [] + assert source_palette is not None + for i in range(0, len(source_palette), 3): + source_color = tuple(source_palette[i : i + 3]) + index = im.palette.colors.get(source_color) + if index in used_palette_colors: + index = None + used_palette_colors.append(index) + for i, index in enumerate(used_palette_colors): + if index is None: + for j in range(len(used_palette_colors)): + if j not in used_palette_colors: + used_palette_colors[i] = j + break + im = im.remap_palette(used_palette_colors) + else: + used_palette_colors = _get_optimize(im, info) + if used_palette_colors is not None: + im = im.remap_palette(used_palette_colors, source_palette) + if "transparency" in info: + try: + info["transparency"] = used_palette_colors.index( + info["transparency"] + ) + except ValueError: + del info["transparency"] + return im + + im.palette.palette = source_palette + return im + + +def _write_single_frame( + im: Image.Image, + fp: IO[bytes], + palette: _Palette | None, +) -> None: + im_out = _normalize_mode(im) + for k, v in im_out.info.items(): + im.encoderinfo.setdefault(k, v) + im_out = _normalize_palette(im_out, palette, im.encoderinfo) + + for s in _get_global_header(im_out, im.encoderinfo): + fp.write(s) + + # local image header + flags = 0 + if get_interlace(im): + flags = flags | 64 + _write_local_header(fp, im, (0, 0), flags) + + im_out.encoderconfig = (8, get_interlace(im)) + ImageFile._save(im_out, fp, [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])]) + + fp.write(b"\0") # end of image data + + +def _getbbox( + base_im: Image.Image, im_frame: Image.Image +) -> tuple[Image.Image, tuple[int, int, int, int] | None]: + if _get_palette_bytes(im_frame) != _get_palette_bytes(base_im): + im_frame = im_frame.convert("RGBA") + base_im = base_im.convert("RGBA") + delta = ImageChops.subtract_modulo(im_frame, base_im) + return delta, delta.getbbox(alpha_only=False) + + +class _Frame(NamedTuple): + im: Image.Image + bbox: tuple[int, int, int, int] | None + encoderinfo: dict[str, Any] + + +def _write_multiple_frames( + im: Image.Image, fp: IO[bytes], palette: _Palette | None +) -> bool: + duration = im.encoderinfo.get("duration") + disposal = im.encoderinfo.get("disposal", im.info.get("disposal")) + + im_frames: list[_Frame] = [] + previous_im: Image.Image | None = None + frame_count = 0 + background_im = None + for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])): + for im_frame in ImageSequence.Iterator(imSequence): + # a copy is required here since seek can still mutate the image + im_frame = _normalize_mode(im_frame.copy()) + if frame_count == 0: + for k, v in im_frame.info.items(): + if k == "transparency": + continue + im.encoderinfo.setdefault(k, v) + + encoderinfo = im.encoderinfo.copy() + if "transparency" in im_frame.info: + encoderinfo.setdefault("transparency", im_frame.info["transparency"]) + im_frame = _normalize_palette(im_frame, palette, encoderinfo) + if isinstance(duration, (list, tuple)): + encoderinfo["duration"] = duration[frame_count] + elif duration is None and "duration" in im_frame.info: + encoderinfo["duration"] = im_frame.info["duration"] + if isinstance(disposal, (list, tuple)): + encoderinfo["disposal"] = disposal[frame_count] + frame_count += 1 + + diff_frame = None + if im_frames and previous_im: + # delta frame + delta, bbox = _getbbox(previous_im, im_frame) + if not bbox: + # This frame is identical to the previous frame + if encoderinfo.get("duration"): + im_frames[-1].encoderinfo["duration"] += encoderinfo["duration"] + continue + if im_frames[-1].encoderinfo.get("disposal") == 2: + if background_im is None: + color = im.encoderinfo.get( + "transparency", im.info.get("transparency", (0, 0, 0)) + ) + background = _get_background(im_frame, color) + background_im = Image.new("P", im_frame.size, background) + background_im.putpalette(im_frames[0].im.palette) + bbox = _getbbox(background_im, im_frame)[1] + elif encoderinfo.get("optimize") and im_frame.mode != "1": + if "transparency" not in encoderinfo: + try: + encoderinfo["transparency"] = ( + im_frame.palette._new_color_index(im_frame) + ) + except ValueError: + pass + if "transparency" in encoderinfo: + # When the delta is zero, fill the image with transparency + diff_frame = im_frame.copy() + fill = Image.new("P", delta.size, encoderinfo["transparency"]) + if delta.mode == "RGBA": + r, g, b, a = delta.split() + mask = ImageMath.lambda_eval( + lambda args: args["convert"]( + args["max"]( + args["max"]( + args["max"](args["r"], args["g"]), args["b"] + ), + args["a"], + ) + * 255, + "1", + ), + r=r, + g=g, + b=b, + a=a, + ) + else: + if delta.mode == "P": + # Convert to L without considering palette + delta_l = Image.new("L", delta.size) + delta_l.putdata(delta.getdata()) + delta = delta_l + mask = ImageMath.lambda_eval( + lambda args: args["convert"](args["im"] * 255, "1"), + im=delta, + ) + diff_frame.paste(fill, mask=ImageOps.invert(mask)) + else: + bbox = None + previous_im = im_frame + im_frames.append(_Frame(diff_frame or im_frame, bbox, encoderinfo)) + + if len(im_frames) == 1: + if "duration" in im.encoderinfo: + # Since multiple frames will not be written, use the combined duration + im.encoderinfo["duration"] = im_frames[0].encoderinfo["duration"] + return False + + for frame_data in im_frames: + im_frame = frame_data.im + if not frame_data.bbox: + # global header + for s in _get_global_header(im_frame, frame_data.encoderinfo): + fp.write(s) + offset = (0, 0) + else: + # compress difference + if not palette: + frame_data.encoderinfo["include_color_table"] = True + + im_frame = im_frame.crop(frame_data.bbox) + offset = frame_data.bbox[:2] + _write_frame_data(fp, im_frame, offset, frame_data.encoderinfo) + return True + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + _save(im, fp, filename, save_all=True) + + +def _save( + im: Image.Image, fp: IO[bytes], filename: str | bytes, save_all: bool = False +) -> None: + # header + if "palette" in im.encoderinfo or "palette" in im.info: + palette = im.encoderinfo.get("palette", im.info.get("palette")) + else: + palette = None + im.encoderinfo.setdefault("optimize", True) + + if not save_all or not _write_multiple_frames(im, fp, palette): + _write_single_frame(im, fp, palette) + + fp.write(b";") # end of file + + if hasattr(fp, "flush"): + fp.flush() + + +def get_interlace(im: Image.Image) -> int: + interlace = im.encoderinfo.get("interlace", 1) + + # workaround for @PIL153 + if min(im.size) < 16: + interlace = 0 + + return interlace + + +def _write_local_header( + fp: IO[bytes], im: Image.Image, offset: tuple[int, int], flags: int +) -> None: + try: + transparency = im.encoderinfo["transparency"] + except KeyError: + transparency = None + + if "duration" in im.encoderinfo: + duration = int(im.encoderinfo["duration"] / 10) + else: + duration = 0 + + disposal = int(im.encoderinfo.get("disposal", 0)) + + if transparency is not None or duration != 0 or disposal: + packed_flag = 1 if transparency is not None else 0 + packed_flag |= disposal << 2 + + fp.write( + b"!" + + o8(249) # extension intro + + o8(4) # length + + o8(packed_flag) # packed fields + + o16(duration) # duration + + o8(transparency or 0) # transparency index + + o8(0) + ) + + include_color_table = im.encoderinfo.get("include_color_table") + if include_color_table: + palette_bytes = _get_palette_bytes(im) + color_table_size = _get_color_table_size(palette_bytes) + if color_table_size: + flags = flags | 128 # local color table flag + flags = flags | color_table_size + + fp.write( + b"," + + o16(offset[0]) # offset + + o16(offset[1]) + + o16(im.size[0]) # size + + o16(im.size[1]) + + o8(flags) # flags + ) + if include_color_table and color_table_size: + fp.write(_get_header_palette(palette_bytes)) + fp.write(o8(8)) # bits + + +def _save_netpbm(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + # Unused by default. + # To use, uncomment the register_save call at the end of the file. + # + # If you need real GIF compression and/or RGB quantization, you + # can use the external NETPBM/PBMPLUS utilities. See comments + # below for information on how to enable this. + tempfile = im._dump() + + try: + with open(filename, "wb") as f: + if im.mode != "RGB": + subprocess.check_call( + ["ppmtogif", tempfile], stdout=f, stderr=subprocess.DEVNULL + ) + else: + # Pipe ppmquant output into ppmtogif + # "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename) + quant_cmd = ["ppmquant", "256", tempfile] + togif_cmd = ["ppmtogif"] + quant_proc = subprocess.Popen( + quant_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL + ) + togif_proc = subprocess.Popen( + togif_cmd, + stdin=quant_proc.stdout, + stdout=f, + stderr=subprocess.DEVNULL, + ) + + # Allow ppmquant to receive SIGPIPE if ppmtogif exits + assert quant_proc.stdout is not None + quant_proc.stdout.close() + + retcode = quant_proc.wait() + if retcode: + raise subprocess.CalledProcessError(retcode, quant_cmd) + + retcode = togif_proc.wait() + if retcode: + raise subprocess.CalledProcessError(retcode, togif_cmd) + finally: + try: + os.unlink(tempfile) + except OSError: + pass + + +# Force optimization so that we can test performance against +# cases where it took lots of memory and time previously. +_FORCE_OPTIMIZE = False + + +def _get_optimize(im: Image.Image, info: dict[str, Any]) -> list[int] | None: + """ + Palette optimization is a potentially expensive operation. + + This function determines if the palette should be optimized using + some heuristics, then returns the list of palette entries in use. + + :param im: Image object + :param info: encoderinfo + :returns: list of indexes of palette entries in use, or None + """ + if im.mode in ("P", "L") and info and info.get("optimize"): + # Potentially expensive operation. + + # The palette saves 3 bytes per color not used, but palette + # lengths are restricted to 3*(2**N) bytes. Max saving would + # be 768 -> 6 bytes if we went all the way down to 2 colors. + # * If we're over 128 colors, we can't save any space. + # * If there aren't any holes, it's not worth collapsing. + # * If we have a 'large' image, the palette is in the noise. + + # create the new palette if not every color is used + optimise = _FORCE_OPTIMIZE or im.mode == "L" + if optimise or im.width * im.height < 512 * 512: + # check which colors are used + used_palette_colors = [] + for i, count in enumerate(im.histogram()): + if count: + used_palette_colors.append(i) + + if optimise or max(used_palette_colors) >= len(used_palette_colors): + return used_palette_colors + + num_palette_colors = len(im.palette.palette) // Image.getmodebands( + im.palette.mode + ) + current_palette_size = 1 << (num_palette_colors - 1).bit_length() + if ( + # check that the palette would become smaller when saved + len(used_palette_colors) <= current_palette_size // 2 + # check that the palette is not already the smallest possible size + and current_palette_size > 2 + ): + return used_palette_colors + return None + + +def _get_color_table_size(palette_bytes: bytes) -> int: + # calculate the palette size for the header + if not palette_bytes: + return 0 + elif len(palette_bytes) < 9: + return 1 + else: + return math.ceil(math.log(len(palette_bytes) // 3, 2)) - 1 + + +def _get_header_palette(palette_bytes: bytes) -> bytes: + """ + Returns the palette, null padded to the next power of 2 (*3) bytes + suitable for direct inclusion in the GIF header + + :param palette_bytes: Unpadded palette bytes, in RGBRGB form + :returns: Null padded palette + """ + color_table_size = _get_color_table_size(palette_bytes) + + # add the missing amount of bytes + # the palette has to be 2< 0: + palette_bytes += o8(0) * 3 * actual_target_size_diff + return palette_bytes + + +def _get_palette_bytes(im: Image.Image) -> bytes: + """ + Gets the palette for inclusion in the gif header + + :param im: Image object + :returns: Bytes, len<=768 suitable for inclusion in gif header + """ + return im.palette.palette if im.palette else b"" + + +def _get_background( + im: Image.Image, + info_background: int | tuple[int, int, int] | tuple[int, int, int, int] | None, +) -> int: + background = 0 + if info_background: + if isinstance(info_background, tuple): + # WebPImagePlugin stores an RGBA value in info["background"] + # So it must be converted to the same format as GifImagePlugin's + # info["background"] - a global color table index + try: + background = im.palette.getcolor(info_background, im) + except ValueError as e: + if str(e) not in ( + # If all 256 colors are in use, + # then there is no need for the background color + "cannot allocate more than 256 colors", + # Ignore non-opaque WebP background + "cannot add non-opaque RGBA color to RGB palette", + ): + raise + else: + background = info_background + return background + + +def _get_global_header(im: Image.Image, info: dict[str, Any]) -> list[bytes]: + """Return a list of strings representing a GIF header""" + + # Header Block + # https://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp + + version = b"87a" + if im.info.get("version") == b"89a" or ( + info + and ( + "transparency" in info + or info.get("loop") is not None + or info.get("duration") + or info.get("comment") + ) + ): + version = b"89a" + + background = _get_background(im, info.get("background")) + + palette_bytes = _get_palette_bytes(im) + color_table_size = _get_color_table_size(palette_bytes) + + header = [ + b"GIF" # signature + + version # version + + o16(im.size[0]) # canvas width + + o16(im.size[1]), # canvas height + # Logical Screen Descriptor + # size of global color table + global color table flag + o8(color_table_size + 128), # packed fields + # background + reserved/aspect + o8(background) + o8(0), + # Global Color Table + _get_header_palette(palette_bytes), + ] + if info.get("loop") is not None: + header.append( + b"!" + + o8(255) # extension intro + + o8(11) + + b"NETSCAPE2.0" + + o8(3) + + o8(1) + + o16(info["loop"]) # number of loops + + o8(0) + ) + if info.get("comment"): + comment_block = b"!" + o8(254) # extension intro + + comment = info["comment"] + if isinstance(comment, str): + comment = comment.encode() + for i in range(0, len(comment), 255): + subblock = comment[i : i + 255] + comment_block += o8(len(subblock)) + subblock + + comment_block += o8(0) + header.append(comment_block) + return header + + +def _write_frame_data( + fp: IO[bytes], + im_frame: Image.Image, + offset: tuple[int, int], + params: dict[str, Any], +) -> None: + try: + im_frame.encoderinfo = params + + # local image header + _write_local_header(fp, im_frame, offset, 0) + + ImageFile._save( + im_frame, fp, [("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])] + ) + + fp.write(b"\0") # end of image data + finally: + del im_frame.encoderinfo + + +# -------------------------------------------------------------------- +# Legacy GIF utilities + + +def getheader( + im: Image.Image, palette: _Palette | None = None, info: dict[str, Any] | None = None +) -> tuple[list[bytes], list[int] | None]: + """ + Legacy Method to get Gif data from image. + + Warning:: May modify image data. + + :param im: Image object + :param palette: bytes object containing the source palette, or .... + :param info: encoderinfo + :returns: tuple of(list of header items, optimized palette) + + """ + if info is None: + info = {} + + used_palette_colors = _get_optimize(im, info) + + if "background" not in info and "background" in im.info: + info["background"] = im.info["background"] + + im_mod = _normalize_palette(im, palette, info) + im.palette = im_mod.palette + im.im = im_mod.im + header = _get_global_header(im, info) + + return header, used_palette_colors + + +def getdata( + im: Image.Image, offset: tuple[int, int] = (0, 0), **params: Any +) -> list[bytes]: + """ + Legacy Method + + Return a list of strings representing this image. + The first string is a local image header, the rest contains + encoded image data. + + To specify duration, add the time in milliseconds, + e.g. ``getdata(im_frame, duration=1000)`` + + :param im: Image object + :param offset: Tuple of (x, y) pixels. Defaults to (0, 0) + :param \\**params: e.g. duration or other encoder info parameters + :returns: List of bytes containing GIF encoded frame data + + """ + from io import BytesIO + + class Collector(BytesIO): + data = [] + + if sys.version_info >= (3, 12): + from collections.abc import Buffer + + def write(self, data: Buffer) -> int: + self.data.append(data) + return len(data) + + else: + + def write(self, data: Any) -> int: + self.data.append(data) + return len(data) + + im.load() # make sure raster data is available + + fp = Collector() + + _write_frame_data(fp, im, offset, params) + + return fp.data + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(GifImageFile.format, GifImageFile, _accept) +Image.register_save(GifImageFile.format, _save) +Image.register_save_all(GifImageFile.format, _save_all) +Image.register_extension(GifImageFile.format, ".gif") +Image.register_mime(GifImageFile.format, "image/gif") + +# +# Uncomment the following line if you wish to use NETPBM/PBMPLUS +# instead of the built-in "uncompressed" GIF encoder + +# Image.register_save(GifImageFile.format, _save_netpbm) diff --git a/.venv/lib/python3.12/site-packages/PIL/GimpGradientFile.py b/.venv/lib/python3.12/site-packages/PIL/GimpGradientFile.py new file mode 100644 index 0000000..220eac5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GimpGradientFile.py @@ -0,0 +1,149 @@ +# +# Python Imaging Library +# $Id$ +# +# stuff to read (and render) GIMP gradient files +# +# History: +# 97-08-23 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# + +""" +Stuff to translate curve segments to palette values (derived from +the corresponding code in GIMP, written by Federico Mena Quintero. +See the GIMP distribution for more information.) +""" +from __future__ import annotations + +from math import log, pi, sin, sqrt +from typing import IO, Callable + +from ._binary import o8 + +EPSILON = 1e-10 +"""""" # Enable auto-doc for data member + + +def linear(middle: float, pos: float) -> float: + if pos <= middle: + if middle < EPSILON: + return 0.0 + else: + return 0.5 * pos / middle + else: + pos = pos - middle + middle = 1.0 - middle + if middle < EPSILON: + return 1.0 + else: + return 0.5 + 0.5 * pos / middle + + +def curved(middle: float, pos: float) -> float: + return pos ** (log(0.5) / log(max(middle, EPSILON))) + + +def sine(middle: float, pos: float) -> float: + return (sin((-pi / 2.0) + pi * linear(middle, pos)) + 1.0) / 2.0 + + +def sphere_increasing(middle: float, pos: float) -> float: + return sqrt(1.0 - (linear(middle, pos) - 1.0) ** 2) + + +def sphere_decreasing(middle: float, pos: float) -> float: + return 1.0 - sqrt(1.0 - linear(middle, pos) ** 2) + + +SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing] +"""""" # Enable auto-doc for data member + + +class GradientFile: + gradient: ( + list[ + tuple[ + float, + float, + float, + list[float], + list[float], + Callable[[float, float], float], + ] + ] + | None + ) = None + + def getpalette(self, entries: int = 256) -> tuple[bytes, str]: + assert self.gradient is not None + palette = [] + + ix = 0 + x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix] + + for i in range(entries): + x = i / (entries - 1) + + while x1 < x: + ix += 1 + x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix] + + w = x1 - x0 + + if w < EPSILON: + scale = segment(0.5, 0.5) + else: + scale = segment((xm - x0) / w, (x - x0) / w) + + # expand to RGBA + r = o8(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5)) + g = o8(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5)) + b = o8(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5)) + a = o8(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5)) + + # add to palette + palette.append(r + g + b + a) + + return b"".join(palette), "RGBA" + + +class GimpGradientFile(GradientFile): + """File handler for GIMP's gradient format.""" + + def __init__(self, fp: IO[bytes]) -> None: + if fp.readline()[:13] != b"GIMP Gradient": + msg = "not a GIMP gradient file" + raise SyntaxError(msg) + + line = fp.readline() + + # GIMP 1.2 gradient files don't contain a name, but GIMP 1.3 files do + if line.startswith(b"Name: "): + line = fp.readline().strip() + + count = int(line) + + self.gradient = [] + + for i in range(count): + s = fp.readline().split() + w = [float(x) for x in s[:11]] + + x0, x1 = w[0], w[2] + xm = w[1] + rgb0 = w[3:7] + rgb1 = w[7:11] + + segment = SEGMENTS[int(s[11])] + cspace = int(s[12]) + + if cspace != 0: + msg = "cannot handle HSV colour space" + raise OSError(msg) + + self.gradient.append((x0, x1, xm, rgb0, rgb1, segment)) diff --git a/.venv/lib/python3.12/site-packages/PIL/GimpPaletteFile.py b/.venv/lib/python3.12/site-packages/PIL/GimpPaletteFile.py new file mode 100644 index 0000000..4cad0eb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GimpPaletteFile.py @@ -0,0 +1,58 @@ +# +# Python Imaging Library +# $Id$ +# +# stuff to read GIMP palette files +# +# History: +# 1997-08-23 fl Created +# 2004-09-07 fl Support GIMP 2.0 palette files. +# +# Copyright (c) Secret Labs AB 1997-2004. All rights reserved. +# Copyright (c) Fredrik Lundh 1997-2004. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import re +from typing import IO + +from ._binary import o8 + + +class GimpPaletteFile: + """File handler for GIMP's palette format.""" + + rawmode = "RGB" + + def __init__(self, fp: IO[bytes]) -> None: + palette = [o8(i) * 3 for i in range(256)] + + if fp.readline()[:12] != b"GIMP Palette": + msg = "not a GIMP palette file" + raise SyntaxError(msg) + + for i in range(256): + s = fp.readline() + if not s: + break + + # skip fields and comment lines + if re.match(rb"\w+:|#", s): + continue + if len(s) > 100: + msg = "bad palette file" + raise SyntaxError(msg) + + v = tuple(map(int, s.split()[:3])) + if len(v) != 3: + msg = "bad palette entry" + raise ValueError(msg) + + palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2]) + + self.palette = b"".join(palette) + + def getpalette(self) -> tuple[bytes, str]: + return self.palette, self.rawmode diff --git a/.venv/lib/python3.12/site-packages/PIL/GribStubImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/GribStubImagePlugin.py new file mode 100644 index 0000000..e9aa084 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/GribStubImagePlugin.py @@ -0,0 +1,76 @@ +# +# The Python Imaging Library +# $Id$ +# +# GRIB stub adapter +# +# Copyright (c) 1996-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from typing import IO + +from . import Image, ImageFile + +_handler = None + + +def register_handler(handler: ImageFile.StubHandler | None) -> None: + """ + Install application-specific GRIB image handler. + + :param handler: Handler object. + """ + global _handler + _handler = handler + + +# -------------------------------------------------------------------- +# Image adapter + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"GRIB" and prefix[7] == 1 + + +class GribStubImageFile(ImageFile.StubImageFile): + format = "GRIB" + format_description = "GRIB" + + def _open(self) -> None: + offset = self.fp.tell() + + if not _accept(self.fp.read(8)): + msg = "Not a GRIB file" + raise SyntaxError(msg) + + self.fp.seek(offset) + + # make something up + self._mode = "F" + self._size = 1, 1 + + loader = self._load() + if loader: + loader.open(self) + + def _load(self) -> ImageFile.StubHandler | None: + return _handler + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if _handler is None or not hasattr(_handler, "save"): + msg = "GRIB save handler not installed" + raise OSError(msg) + _handler.save(im, fp, filename) + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(GribStubImageFile.format, GribStubImageFile, _accept) +Image.register_save(GribStubImageFile.format, _save) + +Image.register_extension(GribStubImageFile.format, ".grib") diff --git a/.venv/lib/python3.12/site-packages/PIL/Hdf5StubImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/Hdf5StubImagePlugin.py new file mode 100644 index 0000000..cc9e73d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/Hdf5StubImagePlugin.py @@ -0,0 +1,76 @@ +# +# The Python Imaging Library +# $Id$ +# +# HDF5 stub adapter +# +# Copyright (c) 2000-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from typing import IO + +from . import Image, ImageFile + +_handler = None + + +def register_handler(handler: ImageFile.StubHandler | None) -> None: + """ + Install application-specific HDF5 image handler. + + :param handler: Handler object. + """ + global _handler + _handler = handler + + +# -------------------------------------------------------------------- +# Image adapter + + +def _accept(prefix: bytes) -> bool: + return prefix[:8] == b"\x89HDF\r\n\x1a\n" + + +class HDF5StubImageFile(ImageFile.StubImageFile): + format = "HDF5" + format_description = "HDF5" + + def _open(self) -> None: + offset = self.fp.tell() + + if not _accept(self.fp.read(8)): + msg = "Not an HDF file" + raise SyntaxError(msg) + + self.fp.seek(offset) + + # make something up + self._mode = "F" + self._size = 1, 1 + + loader = self._load() + if loader: + loader.open(self) + + def _load(self) -> ImageFile.StubHandler | None: + return _handler + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if _handler is None or not hasattr(_handler, "save"): + msg = "HDF5 save handler not installed" + raise OSError(msg) + _handler.save(im, fp, filename) + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(HDF5StubImageFile.format, HDF5StubImageFile, _accept) +Image.register_save(HDF5StubImageFile.format, _save) + +Image.register_extensions(HDF5StubImageFile.format, [".h5", ".hdf"]) diff --git a/.venv/lib/python3.12/site-packages/PIL/IcnsImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/IcnsImagePlugin.py new file mode 100644 index 0000000..2a89d49 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/IcnsImagePlugin.py @@ -0,0 +1,399 @@ +# +# The Python Imaging Library. +# $Id$ +# +# macOS icns file decoder, based on icns.py by Bob Ippolito. +# +# history: +# 2004-10-09 fl Turned into a PIL plugin; removed 2.3 dependencies. +# 2020-04-04 Allow saving on all operating systems. +# +# Copyright (c) 2004 by Bob Ippolito. +# Copyright (c) 2004 by Secret Labs. +# Copyright (c) 2004 by Fredrik Lundh. +# Copyright (c) 2014 by Alastair Houghton. +# Copyright (c) 2020 by Pan Jing. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import os +import struct +import sys +from typing import IO + +from . import Image, ImageFile, PngImagePlugin, features + +enable_jpeg2k = features.check_codec("jpg_2000") +if enable_jpeg2k: + from . import Jpeg2KImagePlugin + +MAGIC = b"icns" +HEADERSIZE = 8 + + +def nextheader(fobj): + return struct.unpack(">4sI", fobj.read(HEADERSIZE)) + + +def read_32t(fobj, start_length, size): + # The 128x128 icon seems to have an extra header for some reason. + (start, length) = start_length + fobj.seek(start) + sig = fobj.read(4) + if sig != b"\x00\x00\x00\x00": + msg = "Unknown signature, expecting 0x00000000" + raise SyntaxError(msg) + return read_32(fobj, (start + 4, length - 4), size) + + +def read_32(fobj, start_length, size): + """ + Read a 32bit RGB icon resource. Seems to be either uncompressed or + an RLE packbits-like scheme. + """ + (start, length) = start_length + fobj.seek(start) + pixel_size = (size[0] * size[2], size[1] * size[2]) + sizesq = pixel_size[0] * pixel_size[1] + if length == sizesq * 3: + # uncompressed ("RGBRGBGB") + indata = fobj.read(length) + im = Image.frombuffer("RGB", pixel_size, indata, "raw", "RGB", 0, 1) + else: + # decode image + im = Image.new("RGB", pixel_size, None) + for band_ix in range(3): + data = [] + bytesleft = sizesq + while bytesleft > 0: + byte = fobj.read(1) + if not byte: + break + byte = byte[0] + if byte & 0x80: + blocksize = byte - 125 + byte = fobj.read(1) + for i in range(blocksize): + data.append(byte) + else: + blocksize = byte + 1 + data.append(fobj.read(blocksize)) + bytesleft -= blocksize + if bytesleft <= 0: + break + if bytesleft != 0: + msg = f"Error reading channel [{repr(bytesleft)} left]" + raise SyntaxError(msg) + band = Image.frombuffer("L", pixel_size, b"".join(data), "raw", "L", 0, 1) + im.im.putband(band.im, band_ix) + return {"RGB": im} + + +def read_mk(fobj, start_length, size): + # Alpha masks seem to be uncompressed + start = start_length[0] + fobj.seek(start) + pixel_size = (size[0] * size[2], size[1] * size[2]) + sizesq = pixel_size[0] * pixel_size[1] + band = Image.frombuffer("L", pixel_size, fobj.read(sizesq), "raw", "L", 0, 1) + return {"A": band} + + +def read_png_or_jpeg2000(fobj, start_length, size): + (start, length) = start_length + fobj.seek(start) + sig = fobj.read(12) + if sig[:8] == b"\x89PNG\x0d\x0a\x1a\x0a": + fobj.seek(start) + im = PngImagePlugin.PngImageFile(fobj) + Image._decompression_bomb_check(im.size) + return {"RGBA": im} + elif ( + sig[:4] == b"\xff\x4f\xff\x51" + or sig[:4] == b"\x0d\x0a\x87\x0a" + or sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" + ): + if not enable_jpeg2k: + msg = ( + "Unsupported icon subimage format (rebuild PIL " + "with JPEG 2000 support to fix this)" + ) + raise ValueError(msg) + # j2k, jpc or j2c + fobj.seek(start) + jp2kstream = fobj.read(length) + f = io.BytesIO(jp2kstream) + im = Jpeg2KImagePlugin.Jpeg2KImageFile(f) + Image._decompression_bomb_check(im.size) + if im.mode != "RGBA": + im = im.convert("RGBA") + return {"RGBA": im} + else: + msg = "Unsupported icon subimage format" + raise ValueError(msg) + + +class IcnsFile: + SIZES = { + (512, 512, 2): [(b"ic10", read_png_or_jpeg2000)], + (512, 512, 1): [(b"ic09", read_png_or_jpeg2000)], + (256, 256, 2): [(b"ic14", read_png_or_jpeg2000)], + (256, 256, 1): [(b"ic08", read_png_or_jpeg2000)], + (128, 128, 2): [(b"ic13", read_png_or_jpeg2000)], + (128, 128, 1): [ + (b"ic07", read_png_or_jpeg2000), + (b"it32", read_32t), + (b"t8mk", read_mk), + ], + (64, 64, 1): [(b"icp6", read_png_or_jpeg2000)], + (32, 32, 2): [(b"ic12", read_png_or_jpeg2000)], + (48, 48, 1): [(b"ih32", read_32), (b"h8mk", read_mk)], + (32, 32, 1): [ + (b"icp5", read_png_or_jpeg2000), + (b"il32", read_32), + (b"l8mk", read_mk), + ], + (16, 16, 2): [(b"ic11", read_png_or_jpeg2000)], + (16, 16, 1): [ + (b"icp4", read_png_or_jpeg2000), + (b"is32", read_32), + (b"s8mk", read_mk), + ], + } + + def __init__(self, fobj): + """ + fobj is a file-like object as an icns resource + """ + # signature : (start, length) + self.dct = dct = {} + self.fobj = fobj + sig, filesize = nextheader(fobj) + if not _accept(sig): + msg = "not an icns file" + raise SyntaxError(msg) + i = HEADERSIZE + while i < filesize: + sig, blocksize = nextheader(fobj) + if blocksize <= 0: + msg = "invalid block header" + raise SyntaxError(msg) + i += HEADERSIZE + blocksize -= HEADERSIZE + dct[sig] = (i, blocksize) + fobj.seek(blocksize, io.SEEK_CUR) + i += blocksize + + def itersizes(self): + sizes = [] + for size, fmts in self.SIZES.items(): + for fmt, reader in fmts: + if fmt in self.dct: + sizes.append(size) + break + return sizes + + def bestsize(self): + sizes = self.itersizes() + if not sizes: + msg = "No 32bit icon resources found" + raise SyntaxError(msg) + return max(sizes) + + def dataforsize(self, size): + """ + Get an icon resource as {channel: array}. Note that + the arrays are bottom-up like windows bitmaps and will likely + need to be flipped or transposed in some way. + """ + dct = {} + for code, reader in self.SIZES[size]: + desc = self.dct.get(code) + if desc is not None: + dct.update(reader(self.fobj, desc, size)) + return dct + + def getimage(self, size=None): + if size is None: + size = self.bestsize() + if len(size) == 2: + size = (size[0], size[1], 1) + channels = self.dataforsize(size) + + im = channels.get("RGBA", None) + if im: + return im + + im = channels.get("RGB").copy() + try: + im.putalpha(channels["A"]) + except KeyError: + pass + return im + + +## +# Image plugin for Mac OS icons. + + +class IcnsImageFile(ImageFile.ImageFile): + """ + PIL image support for Mac OS .icns files. + Chooses the best resolution, but will possibly load + a different size image if you mutate the size attribute + before calling 'load'. + + The info dictionary has a key 'sizes' that is a list + of sizes that the icns file has. + """ + + format = "ICNS" + format_description = "Mac OS icns resource" + + def _open(self) -> None: + self.icns = IcnsFile(self.fp) + self._mode = "RGBA" + self.info["sizes"] = self.icns.itersizes() + self.best_size = self.icns.bestsize() + self.size = ( + self.best_size[0] * self.best_size[2], + self.best_size[1] * self.best_size[2], + ) + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + info_size = value + if info_size not in self.info["sizes"] and len(info_size) == 2: + info_size = (info_size[0], info_size[1], 1) + if ( + info_size not in self.info["sizes"] + and len(info_size) == 3 + and info_size[2] == 1 + ): + simple_sizes = [ + (size[0] * size[2], size[1] * size[2]) for size in self.info["sizes"] + ] + if value in simple_sizes: + info_size = self.info["sizes"][simple_sizes.index(value)] + if info_size not in self.info["sizes"]: + msg = "This is not one of the allowed sizes of this image" + raise ValueError(msg) + self._size = value + + def load(self): + if len(self.size) == 3: + self.best_size = self.size + self.size = ( + self.best_size[0] * self.best_size[2], + self.best_size[1] * self.best_size[2], + ) + + px = Image.Image.load(self) + if self.im is not None and self.im.size == self.size: + # Already loaded + return px + self.load_prepare() + # This is likely NOT the best way to do it, but whatever. + im = self.icns.getimage(self.best_size) + + # If this is a PNG or JPEG 2000, it won't be loaded yet + px = im.load() + + self.im = im.im + self._mode = im.mode + self.size = im.size + + return px + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + """ + Saves the image as a series of PNG files, + that are then combined into a .icns file. + """ + if hasattr(fp, "flush"): + fp.flush() + + sizes = { + b"ic07": 128, + b"ic08": 256, + b"ic09": 512, + b"ic10": 1024, + b"ic11": 32, + b"ic12": 64, + b"ic13": 256, + b"ic14": 512, + } + provided_images = {im.width: im for im in im.encoderinfo.get("append_images", [])} + size_streams = {} + for size in set(sizes.values()): + image = ( + provided_images[size] + if size in provided_images + else im.resize((size, size)) + ) + + temp = io.BytesIO() + image.save(temp, "png") + size_streams[size] = temp.getvalue() + + entries = [] + for type, size in sizes.items(): + stream = size_streams[size] + entries.append((type, HEADERSIZE + len(stream), stream)) + + # Header + fp.write(MAGIC) + file_length = HEADERSIZE # Header + file_length += HEADERSIZE + 8 * len(entries) # TOC + file_length += sum(entry[1] for entry in entries) + fp.write(struct.pack(">i", file_length)) + + # TOC + fp.write(b"TOC ") + fp.write(struct.pack(">i", HEADERSIZE + len(entries) * HEADERSIZE)) + for entry in entries: + fp.write(entry[0]) + fp.write(struct.pack(">i", entry[1])) + + # Data + for entry in entries: + fp.write(entry[0]) + fp.write(struct.pack(">i", entry[1])) + fp.write(entry[2]) + + if hasattr(fp, "flush"): + fp.flush() + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == MAGIC + + +Image.register_open(IcnsImageFile.format, IcnsImageFile, _accept) +Image.register_extension(IcnsImageFile.format, ".icns") + +Image.register_save(IcnsImageFile.format, _save) +Image.register_mime(IcnsImageFile.format, "image/icns") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Syntax: python3 IcnsImagePlugin.py [file]") + sys.exit() + + with open(sys.argv[1], "rb") as fp: + imf = IcnsImageFile(fp) + for size in imf.info["sizes"]: + width, height, scale = imf.size = size + imf.save(f"out-{width}-{height}-{scale}.png") + with Image.open(sys.argv[1]) as im: + im.save("out.png") + if sys.platform == "windows": + os.startfile("out.png") diff --git a/.venv/lib/python3.12/site-packages/PIL/IcoImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/IcoImagePlugin.py new file mode 100644 index 0000000..227fcf3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/IcoImagePlugin.py @@ -0,0 +1,360 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Windows Icon support for PIL +# +# History: +# 96-05-27 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# + +# This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis +# . +# https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki +# +# Icon format references: +# * https://en.wikipedia.org/wiki/ICO_(file_format) +# * https://msdn.microsoft.com/en-us/library/ms997538.aspx +from __future__ import annotations + +import warnings +from io import BytesIO +from math import ceil, log +from typing import IO + +from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin +from ._binary import i16le as i16 +from ._binary import i32le as i32 +from ._binary import o8 +from ._binary import o16le as o16 +from ._binary import o32le as o32 + +# +# -------------------------------------------------------------------- + +_MAGIC = b"\0\0\1\0" + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + fp.write(_MAGIC) # (2+2) + bmp = im.encoderinfo.get("bitmap_format") == "bmp" + sizes = im.encoderinfo.get( + "sizes", + [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)], + ) + frames = [] + provided_ims = [im] + im.encoderinfo.get("append_images", []) + width, height = im.size + for size in sorted(set(sizes)): + if size[0] > width or size[1] > height or size[0] > 256 or size[1] > 256: + continue + + for provided_im in provided_ims: + if provided_im.size != size: + continue + frames.append(provided_im) + if bmp: + bits = BmpImagePlugin.SAVE[provided_im.mode][1] + bits_used = [bits] + for other_im in provided_ims: + if other_im.size != size: + continue + bits = BmpImagePlugin.SAVE[other_im.mode][1] + if bits not in bits_used: + # Another image has been supplied for this size + # with a different bit depth + frames.append(other_im) + bits_used.append(bits) + break + else: + # TODO: invent a more convenient method for proportional scalings + frame = provided_im.copy() + frame.thumbnail(size, Image.Resampling.LANCZOS, reducing_gap=None) + frames.append(frame) + fp.write(o16(len(frames))) # idCount(2) + offset = fp.tell() + len(frames) * 16 + for frame in frames: + width, height = frame.size + # 0 means 256 + fp.write(o8(width if width < 256 else 0)) # bWidth(1) + fp.write(o8(height if height < 256 else 0)) # bHeight(1) + + bits, colors = BmpImagePlugin.SAVE[frame.mode][1:] if bmp else (32, 0) + fp.write(o8(colors)) # bColorCount(1) + fp.write(b"\0") # bReserved(1) + fp.write(b"\0\0") # wPlanes(2) + fp.write(o16(bits)) # wBitCount(2) + + image_io = BytesIO() + if bmp: + frame.save(image_io, "dib") + + if bits != 32: + and_mask = Image.new("1", size) + ImageFile._save( + and_mask, image_io, [("raw", (0, 0) + size, 0, ("1", 0, -1))] + ) + else: + frame.save(image_io, "png") + image_io.seek(0) + image_bytes = image_io.read() + if bmp: + image_bytes = image_bytes[:8] + o32(height * 2) + image_bytes[12:] + bytes_len = len(image_bytes) + fp.write(o32(bytes_len)) # dwBytesInRes(4) + fp.write(o32(offset)) # dwImageOffset(4) + current = fp.tell() + fp.seek(offset) + fp.write(image_bytes) + offset = offset + bytes_len + fp.seek(current) + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == _MAGIC + + +class IcoFile: + def __init__(self, buf): + """ + Parse image from file-like object containing ico file data + """ + + # check magic + s = buf.read(6) + if not _accept(s): + msg = "not an ICO file" + raise SyntaxError(msg) + + self.buf = buf + self.entry = [] + + # Number of items in file + self.nb_items = i16(s, 4) + + # Get headers for each item + for i in range(self.nb_items): + s = buf.read(16) + + icon_header = { + "width": s[0], + "height": s[1], + "nb_color": s[2], # No. of colors in image (0 if >=8bpp) + "reserved": s[3], + "planes": i16(s, 4), + "bpp": i16(s, 6), + "size": i32(s, 8), + "offset": i32(s, 12), + } + + # See Wikipedia + for j in ("width", "height"): + if not icon_header[j]: + icon_header[j] = 256 + + # See Wikipedia notes about color depth. + # We need this just to differ images with equal sizes + icon_header["color_depth"] = ( + icon_header["bpp"] + or ( + icon_header["nb_color"] != 0 + and ceil(log(icon_header["nb_color"], 2)) + ) + or 256 + ) + + icon_header["dim"] = (icon_header["width"], icon_header["height"]) + icon_header["square"] = icon_header["width"] * icon_header["height"] + + self.entry.append(icon_header) + + self.entry = sorted(self.entry, key=lambda x: x["color_depth"]) + # ICO images are usually squares + self.entry = sorted(self.entry, key=lambda x: x["square"], reverse=True) + + def sizes(self): + """ + Get a list of all available icon sizes and color depths. + """ + return {(h["width"], h["height"]) for h in self.entry} + + def getentryindex(self, size, bpp=False): + for i, h in enumerate(self.entry): + if size == h["dim"] and (bpp is False or bpp == h["color_depth"]): + return i + return 0 + + def getimage(self, size, bpp=False): + """ + Get an image from the icon + """ + return self.frame(self.getentryindex(size, bpp)) + + def frame(self, idx: int) -> Image.Image: + """ + Get an image from frame idx + """ + + header = self.entry[idx] + + self.buf.seek(header["offset"]) + data = self.buf.read(8) + self.buf.seek(header["offset"]) + + im: Image.Image + if data[:8] == PngImagePlugin._MAGIC: + # png frame + im = PngImagePlugin.PngImageFile(self.buf) + Image._decompression_bomb_check(im.size) + else: + # XOR + AND mask bmp frame + im = BmpImagePlugin.DibImageFile(self.buf) + Image._decompression_bomb_check(im.size) + + # change tile dimension to only encompass XOR image + im._size = (im.size[0], int(im.size[1] / 2)) + d, e, o, a = im.tile[0] + im.tile[0] = d, (0, 0) + im.size, o, a + + # figure out where AND mask image starts + bpp = header["bpp"] + if 32 == bpp: + # 32-bit color depth icon image allows semitransparent areas + # PIL's DIB format ignores transparency bits, recover them. + # The DIB is packed in BGRX byte order where X is the alpha + # channel. + + # Back up to start of bmp data + self.buf.seek(o) + # extract every 4th byte (eg. 3,7,11,15,...) + alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4] + + # convert to an 8bpp grayscale image + mask = Image.frombuffer( + "L", # 8bpp + im.size, # (w, h) + alpha_bytes, # source chars + "raw", # raw decoder + ("L", 0, -1), # 8bpp inverted, unpadded, reversed + ) + else: + # get AND image from end of bitmap + w = im.size[0] + if (w % 32) > 0: + # bitmap row data is aligned to word boundaries + w += 32 - (im.size[0] % 32) + + # the total mask data is + # padded row size * height / bits per char + + total_bytes = int((w * im.size[1]) / 8) + and_mask_offset = header["offset"] + header["size"] - total_bytes + + self.buf.seek(and_mask_offset) + mask_data = self.buf.read(total_bytes) + + # convert raw data to image + mask = Image.frombuffer( + "1", # 1 bpp + im.size, # (w, h) + mask_data, # source chars + "raw", # raw decoder + ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed + ) + + # now we have two images, im is XOR image and mask is AND image + + # apply mask image as alpha channel + im = im.convert("RGBA") + im.putalpha(mask) + + return im + + +## +# Image plugin for Windows Icon files. + + +class IcoImageFile(ImageFile.ImageFile): + """ + PIL read-only image support for Microsoft Windows .ico files. + + By default the largest resolution image in the file will be loaded. This + can be changed by altering the 'size' attribute before calling 'load'. + + The info dictionary has a key 'sizes' that is a list of the sizes available + in the icon file. + + Handles classic, XP and Vista icon formats. + + When saving, PNG compression is used. Support for this was only added in + Windows Vista. If you are unable to view the icon in Windows, convert the + image to "RGBA" mode before saving. + + This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis + . + https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki + """ + + format = "ICO" + format_description = "Windows Icon" + + def _open(self) -> None: + self.ico = IcoFile(self.fp) + self.info["sizes"] = self.ico.sizes() + self.size = self.ico.entry[0]["dim"] + self.load() + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + if value not in self.info["sizes"]: + msg = "This is not one of the allowed sizes of this image" + raise ValueError(msg) + self._size = value + + def load(self): + if self.im is not None and self.im.size == self.size: + # Already loaded + return Image.Image.load(self) + im = self.ico.getimage(self.size) + # if tile is PNG, it won't really be loaded yet + im.load() + self.im = im.im + self.pyaccess = None + self._mode = im.mode + if im.palette: + self.palette = im.palette + if im.size != self.size: + warnings.warn("Image was not the expected size") + + index = self.ico.getentryindex(self.size) + sizes = list(self.info["sizes"]) + sizes[index] = im.size + self.info["sizes"] = set(sizes) + + self.size = im.size + + def load_seek(self, pos: int) -> None: + # Flag the ImageFile.Parser so that it + # just does all the decode at the end. + pass + + +# +# -------------------------------------------------------------------- + + +Image.register_open(IcoImageFile.format, IcoImageFile, _accept) +Image.register_save(IcoImageFile.format, _save) +Image.register_extension(IcoImageFile.format, ".ico") + +Image.register_mime(IcoImageFile.format, "image/x-icon") diff --git a/.venv/lib/python3.12/site-packages/PIL/ImImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/ImImagePlugin.py new file mode 100644 index 0000000..2fb7ecd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImImagePlugin.py @@ -0,0 +1,374 @@ +# +# The Python Imaging Library. +# $Id$ +# +# IFUNC IM file handling for PIL +# +# history: +# 1995-09-01 fl Created. +# 1997-01-03 fl Save palette images +# 1997-01-08 fl Added sequence support +# 1997-01-23 fl Added P and RGB save support +# 1997-05-31 fl Read floating point images +# 1997-06-22 fl Save floating point images +# 1997-08-27 fl Read and save 1-bit images +# 1998-06-25 fl Added support for RGB+LUT images +# 1998-07-02 fl Added support for YCC images +# 1998-07-15 fl Renamed offset attribute to avoid name clash +# 1998-12-29 fl Added I;16 support +# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7) +# 2003-09-26 fl Added LA/PA support +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1995-2001 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import os +import re +from typing import IO, Any + +from . import Image, ImageFile, ImagePalette + +# -------------------------------------------------------------------- +# Standard tags + +COMMENT = "Comment" +DATE = "Date" +EQUIPMENT = "Digitalization equipment" +FRAMES = "File size (no of images)" +LUT = "Lut" +NAME = "Name" +SCALE = "Scale (x,y)" +SIZE = "Image size (x*y)" +MODE = "Image type" + +TAGS = { + COMMENT: 0, + DATE: 0, + EQUIPMENT: 0, + FRAMES: 0, + LUT: 0, + NAME: 0, + SCALE: 0, + SIZE: 0, + MODE: 0, +} + +OPEN = { + # ifunc93/p3cfunc formats + "0 1 image": ("1", "1"), + "L 1 image": ("1", "1"), + "Greyscale image": ("L", "L"), + "Grayscale image": ("L", "L"), + "RGB image": ("RGB", "RGB;L"), + "RLB image": ("RGB", "RLB"), + "RYB image": ("RGB", "RLB"), + "B1 image": ("1", "1"), + "B2 image": ("P", "P;2"), + "B4 image": ("P", "P;4"), + "X 24 image": ("RGB", "RGB"), + "L 32 S image": ("I", "I;32"), + "L 32 F image": ("F", "F;32"), + # old p3cfunc formats + "RGB3 image": ("RGB", "RGB;T"), + "RYB3 image": ("RGB", "RYB;T"), + # extensions + "LA image": ("LA", "LA;L"), + "PA image": ("LA", "PA;L"), + "RGBA image": ("RGBA", "RGBA;L"), + "RGBX image": ("RGB", "RGBX;L"), + "CMYK image": ("CMYK", "CMYK;L"), + "YCC image": ("YCbCr", "YCbCr;L"), +} + +# ifunc95 extensions +for i in ["8", "8S", "16", "16S", "32", "32F"]: + OPEN[f"L {i} image"] = ("F", f"F;{i}") + OPEN[f"L*{i} image"] = ("F", f"F;{i}") +for i in ["16", "16L", "16B"]: + OPEN[f"L {i} image"] = (f"I;{i}", f"I;{i}") + OPEN[f"L*{i} image"] = (f"I;{i}", f"I;{i}") +for i in ["32S"]: + OPEN[f"L {i} image"] = ("I", f"I;{i}") + OPEN[f"L*{i} image"] = ("I", f"I;{i}") +for j in range(2, 33): + OPEN[f"L*{j} image"] = ("F", f"F;{j}") + + +# -------------------------------------------------------------------- +# Read IM directory + +split = re.compile(rb"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$") + + +def number(s: Any) -> float: + try: + return int(s) + except ValueError: + return float(s) + + +## +# Image plugin for the IFUNC IM file format. + + +class ImImageFile(ImageFile.ImageFile): + format = "IM" + format_description = "IFUNC Image Memory" + _close_exclusive_fp_after_loading = False + + def _open(self) -> None: + # Quick rejection: if there's not an LF among the first + # 100 bytes, this is (probably) not a text header. + + if b"\n" not in self.fp.read(100): + msg = "not an IM file" + raise SyntaxError(msg) + self.fp.seek(0) + + n = 0 + + # Default values + self.info[MODE] = "L" + self.info[SIZE] = (512, 512) + self.info[FRAMES] = 1 + + self.rawmode = "L" + + while True: + s = self.fp.read(1) + + # Some versions of IFUNC uses \n\r instead of \r\n... + if s == b"\r": + continue + + if not s or s == b"\0" or s == b"\x1A": + break + + # FIXME: this may read whole file if not a text file + s = s + self.fp.readline() + + if len(s) > 100: + msg = "not an IM file" + raise SyntaxError(msg) + + if s[-2:] == b"\r\n": + s = s[:-2] + elif s[-1:] == b"\n": + s = s[:-1] + + try: + m = split.match(s) + except re.error as e: + msg = "not an IM file" + raise SyntaxError(msg) from e + + if m: + k, v = m.group(1, 2) + + # Don't know if this is the correct encoding, + # but a decent guess (I guess) + k = k.decode("latin-1", "replace") + v = v.decode("latin-1", "replace") + + # Convert value as appropriate + if k in [FRAMES, SCALE, SIZE]: + v = v.replace("*", ",") + v = tuple(map(number, v.split(","))) + if len(v) == 1: + v = v[0] + elif k == MODE and v in OPEN: + v, self.rawmode = OPEN[v] + + # Add to dictionary. Note that COMMENT tags are + # combined into a list of strings. + if k == COMMENT: + if k in self.info: + self.info[k].append(v) + else: + self.info[k] = [v] + else: + self.info[k] = v + + if k in TAGS: + n += 1 + + else: + msg = f"Syntax error in IM header: {s.decode('ascii', 'replace')}" + raise SyntaxError(msg) + + if not n: + msg = "Not an IM file" + raise SyntaxError(msg) + + # Basic attributes + self._size = self.info[SIZE] + self._mode = self.info[MODE] + + # Skip forward to start of image data + while s and s[:1] != b"\x1A": + s = self.fp.read(1) + if not s: + msg = "File truncated" + raise SyntaxError(msg) + + if LUT in self.info: + # convert lookup table to palette or lut attribute + palette = self.fp.read(768) + greyscale = 1 # greyscale palette + linear = 1 # linear greyscale palette + for i in range(256): + if palette[i] == palette[i + 256] == palette[i + 512]: + if palette[i] != i: + linear = 0 + else: + greyscale = 0 + if self.mode in ["L", "LA", "P", "PA"]: + if greyscale: + if not linear: + self.lut = list(palette[:256]) + else: + if self.mode in ["L", "P"]: + self._mode = self.rawmode = "P" + elif self.mode in ["LA", "PA"]: + self._mode = "PA" + self.rawmode = "PA;L" + self.palette = ImagePalette.raw("RGB;L", palette) + elif self.mode == "RGB": + if not greyscale or not linear: + self.lut = list(palette) + + self.frame = 0 + + self.__offset = offs = self.fp.tell() + + self._fp = self.fp # FIXME: hack + + if self.rawmode[:2] == "F;": + # ifunc95 formats + try: + # use bit decoder (if necessary) + bits = int(self.rawmode[2:]) + if bits not in [8, 16, 32]: + self.tile = [("bit", (0, 0) + self.size, offs, (bits, 8, 3, 0, -1))] + return + except ValueError: + pass + + if self.rawmode in ["RGB;T", "RYB;T"]: + # Old LabEye/3PC files. Would be very surprised if anyone + # ever stumbled upon such a file ;-) + size = self.size[0] * self.size[1] + self.tile = [ + ("raw", (0, 0) + self.size, offs, ("G", 0, -1)), + ("raw", (0, 0) + self.size, offs + size, ("R", 0, -1)), + ("raw", (0, 0) + self.size, offs + 2 * size, ("B", 0, -1)), + ] + else: + # LabEye/IFUNC files + self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] + + @property + def n_frames(self) -> int: + return self.info[FRAMES] + + @property + def is_animated(self) -> bool: + return self.info[FRAMES] > 1 + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + + self.frame = frame + + if self.mode == "1": + bits = 1 + else: + bits = 8 * len(self.mode) + + size = ((self.size[0] * bits + 7) // 8) * self.size[1] + offs = self.__offset + frame * size + + self.fp = self._fp + + self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] + + def tell(self) -> int: + return self.frame + + +# +# -------------------------------------------------------------------- +# Save IM files + + +SAVE = { + # mode: (im type, raw mode) + "1": ("0 1", "1"), + "L": ("Greyscale", "L"), + "LA": ("LA", "LA;L"), + "P": ("Greyscale", "P"), + "PA": ("LA", "PA;L"), + "I": ("L 32S", "I;32S"), + "I;16": ("L 16", "I;16"), + "I;16L": ("L 16L", "I;16L"), + "I;16B": ("L 16B", "I;16B"), + "F": ("L 32F", "F;32F"), + "RGB": ("RGB", "RGB;L"), + "RGBA": ("RGBA", "RGBA;L"), + "RGBX": ("RGBX", "RGBX;L"), + "CMYK": ("CMYK", "CMYK;L"), + "YCbCr": ("YCC", "YCbCr;L"), +} + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + try: + image_type, rawmode = SAVE[im.mode] + except KeyError as e: + msg = f"Cannot save {im.mode} images as IM" + raise ValueError(msg) from e + + frames = im.encoderinfo.get("frames", 1) + + fp.write(f"Image type: {image_type} image\r\n".encode("ascii")) + if filename: + # Each line must be 100 characters or less, + # or: SyntaxError("not an IM file") + # 8 characters are used for "Name: " and "\r\n" + # Keep just the filename, ditch the potentially overlong path + if isinstance(filename, bytes): + filename = filename.decode("ascii") + name, ext = os.path.splitext(os.path.basename(filename)) + name = "".join([name[: 92 - len(ext)], ext]) + + fp.write(f"Name: {name}\r\n".encode("ascii")) + fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode("ascii")) + fp.write(f"File size (no of images): {frames}\r\n".encode("ascii")) + if im.mode in ["P", "PA"]: + fp.write(b"Lut: 1\r\n") + fp.write(b"\000" * (511 - fp.tell()) + b"\032") + if im.mode in ["P", "PA"]: + im_palette = im.im.getpalette("RGB", "RGB;L") + colors = len(im_palette) // 3 + palette = b"" + for i in range(3): + palette += im_palette[colors * i : colors * (i + 1)] + palette += b"\x00" * (256 - colors) + fp.write(palette) # 768 bytes + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))]) + + +# +# -------------------------------------------------------------------- +# Registry + + +Image.register_open(ImImageFile.format, ImImageFile) +Image.register_save(ImImageFile.format, _save) + +Image.register_extension(ImImageFile.format, ".im") diff --git a/.venv/lib/python3.12/site-packages/PIL/Image.py b/.venv/lib/python3.12/site-packages/PIL/Image.py new file mode 100644 index 0000000..d41c065 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/Image.py @@ -0,0 +1,4147 @@ +# +# The Python Imaging Library. +# $Id$ +# +# the Image class wrapper +# +# partial release history: +# 1995-09-09 fl Created +# 1996-03-11 fl PIL release 0.0 (proof of concept) +# 1996-04-30 fl PIL release 0.1b1 +# 1999-07-28 fl PIL release 1.0 final +# 2000-06-07 fl PIL release 1.1 +# 2000-10-20 fl PIL release 1.1.1 +# 2001-05-07 fl PIL release 1.1.2 +# 2002-03-15 fl PIL release 1.1.3 +# 2003-05-10 fl PIL release 1.1.4 +# 2005-03-28 fl PIL release 1.1.5 +# 2006-12-02 fl PIL release 1.1.6 +# 2009-11-15 fl PIL release 1.1.7 +# +# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved. +# Copyright (c) 1995-2009 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + +from __future__ import annotations + +import abc +import atexit +import builtins +import io +import logging +import math +import os +import re +import struct +import sys +import tempfile +import warnings +from collections.abc import Callable, MutableMapping +from enum import IntEnum +from types import ModuleType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Literal, + Protocol, + Sequence, + Tuple, + cast, +) + +# VERSION was removed in Pillow 6.0.0. +# PILLOW_VERSION was removed in Pillow 9.0.0. +# Use __version__ instead. +from . import ( + ExifTags, + ImageMode, + TiffTags, + UnidentifiedImageError, + __version__, + _plugins, +) +from ._binary import i32le, o32be, o32le +from ._deprecate import deprecate +from ._typing import StrOrBytesPath, TypeGuard +from ._util import DeferredError, is_path + +ElementTree: ModuleType | None +try: + from defusedxml import ElementTree +except ImportError: + ElementTree = None + +logger = logging.getLogger(__name__) + + +class DecompressionBombWarning(RuntimeWarning): + pass + + +class DecompressionBombError(Exception): + pass + + +WARN_POSSIBLE_FORMATS: bool = False + +# Limit to around a quarter gigabyte for a 24-bit (3 bpp) image +MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3) + + +try: + # If the _imaging C module is not present, Pillow will not load. + # Note that other modules should not refer to _imaging directly; + # import Image and use the Image.core variable instead. + # Also note that Image.core is not a publicly documented interface, + # and should be considered private and subject to change. + from . import _imaging as core + + if __version__ != getattr(core, "PILLOW_VERSION", None): + msg = ( + "The _imaging extension was built for another version of Pillow or PIL:\n" + f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n" + f"Pillow version: {__version__}" + ) + raise ImportError(msg) + +except ImportError as v: + core = DeferredError.new(ImportError("The _imaging C module is not installed.")) + # Explanations for ways that we know we might have an import error + if str(v).startswith("Module use of python"): + # The _imaging C module is present, but not compiled for + # the right version (windows only). Print a warning, if + # possible. + warnings.warn( + "The _imaging extension was built for another version of Python.", + RuntimeWarning, + ) + elif str(v).startswith("The _imaging extension"): + warnings.warn(str(v), RuntimeWarning) + # Fail here anyway. Don't let people run with a mostly broken Pillow. + # see docs/porting.rst + raise + + +USE_CFFI_ACCESS = False +cffi: ModuleType | None +try: + import cffi +except ImportError: + cffi = None + + +def isImageType(t: Any) -> TypeGuard[Image]: + """ + Checks if an object is an image object. + + .. warning:: + + This function is for internal use only. + + :param t: object to check if it's an image + :returns: True if the object is an image + """ + return hasattr(t, "im") + + +# +# Constants + + +# transpose +class Transpose(IntEnum): + FLIP_LEFT_RIGHT = 0 + FLIP_TOP_BOTTOM = 1 + ROTATE_90 = 2 + ROTATE_180 = 3 + ROTATE_270 = 4 + TRANSPOSE = 5 + TRANSVERSE = 6 + + +# transforms (also defined in Imaging.h) +class Transform(IntEnum): + AFFINE = 0 + EXTENT = 1 + PERSPECTIVE = 2 + QUAD = 3 + MESH = 4 + + +# resampling filters (also defined in Imaging.h) +class Resampling(IntEnum): + NEAREST = 0 + BOX = 4 + BILINEAR = 2 + HAMMING = 5 + BICUBIC = 3 + LANCZOS = 1 + + +_filters_support = { + Resampling.BOX: 0.5, + Resampling.BILINEAR: 1.0, + Resampling.HAMMING: 1.0, + Resampling.BICUBIC: 2.0, + Resampling.LANCZOS: 3.0, +} + + +# dithers +class Dither(IntEnum): + NONE = 0 + ORDERED = 1 # Not yet implemented + RASTERIZE = 2 # Not yet implemented + FLOYDSTEINBERG = 3 # default + + +# palettes/quantizers +class Palette(IntEnum): + WEB = 0 + ADAPTIVE = 1 + + +class Quantize(IntEnum): + MEDIANCUT = 0 + MAXCOVERAGE = 1 + FASTOCTREE = 2 + LIBIMAGEQUANT = 3 + + +module = sys.modules[__name__] +for enum in (Transpose, Transform, Resampling, Dither, Palette, Quantize): + for item in enum: + setattr(module, item.name, item.value) + + +if hasattr(core, "DEFAULT_STRATEGY"): + DEFAULT_STRATEGY = core.DEFAULT_STRATEGY + FILTERED = core.FILTERED + HUFFMAN_ONLY = core.HUFFMAN_ONLY + RLE = core.RLE + FIXED = core.FIXED + + +# -------------------------------------------------------------------- +# Registries + +if TYPE_CHECKING: + from . import ImageFile, PyAccess +ID: list[str] = [] +OPEN: dict[ + str, + tuple[ + Callable[[IO[bytes], str | bytes], ImageFile.ImageFile], + Callable[[bytes], bool | str] | None, + ], +] = {} +MIME: dict[str, str] = {} +SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {} +SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {} +EXTENSION: dict[str, str] = {} +DECODERS: dict[str, type[ImageFile.PyDecoder]] = {} +ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {} + +# -------------------------------------------------------------------- +# Modes + +_ENDIAN = "<" if sys.byteorder == "little" else ">" + + +def _conv_type_shape(im): + m = ImageMode.getmode(im.mode) + shape = (im.height, im.width) + extra = len(m.bands) + if extra != 1: + shape += (extra,) + return shape, m.typestr + + +MODES = [ + "1", + "CMYK", + "F", + "HSV", + "I", + "I;16", + "I;16B", + "I;16L", + "I;16N", + "L", + "LA", + "La", + "LAB", + "P", + "PA", + "RGB", + "RGBA", + "RGBa", + "RGBX", + "YCbCr", +] + +# raw modes that may be memory mapped. NOTE: if you change this, you +# may have to modify the stride calculation in map.c too! +_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B") + + +def getmodebase(mode: str) -> str: + """ + Gets the "base" mode for given mode. This function returns "L" for + images that contain grayscale data, and "RGB" for images that + contain color data. + + :param mode: Input mode. + :returns: "L" or "RGB". + :exception KeyError: If the input mode was not a standard mode. + """ + return ImageMode.getmode(mode).basemode + + +def getmodetype(mode: str) -> str: + """ + Gets the storage type mode. Given a mode, this function returns a + single-layer mode suitable for storing individual bands. + + :param mode: Input mode. + :returns: "L", "I", or "F". + :exception KeyError: If the input mode was not a standard mode. + """ + return ImageMode.getmode(mode).basetype + + +def getmodebandnames(mode: str) -> tuple[str, ...]: + """ + Gets a list of individual band names. Given a mode, this function returns + a tuple containing the names of individual bands (use + :py:method:`~PIL.Image.getmodetype` to get the mode used to store each + individual band. + + :param mode: Input mode. + :returns: A tuple containing band names. The length of the tuple + gives the number of bands in an image of the given mode. + :exception KeyError: If the input mode was not a standard mode. + """ + return ImageMode.getmode(mode).bands + + +def getmodebands(mode: str) -> int: + """ + Gets the number of individual bands for this mode. + + :param mode: Input mode. + :returns: The number of bands in this mode. + :exception KeyError: If the input mode was not a standard mode. + """ + return len(ImageMode.getmode(mode).bands) + + +# -------------------------------------------------------------------- +# Helpers + +_initialized = 0 + + +def preinit() -> None: + """ + Explicitly loads BMP, GIF, JPEG, PPM and PPM file format drivers. + + It is called when opening or saving images. + """ + + global _initialized + if _initialized >= 1: + return + + try: + from . import BmpImagePlugin + + assert BmpImagePlugin + except ImportError: + pass + try: + from . import GifImagePlugin + + assert GifImagePlugin + except ImportError: + pass + try: + from . import JpegImagePlugin + + assert JpegImagePlugin + except ImportError: + pass + try: + from . import PpmImagePlugin + + assert PpmImagePlugin + except ImportError: + pass + try: + from . import PngImagePlugin + + assert PngImagePlugin + except ImportError: + pass + + _initialized = 1 + + +def init() -> bool: + """ + Explicitly initializes the Python Imaging Library. This function + loads all available file format drivers. + + It is called when opening or saving images if :py:meth:`~preinit()` is + insufficient, and by :py:meth:`~PIL.features.pilinfo`. + """ + + global _initialized + if _initialized >= 2: + return False + + parent_name = __name__.rpartition(".")[0] + for plugin in _plugins: + try: + logger.debug("Importing %s", plugin) + __import__(f"{parent_name}.{plugin}", globals(), locals(), []) + except ImportError as e: + logger.debug("Image: failed to import %s: %s", plugin, e) + + if OPEN or SAVE: + _initialized = 2 + return True + return False + + +# -------------------------------------------------------------------- +# Codec factories (used by tobytes/frombytes and ImageFile.load) + + +def _getdecoder( + mode: str, decoder_name: str, args: Any, extra: tuple[Any, ...] = () +) -> core.ImagingDecoder | ImageFile.PyDecoder: + # tweak arguments + if args is None: + args = () + elif not isinstance(args, tuple): + args = (args,) + + try: + decoder = DECODERS[decoder_name] + except KeyError: + pass + else: + return decoder(mode, *args + extra) + + try: + # get decoder + decoder = getattr(core, f"{decoder_name}_decoder") + except AttributeError as e: + msg = f"decoder {decoder_name} not available" + raise OSError(msg) from e + return decoder(mode, *args + extra) + + +def _getencoder( + mode: str, encoder_name: str, args: Any, extra: tuple[Any, ...] = () +) -> core.ImagingEncoder | ImageFile.PyEncoder: + # tweak arguments + if args is None: + args = () + elif not isinstance(args, tuple): + args = (args,) + + try: + encoder = ENCODERS[encoder_name] + except KeyError: + pass + else: + return encoder(mode, *args + extra) + + try: + # get encoder + encoder = getattr(core, f"{encoder_name}_encoder") + except AttributeError as e: + msg = f"encoder {encoder_name} not available" + raise OSError(msg) from e + return encoder(mode, *args + extra) + + +# -------------------------------------------------------------------- +# Simple expression analyzer + + +class _E: + def __init__(self, scale, offset) -> None: + self.scale = scale + self.offset = offset + + def __neg__(self): + return _E(-self.scale, -self.offset) + + def __add__(self, other): + if isinstance(other, _E): + return _E(self.scale + other.scale, self.offset + other.offset) + return _E(self.scale, self.offset + other) + + __radd__ = __add__ + + def __sub__(self, other): + return self + -other + + def __rsub__(self, other): + return other + -self + + def __mul__(self, other): + if isinstance(other, _E): + return NotImplemented + return _E(self.scale * other, self.offset * other) + + __rmul__ = __mul__ + + def __truediv__(self, other): + if isinstance(other, _E): + return NotImplemented + return _E(self.scale / other, self.offset / other) + + +def _getscaleoffset(expr): + a = expr(_E(1, 0)) + return (a.scale, a.offset) if isinstance(a, _E) else (0, a) + + +# -------------------------------------------------------------------- +# Implementation wrapper + + +class SupportsGetData(Protocol): + def getdata( + self, + ) -> tuple[Transform, Sequence[int]]: ... + + +class Image: + """ + This class represents an image object. To create + :py:class:`~PIL.Image.Image` objects, use the appropriate factory + functions. There's hardly ever any reason to call the Image constructor + directly. + + * :py:func:`~PIL.Image.open` + * :py:func:`~PIL.Image.new` + * :py:func:`~PIL.Image.frombytes` + """ + + format: str | None = None + format_description: str | None = None + _close_exclusive_fp_after_loading = True + + def __init__(self): + # FIXME: take "new" parameters / other image? + # FIXME: turn mode and size into delegating properties? + self.im = None + self._mode = "" + self._size = (0, 0) + self.palette = None + self.info = {} + self.readonly = 0 + self.pyaccess = None + self._exif = None + + @property + def width(self) -> int: + return self.size[0] + + @property + def height(self) -> int: + return self.size[1] + + @property + def size(self) -> tuple[int, int]: + return self._size + + @property + def mode(self) -> str: + return self._mode + + def _new(self, im: core.ImagingCore) -> Image: + new = Image() + new.im = im + new._mode = im.mode + new._size = im.size + if im.mode in ("P", "PA"): + if self.palette: + new.palette = self.palette.copy() + else: + from . import ImagePalette + + new.palette = ImagePalette.ImagePalette() + new.info = self.info.copy() + return new + + # Context manager support + def __enter__(self): + return self + + def _close_fp(self): + if getattr(self, "_fp", False): + if self._fp != self.fp: + self._fp.close() + self._fp = DeferredError(ValueError("Operation on closed image")) + if self.fp: + self.fp.close() + + def __exit__(self, *args): + if hasattr(self, "fp"): + if getattr(self, "_exclusive_fp", False): + self._close_fp() + self.fp = None + + def close(self) -> None: + """ + Closes the file pointer, if possible. + + This operation will destroy the image core and release its memory. + The image data will be unusable afterward. + + This function is required to close images that have multiple frames or + have not had their file read and closed by the + :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for + more information. + """ + if hasattr(self, "fp"): + try: + self._close_fp() + self.fp = None + except Exception as msg: + logger.debug("Error closing: %s", msg) + + if getattr(self, "map", None): + self.map = None + + # Instead of simply setting to None, we're setting up a + # deferred error that will better explain that the core image + # object is gone. + self.im = DeferredError(ValueError("Operation on closed image")) + + def _copy(self) -> None: + self.load() + self.im = self.im.copy() + self.pyaccess = None + self.readonly = 0 + + def _ensure_mutable(self) -> None: + if self.readonly: + self._copy() + else: + self.load() + + def _dump( + self, file: str | None = None, format: str | None = None, **options: Any + ) -> str: + suffix = "" + if format: + suffix = f".{format}" + + if not file: + f, filename = tempfile.mkstemp(suffix) + os.close(f) + else: + filename = file + if not filename.endswith(suffix): + filename = filename + suffix + + self.load() + + if not format or format == "PPM": + self.im.save_ppm(filename) + else: + self.save(filename, format, **options) + + return filename + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return False + assert isinstance(other, Image) + return ( + self.mode == other.mode + and self.size == other.size + and self.info == other.info + and self.getpalette() == other.getpalette() + and self.tobytes() == other.tobytes() + ) + + def __repr__(self) -> str: + return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( + self.__class__.__module__, + self.__class__.__name__, + self.mode, + self.size[0], + self.size[1], + id(self), + ) + + def _repr_pretty_(self, p, cycle) -> None: + """IPython plain text display support""" + + # Same as __repr__ but without unpredictable id(self), + # to keep Jupyter notebook `text/plain` output stable. + p.text( + "<%s.%s image mode=%s size=%dx%d>" + % ( + self.__class__.__module__, + self.__class__.__name__, + self.mode, + self.size[0], + self.size[1], + ) + ) + + def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None: + """Helper function for iPython display hook. + + :param image_format: Image format. + :returns: image as bytes, saved into the given format. + """ + b = io.BytesIO() + try: + self.save(b, image_format, **kwargs) + except Exception: + return None + return b.getvalue() + + def _repr_png_(self) -> bytes | None: + """iPython display hook support for PNG format. + + :returns: PNG version of the image as bytes + """ + return self._repr_image("PNG", compress_level=1) + + def _repr_jpeg_(self) -> bytes | None: + """iPython display hook support for JPEG format. + + :returns: JPEG version of the image as bytes + """ + return self._repr_image("JPEG") + + @property + def __array_interface__(self): + # numpy array interface support + new = {"version": 3} + try: + if self.mode == "1": + # Binary images need to be extended from bits to bytes + # See: https://github.com/python-pillow/Pillow/issues/350 + new["data"] = self.tobytes("raw", "L") + else: + new["data"] = self.tobytes() + except Exception as e: + if not isinstance(e, (MemoryError, RecursionError)): + try: + import numpy + from packaging.version import parse as parse_version + except ImportError: + pass + else: + if parse_version(numpy.__version__) < parse_version("1.23"): + warnings.warn(str(e)) + raise + new["shape"], new["typestr"] = _conv_type_shape(self) + return new + + def __getstate__(self): + im_data = self.tobytes() # load image first + return [self.info, self.mode, self.size, self.getpalette(), im_data] + + def __setstate__(self, state) -> None: + Image.__init__(self) + info, mode, size, palette, data = state + self.info = info + self._mode = mode + self._size = size + self.im = core.new(mode, size) + if mode in ("L", "LA", "P", "PA") and palette: + self.putpalette(palette) + self.frombytes(data) + + def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes: + """ + Return image as a bytes object. + + .. warning:: + + This method returns the raw image data from the internal + storage. For compressed image data (e.g. PNG, JPEG) use + :meth:`~.save`, with a BytesIO parameter for in-memory + data. + + :param encoder_name: What encoder to use. The default is to + use the standard "raw" encoder. + + A list of C encoders can be seen under + codecs section of the function array in + :file:`_imaging.c`. Python encoders are + registered within the relevant plugins. + :param args: Extra arguments to the encoder. + :returns: A :py:class:`bytes` object. + """ + + encoder_args: Any = args + if len(encoder_args) == 1 and isinstance(encoder_args[0], tuple): + # may pass tuple instead of argument list + encoder_args = encoder_args[0] + + if encoder_name == "raw" and encoder_args == (): + encoder_args = self.mode + + self.load() + + if self.width == 0 or self.height == 0: + return b"" + + # unpack data + e = _getencoder(self.mode, encoder_name, encoder_args) + e.setimage(self.im) + + bufsize = max(65536, self.size[0] * 4) # see RawEncode.c + + output = [] + while True: + bytes_consumed, errcode, data = e.encode(bufsize) + output.append(data) + if errcode: + break + if errcode < 0: + msg = f"encoder error {errcode} in tobytes" + raise RuntimeError(msg) + + return b"".join(output) + + def tobitmap(self, name: str = "image") -> bytes: + """ + Returns the image converted to an X11 bitmap. + + .. note:: This method only works for mode "1" images. + + :param name: The name prefix to use for the bitmap variables. + :returns: A string containing an X11 bitmap. + :raises ValueError: If the mode is not "1" + """ + + self.load() + if self.mode != "1": + msg = "not a bitmap" + raise ValueError(msg) + data = self.tobytes("xbm") + return b"".join( + [ + f"#define {name}_width {self.size[0]}\n".encode("ascii"), + f"#define {name}_height {self.size[1]}\n".encode("ascii"), + f"static char {name}_bits[] = {{\n".encode("ascii"), + data, + b"};", + ] + ) + + def frombytes( + self, data: bytes | bytearray, decoder_name: str = "raw", *args: Any + ) -> None: + """ + Loads this image with pixel data from a bytes object. + + This method is similar to the :py:func:`~PIL.Image.frombytes` function, + but loads data into this image instead of creating a new image object. + """ + + if self.width == 0 or self.height == 0: + return + + decoder_args: Any = args + if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): + # may pass tuple instead of argument list + decoder_args = decoder_args[0] + + # default format + if decoder_name == "raw" and decoder_args == (): + decoder_args = self.mode + + # unpack data + d = _getdecoder(self.mode, decoder_name, decoder_args) + d.setimage(self.im) + s = d.decode(data) + + if s[0] >= 0: + msg = "not enough image data" + raise ValueError(msg) + if s[1] != 0: + msg = "cannot decode image data" + raise ValueError(msg) + + def load(self) -> core.PixelAccess | PyAccess.PyAccess | None: + """ + Allocates storage for the image and loads the pixel data. In + normal cases, you don't need to call this method, since the + Image class automatically loads an opened image when it is + accessed for the first time. + + If the file associated with the image was opened by Pillow, then this + method will close it. The exception to this is if the image has + multiple frames, in which case the file will be left open for seek + operations. See :ref:`file-handling` for more information. + + :returns: An image access object. + :rtype: :py:class:`.PixelAccess` or :py:class:`.PyAccess` + """ + if self.im is not None and self.palette and self.palette.dirty: + # realize palette + mode, arr = self.palette.getdata() + self.im.putpalette(self.palette.mode, mode, arr) + self.palette.dirty = 0 + self.palette.rawmode = None + if "transparency" in self.info and mode in ("LA", "PA"): + if isinstance(self.info["transparency"], int): + self.im.putpalettealpha(self.info["transparency"], 0) + else: + self.im.putpalettealphas(self.info["transparency"]) + self.palette.mode = "RGBA" + else: + self.palette.palette = self.im.getpalette( + self.palette.mode, self.palette.mode + ) + + if self.im is not None: + if cffi and USE_CFFI_ACCESS: + if self.pyaccess: + return self.pyaccess + from . import PyAccess + + self.pyaccess = PyAccess.new(self, self.readonly) + if self.pyaccess: + return self.pyaccess + return self.im.pixel_access(self.readonly) + return None + + def verify(self) -> None: + """ + Verifies the contents of a file. For data read from a file, this + method attempts to determine if the file is broken, without + actually decoding the image data. If this method finds any + problems, it raises suitable exceptions. If you need to load + the image after using this method, you must reopen the image + file. + """ + pass + + def convert( + self, + mode: str | None = None, + matrix: tuple[float, ...] | None = None, + dither: Dither | None = None, + palette: Palette = Palette.WEB, + colors: int = 256, + ) -> Image: + """ + Returns a converted copy of this image. For the "P" mode, this + method translates pixels through the palette. If mode is + omitted, a mode is chosen so that all information in the image + and the palette can be represented without a palette. + + This supports all possible conversions between "L", "RGB" and "CMYK". The + ``matrix`` argument only supports "L" and "RGB". + + When translating a color image to grayscale (mode "L"), + the library uses the ITU-R 601-2 luma transform:: + + L = R * 299/1000 + G * 587/1000 + B * 114/1000 + + The default method of converting a grayscale ("L") or "RGB" + image into a bilevel (mode "1") image uses Floyd-Steinberg + dither to approximate the original image luminosity levels. If + dither is ``None``, all values larger than 127 are set to 255 (white), + all other values to 0 (black). To use other thresholds, use the + :py:meth:`~PIL.Image.Image.point` method. + + When converting from "RGBA" to "P" without a ``matrix`` argument, + this passes the operation to :py:meth:`~PIL.Image.Image.quantize`, + and ``dither`` and ``palette`` are ignored. + + When converting from "PA", if an "RGBA" palette is present, the alpha + channel from the image will be used instead of the values from the palette. + + :param mode: The requested mode. See: :ref:`concept-modes`. + :param matrix: An optional conversion matrix. If given, this + should be 4- or 12-tuple containing floating point values. + :param dither: Dithering method, used when converting from + mode "RGB" to "P" or from "RGB" or "L" to "1". + Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` + (default). Note that this is not used when ``matrix`` is supplied. + :param palette: Palette to use when converting from mode "RGB" + to "P". Available palettes are :data:`Palette.WEB` or + :data:`Palette.ADAPTIVE`. + :param colors: Number of colors to use for the :data:`Palette.ADAPTIVE` + palette. Defaults to 256. + :rtype: :py:class:`~PIL.Image.Image` + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) + + self.load() + + has_transparency = "transparency" in self.info + if not mode and self.mode == "P": + # determine default mode + if self.palette: + mode = self.palette.mode + else: + mode = "RGB" + if mode == "RGB" and has_transparency: + mode = "RGBA" + if not mode or (mode == self.mode and not matrix): + return self.copy() + + if matrix: + # matrix conversion + if mode not in ("L", "RGB"): + msg = "illegal conversion" + raise ValueError(msg) + im = self.im.convert_matrix(mode, matrix) + new_im = self._new(im) + if has_transparency and self.im.bands == 3: + transparency = new_im.info["transparency"] + + def convert_transparency( + m: tuple[float, ...], v: tuple[int, int, int] + ) -> int: + value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5 + return max(0, min(255, int(value))) + + if mode == "L": + transparency = convert_transparency(matrix, transparency) + elif len(mode) == 3: + transparency = tuple( + convert_transparency(matrix[i * 4 : i * 4 + 4], transparency) + for i in range(0, len(transparency)) + ) + new_im.info["transparency"] = transparency + return new_im + + if mode == "P" and self.mode == "RGBA": + return self.quantize(colors) + + trns = None + delete_trns = False + # transparency handling + if has_transparency: + if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or ( + self.mode == "RGB" and mode in ("La", "LA", "RGBa", "RGBA") + ): + # Use transparent conversion to promote from transparent + # color to an alpha channel. + new_im = self._new( + self.im.convert_transparent(mode, self.info["transparency"]) + ) + del new_im.info["transparency"] + return new_im + elif self.mode in ("L", "RGB", "P") and mode in ("L", "RGB", "P"): + t = self.info["transparency"] + if isinstance(t, bytes): + # Dragons. This can't be represented by a single color + warnings.warn( + "Palette images with Transparency expressed in bytes should be " + "converted to RGBA images" + ) + delete_trns = True + else: + # get the new transparency color. + # use existing conversions + trns_im = new(self.mode, (1, 1)) + if self.mode == "P": + trns_im.putpalette(self.palette) + if isinstance(t, tuple): + err = "Couldn't allocate a palette color for transparency" + try: + t = trns_im.palette.getcolor(t, self) + except ValueError as e: + if str(e) == "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + t = None + else: + raise ValueError(err) from e + if t is None: + trns = None + else: + trns_im.putpixel((0, 0), t) + + if mode in ("L", "RGB"): + trns_im = trns_im.convert(mode) + else: + # can't just retrieve the palette number, got to do it + # after quantization. + trns_im = trns_im.convert("RGB") + trns = trns_im.getpixel((0, 0)) + + elif self.mode == "P" and mode in ("LA", "PA", "RGBA"): + t = self.info["transparency"] + delete_trns = True + + if isinstance(t, bytes): + self.im.putpalettealphas(t) + elif isinstance(t, int): + self.im.putpalettealpha(t, 0) + else: + msg = "Transparency for P mode should be bytes or int" + raise ValueError(msg) + + if mode == "P" and palette == Palette.ADAPTIVE: + im = self.im.quantize(colors) + new_im = self._new(im) + from . import ImagePalette + + new_im.palette = ImagePalette.ImagePalette( + "RGB", new_im.im.getpalette("RGB") + ) + if delete_trns: + # This could possibly happen if we requantize to fewer colors. + # The transparency would be totally off in that case. + del new_im.info["transparency"] + if trns is not None: + try: + new_im.info["transparency"] = new_im.palette.getcolor( + cast(Tuple[int, ...], trns), # trns was converted to RGB + new_im, + ) + except Exception: + # if we can't make a transparent color, don't leave the old + # transparency hanging around to mess us up. + del new_im.info["transparency"] + warnings.warn("Couldn't allocate palette entry for transparency") + return new_im + + if "LAB" in (self.mode, mode): + other_mode = mode if self.mode == "LAB" else self.mode + if other_mode in ("RGB", "RGBA", "RGBX"): + from . import ImageCms + + srgb = ImageCms.createProfile("sRGB") + lab = ImageCms.createProfile("LAB") + profiles = [lab, srgb] if self.mode == "LAB" else [srgb, lab] + transform = ImageCms.buildTransform( + profiles[0], profiles[1], self.mode, mode + ) + return transform.apply(self) + + # colorspace conversion + if dither is None: + dither = Dither.FLOYDSTEINBERG + + try: + im = self.im.convert(mode, dither) + except ValueError: + try: + # normalize source image and try again + modebase = getmodebase(self.mode) + if modebase == self.mode: + raise + im = self.im.convert(modebase) + im = im.convert(mode, dither) + except KeyError as e: + msg = "illegal conversion" + raise ValueError(msg) from e + + new_im = self._new(im) + if mode == "P" and palette != Palette.ADAPTIVE: + from . import ImagePalette + + new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB")) + if delete_trns: + # crash fail if we leave a bytes transparency in an rgb/l mode. + del new_im.info["transparency"] + if trns is not None: + if new_im.mode == "P" and new_im.palette: + try: + new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) + except ValueError as e: + del new_im.info["transparency"] + if str(e) != "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + warnings.warn( + "Couldn't allocate palette entry for transparency" + ) + else: + new_im.info["transparency"] = trns + return new_im + + def quantize( + self, + colors: int = 256, + method: int | None = None, + kmeans: int = 0, + palette=None, + dither: Dither = Dither.FLOYDSTEINBERG, + ) -> Image: + """ + Convert the image to 'P' mode with the specified number + of colors. + + :param colors: The desired number of colors, <= 256 + :param method: :data:`Quantize.MEDIANCUT` (median cut), + :data:`Quantize.MAXCOVERAGE` (maximum coverage), + :data:`Quantize.FASTOCTREE` (fast octree), + :data:`Quantize.LIBIMAGEQUANT` (libimagequant; check support + using :py:func:`PIL.features.check_feature` with + ``feature="libimagequant"``). + + By default, :data:`Quantize.MEDIANCUT` will be used. + + The exception to this is RGBA images. :data:`Quantize.MEDIANCUT` + and :data:`Quantize.MAXCOVERAGE` do not support RGBA images, so + :data:`Quantize.FASTOCTREE` is used by default instead. + :param kmeans: Integer greater than or equal to zero. + :param palette: Quantize to the palette of given + :py:class:`PIL.Image.Image`. + :param dither: Dithering method, used when converting from + mode "RGB" to "P" or from "RGB" or "L" to "1". + Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` + (default). + :returns: A new image + """ + + self.load() + + if method is None: + # defaults: + method = Quantize.MEDIANCUT + if self.mode == "RGBA": + method = Quantize.FASTOCTREE + + if self.mode == "RGBA" and method not in ( + Quantize.FASTOCTREE, + Quantize.LIBIMAGEQUANT, + ): + # Caller specified an invalid mode. + msg = ( + "Fast Octree (method == 2) and libimagequant (method == 3) " + "are the only valid methods for quantizing RGBA images" + ) + raise ValueError(msg) + + if palette: + # use palette from reference image + palette.load() + if palette.mode != "P": + msg = "bad mode for palette image" + raise ValueError(msg) + if self.mode not in {"RGB", "L"}: + msg = "only RGB or L mode images can be quantized to a palette" + raise ValueError(msg) + im = self.im.convert("P", dither, palette.im) + new_im = self._new(im) + new_im.palette = palette.palette.copy() + return new_im + + if kmeans < 0: + msg = "kmeans must not be negative" + raise ValueError(msg) + + im = self._new(self.im.quantize(colors, method, kmeans)) + + from . import ImagePalette + + mode = im.im.getpalettemode() + palette = im.im.getpalette(mode, mode)[: colors * len(mode)] + im.palette = ImagePalette.ImagePalette(mode, palette) + + return im + + def copy(self) -> Image: + """ + Copies this image. Use this method if you wish to paste things + into an image, but still retain the original. + + :rtype: :py:class:`~PIL.Image.Image` + :returns: An :py:class:`~PIL.Image.Image` object. + """ + self.load() + return self._new(self.im.copy()) + + __copy__ = copy + + def crop(self, box: tuple[float, float, float, float] | None = None) -> Image: + """ + Returns a rectangular region from this image. The box is a + 4-tuple defining the left, upper, right, and lower pixel + coordinate. See :ref:`coordinate-system`. + + Note: Prior to Pillow 3.4.0, this was a lazy operation. + + :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. + :rtype: :py:class:`~PIL.Image.Image` + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if box is None: + return self.copy() + + if box[2] < box[0]: + msg = "Coordinate 'right' is less than 'left'" + raise ValueError(msg) + elif box[3] < box[1]: + msg = "Coordinate 'lower' is less than 'upper'" + raise ValueError(msg) + + self.load() + return self._new(self._crop(self.im, box)) + + def _crop( + self, im: core.ImagingCore, box: tuple[float, float, float, float] + ) -> core.ImagingCore: + """ + Returns a rectangular region from the core image object im. + + This is equivalent to calling im.crop((x0, y0, x1, y1)), but + includes additional sanity checks. + + :param im: a core image object + :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. + :returns: A core image object. + """ + + x0, y0, x1, y1 = map(int, map(round, box)) + + absolute_values = (abs(x1 - x0), abs(y1 - y0)) + + _decompression_bomb_check(absolute_values) + + return im.crop((x0, y0, x1, y1)) + + def draft( + self, mode: str | None, size: tuple[int, int] | None + ) -> tuple[str, tuple[int, int, float, float]] | None: + """ + Configures the image file loader so it returns a version of the + image that as closely as possible matches the given mode and + size. For example, you can use this method to convert a color + JPEG to grayscale while loading it. + + If any changes are made, returns a tuple with the chosen ``mode`` and + ``box`` with coordinates of the original image within the altered one. + + Note that this method modifies the :py:class:`~PIL.Image.Image` object + in place. If the image has already been loaded, this method has no + effect. + + Note: This method is not implemented for most images. It is + currently implemented only for JPEG and MPO images. + + :param mode: The requested mode. + :param size: The requested size in pixels, as a 2-tuple: + (width, height). + """ + pass + + def _expand(self, xmargin: int, ymargin: int | None = None) -> Image: + if ymargin is None: + ymargin = xmargin + self.load() + return self._new(self.im.expand(xmargin, ymargin)) + + if TYPE_CHECKING: + from . import ImageFilter + + def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image: + """ + Filters this image using the given filter. For a list of + available filters, see the :py:mod:`~PIL.ImageFilter` module. + + :param filter: Filter kernel. + :returns: An :py:class:`~PIL.Image.Image` object.""" + + from . import ImageFilter + + self.load() + + if callable(filter): + filter = filter() + if not hasattr(filter, "filter"): + msg = "filter argument should be ImageFilter.Filter instance or class" + raise TypeError(msg) + + multiband = isinstance(filter, ImageFilter.MultibandFilter) + if self.im.bands == 1 or multiband: + return self._new(filter.filter(self.im)) + + ims = [ + self._new(filter.filter(self.im.getband(c))) for c in range(self.im.bands) + ] + return merge(self.mode, ims) + + def getbands(self) -> tuple[str, ...]: + """ + Returns a tuple containing the name of each band in this image. + For example, ``getbands`` on an RGB image returns ("R", "G", "B"). + + :returns: A tuple containing band names. + :rtype: tuple + """ + return ImageMode.getmode(self.mode).bands + + def getbbox(self, *, alpha_only: bool = True) -> tuple[int, int, int, int] | None: + """ + Calculates the bounding box of the non-zero regions in the + image. + + :param alpha_only: Optional flag, defaulting to ``True``. + If ``True`` and the image has an alpha channel, trim transparent pixels. + Otherwise, trim pixels when all channels are zero. + Keyword-only argument. + :returns: The bounding box is returned as a 4-tuple defining the + left, upper, right, and lower pixel coordinate. See + :ref:`coordinate-system`. If the image is completely empty, this + method returns None. + + """ + + self.load() + return self.im.getbbox(alpha_only) + + def getcolors(self, maxcolors: int = 256): + """ + Returns a list of colors used in this image. + + The colors will be in the image's mode. For example, an RGB image will + return a tuple of (red, green, blue) color values, and a P image will + return the index of the color in the palette. + + :param maxcolors: Maximum number of colors. If this number is + exceeded, this method returns None. The default limit is + 256 colors. + :returns: An unsorted list of (count, pixel) values. + """ + + self.load() + if self.mode in ("1", "L", "P"): + h = self.im.histogram() + out = [(h[i], i) for i in range(256) if h[i]] + if len(out) > maxcolors: + return None + return out + return self.im.getcolors(maxcolors) + + def getdata(self, band: int | None = None): + """ + Returns the contents of this image as a sequence object + containing pixel values. The sequence object is flattened, so + that values for line one follow directly after the values of + line zero, and so on. + + Note that the sequence object returned by this method is an + internal PIL data type, which only supports certain sequence + operations. To convert it to an ordinary sequence (e.g. for + printing), use ``list(im.getdata())``. + + :param band: What band to return. The default is to return + all bands. To return a single band, pass in the index + value (e.g. 0 to get the "R" band from an "RGB" image). + :returns: A sequence-like object. + """ + + self.load() + if band is not None: + return self.im.getband(band) + return self.im # could be abused + + def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]: + """ + Gets the minimum and maximum pixel values for each band in + the image. + + :returns: For a single-band image, a 2-tuple containing the + minimum and maximum pixel value. For a multi-band image, + a tuple containing one 2-tuple for each band. + """ + + self.load() + if self.im.bands > 1: + return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands)) + return self.im.getextrema() + + def getxmp(self): + """ + Returns a dictionary containing the XMP tags. + Requires defusedxml to be installed. + + :returns: XMP tags in a dictionary. + """ + + def get_name(tag: str) -> str: + return re.sub("^{[^}]+}", "", tag) + + def get_value(element): + value = {get_name(k): v for k, v in element.attrib.items()} + children = list(element) + if children: + for child in children: + name = get_name(child.tag) + child_value = get_value(child) + if name in value: + if not isinstance(value[name], list): + value[name] = [value[name]] + value[name].append(child_value) + else: + value[name] = child_value + elif value: + if element.text: + value["text"] = element.text + else: + return element.text + return value + + if ElementTree is None: + warnings.warn("XMP data cannot be read without defusedxml dependency") + return {} + if "xmp" not in self.info: + return {} + root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00")) + return {get_name(root.tag): get_value(root)} + + def getexif(self) -> Exif: + """ + Gets EXIF data from the image. + + :returns: an :py:class:`~PIL.Image.Exif` object. + """ + if self._exif is None: + self._exif = Exif() + elif self._exif._loaded: + return self._exif + self._exif._loaded = True + + exif_info = self.info.get("exif") + if exif_info is None: + if "Raw profile type exif" in self.info: + exif_info = bytes.fromhex( + "".join(self.info["Raw profile type exif"].split("\n")[3:]) + ) + elif hasattr(self, "tag_v2"): + self._exif.bigtiff = self.tag_v2._bigtiff + self._exif.endian = self.tag_v2._endian + self._exif.load_from_fp(self.fp, self.tag_v2._offset) + if exif_info is not None: + self._exif.load(exif_info) + + # XMP tags + if ExifTags.Base.Orientation not in self._exif: + xmp_tags = self.info.get("XML:com.adobe.xmp") + if xmp_tags: + match = re.search(r'tiff:Orientation(="|>)([0-9])', xmp_tags) + if match: + self._exif[ExifTags.Base.Orientation] = int(match[2]) + + return self._exif + + def _reload_exif(self) -> None: + if self._exif is None or not self._exif._loaded: + return + self._exif._loaded = False + self.getexif() + + def get_child_images(self) -> list[ImageFile.ImageFile]: + child_images = [] + exif = self.getexif() + ifds = [] + if ExifTags.Base.SubIFDs in exif: + subifd_offsets = exif[ExifTags.Base.SubIFDs] + if subifd_offsets: + if not isinstance(subifd_offsets, tuple): + subifd_offsets = (subifd_offsets,) + for subifd_offset in subifd_offsets: + ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) + ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) + if ifd1 and ifd1.get(513): + ifds.append((ifd1, exif._info.next)) + + offset = None + for ifd, ifd_offset in ifds: + current_offset = self.fp.tell() + if offset is None: + offset = current_offset + + fp = self.fp + thumbnail_offset = ifd.get(513) + if thumbnail_offset is not None: + thumbnail_offset += getattr(self, "_exif_offset", 0) + self.fp.seek(thumbnail_offset) + data = self.fp.read(ifd.get(514)) + fp = io.BytesIO(data) + + with open(fp) as im: + from . import TiffImagePlugin + + if thumbnail_offset is None and isinstance( + im, TiffImagePlugin.TiffImageFile + ): + im._frame_pos = [ifd_offset] + im._seek(0) + im.load() + child_images.append(im) + + if offset is not None: + self.fp.seek(offset) + return child_images + + def getim(self): + """ + Returns a capsule that points to the internal image memory. + + :returns: A capsule object. + """ + + self.load() + return self.im.ptr + + def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None: + """ + Returns the image palette as a list. + + :param rawmode: The mode in which to return the palette. ``None`` will + return the palette in its current mode. + + .. versionadded:: 9.1.0 + + :returns: A list of color values [r, g, b, ...], or None if the + image has no palette. + """ + + self.load() + try: + mode = self.im.getpalettemode() + except ValueError: + return None # no palette + if rawmode is None: + rawmode = mode + return list(self.im.getpalette(mode, rawmode)) + + @property + def has_transparency_data(self) -> bool: + """ + Determine if an image has transparency data, whether in the form of an + alpha channel, a palette with an alpha channel, or a "transparency" key + in the info dictionary. + + Note the image might still appear solid, if all of the values shown + within are opaque. + + :returns: A boolean. + """ + return ( + self.mode in ("LA", "La", "PA", "RGBA", "RGBa") + or (self.mode == "P" and self.palette.mode.endswith("A")) + or "transparency" in self.info + ) + + def apply_transparency(self) -> None: + """ + If a P mode image has a "transparency" key in the info dictionary, + remove the key and instead apply the transparency to the palette. + Otherwise, the image is unchanged. + """ + if self.mode != "P" or "transparency" not in self.info: + return + + from . import ImagePalette + + palette = self.getpalette("RGBA") + assert palette is not None + transparency = self.info["transparency"] + if isinstance(transparency, bytes): + for i, alpha in enumerate(transparency): + palette[i * 4 + 3] = alpha + else: + palette[transparency * 4 + 3] = 0 + self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette)) + self.palette.dirty = 1 + + del self.info["transparency"] + + def getpixel( + self, xy: tuple[int, int] | list[int] + ) -> float | tuple[int, ...] | None: + """ + Returns the pixel value at a given position. + + :param xy: The coordinate, given as (x, y). See + :ref:`coordinate-system`. + :returns: The pixel value. If the image is a multi-layer image, + this method returns a tuple. + """ + + self.load() + if self.pyaccess: + return self.pyaccess.getpixel(xy) + return self.im.getpixel(tuple(xy)) + + def getprojection(self) -> tuple[list[int], list[int]]: + """ + Get projection to x and y axes + + :returns: Two sequences, indicating where there are non-zero + pixels along the X-axis and the Y-axis, respectively. + """ + + self.load() + x, y = self.im.getprojection() + return list(x), list(y) + + def histogram(self, mask: Image | None = None, extrema=None) -> list[int]: + """ + Returns a histogram for the image. The histogram is returned as a + list of pixel counts, one for each pixel value in the source + image. Counts are grouped into 256 bins for each band, even if + the image has more than 8 bits per band. If the image has more + than one band, the histograms for all bands are concatenated (for + example, the histogram for an "RGB" image contains 768 values). + + A bilevel image (mode "1") is treated as a grayscale ("L") image + by this method. + + If a mask is provided, the method returns a histogram for those + parts of the image where the mask image is non-zero. The mask + image must have the same size as the image, and be either a + bi-level image (mode "1") or a grayscale image ("L"). + + :param mask: An optional mask. + :param extrema: An optional tuple of manually-specified extrema. + :returns: A list containing pixel counts. + """ + self.load() + if mask: + mask.load() + return self.im.histogram((0, 0), mask.im) + if self.mode in ("I", "F"): + if extrema is None: + extrema = self.getextrema() + return self.im.histogram(extrema) + return self.im.histogram() + + def entropy(self, mask=None, extrema=None): + """ + Calculates and returns the entropy for the image. + + A bilevel image (mode "1") is treated as a grayscale ("L") + image by this method. + + If a mask is provided, the method employs the histogram for + those parts of the image where the mask image is non-zero. + The mask image must have the same size as the image, and be + either a bi-level image (mode "1") or a grayscale image ("L"). + + :param mask: An optional mask. + :param extrema: An optional tuple of manually-specified extrema. + :returns: A float value representing the image entropy + """ + self.load() + if mask: + mask.load() + return self.im.entropy((0, 0), mask.im) + if self.mode in ("I", "F"): + if extrema is None: + extrema = self.getextrema() + return self.im.entropy(extrema) + return self.im.entropy() + + def paste( + self, + im: Image | str | float | tuple[float, ...], + box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None, + mask: Image | None = None, + ) -> None: + """ + Pastes another image into this image. The box argument is either + a 2-tuple giving the upper left corner, a 4-tuple defining the + left, upper, right, and lower pixel coordinate, or None (same as + (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size + of the pasted image must match the size of the region. + + If the modes don't match, the pasted image is converted to the mode of + this image (see the :py:meth:`~PIL.Image.Image.convert` method for + details). + + Instead of an image, the source can be a integer or tuple + containing pixel values. The method then fills the region + with the given color. When creating RGB images, you can + also use color strings as supported by the ImageColor module. + + If a mask is given, this method updates only the regions + indicated by the mask. You can use either "1", "L", "LA", "RGBA" + or "RGBa" images (if present, the alpha band is used as mask). + Where the mask is 255, the given image is copied as is. Where + the mask is 0, the current value is preserved. Intermediate + values will mix the two images together, including their alpha + channels if they have them. + + See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to + combine images with respect to their alpha channels. + + :param im: Source image or pixel value (integer, float or tuple). + :param box: An optional 4-tuple giving the region to paste into. + If a 2-tuple is used instead, it's treated as the upper left + corner. If omitted or None, the source is pasted into the + upper left corner. + + If an image is given as the second argument and there is no + third, the box defaults to (0, 0), and the second argument + is interpreted as a mask image. + :param mask: An optional mask image. + """ + + if isImageType(box): + if mask is not None: + msg = "If using second argument as mask, third argument must be None" + raise ValueError(msg) + # abbreviated paste(im, mask) syntax + mask = box + box = None + assert not isinstance(box, Image) + + if box is None: + box = (0, 0) + + if len(box) == 2: + # upper left corner given; get size from image or mask + if isImageType(im): + size = im.size + elif isImageType(mask): + size = mask.size + else: + # FIXME: use self.size here? + msg = "cannot determine region size; use 4-item box" + raise ValueError(msg) + box += (box[0] + size[0], box[1] + size[1]) + + if isinstance(im, str): + from . import ImageColor + + im = ImageColor.getcolor(im, self.mode) + + elif isImageType(im): + im.load() + if self.mode != im.mode: + if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"): + # should use an adapter for this! + im = im.convert(self.mode) + im = im.im + + self._ensure_mutable() + + if mask: + mask.load() + self.im.paste(im, box, mask.im) + else: + self.im.paste(im, box) + + def alpha_composite( + self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0) + ) -> None: + """'In-place' analog of Image.alpha_composite. Composites an image + onto this image. + + :param im: image to composite over this one + :param dest: Optional 2 tuple (left, top) specifying the upper + left corner in this (destination) image. + :param source: Optional 2 (left, top) tuple for the upper left + corner in the overlay source image, or 4 tuple (left, top, right, + bottom) for the bounds of the source rectangle + + Performance Note: Not currently implemented in-place in the core layer. + """ + + if not isinstance(source, (list, tuple)): + msg = "Source must be a list or tuple" + raise ValueError(msg) + if not isinstance(dest, (list, tuple)): + msg = "Destination must be a list or tuple" + raise ValueError(msg) + + if len(source) == 4: + overlay_crop_box = tuple(source) + elif len(source) == 2: + overlay_crop_box = tuple(source) + im.size + else: + msg = "Source must be a sequence of length 2 or 4" + raise ValueError(msg) + + if not len(dest) == 2: + msg = "Destination must be a sequence of length 2" + raise ValueError(msg) + if min(source) < 0: + msg = "Source must be non-negative" + raise ValueError(msg) + + # over image, crop if it's not the whole image. + if overlay_crop_box == (0, 0) + im.size: + overlay = im + else: + overlay = im.crop(overlay_crop_box) + + # target for the paste + box = tuple(dest) + (dest[0] + overlay.width, dest[1] + overlay.height) + + # destination image. don't copy if we're using the whole image. + if box == (0, 0) + self.size: + background = self + else: + background = self.crop(box) + + result = alpha_composite(background, overlay) + self.paste(result, box) + + def point( + self, + lut: Sequence[float] | Callable[[int], float] | ImagePointHandler, + mode: str | None = None, + ) -> Image: + """ + Maps this image through a lookup table or function. + + :param lut: A lookup table, containing 256 (or 65536 if + self.mode=="I" and mode == "L") values per band in the + image. A function can be used instead, it should take a + single argument. The function is called once for each + possible pixel value, and the resulting table is applied to + all bands of the image. + + It may also be an :py:class:`~PIL.Image.ImagePointHandler` + object:: + + class Example(Image.ImagePointHandler): + def point(self, data): + # Return result + :param mode: Output mode (default is same as input). This can only be used if + the source image has mode "L" or "P", and the output has mode "1" or the + source image mode is "I" and the output mode is "L". + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + self.load() + + if isinstance(lut, ImagePointHandler): + return lut.point(self) + + if callable(lut): + # if it isn't a list, it should be a function + if self.mode in ("I", "I;16", "F"): + # check if the function can be used with point_transform + # UNDONE wiredfool -- I think this prevents us from ever doing + # a gamma function point transform on > 8bit images. + scale, offset = _getscaleoffset(lut) + return self._new(self.im.point_transform(scale, offset)) + # for other modes, convert the function to a table + flatLut = [lut(i) for i in range(256)] * self.im.bands + else: + flatLut = lut + + if self.mode == "F": + # FIXME: _imaging returns a confusing error message for this case + msg = "point operation not supported for this mode" + raise ValueError(msg) + + if mode != "F": + flatLut = [round(i) for i in flatLut] + return self._new(self.im.point(flatLut, mode)) + + def putalpha(self, alpha: Image | int) -> None: + """ + Adds or replaces the alpha layer in this image. If the image + does not have an alpha layer, it's converted to "LA" or "RGBA". + The new layer must be either "L" or "1". + + :param alpha: The new alpha layer. This can either be an "L" or "1" + image having the same size as this image, or an integer. + """ + + self._ensure_mutable() + + if self.mode not in ("LA", "PA", "RGBA"): + # attempt to promote self to a matching alpha mode + try: + mode = getmodebase(self.mode) + "A" + try: + self.im.setmode(mode) + except (AttributeError, ValueError) as e: + # do things the hard way + im = self.im.convert(mode) + if im.mode not in ("LA", "PA", "RGBA"): + msg = "alpha channel could not be added" + raise ValueError(msg) from e # sanity check + self.im = im + self.pyaccess = None + self._mode = self.im.mode + except KeyError as e: + msg = "illegal image mode" + raise ValueError(msg) from e + + if self.mode in ("LA", "PA"): + band = 1 + else: + band = 3 + + if isImageType(alpha): + # alpha layer + if alpha.mode not in ("1", "L"): + msg = "illegal image mode" + raise ValueError(msg) + alpha.load() + if alpha.mode == "1": + alpha = alpha.convert("L") + else: + # constant alpha + alpha = cast(int, alpha) # see python/typing#1013 + try: + self.im.fillband(band, alpha) + except (AttributeError, ValueError): + # do things the hard way + alpha = new("L", self.size, alpha) + else: + return + + self.im.putband(alpha.im, band) + + def putdata( + self, + data: Sequence[float] | Sequence[Sequence[int]], + scale: float = 1.0, + offset: float = 0.0, + ) -> None: + """ + Copies pixel data from a flattened sequence object into the image. The + values should start at the upper left corner (0, 0), continue to the + end of the line, followed directly by the first value of the second + line, and so on. Data will be read until either the image or the + sequence ends. The scale and offset values are used to adjust the + sequence values: **pixel = value*scale + offset**. + + :param data: A flattened sequence object. + :param scale: An optional scale value. The default is 1.0. + :param offset: An optional offset value. The default is 0.0. + """ + + self._ensure_mutable() + + self.im.putdata(data, scale, offset) + + def putpalette(self, data, rawmode="RGB") -> None: + """ + Attaches a palette to this image. The image must be a "P", "PA", "L" + or "LA" image. + + The palette sequence must contain at most 256 colors, made up of one + integer value for each channel in the raw mode. + For example, if the raw mode is "RGB", then it can contain at most 768 + values, made up of red, green and blue values for the corresponding pixel + index in the 256 colors. + If the raw mode is "RGBA", then it can contain at most 1024 values, + containing red, green, blue and alpha values. + + Alternatively, an 8-bit string may be used instead of an integer sequence. + + :param data: A palette sequence (either a list or a string). + :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", or a mode + that can be transformed to "RGB" or "RGBA" (e.g. "R", "BGR;15", "RGBA;L"). + """ + from . import ImagePalette + + if self.mode not in ("L", "LA", "P", "PA"): + msg = "illegal image mode" + raise ValueError(msg) + if isinstance(data, ImagePalette.ImagePalette): + palette = ImagePalette.raw(data.rawmode, data.palette) + else: + if not isinstance(data, bytes): + data = bytes(data) + palette = ImagePalette.raw(rawmode, data) + self._mode = "PA" if "A" in self.mode else "P" + self.palette = palette + self.palette.mode = "RGBA" if "A" in rawmode else "RGB" + self.load() # install new palette + + def putpixel( + self, xy: tuple[int, int], value: float | tuple[int, ...] | list[int] + ) -> None: + """ + Modifies the pixel at the given position. The color is given as + a single numerical value for single-band images, and a tuple for + multi-band images. In addition to this, RGB and RGBA tuples are + accepted for P and PA images. + + Note that this method is relatively slow. For more extensive changes, + use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw` + module instead. + + See: + + * :py:meth:`~PIL.Image.Image.paste` + * :py:meth:`~PIL.Image.Image.putdata` + * :py:mod:`~PIL.ImageDraw` + + :param xy: The pixel coordinate, given as (x, y). See + :ref:`coordinate-system`. + :param value: The pixel value. + """ + + if self.readonly: + self._copy() + self.load() + + if self.pyaccess: + return self.pyaccess.putpixel(xy, value) + + if ( + self.mode in ("P", "PA") + and isinstance(value, (list, tuple)) + and len(value) in [3, 4] + ): + # RGB or RGBA value for a P or PA image + if self.mode == "PA": + alpha = value[3] if len(value) == 4 else 255 + value = value[:3] + palette_index = self.palette.getcolor(value, self) + value = (palette_index, alpha) if self.mode == "PA" else palette_index + return self.im.putpixel(xy, value) + + def remap_palette(self, dest_map, source_palette=None): + """ + Rewrites the image to reorder the palette. + + :param dest_map: A list of indexes into the original palette. + e.g. ``[1,0]`` would swap a two item palette, and ``list(range(256))`` + is the identity transform. + :param source_palette: Bytes or None. + :returns: An :py:class:`~PIL.Image.Image` object. + + """ + from . import ImagePalette + + if self.mode not in ("L", "P"): + msg = "illegal image mode" + raise ValueError(msg) + + bands = 3 + palette_mode = "RGB" + if source_palette is None: + if self.mode == "P": + self.load() + palette_mode = self.im.getpalettemode() + if palette_mode == "RGBA": + bands = 4 + source_palette = self.im.getpalette(palette_mode, palette_mode) + else: # L-mode + source_palette = bytearray(i // 3 for i in range(768)) + + palette_bytes = b"" + new_positions = [0] * 256 + + # pick only the used colors from the palette + for i, oldPosition in enumerate(dest_map): + palette_bytes += source_palette[ + oldPosition * bands : oldPosition * bands + bands + ] + new_positions[oldPosition] = i + + # replace the palette color id of all pixel with the new id + + # Palette images are [0..255], mapped through a 1 or 3 + # byte/color map. We need to remap the whole image + # from palette 1 to palette 2. New_positions is + # an array of indexes into palette 1. Palette 2 is + # palette 1 with any holes removed. + + # We're going to leverage the convert mechanism to use the + # C code to remap the image from palette 1 to palette 2, + # by forcing the source image into 'L' mode and adding a + # mapping 'L' mode palette, then converting back to 'L' + # sans palette thus converting the image bytes, then + # assigning the optimized RGB palette. + + # perf reference, 9500x4000 gif, w/~135 colors + # 14 sec prepatch, 1 sec postpatch with optimization forced. + + mapping_palette = bytearray(new_positions) + + m_im = self.copy() + m_im._mode = "P" + + m_im.palette = ImagePalette.ImagePalette( + palette_mode, palette=mapping_palette * bands + ) + # possibly set palette dirty, then + # m_im.putpalette(mapping_palette, 'L') # converts to 'P' + # or just force it. + # UNDONE -- this is part of the general issue with palettes + m_im.im.putpalette(palette_mode, palette_mode + ";L", m_im.palette.tobytes()) + + m_im = m_im.convert("L") + + m_im.putpalette(palette_bytes, palette_mode) + m_im.palette = ImagePalette.ImagePalette(palette_mode, palette=palette_bytes) + + if "transparency" in self.info: + try: + m_im.info["transparency"] = dest_map.index(self.info["transparency"]) + except ValueError: + if "transparency" in m_im.info: + del m_im.info["transparency"] + + return m_im + + def _get_safe_box(self, size, resample, box): + """Expands the box so it includes adjacent pixels + that may be used by resampling with the given resampling filter. + """ + filter_support = _filters_support[resample] - 0.5 + scale_x = (box[2] - box[0]) / size[0] + scale_y = (box[3] - box[1]) / size[1] + support_x = filter_support * scale_x + support_y = filter_support * scale_y + + return ( + max(0, int(box[0] - support_x)), + max(0, int(box[1] - support_y)), + min(self.size[0], math.ceil(box[2] + support_x)), + min(self.size[1], math.ceil(box[3] + support_y)), + ) + + def resize( + self, + size: tuple[int, int], + resample: int | None = None, + box: tuple[float, float, float, float] | None = None, + reducing_gap: float | None = None, + ) -> Image: + """ + Returns a resized copy of this image. + + :param size: The requested size in pixels, as a 2-tuple: + (width, height). + :param resample: An optional resampling filter. This can be + one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, + :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, + :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. + If the image has mode "1" or "P", it is always set to + :py:data:`Resampling.NEAREST`. If the image mode specifies a number + of bits, such as "I;16", then the default filter is + :py:data:`Resampling.NEAREST`. Otherwise, the default filter is + :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`. + :param box: An optional 4-tuple of floats providing + the source image region to be scaled. + The values must be within (0, 0, width, height) rectangle. + If omitted or None, the entire source is used. + :param reducing_gap: Apply optimization by resizing the image + in two steps. First, reducing the image by integer times + using :py:meth:`~PIL.Image.Image.reduce`. + Second, resizing using regular resampling. The last step + changes size no less than by ``reducing_gap`` times. + ``reducing_gap`` may be None (no first step is performed) + or should be greater than 1.0. The bigger ``reducing_gap``, + the closer the result to the fair resampling. + The smaller ``reducing_gap``, the faster resizing. + With ``reducing_gap`` greater or equal to 3.0, the result is + indistinguishable from fair resampling in most cases. + The default value is None (no optimization). + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if resample is None: + type_special = ";" in self.mode + resample = Resampling.NEAREST if type_special else Resampling.BICUBIC + elif resample not in ( + Resampling.NEAREST, + Resampling.BILINEAR, + Resampling.BICUBIC, + Resampling.LANCZOS, + Resampling.BOX, + Resampling.HAMMING, + ): + msg = f"Unknown resampling filter ({resample})." + + filters = [ + f"{filter[1]} ({filter[0]})" + for filter in ( + (Resampling.NEAREST, "Image.Resampling.NEAREST"), + (Resampling.LANCZOS, "Image.Resampling.LANCZOS"), + (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), + (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), + (Resampling.BOX, "Image.Resampling.BOX"), + (Resampling.HAMMING, "Image.Resampling.HAMMING"), + ) + ] + msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" + raise ValueError(msg) + + if reducing_gap is not None and reducing_gap < 1.0: + msg = "reducing_gap must be 1.0 or greater" + raise ValueError(msg) + + self.load() + if box is None: + box = (0, 0) + self.size + + if self.size == size and box == (0, 0) + self.size: + return self.copy() + + if self.mode in ("1", "P"): + resample = Resampling.NEAREST + + if self.mode in ["LA", "RGBA"] and resample != Resampling.NEAREST: + im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) + im = im.resize(size, resample, box) + return im.convert(self.mode) + + self.load() + + if reducing_gap is not None and resample != Resampling.NEAREST: + factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1 + factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1 + if factor_x > 1 or factor_y > 1: + reduce_box = self._get_safe_box(size, resample, box) + factor = (factor_x, factor_y) + self = ( + self.reduce(factor, box=reduce_box) + if callable(self.reduce) + else Image.reduce(self, factor, box=reduce_box) + ) + box = ( + (box[0] - reduce_box[0]) / factor_x, + (box[1] - reduce_box[1]) / factor_y, + (box[2] - reduce_box[0]) / factor_x, + (box[3] - reduce_box[1]) / factor_y, + ) + + return self._new(self.im.resize(size, resample, box)) + + def reduce( + self, + factor: int | tuple[int, int], + box: tuple[int, int, int, int] | None = None, + ) -> Image: + """ + Returns a copy of the image reduced ``factor`` times. + If the size of the image is not dividable by ``factor``, + the resulting size will be rounded up. + + :param factor: A greater than 0 integer or tuple of two integers + for width and height separately. + :param box: An optional 4-tuple of ints providing + the source image region to be reduced. + The values must be within ``(0, 0, width, height)`` rectangle. + If omitted or ``None``, the entire source is used. + """ + if not isinstance(factor, (list, tuple)): + factor = (factor, factor) + + if box is None: + box = (0, 0) + self.size + + if factor == (1, 1) and box == (0, 0) + self.size: + return self.copy() + + if self.mode in ["LA", "RGBA"]: + im = self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) + im = im.reduce(factor, box) + return im.convert(self.mode) + + self.load() + + return self._new(self.im.reduce(factor, box)) + + def rotate( + self, + angle: float, + resample: Resampling = Resampling.NEAREST, + expand: int | bool = False, + center: tuple[float, float] | None = None, + translate: tuple[int, int] | None = None, + fillcolor: float | tuple[float, ...] | str | None = None, + ) -> Image: + """ + Returns a rotated copy of this image. This method returns a + copy of this image, rotated the given number of degrees counter + clockwise around its centre. + + :param angle: In degrees counter clockwise. + :param resample: An optional resampling filter. This can be + one of :py:data:`Resampling.NEAREST` (use nearest neighbour), + :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 + environment), or :py:data:`Resampling.BICUBIC` (cubic spline + interpolation in a 4x4 environment). If omitted, or if the image has + mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. + See :ref:`concept-filters`. + :param expand: Optional expansion flag. If true, expands the output + image to make it large enough to hold the entire rotated image. + If false or omitted, make the output image the same size as the + input image. Note that the expand flag assumes rotation around + the center and no translation. + :param center: Optional center of rotation (a 2-tuple). Origin is + the upper left corner. Default is the center of the image. + :param translate: An optional post-rotate translation (a 2-tuple). + :param fillcolor: An optional color for area outside the rotated image. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + angle = angle % 360.0 + + # Fast paths regardless of filter, as long as we're not + # translating or changing the center. + if not (center or translate): + if angle == 0: + return self.copy() + if angle == 180: + return self.transpose(Transpose.ROTATE_180) + if angle in (90, 270) and (expand or self.width == self.height): + return self.transpose( + Transpose.ROTATE_90 if angle == 90 else Transpose.ROTATE_270 + ) + + # Calculate the affine matrix. Note that this is the reverse + # transformation (from destination image to source) because we + # want to interpolate the (discrete) destination pixel from + # the local area around the (floating) source pixel. + + # The matrix we actually want (note that it operates from the right): + # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx) + # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy) + # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1) + + # The reverse matrix is thus: + # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx) + # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty) + # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1) + + # In any case, the final translation may be updated at the end to + # compensate for the expand flag. + + w, h = self.size + + if translate is None: + post_trans = (0, 0) + else: + post_trans = translate + if center is None: + center = (w / 2, h / 2) + + angle = -math.radians(angle) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + + def transform(x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + matrix[2], matrix[5] = transform( + -center[0] - post_trans[0], -center[1] - post_trans[1], matrix + ) + matrix[2] += center[0] + matrix[5] += center[1] + + if expand: + # calculate output size + xx = [] + yy = [] + for x, y in ((0, 0), (w, 0), (w, h), (0, h)): + x, y = transform(x, y, matrix) + xx.append(x) + yy.append(y) + nw = math.ceil(max(xx)) - math.floor(min(xx)) + nh = math.ceil(max(yy)) - math.floor(min(yy)) + + # We multiply a translation matrix from the right. Because of its + # special form, this is the same as taking the image of the + # translation vector as new translation vector. + matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix) + w, h = nw, nh + + return self.transform( + (w, h), Transform.AFFINE, matrix, resample, fillcolor=fillcolor + ) + + def save( + self, fp: StrOrBytesPath | IO[bytes], format: str | None = None, **params: Any + ) -> None: + """ + Saves this image under the given filename. If no format is + specified, the format to use is determined from the filename + extension, if possible. + + Keyword options can be used to provide additional instructions + to the writer. If a writer doesn't recognise an option, it is + silently ignored. The available options are described in the + :doc:`image format documentation + <../handbook/image-file-formats>` for each writer. + + You can use a file object instead of a filename. In this case, + you must always specify the format. The file object must + implement the ``seek``, ``tell``, and ``write`` + methods, and be opened in binary mode. + + :param fp: A filename (string), os.PathLike object or file object. + :param format: Optional format override. If omitted, the + format to use is determined from the filename extension. + If a file object was used instead of a filename, this + parameter should always be used. + :param params: Extra parameters to the image writer. + :returns: None + :exception ValueError: If the output format could not be determined + from the file name. Use the format option to solve this. + :exception OSError: If the file could not be written. The file + may have been created, and may contain partial data. + """ + + filename: str | bytes = "" + open_fp = False + if is_path(fp): + filename = os.path.realpath(os.fspath(fp)) + open_fp = True + elif fp == sys.stdout: + try: + fp = sys.stdout.buffer + except AttributeError: + pass + if not filename and hasattr(fp, "name") and is_path(fp.name): + # only set the name for metadata purposes + filename = os.path.realpath(os.fspath(fp.name)) + + # may mutate self! + self._ensure_mutable() + + save_all = params.pop("save_all", False) + self.encoderinfo = params + self.encoderconfig: tuple[Any, ...] = () + + preinit() + + filename_ext = os.path.splitext(filename)[1].lower() + ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext + + if not format: + if ext not in EXTENSION: + init() + try: + format = EXTENSION[ext] + except KeyError as e: + msg = f"unknown file extension: {ext}" + raise ValueError(msg) from e + + if format.upper() not in SAVE: + init() + if save_all: + save_handler = SAVE_ALL[format.upper()] + else: + save_handler = SAVE[format.upper()] + + created = False + if open_fp: + created = not os.path.exists(filename) + if params.get("append", False): + # Open also for reading ("+"), because TIFF save_all + # writer needs to go back and edit the written data. + fp = builtins.open(filename, "r+b") + else: + fp = builtins.open(filename, "w+b") + else: + fp = cast(IO[bytes], fp) + + try: + save_handler(self, fp, filename) + except Exception: + if open_fp: + fp.close() + if created: + try: + os.remove(filename) + except PermissionError: + pass + raise + if open_fp: + fp.close() + + def seek(self, frame: int) -> None: + """ + Seeks to the given frame in this sequence file. If you seek + beyond the end of the sequence, the method raises an + ``EOFError`` exception. When a sequence file is opened, the + library automatically seeks to frame 0. + + See :py:meth:`~PIL.Image.Image.tell`. + + If defined, :attr:`~PIL.Image.Image.n_frames` refers to the + number of available frames. + + :param frame: Frame number, starting at 0. + :exception EOFError: If the call attempts to seek beyond the end + of the sequence. + """ + + # overridden by file handlers + if frame != 0: + msg = "no more images in file" + raise EOFError(msg) + + def show(self, title: str | None = None) -> None: + """ + Displays this image. This method is mainly intended for debugging purposes. + + This method calls :py:func:`PIL.ImageShow.show` internally. You can use + :py:func:`PIL.ImageShow.register` to override its default behaviour. + + The image is first saved to a temporary file. By default, it will be in + PNG format. + + On Unix, the image is then opened using the **xdg-open**, **display**, + **gm**, **eog** or **xv** utility, depending on which one can be found. + + On macOS, the image is opened with the native Preview application. + + On Windows, the image is opened with the standard PNG display utility. + + :param title: Optional title to use for the image window, where possible. + """ + + _show(self, title=title) + + def split(self) -> tuple[Image, ...]: + """ + Split this image into individual bands. This method returns a + tuple of individual image bands from an image. For example, + splitting an "RGB" image creates three new images each + containing a copy of one of the original bands (red, green, + blue). + + If you need only one band, :py:meth:`~PIL.Image.Image.getchannel` + method can be more convenient and faster. + + :returns: A tuple containing bands. + """ + + self.load() + if self.im.bands == 1: + return (self.copy(),) + return tuple(map(self._new, self.im.split())) + + def getchannel(self, channel: int | str) -> Image: + """ + Returns an image containing a single channel of the source image. + + :param channel: What channel to return. Could be index + (0 for "R" channel of "RGB") or channel name + ("A" for alpha channel of "RGBA"). + :returns: An image in "L" mode. + + .. versionadded:: 4.3.0 + """ + self.load() + + if isinstance(channel, str): + try: + channel = self.getbands().index(channel) + except ValueError as e: + msg = f'The image has no channel "{channel}"' + raise ValueError(msg) from e + + return self._new(self.im.getband(channel)) + + def tell(self) -> int: + """ + Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. + + If defined, :attr:`~PIL.Image.Image.n_frames` refers to the + number of available frames. + + :returns: Frame number, starting with 0. + """ + return 0 + + def thumbnail( + self, + size: tuple[float, float], + resample: Resampling = Resampling.BICUBIC, + reducing_gap: float | None = 2.0, + ) -> None: + """ + Make this image into a thumbnail. This method modifies the + image to contain a thumbnail version of itself, no larger than + the given size. This method calculates an appropriate thumbnail + size to preserve the aspect of the image, calls the + :py:meth:`~PIL.Image.Image.draft` method to configure the file reader + (where applicable), and finally resizes the image. + + Note that this function modifies the :py:class:`~PIL.Image.Image` + object in place. If you need to use the full resolution image as well, + apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original + image. + + :param size: The requested size in pixels, as a 2-tuple: + (width, height). + :param resample: Optional resampling filter. This can be one + of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, + :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, + :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. + If omitted, it defaults to :py:data:`Resampling.BICUBIC`. + (was :py:data:`Resampling.NEAREST` prior to version 2.5.0). + See: :ref:`concept-filters`. + :param reducing_gap: Apply optimization by resizing the image + in two steps. First, reducing the image by integer times + using :py:meth:`~PIL.Image.Image.reduce` or + :py:meth:`~PIL.Image.Image.draft` for JPEG images. + Second, resizing using regular resampling. The last step + changes size no less than by ``reducing_gap`` times. + ``reducing_gap`` may be None (no first step is performed) + or should be greater than 1.0. The bigger ``reducing_gap``, + the closer the result to the fair resampling. + The smaller ``reducing_gap``, the faster resizing. + With ``reducing_gap`` greater or equal to 3.0, the result is + indistinguishable from fair resampling in most cases. + The default value is 2.0 (very close to fair resampling + while still being faster in many cases). + :returns: None + """ + + provided_size = tuple(map(math.floor, size)) + + def preserve_aspect_ratio() -> tuple[int, int] | None: + def round_aspect(number, key): + return max(min(math.floor(number), math.ceil(number), key=key), 1) + + x, y = provided_size + if x >= self.width and y >= self.height: + return None + + aspect = self.width / self.height + if x / y >= aspect: + x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) + else: + y = round_aspect( + x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) + ) + return x, y + + box = None + final_size: tuple[int, int] + if reducing_gap is not None: + preserved_size = preserve_aspect_ratio() + if preserved_size is None: + return + final_size = preserved_size + + res = self.draft( + None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) + ) + if res is not None: + box = res[1] + if box is None: + self.load() + + # load() may have changed the size of the image + preserved_size = preserve_aspect_ratio() + if preserved_size is None: + return + final_size = preserved_size + + if self.size != final_size: + im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) + + self.im = im.im + self._size = final_size + self._mode = self.im.mode + + self.readonly = 0 + self.pyaccess = None + + # FIXME: the different transform methods need further explanation + # instead of bloating the method docs, add a separate chapter. + def transform( + self, + size: tuple[int, int], + method: Transform | ImageTransformHandler | SupportsGetData, + data: Sequence[Any] | None = None, + resample: int = Resampling.NEAREST, + fill: int = 1, + fillcolor: float | tuple[float, ...] | str | None = None, + ) -> Image: + """ + Transforms this image. This method creates a new image with the + given size, and the same mode as the original, and copies data + to the new image using the given transform. + + :param size: The output size in pixels, as a 2-tuple: + (width, height). + :param method: The transformation method. This is one of + :py:data:`Transform.EXTENT` (cut out a rectangular subregion), + :py:data:`Transform.AFFINE` (affine transform), + :py:data:`Transform.PERSPECTIVE` (perspective transform), + :py:data:`Transform.QUAD` (map a quadrilateral to a rectangle), or + :py:data:`Transform.MESH` (map a number of source quadrilaterals + in one operation). + + It may also be an :py:class:`~PIL.Image.ImageTransformHandler` + object:: + + class Example(Image.ImageTransformHandler): + def transform(self, size, data, resample, fill=1): + # Return result + + Implementations of :py:class:`~PIL.Image.ImageTransformHandler` + for some of the :py:class:`Transform` methods are provided + in :py:mod:`~PIL.ImageTransform`. + + It may also be an object with a ``method.getdata`` method + that returns a tuple supplying new ``method`` and ``data`` values:: + + class Example: + def getdata(self): + method = Image.Transform.EXTENT + data = (0, 0, 100, 100) + return method, data + :param data: Extra data to the transformation method. + :param resample: Optional resampling filter. It can be one of + :py:data:`Resampling.NEAREST` (use nearest neighbour), + :py:data:`Resampling.BILINEAR` (linear interpolation in a 2x2 + environment), or :py:data:`Resampling.BICUBIC` (cubic spline + interpolation in a 4x4 environment). If omitted, or if the image + has mode "1" or "P", it is set to :py:data:`Resampling.NEAREST`. + See: :ref:`concept-filters`. + :param fill: If ``method`` is an + :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of + the arguments passed to it. Otherwise, it is unused. + :param fillcolor: Optional fill color for the area outside the + transform in the output image. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if self.mode in ("LA", "RGBA") and resample != Resampling.NEAREST: + return ( + self.convert({"LA": "La", "RGBA": "RGBa"}[self.mode]) + .transform(size, method, data, resample, fill, fillcolor) + .convert(self.mode) + ) + + if isinstance(method, ImageTransformHandler): + return method.transform(size, self, resample=resample, fill=fill) + + if hasattr(method, "getdata"): + # compatibility w. old-style transform objects + method, data = method.getdata() + + if data is None: + msg = "missing method data" + raise ValueError(msg) + + im = new(self.mode, size, fillcolor) + if self.mode == "P" and self.palette: + im.palette = self.palette.copy() + im.info = self.info.copy() + if method == Transform.MESH: + # list of quads + for box, quad in data: + im.__transformer( + box, self, Transform.QUAD, quad, resample, fillcolor is None + ) + else: + im.__transformer( + (0, 0) + size, self, method, data, resample, fillcolor is None + ) + + return im + + def __transformer( + self, box, image, method, data, resample=Resampling.NEAREST, fill=1 + ): + w = box[2] - box[0] + h = box[3] - box[1] + + if method == Transform.AFFINE: + data = data[:6] + + elif method == Transform.EXTENT: + # convert extent to an affine transform + x0, y0, x1, y1 = data + xs = (x1 - x0) / w + ys = (y1 - y0) / h + method = Transform.AFFINE + data = (xs, 0, x0, 0, ys, y0) + + elif method == Transform.PERSPECTIVE: + data = data[:8] + + elif method == Transform.QUAD: + # quadrilateral warp. data specifies the four corners + # given as NW, SW, SE, and NE. + nw = data[:2] + sw = data[2:4] + se = data[4:6] + ne = data[6:8] + x0, y0 = nw + As = 1.0 / w + At = 1.0 / h + data = ( + x0, + (ne[0] - x0) * As, + (sw[0] - x0) * At, + (se[0] - sw[0] - ne[0] + x0) * As * At, + y0, + (ne[1] - y0) * As, + (sw[1] - y0) * At, + (se[1] - sw[1] - ne[1] + y0) * As * At, + ) + + else: + msg = "unknown transformation method" + raise ValueError(msg) + + if resample not in ( + Resampling.NEAREST, + Resampling.BILINEAR, + Resampling.BICUBIC, + ): + if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): + msg = { + Resampling.BOX: "Image.Resampling.BOX", + Resampling.HAMMING: "Image.Resampling.HAMMING", + Resampling.LANCZOS: "Image.Resampling.LANCZOS", + }[resample] + f" ({resample}) cannot be used." + else: + msg = f"Unknown resampling filter ({resample})." + + filters = [ + f"{filter[1]} ({filter[0]})" + for filter in ( + (Resampling.NEAREST, "Image.Resampling.NEAREST"), + (Resampling.BILINEAR, "Image.Resampling.BILINEAR"), + (Resampling.BICUBIC, "Image.Resampling.BICUBIC"), + ) + ] + msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}" + raise ValueError(msg) + + image.load() + + self.load() + + if image.mode in ("1", "P"): + resample = Resampling.NEAREST + + self.im.transform(box, image.im, method, data, resample, fill) + + def transpose(self, method: Transpose) -> Image: + """ + Transpose image (flip or rotate in 90 degree steps) + + :param method: One of :py:data:`Transpose.FLIP_LEFT_RIGHT`, + :py:data:`Transpose.FLIP_TOP_BOTTOM`, :py:data:`Transpose.ROTATE_90`, + :py:data:`Transpose.ROTATE_180`, :py:data:`Transpose.ROTATE_270`, + :py:data:`Transpose.TRANSPOSE` or :py:data:`Transpose.TRANSVERSE`. + :returns: Returns a flipped or rotated copy of this image. + """ + + self.load() + return self._new(self.im.transpose(method)) + + def effect_spread(self, distance: int) -> Image: + """ + Randomly spread pixels in an image. + + :param distance: Distance to spread pixels. + """ + self.load() + return self._new(self.im.effect_spread(distance)) + + def toqimage(self): + """Returns a QImage copy of this image""" + from . import ImageQt + + if not ImageQt.qt_is_installed: + msg = "Qt bindings are not installed" + raise ImportError(msg) + return ImageQt.toqimage(self) + + def toqpixmap(self): + """Returns a QPixmap copy of this image""" + from . import ImageQt + + if not ImageQt.qt_is_installed: + msg = "Qt bindings are not installed" + raise ImportError(msg) + return ImageQt.toqpixmap(self) + + +# -------------------------------------------------------------------- +# Abstract handlers. + + +class ImagePointHandler: + """ + Used as a mixin by point transforms + (for use with :py:meth:`~PIL.Image.Image.point`) + """ + + @abc.abstractmethod + def point(self, im: Image) -> Image: + pass + + +class ImageTransformHandler: + """ + Used as a mixin by geometry transforms + (for use with :py:meth:`~PIL.Image.Image.transform`) + """ + + @abc.abstractmethod + def transform( + self, + size: tuple[int, int], + image: Image, + **options: Any, + ) -> Image: + pass + + +# -------------------------------------------------------------------- +# Factories + +# +# Debugging + + +def _wedge() -> Image: + """Create grayscale wedge (for debugging only)""" + + return Image()._new(core.wedge("L")) + + +def _check_size(size: Any) -> None: + """ + Common check to enforce type and sanity check on size tuples + + :param size: Should be a 2 tuple of (width, height) + :returns: None, or raises a ValueError + """ + + if not isinstance(size, (list, tuple)): + msg = "Size must be a list or tuple" + raise ValueError(msg) + if len(size) != 2: + msg = "Size must be a sequence of length 2" + raise ValueError(msg) + if size[0] < 0 or size[1] < 0: + msg = "Width and height must be >= 0" + raise ValueError(msg) + + +def new( + mode: str, + size: tuple[int, int] | list[int], + color: float | tuple[float, ...] | str | None = 0, +) -> Image: + """ + Creates a new image with the given mode and size. + + :param mode: The mode to use for the new image. See: + :ref:`concept-modes`. + :param size: A 2-tuple, containing (width, height) in pixels. + :param color: What color to use for the image. Default is black. + If given, this should be a single integer or floating point value + for single-band modes, and a tuple for multi-band modes (one value + per band). When creating RGB or HSV images, you can also use color + strings as supported by the ImageColor module. If the color is + None, the image is not initialised. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) + + _check_size(size) + + if color is None: + # don't initialize + return Image()._new(core.new(mode, size)) + + if isinstance(color, str): + # css3-style specifier + + from . import ImageColor + + color = ImageColor.getcolor(color, mode) + + im = Image() + if ( + mode == "P" + and isinstance(color, (list, tuple)) + and all(isinstance(i, int) for i in color) + ): + color_ints: tuple[int, ...] = cast(Tuple[int, ...], tuple(color)) + if len(color_ints) == 3 or len(color_ints) == 4: + # RGB or RGBA value for a P image + from . import ImagePalette + + im.palette = ImagePalette.ImagePalette() + color = im.palette.getcolor(color_ints) + return im._new(core.fill(mode, size, color)) + + +def frombytes( + mode: str, + size: tuple[int, int], + data: bytes | bytearray, + decoder_name: str = "raw", + *args: Any, +) -> Image: + """ + Creates a copy of an image memory from pixel data in a buffer. + + In its simplest form, this function takes three arguments + (mode, size, and unpacked pixel data). + + You can also use any pixel decoder supported by PIL. For more + information on available decoders, see the section + :ref:`Writing Your Own File Codec `. + + Note that this function decodes pixel data only, not entire images. + If you have an entire image in a string, wrap it in a + :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load + it. + + :param mode: The image mode. See: :ref:`concept-modes`. + :param size: The image size. + :param data: A byte buffer containing raw data for the given mode. + :param decoder_name: What decoder to use. + :param args: Additional parameters for the given decoder. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + _check_size(size) + + im = new(mode, size) + if im.width != 0 and im.height != 0: + decoder_args: Any = args + if len(decoder_args) == 1 and isinstance(decoder_args[0], tuple): + # may pass tuple instead of argument list + decoder_args = decoder_args[0] + + if decoder_name == "raw" and decoder_args == (): + decoder_args = mode + + im.frombytes(data, decoder_name, decoder_args) + return im + + +def frombuffer( + mode: str, size: tuple[int, int], data, decoder_name: str = "raw", *args: Any +) -> Image: + """ + Creates an image memory referencing pixel data in a byte buffer. + + This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data + in the byte buffer, where possible. This means that changes to the + original buffer object are reflected in this image). Not all modes can + share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". + + Note that this function decodes pixel data only, not entire images. + If you have an entire image file in a string, wrap it in a + :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load it. + + The default parameters used for the "raw" decoder differs from that used for + :py:func:`~PIL.Image.frombytes`. This is a bug, and will probably be fixed in a + future release. The current release issues a warning if you do this; to disable + the warning, you should provide the full set of parameters. See below for details. + + :param mode: The image mode. See: :ref:`concept-modes`. + :param size: The image size. + :param data: A bytes or other buffer object containing raw + data for the given mode. + :param decoder_name: What decoder to use. + :param args: Additional parameters for the given decoder. For the + default encoder ("raw"), it's recommended that you provide the + full set of parameters:: + + frombuffer(mode, size, data, "raw", mode, 0, 1) + + :returns: An :py:class:`~PIL.Image.Image` object. + + .. versionadded:: 1.1.4 + """ + + _check_size(size) + + # may pass tuple instead of argument list + if len(args) == 1 and isinstance(args[0], tuple): + args = args[0] + + if decoder_name == "raw": + if args == (): + args = mode, 0, 1 + if args[0] in _MAPMODES: + im = new(mode, (0, 0)) + im = im._new(core.map_buffer(data, size, decoder_name, 0, args)) + if mode == "P": + from . import ImagePalette + + im.palette = ImagePalette.ImagePalette("RGB", im.im.getpalette("RGB")) + im.readonly = 1 + return im + + return frombytes(mode, size, data, decoder_name, args) + + +class SupportsArrayInterface(Protocol): + """ + An object that has an ``__array_interface__`` dictionary. + """ + + @property + def __array_interface__(self) -> dict[str, Any]: + raise NotImplementedError() + + +def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: + """ + Creates an image memory from an object exporting the array interface + (using the buffer protocol):: + + from PIL import Image + import numpy as np + a = np.zeros((5, 5)) + im = Image.fromarray(a) + + If ``obj`` is not contiguous, then the ``tobytes`` method is called + and :py:func:`~PIL.Image.frombuffer` is used. + + In the case of NumPy, be aware that Pillow modes do not always correspond + to NumPy dtypes. Pillow modes only offer 1-bit pixels, 8-bit pixels, + 32-bit signed integer pixels, and 32-bit floating point pixels. + + Pillow images can also be converted to arrays:: + + from PIL import Image + import numpy as np + im = Image.open("hopper.jpg") + a = np.asarray(im) + + When converting Pillow images to arrays however, only pixel values are + transferred. This means that P and PA mode images will lose their palette. + + :param obj: Object with array interface + :param mode: Optional mode to use when reading ``obj``. Will be determined from + type if ``None``. + + This will not be used to convert the data after reading, but will be used to + change how the data is read:: + + from PIL import Image + import numpy as np + a = np.full((1, 1), 300) + im = Image.fromarray(a, mode="L") + im.getpixel((0, 0)) # 44 + im = Image.fromarray(a, mode="RGB") + im.getpixel((0, 0)) # (44, 1, 0) + + See: :ref:`concept-modes` for general information about modes. + :returns: An image object. + + .. versionadded:: 1.1.6 + """ + arr = obj.__array_interface__ + shape = arr["shape"] + ndim = len(shape) + strides = arr.get("strides", None) + if mode is None: + try: + typekey = (1, 1) + shape[2:], arr["typestr"] + except KeyError as e: + msg = "Cannot handle this data type" + raise TypeError(msg) from e + try: + mode, rawmode = _fromarray_typemap[typekey] + except KeyError as e: + typekey_shape, typestr = typekey + msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" + raise TypeError(msg) from e + else: + rawmode = mode + if mode in ["1", "L", "I", "P", "F"]: + ndmax = 2 + elif mode == "RGB": + ndmax = 3 + else: + ndmax = 4 + if ndim > ndmax: + msg = f"Too many dimensions: {ndim} > {ndmax}." + raise ValueError(msg) + + size = 1 if ndim == 1 else shape[1], shape[0] + if strides is not None: + if hasattr(obj, "tobytes"): + obj = obj.tobytes() + elif hasattr(obj, "tostring"): + obj = obj.tostring() + else: + msg = "'strides' requires either tobytes() or tostring()" + raise ValueError(msg) + + return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) + + +def fromqimage(im): + """Creates an image instance from a QImage image""" + from . import ImageQt + + if not ImageQt.qt_is_installed: + msg = "Qt bindings are not installed" + raise ImportError(msg) + return ImageQt.fromqimage(im) + + +def fromqpixmap(im): + """Creates an image instance from a QPixmap image""" + from . import ImageQt + + if not ImageQt.qt_is_installed: + msg = "Qt bindings are not installed" + raise ImportError(msg) + return ImageQt.fromqpixmap(im) + + +_fromarray_typemap = { + # (shape, typestr) => mode, rawmode + # first two members of shape are set to one + ((1, 1), "|b1"): ("1", "1;8"), + ((1, 1), "|u1"): ("L", "L"), + ((1, 1), "|i1"): ("I", "I;8"), + ((1, 1), "u2"): ("I", "I;16B"), + ((1, 1), "i2"): ("I", "I;16BS"), + ((1, 1), "u4"): ("I", "I;32B"), + ((1, 1), "i4"): ("I", "I;32BS"), + ((1, 1), "f4"): ("F", "F;32BF"), + ((1, 1), "f8"): ("F", "F;64BF"), + ((1, 1, 2), "|u1"): ("LA", "LA"), + ((1, 1, 3), "|u1"): ("RGB", "RGB"), + ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), + # shortcuts: + ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), + ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), +} + + +def _decompression_bomb_check(size: tuple[int, int]) -> None: + if MAX_IMAGE_PIXELS is None: + return + + pixels = max(1, size[0]) * max(1, size[1]) + + if pixels > 2 * MAX_IMAGE_PIXELS: + msg = ( + f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " + "pixels, could be decompression bomb DOS attack." + ) + raise DecompressionBombError(msg) + + if pixels > MAX_IMAGE_PIXELS: + warnings.warn( + f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " + "could be decompression bomb DOS attack.", + DecompressionBombWarning, + ) + + +def open( + fp: StrOrBytesPath | IO[bytes], + mode: Literal["r"] = "r", + formats: list[str] | tuple[str, ...] | None = None, +) -> ImageFile.ImageFile: + """ + Opens and identifies the given image file. + + This is a lazy operation; this function identifies the file, but + the file remains open and the actual image data is not read from + the file until you try to process the data (or call the + :py:meth:`~PIL.Image.Image.load` method). See + :py:func:`~PIL.Image.new`. See :ref:`file-handling`. + + :param fp: A filename (string), os.PathLike object or a file object. + The file object must implement ``file.read``, + ``file.seek``, and ``file.tell`` methods, + and be opened in binary mode. The file object will also seek to zero + before reading. + :param mode: The mode. If given, this argument must be "r". + :param formats: A list or tuple of formats to attempt to load the file in. + This can be used to restrict the set of formats checked. + Pass ``None`` to try all supported formats. You can print the set of + available formats by running ``python3 -m PIL`` or using + the :py:func:`PIL.features.pilinfo` function. + :returns: An :py:class:`~PIL.Image.Image` object. + :exception FileNotFoundError: If the file cannot be found. + :exception PIL.UnidentifiedImageError: If the image cannot be opened and + identified. + :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` + instance is used for ``fp``. + :exception TypeError: If ``formats`` is not ``None``, a list or a tuple. + """ + + if mode != "r": + msg = f"bad mode {repr(mode)}" # type: ignore[unreachable] + raise ValueError(msg) + elif isinstance(fp, io.StringIO): + msg = ( # type: ignore[unreachable] + "StringIO cannot be used to open an image. " + "Binary data must be used instead." + ) + raise ValueError(msg) + + if formats is None: + formats = ID + elif not isinstance(formats, (list, tuple)): + msg = "formats must be a list or tuple" # type: ignore[unreachable] + raise TypeError(msg) + + exclusive_fp = False + filename: str | bytes = "" + if is_path(fp): + filename = os.path.realpath(os.fspath(fp)) + + if filename: + fp = builtins.open(filename, "rb") + exclusive_fp = True + else: + fp = cast(IO[bytes], fp) + + try: + fp.seek(0) + except (AttributeError, io.UnsupportedOperation): + fp = io.BytesIO(fp.read()) + exclusive_fp = True + + prefix = fp.read(16) + + preinit() + + warning_messages: list[str] = [] + + def _open_core( + fp: IO[bytes], + filename: str | bytes, + prefix: bytes, + formats: list[str] | tuple[str, ...], + ) -> ImageFile.ImageFile | None: + for i in formats: + i = i.upper() + if i not in OPEN: + init() + try: + factory, accept = OPEN[i] + result = not accept or accept(prefix) + if isinstance(result, str): + warning_messages.append(result) + elif result: + fp.seek(0) + im = factory(fp, filename) + _decompression_bomb_check(im.size) + return im + except (SyntaxError, IndexError, TypeError, struct.error) as e: + if WARN_POSSIBLE_FORMATS: + warning_messages.append(i + " opening failed. " + str(e)) + except BaseException: + if exclusive_fp: + fp.close() + raise + return None + + im = _open_core(fp, filename, prefix, formats) + + if im is None and formats is ID: + checked_formats = ID.copy() + if init(): + im = _open_core( + fp, + filename, + prefix, + tuple(format for format in formats if format not in checked_formats), + ) + + if im: + im._exclusive_fp = exclusive_fp + return im + + if exclusive_fp: + fp.close() + for message in warning_messages: + warnings.warn(message) + msg = "cannot identify image file %r" % (filename if filename else fp) + raise UnidentifiedImageError(msg) + + +# +# Image processing. + + +def alpha_composite(im1: Image, im2: Image) -> Image: + """ + Alpha composite im2 over im1. + + :param im1: The first image. Must have mode RGBA. + :param im2: The second image. Must have mode RGBA, and the same size as + the first image. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + im1.load() + im2.load() + return im1._new(core.alpha_composite(im1.im, im2.im)) + + +def blend(im1: Image, im2: Image, alpha: float) -> Image: + """ + Creates a new image by interpolating between two input images, using + a constant alpha:: + + out = image1 * (1.0 - alpha) + image2 * alpha + + :param im1: The first image. + :param im2: The second image. Must have the same mode and size as + the first image. + :param alpha: The interpolation alpha factor. If alpha is 0.0, a + copy of the first image is returned. If alpha is 1.0, a copy of + the second image is returned. There are no restrictions on the + alpha value. If necessary, the result is clipped to fit into + the allowed output range. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + im1.load() + im2.load() + return im1._new(core.blend(im1.im, im2.im, alpha)) + + +def composite(image1: Image, image2: Image, mask: Image) -> Image: + """ + Create composite image by blending images using a transparency mask. + + :param image1: The first image. + :param image2: The second image. Must have the same mode and + size as the first image. + :param mask: A mask image. This image can have mode + "1", "L", or "RGBA", and must have the same size as the + other two images. + """ + + image = image2.copy() + image.paste(image1, None, mask) + return image + + +def eval(image, *args): + """ + Applies the function (which should take one argument) to each pixel + in the given image. If the image has more than one band, the same + function is applied to each band. Note that the function is + evaluated once for each possible pixel value, so you cannot use + random components or other generators. + + :param image: The input image. + :param function: A function object, taking one integer argument. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + return image.point(args[0]) + + +def merge(mode: str, bands: Sequence[Image]) -> Image: + """ + Merge a set of single band images into a new multiband image. + + :param mode: The mode to use for the output image. See: + :ref:`concept-modes`. + :param bands: A sequence containing one single-band image for + each band in the output image. All bands must have the + same size. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + + if getmodebands(mode) != len(bands) or "*" in mode: + msg = "wrong number of bands" + raise ValueError(msg) + for band in bands[1:]: + if band.mode != getmodetype(mode): + msg = "mode mismatch" + raise ValueError(msg) + if band.size != bands[0].size: + msg = "size mismatch" + raise ValueError(msg) + for band in bands: + band.load() + return bands[0]._new(core.merge(mode, *[b.im for b in bands])) + + +# -------------------------------------------------------------------- +# Plugin registry + + +def register_open( + id: str, + factory: Callable[[IO[bytes], str | bytes], ImageFile.ImageFile], + accept: Callable[[bytes], bool | str] | None = None, +) -> None: + """ + Register an image file plugin. This function should not be used + in application code. + + :param id: An image format identifier. + :param factory: An image file factory method. + :param accept: An optional function that can be used to quickly + reject images having another format. + """ + id = id.upper() + if id not in ID: + ID.append(id) + OPEN[id] = factory, accept + + +def register_mime(id: str, mimetype: str) -> None: + """ + Registers an image MIME type by populating ``Image.MIME``. This function + should not be used in application code. + + ``Image.MIME`` provides a mapping from image format identifiers to mime + formats, but :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` can + provide a different result for specific images. + + :param id: An image format identifier. + :param mimetype: The image MIME type for this format. + """ + MIME[id.upper()] = mimetype + + +def register_save( + id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] +) -> None: + """ + Registers an image save function. This function should not be + used in application code. + + :param id: An image format identifier. + :param driver: A function to save images in this format. + """ + SAVE[id.upper()] = driver + + +def register_save_all( + id: str, driver: Callable[[Image, IO[bytes], str | bytes], None] +) -> None: + """ + Registers an image function to save all the frames + of a multiframe format. This function should not be + used in application code. + + :param id: An image format identifier. + :param driver: A function to save images in this format. + """ + SAVE_ALL[id.upper()] = driver + + +def register_extension(id: str, extension: str) -> None: + """ + Registers an image extension. This function should not be + used in application code. + + :param id: An image format identifier. + :param extension: An extension used for this format. + """ + EXTENSION[extension.lower()] = id.upper() + + +def register_extensions(id: str, extensions: list[str]) -> None: + """ + Registers image extensions. This function should not be + used in application code. + + :param id: An image format identifier. + :param extensions: A list of extensions used for this format. + """ + for extension in extensions: + register_extension(id, extension) + + +def registered_extensions() -> dict[str, str]: + """ + Returns a dictionary containing all file extensions belonging + to registered plugins + """ + init() + return EXTENSION + + +def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None: + """ + Registers an image decoder. This function should not be + used in application code. + + :param name: The name of the decoder + :param decoder: An ImageFile.PyDecoder object + + .. versionadded:: 4.1.0 + """ + DECODERS[name] = decoder + + +def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: + """ + Registers an image encoder. This function should not be + used in application code. + + :param name: The name of the encoder + :param encoder: An ImageFile.PyEncoder object + + .. versionadded:: 4.1.0 + """ + ENCODERS[name] = encoder + + +# -------------------------------------------------------------------- +# Simple display support. + + +def _show(image: Image, **options: Any) -> None: + from . import ImageShow + + ImageShow.show(image, **options) + + +# -------------------------------------------------------------------- +# Effects + + +def effect_mandelbrot( + size: tuple[int, int], extent: tuple[float, float, float, float], quality: int +) -> Image: + """ + Generate a Mandelbrot set covering the given extent. + + :param size: The requested size in pixels, as a 2-tuple: + (width, height). + :param extent: The extent to cover, as a 4-tuple: + (x0, y0, x1, y1). + :param quality: Quality. + """ + return Image()._new(core.effect_mandelbrot(size, extent, quality)) + + +def effect_noise(size: tuple[int, int], sigma: float) -> Image: + """ + Generate Gaussian noise centered around 128. + + :param size: The requested size in pixels, as a 2-tuple: + (width, height). + :param sigma: Standard deviation of noise. + """ + return Image()._new(core.effect_noise(size, sigma)) + + +def linear_gradient(mode: str) -> Image: + """ + Generate 256x256 linear gradient from black to white, top to bottom. + + :param mode: Input mode. + """ + return Image()._new(core.linear_gradient(mode)) + + +def radial_gradient(mode: str) -> Image: + """ + Generate 256x256 radial gradient from black to white, centre to edge. + + :param mode: Input mode. + """ + return Image()._new(core.radial_gradient(mode)) + + +# -------------------------------------------------------------------- +# Resources + + +def _apply_env_variables(env: dict[str, str] | None = None) -> None: + env_dict = env if env is not None else os.environ + + for var_name, setter in [ + ("PILLOW_ALIGNMENT", core.set_alignment), + ("PILLOW_BLOCK_SIZE", core.set_block_size), + ("PILLOW_BLOCKS_MAX", core.set_blocks_max), + ]: + if var_name not in env_dict: + continue + + var = env_dict[var_name].lower() + + units = 1 + for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]: + if var.endswith(postfix): + units = mul + var = var[: -len(postfix)] + + try: + var_int = int(var) * units + except ValueError: + warnings.warn(f"{var_name} is not int") + continue + + try: + setter(var_int) + except ValueError as e: + warnings.warn(f"{var_name}: {e}") + + +_apply_env_variables() +atexit.register(core.clear_cache) + + +if TYPE_CHECKING: + _ExifBase = MutableMapping[int, Any] +else: + _ExifBase = MutableMapping + + +class Exif(_ExifBase): + """ + This class provides read and write access to EXIF image data:: + + from PIL import Image + im = Image.open("exif.png") + exif = im.getexif() # Returns an instance of this class + + Information can be read and written, iterated over or deleted:: + + print(exif[274]) # 1 + exif[274] = 2 + for k, v in exif.items(): + print("Tag", k, "Value", v) # Tag 274 Value 2 + del exif[274] + + To access information beyond IFD0, :py:meth:`~PIL.Image.Exif.get_ifd` + returns a dictionary:: + + from PIL import ExifTags + im = Image.open("exif_gps.jpg") + exif = im.getexif() + gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) + print(gps_ifd) + + Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.Makernote``, + ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. + + :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: + + print(exif[ExifTags.Base.Software]) # PIL + print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 + """ + + endian = None + bigtiff = False + _loaded = False + + def __init__(self): + self._data = {} + self._hidden_data = {} + self._ifds = {} + self._info = None + self._loaded_exif = None + + def _fixup(self, value): + try: + if len(value) == 1 and isinstance(value, tuple): + return value[0] + except Exception: + pass + return value + + def _fixup_dict(self, src_dict): + # Helper function + # returns a dict with any single item tuples/lists as individual values + return {k: self._fixup(v) for k, v in src_dict.items()} + + def _get_ifd_dict(self, offset, group=None): + try: + # an offset pointer to the location of the nested embedded IFD. + # It should be a long, but may be corrupted. + self.fp.seek(offset) + except (KeyError, TypeError): + pass + else: + from . import TiffImagePlugin + + info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) + info.load(self.fp) + return self._fixup_dict(info) + + def _get_head(self): + version = b"\x2B" if self.bigtiff else b"\x2A" + if self.endian == "<": + head = b"II" + version + b"\x00" + o32le(8) + else: + head = b"MM\x00" + version + o32be(8) + if self.bigtiff: + head += o32le(8) if self.endian == "<" else o32be(8) + head += b"\x00\x00\x00\x00" + return head + + def load(self, data): + # Extract EXIF information. This is highly experimental, + # and is likely to be replaced with something better in a future + # version. + + # The EXIF record consists of a TIFF file embedded in a JPEG + # application marker (!). + if data == self._loaded_exif: + return + self._loaded_exif = data + self._data.clear() + self._hidden_data.clear() + self._ifds.clear() + if data and data.startswith(b"Exif\x00\x00"): + data = data[6:] + if not data: + self._info = None + return + + self.fp = io.BytesIO(data) + self.head = self.fp.read(8) + # process dictionary + from . import TiffImagePlugin + + self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) + self.endian = self._info._endian + self.fp.seek(self._info.next) + self._info.load(self.fp) + + def load_from_fp(self, fp, offset=None): + self._loaded_exif = None + self._data.clear() + self._hidden_data.clear() + self._ifds.clear() + + # process dictionary + from . import TiffImagePlugin + + self.fp = fp + if offset is not None: + self.head = self._get_head() + else: + self.head = self.fp.read(8) + self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) + if self.endian is None: + self.endian = self._info._endian + if offset is None: + offset = self._info.next + self.fp.tell() + self.fp.seek(offset) + self._info.load(self.fp) + + def _get_merged_dict(self): + merged_dict = dict(self) + + # get EXIF extension + if ExifTags.IFD.Exif in self: + ifd = self._get_ifd_dict(self[ExifTags.IFD.Exif], ExifTags.IFD.Exif) + if ifd: + merged_dict.update(ifd) + + # GPS + if ExifTags.IFD.GPSInfo in self: + merged_dict[ExifTags.IFD.GPSInfo] = self._get_ifd_dict( + self[ExifTags.IFD.GPSInfo], ExifTags.IFD.GPSInfo + ) + + return merged_dict + + def tobytes(self, offset: int = 8) -> bytes: + from . import TiffImagePlugin + + head = self._get_head() + ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) + for tag, value in self.items(): + if tag in [ + ExifTags.IFD.Exif, + ExifTags.IFD.GPSInfo, + ] and not isinstance(value, dict): + value = self.get_ifd(tag) + if ( + tag == ExifTags.IFD.Exif + and ExifTags.IFD.Interop in value + and not isinstance(value[ExifTags.IFD.Interop], dict) + ): + value = value.copy() + value[ExifTags.IFD.Interop] = self.get_ifd(ExifTags.IFD.Interop) + ifd[tag] = value + return b"Exif\x00\x00" + head + ifd.tobytes(offset) + + def get_ifd(self, tag): + if tag not in self._ifds: + if tag == ExifTags.IFD.IFD1: + if self._info is not None and self._info.next != 0: + self._ifds[tag] = self._get_ifd_dict(self._info.next) + elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: + offset = self._hidden_data.get(tag, self.get(tag)) + if offset is not None: + self._ifds[tag] = self._get_ifd_dict(offset, tag) + elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]: + if ExifTags.IFD.Exif not in self._ifds: + self.get_ifd(ExifTags.IFD.Exif) + tag_data = self._ifds[ExifTags.IFD.Exif][tag] + if tag == ExifTags.IFD.Makernote: + from .TiffImagePlugin import ImageFileDirectory_v2 + + if tag_data[:8] == b"FUJIFILM": + ifd_offset = i32le(tag_data, 8) + ifd_data = tag_data[ifd_offset:] + + makernote = {} + for i in range(0, struct.unpack(" 4: + (offset,) = struct.unpack("H", tag_data[:2])[0]): + ifd_tag, typ, count, data = struct.unpack( + ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] + ) + if ifd_tag == 0x1101: + # CameraInfo + (offset,) = struct.unpack(">L", data) + self.fp.seek(offset) + + camerainfo = {"ModelID": self.fp.read(4)} + + self.fp.read(4) + # Seconds since 2000 + camerainfo["TimeStamp"] = i32le(self.fp.read(12)) + + self.fp.read(4) + camerainfo["InternalSerialNumber"] = self.fp.read(4) + + self.fp.read(12) + parallax = self.fp.read(4) + handler = ImageFileDirectory_v2._load_dispatch[ + TiffTags.FLOAT + ][1] + camerainfo["Parallax"] = handler( + ImageFileDirectory_v2(), parallax, False + ) + + self.fp.read(4) + camerainfo["Category"] = self.fp.read(2) + + makernote = {0x1101: dict(self._fixup_dict(camerainfo))} + self._ifds[tag] = makernote + else: + # Interop + self._ifds[tag] = self._get_ifd_dict(tag_data, tag) + ifd = self._ifds.get(tag, {}) + if tag == ExifTags.IFD.Exif and self._hidden_data: + ifd = { + k: v + for (k, v) in ifd.items() + if k not in (ExifTags.IFD.Interop, ExifTags.IFD.Makernote) + } + return ifd + + def hide_offsets(self) -> None: + for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo): + if tag in self: + self._hidden_data[tag] = self[tag] + del self[tag] + + def __str__(self) -> str: + if self._info is not None: + # Load all keys into self._data + for tag in self._info: + self[tag] + + return str(self._data) + + def __len__(self) -> int: + keys = set(self._data) + if self._info is not None: + keys.update(self._info) + return len(keys) + + def __getitem__(self, tag): + if self._info is not None and tag not in self._data and tag in self._info: + self._data[tag] = self._fixup(self._info[tag]) + del self._info[tag] + return self._data[tag] + + def __contains__(self, tag) -> bool: + return tag in self._data or (self._info is not None and tag in self._info) + + def __setitem__(self, tag, value) -> None: + if self._info is not None and tag in self._info: + del self._info[tag] + self._data[tag] = value + + def __delitem__(self, tag: int) -> None: + if self._info is not None and tag in self._info: + del self._info[tag] + else: + del self._data[tag] + + def __iter__(self): + keys = set(self._data) + if self._info is not None: + keys.update(self._info) + return iter(keys) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageChops.py b/.venv/lib/python3.12/site-packages/PIL/ImageChops.py new file mode 100644 index 0000000..29a5c99 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageChops.py @@ -0,0 +1,311 @@ +# +# The Python Imaging Library. +# $Id$ +# +# standard channel operations +# +# History: +# 1996-03-24 fl Created +# 1996-08-13 fl Added logical operations (for "1" images) +# 2000-10-12 fl Added offset method (from Image.py) +# +# Copyright (c) 1997-2000 by Secret Labs AB +# Copyright (c) 1996-2000 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# + +from __future__ import annotations + +from . import Image + + +def constant(image: Image.Image, value: int) -> Image.Image: + """Fill a channel with a given gray level. + + :rtype: :py:class:`~PIL.Image.Image` + """ + + return Image.new("L", image.size, value) + + +def duplicate(image: Image.Image) -> Image.Image: + """Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`. + + :rtype: :py:class:`~PIL.Image.Image` + """ + + return image.copy() + + +def invert(image: Image.Image) -> Image.Image: + """ + Invert an image (channel). :: + + out = MAX - image + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image.load() + return image._new(image.im.chop_invert()) + + +def lighter(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Compares the two images, pixel by pixel, and returns a new image containing + the lighter values. :: + + out = max(image1, image2) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_lighter(image2.im)) + + +def darker(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Compares the two images, pixel by pixel, and returns a new image containing + the darker values. :: + + out = min(image1, image2) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_darker(image2.im)) + + +def difference(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Returns the absolute value of the pixel-by-pixel difference between the two + images. :: + + out = abs(image1 - image2) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_difference(image2.im)) + + +def multiply(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Superimposes two images on top of each other. + + If you multiply an image with a solid black image, the result is black. If + you multiply with a solid white image, the image is unaffected. :: + + out = image1 * image2 / MAX + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_multiply(image2.im)) + + +def screen(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Superimposes two inverted images on top of each other. :: + + out = MAX - ((MAX - image1) * (MAX - image2) / MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_screen(image2.im)) + + +def soft_light(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Superimposes two images on top of each other using the Soft Light algorithm + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_soft_light(image2.im)) + + +def hard_light(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Superimposes two images on top of each other using the Hard Light algorithm + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_hard_light(image2.im)) + + +def overlay(image1: Image.Image, image2: Image.Image) -> Image.Image: + """ + Superimposes two images on top of each other using the Overlay algorithm + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_overlay(image2.im)) + + +def add( + image1: Image.Image, image2: Image.Image, scale: float = 1.0, offset: float = 0 +) -> Image.Image: + """ + Adds two images, dividing the result by scale and adding the + offset. If omitted, scale defaults to 1.0, and offset to 0.0. :: + + out = ((image1 + image2) / scale + offset) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_add(image2.im, scale, offset)) + + +def subtract( + image1: Image.Image, image2: Image.Image, scale: float = 1.0, offset: float = 0 +) -> Image.Image: + """ + Subtracts two images, dividing the result by scale and adding the offset. + If omitted, scale defaults to 1.0, and offset to 0.0. :: + + out = ((image1 - image2) / scale + offset) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_subtract(image2.im, scale, offset)) + + +def add_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image: + """Add two images, without clipping the result. :: + + out = ((image1 + image2) % MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_add_modulo(image2.im)) + + +def subtract_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image: + """Subtract two images, without clipping the result. :: + + out = ((image1 - image2) % MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_subtract_modulo(image2.im)) + + +def logical_and(image1: Image.Image, image2: Image.Image) -> Image.Image: + """Logical AND between two images. + + Both of the images must have mode "1". If you would like to perform a + logical AND on an image with a mode other than "1", try + :py:meth:`~PIL.ImageChops.multiply` instead, using a black-and-white mask + as the second image. :: + + out = ((image1 and image2) % MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_and(image2.im)) + + +def logical_or(image1: Image.Image, image2: Image.Image) -> Image.Image: + """Logical OR between two images. + + Both of the images must have mode "1". :: + + out = ((image1 or image2) % MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_or(image2.im)) + + +def logical_xor(image1: Image.Image, image2: Image.Image) -> Image.Image: + """Logical XOR between two images. + + Both of the images must have mode "1". :: + + out = ((bool(image1) != bool(image2)) % MAX) + + :rtype: :py:class:`~PIL.Image.Image` + """ + + image1.load() + image2.load() + return image1._new(image1.im.chop_xor(image2.im)) + + +def blend(image1: Image.Image, image2: Image.Image, alpha: float) -> Image.Image: + """Blend images using constant transparency weight. Alias for + :py:func:`PIL.Image.blend`. + + :rtype: :py:class:`~PIL.Image.Image` + """ + + return Image.blend(image1, image2, alpha) + + +def composite( + image1: Image.Image, image2: Image.Image, mask: Image.Image +) -> Image.Image: + """Create composite using transparency mask. Alias for + :py:func:`PIL.Image.composite`. + + :rtype: :py:class:`~PIL.Image.Image` + """ + + return Image.composite(image1, image2, mask) + + +def offset(image: Image.Image, xoffset: int, yoffset: int | None = None) -> Image.Image: + """Returns a copy of the image where data has been offset by the given + distances. Data wraps around the edges. If ``yoffset`` is omitted, it + is assumed to be equal to ``xoffset``. + + :param image: Input image. + :param xoffset: The horizontal distance. + :param yoffset: The vertical distance. If omitted, both + distances are set to the same value. + :rtype: :py:class:`~PIL.Image.Image` + """ + + if yoffset is None: + yoffset = xoffset + image.load() + return image._new(image.im.offset(xoffset, yoffset)) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageCms.py b/.venv/lib/python3.12/site-packages/PIL/ImageCms.py new file mode 100644 index 0000000..ec10230 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageCms.py @@ -0,0 +1,1127 @@ +# The Python Imaging Library. +# $Id$ + +# Optional color management support, based on Kevin Cazabon's PyCMS +# library. + +# Originally released under LGPL. Graciously donated to PIL in +# March 2009, for distribution under the standard PIL license + +# History: + +# 2009-03-08 fl Added to PIL. + +# Copyright (C) 2002-2003 Kevin Cazabon +# Copyright (c) 2009 by Fredrik Lundh +# Copyright (c) 2013 by Eric Soroos + +# See the README file for information on usage and redistribution. See +# below for the original description. +from __future__ import annotations + +import operator +import sys +from enum import IntEnum, IntFlag +from functools import reduce +from typing import Any, Literal, SupportsFloat, SupportsInt, Union + +from . import Image, __version__ +from ._deprecate import deprecate +from ._typing import SupportsRead + +try: + from . import _imagingcms as core +except ImportError as ex: + # Allow error import for doc purposes, but error out when accessing + # anything in core. + from ._util import DeferredError + + core = DeferredError.new(ex) + +_DESCRIPTION = """ +pyCMS + + a Python / PIL interface to the littleCMS ICC Color Management System + Copyright (C) 2002-2003 Kevin Cazabon + kevin@cazabon.com + https://www.cazabon.com + + pyCMS home page: https://www.cazabon.com/pyCMS + littleCMS home page: https://www.littlecms.com + (littleCMS is Copyright (C) 1998-2001 Marti Maria) + + Originally released under LGPL. Graciously donated to PIL in + March 2009, for distribution under the standard PIL license + + The pyCMS.py module provides a "clean" interface between Python/PIL and + pyCMSdll, taking care of some of the more complex handling of the direct + pyCMSdll functions, as well as error-checking and making sure that all + relevant data is kept together. + + While it is possible to call pyCMSdll functions directly, it's not highly + recommended. + + Version History: + + 1.0.0 pil Oct 2013 Port to LCMS 2. + + 0.1.0 pil mod March 10, 2009 + + Renamed display profile to proof profile. The proof + profile is the profile of the device that is being + simulated, not the profile of the device which is + actually used to display/print the final simulation + (that'd be the output profile) - also see LCMSAPI.txt + input colorspace -> using 'renderingIntent' -> proof + colorspace -> using 'proofRenderingIntent' -> output + colorspace + + Added LCMS FLAGS support. + Added FLAGS["SOFTPROOFING"] as default flag for + buildProofTransform (otherwise the proof profile/intent + would be ignored). + + 0.1.0 pil March 2009 - added to PIL, as PIL.ImageCms + + 0.0.2 alpha Jan 6, 2002 + + Added try/except statements around type() checks of + potential CObjects... Python won't let you use type() + on them, and raises a TypeError (stupid, if you ask + me!) + + Added buildProofTransformFromOpenProfiles() function. + Additional fixes in DLL, see DLL code for details. + + 0.0.1 alpha first public release, Dec. 26, 2002 + + Known to-do list with current version (of Python interface, not pyCMSdll): + + none + +""" + +_VERSION = "1.0.0 pil" + + +def __getattr__(name: str) -> Any: + if name == "DESCRIPTION": + deprecate("PIL.ImageCms.DESCRIPTION", 12) + return _DESCRIPTION + elif name == "VERSION": + deprecate("PIL.ImageCms.VERSION", 12) + return _VERSION + elif name == "FLAGS": + deprecate("PIL.ImageCms.FLAGS", 12, "PIL.ImageCms.Flags") + return _FLAGS + msg = f"module '{__name__}' has no attribute '{name}'" + raise AttributeError(msg) + + +# --------------------------------------------------------------------. + + +# +# intent/direction values + + +class Intent(IntEnum): + PERCEPTUAL = 0 + RELATIVE_COLORIMETRIC = 1 + SATURATION = 2 + ABSOLUTE_COLORIMETRIC = 3 + + +class Direction(IntEnum): + INPUT = 0 + OUTPUT = 1 + PROOF = 2 + + +# +# flags + + +class Flags(IntFlag): + """Flags and documentation are taken from ``lcms2.h``.""" + + NONE = 0 + NOCACHE = 0x0040 + """Inhibit 1-pixel cache""" + NOOPTIMIZE = 0x0100 + """Inhibit optimizations""" + NULLTRANSFORM = 0x0200 + """Don't transform anyway""" + GAMUTCHECK = 0x1000 + """Out of Gamut alarm""" + SOFTPROOFING = 0x4000 + """Do softproofing""" + BLACKPOINTCOMPENSATION = 0x2000 + NOWHITEONWHITEFIXUP = 0x0004 + """Don't fix scum dot""" + HIGHRESPRECALC = 0x0400 + """Use more memory to give better accuracy""" + LOWRESPRECALC = 0x0800 + """Use less memory to minimize resources""" + # this should be 8BITS_DEVICELINK, but that is not a valid name in Python: + USE_8BITS_DEVICELINK = 0x0008 + """Create 8 bits devicelinks""" + GUESSDEVICECLASS = 0x0020 + """Guess device class (for ``transform2devicelink``)""" + KEEP_SEQUENCE = 0x0080 + """Keep profile sequence for devicelink creation""" + FORCE_CLUT = 0x0002 + """Force CLUT optimization""" + CLUT_POST_LINEARIZATION = 0x0001 + """create postlinearization tables if possible""" + CLUT_PRE_LINEARIZATION = 0x0010 + """create prelinearization tables if possible""" + NONEGATIVES = 0x8000 + """Prevent negative numbers in floating point transforms""" + COPY_ALPHA = 0x04000000 + """Alpha channels are copied on ``cmsDoTransform()``""" + NODEFAULTRESOURCEDEF = 0x01000000 + + _GRIDPOINTS_1 = 1 << 16 + _GRIDPOINTS_2 = 2 << 16 + _GRIDPOINTS_4 = 4 << 16 + _GRIDPOINTS_8 = 8 << 16 + _GRIDPOINTS_16 = 16 << 16 + _GRIDPOINTS_32 = 32 << 16 + _GRIDPOINTS_64 = 64 << 16 + _GRIDPOINTS_128 = 128 << 16 + + @staticmethod + def GRIDPOINTS(n: int) -> Flags: + """ + Fine-tune control over number of gridpoints + + :param n: :py:class:`int` in range ``0 <= n <= 255`` + """ + return Flags.NONE | ((n & 0xFF) << 16) + + +_MAX_FLAG = reduce(operator.or_, Flags) + + +_FLAGS = { + "MATRIXINPUT": 1, + "MATRIXOUTPUT": 2, + "MATRIXONLY": (1 | 2), + "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot + # Don't create prelinearization tables on precalculated transforms + # (internal use): + "NOPRELINEARIZATION": 16, + "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink) + "NOTCACHE": 64, # Inhibit 1-pixel cache + "NOTPRECALC": 256, + "NULLTRANSFORM": 512, # Don't transform anyway + "HIGHRESPRECALC": 1024, # Use more memory to give better accuracy + "LOWRESPRECALC": 2048, # Use less memory to minimize resources + "WHITEBLACKCOMPENSATION": 8192, + "BLACKPOINTCOMPENSATION": 8192, + "GAMUTCHECK": 4096, # Out of Gamut alarm + "SOFTPROOFING": 16384, # Do softproofing + "PRESERVEBLACK": 32768, # Black preservation + "NODEFAULTRESOURCEDEF": 16777216, # CRD special + "GRIDPOINTS": lambda n: (n & 0xFF) << 16, # Gridpoints +} + + +# --------------------------------------------------------------------. +# Experimental PIL-level API +# --------------------------------------------------------------------. + +## +# Profile. + + +class ImageCmsProfile: + def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None: + """ + :param profile: Either a string representing a filename, + a file like object containing a profile or a + low-level profile object + + """ + + if isinstance(profile, str): + if sys.platform == "win32": + profile_bytes_path = profile.encode() + try: + profile_bytes_path.decode("ascii") + except UnicodeDecodeError: + with open(profile, "rb") as f: + self._set(core.profile_frombytes(f.read())) + return + self._set(core.profile_open(profile), profile) + elif hasattr(profile, "read"): + self._set(core.profile_frombytes(profile.read())) + elif isinstance(profile, core.CmsProfile): + self._set(profile) + else: + msg = "Invalid type for Profile" # type: ignore[unreachable] + raise TypeError(msg) + + def _set(self, profile: core.CmsProfile, filename: str | None = None) -> None: + self.profile = profile + self.filename = filename + self.product_name = None # profile.product_name + self.product_info = None # profile.product_info + + def tobytes(self) -> bytes: + """ + Returns the profile in a format suitable for embedding in + saved images. + + :returns: a bytes object containing the ICC profile. + """ + + return core.profile_tobytes(self.profile) + + +class ImageCmsTransform(Image.ImagePointHandler): + """ + Transform. This can be used with the procedural API, or with the standard + :py:func:`~PIL.Image.Image.point` method. + + Will return the output profile in the ``output.info['icc_profile']``. + """ + + def __init__( + self, + input: ImageCmsProfile, + output: ImageCmsProfile, + input_mode: str, + output_mode: str, + intent: Intent = Intent.PERCEPTUAL, + proof: ImageCmsProfile | None = None, + proof_intent: Intent = Intent.ABSOLUTE_COLORIMETRIC, + flags: Flags = Flags.NONE, + ): + supported_modes = ( + "RGB", + "RGBA", + "RGBX", + "CMYK", + "I;16", + "I;16L", + "I;16B", + "YCbCr", + "LAB", + "L", + "1", + ) + for mode in (input_mode, output_mode): + if mode not in supported_modes: + deprecate( + mode, + 12, + { + "L;16": "I;16 or I;16L", + "L:16B": "I;16B", + "YCCA": "YCbCr", + "YCC": "YCbCr", + }.get(mode), + ) + if proof is None: + self.transform = core.buildTransform( + input.profile, output.profile, input_mode, output_mode, intent, flags + ) + else: + self.transform = core.buildProofTransform( + input.profile, + output.profile, + proof.profile, + input_mode, + output_mode, + intent, + proof_intent, + flags, + ) + # Note: inputMode and outputMode are for pyCMS compatibility only + self.input_mode = self.inputMode = input_mode + self.output_mode = self.outputMode = output_mode + + self.output_profile = output + + def point(self, im: Image.Image) -> Image.Image: + return self.apply(im) + + def apply(self, im: Image.Image, imOut: Image.Image | None = None) -> Image.Image: + im.load() + if imOut is None: + imOut = Image.new(self.output_mode, im.size, None) + self.transform.apply(im.im.id, imOut.im.id) + imOut.info["icc_profile"] = self.output_profile.tobytes() + return imOut + + def apply_in_place(self, im: Image.Image) -> Image.Image: + im.load() + if im.mode != self.output_mode: + msg = "mode mismatch" + raise ValueError(msg) # wrong output mode + self.transform.apply(im.im.id, im.im.id) + im.info["icc_profile"] = self.output_profile.tobytes() + return im + + +def get_display_profile(handle: SupportsInt | None = None) -> ImageCmsProfile | None: + """ + (experimental) Fetches the profile for the current display device. + + :returns: ``None`` if the profile is not known. + """ + + if sys.platform != "win32": + return None + + from . import ImageWin # type: ignore[unused-ignore, unreachable] + + if isinstance(handle, ImageWin.HDC): + profile = core.get_display_profile_win32(int(handle), 1) + else: + profile = core.get_display_profile_win32(int(handle or 0)) + if profile is None: + return None + return ImageCmsProfile(profile) + + +# --------------------------------------------------------------------. +# pyCMS compatible layer +# --------------------------------------------------------------------. + +_CmsProfileCompatible = Union[ + str, SupportsRead[bytes], core.CmsProfile, ImageCmsProfile +] + + +class PyCMSError(Exception): + """(pyCMS) Exception class. + This is used for all errors in the pyCMS API.""" + + pass + + +def profileToProfile( + im: Image.Image, + inputProfile: _CmsProfileCompatible, + outputProfile: _CmsProfileCompatible, + renderingIntent: Intent = Intent.PERCEPTUAL, + outputMode: str | None = None, + inPlace: bool = False, + flags: Flags = Flags.NONE, +) -> Image.Image | None: + """ + (pyCMS) Applies an ICC transformation to a given image, mapping from + ``inputProfile`` to ``outputProfile``. + + If the input or output profiles specified are not valid filenames, a + :exc:`PyCMSError` will be raised. If ``inPlace`` is ``True`` and + ``outputMode != im.mode``, a :exc:`PyCMSError` will be raised. + If an error occurs during application of the profiles, + a :exc:`PyCMSError` will be raised. + If ``outputMode`` is not a mode supported by the ``outputProfile`` (or by pyCMS), + a :exc:`PyCMSError` will be raised. + + This function applies an ICC transformation to im from ``inputProfile``'s + color space to ``outputProfile``'s color space using the specified rendering + intent to decide how to handle out-of-gamut colors. + + ``outputMode`` can be used to specify that a color mode conversion is to + be done using these profiles, but the specified profiles must be able + to handle that mode. I.e., if converting im from RGB to CMYK using + profiles, the input profile must handle RGB data, and the output + profile must handle CMYK data. + + :param im: An open :py:class:`~PIL.Image.Image` object (i.e. Image.new(...) + or Image.open(...), etc.) + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this image, or a profile object + :param outputProfile: String, as a valid filename path to the ICC output + profile you wish to use for this image, or a profile object + :param renderingIntent: Integer (0-3) specifying the rendering intent you + wish to use for the transform + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :param outputMode: A valid PIL mode for the output image (i.e. "RGB", + "CMYK", etc.). Note: if rendering the image "inPlace", outputMode + MUST be the same mode as the input, or omitted completely. If + omitted, the outputMode will be the same as the mode of the input + image (im.mode) + :param inPlace: Boolean. If ``True``, the original image is modified in-place, + and ``None`` is returned. If ``False`` (default), a new + :py:class:`~PIL.Image.Image` object is returned with the transform applied. + :param flags: Integer (0-...) specifying additional flags + :returns: Either None or a new :py:class:`~PIL.Image.Image` object, depending on + the value of ``inPlace`` + :exception PyCMSError: + """ + + if outputMode is None: + outputMode = im.mode + + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): + msg = "renderingIntent must be an integer between 0 and 3" + raise PyCMSError(msg) + + if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): + msg = f"flags must be an integer between 0 and {_MAX_FLAG}" + raise PyCMSError(msg) + + try: + if not isinstance(inputProfile, ImageCmsProfile): + inputProfile = ImageCmsProfile(inputProfile) + if not isinstance(outputProfile, ImageCmsProfile): + outputProfile = ImageCmsProfile(outputProfile) + transform = ImageCmsTransform( + inputProfile, + outputProfile, + im.mode, + outputMode, + renderingIntent, + flags=flags, + ) + if inPlace: + transform.apply_in_place(im) + imOut = None + else: + imOut = transform.apply(im) + except (OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + return imOut + + +def getOpenProfile( + profileFilename: str | SupportsRead[bytes] | core.CmsProfile, +) -> ImageCmsProfile: + """ + (pyCMS) Opens an ICC profile file. + + The PyCMSProfile object can be passed back into pyCMS for use in creating + transforms and such (as in ImageCms.buildTransformFromOpenProfiles()). + + If ``profileFilename`` is not a valid filename for an ICC profile, + a :exc:`PyCMSError` will be raised. + + :param profileFilename: String, as a valid filename path to the ICC profile + you wish to open, or a file-like object. + :returns: A CmsProfile class object. + :exception PyCMSError: + """ + + try: + return ImageCmsProfile(profileFilename) + except (OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def buildTransform( + inputProfile: _CmsProfileCompatible, + outputProfile: _CmsProfileCompatible, + inMode: str, + outMode: str, + renderingIntent: Intent = Intent.PERCEPTUAL, + flags: Flags = Flags.NONE, +) -> ImageCmsTransform: + """ + (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the + ``outputProfile``. Use applyTransform to apply the transform to a given + image. + + If the input or output profiles specified are not valid filenames, a + :exc:`PyCMSError` will be raised. If an error occurs during creation + of the transform, a :exc:`PyCMSError` will be raised. + + If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile`` + (or by pyCMS), a :exc:`PyCMSError` will be raised. + + This function builds and returns an ICC transform from the ``inputProfile`` + to the ``outputProfile`` using the ``renderingIntent`` to determine what to do + with out-of-gamut colors. It will ONLY work for converting images that + are in ``inMode`` to images that are in ``outMode`` color format (PIL mode, + i.e. "RGB", "RGBA", "CMYK", etc.). + + Building the transform is a fair part of the overhead in + ImageCms.profileToProfile(), so if you're planning on converting multiple + images using the same input/output settings, this can save you time. + Once you have a transform object, it can be used with + ImageCms.applyProfile() to convert images without the need to re-compute + the lookup table for the transform. + + The reason pyCMS returns a class object rather than a handle directly + to the transform is that it needs to keep track of the PIL input/output + modes that the transform is meant for. These attributes are stored in + the ``inMode`` and ``outMode`` attributes of the object (which can be + manually overridden if you really want to, but I don't know of any + time that would be of use, or would even work). + + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this transform, or a profile object + :param outputProfile: String, as a valid filename path to the ICC output + profile you wish to use for this transform, or a profile object + :param inMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param outMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param renderingIntent: Integer (0-3) specifying the rendering intent you + wish to use for the transform + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :param flags: Integer (0-...) specifying additional flags + :returns: A CmsTransform class object. + :exception PyCMSError: + """ + + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): + msg = "renderingIntent must be an integer between 0 and 3" + raise PyCMSError(msg) + + if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): + msg = f"flags must be an integer between 0 and {_MAX_FLAG}" + raise PyCMSError(msg) + + try: + if not isinstance(inputProfile, ImageCmsProfile): + inputProfile = ImageCmsProfile(inputProfile) + if not isinstance(outputProfile, ImageCmsProfile): + outputProfile = ImageCmsProfile(outputProfile) + return ImageCmsTransform( + inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags + ) + except (OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def buildProofTransform( + inputProfile: _CmsProfileCompatible, + outputProfile: _CmsProfileCompatible, + proofProfile: _CmsProfileCompatible, + inMode: str, + outMode: str, + renderingIntent: Intent = Intent.PERCEPTUAL, + proofRenderingIntent: Intent = Intent.ABSOLUTE_COLORIMETRIC, + flags: Flags = Flags.SOFTPROOFING, +) -> ImageCmsTransform: + """ + (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the + ``outputProfile``, but tries to simulate the result that would be + obtained on the ``proofProfile`` device. + + If the input, output, or proof profiles specified are not valid + filenames, a :exc:`PyCMSError` will be raised. + + If an error occurs during creation of the transform, + a :exc:`PyCMSError` will be raised. + + If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile`` + (or by pyCMS), a :exc:`PyCMSError` will be raised. + + This function builds and returns an ICC transform from the ``inputProfile`` + to the ``outputProfile``, but tries to simulate the result that would be + obtained on the ``proofProfile`` device using ``renderingIntent`` and + ``proofRenderingIntent`` to determine what to do with out-of-gamut + colors. This is known as "soft-proofing". It will ONLY work for + converting images that are in ``inMode`` to images that are in outMode + color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.). + + Usage of the resulting transform object is exactly the same as with + ImageCms.buildTransform(). + + Proof profiling is generally used when using an output device to get a + good idea of what the final printed/displayed image would look like on + the ``proofProfile`` device when it's quicker and easier to use the + output device for judging color. Generally, this means that the + output device is a monitor, or a dye-sub printer (etc.), and the simulated + device is something more expensive, complicated, or time consuming + (making it difficult to make a real print for color judgement purposes). + + Soft-proofing basically functions by adjusting the colors on the + output device to match the colors of the device being simulated. However, + when the simulated device has a much wider gamut than the output + device, you may obtain marginal results. + + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this transform, or a profile object + :param outputProfile: String, as a valid filename path to the ICC output + (monitor, usually) profile you wish to use for this transform, or a + profile object + :param proofProfile: String, as a valid filename path to the ICC proof + profile you wish to use for this transform, or a profile object + :param inMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param outMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param renderingIntent: Integer (0-3) specifying the rendering intent you + wish to use for the input->proof (simulated) transform + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :param proofRenderingIntent: Integer (0-3) specifying the rendering intent + you wish to use for proof->output transform + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :param flags: Integer (0-...) specifying additional flags + :returns: A CmsTransform class object. + :exception PyCMSError: + """ + + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): + msg = "renderingIntent must be an integer between 0 and 3" + raise PyCMSError(msg) + + if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): + msg = f"flags must be an integer between 0 and {_MAX_FLAG}" + raise PyCMSError(msg) + + try: + if not isinstance(inputProfile, ImageCmsProfile): + inputProfile = ImageCmsProfile(inputProfile) + if not isinstance(outputProfile, ImageCmsProfile): + outputProfile = ImageCmsProfile(outputProfile) + if not isinstance(proofProfile, ImageCmsProfile): + proofProfile = ImageCmsProfile(proofProfile) + return ImageCmsTransform( + inputProfile, + outputProfile, + inMode, + outMode, + renderingIntent, + proofProfile, + proofRenderingIntent, + flags, + ) + except (OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +buildTransformFromOpenProfiles = buildTransform +buildProofTransformFromOpenProfiles = buildProofTransform + + +def applyTransform( + im: Image.Image, transform: ImageCmsTransform, inPlace: bool = False +) -> Image.Image | None: + """ + (pyCMS) Applies a transform to a given image. + + If ``im.mode != transform.input_mode``, a :exc:`PyCMSError` is raised. + + If ``inPlace`` is ``True`` and ``transform.input_mode != transform.output_mode``, a + :exc:`PyCMSError` is raised. + + If ``im.mode``, ``transform.input_mode`` or ``transform.output_mode`` is not + supported by pyCMSdll or the profiles you used for the transform, a + :exc:`PyCMSError` is raised. + + If an error occurs while the transform is being applied, + a :exc:`PyCMSError` is raised. + + This function applies a pre-calculated transform (from + ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles()) + to an image. The transform can be used for multiple images, saving + considerable calculation time if doing the same conversion multiple times. + + If you want to modify im in-place instead of receiving a new image as + the return value, set ``inPlace`` to ``True``. This can only be done if + ``transform.input_mode`` and ``transform.output_mode`` are the same, because we + can't change the mode in-place (the buffer sizes for some modes are + different). The default behavior is to return a new :py:class:`~PIL.Image.Image` + object of the same dimensions in mode ``transform.output_mode``. + + :param im: An :py:class:`~PIL.Image.Image` object, and ``im.mode`` must be the same + as the ``input_mode`` supported by the transform. + :param transform: A valid CmsTransform class object + :param inPlace: Bool. If ``True``, ``im`` is modified in place and ``None`` is + returned, if ``False``, a new :py:class:`~PIL.Image.Image` object with the + transform applied is returned (and ``im`` is not changed). The default is + ``False``. + :returns: Either ``None``, or a new :py:class:`~PIL.Image.Image` object, + depending on the value of ``inPlace``. The profile will be returned in + the image's ``info['icc_profile']``. + :exception PyCMSError: + """ + + try: + if inPlace: + transform.apply_in_place(im) + imOut = None + else: + imOut = transform.apply(im) + except (TypeError, ValueError) as v: + raise PyCMSError(v) from v + + return imOut + + +def createProfile( + colorSpace: Literal["LAB", "XYZ", "sRGB"], colorTemp: SupportsFloat = 0 +) -> core.CmsProfile: + """ + (pyCMS) Creates a profile. + + If colorSpace not in ``["LAB", "XYZ", "sRGB"]``, + a :exc:`PyCMSError` is raised. + + If using LAB and ``colorTemp`` is not a positive integer, + a :exc:`PyCMSError` is raised. + + If an error occurs while creating the profile, + a :exc:`PyCMSError` is raised. + + Use this function to create common profiles on-the-fly instead of + having to supply a profile on disk and knowing the path to it. It + returns a normal CmsProfile object that can be passed to + ImageCms.buildTransformFromOpenProfiles() to create a transform to apply + to images. + + :param colorSpace: String, the color space of the profile you wish to + create. + Currently only "LAB", "XYZ", and "sRGB" are supported. + :param colorTemp: Positive number for the white point for the profile, in + degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50 + illuminant if omitted (5000k). colorTemp is ONLY applied to LAB + profiles, and is ignored for XYZ and sRGB. + :returns: A CmsProfile class object + :exception PyCMSError: + """ + + if colorSpace not in ["LAB", "XYZ", "sRGB"]: + msg = ( + f"Color space not supported for on-the-fly profile creation ({colorSpace})" + ) + raise PyCMSError(msg) + + if colorSpace == "LAB": + try: + colorTemp = float(colorTemp) + except (TypeError, ValueError) as e: + msg = f'Color temperature must be numeric, "{colorTemp}" not valid' + raise PyCMSError(msg) from e + + try: + return core.createProfile(colorSpace, colorTemp) + except (TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileName(profile: _CmsProfileCompatible) -> str: + """ + + (pyCMS) Gets the internal product name for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, + a :exc:`PyCMSError` is raised If an error occurs while trying + to obtain the name tag, a :exc:`PyCMSError` is raised. + + Use this function to obtain the INTERNAL name of the profile (stored + in an ICC tag in the profile itself), usually the one used when the + profile was originally created. Sometimes this tag also contains + additional information supplied by the creator. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal name of the profile as stored + in an ICC tag. + :exception PyCMSError: + """ + + try: + # add an extra newline to preserve pyCMS compatibility + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + # do it in python, not c. + # // name was "%s - %s" (model, manufacturer) || Description , + # // but if the Model and Manufacturer were the same or the model + # // was long, Just the model, in 1.x + model = profile.profile.model + manufacturer = profile.profile.manufacturer + + if not (model or manufacturer): + return (profile.profile.profile_description or "") + "\n" + if not manufacturer or (model and len(model) > 30): + return f"{model}\n" + return f"{model} - {manufacturer}\n" + + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileInfo(profile: _CmsProfileCompatible) -> str: + """ + (pyCMS) Gets the internal product information for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, + a :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the info tag, + a :exc:`PyCMSError` is raised. + + Use this function to obtain the information stored in the profile's + info tag. This often contains details about the profile, and how it + was created, as supplied by the creator. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. + :exception PyCMSError: + """ + + try: + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + # add an extra newline to preserve pyCMS compatibility + # Python, not C. the white point bits weren't working well, + # so skipping. + # info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint + description = profile.profile.profile_description + cpright = profile.profile.copyright + elements = [element for element in (description, cpright) if element] + return "\r\n\r\n".join(elements) + "\r\n\r\n" + + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileCopyright(profile: _CmsProfileCompatible) -> str: + """ + (pyCMS) Gets the copyright for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, a + :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the copyright tag, + a :exc:`PyCMSError` is raised. + + Use this function to obtain the information stored in the profile's + copyright tag. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. + :exception PyCMSError: + """ + try: + # add an extra newline to preserve pyCMS compatibility + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + return (profile.profile.copyright or "") + "\n" + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileManufacturer(profile: _CmsProfileCompatible) -> str: + """ + (pyCMS) Gets the manufacturer for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, a + :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the manufacturer tag, a + :exc:`PyCMSError` is raised. + + Use this function to obtain the information stored in the profile's + manufacturer tag. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. + :exception PyCMSError: + """ + try: + # add an extra newline to preserve pyCMS compatibility + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + return (profile.profile.manufacturer or "") + "\n" + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileModel(profile: _CmsProfileCompatible) -> str: + """ + (pyCMS) Gets the model for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, a + :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the model tag, + a :exc:`PyCMSError` is raised. + + Use this function to obtain the information stored in the profile's + model tag. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. + :exception PyCMSError: + """ + + try: + # add an extra newline to preserve pyCMS compatibility + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + return (profile.profile.model or "") + "\n" + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getProfileDescription(profile: _CmsProfileCompatible) -> str: + """ + (pyCMS) Gets the description for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, a + :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the description tag, + a :exc:`PyCMSError` is raised. + + Use this function to obtain the information stored in the profile's + description tag. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in an + ICC tag. + :exception PyCMSError: + """ + + try: + # add an extra newline to preserve pyCMS compatibility + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + return (profile.profile.profile_description or "") + "\n" + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def getDefaultIntent(profile: _CmsProfileCompatible) -> int: + """ + (pyCMS) Gets the default intent name for the given profile. + + If ``profile`` isn't a valid CmsProfile object or filename to a profile, a + :exc:`PyCMSError` is raised. + + If an error occurs while trying to obtain the default intent, a + :exc:`PyCMSError` is raised. + + Use this function to determine the default (and usually best optimized) + rendering intent for this profile. Most profiles support multiple + rendering intents, but are intended mostly for one type of conversion. + If you wish to use a different intent than returned, use + ImageCms.isIntentSupported() to verify it will work first. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: Integer 0-3 specifying the default rendering intent for this + profile. + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :exception PyCMSError: + """ + + try: + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + return profile.profile.rendering_intent + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def isIntentSupported( + profile: _CmsProfileCompatible, intent: Intent, direction: Direction +) -> Literal[-1, 1]: + """ + (pyCMS) Checks if a given intent is supported. + + Use this function to verify that you can use your desired + ``intent`` with ``profile``, and that ``profile`` can be used for the + input/output/proof profile as you desire. + + Some profiles are created specifically for one "direction", can cannot + be used for others. Some profiles can only be used for certain + rendering intents, so it's best to either verify this before trying + to create a transform with them (using this function), or catch the + potential :exc:`PyCMSError` that will occur if they don't + support the modes you select. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :param intent: Integer (0-3) specifying the rendering intent you wish to + use with this profile + + ImageCms.Intent.PERCEPTUAL = 0 (DEFAULT) + ImageCms.Intent.RELATIVE_COLORIMETRIC = 1 + ImageCms.Intent.SATURATION = 2 + ImageCms.Intent.ABSOLUTE_COLORIMETRIC = 3 + + see the pyCMS documentation for details on rendering intents and what + they do. + :param direction: Integer specifying if the profile is to be used for + input, output, or proof + + INPUT = 0 (or use ImageCms.Direction.INPUT) + OUTPUT = 1 (or use ImageCms.Direction.OUTPUT) + PROOF = 2 (or use ImageCms.Direction.PROOF) + + :returns: 1 if the intent/direction are supported, -1 if they are not. + :exception PyCMSError: + """ + + try: + if not isinstance(profile, ImageCmsProfile): + profile = ImageCmsProfile(profile) + # FIXME: I get different results for the same data w. different + # compilers. Bug in LittleCMS or in the binding? + if profile.profile.is_intent_supported(intent, direction): + return 1 + else: + return -1 + except (AttributeError, OSError, TypeError, ValueError) as v: + raise PyCMSError(v) from v + + +def versions() -> tuple[str, str | None, str, str]: + """ + (pyCMS) Fetches versions. + """ + + deprecate( + "PIL.ImageCms.versions()", + 12, + '(PIL.features.version("littlecms2"), sys.version, PIL.__version__)', + ) + return _VERSION, core.littlecms_version, sys.version.split()[0], __version__ diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageColor.py b/.venv/lib/python3.12/site-packages/PIL/ImageColor.py new file mode 100644 index 0000000..9a15a8e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageColor.py @@ -0,0 +1,320 @@ +# +# The Python Imaging Library +# $Id$ +# +# map CSS3-style colour description strings to RGB +# +# History: +# 2002-10-24 fl Added support for CSS-style color strings +# 2002-12-15 fl Added RGBA support +# 2004-03-27 fl Fixed remaining int() problems for Python 1.5.2 +# 2004-07-19 fl Fixed gray/grey spelling issues +# 2009-03-05 fl Fixed rounding error in grayscale calculation +# +# Copyright (c) 2002-2004 by Secret Labs AB +# Copyright (c) 2002-2004 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import re +from functools import lru_cache + +from . import Image + + +@lru_cache +def getrgb(color: str) -> tuple[int, int, int] | tuple[int, int, int, int]: + """ + Convert a color string to an RGB or RGBA tuple. If the string cannot be + parsed, this function raises a :py:exc:`ValueError` exception. + + .. versionadded:: 1.1.4 + + :param color: A color string + :return: ``(red, green, blue[, alpha])`` + """ + if len(color) > 100: + msg = "color specifier is too long" + raise ValueError(msg) + color = color.lower() + + rgb = colormap.get(color, None) + if rgb: + if isinstance(rgb, tuple): + return rgb + rgb_tuple = getrgb(rgb) + assert len(rgb_tuple) == 3 + colormap[color] = rgb_tuple + return rgb_tuple + + # check for known string formats + if re.match("#[a-f0-9]{3}$", color): + return int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16) + + if re.match("#[a-f0-9]{4}$", color): + return ( + int(color[1] * 2, 16), + int(color[2] * 2, 16), + int(color[3] * 2, 16), + int(color[4] * 2, 16), + ) + + if re.match("#[a-f0-9]{6}$", color): + return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16) + + if re.match("#[a-f0-9]{8}$", color): + return ( + int(color[1:3], 16), + int(color[3:5], 16), + int(color[5:7], 16), + int(color[7:9], 16), + ) + + m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) + if m: + return int(m.group(1)), int(m.group(2)), int(m.group(3)) + + m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) + if m: + return ( + int((int(m.group(1)) * 255) / 100.0 + 0.5), + int((int(m.group(2)) * 255) / 100.0 + 0.5), + int((int(m.group(3)) * 255) / 100.0 + 0.5), + ) + + m = re.match( + r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color + ) + if m: + from colorsys import hls_to_rgb + + rgb_floats = hls_to_rgb( + float(m.group(1)) / 360.0, + float(m.group(3)) / 100.0, + float(m.group(2)) / 100.0, + ) + return ( + int(rgb_floats[0] * 255 + 0.5), + int(rgb_floats[1] * 255 + 0.5), + int(rgb_floats[2] * 255 + 0.5), + ) + + m = re.match( + r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color + ) + if m: + from colorsys import hsv_to_rgb + + rgb_floats = hsv_to_rgb( + float(m.group(1)) / 360.0, + float(m.group(2)) / 100.0, + float(m.group(3)) / 100.0, + ) + return ( + int(rgb_floats[0] * 255 + 0.5), + int(rgb_floats[1] * 255 + 0.5), + int(rgb_floats[2] * 255 + 0.5), + ) + + m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) + if m: + return int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)) + msg = f"unknown color specifier: {repr(color)}" + raise ValueError(msg) + + +@lru_cache +def getcolor(color: str, mode: str) -> int | tuple[int, ...]: + """ + Same as :py:func:`~PIL.ImageColor.getrgb` for most modes. However, if + ``mode`` is HSV, converts the RGB value to a HSV value, or if ``mode`` is + not color or a palette image, converts the RGB value to a grayscale value. + If the string cannot be parsed, this function raises a :py:exc:`ValueError` + exception. + + .. versionadded:: 1.1.4 + + :param color: A color string + :param mode: Convert result to this mode + :return: ``graylevel, (graylevel, alpha) or (red, green, blue[, alpha])`` + """ + # same as getrgb, but converts the result to the given mode + rgb, alpha = getrgb(color), 255 + if len(rgb) == 4: + alpha = rgb[3] + rgb = rgb[:3] + + if mode == "HSV": + from colorsys import rgb_to_hsv + + r, g, b = rgb + h, s, v = rgb_to_hsv(r / 255, g / 255, b / 255) + return int(h * 255), int(s * 255), int(v * 255) + elif Image.getmodebase(mode) == "L": + r, g, b = rgb + # ITU-R Recommendation 601-2 for nonlinear RGB + # scaled to 24 bits to match the convert's implementation. + graylevel = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16 + if mode[-1] == "A": + return graylevel, alpha + return graylevel + elif mode[-1] == "A": + return rgb + (alpha,) + return rgb + + +colormap: dict[str, str | tuple[int, int, int]] = { + # X11 colour table from https://drafts.csswg.org/css-color-4/, with + # gray/grey spelling issues fixed. This is a superset of HTML 4.0 + # colour names used in CSS 1. + "aliceblue": "#f0f8ff", + "antiquewhite": "#faebd7", + "aqua": "#00ffff", + "aquamarine": "#7fffd4", + "azure": "#f0ffff", + "beige": "#f5f5dc", + "bisque": "#ffe4c4", + "black": "#000000", + "blanchedalmond": "#ffebcd", + "blue": "#0000ff", + "blueviolet": "#8a2be2", + "brown": "#a52a2a", + "burlywood": "#deb887", + "cadetblue": "#5f9ea0", + "chartreuse": "#7fff00", + "chocolate": "#d2691e", + "coral": "#ff7f50", + "cornflowerblue": "#6495ed", + "cornsilk": "#fff8dc", + "crimson": "#dc143c", + "cyan": "#00ffff", + "darkblue": "#00008b", + "darkcyan": "#008b8b", + "darkgoldenrod": "#b8860b", + "darkgray": "#a9a9a9", + "darkgrey": "#a9a9a9", + "darkgreen": "#006400", + "darkkhaki": "#bdb76b", + "darkmagenta": "#8b008b", + "darkolivegreen": "#556b2f", + "darkorange": "#ff8c00", + "darkorchid": "#9932cc", + "darkred": "#8b0000", + "darksalmon": "#e9967a", + "darkseagreen": "#8fbc8f", + "darkslateblue": "#483d8b", + "darkslategray": "#2f4f4f", + "darkslategrey": "#2f4f4f", + "darkturquoise": "#00ced1", + "darkviolet": "#9400d3", + "deeppink": "#ff1493", + "deepskyblue": "#00bfff", + "dimgray": "#696969", + "dimgrey": "#696969", + "dodgerblue": "#1e90ff", + "firebrick": "#b22222", + "floralwhite": "#fffaf0", + "forestgreen": "#228b22", + "fuchsia": "#ff00ff", + "gainsboro": "#dcdcdc", + "ghostwhite": "#f8f8ff", + "gold": "#ffd700", + "goldenrod": "#daa520", + "gray": "#808080", + "grey": "#808080", + "green": "#008000", + "greenyellow": "#adff2f", + "honeydew": "#f0fff0", + "hotpink": "#ff69b4", + "indianred": "#cd5c5c", + "indigo": "#4b0082", + "ivory": "#fffff0", + "khaki": "#f0e68c", + "lavender": "#e6e6fa", + "lavenderblush": "#fff0f5", + "lawngreen": "#7cfc00", + "lemonchiffon": "#fffacd", + "lightblue": "#add8e6", + "lightcoral": "#f08080", + "lightcyan": "#e0ffff", + "lightgoldenrodyellow": "#fafad2", + "lightgreen": "#90ee90", + "lightgray": "#d3d3d3", + "lightgrey": "#d3d3d3", + "lightpink": "#ffb6c1", + "lightsalmon": "#ffa07a", + "lightseagreen": "#20b2aa", + "lightskyblue": "#87cefa", + "lightslategray": "#778899", + "lightslategrey": "#778899", + "lightsteelblue": "#b0c4de", + "lightyellow": "#ffffe0", + "lime": "#00ff00", + "limegreen": "#32cd32", + "linen": "#faf0e6", + "magenta": "#ff00ff", + "maroon": "#800000", + "mediumaquamarine": "#66cdaa", + "mediumblue": "#0000cd", + "mediumorchid": "#ba55d3", + "mediumpurple": "#9370db", + "mediumseagreen": "#3cb371", + "mediumslateblue": "#7b68ee", + "mediumspringgreen": "#00fa9a", + "mediumturquoise": "#48d1cc", + "mediumvioletred": "#c71585", + "midnightblue": "#191970", + "mintcream": "#f5fffa", + "mistyrose": "#ffe4e1", + "moccasin": "#ffe4b5", + "navajowhite": "#ffdead", + "navy": "#000080", + "oldlace": "#fdf5e6", + "olive": "#808000", + "olivedrab": "#6b8e23", + "orange": "#ffa500", + "orangered": "#ff4500", + "orchid": "#da70d6", + "palegoldenrod": "#eee8aa", + "palegreen": "#98fb98", + "paleturquoise": "#afeeee", + "palevioletred": "#db7093", + "papayawhip": "#ffefd5", + "peachpuff": "#ffdab9", + "peru": "#cd853f", + "pink": "#ffc0cb", + "plum": "#dda0dd", + "powderblue": "#b0e0e6", + "purple": "#800080", + "rebeccapurple": "#663399", + "red": "#ff0000", + "rosybrown": "#bc8f8f", + "royalblue": "#4169e1", + "saddlebrown": "#8b4513", + "salmon": "#fa8072", + "sandybrown": "#f4a460", + "seagreen": "#2e8b57", + "seashell": "#fff5ee", + "sienna": "#a0522d", + "silver": "#c0c0c0", + "skyblue": "#87ceeb", + "slateblue": "#6a5acd", + "slategray": "#708090", + "slategrey": "#708090", + "snow": "#fffafa", + "springgreen": "#00ff7f", + "steelblue": "#4682b4", + "tan": "#d2b48c", + "teal": "#008080", + "thistle": "#d8bfd8", + "tomato": "#ff6347", + "turquoise": "#40e0d0", + "violet": "#ee82ee", + "wheat": "#f5deb3", + "white": "#ffffff", + "whitesmoke": "#f5f5f5", + "yellow": "#ffff00", + "yellowgreen": "#9acd32", +} diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageDraw.py b/.venv/lib/python3.12/site-packages/PIL/ImageDraw.py new file mode 100644 index 0000000..244d3d5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageDraw.py @@ -0,0 +1,1206 @@ +# +# The Python Imaging Library +# $Id$ +# +# drawing interface operations +# +# History: +# 1996-04-13 fl Created (experimental) +# 1996-08-07 fl Filled polygons, ellipses. +# 1996-08-13 fl Added text support +# 1998-06-28 fl Handle I and F images +# 1998-12-29 fl Added arc; use arc primitive to draw ellipses +# 1999-01-10 fl Added shape stuff (experimental) +# 1999-02-06 fl Added bitmap support +# 1999-02-11 fl Changed all primitives to take options +# 1999-02-20 fl Fixed backwards compatibility +# 2000-10-12 fl Copy on write, when necessary +# 2001-02-18 fl Use default ink for bitmap/text also in fill mode +# 2002-10-24 fl Added support for CSS-style color strings +# 2002-12-10 fl Added experimental support for RGBA-on-RGB drawing +# 2002-12-11 fl Refactored low-level drawing API (work in progress) +# 2004-08-26 fl Made Draw() a factory function, added getdraw() support +# 2004-09-04 fl Added width support to line primitive +# 2004-09-10 fl Added font mode handling +# 2006-06-19 fl Added font bearing support (getmask2) +# +# Copyright (c) 1997-2006 by Secret Labs AB +# Copyright (c) 1996-2006 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import math +import numbers +import struct +from types import ModuleType +from typing import TYPE_CHECKING, AnyStr, Callable, List, Sequence, Tuple, Union, cast + +from . import Image, ImageColor +from ._deprecate import deprecate +from ._typing import Coords + +# experimental access to the outline API +Outline: Callable[[], Image.core._Outline] | None +try: + Outline = Image.core.outline +except AttributeError: + Outline = None + +if TYPE_CHECKING: + from . import ImageDraw2, ImageFont + +_Ink = Union[float, Tuple[int, ...], str] + +""" +A simple 2D drawing interface for PIL images. +

+Application code should use the Draw factory, instead of +directly. +""" + + +class ImageDraw: + font: ( + ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont | None + ) = None + + def __init__(self, im: Image.Image, mode: str | None = None) -> None: + """ + Create a drawing instance. + + :param im: The image to draw in. + :param mode: Optional mode to use for color values. For RGB + images, this argument can be RGB or RGBA (to blend the + drawing into the image). For all other modes, this argument + must be the same as the image mode. If omitted, the mode + defaults to the mode of the image. + """ + im.load() + if im.readonly: + im._copy() # make it writeable + blend = 0 + if mode is None: + mode = im.mode + if mode != im.mode: + if mode == "RGBA" and im.mode == "RGB": + blend = 1 + else: + msg = "mode mismatch" + raise ValueError(msg) + if mode == "P": + self.palette = im.palette + else: + self.palette = None + self._image = im + self.im = im.im + self.draw = Image.core.draw(self.im, blend) + self.mode = mode + if mode in ("I", "F"): + self.ink = self.draw.draw_ink(1) + else: + self.ink = self.draw.draw_ink(-1) + if mode in ("1", "P", "I", "F"): + # FIXME: fix Fill2 to properly support matte for I+F images + self.fontmode = "1" + else: + self.fontmode = "L" # aliasing is okay for other modes + self.fill = False + + def getfont( + self, + ) -> ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont: + """ + Get the current default font. + + To set the default font for this ImageDraw instance:: + + from PIL import ImageDraw, ImageFont + draw.font = ImageFont.truetype("Tests/fonts/FreeMono.ttf") + + To set the default font for all future ImageDraw instances:: + + from PIL import ImageDraw, ImageFont + ImageDraw.ImageDraw.font = ImageFont.truetype("Tests/fonts/FreeMono.ttf") + + If the current default font is ``None``, + it is initialized with ``ImageFont.load_default()``. + + :returns: An image font.""" + if not self.font: + # FIXME: should add a font repository + from . import ImageFont + + self.font = ImageFont.load_default() + return self.font + + def _getfont( + self, font_size: float | None + ) -> ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont: + if font_size is not None: + from . import ImageFont + + return ImageFont.load_default(font_size) + else: + return self.getfont() + + def _getink( + self, ink: _Ink | None, fill: _Ink | None = None + ) -> tuple[int | None, int | None]: + result_ink = None + result_fill = None + if ink is None and fill is None: + if self.fill: + result_fill = self.ink + else: + result_ink = self.ink + else: + if ink is not None: + if isinstance(ink, str): + ink = ImageColor.getcolor(ink, self.mode) + if self.palette and not isinstance(ink, numbers.Number): + ink = self.palette.getcolor(ink, self._image) + result_ink = self.draw.draw_ink(ink) + if fill is not None: + if isinstance(fill, str): + fill = ImageColor.getcolor(fill, self.mode) + if self.palette and not isinstance(fill, numbers.Number): + fill = self.palette.getcolor(fill, self._image) + result_fill = self.draw.draw_ink(fill) + return result_ink, result_fill + + def arc( + self, + xy: Coords, + start: float, + end: float, + fill: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw an arc.""" + ink, fill = self._getink(fill) + if ink is not None: + self.draw.draw_arc(xy, start, end, ink, width) + + def bitmap( + self, xy: Sequence[int], bitmap: Image.Image, fill: _Ink | None = None + ) -> None: + """Draw a bitmap.""" + bitmap.load() + ink, fill = self._getink(fill) + if ink is None: + ink = fill + if ink is not None: + self.draw.draw_bitmap(xy, bitmap.im, ink) + + def chord( + self, + xy: Coords, + start: float, + end: float, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a chord.""" + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_chord(xy, start, end, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + self.draw.draw_chord(xy, start, end, ink, 0, width) + + def ellipse( + self, + xy: Coords, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw an ellipse.""" + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_ellipse(xy, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + self.draw.draw_ellipse(xy, ink, 0, width) + + def circle( + self, + xy: Sequence[float], + radius: float, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a circle given center coordinates and a radius.""" + ellipse_xy = (xy[0] - radius, xy[1] - radius, xy[0] + radius, xy[1] + radius) + self.ellipse(ellipse_xy, fill, outline, width) + + def line( + self, + xy: Coords, + fill: _Ink | None = None, + width: int = 0, + joint: str | None = None, + ) -> None: + """Draw a line, or a connected sequence of line segments.""" + ink = self._getink(fill)[0] + if ink is not None: + self.draw.draw_lines(xy, ink, width) + if joint == "curve" and width > 4: + points: Sequence[Sequence[float]] + if isinstance(xy[0], (list, tuple)): + points = cast(Sequence[Sequence[float]], xy) + else: + points = [ + cast(Sequence[float], tuple(xy[i : i + 2])) + for i in range(0, len(xy), 2) + ] + for i in range(1, len(points) - 1): + point = points[i] + angles = [ + math.degrees(math.atan2(end[0] - start[0], start[1] - end[1])) + % 360 + for start, end in ( + (points[i - 1], point), + (point, points[i + 1]), + ) + ] + if angles[0] == angles[1]: + # This is a straight line, so no joint is required + continue + + def coord_at_angle( + coord: Sequence[float], angle: float + ) -> tuple[float, ...]: + x, y = coord + angle -= 90 + distance = width / 2 - 1 + return tuple( + p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d)) + for p, p_d in ( + (x, distance * math.cos(math.radians(angle))), + (y, distance * math.sin(math.radians(angle))), + ) + ) + + flipped = ( + angles[1] > angles[0] and angles[1] - 180 > angles[0] + ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0]) + coords = [ + (point[0] - width / 2 + 1, point[1] - width / 2 + 1), + (point[0] + width / 2 - 1, point[1] + width / 2 - 1), + ] + if flipped: + start, end = (angles[1] + 90, angles[0] + 90) + else: + start, end = (angles[0] - 90, angles[1] - 90) + self.pieslice(coords, start - 90, end - 90, fill) + + if width > 8: + # Cover potential gaps between the line and the joint + if flipped: + gap_coords = [ + coord_at_angle(point, angles[0] + 90), + point, + coord_at_angle(point, angles[1] + 90), + ] + else: + gap_coords = [ + coord_at_angle(point, angles[0] - 90), + point, + coord_at_angle(point, angles[1] - 90), + ] + self.line(gap_coords, fill, width=3) + + def shape( + self, + shape: Image.core._Outline, + fill: _Ink | None = None, + outline: _Ink | None = None, + ) -> None: + """(Experimental) Draw a shape.""" + shape.close() + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_outline(shape, fill_ink, 1) + if ink is not None and ink != fill_ink: + self.draw.draw_outline(shape, ink, 0) + + def pieslice( + self, + xy: Coords, + start: float, + end: float, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a pieslice.""" + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_pieslice(xy, start, end, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + self.draw.draw_pieslice(xy, start, end, ink, 0, width) + + def point(self, xy: Coords, fill: _Ink | None = None) -> None: + """Draw one or more individual pixels.""" + ink, fill = self._getink(fill) + if ink is not None: + self.draw.draw_points(xy, ink) + + def polygon( + self, + xy: Coords, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a polygon.""" + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_polygon(xy, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + if width == 1: + self.draw.draw_polygon(xy, ink, 0, width) + elif self.im is not None: + # To avoid expanding the polygon outwards, + # use the fill as a mask + mask = Image.new("1", self.im.size) + mask_ink = self._getink(1)[0] + + fill_im = mask.copy() + draw = Draw(fill_im) + draw.draw.draw_polygon(xy, mask_ink, 1) + + ink_im = mask.copy() + draw = Draw(ink_im) + width = width * 2 - 1 + draw.draw.draw_polygon(xy, mask_ink, 0, width) + + mask.paste(ink_im, mask=fill_im) + + im = Image.new(self.mode, self.im.size) + draw = Draw(im) + draw.draw.draw_polygon(xy, ink, 0, width) + self.im.paste(im.im, (0, 0) + im.size, mask.im) + + def regular_polygon( + self, + bounding_circle: Sequence[Sequence[float] | float], + n_sides: int, + rotation: float = 0, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a regular polygon.""" + xy = _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) + self.polygon(xy, fill, outline, width) + + def rectangle( + self, + xy: Coords, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + ) -> None: + """Draw a rectangle.""" + ink, fill_ink = self._getink(outline, fill) + if fill_ink is not None: + self.draw.draw_rectangle(xy, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + self.draw.draw_rectangle(xy, ink, 0, width) + + def rounded_rectangle( + self, + xy: Coords, + radius: float = 0, + fill: _Ink | None = None, + outline: _Ink | None = None, + width: int = 1, + *, + corners: tuple[bool, bool, bool, bool] | None = None, + ) -> None: + """Draw a rounded rectangle.""" + if isinstance(xy[0], (list, tuple)): + (x0, y0), (x1, y1) = cast(Sequence[Sequence[float]], xy) + else: + x0, y0, x1, y1 = cast(Sequence[float], xy) + if x1 < x0: + msg = "x1 must be greater than or equal to x0" + raise ValueError(msg) + if y1 < y0: + msg = "y1 must be greater than or equal to y0" + raise ValueError(msg) + if corners is None: + corners = (True, True, True, True) + + d = radius * 2 + + x0 = round(x0) + y0 = round(y0) + x1 = round(x1) + y1 = round(y1) + full_x, full_y = False, False + if all(corners): + full_x = d >= x1 - x0 - 1 + if full_x: + # The two left and two right corners are joined + d = x1 - x0 + full_y = d >= y1 - y0 - 1 + if full_y: + # The two top and two bottom corners are joined + d = y1 - y0 + if full_x and full_y: + # If all corners are joined, that is a circle + return self.ellipse(xy, fill, outline, width) + + if d == 0 or not any(corners): + # If the corners have no curve, + # or there are no corners, + # that is a rectangle + return self.rectangle(xy, fill, outline, width) + + r = int(d // 2) + ink, fill_ink = self._getink(outline, fill) + + def draw_corners(pieslice: bool) -> None: + parts: tuple[tuple[tuple[float, float, float, float], int, int], ...] + if full_x: + # Draw top and bottom halves + parts = ( + ((x0, y0, x0 + d, y0 + d), 180, 360), + ((x0, y1 - d, x0 + d, y1), 0, 180), + ) + elif full_y: + # Draw left and right halves + parts = ( + ((x0, y0, x0 + d, y0 + d), 90, 270), + ((x1 - d, y0, x1, y0 + d), 270, 90), + ) + else: + # Draw four separate corners + parts = tuple( + part + for i, part in enumerate( + ( + ((x0, y0, x0 + d, y0 + d), 180, 270), + ((x1 - d, y0, x1, y0 + d), 270, 360), + ((x1 - d, y1 - d, x1, y1), 0, 90), + ((x0, y1 - d, x0 + d, y1), 90, 180), + ) + ) + if corners[i] + ) + for part in parts: + if pieslice: + self.draw.draw_pieslice(*(part + (fill_ink, 1))) + else: + self.draw.draw_arc(*(part + (ink, width))) + + if fill_ink is not None: + draw_corners(True) + + if full_x: + self.draw.draw_rectangle((x0, y0 + r + 1, x1, y1 - r - 1), fill_ink, 1) + else: + self.draw.draw_rectangle((x0 + r + 1, y0, x1 - r - 1, y1), fill_ink, 1) + if not full_x and not full_y: + left = [x0, y0, x0 + r, y1] + if corners[0]: + left[1] += r + 1 + if corners[3]: + left[3] -= r + 1 + self.draw.draw_rectangle(left, fill_ink, 1) + + right = [x1 - r, y0, x1, y1] + if corners[1]: + right[1] += r + 1 + if corners[2]: + right[3] -= r + 1 + self.draw.draw_rectangle(right, fill_ink, 1) + if ink is not None and ink != fill_ink and width != 0: + draw_corners(False) + + if not full_x: + top = [x0, y0, x1, y0 + width - 1] + if corners[0]: + top[0] += r + 1 + if corners[1]: + top[2] -= r + 1 + self.draw.draw_rectangle(top, ink, 1) + + bottom = [x0, y1 - width + 1, x1, y1] + if corners[3]: + bottom[0] += r + 1 + if corners[2]: + bottom[2] -= r + 1 + self.draw.draw_rectangle(bottom, ink, 1) + if not full_y: + left = [x0, y0, x0 + width - 1, y1] + if corners[0]: + left[1] += r + 1 + if corners[3]: + left[3] -= r + 1 + self.draw.draw_rectangle(left, ink, 1) + + right = [x1 - width + 1, y0, x1, y1] + if corners[1]: + right[1] += r + 1 + if corners[2]: + right[3] -= r + 1 + self.draw.draw_rectangle(right, ink, 1) + + def _multiline_check(self, text: AnyStr) -> bool: + split_character = "\n" if isinstance(text, str) else b"\n" + + return split_character in text + + def _multiline_split(self, text: AnyStr) -> list[AnyStr]: + return text.split("\n" if isinstance(text, str) else b"\n") + + def _multiline_spacing(self, font, spacing, stroke_width): + return ( + self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3] + + stroke_width + + spacing + ) + + def text( + self, + xy: tuple[float, float], + text: str, + fill=None, + font: ( + ImageFont.ImageFont + | ImageFont.FreeTypeFont + | ImageFont.TransposedFont + | None + ) = None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + stroke_fill=None, + embedded_color=False, + *args, + **kwargs, + ) -> None: + """Draw text.""" + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + + if font is None: + font = self._getfont(kwargs.get("font_size")) + + if self._multiline_check(text): + return self.multiline_text( + xy, + text, + fill, + font, + anchor, + spacing, + align, + direction, + features, + language, + stroke_width, + stroke_fill, + embedded_color, + ) + + def getink(fill: _Ink | None) -> int: + ink, fill_ink = self._getink(fill) + if ink is None: + assert fill_ink is not None + return fill_ink + return ink + + def draw_text(ink, stroke_width=0, stroke_offset=None) -> None: + mode = self.fontmode + if stroke_width == 0 and embedded_color: + mode = "RGBA" + coord = [] + start = [] + for i in range(2): + coord.append(int(xy[i])) + start.append(math.modf(xy[i])[0]) + try: + mask, offset = font.getmask2( # type: ignore[union-attr,misc] + text, + mode, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + anchor=anchor, + ink=ink, + start=start, + *args, + **kwargs, + ) + coord = [coord[0] + offset[0], coord[1] + offset[1]] + except AttributeError: + try: + mask = font.getmask( # type: ignore[misc] + text, + mode, + direction, + features, + language, + stroke_width, + anchor, + ink, + start=start, + *args, + **kwargs, + ) + except TypeError: + mask = font.getmask(text) + if stroke_offset: + coord = [coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]] + if mode == "RGBA": + # font.getmask2(mode="RGBA") returns color in RGB bands and mask in A + # extract mask and set text alpha + color, mask = mask, mask.getband(3) + ink_alpha = struct.pack("i", ink)[3] + color.fillband(3, ink_alpha) + x, y = coord + if self.im is not None: + self.im.paste( + color, (x, y, x + mask.size[0], y + mask.size[1]), mask + ) + else: + self.draw.draw_bitmap(coord, mask, ink) + + ink = getink(fill) + if ink is not None: + stroke_ink = None + if stroke_width: + stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink + + if stroke_ink is not None: + # Draw stroked text + draw_text(stroke_ink, stroke_width) + + # Draw normal text + draw_text(ink, 0) + else: + # Only draw normal text + draw_text(ink) + + def multiline_text( + self, + xy: tuple[float, float], + text: str, + fill=None, + font: ( + ImageFont.ImageFont + | ImageFont.FreeTypeFont + | ImageFont.TransposedFont + | None + ) = None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + stroke_fill=None, + embedded_color=False, + *, + font_size=None, + ) -> None: + if direction == "ttb": + msg = "ttb direction is unsupported for multiline text" + raise ValueError(msg) + + if anchor is None: + anchor = "la" + elif len(anchor) != 2: + msg = "anchor must be a 2 character string" + raise ValueError(msg) + elif anchor[1] in "tb": + msg = "anchor not supported for multiline text" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + + widths = [] + max_width: float = 0 + lines = self._multiline_split(text) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) + for line in lines: + line_width = self.textlength( + line, font, direction=direction, features=features, language=language + ) + widths.append(line_width) + max_width = max(max_width, line_width) + + top = xy[1] + if anchor[1] == "m": + top -= (len(lines) - 1) * line_spacing / 2.0 + elif anchor[1] == "d": + top -= (len(lines) - 1) * line_spacing + + for idx, line in enumerate(lines): + left = xy[0] + width_difference = max_width - widths[idx] + + # first align left by anchor + if anchor[0] == "m": + left -= width_difference / 2.0 + elif anchor[0] == "r": + left -= width_difference + + # then align by align parameter + if align == "left": + pass + elif align == "center": + left += width_difference / 2.0 + elif align == "right": + left += width_difference + else: + msg = 'align must be "left", "center" or "right"' + raise ValueError(msg) + + self.text( + (left, top), + line, + fill, + font, + anchor, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + stroke_fill=stroke_fill, + embedded_color=embedded_color, + ) + top += line_spacing + + def textlength( + self, + text: str, + font: ( + ImageFont.ImageFont + | ImageFont.FreeTypeFont + | ImageFont.TransposedFont + | None + ) = None, + direction=None, + features=None, + language=None, + embedded_color=False, + *, + font_size=None, + ) -> float: + """Get the length of a given string, in pixels with 1/64 precision.""" + if self._multiline_check(text): + msg = "can't measure length of multiline text" + raise ValueError(msg) + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + mode = "RGBA" if embedded_color else self.fontmode + return font.getlength(text, mode, direction, features, language) + + def textbbox( + self, + xy, + text, + font=None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + embedded_color=False, + *, + font_size=None, + ) -> tuple[int, int, int, int]: + """Get the bounding box of a given string, in pixels.""" + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + + if self._multiline_check(text): + return self.multiline_textbbox( + xy, + text, + font, + anchor, + spacing, + align, + direction, + features, + language, + stroke_width, + embedded_color, + ) + + mode = "RGBA" if embedded_color else self.fontmode + bbox = font.getbbox( + text, mode, direction, features, language, stroke_width, anchor + ) + return bbox[0] + xy[0], bbox[1] + xy[1], bbox[2] + xy[0], bbox[3] + xy[1] + + def multiline_textbbox( + self, + xy, + text, + font=None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + embedded_color=False, + *, + font_size=None, + ) -> tuple[int, int, int, int]: + if direction == "ttb": + msg = "ttb direction is unsupported for multiline text" + raise ValueError(msg) + + if anchor is None: + anchor = "la" + elif len(anchor) != 2: + msg = "anchor must be a 2 character string" + raise ValueError(msg) + elif anchor[1] in "tb": + msg = "anchor not supported for multiline text" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + + widths = [] + max_width: float = 0 + lines = self._multiline_split(text) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) + for line in lines: + line_width = self.textlength( + line, + font, + direction=direction, + features=features, + language=language, + embedded_color=embedded_color, + ) + widths.append(line_width) + max_width = max(max_width, line_width) + + top = xy[1] + if anchor[1] == "m": + top -= (len(lines) - 1) * line_spacing / 2.0 + elif anchor[1] == "d": + top -= (len(lines) - 1) * line_spacing + + bbox: tuple[int, int, int, int] | None = None + + for idx, line in enumerate(lines): + left = xy[0] + width_difference = max_width - widths[idx] + + # first align left by anchor + if anchor[0] == "m": + left -= width_difference / 2.0 + elif anchor[0] == "r": + left -= width_difference + + # then align by align parameter + if align == "left": + pass + elif align == "center": + left += width_difference / 2.0 + elif align == "right": + left += width_difference + else: + msg = 'align must be "left", "center" or "right"' + raise ValueError(msg) + + bbox_line = self.textbbox( + (left, top), + line, + font, + anchor, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + embedded_color=embedded_color, + ) + if bbox is None: + bbox = bbox_line + else: + bbox = ( + min(bbox[0], bbox_line[0]), + min(bbox[1], bbox_line[1]), + max(bbox[2], bbox_line[2]), + max(bbox[3], bbox_line[3]), + ) + + top += line_spacing + + if bbox is None: + return xy[0], xy[1], xy[0], xy[1] + return bbox + + +def Draw(im: Image.Image, mode: str | None = None) -> ImageDraw: + """ + A simple 2D drawing interface for PIL images. + + :param im: The image to draw in. + :param mode: Optional mode to use for color values. For RGB + images, this argument can be RGB or RGBA (to blend the + drawing into the image). For all other modes, this argument + must be the same as the image mode. If omitted, the mode + defaults to the mode of the image. + """ + try: + return getattr(im, "getdraw")(mode) + except AttributeError: + return ImageDraw(im, mode) + + +def getdraw( + im: Image.Image | None = None, hints: list[str] | None = None +) -> tuple[ImageDraw2.Draw | None, ModuleType]: + """ + :param im: The image to draw in. + :param hints: An optional list of hints. Deprecated. + :returns: A (drawing context, drawing resource factory) tuple. + """ + if hints is not None: + deprecate("'hints' parameter", 12) + from . import ImageDraw2 + + draw = ImageDraw2.Draw(im) if im is not None else None + return draw, ImageDraw2 + + +def floodfill( + image: Image.Image, + xy: tuple[int, int], + value: float | tuple[int, ...], + border: float | tuple[int, ...] | None = None, + thresh: float = 0, +) -> None: + """ + .. warning:: This method is experimental. + + Fills a bounded region with a given color. + + :param image: Target image. + :param xy: Seed position (a 2-item coordinate tuple). See + :ref:`coordinate-system`. + :param value: Fill color. + :param border: Optional border value. If given, the region consists of + pixels with a color different from the border color. If not given, + the region consists of pixels having the same color as the seed + pixel. + :param thresh: Optional threshold value which specifies a maximum + tolerable difference of a pixel value from the 'background' in + order for it to be replaced. Useful for filling regions of + non-homogeneous, but similar, colors. + """ + # based on an implementation by Eric S. Raymond + # amended by yo1995 @20180806 + pixel = image.load() + assert pixel is not None + x, y = xy + try: + background = pixel[x, y] + if _color_diff(value, background) <= thresh: + return # seed point already has fill color + pixel[x, y] = value + except (ValueError, IndexError): + return # seed point outside image + edge = {(x, y)} + # use a set to keep record of current and previous edge pixels + # to reduce memory consumption + full_edge = set() + while edge: + new_edge = set() + for x, y in edge: # 4 adjacent method + for s, t in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)): + # If already processed, or if a coordinate is negative, skip + if (s, t) in full_edge or s < 0 or t < 0: + continue + try: + p = pixel[s, t] + except (ValueError, IndexError): + pass + else: + full_edge.add((s, t)) + if border is None: + fill = _color_diff(p, background) <= thresh + else: + fill = p not in (value, border) + if fill: + pixel[s, t] = value + new_edge.add((s, t)) + full_edge = edge # discard pixels processed + edge = new_edge + + +def _compute_regular_polygon_vertices( + bounding_circle: Sequence[Sequence[float] | float], n_sides: int, rotation: float +) -> list[tuple[float, float]]: + """ + Generate a list of vertices for a 2D regular polygon. + + :param bounding_circle: The bounding circle is a sequence defined + by a point and radius. The polygon is inscribed in this circle. + (e.g. ``bounding_circle=(x, y, r)`` or ``((x, y), r)``) + :param n_sides: Number of sides + (e.g. ``n_sides=3`` for a triangle, ``6`` for a hexagon) + :param rotation: Apply an arbitrary rotation to the polygon + (e.g. ``rotation=90``, applies a 90 degree rotation) + :return: List of regular polygon vertices + (e.g. ``[(25, 50), (50, 50), (50, 25), (25, 25)]``) + + How are the vertices computed? + 1. Compute the following variables + - theta: Angle between the apothem & the nearest polygon vertex + - side_length: Length of each polygon edge + - centroid: Center of bounding circle (1st, 2nd elements of bounding_circle) + - polygon_radius: Polygon radius (last element of bounding_circle) + - angles: Location of each polygon vertex in polar grid + (e.g. A square with 0 degree rotation => [225.0, 315.0, 45.0, 135.0]) + + 2. For each angle in angles, get the polygon vertex at that angle + The vertex is computed using the equation below. + X= xcos(φ) + ysin(φ) + Y= −xsin(φ) + ycos(φ) + + Note: + φ = angle in degrees + x = 0 + y = polygon_radius + + The formula above assumes rotation around the origin. + In our case, we are rotating around the centroid. + To account for this, we use the formula below + X = xcos(φ) + ysin(φ) + centroid_x + Y = −xsin(φ) + ycos(φ) + centroid_y + """ + # 1. Error Handling + # 1.1 Check `n_sides` has an appropriate value + if not isinstance(n_sides, int): + msg = "n_sides should be an int" # type: ignore[unreachable] + raise TypeError(msg) + if n_sides < 3: + msg = "n_sides should be an int > 2" + raise ValueError(msg) + + # 1.2 Check `bounding_circle` has an appropriate value + if not isinstance(bounding_circle, (list, tuple)): + msg = "bounding_circle should be a sequence" + raise TypeError(msg) + + if len(bounding_circle) == 3: + if not all(isinstance(i, (int, float)) for i in bounding_circle): + msg = "bounding_circle should only contain numeric data" + raise ValueError(msg) + + *centroid, polygon_radius = cast(List[float], list(bounding_circle)) + elif len(bounding_circle) == 2 and isinstance(bounding_circle[0], (list, tuple)): + if not all( + isinstance(i, (int, float)) for i in bounding_circle[0] + ) or not isinstance(bounding_circle[1], (int, float)): + msg = "bounding_circle should only contain numeric data" + raise ValueError(msg) + + if len(bounding_circle[0]) != 2: + msg = "bounding_circle centre should contain 2D coordinates (e.g. (x, y))" + raise ValueError(msg) + + centroid = cast(List[float], list(bounding_circle[0])) + polygon_radius = cast(float, bounding_circle[1]) + else: + msg = ( + "bounding_circle should contain 2D coordinates " + "and a radius (e.g. (x, y, r) or ((x, y), r) )" + ) + raise ValueError(msg) + + if polygon_radius <= 0: + msg = "bounding_circle radius should be > 0" + raise ValueError(msg) + + # 1.3 Check `rotation` has an appropriate value + if not isinstance(rotation, (int, float)): + msg = "rotation should be an int or float" # type: ignore[unreachable] + raise ValueError(msg) + + # 2. Define Helper Functions + def _apply_rotation(point: list[float], degrees: float) -> tuple[float, float]: + return ( + round( + point[0] * math.cos(math.radians(360 - degrees)) + - point[1] * math.sin(math.radians(360 - degrees)) + + centroid[0], + 2, + ), + round( + point[1] * math.cos(math.radians(360 - degrees)) + + point[0] * math.sin(math.radians(360 - degrees)) + + centroid[1], + 2, + ), + ) + + def _compute_polygon_vertex(angle: float) -> tuple[float, float]: + start_point = [polygon_radius, 0] + return _apply_rotation(start_point, angle) + + def _get_angles(n_sides: int, rotation: float) -> list[float]: + angles = [] + degrees = 360 / n_sides + # Start with the bottom left polygon vertex + current_angle = (270 - 0.5 * degrees) + rotation + for _ in range(0, n_sides): + angles.append(current_angle) + current_angle += degrees + if current_angle > 360: + current_angle -= 360 + return angles + + # 3. Variable Declarations + angles = _get_angles(n_sides, rotation) + + # 4. Compute Vertices + return [_compute_polygon_vertex(angle) for angle in angles] + + +def _color_diff( + color1: float | tuple[int, ...], color2: float | tuple[int, ...] +) -> float: + """ + Uses 1-norm distance to calculate difference between two values. + """ + first = color1 if isinstance(color1, tuple) else (color1,) + second = color2 if isinstance(color2, tuple) else (color2,) + + return sum(abs(first[i] - second[i]) for i in range(0, len(second))) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageDraw2.py b/.venv/lib/python3.12/site-packages/PIL/ImageDraw2.py new file mode 100644 index 0000000..e89a78b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageDraw2.py @@ -0,0 +1,206 @@ +# +# The Python Imaging Library +# $Id$ +# +# WCK-style drawing interface operations +# +# History: +# 2003-12-07 fl created +# 2005-05-15 fl updated; added to PIL as ImageDraw2 +# 2005-05-15 fl added text support +# 2005-05-20 fl added arc/chord/pieslice support +# +# Copyright (c) 2003-2005 by Secret Labs AB +# Copyright (c) 2003-2005 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# + + +""" +(Experimental) WCK-style drawing interface operations + +.. seealso:: :py:mod:`PIL.ImageDraw` +""" +from __future__ import annotations + +from typing import BinaryIO + +from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath +from ._typing import StrOrBytesPath + + +class Pen: + """Stores an outline color and width.""" + + def __init__(self, color: str, width: int = 1, opacity: int = 255) -> None: + self.color = ImageColor.getrgb(color) + self.width = width + + +class Brush: + """Stores a fill color""" + + def __init__(self, color: str, opacity: int = 255) -> None: + self.color = ImageColor.getrgb(color) + + +class Font: + """Stores a TrueType font and color""" + + def __init__( + self, color: str, file: StrOrBytesPath | BinaryIO, size: float = 12 + ) -> None: + # FIXME: add support for bitmap fonts + self.color = ImageColor.getrgb(color) + self.font = ImageFont.truetype(file, size) + + +class Draw: + """ + (Experimental) WCK-style drawing interface + """ + + def __init__( + self, + image: Image.Image | str, + size: tuple[int, int] | list[int] | None = None, + color: float | tuple[float, ...] | str | None = None, + ) -> None: + if isinstance(image, str): + if size is None: + msg = "If image argument is mode string, size must be a list or tuple" + raise ValueError(msg) + image = Image.new(image, size, color) + self.draw = ImageDraw.Draw(image) + self.image = image + self.transform = None + + def flush(self) -> Image.Image: + return self.image + + def render(self, op, xy, pen, brush=None): + # handle color arguments + outline = fill = None + width = 1 + if isinstance(pen, Pen): + outline = pen.color + width = pen.width + elif isinstance(brush, Pen): + outline = brush.color + width = brush.width + if isinstance(brush, Brush): + fill = brush.color + elif isinstance(pen, Brush): + fill = pen.color + # handle transformation + if self.transform: + xy = ImagePath.Path(xy) + xy.transform(self.transform) + # render the item + if op == "line": + self.draw.line(xy, fill=outline, width=width) + else: + getattr(self.draw, op)(xy, fill=fill, outline=outline) + + def settransform(self, offset): + """Sets a transformation offset.""" + (xoffset, yoffset) = offset + self.transform = (1, 0, xoffset, 0, 1, yoffset) + + def arc(self, xy, start, end, *options): + """ + Draws an arc (a portion of a circle outline) between the start and end + angles, inside the given bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.arc` + """ + self.render("arc", xy, start, end, *options) + + def chord(self, xy, start, end, *options): + """ + Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points + with a straight line. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord` + """ + self.render("chord", xy, start, end, *options) + + def ellipse(self, xy, *options): + """ + Draws an ellipse inside the given bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.ellipse` + """ + self.render("ellipse", xy, *options) + + def line(self, xy, *options): + """ + Draws a line between the coordinates in the ``xy`` list. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.line` + """ + self.render("line", xy, *options) + + def pieslice(self, xy, start, end, *options): + """ + Same as arc, but also draws straight lines between the end points and the + center of the bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.pieslice` + """ + self.render("pieslice", xy, start, end, *options) + + def polygon(self, xy, *options): + """ + Draws a polygon. + + The polygon outline consists of straight lines between the given + coordinates, plus a straight line between the last and the first + coordinate. + + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.polygon` + """ + self.render("polygon", xy, *options) + + def rectangle(self, xy, *options): + """ + Draws a rectangle. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.rectangle` + """ + self.render("rectangle", xy, *options) + + def text(self, xy, text, font): + """ + Draws the string at the given position. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.text` + """ + if self.transform: + xy = ImagePath.Path(xy) + xy.transform(self.transform) + self.draw.text(xy, text, font=font.font, fill=font.color) + + def textbbox(self, xy, text, font): + """ + Returns bounding box (in pixels) of given text. + + :return: ``(left, top, right, bottom)`` bounding box + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textbbox` + """ + if self.transform: + xy = ImagePath.Path(xy) + xy.transform(self.transform) + return self.draw.textbbox(xy, text, font=font.font) + + def textlength(self, text, font): + """ + Returns length (in pixels) of given text. + This is the amount by which following text should be offset. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textlength` + """ + return self.draw.textlength(text, font=font.font) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageEnhance.py b/.venv/lib/python3.12/site-packages/PIL/ImageEnhance.py new file mode 100644 index 0000000..d7e99a9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageEnhance.py @@ -0,0 +1,107 @@ +# +# The Python Imaging Library. +# $Id$ +# +# image enhancement classes +# +# For a background, see "Image Processing By Interpolation and +# Extrapolation", Paul Haeberli and Douglas Voorhies. Available +# at http://www.graficaobscura.com/interp/index.html +# +# History: +# 1996-03-23 fl Created +# 2009-06-16 fl Fixed mean calculation +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image, ImageFilter, ImageStat + + +class _Enhance: + image: Image.Image + degenerate: Image.Image + + def enhance(self, factor: float) -> Image.Image: + """ + Returns an enhanced image. + + :param factor: A floating point value controlling the enhancement. + Factor 1.0 always returns a copy of the original image, + lower factors mean less color (brightness, contrast, + etc), and higher values more. There are no restrictions + on this value. + :rtype: :py:class:`~PIL.Image.Image` + """ + return Image.blend(self.degenerate, self.image, factor) + + +class Color(_Enhance): + """Adjust image color balance. + + This class can be used to adjust the colour balance of an image, in + a manner similar to the controls on a colour TV set. An enhancement + factor of 0.0 gives a black and white image. A factor of 1.0 gives + the original image. + """ + + def __init__(self, image: Image.Image) -> None: + self.image = image + self.intermediate_mode = "L" + if "A" in image.getbands(): + self.intermediate_mode = "LA" + + self.degenerate = image.convert(self.intermediate_mode).convert(image.mode) + + +class Contrast(_Enhance): + """Adjust image contrast. + + This class can be used to control the contrast of an image, similar + to the contrast control on a TV set. An enhancement factor of 0.0 + gives a solid gray image. A factor of 1.0 gives the original image. + """ + + def __init__(self, image: Image.Image) -> None: + self.image = image + mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5) + self.degenerate = Image.new("L", image.size, mean).convert(image.mode) + + if "A" in image.getbands(): + self.degenerate.putalpha(image.getchannel("A")) + + +class Brightness(_Enhance): + """Adjust image brightness. + + This class can be used to control the brightness of an image. An + enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the + original image. + """ + + def __init__(self, image: Image.Image) -> None: + self.image = image + self.degenerate = Image.new(image.mode, image.size, 0) + + if "A" in image.getbands(): + self.degenerate.putalpha(image.getchannel("A")) + + +class Sharpness(_Enhance): + """Adjust image sharpness. + + This class can be used to adjust the sharpness of an image. An + enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the + original image, and a factor of 2.0 gives a sharpened image. + """ + + def __init__(self, image: Image.Image) -> None: + self.image = image + self.degenerate = image.filter(ImageFilter.SMOOTH) + + if "A" in image.getbands(): + self.degenerate.putalpha(image.getchannel("A")) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageFile.py b/.venv/lib/python3.12/site-packages/PIL/ImageFile.py new file mode 100644 index 0000000..69e7ee5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageFile.py @@ -0,0 +1,810 @@ +# +# The Python Imaging Library. +# $Id$ +# +# base class for image file handlers +# +# history: +# 1995-09-09 fl Created +# 1996-03-11 fl Fixed load mechanism. +# 1996-04-15 fl Added pcx/xbm decoders. +# 1996-04-30 fl Added encoders. +# 1996-12-14 fl Added load helpers +# 1997-01-11 fl Use encode_to_file where possible +# 1997-08-27 fl Flush output in _save +# 1998-03-05 fl Use memory mapping for some modes +# 1999-02-04 fl Use memory mapping also for "I;16" and "I;16B" +# 1999-05-31 fl Added image parser +# 2000-10-12 fl Set readonly flag on memory-mapped images +# 2002-03-20 fl Use better messages for common decoder errors +# 2003-04-21 fl Fall back on mmap/map_buffer if map is not available +# 2003-10-30 fl Added StubImageFile class +# 2004-02-25 fl Made incremental parser more robust +# +# Copyright (c) 1997-2004 by Secret Labs AB +# Copyright (c) 1995-2004 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import abc +import io +import itertools +import struct +import sys +from typing import IO, Any, NamedTuple + +from . import Image +from ._deprecate import deprecate +from ._util import is_path + +MAXBLOCK = 65536 + +SAFEBLOCK = 1024 * 1024 + +LOAD_TRUNCATED_IMAGES = False +"""Whether or not to load truncated image files. User code may change this.""" + +ERRORS = { + -1: "image buffer overrun error", + -2: "decoding error", + -3: "unknown error", + -8: "bad configuration", + -9: "out of memory error", +} +""" +Dict of known error codes returned from :meth:`.PyDecoder.decode`, +:meth:`.PyEncoder.encode` :meth:`.PyEncoder.encode_to_pyfd` and +:meth:`.PyEncoder.encode_to_file`. +""" + + +# +# -------------------------------------------------------------------- +# Helpers + + +def _get_oserror(error: int, *, encoder: bool) -> OSError: + try: + msg = Image.core.getcodecstatus(error) + except AttributeError: + msg = ERRORS.get(error) + if not msg: + msg = f"{'encoder' if encoder else 'decoder'} error {error}" + msg += f" when {'writing' if encoder else 'reading'} image file" + return OSError(msg) + + +def raise_oserror(error: int) -> OSError: + deprecate( + "raise_oserror", + 12, + action="It is only useful for translating error codes returned by a codec's " + "decode() method, which ImageFile already does automatically.", + ) + raise _get_oserror(error, encoder=False) + + +def _tilesort(t): + # sort on offset + return t[2] + + +class _Tile(NamedTuple): + codec_name: str + extents: tuple[int, int, int, int] + offset: int + args: tuple[Any, ...] | str | None + + +# +# -------------------------------------------------------------------- +# ImageFile base class + + +class ImageFile(Image.Image): + """Base class for image file format handlers.""" + + def __init__(self, fp=None, filename=None): + super().__init__() + + self._min_frame = 0 + + self.custom_mimetype = None + + self.tile = None + """ A list of tile descriptors, or ``None`` """ + + self.readonly = 1 # until we know better + + self.decoderconfig = () + self.decodermaxblock = MAXBLOCK + + if is_path(fp): + # filename + self.fp = open(fp, "rb") + self.filename = fp + self._exclusive_fp = True + else: + # stream + self.fp = fp + self.filename = filename + # can be overridden + self._exclusive_fp = None + + try: + try: + self._open() + except ( + IndexError, # end of data + TypeError, # end of data (ord) + KeyError, # unsupported mode + EOFError, # got header but not the first frame + struct.error, + ) as v: + raise SyntaxError(v) from v + + if not self.mode or self.size[0] <= 0 or self.size[1] <= 0: + msg = "not identified by this driver" + raise SyntaxError(msg) + except BaseException: + # close the file only if we have opened it this constructor + if self._exclusive_fp: + self.fp.close() + raise + + def get_format_mimetype(self) -> str | None: + if self.custom_mimetype: + return self.custom_mimetype + if self.format is not None: + return Image.MIME.get(self.format.upper()) + return None + + def __setstate__(self, state): + self.tile = [] + super().__setstate__(state) + + def verify(self) -> None: + """Check file integrity""" + + # raise exception if something's wrong. must be called + # directly after open, and closes file when finished. + if self._exclusive_fp: + self.fp.close() + self.fp = None + + def load(self): + """Load image data based on tile list""" + + if self.tile is None: + msg = "cannot load this image" + raise OSError(msg) + + pixel = Image.Image.load(self) + if not self.tile: + return pixel + + self.map = None + use_mmap = self.filename and len(self.tile) == 1 + # As of pypy 2.1.0, memory mapping was failing here. + use_mmap = use_mmap and not hasattr(sys, "pypy_version_info") + + readonly = 0 + + # look for read/seek overrides + try: + read = self.load_read + # don't use mmap if there are custom read/seek functions + use_mmap = False + except AttributeError: + read = self.fp.read + + try: + seek = self.load_seek + use_mmap = False + except AttributeError: + seek = self.fp.seek + + if use_mmap: + # try memory mapping + decoder_name, extents, offset, args = self.tile[0] + if isinstance(args, str): + args = (args, 0, 1) + if ( + decoder_name == "raw" + and len(args) >= 3 + and args[0] == self.mode + and args[0] in Image._MAPMODES + ): + try: + # use mmap, if possible + import mmap + + with open(self.filename) as fp: + self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) + if offset + self.size[1] * args[1] > self.map.size(): + msg = "buffer is not large enough" + raise OSError(msg) + self.im = Image.core.map_buffer( + self.map, self.size, decoder_name, offset, args + ) + readonly = 1 + # After trashing self.im, + # we might need to reload the palette data. + if self.palette: + self.palette.dirty = 1 + except (AttributeError, OSError, ImportError): + self.map = None + + self.load_prepare() + err_code = -3 # initialize to unknown error + if not self.map: + # sort tiles in file order + self.tile.sort(key=_tilesort) + + try: + # FIXME: This is a hack to handle TIFF's JpegTables tag. + prefix = self.tile_prefix + except AttributeError: + prefix = b"" + + # Remove consecutive duplicates that only differ by their offset + self.tile = [ + list(tiles)[-1] + for _, tiles in itertools.groupby( + self.tile, lambda tile: (tile[0], tile[1], tile[3]) + ) + ] + for decoder_name, extents, offset, args in self.tile: + seek(offset) + decoder = Image._getdecoder( + self.mode, decoder_name, args, self.decoderconfig + ) + try: + decoder.setimage(self.im, extents) + if decoder.pulls_fd: + decoder.setfd(self.fp) + err_code = decoder.decode(b"")[1] + else: + b = prefix + while True: + try: + s = read(self.decodermaxblock) + except (IndexError, struct.error) as e: + # truncated png/gif + if LOAD_TRUNCATED_IMAGES: + break + else: + msg = "image file is truncated" + raise OSError(msg) from e + + if not s: # truncated jpeg + if LOAD_TRUNCATED_IMAGES: + break + else: + msg = ( + "image file is truncated " + f"({len(b)} bytes not processed)" + ) + raise OSError(msg) + + b = b + s + n, err_code = decoder.decode(b) + if n < 0: + break + b = b[n:] + finally: + # Need to cleanup here to prevent leaks + decoder.cleanup() + + self.tile = [] + self.readonly = readonly + + self.load_end() + + if self._exclusive_fp and self._close_exclusive_fp_after_loading: + self.fp.close() + self.fp = None + + if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0: + # still raised if decoder fails to return anything + raise _get_oserror(err_code, encoder=False) + + return Image.Image.load(self) + + def load_prepare(self) -> None: + # create image memory if necessary + if not self.im or self.im.mode != self.mode or self.im.size != self.size: + self.im = Image.core.new(self.mode, self.size) + # create palette (optional) + if self.mode == "P": + Image.Image.load(self) + + def load_end(self) -> None: + # may be overridden + pass + + # may be defined for contained formats + # def load_seek(self, pos: int) -> None: + # pass + + # may be defined for blocked formats (e.g. PNG) + # def load_read(self, read_bytes: int) -> bytes: + # pass + + def _seek_check(self, frame): + if ( + frame < self._min_frame + # Only check upper limit on frames if additional seek operations + # are not required to do so + or ( + not (hasattr(self, "_n_frames") and self._n_frames is None) + and frame >= self.n_frames + self._min_frame + ) + ): + msg = "attempt to seek outside sequence" + raise EOFError(msg) + + return self.tell() != frame + + +class StubHandler: + def open(self, im: StubImageFile) -> None: + pass + + @abc.abstractmethod + def load(self, im: StubImageFile) -> Image.Image: + pass + + +class StubImageFile(ImageFile): + """ + Base class for stub image loaders. + + A stub loader is an image loader that can identify files of a + certain format, but relies on external code to load the file. + """ + + def _open(self) -> None: + msg = "StubImageFile subclass must implement _open" + raise NotImplementedError(msg) + + def load(self): + loader = self._load() + if loader is None: + msg = f"cannot find loader for this {self.format} file" + raise OSError(msg) + image = loader.load(self) + assert image is not None + # become the other object (!) + self.__class__ = image.__class__ + self.__dict__ = image.__dict__ + return image.load() + + def _load(self) -> StubHandler | None: + """(Hook) Find actual image loader.""" + msg = "StubImageFile subclass must implement _load" + raise NotImplementedError(msg) + + +class Parser: + """ + Incremental image parser. This class implements the standard + feed/close consumer interface. + """ + + incremental = None + image: Image.Image | None = None + data = None + decoder = None + offset = 0 + finished = 0 + + def reset(self) -> None: + """ + (Consumer) Reset the parser. Note that you can only call this + method immediately after you've created a parser; parser + instances cannot be reused. + """ + assert self.data is None, "cannot reuse parsers" + + def feed(self, data): + """ + (Consumer) Feed data to the parser. + + :param data: A string buffer. + :exception OSError: If the parser failed to parse the image file. + """ + # collect data + + if self.finished: + return + + if self.data is None: + self.data = data + else: + self.data = self.data + data + + # parse what we have + if self.decoder: + if self.offset > 0: + # skip header + skip = min(len(self.data), self.offset) + self.data = self.data[skip:] + self.offset = self.offset - skip + if self.offset > 0 or not self.data: + return + + n, e = self.decoder.decode(self.data) + + if n < 0: + # end of stream + self.data = None + self.finished = 1 + if e < 0: + # decoding error + self.image = None + raise _get_oserror(e, encoder=False) + else: + # end of image + return + self.data = self.data[n:] + + elif self.image: + # if we end up here with no decoder, this file cannot + # be incrementally parsed. wait until we've gotten all + # available data + pass + + else: + # attempt to open this file + try: + with io.BytesIO(self.data) as fp: + im = Image.open(fp) + except OSError: + pass # not enough data + else: + flag = hasattr(im, "load_seek") or hasattr(im, "load_read") + if flag or len(im.tile) != 1: + # custom load code, or multiple tiles + self.decode = None + else: + # initialize decoder + im.load_prepare() + d, e, o, a = im.tile[0] + im.tile = [] + self.decoder = Image._getdecoder(im.mode, d, a, im.decoderconfig) + self.decoder.setimage(im.im, e) + + # calculate decoder offset + self.offset = o + if self.offset <= len(self.data): + self.data = self.data[self.offset :] + self.offset = 0 + + self.image = im + + def __enter__(self): + return self + + def __exit__(self, *args: object) -> None: + self.close() + + def close(self): + """ + (Consumer) Close the stream. + + :returns: An image object. + :exception OSError: If the parser failed to parse the image file either + because it cannot be identified or cannot be + decoded. + """ + # finish decoding + if self.decoder: + # get rid of what's left in the buffers + self.feed(b"") + self.data = self.decoder = None + if not self.finished: + msg = "image was incomplete" + raise OSError(msg) + if not self.image: + msg = "cannot parse this image" + raise OSError(msg) + if self.data: + # incremental parsing not possible; reopen the file + # not that we have all data + with io.BytesIO(self.data) as fp: + try: + self.image = Image.open(fp) + finally: + self.image.load() + return self.image + + +# -------------------------------------------------------------------- + + +def _save(im, fp, tile, bufsize=0) -> None: + """Helper to save image based on tile list + + :param im: Image object. + :param fp: File object. + :param tile: Tile list. + :param bufsize: Optional buffer size + """ + + im.load() + if not hasattr(im, "encoderconfig"): + im.encoderconfig = () + tile.sort(key=_tilesort) + # FIXME: make MAXBLOCK a configuration parameter + # It would be great if we could have the encoder specify what it needs + # But, it would need at least the image size in most cases. RawEncode is + # a tricky case. + bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c + try: + fh = fp.fileno() + fp.flush() + _encode_tile(im, fp, tile, bufsize, fh) + except (AttributeError, io.UnsupportedOperation) as exc: + _encode_tile(im, fp, tile, bufsize, None, exc) + if hasattr(fp, "flush"): + fp.flush() + + +def _encode_tile(im, fp, tile: list[_Tile], bufsize, fh, exc=None): + for encoder_name, extents, offset, args in tile: + if offset > 0: + fp.seek(offset) + encoder = Image._getencoder(im.mode, encoder_name, args, im.encoderconfig) + try: + encoder.setimage(im.im, extents) + if encoder.pushes_fd: + encoder.setfd(fp) + errcode = encoder.encode_to_pyfd()[1] + else: + if exc: + # compress to Python file-compatible object + while True: + errcode, data = encoder.encode(bufsize)[1:] + fp.write(data) + if errcode: + break + else: + # slight speedup: compress to real file object + errcode = encoder.encode_to_file(fh, bufsize) + if errcode < 0: + raise _get_oserror(errcode, encoder=True) from exc + finally: + encoder.cleanup() + + +def _safe_read(fp, size): + """ + Reads large blocks in a safe way. Unlike fp.read(n), this function + doesn't trust the user. If the requested size is larger than + SAFEBLOCK, the file is read block by block. + + :param fp: File handle. Must implement a read method. + :param size: Number of bytes to read. + :returns: A string containing size bytes of data. + + Raises an OSError if the file is truncated and the read cannot be completed + + """ + if size <= 0: + return b"" + if size <= SAFEBLOCK: + data = fp.read(size) + if len(data) < size: + msg = "Truncated File Read" + raise OSError(msg) + return data + data = [] + remaining_size = size + while remaining_size > 0: + block = fp.read(min(remaining_size, SAFEBLOCK)) + if not block: + break + data.append(block) + remaining_size -= len(block) + if sum(len(d) for d in data) < size: + msg = "Truncated File Read" + raise OSError(msg) + return b"".join(data) + + +class PyCodecState: + def __init__(self) -> None: + self.xsize = 0 + self.ysize = 0 + self.xoff = 0 + self.yoff = 0 + + def extents(self) -> tuple[int, int, int, int]: + return self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize + + +class PyCodec: + fd: IO[bytes] | None + + def __init__(self, mode, *args): + self.im = None + self.state = PyCodecState() + self.fd = None + self.mode = mode + self.init(args) + + def init(self, args): + """ + Override to perform codec specific initialization + + :param args: Array of args items from the tile entry + :returns: None + """ + self.args = args + + def cleanup(self) -> None: + """ + Override to perform codec specific cleanup + + :returns: None + """ + pass + + def setfd(self, fd): + """ + Called from ImageFile to set the Python file-like object + + :param fd: A Python file-like object + :returns: None + """ + self.fd = fd + + def setimage(self, im, extents: tuple[int, int, int, int] | None = None) -> None: + """ + Called from ImageFile to set the core output image for the codec + + :param im: A core image object + :param extents: a 4 tuple of (x0, y0, x1, y1) defining the rectangle + for this tile + :returns: None + """ + + # following c code + self.im = im + + if extents: + (x0, y0, x1, y1) = extents + else: + (x0, y0, x1, y1) = (0, 0, 0, 0) + + if x0 == 0 and x1 == 0: + self.state.xsize, self.state.ysize = self.im.size + else: + self.state.xoff = x0 + self.state.yoff = y0 + self.state.xsize = x1 - x0 + self.state.ysize = y1 - y0 + + if self.state.xsize <= 0 or self.state.ysize <= 0: + msg = "Size cannot be negative" + raise ValueError(msg) + + if ( + self.state.xsize + self.state.xoff > self.im.size[0] + or self.state.ysize + self.state.yoff > self.im.size[1] + ): + msg = "Tile cannot extend outside image" + raise ValueError(msg) + + +class PyDecoder(PyCodec): + """ + Python implementation of a format decoder. Override this class and + add the decoding logic in the :meth:`decode` method. + + See :ref:`Writing Your Own File Codec in Python` + """ + + _pulls_fd = False + + @property + def pulls_fd(self) -> bool: + return self._pulls_fd + + def decode(self, buffer: bytes) -> tuple[int, int]: + """ + Override to perform the decoding process. + + :param buffer: A bytes object with the data to be decoded. + :returns: A tuple of ``(bytes consumed, errcode)``. + If finished with decoding return -1 for the bytes consumed. + Err codes are from :data:`.ImageFile.ERRORS`. + """ + msg = "unavailable in base decoder" + raise NotImplementedError(msg) + + def set_as_raw(self, data: bytes, rawmode=None) -> None: + """ + Convenience method to set the internal image from a stream of raw data + + :param data: Bytes to be set + :param rawmode: The rawmode to be used for the decoder. + If not specified, it will default to the mode of the image + :returns: None + """ + + if not rawmode: + rawmode = self.mode + d = Image._getdecoder(self.mode, "raw", rawmode) + assert self.im is not None + d.setimage(self.im, self.state.extents()) + s = d.decode(data) + + if s[0] >= 0: + msg = "not enough image data" + raise ValueError(msg) + if s[1] != 0: + msg = "cannot decode image data" + raise ValueError(msg) + + +class PyEncoder(PyCodec): + """ + Python implementation of a format encoder. Override this class and + add the decoding logic in the :meth:`encode` method. + + See :ref:`Writing Your Own File Codec in Python` + """ + + _pushes_fd = False + + @property + def pushes_fd(self) -> bool: + return self._pushes_fd + + def encode(self, bufsize: int) -> tuple[int, int, bytes]: + """ + Override to perform the encoding process. + + :param bufsize: Buffer size. + :returns: A tuple of ``(bytes encoded, errcode, bytes)``. + If finished with encoding return 1 for the error code. + Err codes are from :data:`.ImageFile.ERRORS`. + """ + msg = "unavailable in base encoder" + raise NotImplementedError(msg) + + def encode_to_pyfd(self) -> tuple[int, int]: + """ + If ``pushes_fd`` is ``True``, then this method will be used, + and ``encode()`` will only be called once. + + :returns: A tuple of ``(bytes consumed, errcode)``. + Err codes are from :data:`.ImageFile.ERRORS`. + """ + if not self.pushes_fd: + return 0, -8 # bad configuration + bytes_consumed, errcode, data = self.encode(0) + if data: + assert self.fd is not None + self.fd.write(data) + return bytes_consumed, errcode + + def encode_to_file(self, fh, bufsize): + """ + :param fh: File handle. + :param bufsize: Buffer size. + + :returns: If finished successfully, return 0. + Otherwise, return an error code. Err codes are from + :data:`.ImageFile.ERRORS`. + """ + errcode = 0 + while errcode == 0: + status, errcode, buf = self.encode(bufsize) + if status > 0: + fh.write(buf[status:]) + return errcode diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageFilter.py b/.venv/lib/python3.12/site-packages/PIL/ImageFilter.py new file mode 100644 index 0000000..e18b4a4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageFilter.py @@ -0,0 +1,604 @@ +# +# The Python Imaging Library. +# $Id$ +# +# standard filters +# +# History: +# 1995-11-27 fl Created +# 2002-06-08 fl Added rank and mode filters +# 2003-09-15 fl Fixed rank calculation in rank filter; added expand call +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1995-2002 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import abc +import functools +from types import ModuleType +from typing import TYPE_CHECKING, Any, Callable, Sequence, cast + +if TYPE_CHECKING: + from . import _imaging + from ._typing import NumpyArray + + +class Filter: + @abc.abstractmethod + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + pass + + +class MultibandFilter(Filter): + pass + + +class BuiltinFilter(MultibandFilter): + filterargs: tuple[Any, ...] + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + if image.mode == "P": + msg = "cannot filter palette images" + raise ValueError(msg) + return image.filter(*self.filterargs) + + +class Kernel(BuiltinFilter): + """ + Create a convolution kernel. This only supports 3x3 and 5x5 integer and floating + point kernels. + + Kernels can only be applied to "L" and "RGB" images. + + :param size: Kernel size, given as (width, height). This must be (3,3) or (5,5). + :param kernel: A sequence containing kernel weights. The kernel will be flipped + vertically before being applied to the image. + :param scale: Scale factor. If given, the result for each pixel is divided by this + value. The default is the sum of the kernel weights. + :param offset: Offset. If given, this value is added to the result, after it has + been divided by the scale factor. + """ + + name = "Kernel" + + def __init__( + self, + size: tuple[int, int], + kernel: Sequence[float], + scale: float | None = None, + offset: float = 0, + ) -> None: + if scale is None: + # default scale is sum of kernel + scale = functools.reduce(lambda a, b: a + b, kernel) + if size[0] * size[1] != len(kernel): + msg = "not enough coefficients in kernel" + raise ValueError(msg) + self.filterargs = size, scale, offset, kernel + + +class RankFilter(Filter): + """ + Create a rank filter. The rank filter sorts all pixels in + a window of the given size, and returns the ``rank``'th value. + + :param size: The kernel size, in pixels. + :param rank: What pixel value to pick. Use 0 for a min filter, + ``size * size / 2`` for a median filter, ``size * size - 1`` + for a max filter, etc. + """ + + name = "Rank" + + def __init__(self, size: int, rank: int) -> None: + self.size = size + self.rank = rank + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + if image.mode == "P": + msg = "cannot filter palette images" + raise ValueError(msg) + image = image.expand(self.size // 2, self.size // 2) + return image.rankfilter(self.size, self.rank) + + +class MedianFilter(RankFilter): + """ + Create a median filter. Picks the median pixel value in a window with the + given size. + + :param size: The kernel size, in pixels. + """ + + name = "Median" + + def __init__(self, size: int = 3) -> None: + self.size = size + self.rank = size * size // 2 + + +class MinFilter(RankFilter): + """ + Create a min filter. Picks the lowest pixel value in a window with the + given size. + + :param size: The kernel size, in pixels. + """ + + name = "Min" + + def __init__(self, size: int = 3) -> None: + self.size = size + self.rank = 0 + + +class MaxFilter(RankFilter): + """ + Create a max filter. Picks the largest pixel value in a window with the + given size. + + :param size: The kernel size, in pixels. + """ + + name = "Max" + + def __init__(self, size: int = 3) -> None: + self.size = size + self.rank = size * size - 1 + + +class ModeFilter(Filter): + """ + Create a mode filter. Picks the most frequent pixel value in a box with the + given size. Pixel values that occur only once or twice are ignored; if no + pixel value occurs more than twice, the original pixel value is preserved. + + :param size: The kernel size, in pixels. + """ + + name = "Mode" + + def __init__(self, size: int = 3) -> None: + self.size = size + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + return image.modefilter(self.size) + + +class GaussianBlur(MultibandFilter): + """Blurs the image with a sequence of extended box filters, which + approximates a Gaussian kernel. For details on accuracy see + + + :param radius: Standard deviation of the Gaussian kernel. Either a sequence of two + numbers for x and y, or a single number for both. + """ + + name = "GaussianBlur" + + def __init__(self, radius: float | Sequence[float] = 2) -> None: + self.radius = radius + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + xy = self.radius + if isinstance(xy, (int, float)): + xy = (xy, xy) + if xy == (0, 0): + return image.copy() + return image.gaussian_blur(xy) + + +class BoxBlur(MultibandFilter): + """Blurs the image by setting each pixel to the average value of the pixels + in a square box extending radius pixels in each direction. + Supports float radius of arbitrary size. Uses an optimized implementation + which runs in linear time relative to the size of the image + for any radius value. + + :param radius: Size of the box in a direction. Either a sequence of two numbers for + x and y, or a single number for both. + + Radius 0 does not blur, returns an identical image. + Radius 1 takes 1 pixel in each direction, i.e. 9 pixels in total. + """ + + name = "BoxBlur" + + def __init__(self, radius: float | Sequence[float]) -> None: + xy = radius if isinstance(radius, (tuple, list)) else (radius, radius) + if xy[0] < 0 or xy[1] < 0: + msg = "radius must be >= 0" + raise ValueError(msg) + self.radius = radius + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + xy = self.radius + if isinstance(xy, (int, float)): + xy = (xy, xy) + if xy == (0, 0): + return image.copy() + return image.box_blur(xy) + + +class UnsharpMask(MultibandFilter): + """Unsharp mask filter. + + See Wikipedia's entry on `digital unsharp masking`_ for an explanation of + the parameters. + + :param radius: Blur Radius + :param percent: Unsharp strength, in percent + :param threshold: Threshold controls the minimum brightness change that + will be sharpened + + .. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking + + """ + + name = "UnsharpMask" + + def __init__( + self, radius: float = 2, percent: int = 150, threshold: int = 3 + ) -> None: + self.radius = radius + self.percent = percent + self.threshold = threshold + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + return image.unsharp_mask(self.radius, self.percent, self.threshold) + + +class BLUR(BuiltinFilter): + name = "Blur" + # fmt: off + filterargs = (5, 5), 16, 0, ( + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + ) + # fmt: on + + +class CONTOUR(BuiltinFilter): + name = "Contour" + # fmt: off + filterargs = (3, 3), 1, 255, ( + -1, -1, -1, + -1, 8, -1, + -1, -1, -1, + ) + # fmt: on + + +class DETAIL(BuiltinFilter): + name = "Detail" + # fmt: off + filterargs = (3, 3), 6, 0, ( + 0, -1, 0, + -1, 10, -1, + 0, -1, 0, + ) + # fmt: on + + +class EDGE_ENHANCE(BuiltinFilter): + name = "Edge-enhance" + # fmt: off + filterargs = (3, 3), 2, 0, ( + -1, -1, -1, + -1, 10, -1, + -1, -1, -1, + ) + # fmt: on + + +class EDGE_ENHANCE_MORE(BuiltinFilter): + name = "Edge-enhance More" + # fmt: off + filterargs = (3, 3), 1, 0, ( + -1, -1, -1, + -1, 9, -1, + -1, -1, -1, + ) + # fmt: on + + +class EMBOSS(BuiltinFilter): + name = "Emboss" + # fmt: off + filterargs = (3, 3), 1, 128, ( + -1, 0, 0, + 0, 1, 0, + 0, 0, 0, + ) + # fmt: on + + +class FIND_EDGES(BuiltinFilter): + name = "Find Edges" + # fmt: off + filterargs = (3, 3), 1, 0, ( + -1, -1, -1, + -1, 8, -1, + -1, -1, -1, + ) + # fmt: on + + +class SHARPEN(BuiltinFilter): + name = "Sharpen" + # fmt: off + filterargs = (3, 3), 16, 0, ( + -2, -2, -2, + -2, 32, -2, + -2, -2, -2, + ) + # fmt: on + + +class SMOOTH(BuiltinFilter): + name = "Smooth" + # fmt: off + filterargs = (3, 3), 13, 0, ( + 1, 1, 1, + 1, 5, 1, + 1, 1, 1, + ) + # fmt: on + + +class SMOOTH_MORE(BuiltinFilter): + name = "Smooth More" + # fmt: off + filterargs = (5, 5), 100, 0, ( + 1, 1, 1, 1, 1, + 1, 5, 5, 5, 1, + 1, 5, 44, 5, 1, + 1, 5, 5, 5, 1, + 1, 1, 1, 1, 1, + ) + # fmt: on + + +class Color3DLUT(MultibandFilter): + """Three-dimensional color lookup table. + + Transforms 3-channel pixels using the values of the channels as coordinates + in the 3D lookup table and interpolating the nearest elements. + + This method allows you to apply almost any color transformation + in constant time by using pre-calculated decimated tables. + + .. versionadded:: 5.2.0 + + :param size: Size of the table. One int or tuple of (int, int, int). + Minimal size in any dimension is 2, maximum is 65. + :param table: Flat lookup table. A list of ``channels * size**3`` + float elements or a list of ``size**3`` channels-sized + tuples with floats. Channels are changed first, + then first dimension, then second, then third. + Value 0.0 corresponds lowest value of output, 1.0 highest. + :param channels: Number of channels in the table. Could be 3 or 4. + Default is 3. + :param target_mode: A mode for the result image. Should have not less + than ``channels`` channels. Default is ``None``, + which means that mode wouldn't be changed. + """ + + name = "Color 3D LUT" + + def __init__( + self, + size: int | tuple[int, int, int], + table: Sequence[float] | Sequence[Sequence[int]] | NumpyArray, + channels: int = 3, + target_mode: str | None = None, + **kwargs: bool, + ) -> None: + if channels not in (3, 4): + msg = "Only 3 or 4 output channels are supported" + raise ValueError(msg) + self.size = size = self._check_size(size) + self.channels = channels + self.mode = target_mode + + # Hidden flag `_copy_table=False` could be used to avoid extra copying + # of the table if the table is specially made for the constructor. + copy_table = kwargs.get("_copy_table", True) + items = size[0] * size[1] * size[2] + wrong_size = False + + numpy: ModuleType | None = None + if hasattr(table, "shape"): + try: + import numpy + except ImportError: + pass + + if numpy and isinstance(table, numpy.ndarray): + numpy_table: NumpyArray = table + if copy_table: + numpy_table = numpy_table.copy() + + if numpy_table.shape in [ + (items * channels,), + (items, channels), + (size[2], size[1], size[0], channels), + ]: + table = numpy_table.reshape(items * channels) + else: + wrong_size = True + + else: + if copy_table: + table = list(table) + + # Convert to a flat list + if table and isinstance(table[0], (list, tuple)): + raw_table = cast(Sequence[Sequence[int]], table) + flat_table: list[int] = [] + for pixel in raw_table: + if len(pixel) != channels: + msg = ( + "The elements of the table should " + f"have a length of {channels}." + ) + raise ValueError(msg) + flat_table.extend(pixel) + table = flat_table + + if wrong_size or len(table) != items * channels: + msg = ( + "The table should have either channels * size**3 float items " + "or size**3 items of channels-sized tuples with floats. " + f"Table should be: {channels}x{size[0]}x{size[1]}x{size[2]}. " + f"Actual length: {len(table)}" + ) + raise ValueError(msg) + self.table = table + + @staticmethod + def _check_size(size: Any) -> tuple[int, int, int]: + try: + _, _, _ = size + except ValueError as e: + msg = "Size should be either an integer or a tuple of three integers." + raise ValueError(msg) from e + except TypeError: + size = (size, size, size) + size = tuple(int(x) for x in size) + for size_1d in size: + if not 2 <= size_1d <= 65: + msg = "Size should be in [2, 65] range." + raise ValueError(msg) + return size + + @classmethod + def generate( + cls, + size: int | tuple[int, int, int], + callback: Callable[[float, float, float], tuple[float, ...]], + channels: int = 3, + target_mode: str | None = None, + ) -> Color3DLUT: + """Generates new LUT using provided callback. + + :param size: Size of the table. Passed to the constructor. + :param callback: Function with three parameters which correspond + three color channels. Will be called ``size**3`` + times with values from 0.0 to 1.0 and should return + a tuple with ``channels`` elements. + :param channels: The number of channels which should return callback. + :param target_mode: Passed to the constructor of the resulting + lookup table. + """ + size_1d, size_2d, size_3d = cls._check_size(size) + if channels not in (3, 4): + msg = "Only 3 or 4 output channels are supported" + raise ValueError(msg) + + table: list[float] = [0] * (size_1d * size_2d * size_3d * channels) + idx_out = 0 + for b in range(size_3d): + for g in range(size_2d): + for r in range(size_1d): + table[idx_out : idx_out + channels] = callback( + r / (size_1d - 1), g / (size_2d - 1), b / (size_3d - 1) + ) + idx_out += channels + + return cls( + (size_1d, size_2d, size_3d), + table, + channels=channels, + target_mode=target_mode, + _copy_table=False, + ) + + def transform( + self, + callback: Callable[..., tuple[float, ...]], + with_normals: bool = False, + channels: int | None = None, + target_mode: str | None = None, + ) -> Color3DLUT: + """Transforms the table values using provided callback and returns + a new LUT with altered values. + + :param callback: A function which takes old lookup table values + and returns a new set of values. The number + of arguments which function should take is + ``self.channels`` or ``3 + self.channels`` + if ``with_normals`` flag is set. + Should return a tuple of ``self.channels`` or + ``channels`` elements if it is set. + :param with_normals: If true, ``callback`` will be called with + coordinates in the color cube as the first + three arguments. Otherwise, ``callback`` + will be called only with actual color values. + :param channels: The number of channels in the resulting lookup table. + :param target_mode: Passed to the constructor of the resulting + lookup table. + """ + if channels not in (None, 3, 4): + msg = "Only 3 or 4 output channels are supported" + raise ValueError(msg) + ch_in = self.channels + ch_out = channels or ch_in + size_1d, size_2d, size_3d = self.size + + table = [0] * (size_1d * size_2d * size_3d * ch_out) + idx_in = 0 + idx_out = 0 + for b in range(size_3d): + for g in range(size_2d): + for r in range(size_1d): + values = self.table[idx_in : idx_in + ch_in] + if with_normals: + values = callback( + r / (size_1d - 1), + g / (size_2d - 1), + b / (size_3d - 1), + *values, + ) + else: + values = callback(*values) + table[idx_out : idx_out + ch_out] = values + idx_in += ch_in + idx_out += ch_out + + return type(self)( + self.size, + table, + channels=ch_out, + target_mode=target_mode or self.mode, + _copy_table=False, + ) + + def __repr__(self) -> str: + r = [ + f"{self.__class__.__name__} from {self.table.__class__.__name__}", + "size={:d}x{:d}x{:d}".format(*self.size), + f"channels={self.channels:d}", + ] + if self.mode: + r.append(f"target_mode={self.mode}") + return "<{}>".format(" ".join(r)) + + def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: + from . import Image + + return image.color_lut_3d( + self.mode or image.mode, + Image.Resampling.BILINEAR, + self.channels, + self.size[0], + self.size[1], + self.size[2], + self.table, + ) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageFont.py b/.venv/lib/python3.12/site-packages/PIL/ImageFont.py new file mode 100644 index 0000000..d260eef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageFont.py @@ -0,0 +1,1290 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PIL raster font management +# +# History: +# 1996-08-07 fl created (experimental) +# 1997-08-25 fl minor adjustments to handle fonts from pilfont 0.3 +# 1999-02-06 fl rewrote most font management stuff in C +# 1999-03-17 fl take pth files into account in load_path (from Richard Jones) +# 2001-02-17 fl added freetype support +# 2001-05-09 fl added TransposedFont wrapper class +# 2002-03-04 fl make sure we have a "L" or "1" font +# 2002-12-04 fl skip non-directory entries in the system path +# 2003-04-29 fl add embedded default font +# 2003-09-27 fl added support for truetype charmap encodings +# +# Todo: +# Adapt to PILFONT2 format (16-bit fonts, compressed, single file) +# +# Copyright (c) 1997-2003 by Secret Labs AB +# Copyright (c) 1996-2003 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# + +from __future__ import annotations + +import base64 +import os +import sys +import warnings +from enum import IntEnum +from io import BytesIO +from types import ModuleType +from typing import IO, TYPE_CHECKING, Any, BinaryIO + +from . import Image +from ._typing import StrOrBytesPath +from ._util import DeferredError, is_path + +if TYPE_CHECKING: + from . import ImageFile + from ._imaging import ImagingFont + from ._imagingft import Font + + +class Layout(IntEnum): + BASIC = 0 + RAQM = 1 + + +MAX_STRING_LENGTH = 1_000_000 + + +core: ModuleType | DeferredError +try: + from . import _imagingft as core +except ImportError as ex: + core = DeferredError.new(ex) + + +def _string_length_check(text: str | bytes | bytearray) -> None: + if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH: + msg = "too many characters in string" + raise ValueError(msg) + + +# FIXME: add support for pilfont2 format (see FontFile.py) + +# -------------------------------------------------------------------- +# Font metrics format: +# "PILfont" LF +# fontdescriptor LF +# (optional) key=value... LF +# "DATA" LF +# binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox) +# +# To place a character, cut out srcbox and paste at dstbox, +# relative to the character position. Then move the character +# position according to dx, dy. +# -------------------------------------------------------------------- + + +class ImageFont: + """PIL font wrapper""" + + font: ImagingFont + + def _load_pilfont(self, filename: str) -> None: + with open(filename, "rb") as fp: + image: ImageFile.ImageFile | None = None + for ext in (".png", ".gif", ".pbm"): + if image: + image.close() + try: + fullname = os.path.splitext(filename)[0] + ext + image = Image.open(fullname) + except Exception: + pass + else: + if image and image.mode in ("1", "L"): + break + else: + if image: + image.close() + msg = "cannot find glyph data file" + raise OSError(msg) + + self.file = fullname + + self._load_pilfont_data(fp, image) + image.close() + + def _load_pilfont_data(self, file: IO[bytes], image: Image.Image) -> None: + # read PILfont header + if file.readline() != b"PILfont\n": + msg = "Not a PILfont file" + raise SyntaxError(msg) + file.readline().split(b";") + self.info = [] # FIXME: should be a dictionary + while True: + s = file.readline() + if not s or s == b"DATA\n": + break + self.info.append(s) + + # read PILfont metrics + data = file.read(256 * 20) + + # check image + if image.mode not in ("1", "L"): + msg = "invalid font image mode" + raise TypeError(msg) + + image.load() + + self.font = Image.core.font(image.im, data) + + def getmask(self, text, mode="", *args, **kwargs): + """ + Create a bitmap for the text. + + If the font uses antialiasing, the bitmap should have mode ``L`` and use a + maximum value of 255. Otherwise, it should have mode ``1``. + + :param text: Text to render. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + .. versionadded:: 1.1.5 + + :return: An internal PIL storage memory instance as defined by the + :py:mod:`PIL.Image.core` interface module. + """ + _string_length_check(text) + Image._decompression_bomb_check(self.font.getsize(text)) + return self.font.getmask(text, mode) + + def getbbox( + self, text: str | bytes | bytearray, *args: Any, **kwargs: Any + ) -> tuple[int, int, int, int]: + """ + Returns bounding box (in pixels) of given text. + + .. versionadded:: 9.2.0 + + :param text: Text to render. + + :return: ``(left, top, right, bottom)`` bounding box + """ + _string_length_check(text) + width, height = self.font.getsize(text) + return 0, 0, width, height + + def getlength( + self, text: str | bytes | bytearray, *args: Any, **kwargs: Any + ) -> int: + """ + Returns length (in pixels) of given text. + This is the amount by which following text should be offset. + + .. versionadded:: 9.2.0 + """ + _string_length_check(text) + width, height = self.font.getsize(text) + return width + + +## +# Wrapper for FreeType fonts. Application code should use the +# truetype factory function to create font objects. + + +class FreeTypeFont: + """FreeType font wrapper (requires _imagingft service)""" + + font: Font + font_bytes: bytes + + def __init__( + self, + font: StrOrBytesPath | BinaryIO | None = None, + size: float = 10, + index: int = 0, + encoding: str = "", + layout_engine: Layout | None = None, + ) -> None: + # FIXME: use service provider instead + + if isinstance(core, DeferredError): + raise core.ex + + if size <= 0: + msg = "font size must be greater than 0" + raise ValueError(msg) + + self.path = font + self.size = size + self.index = index + self.encoding = encoding + + if layout_engine not in (Layout.BASIC, Layout.RAQM): + layout_engine = Layout.BASIC + if core.HAVE_RAQM: + layout_engine = Layout.RAQM + elif layout_engine == Layout.RAQM and not core.HAVE_RAQM: + warnings.warn( + "Raqm layout was requested, but Raqm is not available. " + "Falling back to basic layout." + ) + layout_engine = Layout.BASIC + + self.layout_engine = layout_engine + + def load_from_bytes(f): + self.font_bytes = f.read() + self.font = core.getfont( + "", size, index, encoding, self.font_bytes, layout_engine + ) + + if is_path(font): + font = os.path.realpath(os.fspath(font)) + if sys.platform == "win32": + font_bytes_path = font if isinstance(font, bytes) else font.encode() + try: + font_bytes_path.decode("ascii") + except UnicodeDecodeError: + # FreeType cannot load fonts with non-ASCII characters on Windows + # So load it into memory first + with open(font, "rb") as f: + load_from_bytes(f) + return + self.font = core.getfont( + font, size, index, encoding, layout_engine=layout_engine + ) + else: + load_from_bytes(font) + + def __getstate__(self): + return [self.path, self.size, self.index, self.encoding, self.layout_engine] + + def __setstate__(self, state): + path, size, index, encoding, layout_engine = state + self.__init__(path, size, index, encoding, layout_engine) + + def getname(self) -> tuple[str | None, str | None]: + """ + :return: A tuple of the font family (e.g. Helvetica) and the font style + (e.g. Bold) + """ + return self.font.family, self.font.style + + def getmetrics(self) -> tuple[int, int]: + """ + :return: A tuple of the font ascent (the distance from the baseline to + the highest outline point) and descent (the distance from the + baseline to the lowest outline point, a negative value) + """ + return self.font.ascent, self.font.descent + + def getlength( + self, text: str | bytes, mode="", direction=None, features=None, language=None + ) -> float: + """ + Returns length (in pixels with 1/64 precision) of given text when rendered + in font with provided direction, features, and language. + + This is the amount by which following text should be offset. + Text bounding box may extend past the length in some fonts, + e.g. when using italics or accents. + + The result is returned as a float; it is a whole number if using basic layout. + + Note that the sum of two lengths may not equal the length of a concatenated + string due to kerning. If you need to adjust for kerning, include the following + character and subtract its length. + + For example, instead of :: + + hello = font.getlength("Hello") + world = font.getlength("World") + hello_world = hello + world # not adjusted for kerning + assert hello_world == font.getlength("HelloWorld") # may fail + + use :: + + hello = font.getlength("HelloW") - font.getlength("W") # adjusted for kerning + world = font.getlength("World") + hello_world = hello + world # adjusted for kerning + assert hello_world == font.getlength("HelloWorld") # True + + or disable kerning with (requires libraqm) :: + + hello = draw.textlength("Hello", font, features=["-kern"]) + world = draw.textlength("World", font, features=["-kern"]) + hello_world = hello + world # kerning is disabled, no need to adjust + assert hello_world == draw.textlength("HelloWorld", font, features=["-kern"]) + + .. versionadded:: 8.0.0 + + :param text: Text to measure. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + :param direction: Direction of the text. It can be 'rtl' (right to + left), 'ltr' (left to right) or 'ttb' (top to bottom). + Requires libraqm. + + :param features: A list of OpenType font features to be used during text + layout. This is usually used to turn on optional + font features that are not enabled by default, + for example 'dlig' or 'ss01', but can be also + used to turn off default font features for + example '-liga' to disable ligatures or '-kern' + to disable kerning. To get all supported + features, see + https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist + Requires libraqm. + + :param language: Language of the text. Different languages may use + different glyph shapes or ligatures. This parameter tells + the font which language the text is in, and to apply the + correct substitutions as appropriate, if available. + It should be a `BCP 47 language code + `_ + Requires libraqm. + + :return: Either width for horizontal text, or height for vertical text. + """ + _string_length_check(text) + return self.font.getlength(text, mode, direction, features, language) / 64 + + def getbbox( + self, + text: str | bytes, + mode: str = "", + direction: str | None = None, + features: list[str] | None = None, + language: str | None = None, + stroke_width: float = 0, + anchor: str | None = None, + ) -> tuple[float, float, float, float]: + """ + Returns bounding box (in pixels) of given text relative to given anchor + when rendered in font with provided direction, features, and language. + + Use :py:meth:`getlength()` to get the offset of following text with + 1/64 pixel precision. The bounding box includes extra margins for + some fonts, e.g. italics or accents. + + .. versionadded:: 8.0.0 + + :param text: Text to render. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + :param direction: Direction of the text. It can be 'rtl' (right to + left), 'ltr' (left to right) or 'ttb' (top to bottom). + Requires libraqm. + + :param features: A list of OpenType font features to be used during text + layout. This is usually used to turn on optional + font features that are not enabled by default, + for example 'dlig' or 'ss01', but can be also + used to turn off default font features for + example '-liga' to disable ligatures or '-kern' + to disable kerning. To get all supported + features, see + https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist + Requires libraqm. + + :param language: Language of the text. Different languages may use + different glyph shapes or ligatures. This parameter tells + the font which language the text is in, and to apply the + correct substitutions as appropriate, if available. + It should be a `BCP 47 language code + `_ + Requires libraqm. + + :param stroke_width: The width of the text stroke. + + :param anchor: The text anchor alignment. Determines the relative location of + the anchor to the text. The default alignment is top left, + specifically ``la`` for horizontal text and ``lt`` for + vertical text. See :ref:`text-anchors` for details. + + :return: ``(left, top, right, bottom)`` bounding box + """ + _string_length_check(text) + size, offset = self.font.getsize( + text, mode, direction, features, language, anchor + ) + left, top = offset[0] - stroke_width, offset[1] - stroke_width + width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width + return left, top, left + width, top + height + + def getmask( + self, + text, + mode="", + direction=None, + features=None, + language=None, + stroke_width=0, + anchor=None, + ink=0, + start=None, + ): + """ + Create a bitmap for the text. + + If the font uses antialiasing, the bitmap should have mode ``L`` and use a + maximum value of 255. If the font has embedded color data, the bitmap + should have mode ``RGBA``. Otherwise, it should have mode ``1``. + + :param text: Text to render. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + .. versionadded:: 1.1.5 + + :param direction: Direction of the text. It can be 'rtl' (right to + left), 'ltr' (left to right) or 'ttb' (top to bottom). + Requires libraqm. + + .. versionadded:: 4.2.0 + + :param features: A list of OpenType font features to be used during text + layout. This is usually used to turn on optional + font features that are not enabled by default, + for example 'dlig' or 'ss01', but can be also + used to turn off default font features for + example '-liga' to disable ligatures or '-kern' + to disable kerning. To get all supported + features, see + https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist + Requires libraqm. + + .. versionadded:: 4.2.0 + + :param language: Language of the text. Different languages may use + different glyph shapes or ligatures. This parameter tells + the font which language the text is in, and to apply the + correct substitutions as appropriate, if available. + It should be a `BCP 47 language code + `_ + Requires libraqm. + + .. versionadded:: 6.0.0 + + :param stroke_width: The width of the text stroke. + + .. versionadded:: 6.2.0 + + :param anchor: The text anchor alignment. Determines the relative location of + the anchor to the text. The default alignment is top left, + specifically ``la`` for horizontal text and ``lt`` for + vertical text. See :ref:`text-anchors` for details. + + .. versionadded:: 8.0.0 + + :param ink: Foreground ink for rendering in RGBA mode. + + .. versionadded:: 8.0.0 + + :param start: Tuple of horizontal and vertical offset, as text may render + differently when starting at fractional coordinates. + + .. versionadded:: 9.4.0 + + :return: An internal PIL storage memory instance as defined by the + :py:mod:`PIL.Image.core` interface module. + """ + return self.getmask2( + text, + mode, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + anchor=anchor, + ink=ink, + start=start, + )[0] + + def getmask2( + self, + text: str | bytes, + mode="", + direction=None, + features=None, + language=None, + stroke_width=0, + anchor=None, + ink=0, + start=None, + *args, + **kwargs, + ): + """ + Create a bitmap for the text. + + If the font uses antialiasing, the bitmap should have mode ``L`` and use a + maximum value of 255. If the font has embedded color data, the bitmap + should have mode ``RGBA``. Otherwise, it should have mode ``1``. + + :param text: Text to render. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + .. versionadded:: 1.1.5 + + :param direction: Direction of the text. It can be 'rtl' (right to + left), 'ltr' (left to right) or 'ttb' (top to bottom). + Requires libraqm. + + .. versionadded:: 4.2.0 + + :param features: A list of OpenType font features to be used during text + layout. This is usually used to turn on optional + font features that are not enabled by default, + for example 'dlig' or 'ss01', but can be also + used to turn off default font features for + example '-liga' to disable ligatures or '-kern' + to disable kerning. To get all supported + features, see + https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist + Requires libraqm. + + .. versionadded:: 4.2.0 + + :param language: Language of the text. Different languages may use + different glyph shapes or ligatures. This parameter tells + the font which language the text is in, and to apply the + correct substitutions as appropriate, if available. + It should be a `BCP 47 language code + `_ + Requires libraqm. + + .. versionadded:: 6.0.0 + + :param stroke_width: The width of the text stroke. + + .. versionadded:: 6.2.0 + + :param anchor: The text anchor alignment. Determines the relative location of + the anchor to the text. The default alignment is top left, + specifically ``la`` for horizontal text and ``lt`` for + vertical text. See :ref:`text-anchors` for details. + + .. versionadded:: 8.0.0 + + :param ink: Foreground ink for rendering in RGBA mode. + + .. versionadded:: 8.0.0 + + :param start: Tuple of horizontal and vertical offset, as text may render + differently when starting at fractional coordinates. + + .. versionadded:: 9.4.0 + + :return: A tuple of an internal PIL storage memory instance as defined by the + :py:mod:`PIL.Image.core` interface module, and the text offset, the + gap between the starting coordinate and the first marking + """ + _string_length_check(text) + if start is None: + start = (0, 0) + + def fill(width, height): + size = (width, height) + Image._decompression_bomb_check(size) + return Image.core.fill("RGBA" if mode == "RGBA" else "L", size) + + return self.font.render( + text, + fill, + mode, + direction, + features, + language, + stroke_width, + anchor, + ink, + start[0], + start[1], + ) + + def font_variant( + self, font=None, size=None, index=None, encoding=None, layout_engine=None + ): + """ + Create a copy of this FreeTypeFont object, + using any specified arguments to override the settings. + + Parameters are identical to the parameters used to initialize this + object. + + :return: A FreeTypeFont object. + """ + if font is None: + try: + font = BytesIO(self.font_bytes) + except AttributeError: + font = self.path + return FreeTypeFont( + font=font, + size=self.size if size is None else size, + index=self.index if index is None else index, + encoding=self.encoding if encoding is None else encoding, + layout_engine=layout_engine or self.layout_engine, + ) + + def get_variation_names(self) -> list[bytes]: + """ + :returns: A list of the named styles in a variation font. + :exception OSError: If the font is not a variation font. + """ + try: + names = self.font.getvarnames() + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e + return [name.replace(b"\x00", b"") for name in names] + + def set_variation_by_name(self, name): + """ + :param name: The name of the style. + :exception OSError: If the font is not a variation font. + """ + names = self.get_variation_names() + if not isinstance(name, bytes): + name = name.encode() + index = names.index(name) + 1 + + if index == getattr(self, "_last_variation_index", None): + # When the same name is set twice in a row, + # there is an 'unknown freetype error' + # https://savannah.nongnu.org/bugs/?56186 + return + self._last_variation_index = index + + self.font.setvarname(index) + + def get_variation_axes(self): + """ + :returns: A list of the axes in a variation font. + :exception OSError: If the font is not a variation font. + """ + try: + axes = self.font.getvaraxes() + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e + for axis in axes: + if axis["name"]: + axis["name"] = axis["name"].replace(b"\x00", b"") + return axes + + def set_variation_by_axes(self, axes: list[float]) -> None: + """ + :param axes: A list of values for each axis. + :exception OSError: If the font is not a variation font. + """ + try: + self.font.setvaraxes(axes) + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e + + +class TransposedFont: + """Wrapper for writing rotated or mirrored text""" + + def __init__(self, font, orientation=None): + """ + Wrapper that creates a transposed font from any existing font + object. + + :param font: A font object. + :param orientation: An optional orientation. If given, this should + be one of Image.Transpose.FLIP_LEFT_RIGHT, Image.Transpose.FLIP_TOP_BOTTOM, + Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_180, or + Image.Transpose.ROTATE_270. + """ + self.font = font + self.orientation = orientation # any 'transpose' argument, or None + + def getmask(self, text, mode="", *args, **kwargs): + im = self.font.getmask(text, mode, *args, **kwargs) + if self.orientation is not None: + return im.transpose(self.orientation) + return im + + def getbbox(self, text, *args, **kwargs): + # TransposedFont doesn't support getmask2, move top-left point to (0, 0) + # this has no effect on ImageFont and simulates anchor="lt" for FreeTypeFont + left, top, right, bottom = self.font.getbbox(text, *args, **kwargs) + width = right - left + height = bottom - top + if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): + return 0, 0, height, width + return 0, 0, width, height + + def getlength(self, text: str | bytes, *args, **kwargs) -> float: + if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): + msg = "text length is undefined for text rotated by 90 or 270 degrees" + raise ValueError(msg) + return self.font.getlength(text, *args, **kwargs) + + +def load(filename: str) -> ImageFont: + """ + Load a font file. This function loads a font object from the given + bitmap font file, and returns the corresponding font object. + + :param filename: Name of font file. + :return: A font object. + :exception OSError: If the file could not be read. + """ + f = ImageFont() + f._load_pilfont(filename) + return f + + +def truetype( + font: StrOrBytesPath | BinaryIO | None = None, + size: float = 10, + index: int = 0, + encoding: str = "", + layout_engine: Layout | None = None, +) -> FreeTypeFont: + """ + Load a TrueType or OpenType font from a file or file-like object, + and create a font object. + This function loads a font object from the given file or file-like + object, and creates a font object for a font of the given size. + + Pillow uses FreeType to open font files. On Windows, be aware that FreeType + will keep the file open as long as the FreeTypeFont object exists. Windows + limits the number of files that can be open in C at once to 512, so if many + fonts are opened simultaneously and that limit is approached, an + ``OSError`` may be thrown, reporting that FreeType "cannot open resource". + A workaround would be to copy the file(s) into memory, and open that instead. + + This function requires the _imagingft service. + + :param font: A filename or file-like object containing a TrueType font. + If the file is not found in this filename, the loader may also + search in other directories, such as: + + * The :file:`fonts/` directory on Windows, + * :file:`/Library/Fonts/`, :file:`/System/Library/Fonts/` + and :file:`~/Library/Fonts/` on macOS. + * :file:`~/.local/share/fonts`, :file:`/usr/local/share/fonts`, + and :file:`/usr/share/fonts` on Linux; or those specified by + the ``XDG_DATA_HOME`` and ``XDG_DATA_DIRS`` environment variables + for user-installed and system-wide fonts, respectively. + + :param size: The requested size, in pixels. + :param index: Which font face to load (default is first available face). + :param encoding: Which font encoding to use (default is Unicode). Possible + encodings include (see the FreeType documentation for more + information): + + * "unic" (Unicode) + * "symb" (Microsoft Symbol) + * "ADOB" (Adobe Standard) + * "ADBE" (Adobe Expert) + * "ADBC" (Adobe Custom) + * "armn" (Apple Roman) + * "sjis" (Shift JIS) + * "gb " (PRC) + * "big5" + * "wans" (Extended Wansung) + * "joha" (Johab) + * "lat1" (Latin-1) + + This specifies the character set to use. It does not alter the + encoding of any text provided in subsequent operations. + :param layout_engine: Which layout engine to use, if available: + :attr:`.ImageFont.Layout.BASIC` or :attr:`.ImageFont.Layout.RAQM`. + If it is available, Raqm layout will be used by default. + Otherwise, basic layout will be used. + + Raqm layout is recommended for all non-English text. If Raqm layout + is not required, basic layout will have better performance. + + You can check support for Raqm layout using + :py:func:`PIL.features.check_feature` with ``feature="raqm"``. + + .. versionadded:: 4.2.0 + :return: A font object. + :exception OSError: If the file could not be read. + :exception ValueError: If the font size is not greater than zero. + """ + + def freetype(font: StrOrBytesPath | BinaryIO | None) -> FreeTypeFont: + return FreeTypeFont(font, size, index, encoding, layout_engine) + + try: + return freetype(font) + except OSError: + if not is_path(font): + raise + ttf_filename = os.path.basename(font) + + dirs = [] + if sys.platform == "win32": + # check the windows font repository + # NOTE: must use uppercase WINDIR, to work around bugs in + # 1.5.2's os.environ.get() + windir = os.environ.get("WINDIR") + if windir: + dirs.append(os.path.join(windir, "fonts")) + elif sys.platform in ("linux", "linux2"): + data_home = os.environ.get("XDG_DATA_HOME") + if not data_home: + # The freedesktop spec defines the following default directory for + # when XDG_DATA_HOME is unset or empty. This user-level directory + # takes precedence over system-level directories. + data_home = os.path.expanduser("~/.local/share") + xdg_dirs = [data_home] + + data_dirs = os.environ.get("XDG_DATA_DIRS") + if not data_dirs: + # Similarly, defaults are defined for the system-level directories + data_dirs = "/usr/local/share:/usr/share" + xdg_dirs += data_dirs.split(":") + + dirs += [os.path.join(xdg_dir, "fonts") for xdg_dir in xdg_dirs] + elif sys.platform == "darwin": + dirs += [ + "/Library/Fonts", + "/System/Library/Fonts", + os.path.expanduser("~/Library/Fonts"), + ] + + ext = os.path.splitext(ttf_filename)[1] + first_font_with_a_different_extension = None + for directory in dirs: + for walkroot, walkdir, walkfilenames in os.walk(directory): + for walkfilename in walkfilenames: + if ext and walkfilename == ttf_filename: + return freetype(os.path.join(walkroot, walkfilename)) + elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename: + fontpath = os.path.join(walkroot, walkfilename) + if os.path.splitext(fontpath)[1] == ".ttf": + return freetype(fontpath) + if not ext and first_font_with_a_different_extension is None: + first_font_with_a_different_extension = fontpath + if first_font_with_a_different_extension: + return freetype(first_font_with_a_different_extension) + raise + + +def load_path(filename: str | bytes) -> ImageFont: + """ + Load font file. Same as :py:func:`~PIL.ImageFont.load`, but searches for a + bitmap font along the Python path. + + :param filename: Name of font file. + :return: A font object. + :exception OSError: If the file could not be read. + """ + if not isinstance(filename, str): + filename = filename.decode("utf-8") + for directory in sys.path: + try: + return load(os.path.join(directory, filename)) + except OSError: + pass + msg = "cannot find font file" + raise OSError(msg) + + +def load_default_imagefont() -> ImageFont: + f = ImageFont() + f._load_pilfont_data( + # courB08 + BytesIO( + base64.b64decode( + b""" +UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAA//8AAQAAAAAAAAABAAEA +BgAAAAH/+gADAAAAAQAAAAMABgAGAAAAAf/6AAT//QADAAAABgADAAYAAAAA//kABQABAAYAAAAL +AAgABgAAAAD/+AAFAAEACwAAABAACQAGAAAAAP/5AAUAAAAQAAAAFQAHAAYAAP////oABQAAABUA +AAAbAAYABgAAAAH/+QAE//wAGwAAAB4AAwAGAAAAAf/5AAQAAQAeAAAAIQAIAAYAAAAB//kABAAB +ACEAAAAkAAgABgAAAAD/+QAE//0AJAAAACgABAAGAAAAAP/6AAX//wAoAAAALQAFAAYAAAAB//8A +BAACAC0AAAAwAAMABgAAAAD//AAF//0AMAAAADUAAQAGAAAAAf//AAMAAAA1AAAANwABAAYAAAAB +//kABQABADcAAAA7AAgABgAAAAD/+QAFAAAAOwAAAEAABwAGAAAAAP/5AAYAAABAAAAARgAHAAYA +AAAA//kABQAAAEYAAABLAAcABgAAAAD/+QAFAAAASwAAAFAABwAGAAAAAP/5AAYAAABQAAAAVgAH +AAYAAAAA//kABQAAAFYAAABbAAcABgAAAAD/+QAFAAAAWwAAAGAABwAGAAAAAP/5AAUAAABgAAAA +ZQAHAAYAAAAA//kABQAAAGUAAABqAAcABgAAAAD/+QAFAAAAagAAAG8ABwAGAAAAAf/8AAMAAABv +AAAAcQAEAAYAAAAA//wAAwACAHEAAAB0AAYABgAAAAD/+gAE//8AdAAAAHgABQAGAAAAAP/7AAT/ +/gB4AAAAfAADAAYAAAAB//oABf//AHwAAACAAAUABgAAAAD/+gAFAAAAgAAAAIUABgAGAAAAAP/5 +AAYAAQCFAAAAiwAIAAYAAP////oABgAAAIsAAACSAAYABgAA////+gAFAAAAkgAAAJgABgAGAAAA +AP/6AAUAAACYAAAAnQAGAAYAAP////oABQAAAJ0AAACjAAYABgAA////+gAFAAAAowAAAKkABgAG +AAD////6AAUAAACpAAAArwAGAAYAAAAA//oABQAAAK8AAAC0AAYABgAA////+gAGAAAAtAAAALsA +BgAGAAAAAP/6AAQAAAC7AAAAvwAGAAYAAP////oABQAAAL8AAADFAAYABgAA////+gAGAAAAxQAA +AMwABgAGAAD////6AAUAAADMAAAA0gAGAAYAAP////oABQAAANIAAADYAAYABgAA////+gAGAAAA +2AAAAN8ABgAGAAAAAP/6AAUAAADfAAAA5AAGAAYAAP////oABQAAAOQAAADqAAYABgAAAAD/+gAF +AAEA6gAAAO8ABwAGAAD////6AAYAAADvAAAA9gAGAAYAAAAA//oABQAAAPYAAAD7AAYABgAA//// ++gAFAAAA+wAAAQEABgAGAAD////6AAYAAAEBAAABCAAGAAYAAP////oABgAAAQgAAAEPAAYABgAA +////+gAGAAABDwAAARYABgAGAAAAAP/6AAYAAAEWAAABHAAGAAYAAP////oABgAAARwAAAEjAAYA +BgAAAAD/+gAFAAABIwAAASgABgAGAAAAAf/5AAQAAQEoAAABKwAIAAYAAAAA//kABAABASsAAAEv +AAgABgAAAAH/+QAEAAEBLwAAATIACAAGAAAAAP/5AAX//AEyAAABNwADAAYAAAAAAAEABgACATcA +AAE9AAEABgAAAAH/+QAE//wBPQAAAUAAAwAGAAAAAP/7AAYAAAFAAAABRgAFAAYAAP////kABQAA +AUYAAAFMAAcABgAAAAD/+wAFAAABTAAAAVEABQAGAAAAAP/5AAYAAAFRAAABVwAHAAYAAAAA//sA +BQAAAVcAAAFcAAUABgAAAAD/+QAFAAABXAAAAWEABwAGAAAAAP/7AAYAAgFhAAABZwAHAAYAAP// +//kABQAAAWcAAAFtAAcABgAAAAD/+QAGAAABbQAAAXMABwAGAAAAAP/5AAQAAgFzAAABdwAJAAYA +AP////kABgAAAXcAAAF+AAcABgAAAAD/+QAGAAABfgAAAYQABwAGAAD////7AAUAAAGEAAABigAF +AAYAAP////sABQAAAYoAAAGQAAUABgAAAAD/+wAFAAABkAAAAZUABQAGAAD////7AAUAAgGVAAAB +mwAHAAYAAAAA//sABgACAZsAAAGhAAcABgAAAAD/+wAGAAABoQAAAacABQAGAAAAAP/7AAYAAAGn +AAABrQAFAAYAAAAA//kABgAAAa0AAAGzAAcABgAA////+wAGAAABswAAAboABQAGAAD////7AAUA +AAG6AAABwAAFAAYAAP////sABgAAAcAAAAHHAAUABgAAAAD/+wAGAAABxwAAAc0ABQAGAAD////7 +AAYAAgHNAAAB1AAHAAYAAAAA//sABQAAAdQAAAHZAAUABgAAAAH/+QAFAAEB2QAAAd0ACAAGAAAA +Av/6AAMAAQHdAAAB3gAHAAYAAAAA//kABAABAd4AAAHiAAgABgAAAAD/+wAF//0B4gAAAecAAgAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAB +//sAAwACAecAAAHpAAcABgAAAAD/+QAFAAEB6QAAAe4ACAAGAAAAAP/5AAYAAAHuAAAB9AAHAAYA +AAAA//oABf//AfQAAAH5AAUABgAAAAD/+QAGAAAB+QAAAf8ABwAGAAAAAv/5AAMAAgH/AAACAAAJ +AAYAAAAA//kABQABAgAAAAIFAAgABgAAAAH/+gAE//sCBQAAAggAAQAGAAAAAP/5AAYAAAIIAAAC +DgAHAAYAAAAB//kABf/+Ag4AAAISAAUABgAA////+wAGAAACEgAAAhkABQAGAAAAAP/7AAX//gIZ +AAACHgADAAYAAAAA//wABf/9Ah4AAAIjAAEABgAAAAD/+QAHAAACIwAAAioABwAGAAAAAP/6AAT/ ++wIqAAACLgABAAYAAAAA//kABP/8Ai4AAAIyAAMABgAAAAD/+gAFAAACMgAAAjcABgAGAAAAAf/5 +AAT//QI3AAACOgAEAAYAAAAB//kABP/9AjoAAAI9AAQABgAAAAL/+QAE//sCPQAAAj8AAgAGAAD/ +///7AAYAAgI/AAACRgAHAAYAAAAA//kABgABAkYAAAJMAAgABgAAAAH//AAD//0CTAAAAk4AAQAG +AAAAAf//AAQAAgJOAAACUQADAAYAAAAB//kABP/9AlEAAAJUAAQABgAAAAH/+QAF//4CVAAAAlgA +BQAGAAD////7AAYAAAJYAAACXwAFAAYAAP////kABgAAAl8AAAJmAAcABgAA////+QAGAAACZgAA +Am0ABwAGAAD////5AAYAAAJtAAACdAAHAAYAAAAA//sABQACAnQAAAJ5AAcABgAA////9wAGAAAC +eQAAAoAACQAGAAD////3AAYAAAKAAAAChwAJAAYAAP////cABgAAAocAAAKOAAkABgAA////9wAG +AAACjgAAApUACQAGAAD////4AAYAAAKVAAACnAAIAAYAAP////cABgAAApwAAAKjAAkABgAA//// ++gAGAAACowAAAqoABgAGAAAAAP/6AAUAAgKqAAACrwAIAAYAAP////cABQAAAq8AAAK1AAkABgAA +////9wAFAAACtQAAArsACQAGAAD////3AAUAAAK7AAACwQAJAAYAAP////gABQAAAsEAAALHAAgA +BgAAAAD/9wAEAAACxwAAAssACQAGAAAAAP/3AAQAAALLAAACzwAJAAYAAAAA//cABAAAAs8AAALT +AAkABgAAAAD/+AAEAAAC0wAAAtcACAAGAAD////6AAUAAALXAAAC3QAGAAYAAP////cABgAAAt0A +AALkAAkABgAAAAD/9wAFAAAC5AAAAukACQAGAAAAAP/3AAUAAALpAAAC7gAJAAYAAAAA//cABQAA +Au4AAALzAAkABgAAAAD/9wAFAAAC8wAAAvgACQAGAAAAAP/4AAUAAAL4AAAC/QAIAAYAAAAA//oA +Bf//Av0AAAMCAAUABgAA////+gAGAAADAgAAAwkABgAGAAD////3AAYAAAMJAAADEAAJAAYAAP// +//cABgAAAxAAAAMXAAkABgAA////9wAGAAADFwAAAx4ACQAGAAD////4AAYAAAAAAAoABwASAAYA +AP////cABgAAAAcACgAOABMABgAA////+gAFAAAADgAKABQAEAAGAAD////6AAYAAAAUAAoAGwAQ +AAYAAAAA//gABgAAABsACgAhABIABgAAAAD/+AAGAAAAIQAKACcAEgAGAAAAAP/4AAYAAAAnAAoA +LQASAAYAAAAA//gABgAAAC0ACgAzABIABgAAAAD/+QAGAAAAMwAKADkAEQAGAAAAAP/3AAYAAAA5 +AAoAPwATAAYAAP////sABQAAAD8ACgBFAA8ABgAAAAD/+wAFAAIARQAKAEoAEQAGAAAAAP/4AAUA +AABKAAoATwASAAYAAAAA//gABQAAAE8ACgBUABIABgAAAAD/+AAFAAAAVAAKAFkAEgAGAAAAAP/5 +AAUAAABZAAoAXgARAAYAAAAA//gABgAAAF4ACgBkABIABgAAAAD/+AAGAAAAZAAKAGoAEgAGAAAA +AP/4AAYAAABqAAoAcAASAAYAAAAA//kABgAAAHAACgB2ABEABgAAAAD/+AAFAAAAdgAKAHsAEgAG +AAD////4AAYAAAB7AAoAggASAAYAAAAA//gABQAAAIIACgCHABIABgAAAAD/+AAFAAAAhwAKAIwA +EgAGAAAAAP/4AAUAAACMAAoAkQASAAYAAAAA//gABQAAAJEACgCWABIABgAAAAD/+QAFAAAAlgAK +AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA +pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG +AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA//// ++QAGAAIAzgAKANUAEw== +""" + ) + ), + Image.open( + BytesIO( + base64.b64decode( + b""" +iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u +Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9 +M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g +LeNZUworuN1cjTPIzrTX6ofHWeo3v336qPzfEwRmBnHTtf95/fglZK5N0PDgfRTslpGBvz7LFc4F +IUXBWQGjQ5MGCx34EDFPwXiY4YbYxavpnhHFrk14CDAAAAD//wBlAJr/AgKqRooH2gAgPeggvUAA +Bu2WfgPoAwzRAABAAAAAAACQgLz/3Uv4Gv+gX7BJgDeeGP6AAAD1NMDzKHD7ANWr3loYbxsAD791 +NAADfcoIDyP44K/jv4Y63/Z+t98Ovt+ub4T48LAAAAD//wBlAJr/AuplMlADJAAAAGuAphWpqhMx +in0A/fRvAYBABPgBwBUgABBQ/sYAyv9g0bCHgOLoGAAAAAAAREAAwI7nr0ArYpow7aX8//9LaP/9 +SjdavWA8ePHeBIKB//81/83ndznOaXx379wAAAD//wBlAJr/AqDxW+D3AABAAbUh/QMnbQag/gAY +AYDAAACgtgD/gOqAAAB5IA/8AAAk+n9w0AAA8AAAmFRJuPo27ciC0cD5oeW4E7KA/wD3ECMAn2tt +y8PgwH8AfAxFzC0JzeAMtratAsC/ffwAAAD//wBlAJr/BGKAyCAA4AAAAvgeYTAwHd1kmQF5chkG +ABoMIHcL5xVpTfQbUqzlAAAErwAQBgAAEOClA5D9il08AEh/tUzdCBsXkbgACED+woQg8Si9VeqY +lODCn7lmF6NhnAEYgAAA/NMIAAAAAAD//2JgjLZgVGBg5Pv/Tvpc8hwGBjYGJADjHDrAwPzAjv/H +/Wf3PzCwtzcwHmBgYGcwbZz8wHaCAQMDOwMDQ8MCBgYOC3W7mp+f0w+wHOYxO3OG+e376hsMZjk3 +AAAAAP//YmCMY2A4wMAIN5e5gQETPD6AZisDAwMDgzSDAAPjByiHcQMDAwMDg1nOze1lByRu5/47 +c4859311AYNZzg0AAAAA//9iYGDBYihOIIMuwIjGL39/fwffA8b//xv/P2BPtzzHwCBjUQAAAAD/ +/yLFBrIBAAAA//9i1HhcwdhizX7u8NZNzyLbvT97bfrMf/QHI8evOwcSqGUJAAAA//9iYBB81iSw +pEE170Qrg5MIYydHqwdDQRMrAwcVrQAAAAD//2J4x7j9AAMDn8Q/BgYLBoaiAwwMjPdvMDBYM1Tv +oJodAAAAAP//Yqo/83+dxePWlxl3npsel9lvLfPcqlE9725C+acfVLMEAAAA//9i+s9gwCoaaGMR +evta/58PTEWzr21hufPjA8N+qlnBwAAAAAD//2JiWLci5v1+HmFXDqcnULE/MxgYGBj+f6CaJQAA +AAD//2Ji2FrkY3iYpYC5qDeGgeEMAwPDvwQBBoYvcTwOVLMEAAAA//9isDBgkP///0EOg9z35v// +Gc/eeW7BwPj5+QGZhANUswMAAAD//2JgqGBgYGBgqEMXlvhMPUsAAAAA//8iYDd1AAAAAP//AwDR +w7IkEbzhVQAAAABJRU5ErkJggg== +""" + ) + ) + ), + ) + return f + + +def load_default(size: float | None = None) -> FreeTypeFont | ImageFont: + """If FreeType support is available, load a version of Aileron Regular, + https://dotcolon.net/font/aileron, with a more limited character set. + + Otherwise, load a "better than nothing" font. + + .. versionadded:: 1.1.4 + + :param size: The font size of Aileron Regular. + + .. versionadded:: 10.1.0 + + :return: A font object. + """ + if isinstance(core, ModuleType) or size is not None: + return truetype( + BytesIO( + base64.b64decode( + b""" +AAEAAAAPAIAAAwBwRkZUTYwDlUAAADFoAAAAHEdERUYAqADnAAAo8AAAACRHUE9ThhmITwAAKfgAA +AduR1NVQnHxefoAACkUAAAA4k9TLzJovoHLAAABeAAAAGBjbWFw5lFQMQAAA6gAAAGqZ2FzcP//AA +MAACjoAAAACGdseWYmRXoPAAAGQAAAHfhoZWFkE18ayQAAAPwAAAA2aGhlYQboArEAAAE0AAAAJGh +tdHjjERZ8AAAB2AAAAdBsb2NhuOexrgAABVQAAADqbWF4cAC7AEYAAAFYAAAAIG5hbWUr+h5lAAAk +OAAAA6Jwb3N0D3oPTQAAJ9wAAAEKAAEAAAABGhxJDqIhXw889QALA+gAAAAA0Bqf2QAAAADhCh2h/ +2r/LgOxAyAAAAAIAAIAAAAAAAAAAQAAA8r/GgAAA7j/av9qA7EAAQAAAAAAAAAAAAAAAAAAAHQAAQ +AAAHQAQwAFAAAAAAACAAAAAQABAAAAQAAAAAAAAAADAfoBkAAFAAgCigJYAAAASwKKAlgAAAFeADI +BPgAAAAAFAAAAAAAAAAAAAAcAAAAAAAAAAAAAAABVS1dOAEAAIPsCAwL/GgDIA8oA5iAAAJMAAAAA +AhICsgAAACAAAwH0AAAAAAAAAU0AAADYAAAA8gA5AVMAVgJEAEYCRAA1AuQAKQKOAEAAsAArATsAZ +AE7AB4CMABVAkQAUADc/+EBEgAgANwAJQEv//sCRAApAkQAggJEADwCRAAtAkQAIQJEADkCRAArAk +QAMgJEACwCRAAxANwAJQDc/+ECRABnAkQAUAJEAEQB8wAjA1QANgJ/AB0CcwBkArsALwLFAGQCSwB +kAjcAZALGAC8C2gBkAQgAZAIgADcCYQBkAj8AZANiAGQCzgBkAuEALwJWAGQC3QAvAmsAZAJJADQC +ZAAiAqoAXgJuACADuAAaAnEAGQJFABMCTwAuATMAYgEv//sBJwAiAkQAUAH0ADIBLAApAhMAJAJjA +EoCEQAeAmcAHgIlAB4BIgAVAmcAHgJRAEoA7gA+AOn/8wIKAEoA9wBGA1cASgJRAEoCSgAeAmMASg +JnAB4BSgBKAcsAGAE5ABQCUABCAgIAAQMRAAEB4v/6AgEAAQHOABQBLwBAAPoAYAEvACECRABNA0Y +AJAItAHgBKgAcAkQAUAEsAHQAygAgAi0AOQD3ADYA9wAWAaEANgGhABYCbAAlAYMAeAGDADkA6/9q +AhsAFAIKABUB/QAVAAAAAwAAAAMAAAAcAAEAAAAAAKQAAwABAAAAHAAEAIgAAAAeABAAAwAOAH4Aq +QCrALEAtAC3ALsgGSAdICYgOiBEISL7Av//AAAAIACpAKsAsAC0ALcAuyAYIBwgJiA5IEQhIvsB// +//4/+5/7j/tP+y/7D/reBR4E/gR+A14CzfTwVxAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAEGAAABAAAAAAAAAAECAAAAAgAAAAAAAAAAAAAAAAAAAAEAAAMEBQYHCAkKCwwNDg8QERIT +FBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMT +U5PUFFSU1RVVldYWVpbXF1eX2BhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAA +AAAAAAYnFmAAAAAABlAAAAAAAAAAAAAAAAAAAAAAAAAAAAY2htAAAAAAAAAABrbGlqAAAAAHAAbm9 +ycwBnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmACYAJgAmAD4AUgCCAMoBCgFO +AVwBcgGIAaYBvAHKAdYB6AH2AgwCIAJKAogCpgLWAw4DIgNkA5wDugPUA+gD/AQQBEYEogS8BPoFJ +gVSBWoFgAWwBcoF1gX6BhQGJAZMBmgGiga0BuIHGgdUB2YHkAeiB8AH3AfyCAoIHAgqCDoITghcCG +oIogjSCPoJKglYCXwJwgnqCgIKKApACl4Klgq8CtwLDAs8C1YLjAuyC9oL7gwMDCYMSAxgDKAMrAz +qDQoNTA1mDYQNoA2uDcAN2g3oDfYODA4iDkoOXA5sDnoOnA7EDvwAAAAFAAAAAAH0ArwAAwAGAAkA +DAAPAAAxESERAxMhExcRASELARETAfT6qv6syKr+jgFUqsiqArz9RAGLAP/+1P8B/v3VAP8BLP4CA +P8AAgA5//IAuQKyAAMACwAANyMDMwIyFhQGIiY0oE4MZk84JCQ4JLQB/v3AJDgkJDgAAgBWAeUBPA +LfAAMABwAAEyMnMxcjJzOmRgpagkYKWgHl+vr6AAAAAAIARgAAAf4CsgAbAB8AAAEHMxUjByM3Iwc +jNyM1MzcjNTM3MwczNzMHMxUrAQczAZgdZXEvOi9bLzovWmYdZXEvOi9bLzovWp9bHlsBn4w429vb +2ziMONvb29s4jAAAAAMANf+mAg4DDAAfACYALAAAJRQGBxUjNS4BJzMeARcRLgE0Njc1MxUeARcjJ +icVHgEBFBYXNQ4BExU+ATU0Ag5xWDpgcgRcBz41Xl9oVTpVYwpcC1ttXP6cLTQuM5szOrVRZwlOTQ +ZqVzZECAEAGlukZAlOTQdrUG8O7iNlAQgxNhDlCDj+8/YGOjReAAAAAAUAKf/yArsCvAAHAAsAFQA +dACcAABIyFhQGIiY0EyMBMwQiBhUUFjI2NTQSMhYUBiImNDYiBhUUFjI2NTR5iFBQiFCVVwHAV/5c +OiMjOiPmiFBQiFCxOiMjOiMCvFaSVlaS/ZoCsjIzMC80NC8w/uNWklZWkhozMC80NC8wAAAAAgBA/ +/ICbgLAACIALgAAARUjEQYjIiY1NDY3LgE1NDYzMhcVJiMiBhUUFhcWOwE1MxUFFBYzMjc1IyIHDg +ECbmBcYYOOVkg7R4hsQjY4Q0RNRD4SLDxW/pJUXzksPCkUUk0BgUb+zBVUZ0BkDw5RO1huCkULQzp +COAMBcHDHRz0J/AIHRQAAAAEAKwHlAIUC3wADAAATIycze0YKWgHl+gAAAAABAGT/sAEXAwwACQAA +EzMGEBcjLgE0Nt06dXU6OUBAAwzG/jDGVePs4wAAAAEAHv+wANEDDAAJAAATMx4BFAYHIzYQHjo5Q +EA5OnUDDFXj7ONVxgHQAAAAAQBVAFIB2wHbAA4AAAE3FwcXBycHJzcnNxcnMwEtmxOfcTJjYzJxnx +ObCj4BKD07KYolmZkliik7PbMAAQBQAFUB9AIlAAsAAAEjFSM1IzUzNTMVMwH0tTq1tTq1AR/Kyjj +OzgAAAAAB/+H/iACMAGQABAAANwcjNzOMWlFOXVrS3AAAAQAgAP8A8gE3AAMAABMjNTPy0tIA/zgA +AQAl//IApQByAAcAADYyFhQGIiY0STgkJDgkciQ4JCQ4AAAAAf/7/+IBNALQAAMAABcjEzM5Pvs+H +gLuAAAAAAIAKf/yAhsCwAADAAcAABIgECA2IBAgKQHy/g5gATL+zgLA/TJEAkYAAAAAAQCCAAABlg +KyAAgAAAERIxEHNTc2MwGWVr6SIygCsv1OAldxW1sWAAEAPAAAAg4CwAAZAAA3IRUhNRM+ATU0JiM +iDwEjNz4BMzIWFRQGB7kBUv4x+kI2QTt+EAFWAQp8aGVtSl5GRjEA/0RVLzlLmAoKa3FsUkNxXQAA +AAEALf/yAhYCwAAqAAABHgEVFAYjIi8BMxceATMyNjU0KwE1MzI2NTQmIyIGDwEjNz4BMzIWFRQGA +YxBSZJo2RUBVgEHV0JBUaQREUBUQzc5TQcBVgEKfGhfcEMBbxJbQl1x0AoKRkZHPn9GSD80QUVCCg +pfbGBPOlgAAAACACEAAAIkArIACgAPAAAlIxUjNSE1ATMRMyMRBg8BAiRXVv6qAVZWV60dHLCurq4 +rAdn+QgFLMibzAAABADn/8gIZArIAHQAAATIWFRQGIyIvATMXFjMyNjU0JiMiByMTIRUhBzc2ATNv +d5Fl1RQBVgIad0VSTkVhL1IwAYj+vh8rMAHHgGdtgcUKCoFXTU5bYgGRRvAuHQAAAAACACv/8gITA +sAAFwAjAAABMhYVFAYjIhE0NjMyFh8BIycmIyIDNzYTMjY1NCYjIgYVFBYBLmp7imr0l3RZdAgBXA +IYZ5wKJzU6QVNJSz5SUAHSgWltiQFGxcNlVQoKdv7sPiz+ZF1LTmJbU0lhAAAAAQAyAAACGgKyAAY +AAAEVASMBITUCGv6oXAFL/oECsij9dgJsRgAAAAMALP/xAhgCwAAWACAALAAAAR4BFRQGIyImNTQ2 +Ny4BNTQ2MhYVFAYmIgYVFBYyNjU0AzI2NTQmIyIGFRQWAZQ5S5BmbIpPOjA7ecp5P2F8Q0J8RIVJS +0pLTEtOAW0TXTxpZ2ZqPF0SE1A3VWVlVTdQ/UU0N0RENzT9/ko+Ok1NOj1LAAIAMf/yAhkCwAAXAC +MAAAEyERQGIyImLwEzFxYzMhMHBiMiJjU0NhMyNjU0JiMiBhUUFgEl9Jd0WXQIAVwCGGecCic1SWp +7imo+UlBAQVNJAsD+usXDZVUKCnYBFD4sgWltif5kW1NJYV1LTmIAAAACACX/8gClAiAABwAPAAAS +MhYUBiImNBIyFhQGIiY0STgkJDgkJDgkJDgkAiAkOCQkOP52JDgkJDgAAAAC/+H/iAClAiAABwAMA +AASMhYUBiImNBMHIzczSTgkJDgkaFpSTl4CICQ4JCQ4/mba5gAAAQBnAB4B+AH0AAYAAAENARUlNS +UB+P6qAVb+bwGRAbCmpkbJRMkAAAIAUAC7AfQBuwADAAcAAAEhNSERITUhAfT+XAGk/lwBpAGDOP8 +AOAABAEQAHgHVAfQABgAAARUFNS0BNQHV/m8BVv6qAStEyUSmpkYAAAAAAgAj//IB1ALAABgAIAAA +ATIWFRQHDgEHIz4BNz4BNTQmIyIGByM+ARIyFhQGIiY0AQRibmktIAJWBSEqNig+NTlHBFoDezQ4J +CQ4JALAZ1BjaS03JS1DMD5LLDQ/SUVgcv2yJDgkJDgAAAAAAgA2/5gDFgKYADYAQgAAAQMGFRQzMj +Y1NCYjIg4CFRQWMzI2NxcGIyImNTQ+AjMyFhUUBiMiJwcGIyImNTQ2MzIfATcHNzYmIyIGFRQzMjY +Cej8EJjJJlnBAfGQ+oHtAhjUYg5OPx0h2k06Os3xRWQsVLjY5VHtdPBwJETcJDyUoOkZEJz8B0f74 +EQ8kZl6EkTFZjVOLlyknMVm1pmCiaTq4lX6CSCknTVRmmR8wPdYnQzxuSWVGAAIAHQAAAncCsgAHA +AoAACUjByMTMxMjATMDAcj+UVz4dO5d/sjPZPT0ArL9TgE6ATQAAAADAGQAAAJMArIAEAAbACcAAA +EeARUUBgcGKwERMzIXFhUUJRUzMjc2NTQnJiMTPgE1NCcmKwEVMzIBvkdHZkwiNt7LOSGq/oeFHBt +hahIlSTM+cB8Yj5UWAW8QT0VYYgwFArIEF5Fv1eMED2NfDAL93AU+N24PBP0AAAAAAQAv//ICjwLA +ABsAAAEyFh8BIycmIyIGFRQWMzI/ATMHDgEjIiY1NDYBdX+PCwFWAiKiaHx5ZaIiAlYBCpWBk6a0A +sCAagoKpqN/gaOmCgplhcicn8sAAAIAZAAAAp8CsgAMABkAAAEeARUUBgcGKwERMzITPgE1NCYnJi +sBETMyAY59lJp8IzXN0jUVWmdjWRs5d3I4Aq4QqJWUug8EArL9mQ+PeHGHDgX92gAAAAABAGQAAAI +vArIACwAAJRUhESEVIRUhFSEVAi/+NQHB/pUBTf6zRkYCskbwRvAAAAABAGQAAAIlArIACQAAExUh +FSERIxEhFboBQ/69VgHBAmzwRv7KArJGAAAAAAEAL//yAo8CwAAfAAABMxEjNQcGIyImNTQ2MzIWH +wEjJyYjIgYVFBYzMjY1IwGP90wfPnWTprSSf48LAVYCIqJofHllVG+hAU3+s3hARsicn8uAagoKpq +N/gaN1XAAAAAEAZAAAAowCsgALAAABESMRIREjETMRIRECjFb+hFZWAXwCsv1OAS7+0gKy/sQBPAA +AAAABAGQAAAC6ArIAAwAAMyMRM7pWVgKyAAABADf/8gHoArIAEwAAAREUBw4BIyImLwEzFxYzMjc2 +NREB6AIFcGpgbQIBVgIHfXQKAQKy/lYxIltob2EpKYyEFD0BpwAAAAABAGQAAAJ0ArIACwAACQEjA +wcVIxEzEQEzATsBJ3ntQlZWAVVlAWH+nwEnR+ACsv6RAW8AAQBkAAACLwKyAAUAACUVIREzEQIv/j +VWRkYCsv2UAAABAGQAAAMUArIAFAAAAREjETQ3BgcDIwMmJxYVESMRMxsBAxRWAiMxemx8NxsCVo7 +MywKy/U4BY7ZLco7+nAFmoFxLtP6dArL9lwJpAAAAAAEAZAAAAoACsgANAAAhIwEWFREjETMBJjUR +MwKAhP67A1aEAUUDVAJeeov+pwKy/aJ5jAFZAAAAAgAv//ICuwLAAAkAEwAAEiAWFRQGICY1NBIyN +jU0JiIGFRTbATSsrP7MrNrYenrYegLAxaKhxsahov47nIeIm5uIhwACAGQAAAJHArIADgAYAAABHg +EVFAYHBisBESMRMzITNjQnJisBETMyAZRUX2VOHzuAVtY7GlxcGDWIiDUCrgtnVlVpCgT+5gKy/rU +V1BUF/vgAAAACAC//zAK9AsAAEgAcAAAlFhcHJiMiBwYjIiY1NDYgFhUUJRQWMjY1NCYiBgI9PUMx +UDcfKh8omqysATSs/dR62Hp62HpICTg7NgkHxqGixcWitbWHnJyHiJubAAIAZAAAAlgCsgAXACMAA +CUWFyMmJyYnJisBESMRMzIXHgEVFAYHFiUzMjc+ATU0JyYrAQIqDCJfGQwNWhAhglbiOx9QXEY1Tv +6bhDATMj1lGSyMtYgtOXR0BwH+1wKyBApbU0BSESRAAgVAOGoQBAABADT/8gIoAsAAJQAAATIWFyM +uASMiBhUUFhceARUUBiMiJiczHgEzMjY1NCYnLgE1NDYBOmd2ClwGS0E6SUNRdW+HZnKKC1wPWkQ9 +Uk1cZGuEAsBwXUJHNjQ3OhIbZVZZbm5kREo+NT5DFRdYUFdrAAAAAAEAIgAAAmQCsgAHAAABIxEjE +SM1IQJk9lb2AkICbP2UAmxGAAEAXv/yAmQCsgAXAAABERQHDgEiJicmNREzERQXHgEyNjc2NRECZA +IIgfCBCAJWAgZYmlgGAgKy/k0qFFxzc1wUKgGz/lUrEkRQUEQSKwGrAAAAAAEAIAAAAnoCsgAGAAA +hIwMzGwEzAYJ07l3N1FwCsv2PAnEAAAEAGgAAA7ECsgAMAAABAyMLASMDMxsBMxsBA7HAcZyicrZi +kaB0nJkCsv1OAlP9rQKy/ZsCW/2kAmYAAAEAGQAAAm8CsgALAAAhCwEjEwMzGwEzAxMCCsrEY/bkY +re+Y/D6AST+3AFcAVb+5gEa/q3+oQAAAQATAAACUQKyAAgAAAERIxEDMxsBMwFdVvRjwLphARD+8A +EQAaL+sQFPAAABAC4AAAI5ArIACQAAJRUhNQEhNSEVAQI5/fUBof57Aen+YUZGQgIqRkX92QAAAAA +BAGL/sAEFAwwABwAAARUjETMVIxEBBWlpowMMOP0UOANcAAAB//v/4gE0AtAAAwAABSMDMwE0Pvs+ +HgLuAAAAAQAi/7AAxQMMAAcAABcjNTMRIzUzxaNpaaNQOALsOAABAFAA1wH0AmgABgAAJQsBIxMzE +wGwjY1GsESw1wFZ/qcBkf5vAAAAAQAy/6oBwv/iAAMAAAUhNSEBwv5wAZBWOAAAAAEAKQJEALYCsg +ADAAATIycztjhVUAJEbgAAAAACACT/8gHQAiAAHQAlAAAhJwcGIyImNTQ2OwE1NCcmIyIHIz4BMzI +XFh0BFBcnMjY9ASYVFAF6CR0wVUtgkJoiAgdgaQlaBm1Zrg4DCuQ9R+5MOSFQR1tbDiwUUXBUXowf +J8c9SjRORzYSgVwAAAAAAgBK//ICRQLfABEAHgAAATIWFRQGIyImLwEVIxEzETc2EzI2NTQmIyIGH +QEUFgFUcYCVbiNJEyNWVigySElcU01JXmECIJd4i5QTEDRJAt/+3jkq/hRuZV55ZWsdX14AAQAe// +IB9wIgABgAAAEyFhcjJiMiBhUUFjMyNjczDgEjIiY1NDYBF152DFocbEJXU0A1Rw1aE3pbaoKQAiB +oWH5qZm1tPDlaXYuLgZcAAAACAB7/8gIZAt8AEQAeAAABESM1BwYjIiY1NDYzMhYfAREDMjY9ATQm +IyIGFRQWAhlWKDJacYCVbiNJEyOnSV5hQUlcUwLf/SFVOSqXeIuUExA0ARb9VWVrHV9ebmVeeQACA +B7/8gH9AiAAFQAbAAABFAchHgEzMjY3Mw4BIyImNTQ2MzIWJyIGByEmAf0C/oAGUkA1SwlaD4FXbI +WObmt45UBVBwEqDQEYFhNjWD84W16Oh3+akU9aU60AAAEAFQAAARoC8gAWAAATBh0BMxUjESMRIzU +zNTQ3PgEzMhcVJqcDbW1WOTkDB0k8Hx5oAngVITRC/jQBzEIsJRs5PwVHEwAAAAIAHv8uAhkCIAAi +AC8AAAERFAcOASMiLwEzFx4BMzI2NzY9AQcGIyImNTQ2MzIWHwE1AzI2PQE0JiMiBhUUFgIZAQSEd +NwRAVcBBU5DTlUDASgyWnGAlW4jSRMjp0leYUFJXFMCEv5wSh1zeq8KCTI8VU0ZIQk5Kpd4i5QTED +RJ/iJlax1fXm5lXnkAAQBKAAACCgLkABcAAAEWFREjETQnLgEHDgEdASMRMxE3NjMyFgIIAlYCBDs +6RVRWViE5UVViAYUbQP7WASQxGzI7AQJyf+kC5P7TPSxUAAACAD4AAACsAsAABwALAAASMhYUBiIm +NBMjETNeLiAgLiBiVlYCwCAuICAu/WACEgAC//P/LgCnAsAABwAVAAASMhYUBiImNBcRFAcGIyInN +RY3NjURWS4gIC4gYgMLcRwNSgYCAsAgLiAgLo79wCUbZAJGBzMOHgJEAAAAAQBKAAACCALfAAsAAC +EnBxUjETMREzMHEwGTwTJWVvdu9/rgN6kC3/4oAQv6/ugAAQBG//wA3gLfAA8AABMRFBceATcVBiM +iJicmNRGcAQIcIxkkKi4CAQLf/bkhERoSBD4EJC8SNAJKAAAAAQBKAAADEAIgACQAAAEWFREjETQn +JiMiFREjETQnJiMiFREjETMVNzYzMhYXNzYzMhYDCwVWBAxedFYEDF50VlYiJko7ThAvJkpEVAGfI +jn+vAEcQyRZ1v76ARxDJFnW/voCEk08HzYtRB9HAAAAAAEASgAAAgoCIAAWAAABFhURIxE0JyYjIg +YdASMRMxU3NjMyFgIIAlYCCXBEVVZWITlRVWIBhRtA/tYBJDEbbHR/6QISWz0sVAAAAAACAB7/8gI +sAiAABwARAAASIBYUBiAmNBIyNjU0JiIGFRSlAQCHh/8Ah7ieWlqeWgIgn/Cfn/D+s3ZfYHV1YF8A +AgBK/zwCRQIgABEAHgAAATIWFRQGIyImLwERIxEzFTc2EzI2NTQmIyIGHQEUFgFUcYCVbiNJEyNWV +igySElcU01JXmECIJd4i5QTEDT+8wLWVTkq/hRuZV55ZWsdX14AAgAe/zwCGQIgABEAHgAAAREjEQ +cGIyImNTQ2MzIWHwE1AzI2PQE0JiMiBhUUFgIZVigyWnGAlW4jSRMjp0leYUFJXFMCEv0qARk5Kpd +4i5QTEDRJ/iJlax1fXm5lXnkAAQBKAAABPgIeAA0AAAEyFxUmBhURIxEzFTc2ARoWDkdXVlYwIwIe +B0EFVlf+0gISU0cYAAEAGP/yAa0CIAAjAAATMhYXIyYjIgYVFBYXHgEVFAYjIiYnMxYzMjY1NCYnL +gE1NDbkV2MJWhNdKy04PF1XbVhWbgxaE2ktOjlEUllkAiBaS2MrJCUoEBlPQkhOVFZoKCUmLhIWSE +BIUwAAAAEAFP/4ARQCiQAXAAATERQXHgE3FQYjIiYnJjURIzUzNTMVMxWxAQMmMx8qMjMEAUdHVmM +BzP7PGw4mFgY/BSwxDjQBNUJ7e0IAAAABAEL/8gICAhIAFwAAAREjNQcGIyImJyY1ETMRFBceATMy +Nj0BAgJWITlRT2EKBVYEBkA1RFECEv3uWj4qTToiOQE+/tIlJC43c4DpAAAAAAEAAQAAAfwCEgAGA +AABAyMDMxsBAfzJaclfop8CEv3uAhL+LQHTAAABAAEAAAMLAhIADAAAAQMjCwEjAzMbATMbAQMLqW +Z2dmapY3t0a3Z7AhL97gG+/kICEv5AAcD+QwG9AAAB//oAAAHWAhIACwAAARMjJwcjEwMzFzczARq +8ZIuKY763ZoWFYwEO/vLV1QEMAQbNzQAAAQAB/y4B+wISABEAAAEDDgEjIic1FjMyNj8BAzMbAQH7 +2iFZQB8NDRIpNhQH02GenQIS/cFVUAJGASozEwIt/i4B0gABABQAAAGxAg4ACQAAJRUhNQEhNSEVA +QGx/mMBNP7iAYL+zkREQgGIREX+ewAAAAABAED/sAEOAwwALAAAASMiBhUUFxYVFAYHHgEVFAcGFR +QWOwEVIyImNTQ3NjU0JzU2NTQnJjU0NjsBAQ4MKiMLDS4pKS4NCyMqDAtERAwLUlILDERECwLUGBk +WTlsgKzUFBTcrIFtOFhkYOC87GFVMIkUIOAhFIkxVGDsvAAAAAAEAYP84AJoDIAADAAAXIxEzmjo6 +yAPoAAEAIf+wAO8DDAAsAAATFQYVFBcWFRQGKwE1MzI2NTQnJjU0NjcuATU0NzY1NCYrATUzMhYVF +AcGFRTvUgsMREQLDCojCw0uKSkuDQsjKgwLREQMCwF6OAhFIkxVGDsvOBgZFk5bICs1BQU3KyBbTh +YZGDgvOxhVTCJFAAABAE0A3wH2AWQAEwAAATMUIyImJyYjIhUjNDMyFhcWMzIBvjhuGywtQR0xOG4 +bLC1BHTEBZIURGCNMhREYIwAAAwAk/94DIgLoAAcAEQApAAAAIBYQBiAmECQgBhUUFiA2NTQlMhYX +IyYjIgYUFjMyNjczDgEjIiY1NDYBAQFE3d3+vN0CB/7wubkBELn+xVBnD1wSWDo+QTcqOQZcEmZWX +HN2Aujg/rbg4AFKpr+Mjb6+jYxbWEldV5ZZNShLVn5na34AAgB4AFIB9AGeAAUACwAAAQcXIyc3Mw +cXIyc3AUqJiUmJifOJiUmJiQGepqampqampqYAAAIAHAHSAQ4CwAAHAA8AABIyFhQGIiY0NiIGFBY +yNjRgakREakSTNCEhNCECwEJqQkJqCiM4IyM4AAAAAAIAUAAAAfQCCwALAA8AAAEzFSMVIzUjNTM1 +MxMhNSEBP7W1OrW1OrX+XAGkAVs4tLQ4sP31OAAAAQB0AkQBAQKyAAMAABMjNzOsOD1QAkRuAAAAA +AEAIADsAKoBdgAHAAASMhYUBiImNEg6KCg6KAF2KDooKDoAAAIAOQBSAbUBngAFAAsAACUHIzcnMw +UHIzcnMwELiUmJiUkBM4lJiYlJ+KampqampqYAAAABADYB5QDhAt8ABAAAEzczByM2Xk1OXQHv8Po +AAQAWAeUAwQLfAAQAABMHIzczwV5NTl0C1fD6AAIANgHlAYsC3wAEAAkAABM3MwcjPwEzByM2Xk1O +XapeTU5dAe/w+grw+gAAAgAWAeUBawLfAAQACQAAEwcjNzMXByM3M8FeTU5dql5NTl0C1fD6CvD6A +AADACX/8gI1AHIABwAPABcAADYyFhQGIiY0NjIWFAYiJjQ2MhYUBiImNEk4JCQ4JOw4JCQ4JOw4JC +Q4JHIkOCQkOCQkOCQkOCQkOCQkOAAAAAEAeABSAUoBngAFAAABBxcjJzcBSomJSYmJAZ6mpqamAAA +AAAEAOQBSAQsBngAFAAAlByM3JzMBC4lJiYlJ+KampgAAAf9qAAABgQKyAAMAACsBATM/VwHAVwKy +AAAAAAIAFAHIAdwClAAHABQAABMVIxUjNSM1BRUjNwcjJxcjNTMXN9pKMkoByDICKzQqATJLKysCl +CmjoykBy46KiY3Lm5sAAQAVAAABvALyABgAAAERIxEjESMRIzUzNTQ3NjMyFxUmBgcGHQEBvFbCVj +k5AxHHHx5iVgcDAg798gHM/jQBzEIOJRuWBUcIJDAVIRYAAAABABX//AHkAvIAJQAAJR4BNxUGIyI +mJyY1ESYjIgcGHQEzFSMRIxEjNTM1NDc2MzIXERQBowIcIxkkKi4CAR4nXgwDbW1WLy8DEbNdOmYa +EQQ/BCQvEjQCFQZWFSEWQv40AcxCDiUblhP9uSEAAAAAAAAWAQ4AAQAAAAAAAAATACgAAQAAAAAAA +QAHAEwAAQAAAAAAAgAHAGQAAQAAAAAAAwAaAKIAAQAAAAAABAAHAM0AAQAAAAAABQA8AU8AAQAAAA +AABgAPAawAAQAAAAAACAALAdQAAQAAAAAACQALAfgAAQAAAAAACwAXAjQAAQAAAAAADAAXAnwAAwA +BBAkAAAAmAAAAAwABBAkAAQAOADwAAwABBAkAAgAOAFQAAwABBAkAAwA0AGwAAwABBAkABAAOAL0A +AwABBAkABQB4ANUAAwABBAkABgAeAYwAAwABBAkACAAWAbwAAwABBAkACQAWAeAAAwABBAkACwAuA +gQAAwABBAkADAAuAkwATgBvACAAUgBpAGcAaAB0AHMAIABSAGUAcwBlAHIAdgBlAGQALgAATm8gUm +lnaHRzIFJlc2VydmVkLgAAQQBpAGwAZQByAG8AbgAAQWlsZXJvbgAAUgBlAGcAdQBsAGEAcgAAUmV +ndWxhcgAAMQAuADEAMAAyADsAVQBLAFcATgA7AEEAaQBsAGUAcgBvAG4ALQBSAGUAZwB1AGwAYQBy +AAAxLjEwMjtVS1dOO0FpbGVyb24tUmVndWxhcgAAQQBpAGwAZQByAG8AbgAAQWlsZXJvbgAAVgBlA +HIAcwBpAG8AbgAgADEALgAxADAAMgA7AFAAUwAgADAAMAAxAC4AMQAwADIAOwBoAG8AdABjAG8Abg +B2ACAAMQAuADAALgA3ADAAOwBtAGEAawBlAG8AdABmAC4AbABpAGIAMgAuADUALgA1ADgAMwAyADk +AAFZlcnNpb24gMS4xMDI7UFMgMDAxLjEwMjtob3Rjb252IDEuMC43MDttYWtlb3RmLmxpYjIuNS41 +ODMyOQAAQQBpAGwAZQByAG8AbgAtAFIAZQBnAHUAbABhAHIAAEFpbGVyb24tUmVndWxhcgAAUwBvA +HIAYQAgAFMAYQBnAGEAbgBvAABTb3JhIFNhZ2FubwAAUwBvAHIAYQAgAFMAYQBnAGEAbgBvAABTb3 +JhIFNhZ2FubwAAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGQAbwB0AGMAbwBsAG8AbgAuAG4AZQB0AAB +odHRwOi8vd3d3LmRvdGNvbG9uLm5ldAAAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGQAbwB0AGMAbwBs +AG8AbgAuAG4AZQB0AABodHRwOi8vd3d3LmRvdGNvbG9uLm5ldAAAAAACAAAAAAAA/4MAMgAAAAAAA +AAAAAAAAAAAAAAAAAAAAHQAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATAB +QAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAA +xADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0A +TgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAIsAqQCDAJMAjQDDAKoAtgC3A +LQAtQCrAL4AvwC8AIwAwADBAAAAAAAB//8AAgABAAAADAAAABwAAAACAAIAAwBxAAEAcgBzAAIABA +AAAAIAAAABAAAACgBMAGYAAkRGTFQADmxhdG4AGgAEAAAAAP//AAEAAAAWAANDQVQgAB5NT0wgABZ +ST00gABYAAP//AAEAAAAA//8AAgAAAAEAAmxpZ2EADmxvY2wAFAAAAAEAAQAAAAEAAAACAAYAEAAG +AAAAAgASADQABAAAAAEATAADAAAAAgAQABYAAQAcAAAAAQABAE8AAQABAGcAAQABAE8AAwAAAAIAE +AAWAAEAHAAAAAEAAQAvAAEAAQBnAAEAAQAvAAEAGgABAAgAAgAGAAwAcwACAE8AcgACAEwAAQABAE +kAAAABAAAACgBGAGAAAkRGTFQADmxhdG4AHAAEAAAAAP//AAIAAAABABYAA0NBVCAAFk1PTCAAFlJ +PTSAAFgAA//8AAgAAAAEAAmNwc3AADmtlcm4AFAAAAAEAAAAAAAEAAQACAAYADgABAAAAAQASAAIA +AAACAB4ANgABAAoABQAFAAoAAgABACQAPQAAAAEAEgAEAAAAAQAMAAEAOP/nAAEAAQAkAAIGigAEA +AAFJAXKABoAGQAA//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAD/sv+4/+z/7v/MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAD/xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9T/6AAAAAD/8QAA +ABD/vQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7gAAAAAAAAAAAAAAAAAA//MAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAAAAAAAP/5AAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAD/4AAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//L/9AAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAA/+gAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/zAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/mAAAAAAAAAAAAAAAAAAD +/4gAA//AAAAAA//YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+AAAAAAAAP/OAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/zv/qAAAAAP/0AAAACAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/ZAAD/egAA/1kAAAAA/5D/rgAAAAAAAAAAAA +AAAAAAAAAAAAAAAAD/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAD/8AAA/7b/8P+wAAD/8P/E/98AAAAA/8P/+P/0//oAAAAAAAAAAAAA//gA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+AAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/w//C/9MAAP/SAAD/9wAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAD/yAAA/+kAAAAA//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9wAAAAD//QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAP/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAP/cAAAAAAAAAAAAAAAA/7YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAP/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/6AAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAkAFAAEAAAAAQACwAAABcA +BgAAAAAAAAAIAA4AAAAAAAsAEgAAAAAAAAATABkAAwANAAAAAQAJAAAAAAAAAAAAAAAAAAAAGAAAA +AAABwAAAAAAAAAAAAAAFQAFAAAAAAAYABgAAAAUAAAACgAAAAwAAgAPABEAFgAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAEAEQBdAAYAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAcAAAAAAAAABwAAAAAACAAAAAAAAAAAAAcAAAAHAAAAEwAJ +ABUADgAPAAAACwAQAAAAAAAAAAAAAAAAAAUAGAACAAIAAgAAAAIAGAAXAAAAGAAAABYAFgACABYAA +gAWAAAAEQADAAoAFAAMAA0ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAEgAGAAEAHgAkAC +YAJwApACoALQAuAC8AMgAzADcAOAA5ADoAPAA9AEUASABOAE8AUgBTAFUAVwBZAFoAWwBcAF0AcwA +AAAAAAQAAAADa3tfFAAAAANAan9kAAAAA4QodoQ== +""" + ) + ), + 10 if size is None else size, + layout_engine=Layout.BASIC, + ) + return load_default_imagefont() diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageGrab.py b/.venv/lib/python3.12/site-packages/PIL/ImageGrab.py new file mode 100644 index 0000000..e27ca7e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageGrab.py @@ -0,0 +1,194 @@ +# +# The Python Imaging Library +# $Id$ +# +# screen grabber +# +# History: +# 2001-04-26 fl created +# 2001-09-17 fl use builtin driver, if present +# 2002-11-19 fl added grabclipboard support +# +# Copyright (c) 2001-2002 by Secret Labs AB +# Copyright (c) 2001-2002 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import os +import shutil +import subprocess +import sys +import tempfile + +from . import Image + + +def grab( + bbox: tuple[int, int, int, int] | None = None, + include_layered_windows: bool = False, + all_screens: bool = False, + xdisplay: str | None = None, +) -> Image.Image: + im: Image.Image + if xdisplay is None: + if sys.platform == "darwin": + fh, filepath = tempfile.mkstemp(".png") + os.close(fh) + args = ["screencapture"] + if bbox: + left, top, right, bottom = bbox + args += ["-R", f"{left},{top},{right-left},{bottom-top}"] + subprocess.call(args + ["-x", filepath]) + im = Image.open(filepath) + im.load() + os.unlink(filepath) + if bbox: + im_resized = im.resize((right - left, bottom - top)) + im.close() + return im_resized + return im + elif sys.platform == "win32": + offset, size, data = Image.core.grabscreen_win32( + include_layered_windows, all_screens + ) + im = Image.frombytes( + "RGB", + size, + data, + # RGB, 32-bit line padding, origin lower left corner + "raw", + "BGR", + (size[0] * 3 + 3) & -4, + -1, + ) + if bbox: + x0, y0 = offset + left, top, right, bottom = bbox + im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) + return im + # Cast to Optional[str] needed for Windows and macOS. + display_name: str | None = xdisplay + try: + if not Image.core.HAVE_XCB: + msg = "Pillow was built without XCB support" + raise OSError(msg) + size, data = Image.core.grabscreen_x11(display_name) + except OSError: + if ( + display_name is None + and sys.platform not in ("darwin", "win32") + and shutil.which("gnome-screenshot") + ): + fh, filepath = tempfile.mkstemp(".png") + os.close(fh) + subprocess.call(["gnome-screenshot", "-f", filepath]) + im = Image.open(filepath) + im.load() + os.unlink(filepath) + if bbox: + im_cropped = im.crop(bbox) + im.close() + return im_cropped + return im + else: + raise + else: + im = Image.frombytes("RGB", size, data, "raw", "BGRX", size[0] * 4, 1) + if bbox: + im = im.crop(bbox) + return im + + +def grabclipboard() -> Image.Image | list[str] | None: + if sys.platform == "darwin": + fh, filepath = tempfile.mkstemp(".png") + os.close(fh) + commands = [ + 'set theFile to (open for access POSIX file "' + + filepath + + '" with write permission)', + "try", + " write (the clipboard as «class PNGf») to theFile", + "end try", + "close access theFile", + ] + script = ["osascript"] + for command in commands: + script += ["-e", command] + subprocess.call(script) + + im = None + if os.stat(filepath).st_size != 0: + im = Image.open(filepath) + im.load() + os.unlink(filepath) + return im + elif sys.platform == "win32": + fmt, data = Image.core.grabclipboard_win32() + if fmt == "file": # CF_HDROP + import struct + + o = struct.unpack_from("I", data)[0] + if data[16] != 0: + files = data[o:].decode("utf-16le").split("\0") + else: + files = data[o:].decode("mbcs").split("\0") + return files[: files.index("")] + if isinstance(data, bytes): + data = io.BytesIO(data) + if fmt == "png": + from . import PngImagePlugin + + return PngImagePlugin.PngImageFile(data) + elif fmt == "DIB": + from . import BmpImagePlugin + + return BmpImagePlugin.DibImageFile(data) + return None + else: + if os.getenv("WAYLAND_DISPLAY"): + session_type = "wayland" + elif os.getenv("DISPLAY"): + session_type = "x11" + else: # Session type check failed + session_type = None + + if shutil.which("wl-paste") and session_type in ("wayland", None): + args = ["wl-paste", "-t", "image"] + elif shutil.which("xclip") and session_type in ("x11", None): + args = ["xclip", "-selection", "clipboard", "-t", "image/png", "-o"] + else: + msg = "wl-paste or xclip is required for ImageGrab.grabclipboard() on Linux" + raise NotImplementedError(msg) + + p = subprocess.run(args, capture_output=True) + if p.returncode != 0: + err = p.stderr + for silent_error in [ + # wl-paste, when the clipboard is empty + b"Nothing is copied", + # Ubuntu/Debian wl-paste, when the clipboard is empty + b"No selection", + # Ubuntu/Debian wl-paste, when an image isn't available + b"No suitable type of content copied", + # wl-paste or Ubuntu/Debian xclip, when an image isn't available + b" not available", + # xclip, when an image isn't available + b"cannot convert ", + # xclip, when the clipboard isn't initialized + b"xclip: Error: There is no owner for the ", + ]: + if silent_error in err: + return None + msg = f"{args[0]} error" + if err: + msg += f": {err.strip().decode()}" + raise ChildProcessError(msg) + + data = io.BytesIO(p.stdout) + im = Image.open(data) + im.load() + return im diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageMath.py b/.venv/lib/python3.12/site-packages/PIL/ImageMath.py new file mode 100644 index 0000000..6664434 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageMath.py @@ -0,0 +1,357 @@ +# +# The Python Imaging Library +# $Id$ +# +# a simple math add-on for the Python Imaging Library +# +# History: +# 1999-02-15 fl Original PIL Plus release +# 2005-05-05 fl Simplified and cleaned up for PIL 1.1.6 +# 2005-09-12 fl Fixed int() and float() for Python 2.4.1 +# +# Copyright (c) 1999-2005 by Secret Labs AB +# Copyright (c) 2005 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import builtins +from types import CodeType +from typing import Any, Callable + +from . import Image, _imagingmath +from ._deprecate import deprecate + + +class _Operand: + """Wraps an image operand, providing standard operators""" + + def __init__(self, im: Image.Image): + self.im = im + + def __fixup(self, im1: _Operand | float) -> Image.Image: + # convert image to suitable mode + if isinstance(im1, _Operand): + # argument was an image. + if im1.im.mode in ("1", "L"): + return im1.im.convert("I") + elif im1.im.mode in ("I", "F"): + return im1.im + else: + msg = f"unsupported mode: {im1.im.mode}" + raise ValueError(msg) + else: + # argument was a constant + if isinstance(im1, (int, float)) and self.im.mode in ("1", "L", "I"): + return Image.new("I", self.im.size, im1) + else: + return Image.new("F", self.im.size, im1) + + def apply( + self, + op: str, + im1: _Operand | float, + im2: _Operand | float | None = None, + mode: str | None = None, + ) -> _Operand: + im_1 = self.__fixup(im1) + if im2 is None: + # unary operation + out = Image.new(mode or im_1.mode, im_1.size, None) + im_1.load() + try: + op = getattr(_imagingmath, f"{op}_{im_1.mode}") + except AttributeError as e: + msg = f"bad operand type for '{op}'" + raise TypeError(msg) from e + _imagingmath.unop(op, out.im.id, im_1.im.id) + else: + # binary operation + im_2 = self.__fixup(im2) + if im_1.mode != im_2.mode: + # convert both arguments to floating point + if im_1.mode != "F": + im_1 = im_1.convert("F") + if im_2.mode != "F": + im_2 = im_2.convert("F") + if im_1.size != im_2.size: + # crop both arguments to a common size + size = ( + min(im_1.size[0], im_2.size[0]), + min(im_1.size[1], im_2.size[1]), + ) + if im_1.size != size: + im_1 = im_1.crop((0, 0) + size) + if im_2.size != size: + im_2 = im_2.crop((0, 0) + size) + out = Image.new(mode or im_1.mode, im_1.size, None) + im_1.load() + im_2.load() + try: + op = getattr(_imagingmath, f"{op}_{im_1.mode}") + except AttributeError as e: + msg = f"bad operand type for '{op}'" + raise TypeError(msg) from e + _imagingmath.binop(op, out.im.id, im_1.im.id, im_2.im.id) + return _Operand(out) + + # unary operators + def __bool__(self) -> bool: + # an image is "true" if it contains at least one non-zero pixel + return self.im.getbbox() is not None + + def __abs__(self) -> _Operand: + return self.apply("abs", self) + + def __pos__(self) -> _Operand: + return self + + def __neg__(self) -> _Operand: + return self.apply("neg", self) + + # binary operators + def __add__(self, other: _Operand | float) -> _Operand: + return self.apply("add", self, other) + + def __radd__(self, other: _Operand | float) -> _Operand: + return self.apply("add", other, self) + + def __sub__(self, other: _Operand | float) -> _Operand: + return self.apply("sub", self, other) + + def __rsub__(self, other: _Operand | float) -> _Operand: + return self.apply("sub", other, self) + + def __mul__(self, other: _Operand | float) -> _Operand: + return self.apply("mul", self, other) + + def __rmul__(self, other: _Operand | float) -> _Operand: + return self.apply("mul", other, self) + + def __truediv__(self, other: _Operand | float) -> _Operand: + return self.apply("div", self, other) + + def __rtruediv__(self, other: _Operand | float) -> _Operand: + return self.apply("div", other, self) + + def __mod__(self, other: _Operand | float) -> _Operand: + return self.apply("mod", self, other) + + def __rmod__(self, other: _Operand | float) -> _Operand: + return self.apply("mod", other, self) + + def __pow__(self, other: _Operand | float) -> _Operand: + return self.apply("pow", self, other) + + def __rpow__(self, other: _Operand | float) -> _Operand: + return self.apply("pow", other, self) + + # bitwise + def __invert__(self) -> _Operand: + return self.apply("invert", self) + + def __and__(self, other: _Operand | float) -> _Operand: + return self.apply("and", self, other) + + def __rand__(self, other: _Operand | float) -> _Operand: + return self.apply("and", other, self) + + def __or__(self, other: _Operand | float) -> _Operand: + return self.apply("or", self, other) + + def __ror__(self, other: _Operand | float) -> _Operand: + return self.apply("or", other, self) + + def __xor__(self, other: _Operand | float) -> _Operand: + return self.apply("xor", self, other) + + def __rxor__(self, other: _Operand | float) -> _Operand: + return self.apply("xor", other, self) + + def __lshift__(self, other: _Operand | float) -> _Operand: + return self.apply("lshift", self, other) + + def __rshift__(self, other: _Operand | float) -> _Operand: + return self.apply("rshift", self, other) + + # logical + def __eq__(self, other): + return self.apply("eq", self, other) + + def __ne__(self, other): + return self.apply("ne", self, other) + + def __lt__(self, other: _Operand | float) -> _Operand: + return self.apply("lt", self, other) + + def __le__(self, other: _Operand | float) -> _Operand: + return self.apply("le", self, other) + + def __gt__(self, other: _Operand | float) -> _Operand: + return self.apply("gt", self, other) + + def __ge__(self, other: _Operand | float) -> _Operand: + return self.apply("ge", self, other) + + +# conversions +def imagemath_int(self: _Operand) -> _Operand: + return _Operand(self.im.convert("I")) + + +def imagemath_float(self: _Operand) -> _Operand: + return _Operand(self.im.convert("F")) + + +# logical +def imagemath_equal(self: _Operand, other: _Operand | float | None) -> _Operand: + return self.apply("eq", self, other, mode="I") + + +def imagemath_notequal(self: _Operand, other: _Operand | float | None) -> _Operand: + return self.apply("ne", self, other, mode="I") + + +def imagemath_min(self: _Operand, other: _Operand | float | None) -> _Operand: + return self.apply("min", self, other) + + +def imagemath_max(self: _Operand, other: _Operand | float | None) -> _Operand: + return self.apply("max", self, other) + + +def imagemath_convert(self: _Operand, mode: str) -> _Operand: + return _Operand(self.im.convert(mode)) + + +ops = { + "int": imagemath_int, + "float": imagemath_float, + "equal": imagemath_equal, + "notequal": imagemath_notequal, + "min": imagemath_min, + "max": imagemath_max, + "convert": imagemath_convert, +} + + +def lambda_eval( + expression: Callable[[dict[str, Any]], Any], + options: dict[str, Any] = {}, + **kw: Any, +) -> Any: + """ + Returns the result of an image function. + + :py:mod:`~PIL.ImageMath` only supports single-layer images. To process multi-band + images, use the :py:meth:`~PIL.Image.Image.split` method or + :py:func:`~PIL.Image.merge` function. + + :param expression: A function that receives a dictionary. + :param options: Values to add to the function's dictionary. You + can either use a dictionary, or one or more keyword + arguments. + :return: The expression result. This is usually an image object, but can + also be an integer, a floating point value, or a pixel tuple, + depending on the expression. + """ + + args: dict[str, Any] = ops.copy() + args.update(options) + args.update(kw) + for k, v in args.items(): + if hasattr(v, "im"): + args[k] = _Operand(v) + + out = expression(args) + try: + return out.im + except AttributeError: + return out + + +def unsafe_eval( + expression: str, + options: dict[str, Any] = {}, + **kw: Any, +) -> Any: + """ + Evaluates an image expression. This uses Python's ``eval()`` function to process + the expression string, and carries the security risks of doing so. It is not + recommended to process expressions without considering this. + :py:meth:`~lambda_eval` is a more secure alternative. + + :py:mod:`~PIL.ImageMath` only supports single-layer images. To process multi-band + images, use the :py:meth:`~PIL.Image.Image.split` method or + :py:func:`~PIL.Image.merge` function. + + :param expression: A string containing a Python-style expression. + :param options: Values to add to the evaluation context. You + can either use a dictionary, or one or more keyword + arguments. + :return: The evaluated expression. This is usually an image object, but can + also be an integer, a floating point value, or a pixel tuple, + depending on the expression. + """ + + # build execution namespace + args: dict[str, Any] = ops.copy() + for k in list(options.keys()) + list(kw.keys()): + if "__" in k or hasattr(builtins, k): + msg = f"'{k}' not allowed" + raise ValueError(msg) + + args.update(options) + args.update(kw) + for k, v in args.items(): + if hasattr(v, "im"): + args[k] = _Operand(v) + + compiled_code = compile(expression, "", "eval") + + def scan(code: CodeType) -> None: + for const in code.co_consts: + if type(const) is type(compiled_code): + scan(const) + + for name in code.co_names: + if name not in args and name != "abs": + msg = f"'{name}' not allowed" + raise ValueError(msg) + + scan(compiled_code) + out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args) + try: + return out.im + except AttributeError: + return out + + +def eval( + expression: str, + _dict: dict[str, Any] = {}, + **kw: Any, +) -> Any: + """ + Evaluates an image expression. + + Deprecated. Use lambda_eval() or unsafe_eval() instead. + + :param expression: A string containing a Python-style expression. + :param _dict: Values to add to the evaluation context. You + can either use a dictionary, or one or more keyword + arguments. + :return: The evaluated expression. This is usually an image object, but can + also be an integer, a floating point value, or a pixel tuple, + depending on the expression. + + .. deprecated:: 10.3.0 + """ + + deprecate( + "ImageMath.eval", + 12, + "ImageMath.lambda_eval or ImageMath.unsafe_eval", + ) + return unsafe_eval(expression, _dict, **kw) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageMode.py b/.venv/lib/python3.12/site-packages/PIL/ImageMode.py new file mode 100644 index 0000000..92a08d2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageMode.py @@ -0,0 +1,92 @@ +# +# The Python Imaging Library. +# $Id$ +# +# standard mode descriptors +# +# History: +# 2006-03-20 fl Added +# +# Copyright (c) 2006 by Secret Labs AB. +# Copyright (c) 2006 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import sys +from functools import lru_cache +from typing import NamedTuple + +from ._deprecate import deprecate + + +class ModeDescriptor(NamedTuple): + """Wrapper for mode strings.""" + + mode: str + bands: tuple[str, ...] + basemode: str + basetype: str + typestr: str + + def __str__(self) -> str: + return self.mode + + +@lru_cache +def getmode(mode: str) -> ModeDescriptor: + """Gets a mode descriptor for the given mode.""" + endian = "<" if sys.byteorder == "little" else ">" + + modes = { + # core modes + # Bits need to be extended to bytes + "1": ("L", "L", ("1",), "|b1"), + "L": ("L", "L", ("L",), "|u1"), + "I": ("L", "I", ("I",), f"{endian}i4"), + "F": ("L", "F", ("F",), f"{endian}f4"), + "P": ("P", "L", ("P",), "|u1"), + "RGB": ("RGB", "L", ("R", "G", "B"), "|u1"), + "RGBX": ("RGB", "L", ("R", "G", "B", "X"), "|u1"), + "RGBA": ("RGB", "L", ("R", "G", "B", "A"), "|u1"), + "CMYK": ("RGB", "L", ("C", "M", "Y", "K"), "|u1"), + "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr"), "|u1"), + # UNDONE - unsigned |u1i1i1 + "LAB": ("RGB", "L", ("L", "A", "B"), "|u1"), + "HSV": ("RGB", "L", ("H", "S", "V"), "|u1"), + # extra experimental modes + "RGBa": ("RGB", "L", ("R", "G", "B", "a"), "|u1"), + "BGR;15": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;16": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;24": ("RGB", "L", ("B", "G", "R"), "|u1"), + "LA": ("L", "L", ("L", "A"), "|u1"), + "La": ("L", "L", ("L", "a"), "|u1"), + "PA": ("RGB", "L", ("P", "A"), "|u1"), + } + if mode in modes: + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) + base_mode, base_type, bands, type_str = modes[mode] + return ModeDescriptor(mode, bands, base_mode, base_type, type_str) + + mapping_modes = { + # I;16 == I;16L, and I;32 == I;32L + "I;16": "u2", + "I;16BS": ">i2", + "I;16N": f"{endian}u2", + "I;16NS": f"{endian}i2", + "I;32": "u4", + "I;32L": "i4", + "I;32LS": " +from __future__ import annotations + +import re + +from . import Image, _imagingmorph + +LUT_SIZE = 1 << 9 + +# fmt: off +ROTATION_MATRIX = [ + 6, 3, 0, + 7, 4, 1, + 8, 5, 2, +] +MIRROR_MATRIX = [ + 2, 1, 0, + 5, 4, 3, + 8, 7, 6, +] +# fmt: on + + +class LutBuilder: + """A class for building a MorphLut from a descriptive language + + The input patterns is a list of a strings sequences like these:: + + 4:(... + .1. + 111)->1 + + (whitespaces including linebreaks are ignored). The option 4 + describes a series of symmetry operations (in this case a + 4-rotation), the pattern is described by: + + - . or X - Ignore + - 1 - Pixel is on + - 0 - Pixel is off + + The result of the operation is described after "->" string. + + The default is to return the current pixel value, which is + returned if no other match is found. + + Operations: + + - 4 - 4 way rotation + - N - Negate + - 1 - Dummy op for no other operation (an op must always be given) + - M - Mirroring + + Example:: + + lb = LutBuilder(patterns = ["4:(... .1. 111)->1"]) + lut = lb.build_lut() + + """ + + def __init__( + self, patterns: list[str] | None = None, op_name: str | None = None + ) -> None: + if patterns is not None: + self.patterns = patterns + else: + self.patterns = [] + self.lut: bytearray | None = None + if op_name is not None: + known_patterns = { + "corner": ["1:(... ... ...)->0", "4:(00. 01. ...)->1"], + "dilation4": ["4:(... .0. .1.)->1"], + "dilation8": ["4:(... .0. .1.)->1", "4:(... .0. ..1)->1"], + "erosion4": ["4:(... .1. .0.)->0"], + "erosion8": ["4:(... .1. .0.)->0", "4:(... .1. ..0)->0"], + "edge": [ + "1:(... ... ...)->0", + "4:(.0. .1. ...)->1", + "4:(01. .1. ...)->1", + ], + } + if op_name not in known_patterns: + msg = f"Unknown pattern {op_name}!" + raise Exception(msg) + + self.patterns = known_patterns[op_name] + + def add_patterns(self, patterns: list[str]) -> None: + self.patterns += patterns + + def build_default_lut(self) -> None: + symbols = [0, 1] + m = 1 << 4 # pos of current pixel + self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE)) + + def get_lut(self) -> bytearray | None: + return self.lut + + def _string_permute(self, pattern: str, permutation: list[int]) -> str: + """string_permute takes a pattern and a permutation and returns the + string permuted according to the permutation list. + """ + assert len(permutation) == 9 + return "".join(pattern[p] for p in permutation) + + def _pattern_permute( + self, basic_pattern: str, options: str, basic_result: int + ) -> list[tuple[str, int]]: + """pattern_permute takes a basic pattern and its result and clones + the pattern according to the modifications described in the $options + parameter. It returns a list of all cloned patterns.""" + patterns = [(basic_pattern, basic_result)] + + # rotations + if "4" in options: + res = patterns[-1][1] + for i in range(4): + patterns.append( + (self._string_permute(patterns[-1][0], ROTATION_MATRIX), res) + ) + # mirror + if "M" in options: + n = len(patterns) + for pattern, res in patterns[:n]: + patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res)) + + # negate + if "N" in options: + n = len(patterns) + for pattern, res in patterns[:n]: + # Swap 0 and 1 + pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1") + res = 1 - int(res) + patterns.append((pattern, res)) + + return patterns + + def build_lut(self) -> bytearray: + """Compile all patterns into a morphology lut. + + TBD :Build based on (file) morphlut:modify_lut + """ + self.build_default_lut() + assert self.lut is not None + patterns = [] + + # Parse and create symmetries of the patterns strings + for p in self.patterns: + m = re.search(r"(\w*):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", "")) + if not m: + msg = 'Syntax error in pattern "' + p + '"' + raise Exception(msg) + options = m.group(1) + pattern = m.group(2) + result = int(m.group(3)) + + # Get rid of spaces + pattern = pattern.replace(" ", "").replace("\n", "") + + patterns += self._pattern_permute(pattern, options, result) + + # compile the patterns into regular expressions for speed + compiled_patterns = [] + for pattern in patterns: + p = pattern[0].replace(".", "X").replace("X", "[01]") + compiled_patterns.append((re.compile(p), pattern[1])) + + # Step through table and find patterns that match. + # Note that all the patterns are searched. The last one + # caught overrides + for i in range(LUT_SIZE): + # Build the bit pattern + bitpattern = bin(i)[2:] + bitpattern = ("0" * (9 - len(bitpattern)) + bitpattern)[::-1] + + for pattern, r in compiled_patterns: + if pattern.match(bitpattern): + self.lut[i] = [0, 1][r] + + return self.lut + + +class MorphOp: + """A class for binary morphological operators""" + + def __init__( + self, + lut: bytearray | None = None, + op_name: str | None = None, + patterns: list[str] | None = None, + ) -> None: + """Create a binary morphological operator""" + self.lut = lut + if op_name is not None: + self.lut = LutBuilder(op_name=op_name).build_lut() + elif patterns is not None: + self.lut = LutBuilder(patterns=patterns).build_lut() + + def apply(self, image: Image.Image) -> tuple[int, Image.Image]: + """Run a single morphological operation on an image + + Returns a tuple of the number of changed pixels and the + morphed image""" + if self.lut is None: + msg = "No operator loaded" + raise Exception(msg) + + if image.mode != "L": + msg = "Image mode must be L" + raise ValueError(msg) + outimage = Image.new(image.mode, image.size, None) + count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id) + return count, outimage + + def match(self, image: Image.Image) -> list[tuple[int, int]]: + """Get a list of coordinates matching the morphological operation on + an image. + + Returns a list of tuples of (x,y) coordinates + of all matching pixels. See :ref:`coordinate-system`.""" + if self.lut is None: + msg = "No operator loaded" + raise Exception(msg) + + if image.mode != "L": + msg = "Image mode must be L" + raise ValueError(msg) + return _imagingmorph.match(bytes(self.lut), image.im.id) + + def get_on_pixels(self, image: Image.Image) -> list[tuple[int, int]]: + """Get a list of all turned on pixels in a binary image + + Returns a list of tuples of (x,y) coordinates + of all matching pixels. See :ref:`coordinate-system`.""" + + if image.mode != "L": + msg = "Image mode must be L" + raise ValueError(msg) + return _imagingmorph.get_on_pixels(image.im.id) + + def load_lut(self, filename: str) -> None: + """Load an operator from an mrl file""" + with open(filename, "rb") as f: + self.lut = bytearray(f.read()) + + if len(self.lut) != LUT_SIZE: + self.lut = None + msg = "Wrong size operator file!" + raise Exception(msg) + + def save_lut(self, filename: str) -> None: + """Save an operator to an mrl file""" + if self.lut is None: + msg = "No operator loaded" + raise Exception(msg) + with open(filename, "wb") as f: + f.write(self.lut) + + def set_lut(self, lut: bytearray | None) -> None: + """Set the lut from an external source""" + self.lut = lut diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageOps.py b/.venv/lib/python3.12/site-packages/PIL/ImageOps.py new file mode 100644 index 0000000..a84c083 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageOps.py @@ -0,0 +1,728 @@ +# +# The Python Imaging Library. +# $Id$ +# +# standard image operations +# +# History: +# 2001-10-20 fl Created +# 2001-10-23 fl Added autocontrast operator +# 2001-12-18 fl Added Kevin's fit operator +# 2004-03-14 fl Fixed potential division by zero in equalize +# 2005-05-05 fl Fixed equalize for low number of values +# +# Copyright (c) 2001-2004 by Secret Labs AB +# Copyright (c) 2001-2004 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import functools +import operator +import re +from typing import Protocol, Sequence, cast + +from . import ExifTags, Image, ImagePalette + +# +# helpers + + +def _border(border: int | tuple[int, ...]) -> tuple[int, int, int, int]: + if isinstance(border, tuple): + if len(border) == 2: + left, top = right, bottom = border + elif len(border) == 4: + left, top, right, bottom = border + else: + left = top = right = bottom = border + return left, top, right, bottom + + +def _color(color: str | int | tuple[int, ...], mode: str) -> int | tuple[int, ...]: + if isinstance(color, str): + from . import ImageColor + + color = ImageColor.getcolor(color, mode) + return color + + +def _lut(image: Image.Image, lut: list[int]) -> Image.Image: + if image.mode == "P": + # FIXME: apply to lookup table, not image data + msg = "mode P support coming soon" + raise NotImplementedError(msg) + elif image.mode in ("L", "RGB"): + if image.mode == "RGB" and len(lut) == 256: + lut = lut + lut + lut + return image.point(lut) + else: + msg = f"not supported for mode {image.mode}" + raise OSError(msg) + + +# +# actions + + +def autocontrast( + image: Image.Image, + cutoff: float | tuple[float, float] = 0, + ignore: int | Sequence[int] | None = None, + mask: Image.Image | None = None, + preserve_tone: bool = False, +) -> Image.Image: + """ + Maximize (normalize) image contrast. This function calculates a + histogram of the input image (or mask region), removes ``cutoff`` percent of the + lightest and darkest pixels from the histogram, and remaps the image + so that the darkest pixel becomes black (0), and the lightest + becomes white (255). + + :param image: The image to process. + :param cutoff: The percent to cut off from the histogram on the low and + high ends. Either a tuple of (low, high), or a single + number for both. + :param ignore: The background pixel value (use None for no background). + :param mask: Histogram used in contrast operation is computed using pixels + within the mask. If no mask is given the entire image is used + for histogram computation. + :param preserve_tone: Preserve image tone in Photoshop-like style autocontrast. + + .. versionadded:: 8.2.0 + + :return: An image. + """ + if preserve_tone: + histogram = image.convert("L").histogram(mask) + else: + histogram = image.histogram(mask) + + lut = [] + for layer in range(0, len(histogram), 256): + h = histogram[layer : layer + 256] + if ignore is not None: + # get rid of outliers + if isinstance(ignore, int): + h[ignore] = 0 + else: + for ix in ignore: + h[ix] = 0 + if cutoff: + # cut off pixels from both ends of the histogram + if not isinstance(cutoff, tuple): + cutoff = (cutoff, cutoff) + # get number of pixels + n = 0 + for ix in range(256): + n = n + h[ix] + # remove cutoff% pixels from the low end + cut = int(n * cutoff[0] // 100) + for lo in range(256): + if cut > h[lo]: + cut = cut - h[lo] + h[lo] = 0 + else: + h[lo] -= cut + cut = 0 + if cut <= 0: + break + # remove cutoff% samples from the high end + cut = int(n * cutoff[1] // 100) + for hi in range(255, -1, -1): + if cut > h[hi]: + cut = cut - h[hi] + h[hi] = 0 + else: + h[hi] -= cut + cut = 0 + if cut <= 0: + break + # find lowest/highest samples after preprocessing + for lo in range(256): + if h[lo]: + break + for hi in range(255, -1, -1): + if h[hi]: + break + if hi <= lo: + # don't bother + lut.extend(list(range(256))) + else: + scale = 255.0 / (hi - lo) + offset = -lo * scale + for ix in range(256): + ix = int(ix * scale + offset) + if ix < 0: + ix = 0 + elif ix > 255: + ix = 255 + lut.append(ix) + return _lut(image, lut) + + +def colorize( + image: Image.Image, + black: str | tuple[int, ...], + white: str | tuple[int, ...], + mid: str | int | tuple[int, ...] | None = None, + blackpoint: int = 0, + whitepoint: int = 255, + midpoint: int = 127, +) -> Image.Image: + """ + Colorize grayscale image. + This function calculates a color wedge which maps all black pixels in + the source image to the first color and all white pixels to the + second color. If ``mid`` is specified, it uses three-color mapping. + The ``black`` and ``white`` arguments should be RGB tuples or color names; + optionally you can use three-color mapping by also specifying ``mid``. + Mapping positions for any of the colors can be specified + (e.g. ``blackpoint``), where these parameters are the integer + value corresponding to where the corresponding color should be mapped. + These parameters must have logical order, such that + ``blackpoint <= midpoint <= whitepoint`` (if ``mid`` is specified). + + :param image: The image to colorize. + :param black: The color to use for black input pixels. + :param white: The color to use for white input pixels. + :param mid: The color to use for midtone input pixels. + :param blackpoint: an int value [0, 255] for the black mapping. + :param whitepoint: an int value [0, 255] for the white mapping. + :param midpoint: an int value [0, 255] for the midtone mapping. + :return: An image. + """ + + # Initial asserts + assert image.mode == "L" + if mid is None: + assert 0 <= blackpoint <= whitepoint <= 255 + else: + assert 0 <= blackpoint <= midpoint <= whitepoint <= 255 + + # Define colors from arguments + rgb_black = cast(Sequence[int], _color(black, "RGB")) + rgb_white = cast(Sequence[int], _color(white, "RGB")) + rgb_mid = cast(Sequence[int], _color(mid, "RGB")) if mid is not None else None + + # Empty lists for the mapping + red = [] + green = [] + blue = [] + + # Create the low-end values + for i in range(0, blackpoint): + red.append(rgb_black[0]) + green.append(rgb_black[1]) + blue.append(rgb_black[2]) + + # Create the mapping (2-color) + if rgb_mid is None: + range_map = range(0, whitepoint - blackpoint) + + for i in range_map: + red.append( + rgb_black[0] + i * (rgb_white[0] - rgb_black[0]) // len(range_map) + ) + green.append( + rgb_black[1] + i * (rgb_white[1] - rgb_black[1]) // len(range_map) + ) + blue.append( + rgb_black[2] + i * (rgb_white[2] - rgb_black[2]) // len(range_map) + ) + + # Create the mapping (3-color) + else: + range_map1 = range(0, midpoint - blackpoint) + range_map2 = range(0, whitepoint - midpoint) + + for i in range_map1: + red.append( + rgb_black[0] + i * (rgb_mid[0] - rgb_black[0]) // len(range_map1) + ) + green.append( + rgb_black[1] + i * (rgb_mid[1] - rgb_black[1]) // len(range_map1) + ) + blue.append( + rgb_black[2] + i * (rgb_mid[2] - rgb_black[2]) // len(range_map1) + ) + for i in range_map2: + red.append(rgb_mid[0] + i * (rgb_white[0] - rgb_mid[0]) // len(range_map2)) + green.append( + rgb_mid[1] + i * (rgb_white[1] - rgb_mid[1]) // len(range_map2) + ) + blue.append(rgb_mid[2] + i * (rgb_white[2] - rgb_mid[2]) // len(range_map2)) + + # Create the high-end values + for i in range(0, 256 - whitepoint): + red.append(rgb_white[0]) + green.append(rgb_white[1]) + blue.append(rgb_white[2]) + + # Return converted image + image = image.convert("RGB") + return _lut(image, red + green + blue) + + +def contain( + image: Image.Image, size: tuple[int, int], method: int = Image.Resampling.BICUBIC +) -> Image.Image: + """ + Returns a resized version of the image, set to the maximum width and height + within the requested size, while maintaining the original aspect ratio. + + :param image: The image to resize. + :param size: The requested output size in pixels, given as a + (width, height) tuple. + :param method: Resampling method to use. Default is + :py:attr:`~PIL.Image.Resampling.BICUBIC`. + See :ref:`concept-filters`. + :return: An image. + """ + + im_ratio = image.width / image.height + dest_ratio = size[0] / size[1] + + if im_ratio != dest_ratio: + if im_ratio > dest_ratio: + new_height = round(image.height / image.width * size[0]) + if new_height != size[1]: + size = (size[0], new_height) + else: + new_width = round(image.width / image.height * size[1]) + if new_width != size[0]: + size = (new_width, size[1]) + return image.resize(size, resample=method) + + +def cover( + image: Image.Image, size: tuple[int, int], method: int = Image.Resampling.BICUBIC +) -> Image.Image: + """ + Returns a resized version of the image, so that the requested size is + covered, while maintaining the original aspect ratio. + + :param image: The image to resize. + :param size: The requested output size in pixels, given as a + (width, height) tuple. + :param method: Resampling method to use. Default is + :py:attr:`~PIL.Image.Resampling.BICUBIC`. + See :ref:`concept-filters`. + :return: An image. + """ + + im_ratio = image.width / image.height + dest_ratio = size[0] / size[1] + + if im_ratio != dest_ratio: + if im_ratio < dest_ratio: + new_height = round(image.height / image.width * size[0]) + if new_height != size[1]: + size = (size[0], new_height) + else: + new_width = round(image.width / image.height * size[1]) + if new_width != size[0]: + size = (new_width, size[1]) + return image.resize(size, resample=method) + + +def pad( + image: Image.Image, + size: tuple[int, int], + method: int = Image.Resampling.BICUBIC, + color: str | int | tuple[int, ...] | None = None, + centering: tuple[float, float] = (0.5, 0.5), +) -> Image.Image: + """ + Returns a resized and padded version of the image, expanded to fill the + requested aspect ratio and size. + + :param image: The image to resize and crop. + :param size: The requested output size in pixels, given as a + (width, height) tuple. + :param method: Resampling method to use. Default is + :py:attr:`~PIL.Image.Resampling.BICUBIC`. + See :ref:`concept-filters`. + :param color: The background color of the padded image. + :param centering: Control the position of the original image within the + padded version. + + (0.5, 0.5) will keep the image centered + (0, 0) will keep the image aligned to the top left + (1, 1) will keep the image aligned to the bottom + right + :return: An image. + """ + + resized = contain(image, size, method) + if resized.size == size: + out = resized + else: + out = Image.new(image.mode, size, color) + if resized.palette: + out.putpalette(resized.getpalette()) + if resized.width != size[0]: + x = round((size[0] - resized.width) * max(0, min(centering[0], 1))) + out.paste(resized, (x, 0)) + else: + y = round((size[1] - resized.height) * max(0, min(centering[1], 1))) + out.paste(resized, (0, y)) + return out + + +def crop(image: Image.Image, border: int = 0) -> Image.Image: + """ + Remove border from image. The same amount of pixels are removed + from all four sides. This function works on all image modes. + + .. seealso:: :py:meth:`~PIL.Image.Image.crop` + + :param image: The image to crop. + :param border: The number of pixels to remove. + :return: An image. + """ + left, top, right, bottom = _border(border) + return image.crop((left, top, image.size[0] - right, image.size[1] - bottom)) + + +def scale( + image: Image.Image, factor: float, resample: int = Image.Resampling.BICUBIC +) -> Image.Image: + """ + Returns a rescaled image by a specific factor given in parameter. + A factor greater than 1 expands the image, between 0 and 1 contracts the + image. + + :param image: The image to rescale. + :param factor: The expansion factor, as a float. + :param resample: Resampling method to use. Default is + :py:attr:`~PIL.Image.Resampling.BICUBIC`. + See :ref:`concept-filters`. + :returns: An :py:class:`~PIL.Image.Image` object. + """ + if factor == 1: + return image.copy() + elif factor <= 0: + msg = "the factor must be greater than 0" + raise ValueError(msg) + else: + size = (round(factor * image.width), round(factor * image.height)) + return image.resize(size, resample) + + +class SupportsGetMesh(Protocol): + """ + An object that supports the ``getmesh`` method, taking an image as an + argument, and returning a list of tuples. Each tuple contains two tuples, + the source box as a tuple of 4 integers, and a tuple of 8 integers for the + final quadrilateral, in order of top left, bottom left, bottom right, top + right. + """ + + def getmesh( + self, image: Image.Image + ) -> list[ + tuple[tuple[int, int, int, int], tuple[int, int, int, int, int, int, int, int]] + ]: ... + + +def deform( + image: Image.Image, + deformer: SupportsGetMesh, + resample: int = Image.Resampling.BILINEAR, +) -> Image.Image: + """ + Deform the image. + + :param image: The image to deform. + :param deformer: A deformer object. Any object that implements a + ``getmesh`` method can be used. + :param resample: An optional resampling filter. Same values possible as + in the PIL.Image.transform function. + :return: An image. + """ + return image.transform( + image.size, Image.Transform.MESH, deformer.getmesh(image), resample + ) + + +def equalize(image: Image.Image, mask: Image.Image | None = None) -> Image.Image: + """ + Equalize the image histogram. This function applies a non-linear + mapping to the input image, in order to create a uniform + distribution of grayscale values in the output image. + + :param image: The image to equalize. + :param mask: An optional mask. If given, only the pixels selected by + the mask are included in the analysis. + :return: An image. + """ + if image.mode == "P": + image = image.convert("RGB") + h = image.histogram(mask) + lut = [] + for b in range(0, len(h), 256): + histo = [_f for _f in h[b : b + 256] if _f] + if len(histo) <= 1: + lut.extend(list(range(256))) + else: + step = (functools.reduce(operator.add, histo) - histo[-1]) // 255 + if not step: + lut.extend(list(range(256))) + else: + n = step // 2 + for i in range(256): + lut.append(n // step) + n = n + h[i + b] + return _lut(image, lut) + + +def expand( + image: Image.Image, + border: int | tuple[int, ...] = 0, + fill: str | int | tuple[int, ...] = 0, +) -> Image.Image: + """ + Add border to the image + + :param image: The image to expand. + :param border: Border width, in pixels. + :param fill: Pixel fill value (a color value). Default is 0 (black). + :return: An image. + """ + left, top, right, bottom = _border(border) + width = left + image.size[0] + right + height = top + image.size[1] + bottom + color = _color(fill, image.mode) + if image.palette: + palette = ImagePalette.ImagePalette(palette=image.getpalette()) + if isinstance(color, tuple) and (len(color) == 3 or len(color) == 4): + color = palette.getcolor(color) + else: + palette = None + out = Image.new(image.mode, (width, height), color) + if palette: + out.putpalette(palette.palette) + out.paste(image, (left, top)) + return out + + +def fit( + image: Image.Image, + size: tuple[int, int], + method: int = Image.Resampling.BICUBIC, + bleed: float = 0.0, + centering: tuple[float, float] = (0.5, 0.5), +) -> Image.Image: + """ + Returns a resized and cropped version of the image, cropped to the + requested aspect ratio and size. + + This function was contributed by Kevin Cazabon. + + :param image: The image to resize and crop. + :param size: The requested output size in pixels, given as a + (width, height) tuple. + :param method: Resampling method to use. Default is + :py:attr:`~PIL.Image.Resampling.BICUBIC`. + See :ref:`concept-filters`. + :param bleed: Remove a border around the outside of the image from all + four edges. The value is a decimal percentage (use 0.01 for + one percent). The default value is 0 (no border). + Cannot be greater than or equal to 0.5. + :param centering: Control the cropping position. Use (0.5, 0.5) for + center cropping (e.g. if cropping the width, take 50% off + of the left side, and therefore 50% off the right side). + (0.0, 0.0) will crop from the top left corner (i.e. if + cropping the width, take all of the crop off of the right + side, and if cropping the height, take all of it off the + bottom). (1.0, 0.0) will crop from the bottom left + corner, etc. (i.e. if cropping the width, take all of the + crop off the left side, and if cropping the height take + none from the top, and therefore all off the bottom). + :return: An image. + """ + + # by Kevin Cazabon, Feb 17/2000 + # kevin@cazabon.com + # https://www.cazabon.com + + centering_x, centering_y = centering + + if not 0.0 <= centering_x <= 1.0: + centering_x = 0.5 + if not 0.0 <= centering_y <= 1.0: + centering_y = 0.5 + + if not 0.0 <= bleed < 0.5: + bleed = 0.0 + + # calculate the area to use for resizing and cropping, subtracting + # the 'bleed' around the edges + + # number of pixels to trim off on Top and Bottom, Left and Right + bleed_pixels = (bleed * image.size[0], bleed * image.size[1]) + + live_size = ( + image.size[0] - bleed_pixels[0] * 2, + image.size[1] - bleed_pixels[1] * 2, + ) + + # calculate the aspect ratio of the live_size + live_size_ratio = live_size[0] / live_size[1] + + # calculate the aspect ratio of the output image + output_ratio = size[0] / size[1] + + # figure out if the sides or top/bottom will be cropped off + if live_size_ratio == output_ratio: + # live_size is already the needed ratio + crop_width = live_size[0] + crop_height = live_size[1] + elif live_size_ratio >= output_ratio: + # live_size is wider than what's needed, crop the sides + crop_width = output_ratio * live_size[1] + crop_height = live_size[1] + else: + # live_size is taller than what's needed, crop the top and bottom + crop_width = live_size[0] + crop_height = live_size[0] / output_ratio + + # make the crop + crop_left = bleed_pixels[0] + (live_size[0] - crop_width) * centering_x + crop_top = bleed_pixels[1] + (live_size[1] - crop_height) * centering_y + + crop = (crop_left, crop_top, crop_left + crop_width, crop_top + crop_height) + + # resize the image and return it + return image.resize(size, method, box=crop) + + +def flip(image: Image.Image) -> Image.Image: + """ + Flip the image vertically (top to bottom). + + :param image: The image to flip. + :return: An image. + """ + return image.transpose(Image.Transpose.FLIP_TOP_BOTTOM) + + +def grayscale(image: Image.Image) -> Image.Image: + """ + Convert the image to grayscale. + + :param image: The image to convert. + :return: An image. + """ + return image.convert("L") + + +def invert(image: Image.Image) -> Image.Image: + """ + Invert (negate) the image. + + :param image: The image to invert. + :return: An image. + """ + lut = list(range(255, -1, -1)) + return image.point(lut) if image.mode == "1" else _lut(image, lut) + + +def mirror(image: Image.Image) -> Image.Image: + """ + Flip image horizontally (left to right). + + :param image: The image to mirror. + :return: An image. + """ + return image.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + + +def posterize(image: Image.Image, bits: int) -> Image.Image: + """ + Reduce the number of bits for each color channel. + + :param image: The image to posterize. + :param bits: The number of bits to keep for each channel (1-8). + :return: An image. + """ + mask = ~(2 ** (8 - bits) - 1) + lut = [i & mask for i in range(256)] + return _lut(image, lut) + + +def solarize(image: Image.Image, threshold: int = 128) -> Image.Image: + """ + Invert all pixel values above a threshold. + + :param image: The image to solarize. + :param threshold: All pixels above this grayscale level are inverted. + :return: An image. + """ + lut = [] + for i in range(256): + if i < threshold: + lut.append(i) + else: + lut.append(255 - i) + return _lut(image, lut) + + +def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image | None: + """ + If an image has an EXIF Orientation tag, other than 1, transpose the image + accordingly, and remove the orientation data. + + :param image: The image to transpose. + :param in_place: Boolean. Keyword-only argument. + If ``True``, the original image is modified in-place, and ``None`` is returned. + If ``False`` (default), a new :py:class:`~PIL.Image.Image` object is returned + with the transposition applied. If there is no transposition, a copy of the + image will be returned. + """ + image.load() + image_exif = image.getexif() + orientation = image_exif.get(ExifTags.Base.Orientation, 1) + method = { + 2: Image.Transpose.FLIP_LEFT_RIGHT, + 3: Image.Transpose.ROTATE_180, + 4: Image.Transpose.FLIP_TOP_BOTTOM, + 5: Image.Transpose.TRANSPOSE, + 6: Image.Transpose.ROTATE_270, + 7: Image.Transpose.TRANSVERSE, + 8: Image.Transpose.ROTATE_90, + }.get(orientation) + if method is not None: + transposed_image = image.transpose(method) + if in_place: + image.im = transposed_image.im + image.pyaccess = None + image._size = transposed_image._size + exif_image = image if in_place else transposed_image + + exif = exif_image.getexif() + if ExifTags.Base.Orientation in exif: + del exif[ExifTags.Base.Orientation] + if "exif" in exif_image.info: + exif_image.info["exif"] = exif.tobytes() + elif "Raw profile type exif" in exif_image.info: + exif_image.info["Raw profile type exif"] = exif.tobytes().hex() + for key in ("XML:com.adobe.xmp", "xmp"): + if key in exif_image.info: + for pattern in ( + r'tiff:Orientation="([0-9])"', + r"([0-9])", + ): + value = exif_image.info[key] + exif_image.info[key] = ( + re.sub(pattern, "", value) + if isinstance(value, str) + else re.sub(pattern.encode(), b"", value) + ) + if not in_place: + return transposed_image + elif not in_place: + return image.copy() + return None diff --git a/.venv/lib/python3.12/site-packages/PIL/ImagePalette.py b/.venv/lib/python3.12/site-packages/PIL/ImagePalette.py new file mode 100644 index 0000000..ed38285 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImagePalette.py @@ -0,0 +1,284 @@ +# +# The Python Imaging Library. +# $Id$ +# +# image palette object +# +# History: +# 1996-03-11 fl Rewritten. +# 1997-01-03 fl Up and running. +# 1997-08-23 fl Added load hack +# 2001-04-16 fl Fixed randint shadow bug in random() +# +# Copyright (c) 1997-2001 by Secret Labs AB +# Copyright (c) 1996-1997 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import array +from typing import IO, TYPE_CHECKING, Sequence + +from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile + +if TYPE_CHECKING: + from . import Image + + +class ImagePalette: + """ + Color palette for palette mapped images + + :param mode: The mode to use for the palette. See: + :ref:`concept-modes`. Defaults to "RGB" + :param palette: An optional palette. If given, it must be a bytearray, + an array or a list of ints between 0-255. The list must consist of + all channels for one color followed by the next color (e.g. RGBRGBRGB). + Defaults to an empty palette. + """ + + def __init__( + self, + mode: str = "RGB", + palette: Sequence[int] | bytes | bytearray | None = None, + ) -> None: + self.mode = mode + self.rawmode: str | None = None # if set, palette contains raw data + self.palette = palette or bytearray() + self.dirty: int | None = None + + @property + def palette(self) -> Sequence[int] | bytes | bytearray: + return self._palette + + @palette.setter + def palette(self, palette: Sequence[int] | bytes | bytearray) -> None: + self._colors: dict[tuple[int, ...], int] | None = None + self._palette = palette + + @property + def colors(self) -> dict[tuple[int, ...], int]: + if self._colors is None: + mode_len = len(self.mode) + self._colors = {} + for i in range(0, len(self.palette), mode_len): + color = tuple(self.palette[i : i + mode_len]) + if color in self._colors: + continue + self._colors[color] = i // mode_len + return self._colors + + @colors.setter + def colors(self, colors: dict[tuple[int, ...], int]) -> None: + self._colors = colors + + def copy(self) -> ImagePalette: + new = ImagePalette() + + new.mode = self.mode + new.rawmode = self.rawmode + if self.palette is not None: + new.palette = self.palette[:] + new.dirty = self.dirty + + return new + + def getdata(self) -> tuple[str, Sequence[int] | bytes | bytearray]: + """ + Get palette contents in format suitable for the low-level + ``im.putpalette`` primitive. + + .. warning:: This method is experimental. + """ + if self.rawmode: + return self.rawmode, self.palette + return self.mode, self.tobytes() + + def tobytes(self) -> bytes: + """Convert palette to bytes. + + .. warning:: This method is experimental. + """ + if self.rawmode: + msg = "palette contains raw palette data" + raise ValueError(msg) + if isinstance(self.palette, bytes): + return self.palette + arr = array.array("B", self.palette) + return arr.tobytes() + + # Declare tostring as an alias for tobytes + tostring = tobytes + + def _new_color_index( + self, image: Image.Image | None = None, e: Exception | None = None + ) -> int: + if not isinstance(self.palette, bytearray): + self._palette = bytearray(self.palette) + index = len(self.palette) // 3 + special_colors: tuple[int | tuple[int, ...] | None, ...] = () + if image: + special_colors = ( + image.info.get("background"), + image.info.get("transparency"), + ) + while index in special_colors: + index += 1 + if index >= 256: + if image: + # Search for an unused index + for i, count in reversed(list(enumerate(image.histogram()))): + if count == 0 and i not in special_colors: + index = i + break + if index >= 256: + msg = "cannot allocate more than 256 colors" + raise ValueError(msg) from e + return index + + def getcolor( + self, + color: tuple[int, ...], + image: Image.Image | None = None, + ) -> int: + """Given an rgb tuple, allocate palette entry. + + .. warning:: This method is experimental. + """ + if self.rawmode: + msg = "palette contains raw palette data" + raise ValueError(msg) + if isinstance(color, tuple): + if self.mode == "RGB": + if len(color) == 4: + if color[3] != 255: + msg = "cannot add non-opaque RGBA color to RGB palette" + raise ValueError(msg) + color = color[:3] + elif self.mode == "RGBA": + if len(color) == 3: + color += (255,) + try: + return self.colors[color] + except KeyError as e: + # allocate new color slot + index = self._new_color_index(image, e) + assert isinstance(self._palette, bytearray) + self.colors[color] = index + if index * 3 < len(self.palette): + self._palette = ( + self._palette[: index * 3] + + bytes(color) + + self._palette[index * 3 + 3 :] + ) + else: + self._palette += bytes(color) + self.dirty = 1 + return index + else: + msg = f"unknown color specifier: {repr(color)}" # type: ignore[unreachable] + raise ValueError(msg) + + def save(self, fp: str | IO[str]) -> None: + """Save palette to text file. + + .. warning:: This method is experimental. + """ + if self.rawmode: + msg = "palette contains raw palette data" + raise ValueError(msg) + if isinstance(fp, str): + fp = open(fp, "w") + fp.write("# Palette\n") + fp.write(f"# Mode: {self.mode}\n") + for i in range(256): + fp.write(f"{i}") + for j in range(i * len(self.mode), (i + 1) * len(self.mode)): + try: + fp.write(f" {self.palette[j]}") + except IndexError: + fp.write(" 0") + fp.write("\n") + fp.close() + + +# -------------------------------------------------------------------- +# Internal + + +def raw(rawmode, data: Sequence[int] | bytes | bytearray) -> ImagePalette: + palette = ImagePalette() + palette.rawmode = rawmode + palette.palette = data + palette.dirty = 1 + return palette + + +# -------------------------------------------------------------------- +# Factories + + +def make_linear_lut(black: int, white: float) -> list[int]: + if black == 0: + return [int(white * i // 255) for i in range(256)] + + msg = "unavailable when black is non-zero" + raise NotImplementedError(msg) # FIXME + + +def make_gamma_lut(exp: float) -> list[int]: + return [int(((i / 255.0) ** exp) * 255.0 + 0.5) for i in range(256)] + + +def negative(mode: str = "RGB") -> ImagePalette: + palette = list(range(256 * len(mode))) + palette.reverse() + return ImagePalette(mode, [i // len(mode) for i in palette]) + + +def random(mode: str = "RGB") -> ImagePalette: + from random import randint + + palette = [randint(0, 255) for _ in range(256 * len(mode))] + return ImagePalette(mode, palette) + + +def sepia(white: str = "#fff0c0") -> ImagePalette: + bands = [make_linear_lut(0, band) for band in ImageColor.getrgb(white)] + return ImagePalette("RGB", [bands[i % 3][i // 3] for i in range(256 * 3)]) + + +def wedge(mode: str = "RGB") -> ImagePalette: + palette = list(range(256 * len(mode))) + return ImagePalette(mode, [i // len(mode) for i in palette]) + + +def load(filename: str) -> tuple[bytes, str]: + # FIXME: supports GIMP gradients only + + with open(filename, "rb") as fp: + paletteHandlers: list[ + type[ + GimpPaletteFile.GimpPaletteFile + | GimpGradientFile.GimpGradientFile + | PaletteFile.PaletteFile + ] + ] = [ + GimpPaletteFile.GimpPaletteFile, + GimpGradientFile.GimpGradientFile, + PaletteFile.PaletteFile, + ] + for paletteHandler in paletteHandlers: + try: + fp.seek(0) + lut = paletteHandler(fp).getpalette() + if lut: + break + except (SyntaxError, ValueError): + pass + else: + msg = "cannot load palette" + raise OSError(msg) + + return lut # data, rawmode diff --git a/.venv/lib/python3.12/site-packages/PIL/ImagePath.py b/.venv/lib/python3.12/site-packages/PIL/ImagePath.py new file mode 100644 index 0000000..77e8a60 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImagePath.py @@ -0,0 +1,20 @@ +# +# The Python Imaging Library +# $Id$ +# +# path interface +# +# History: +# 1996-11-04 fl Created +# 2002-04-14 fl Added documentation stub class +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image + +Path = Image.core.path diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageQt.py b/.venv/lib/python3.12/site-packages/PIL/ImageQt.py new file mode 100644 index 0000000..35a3776 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageQt.py @@ -0,0 +1,205 @@ +# +# The Python Imaging Library. +# $Id$ +# +# a simple Qt image interface. +# +# history: +# 2006-06-03 fl: created +# 2006-06-04 fl: inherit from QImage instead of wrapping it +# 2006-06-05 fl: removed toimage helper; move string support to ImageQt +# 2013-11-13 fl: add support for Qt5 (aurelien.ballier@cyclonit.com) +# +# Copyright (c) 2006 by Secret Labs AB +# Copyright (c) 2006 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import sys +from io import BytesIO +from typing import Callable + +from . import Image +from ._util import is_path + +qt_version: str | None +qt_versions = [ + ["6", "PyQt6"], + ["side6", "PySide6"], +] + +# If a version has already been imported, attempt it first +qt_versions.sort(key=lambda version: version[1] in sys.modules, reverse=True) +for version, qt_module in qt_versions: + try: + QBuffer: type + QIODevice: type + QImage: type + QPixmap: type + qRgba: Callable[[int, int, int, int], int] + if qt_module == "PyQt6": + from PyQt6.QtCore import QBuffer, QIODevice + from PyQt6.QtGui import QImage, QPixmap, qRgba + elif qt_module == "PySide6": + from PySide6.QtCore import QBuffer, QIODevice + from PySide6.QtGui import QImage, QPixmap, qRgba + except (ImportError, RuntimeError): + continue + qt_is_installed = True + qt_version = version + break +else: + qt_is_installed = False + qt_version = None + + +def rgb(r, g, b, a=255): + """(Internal) Turns an RGB color into a Qt compatible color integer.""" + # use qRgb to pack the colors, and then turn the resulting long + # into a negative integer with the same bitpattern. + return qRgba(r, g, b, a) & 0xFFFFFFFF + + +def fromqimage(im): + """ + :param im: QImage or PIL ImageQt object + """ + buffer = QBuffer() + if qt_version == "6": + try: + qt_openmode = QIODevice.OpenModeFlag + except AttributeError: + qt_openmode = QIODevice.OpenMode + else: + qt_openmode = QIODevice + buffer.open(qt_openmode.ReadWrite) + # preserve alpha channel with png + # otherwise ppm is more friendly with Image.open + if im.hasAlphaChannel(): + im.save(buffer, "png") + else: + im.save(buffer, "ppm") + + b = BytesIO() + b.write(buffer.data()) + buffer.close() + b.seek(0) + + return Image.open(b) + + +def fromqpixmap(im): + return fromqimage(im) + + +def align8to32(bytes, width, mode): + """ + converts each scanline of data from 8 bit to 32 bit aligned + """ + + bits_per_pixel = {"1": 1, "L": 8, "P": 8, "I;16": 16}[mode] + + # calculate bytes per line and the extra padding if needed + bits_per_line = bits_per_pixel * width + full_bytes_per_line, remaining_bits_per_line = divmod(bits_per_line, 8) + bytes_per_line = full_bytes_per_line + (1 if remaining_bits_per_line else 0) + + extra_padding = -bytes_per_line % 4 + + # already 32 bit aligned by luck + if not extra_padding: + return bytes + + new_data = [ + bytes[i * bytes_per_line : (i + 1) * bytes_per_line] + b"\x00" * extra_padding + for i in range(len(bytes) // bytes_per_line) + ] + + return b"".join(new_data) + + +def _toqclass_helper(im): + data = None + colortable = None + exclusive_fp = False + + # handle filename, if given instead of image name + if hasattr(im, "toUtf8"): + # FIXME - is this really the best way to do this? + im = str(im.toUtf8(), "utf-8") + if is_path(im): + im = Image.open(im) + exclusive_fp = True + + qt_format = QImage.Format if qt_version == "6" else QImage + if im.mode == "1": + format = qt_format.Format_Mono + elif im.mode == "L": + format = qt_format.Format_Indexed8 + colortable = [rgb(i, i, i) for i in range(256)] + elif im.mode == "P": + format = qt_format.Format_Indexed8 + palette = im.getpalette() + colortable = [rgb(*palette[i : i + 3]) for i in range(0, len(palette), 3)] + elif im.mode == "RGB": + # Populate the 4th channel with 255 + im = im.convert("RGBA") + + data = im.tobytes("raw", "BGRA") + format = qt_format.Format_RGB32 + elif im.mode == "RGBA": + data = im.tobytes("raw", "BGRA") + format = qt_format.Format_ARGB32 + elif im.mode == "I;16": + im = im.point(lambda i: i * 256) + + format = qt_format.Format_Grayscale16 + else: + if exclusive_fp: + im.close() + msg = f"unsupported image mode {repr(im.mode)}" + raise ValueError(msg) + + size = im.size + __data = data or align8to32(im.tobytes(), size[0], im.mode) + if exclusive_fp: + im.close() + return {"data": __data, "size": size, "format": format, "colortable": colortable} + + +if qt_is_installed: + + class ImageQt(QImage): + def __init__(self, im): + """ + An PIL image wrapper for Qt. This is a subclass of PyQt's QImage + class. + + :param im: A PIL Image object, or a file name (given either as + Python string or a PyQt string object). + """ + im_data = _toqclass_helper(im) + # must keep a reference, or Qt will crash! + # All QImage constructors that take data operate on an existing + # buffer, so this buffer has to hang on for the life of the image. + # Fixes https://github.com/python-pillow/Pillow/issues/1370 + self.__data = im_data["data"] + super().__init__( + self.__data, + im_data["size"][0], + im_data["size"][1], + im_data["format"], + ) + if im_data["colortable"]: + self.setColorTable(im_data["colortable"]) + + +def toqimage(im) -> ImageQt: + return ImageQt(im) + + +def toqpixmap(im): + qimage = toqimage(im) + return QPixmap.fromImage(qimage) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageSequence.py b/.venv/lib/python3.12/site-packages/PIL/ImageSequence.py new file mode 100644 index 0000000..2c18502 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageSequence.py @@ -0,0 +1,86 @@ +# +# The Python Imaging Library. +# $Id$ +# +# sequence support classes +# +# history: +# 1997-02-20 fl Created +# +# Copyright (c) 1997 by Secret Labs AB. +# Copyright (c) 1997 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + +## +from __future__ import annotations + +from typing import Callable + +from . import Image + + +class Iterator: + """ + This class implements an iterator object that can be used to loop + over an image sequence. + + You can use the ``[]`` operator to access elements by index. This operator + will raise an :py:exc:`IndexError` if you try to access a nonexistent + frame. + + :param im: An image object. + """ + + def __init__(self, im: Image.Image): + if not hasattr(im, "seek"): + msg = "im must have seek method" + raise AttributeError(msg) + self.im = im + self.position = getattr(self.im, "_min_frame", 0) + + def __getitem__(self, ix: int) -> Image.Image: + try: + self.im.seek(ix) + return self.im + except EOFError as e: + msg = "end of sequence" + raise IndexError(msg) from e + + def __iter__(self) -> Iterator: + return self + + def __next__(self) -> Image.Image: + try: + self.im.seek(self.position) + self.position += 1 + return self.im + except EOFError as e: + msg = "end of sequence" + raise StopIteration(msg) from e + + +def all_frames( + im: Image.Image | list[Image.Image], + func: Callable[[Image.Image], Image.Image] | None = None, +) -> list[Image.Image]: + """ + Applies a given function to all frames in an image or a list of images. + The frames are returned as a list of separate images. + + :param im: An image, or a list of images. + :param func: The function to apply to all of the image frames. + :returns: A list of images. + """ + if not isinstance(im, list): + im = [im] + + ims = [] + for imSequence in im: + current = imSequence.tell() + + ims += [im_frame.copy() for im_frame in Iterator(imSequence)] + + imSequence.seek(current) + return [func(im) for im in ims] if func else ims diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageShow.py b/.venv/lib/python3.12/site-packages/PIL/ImageShow.py new file mode 100644 index 0000000..037d6f4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageShow.py @@ -0,0 +1,363 @@ +# +# The Python Imaging Library. +# $Id$ +# +# im.show() drivers +# +# History: +# 2008-04-06 fl Created +# +# Copyright (c) Secret Labs AB 2008. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import abc +import os +import shutil +import subprocess +import sys +from shlex import quote +from typing import Any + +from . import Image + +_viewers = [] + + +def register(viewer, order: int = 1) -> None: + """ + The :py:func:`register` function is used to register additional viewers:: + + from PIL import ImageShow + ImageShow.register(MyViewer()) # MyViewer will be used as a last resort + ImageShow.register(MySecondViewer(), 0) # MySecondViewer will be prioritised + ImageShow.register(ImageShow.XVViewer(), 0) # XVViewer will be prioritised + + :param viewer: The viewer to be registered. + :param order: + Zero or a negative integer to prepend this viewer to the list, + a positive integer to append it. + """ + try: + if issubclass(viewer, Viewer): + viewer = viewer() + except TypeError: + pass # raised if viewer wasn't a class + if order > 0: + _viewers.append(viewer) + else: + _viewers.insert(0, viewer) + + +def show(image: Image.Image, title: str | None = None, **options: Any) -> bool: + r""" + Display a given image. + + :param image: An image object. + :param title: Optional title. Not all viewers can display the title. + :param \**options: Additional viewer options. + :returns: ``True`` if a suitable viewer was found, ``False`` otherwise. + """ + for viewer in _viewers: + if viewer.show(image, title=title, **options): + return True + return False + + +class Viewer: + """Base class for viewers.""" + + # main api + + def show(self, image: Image.Image, **options: Any) -> int: + """ + The main function for displaying an image. + Converts the given image to the target format and displays it. + """ + + if not ( + image.mode in ("1", "RGBA") + or (self.format == "PNG" and image.mode in ("I;16", "LA")) + ): + base = Image.getmodebase(image.mode) + if image.mode != base: + image = image.convert(base) + + return self.show_image(image, **options) + + # hook methods + + format: str | None = None + """The format to convert the image into.""" + options: dict[str, Any] = {} + """Additional options used to convert the image.""" + + def get_format(self, image: Image.Image) -> str | None: + """Return format name, or ``None`` to save as PGM/PPM.""" + return self.format + + def get_command(self, file: str, **options: Any) -> str: + """ + Returns the command used to display the file. + Not implemented in the base class. + """ + msg = "unavailable in base viewer" + raise NotImplementedError(msg) + + def save_image(self, image: Image.Image) -> str: + """Save to temporary file and return filename.""" + return image._dump(format=self.get_format(image), **self.options) + + def show_image(self, image: Image.Image, **options: Any) -> int: + """Display the given image.""" + return self.show_file(self.save_image(image), **options) + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + os.system(self.get_command(path, **options)) # nosec + return 1 + + +# -------------------------------------------------------------------- + + +class WindowsViewer(Viewer): + """The default viewer on Windows is the default system application for PNG files.""" + + format = "PNG" + options = {"compress_level": 1, "save_all": True} + + def get_command(self, file: str, **options: Any) -> str: + return ( + f'start "Pillow" /WAIT "{file}" ' + "&& ping -n 4 127.0.0.1 >NUL " + f'&& del /f "{file}"' + ) + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + subprocess.Popen( + self.get_command(path, **options), + shell=True, + creationflags=getattr(subprocess, "CREATE_NO_WINDOW"), + ) # nosec + return 1 + + +if sys.platform == "win32": + register(WindowsViewer) + + +class MacViewer(Viewer): + """The default viewer on macOS using ``Preview.app``.""" + + format = "PNG" + options = {"compress_level": 1, "save_all": True} + + def get_command(self, file: str, **options: Any) -> str: + # on darwin open returns immediately resulting in the temp + # file removal while app is opening + command = "open -a Preview.app" + command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&" + return command + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + subprocess.call(["open", "-a", "Preview.app", path]) + executable = sys.executable or shutil.which("python3") + if executable: + subprocess.Popen( + [ + executable, + "-c", + "import os, sys, time; time.sleep(20); os.remove(sys.argv[1])", + path, + ] + ) + return 1 + + +if sys.platform == "darwin": + register(MacViewer) + + +class UnixViewer(Viewer): + format = "PNG" + options = {"compress_level": 1, "save_all": True} + + @abc.abstractmethod + def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]: + pass + + def get_command(self, file: str, **options: Any) -> str: + command = self.get_command_ex(file, **options)[0] + return f"{command} {quote(file)}" + + +class XDGViewer(UnixViewer): + """ + The freedesktop.org ``xdg-open`` command. + """ + + def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]: + command = executable = "xdg-open" + return command, executable + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + subprocess.Popen(["xdg-open", path]) + return 1 + + +class DisplayViewer(UnixViewer): + """ + The ImageMagick ``display`` command. + This viewer supports the ``title`` parameter. + """ + + def get_command_ex( + self, file: str, title: str | None = None, **options: Any + ) -> tuple[str, str]: + command = executable = "display" + if title: + command += f" -title {quote(title)}" + return command, executable + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + args = ["display"] + title = options.get("title") + if title: + args += ["-title", title] + args.append(path) + + subprocess.Popen(args) + return 1 + + +class GmDisplayViewer(UnixViewer): + """The GraphicsMagick ``gm display`` command.""" + + def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]: + executable = "gm" + command = "gm display" + return command, executable + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + subprocess.Popen(["gm", "display", path]) + return 1 + + +class EogViewer(UnixViewer): + """The GNOME Image Viewer ``eog`` command.""" + + def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]: + executable = "eog" + command = "eog -n" + return command, executable + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + subprocess.Popen(["eog", "-n", path]) + return 1 + + +class XVViewer(UnixViewer): + """ + The X Viewer ``xv`` command. + This viewer supports the ``title`` parameter. + """ + + def get_command_ex( + self, file: str, title: str | None = None, **options: Any + ) -> tuple[str, str]: + # note: xv is pretty outdated. most modern systems have + # imagemagick's display command instead. + command = executable = "xv" + if title: + command += f" -name {quote(title)}" + return command, executable + + def show_file(self, path: str, **options: Any) -> int: + """ + Display given file. + """ + if not os.path.exists(path): + raise FileNotFoundError + args = ["xv"] + title = options.get("title") + if title: + args += ["-name", title] + args.append(path) + + subprocess.Popen(args) + return 1 + + +if sys.platform not in ("win32", "darwin"): # unixoids + if shutil.which("xdg-open"): + register(XDGViewer) + if shutil.which("display"): + register(DisplayViewer) + if shutil.which("gm"): + register(GmDisplayViewer) + if shutil.which("eog"): + register(EogViewer) + if shutil.which("xv"): + register(XVViewer) + + +class IPythonViewer(Viewer): + """The viewer for IPython frontends.""" + + def show_image(self, image: Image.Image, **options: Any) -> int: + ipython_display(image) + return 1 + + +try: + from IPython.display import display as ipython_display +except ImportError: + pass +else: + register(IPythonViewer) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Syntax: python3 ImageShow.py imagefile [title]") + sys.exit() + + with Image.open(sys.argv[1]) as im: + print(show(im, *sys.argv[2:])) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageStat.py b/.venv/lib/python3.12/site-packages/PIL/ImageStat.py new file mode 100644 index 0000000..8bc5045 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageStat.py @@ -0,0 +1,160 @@ +# +# The Python Imaging Library. +# $Id$ +# +# global image statistics +# +# History: +# 1996-04-05 fl Created +# 1997-05-21 fl Added mask; added rms, var, stddev attributes +# 1997-08-05 fl Added median +# 1998-07-05 hk Fixed integer overflow error +# +# Notes: +# This class shows how to implement delayed evaluation of attributes. +# To get a certain value, simply access the corresponding attribute. +# The __getattr__ dispatcher takes care of the rest. +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996-97. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import math +from functools import cached_property + +from . import Image + + +class Stat: + def __init__( + self, image_or_list: Image.Image | list[int], mask: Image.Image | None = None + ) -> None: + """ + Calculate statistics for the given image. If a mask is included, + only the regions covered by that mask are included in the + statistics. You can also pass in a previously calculated histogram. + + :param image: A PIL image, or a precalculated histogram. + + .. note:: + + For a PIL image, calculations rely on the + :py:meth:`~PIL.Image.Image.histogram` method. The pixel counts are + grouped into 256 bins, even if the image has more than 8 bits per + channel. So ``I`` and ``F`` mode images have a maximum ``mean``, + ``median`` and ``rms`` of 255, and cannot have an ``extrema`` maximum + of more than 255. + + :param mask: An optional mask. + """ + if isinstance(image_or_list, Image.Image): + self.h = image_or_list.histogram(mask) + elif isinstance(image_or_list, list): + self.h = image_or_list + else: + msg = "first argument must be image or list" # type: ignore[unreachable] + raise TypeError(msg) + self.bands = list(range(len(self.h) // 256)) + + @cached_property + def extrema(self) -> list[tuple[int, int]]: + """ + Min/max values for each band in the image. + + .. note:: + This relies on the :py:meth:`~PIL.Image.Image.histogram` method, and + simply returns the low and high bins used. This is correct for + images with 8 bits per channel, but fails for other modes such as + ``I`` or ``F``. Instead, use :py:meth:`~PIL.Image.Image.getextrema` to + return per-band extrema for the image. This is more correct and + efficient because, for non-8-bit modes, the histogram method uses + :py:meth:`~PIL.Image.Image.getextrema` to determine the bins used. + """ + + def minmax(histogram: list[int]) -> tuple[int, int]: + res_min, res_max = 255, 0 + for i in range(256): + if histogram[i]: + res_min = i + break + for i in range(255, -1, -1): + if histogram[i]: + res_max = i + break + return res_min, res_max + + return [minmax(self.h[i:]) for i in range(0, len(self.h), 256)] + + @cached_property + def count(self) -> list[int]: + """Total number of pixels for each band in the image.""" + return [sum(self.h[i : i + 256]) for i in range(0, len(self.h), 256)] + + @cached_property + def sum(self) -> list[float]: + """Sum of all pixels for each band in the image.""" + + v = [] + for i in range(0, len(self.h), 256): + layer_sum = 0.0 + for j in range(256): + layer_sum += j * self.h[i + j] + v.append(layer_sum) + return v + + @cached_property + def sum2(self) -> list[float]: + """Squared sum of all pixels for each band in the image.""" + + v = [] + for i in range(0, len(self.h), 256): + sum2 = 0.0 + for j in range(256): + sum2 += (j**2) * float(self.h[i + j]) + v.append(sum2) + return v + + @cached_property + def mean(self) -> list[float]: + """Average (arithmetic mean) pixel level for each band in the image.""" + return [self.sum[i] / self.count[i] for i in self.bands] + + @cached_property + def median(self) -> list[int]: + """Median pixel level for each band in the image.""" + + v = [] + for i in self.bands: + s = 0 + half = self.count[i] // 2 + b = i * 256 + for j in range(256): + s = s + self.h[b + j] + if s > half: + break + v.append(j) + return v + + @cached_property + def rms(self) -> list[float]: + """RMS (root-mean-square) for each band in the image.""" + return [math.sqrt(self.sum2[i] / self.count[i]) for i in self.bands] + + @cached_property + def var(self) -> list[float]: + """Variance for each band in the image.""" + return [ + (self.sum2[i] - (self.sum[i] ** 2.0) / self.count[i]) / self.count[i] + for i in self.bands + ] + + @cached_property + def stddev(self) -> list[float]: + """Standard deviation for each band in the image.""" + return [math.sqrt(self.var[i]) for i in self.bands] + + +Global = Stat # compatibility diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageTk.py b/.venv/lib/python3.12/site-packages/PIL/ImageTk.py new file mode 100644 index 0000000..90defdb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageTk.py @@ -0,0 +1,284 @@ +# +# The Python Imaging Library. +# $Id$ +# +# a Tk display interface +# +# History: +# 96-04-08 fl Created +# 96-09-06 fl Added getimage method +# 96-11-01 fl Rewritten, removed image attribute and crop method +# 97-05-09 fl Use PyImagingPaste method instead of image type +# 97-05-12 fl Minor tweaks to match the IFUNC95 interface +# 97-05-17 fl Support the "pilbitmap" booster patch +# 97-06-05 fl Added file= and data= argument to image constructors +# 98-03-09 fl Added width and height methods to Image classes +# 98-07-02 fl Use default mode for "P" images without palette attribute +# 98-07-02 fl Explicitly destroy Tkinter image objects +# 99-07-24 fl Support multiple Tk interpreters (from Greg Couch) +# 99-07-26 fl Automatically hook into Tkinter (if possible) +# 99-08-15 fl Hook uses _imagingtk instead of _imaging +# +# Copyright (c) 1997-1999 by Secret Labs AB +# Copyright (c) 1996-1997 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import tkinter +from io import BytesIO + +from . import Image + +# -------------------------------------------------------------------- +# Check for Tkinter interface hooks + +_pilbitmap_ok = None + + +def _pilbitmap_check() -> int: + global _pilbitmap_ok + if _pilbitmap_ok is None: + try: + im = Image.new("1", (1, 1)) + tkinter.BitmapImage(data=f"PIL:{im.im.id}") + _pilbitmap_ok = 1 + except tkinter.TclError: + _pilbitmap_ok = 0 + return _pilbitmap_ok + + +def _get_image_from_kw(kw): + source = None + if "file" in kw: + source = kw.pop("file") + elif "data" in kw: + source = BytesIO(kw.pop("data")) + if source: + return Image.open(source) + + +def _pyimagingtkcall(command, photo, id): + tk = photo.tk + try: + tk.call(command, photo, id) + except tkinter.TclError: + # activate Tkinter hook + # may raise an error if it cannot attach to Tkinter + from . import _imagingtk + + _imagingtk.tkinit(tk.interpaddr()) + tk.call(command, photo, id) + + +# -------------------------------------------------------------------- +# PhotoImage + + +class PhotoImage: + """ + A Tkinter-compatible photo image. This can be used + everywhere Tkinter expects an image object. If the image is an RGBA + image, pixels having alpha 0 are treated as transparent. + + The constructor takes either a PIL image, or a mode and a size. + Alternatively, you can use the ``file`` or ``data`` options to initialize + the photo image object. + + :param image: Either a PIL image, or a mode string. If a mode string is + used, a size must also be given. + :param size: If the first argument is a mode string, this defines the size + of the image. + :keyword file: A filename to load the image from (using + ``Image.open(file)``). + :keyword data: An 8-bit string containing image data (as loaded from an + image file). + """ + + def __init__(self, image=None, size=None, **kw): + # Tk compatibility: file or data + if image is None: + image = _get_image_from_kw(kw) + + if hasattr(image, "mode") and hasattr(image, "size"): + # got an image instead of a mode + mode = image.mode + if mode == "P": + # palette mapped data + image.apply_transparency() + image.load() + try: + mode = image.palette.mode + except AttributeError: + mode = "RGB" # default + size = image.size + kw["width"], kw["height"] = size + else: + mode = image + image = None + + if mode not in ["1", "L", "RGB", "RGBA"]: + mode = Image.getmodebase(mode) + + self.__mode = mode + self.__size = size + self.__photo = tkinter.PhotoImage(**kw) + self.tk = self.__photo.tk + if image: + self.paste(image) + + def __del__(self) -> None: + name = self.__photo.name + self.__photo.name = None + try: + self.__photo.tk.call("image", "delete", name) + except Exception: + pass # ignore internal errors + + def __str__(self) -> str: + """ + Get the Tkinter photo image identifier. This method is automatically + called by Tkinter whenever a PhotoImage object is passed to a Tkinter + method. + + :return: A Tkinter photo image identifier (a string). + """ + return str(self.__photo) + + def width(self) -> int: + """ + Get the width of the image. + + :return: The width, in pixels. + """ + return self.__size[0] + + def height(self) -> int: + """ + Get the height of the image. + + :return: The height, in pixels. + """ + return self.__size[1] + + def paste(self, im: Image.Image) -> None: + """ + Paste a PIL image into the photo image. Note that this can + be very slow if the photo image is displayed. + + :param im: A PIL image. The size must match the target region. If the + mode does not match, the image is converted to the mode of + the bitmap image. + """ + # convert to blittable + im.load() + image = im.im + if image.isblock() and im.mode == self.__mode: + block = image + else: + block = image.new_block(self.__mode, im.size) + image.convert2(block, image) # convert directly between buffers + + _pyimagingtkcall("PyImagingPhoto", self.__photo, block.id) + + +# -------------------------------------------------------------------- +# BitmapImage + + +class BitmapImage: + """ + A Tkinter-compatible bitmap image. This can be used everywhere Tkinter + expects an image object. + + The given image must have mode "1". Pixels having value 0 are treated as + transparent. Options, if any, are passed on to Tkinter. The most commonly + used option is ``foreground``, which is used to specify the color for the + non-transparent parts. See the Tkinter documentation for information on + how to specify colours. + + :param image: A PIL image. + """ + + def __init__(self, image=None, **kw): + # Tk compatibility: file or data + if image is None: + image = _get_image_from_kw(kw) + + self.__mode = image.mode + self.__size = image.size + + if _pilbitmap_check(): + # fast way (requires the pilbitmap booster patch) + image.load() + kw["data"] = f"PIL:{image.im.id}" + self.__im = image # must keep a reference + else: + # slow but safe way + kw["data"] = image.tobitmap() + self.__photo = tkinter.BitmapImage(**kw) + + def __del__(self) -> None: + name = self.__photo.name + self.__photo.name = None + try: + self.__photo.tk.call("image", "delete", name) + except Exception: + pass # ignore internal errors + + def width(self) -> int: + """ + Get the width of the image. + + :return: The width, in pixels. + """ + return self.__size[0] + + def height(self) -> int: + """ + Get the height of the image. + + :return: The height, in pixels. + """ + return self.__size[1] + + def __str__(self) -> str: + """ + Get the Tkinter bitmap image identifier. This method is automatically + called by Tkinter whenever a BitmapImage object is passed to a Tkinter + method. + + :return: A Tkinter bitmap image identifier (a string). + """ + return str(self.__photo) + + +def getimage(photo: PhotoImage) -> Image.Image: + """Copies the contents of a PhotoImage to a PIL image memory.""" + im = Image.new("RGBA", (photo.width(), photo.height())) + block = im.im + + _pyimagingtkcall("PyImagingPhotoGet", photo, block.id) + + return im + + +def _show(image, title): + """Helper for the Image.show method.""" + + class UI(tkinter.Label): + def __init__(self, master, im): + if im.mode == "1": + self.image = BitmapImage(im, foreground="white", master=master) + else: + self.image = PhotoImage(im, master=master) + super().__init__(master, image=self.image, bg="black", bd=0) + + if not tkinter._default_root: + msg = "tkinter not initialized" + raise OSError(msg) + top = tkinter.Toplevel() + if title: + top.title(title) + UI(top, image).pack() diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageTransform.py b/.venv/lib/python3.12/site-packages/PIL/ImageTransform.py new file mode 100644 index 0000000..ffd7916 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageTransform.py @@ -0,0 +1,135 @@ +# +# The Python Imaging Library. +# $Id$ +# +# transform wrappers +# +# History: +# 2002-04-08 fl Created +# +# Copyright (c) 2002 by Secret Labs AB +# Copyright (c) 2002 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from typing import Any, Sequence + +from . import Image + + +class Transform(Image.ImageTransformHandler): + """Base class for other transforms defined in :py:mod:`~PIL.ImageTransform`.""" + + method: Image.Transform + + def __init__(self, data: Sequence[Any]) -> None: + self.data = data + + def getdata(self) -> tuple[Image.Transform, Sequence[int]]: + return self.method, self.data + + def transform( + self, + size: tuple[int, int], + image: Image.Image, + **options: Any, + ) -> Image.Image: + """Perform the transform. Called from :py:meth:`.Image.transform`.""" + # can be overridden + method, data = self.getdata() + return image.transform(size, method, data, **options) + + +class AffineTransform(Transform): + """ + Define an affine image transform. + + This function takes a 6-tuple (a, b, c, d, e, f) which contain the first + two rows from an affine transform matrix. For each pixel (x, y) in the + output image, the new value is taken from a position (a x + b y + c, + d x + e y + f) in the input image, rounded to nearest pixel. + + This function can be used to scale, translate, rotate, and shear the + original image. + + See :py:meth:`.Image.transform` + + :param matrix: A 6-tuple (a, b, c, d, e, f) containing the first two rows + from an affine transform matrix. + """ + + method = Image.Transform.AFFINE + + +class PerspectiveTransform(Transform): + """ + Define a perspective image transform. + + This function takes an 8-tuple (a, b, c, d, e, f, g, h). For each pixel + (x, y) in the output image, the new value is taken from a position + ((a x + b y + c) / (g x + h y + 1), (d x + e y + f) / (g x + h y + 1)) in + the input image, rounded to nearest pixel. + + This function can be used to scale, translate, rotate, and shear the + original image. + + See :py:meth:`.Image.transform` + + :param matrix: An 8-tuple (a, b, c, d, e, f, g, h). + """ + + method = Image.Transform.PERSPECTIVE + + +class ExtentTransform(Transform): + """ + Define a transform to extract a subregion from an image. + + Maps a rectangle (defined by two corners) from the image to a rectangle of + the given size. The resulting image will contain data sampled from between + the corners, such that (x0, y0) in the input image will end up at (0,0) in + the output image, and (x1, y1) at size. + + This method can be used to crop, stretch, shrink, or mirror an arbitrary + rectangle in the current image. It is slightly slower than crop, but about + as fast as a corresponding resize operation. + + See :py:meth:`.Image.transform` + + :param bbox: A 4-tuple (x0, y0, x1, y1) which specifies two points in the + input image's coordinate system. See :ref:`coordinate-system`. + """ + + method = Image.Transform.EXTENT + + +class QuadTransform(Transform): + """ + Define a quad image transform. + + Maps a quadrilateral (a region defined by four corners) from the image to a + rectangle of the given size. + + See :py:meth:`.Image.transform` + + :param xy: An 8-tuple (x0, y0, x1, y1, x2, y2, x3, y3) which contain the + upper left, lower left, lower right, and upper right corner of the + source quadrilateral. + """ + + method = Image.Transform.QUAD + + +class MeshTransform(Transform): + """ + Define a mesh image transform. A mesh transform consists of one or more + individual quad transforms. + + See :py:meth:`.Image.transform` + + :param data: A list of (bbox, quad) tuples. + """ + + method = Image.Transform.MESH diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageWin.py b/.venv/lib/python3.12/site-packages/PIL/ImageWin.py new file mode 100644 index 0000000..978c5a9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImageWin.py @@ -0,0 +1,238 @@ +# +# The Python Imaging Library. +# $Id$ +# +# a Windows DIB display interface +# +# History: +# 1996-05-20 fl Created +# 1996-09-20 fl Fixed subregion exposure +# 1997-09-21 fl Added draw primitive (for tzPrint) +# 2003-05-21 fl Added experimental Window/ImageWindow classes +# 2003-09-05 fl Added fromstring/tostring methods +# +# Copyright (c) Secret Labs AB 1997-2003. +# Copyright (c) Fredrik Lundh 1996-2003. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image + + +class HDC: + """ + Wraps an HDC integer. The resulting object can be passed to the + :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` + methods. + """ + + def __init__(self, dc: int) -> None: + self.dc = dc + + def __int__(self) -> int: + return self.dc + + +class HWND: + """ + Wraps an HWND integer. The resulting object can be passed to the + :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` + methods, instead of a DC. + """ + + def __init__(self, wnd: int) -> None: + self.wnd = wnd + + def __int__(self) -> int: + return self.wnd + + +class Dib: + """ + A Windows bitmap with the given mode and size. The mode can be one of "1", + "L", "P", or "RGB". + + If the display requires a palette, this constructor creates a suitable + palette and associates it with the image. For an "L" image, 128 graylevels + are allocated. For an "RGB" image, a 6x6x6 colour cube is used, together + with 20 graylevels. + + To make sure that palettes work properly under Windows, you must call the + ``palette`` method upon certain events from Windows. + + :param image: Either a PIL image, or a mode string. If a mode string is + used, a size must also be given. The mode can be one of "1", + "L", "P", or "RGB". + :param size: If the first argument is a mode string, this + defines the size of the image. + """ + + def __init__( + self, image: Image.Image | str, size: tuple[int, int] | list[int] | None = None + ) -> None: + if isinstance(image, str): + mode = image + image = "" + else: + mode = image.mode + size = image.size + if mode not in ["1", "L", "P", "RGB"]: + mode = Image.getmodebase(mode) + self.image = Image.core.display(mode, size) + self.mode = mode + self.size = size + if image: + assert not isinstance(image, str) + self.paste(image) + + def expose(self, handle): + """ + Copy the bitmap contents to a device context. + + :param handle: Device context (HDC), cast to a Python integer, or an + HDC or HWND instance. In PythonWin, you can use + ``CDC.GetHandleAttrib()`` to get a suitable handle. + """ + if isinstance(handle, HWND): + dc = self.image.getdc(handle) + try: + result = self.image.expose(dc) + finally: + self.image.releasedc(handle, dc) + else: + result = self.image.expose(handle) + return result + + def draw(self, handle, dst, src=None): + """ + Same as expose, but allows you to specify where to draw the image, and + what part of it to draw. + + The destination and source areas are given as 4-tuple rectangles. If + the source is omitted, the entire image is copied. If the source and + the destination have different sizes, the image is resized as + necessary. + """ + if not src: + src = (0, 0) + self.size + if isinstance(handle, HWND): + dc = self.image.getdc(handle) + try: + result = self.image.draw(dc, dst, src) + finally: + self.image.releasedc(handle, dc) + else: + result = self.image.draw(handle, dst, src) + return result + + def query_palette(self, handle): + """ + Installs the palette associated with the image in the given device + context. + + This method should be called upon **QUERYNEWPALETTE** and + **PALETTECHANGED** events from Windows. If this method returns a + non-zero value, one or more display palette entries were changed, and + the image should be redrawn. + + :param handle: Device context (HDC), cast to a Python integer, or an + HDC or HWND instance. + :return: A true value if one or more entries were changed (this + indicates that the image should be redrawn). + """ + if isinstance(handle, HWND): + handle = self.image.getdc(handle) + try: + result = self.image.query_palette(handle) + finally: + self.image.releasedc(handle, handle) + else: + result = self.image.query_palette(handle) + return result + + def paste( + self, im: Image.Image, box: tuple[int, int, int, int] | None = None + ) -> None: + """ + Paste a PIL image into the bitmap image. + + :param im: A PIL image. The size must match the target region. + If the mode does not match, the image is converted to the + mode of the bitmap image. + :param box: A 4-tuple defining the left, upper, right, and + lower pixel coordinate. See :ref:`coordinate-system`. If + None is given instead of a tuple, all of the image is + assumed. + """ + im.load() + if self.mode != im.mode: + im = im.convert(self.mode) + if box: + self.image.paste(im.im, box) + else: + self.image.paste(im.im) + + def frombytes(self, buffer: bytes) -> None: + """ + Load display memory contents from byte data. + + :param buffer: A buffer containing display data (usually + data returned from :py:func:`~PIL.ImageWin.Dib.tobytes`) + """ + self.image.frombytes(buffer) + + def tobytes(self) -> bytes: + """ + Copy display memory contents to bytes object. + + :return: A bytes object containing display data. + """ + return self.image.tobytes() + + +class Window: + """Create a Window with the given title size.""" + + def __init__( + self, title: str = "PIL", width: int | None = None, height: int | None = None + ) -> None: + self.hwnd = Image.core.createwindow( + title, self.__dispatcher, width or 0, height or 0 + ) + + def __dispatcher(self, action, *args): + return getattr(self, f"ui_handle_{action}")(*args) + + def ui_handle_clear(self, dc, x0, y0, x1, y1): + pass + + def ui_handle_damage(self, x0, y0, x1, y1): + pass + + def ui_handle_destroy(self) -> None: + pass + + def ui_handle_repair(self, dc, x0, y0, x1, y1): + pass + + def ui_handle_resize(self, width, height): + pass + + def mainloop(self) -> None: + Image.core.eventloop() + + +class ImageWindow(Window): + """Create an image window which displays the given image.""" + + def __init__(self, image, title="PIL"): + if not isinstance(image, Dib): + image = Dib(image) + self.image = image + width, height = image.size + super().__init__(title, width=width, height=height) + + def ui_handle_repair(self, dc, x0, y0, x1, y1): + self.image.draw(dc, (x0, y0, x1, y1)) diff --git a/.venv/lib/python3.12/site-packages/PIL/ImtImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/ImtImagePlugin.py new file mode 100644 index 0000000..abb3fb7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/ImtImagePlugin.py @@ -0,0 +1,103 @@ +# +# The Python Imaging Library. +# $Id$ +# +# IM Tools support for PIL +# +# history: +# 1996-05-27 fl Created (read 8-bit images only) +# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.2) +# +# Copyright (c) Secret Labs AB 1997-2001. +# Copyright (c) Fredrik Lundh 1996-2001. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import re + +from . import Image, ImageFile + +# +# -------------------------------------------------------------------- + +field = re.compile(rb"([a-z]*) ([^ \r\n]*)") + + +## +# Image plugin for IM Tools images. + + +class ImtImageFile(ImageFile.ImageFile): + format = "IMT" + format_description = "IM Tools" + + def _open(self) -> None: + # Quick rejection: if there's not a LF among the first + # 100 bytes, this is (probably) not a text header. + + assert self.fp is not None + + buffer = self.fp.read(100) + if b"\n" not in buffer: + msg = "not an IM file" + raise SyntaxError(msg) + + xsize = ysize = 0 + + while True: + if buffer: + s = buffer[:1] + buffer = buffer[1:] + else: + s = self.fp.read(1) + if not s: + break + + if s == b"\x0C": + # image data begins + self.tile = [ + ( + "raw", + (0, 0) + self.size, + self.fp.tell() - len(buffer), + (self.mode, 0, 1), + ) + ] + + break + + else: + # read key/value pair + if b"\n" not in buffer: + buffer += self.fp.read(100) + lines = buffer.split(b"\n") + s += lines.pop(0) + buffer = b"\n".join(lines) + if len(s) == 1 or len(s) > 100: + break + if s[0] == ord(b"*"): + continue # comment + + m = field.match(s) + if not m: + break + k, v = m.group(1, 2) + if k == b"width": + xsize = int(v) + self._size = xsize, ysize + elif k == b"height": + ysize = int(v) + self._size = xsize, ysize + elif k == b"pixel" and v == b"n8": + self._mode = "L" + + +# +# -------------------------------------------------------------------- + +Image.register_open(ImtImageFile.format, ImtImageFile) + +# +# no extension registered (".im" is simply too common) diff --git a/.venv/lib/python3.12/site-packages/PIL/IptcImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/IptcImagePlugin.py new file mode 100644 index 0000000..73df83b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/IptcImagePlugin.py @@ -0,0 +1,235 @@ +# +# The Python Imaging Library. +# $Id$ +# +# IPTC/NAA file handling +# +# history: +# 1995-10-01 fl Created +# 1998-03-09 fl Cleaned up and added to PIL +# 2002-06-18 fl Added getiptcinfo helper +# +# Copyright (c) Secret Labs AB 1997-2002. +# Copyright (c) Fredrik Lundh 1995. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from io import BytesIO +from typing import Sequence + +from . import Image, ImageFile +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._deprecate import deprecate + +COMPRESSION = {1: "raw", 5: "jpeg"} + + +def __getattr__(name: str) -> bytes: + if name == "PAD": + deprecate("IptcImagePlugin.PAD", 12) + return b"\0\0\0\0" + msg = f"module '{__name__}' has no attribute '{name}'" + raise AttributeError(msg) + + +# +# Helpers + + +def _i(c: bytes) -> int: + return i32((b"\0\0\0\0" + c)[-4:]) + + +def _i8(c: int | bytes) -> int: + return c if isinstance(c, int) else c[0] + + +def i(c: bytes) -> int: + """.. deprecated:: 10.2.0""" + deprecate("IptcImagePlugin.i", 12) + return _i(c) + + +def dump(c: Sequence[int | bytes]) -> None: + """.. deprecated:: 10.2.0""" + deprecate("IptcImagePlugin.dump", 12) + for i in c: + print(f"{_i8(i):02x}", end=" ") + print() + + +## +# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields +# from TIFF and JPEG files, use the getiptcinfo function. + + +class IptcImageFile(ImageFile.ImageFile): + format = "IPTC" + format_description = "IPTC/NAA" + + def getint(self, key: tuple[int, int]) -> int: + return _i(self.info[key]) + + def field(self) -> tuple[tuple[int, int] | None, int]: + # + # get a IPTC field header + s = self.fp.read(5) + if not s.strip(b"\x00"): + return None, 0 + + tag = s[1], s[2] + + # syntax + if s[0] != 0x1C or tag[0] not in [1, 2, 3, 4, 5, 6, 7, 8, 9, 240]: + msg = "invalid IPTC/NAA file" + raise SyntaxError(msg) + + # field size + size = s[3] + if size > 132: + msg = "illegal field length in IPTC/NAA file" + raise OSError(msg) + elif size == 128: + size = 0 + elif size > 128: + size = _i(self.fp.read(size - 128)) + else: + size = i16(s, 3) + + return tag, size + + def _open(self) -> None: + # load descriptive fields + while True: + offset = self.fp.tell() + tag, size = self.field() + if not tag or tag == (8, 10): + break + if size: + tagdata = self.fp.read(size) + else: + tagdata = None + if tag in self.info: + if isinstance(self.info[tag], list): + self.info[tag].append(tagdata) + else: + self.info[tag] = [self.info[tag], tagdata] + else: + self.info[tag] = tagdata + + # mode + layers = self.info[(3, 60)][0] + component = self.info[(3, 60)][1] + if (3, 65) in self.info: + id = self.info[(3, 65)][0] - 1 + else: + id = 0 + if layers == 1 and not component: + self._mode = "L" + elif layers == 3 and component: + self._mode = "RGB"[id] + elif layers == 4 and component: + self._mode = "CMYK"[id] + + # size + self._size = self.getint((3, 20)), self.getint((3, 30)) + + # compression + try: + compression = COMPRESSION[self.getint((3, 120))] + except KeyError as e: + msg = "Unknown IPTC image compression" + raise OSError(msg) from e + + # tile + if tag == (8, 10): + self.tile = [("iptc", (0, 0) + self.size, offset, compression)] + + def load(self): + if len(self.tile) != 1 or self.tile[0][0] != "iptc": + return ImageFile.ImageFile.load(self) + + offset, compression = self.tile[0][2:] + + self.fp.seek(offset) + + # Copy image data to temporary file + o = BytesIO() + if compression == "raw": + # To simplify access to the extracted file, + # prepend a PPM header + o.write(b"P5\n%d %d\n255\n" % self.size) + while True: + type, size = self.field() + if type != (8, 10): + break + while size > 0: + s = self.fp.read(min(size, 8192)) + if not s: + break + o.write(s) + size -= len(s) + + with Image.open(o) as _im: + _im.load() + self.im = _im.im + + +Image.register_open(IptcImageFile.format, IptcImageFile) + +Image.register_extension(IptcImageFile.format, ".iim") + + +def getiptcinfo(im): + """ + Get IPTC information from TIFF, JPEG, or IPTC file. + + :param im: An image containing IPTC data. + :returns: A dictionary containing IPTC information, or None if + no IPTC information block was found. + """ + from . import JpegImagePlugin, TiffImagePlugin + + data = None + + if isinstance(im, IptcImageFile): + # return info dictionary right away + return im.info + + elif isinstance(im, JpegImagePlugin.JpegImageFile): + # extract the IPTC/NAA resource + photoshop = im.info.get("photoshop") + if photoshop: + data = photoshop.get(0x0404) + + elif isinstance(im, TiffImagePlugin.TiffImageFile): + # get raw data from the IPTC/NAA tag (PhotoShop tags the data + # as 4-byte integers, so we cannot use the get method...) + try: + data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK] + except (AttributeError, KeyError): + pass + + if data is None: + return None # no properties + + # create an IptcImagePlugin object without initializing it + class FakeImage: + pass + + im = FakeImage() + im.__class__ = IptcImageFile + + # parse the IPTC information chunk + im.info = {} + im.fp = BytesIO(data) + + try: + im._open() + except (IndexError, KeyError): + pass # expected failure + + return im.info diff --git a/.venv/lib/python3.12/site-packages/PIL/Jpeg2KImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/Jpeg2KImagePlugin.py new file mode 100644 index 0000000..e50cd77 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/Jpeg2KImagePlugin.py @@ -0,0 +1,408 @@ +# +# The Python Imaging Library +# $Id$ +# +# JPEG2000 file handling +# +# History: +# 2014-03-12 ajh Created +# 2021-06-30 rogermb Extract dpi information from the 'resc' header box +# +# Copyright (c) 2014 Coriolis Systems Limited +# Copyright (c) 2014 Alastair Houghton +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import os +import struct +from typing import IO, Tuple, cast + +from . import Image, ImageFile, ImagePalette, _binary + + +class BoxReader: + """ + A small helper class to read fields stored in JPEG2000 header boxes + and to easily step into and read sub-boxes. + """ + + def __init__(self, fp, length=-1): + self.fp = fp + self.has_length = length >= 0 + self.length = length + self.remaining_in_box = -1 + + def _can_read(self, num_bytes: int) -> bool: + if self.has_length and self.fp.tell() + num_bytes > self.length: + # Outside box: ensure we don't read past the known file length + return False + if self.remaining_in_box >= 0: + # Inside box contents: ensure read does not go past box boundaries + return num_bytes <= self.remaining_in_box + else: + return True # No length known, just read + + def _read_bytes(self, num_bytes: int) -> bytes: + if not self._can_read(num_bytes): + msg = "Not enough data in header" + raise SyntaxError(msg) + + data = self.fp.read(num_bytes) + if len(data) < num_bytes: + msg = f"Expected to read {num_bytes} bytes but only got {len(data)}." + raise OSError(msg) + + if self.remaining_in_box > 0: + self.remaining_in_box -= num_bytes + return data + + def read_fields(self, field_format: str) -> tuple[int | bytes, ...]: + size = struct.calcsize(field_format) + data = self._read_bytes(size) + return struct.unpack(field_format, data) + + def read_boxes(self) -> BoxReader: + size = self.remaining_in_box + data = self._read_bytes(size) + return BoxReader(io.BytesIO(data), size) + + def has_next_box(self) -> bool: + if self.has_length: + return self.fp.tell() + self.remaining_in_box < self.length + else: + return True + + def next_box_type(self) -> bytes: + # Skip the rest of the box if it has not been read + if self.remaining_in_box > 0: + self.fp.seek(self.remaining_in_box, os.SEEK_CUR) + self.remaining_in_box = -1 + + # Read the length and type of the next box + lbox, tbox = cast(Tuple[int, bytes], self.read_fields(">I4s")) + if lbox == 1: + lbox = cast(int, self.read_fields(">Q")[0]) + hlen = 16 + else: + hlen = 8 + + if lbox < hlen or not self._can_read(lbox - hlen): + msg = "Invalid header length" + raise SyntaxError(msg) + + self.remaining_in_box = lbox - hlen + return tbox + + +def _parse_codestream(fp) -> tuple[tuple[int, int], str]: + """Parse the JPEG 2000 codestream to extract the size and component + count from the SIZ marker segment, returning a PIL (size, mode) tuple.""" + + hdr = fp.read(2) + lsiz = _binary.i16be(hdr) + siz = hdr + fp.read(lsiz - 2) + lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, _, _, _, _, csiz = struct.unpack_from( + ">HHIIIIIIIIH", siz + ) + + size = (xsiz - xosiz, ysiz - yosiz) + if csiz == 1: + ssiz = struct.unpack_from(">B", siz, 38) + if (ssiz[0] & 0x7F) + 1 > 8: + mode = "I;16" + else: + mode = "L" + elif csiz == 2: + mode = "LA" + elif csiz == 3: + mode = "RGB" + elif csiz == 4: + mode = "RGBA" + else: + msg = "unable to determine J2K image mode" + raise SyntaxError(msg) + + return size, mode + + +def _res_to_dpi(num: int, denom: int, exp: int) -> float | None: + """Convert JPEG2000's (numerator, denominator, exponent-base-10) resolution, + calculated as (num / denom) * 10^exp and stored in dots per meter, + to floating-point dots per inch.""" + if denom == 0: + return None + return (254 * num * (10**exp)) / (10000 * denom) + + +def _parse_jp2_header(fp): + """Parse the JP2 header box to extract size, component count, + color space information, and optionally DPI information, + returning a (size, mode, mimetype, dpi) tuple.""" + + # Find the JP2 header box + reader = BoxReader(fp) + header = None + mimetype = None + while reader.has_next_box(): + tbox = reader.next_box_type() + + if tbox == b"jp2h": + header = reader.read_boxes() + break + elif tbox == b"ftyp": + if reader.read_fields(">4s")[0] == b"jpx ": + mimetype = "image/jpx" + + size = None + mode = None + bpc = None + nc = None + dpi = None # 2-tuple of DPI info, or None + palette = None + + while header.has_next_box(): + tbox = header.next_box_type() + + if tbox == b"ihdr": + height, width, nc, bpc = header.read_fields(">IIHB") + size = (width, height) + if nc == 1 and (bpc & 0x7F) > 8: + mode = "I;16" + elif nc == 1: + mode = "L" + elif nc == 2: + mode = "LA" + elif nc == 3: + mode = "RGB" + elif nc == 4: + mode = "RGBA" + elif tbox == b"colr" and nc == 4: + meth, _, _, enumcs = header.read_fields(">BBBI") + if meth == 1 and enumcs == 12: + mode = "CMYK" + elif tbox == b"pclr" and mode in ("L", "LA"): + ne, npc = header.read_fields(">HB") + bitdepths = header.read_fields(">" + ("B" * npc)) + if max(bitdepths) <= 8: + palette = ImagePalette.ImagePalette() + for i in range(ne): + palette.getcolor(header.read_fields(">" + ("B" * npc))) + mode = "P" if mode == "L" else "PA" + elif tbox == b"res ": + res = header.read_boxes() + while res.has_next_box(): + tres = res.next_box_type() + if tres == b"resc": + vrcn, vrcd, hrcn, hrcd, vrce, hrce = res.read_fields(">HHHHBB") + hres = _res_to_dpi(hrcn, hrcd, hrce) + vres = _res_to_dpi(vrcn, vrcd, vrce) + if hres is not None and vres is not None: + dpi = (hres, vres) + break + + if size is None or mode is None: + msg = "Malformed JP2 header" + raise SyntaxError(msg) + + return size, mode, mimetype, dpi, palette + + +## +# Image plugin for JPEG2000 images. + + +class Jpeg2KImageFile(ImageFile.ImageFile): + format = "JPEG2000" + format_description = "JPEG 2000 (ISO 15444)" + + def _open(self) -> None: + sig = self.fp.read(4) + if sig == b"\xff\x4f\xff\x51": + self.codec = "j2k" + self._size, self._mode = _parse_codestream(self.fp) + else: + sig = sig + self.fp.read(8) + + if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a": + self.codec = "jp2" + header = _parse_jp2_header(self.fp) + self._size, self._mode, self.custom_mimetype, dpi, self.palette = header + if dpi is not None: + self.info["dpi"] = dpi + if self.fp.read(12).endswith(b"jp2c\xff\x4f\xff\x51"): + self._parse_comment() + else: + msg = "not a JPEG 2000 file" + raise SyntaxError(msg) + + self._reduce = 0 + self.layers = 0 + + fd = -1 + length = -1 + + try: + fd = self.fp.fileno() + length = os.fstat(fd).st_size + except Exception: + fd = -1 + try: + pos = self.fp.tell() + self.fp.seek(0, io.SEEK_END) + length = self.fp.tell() + self.fp.seek(pos) + except Exception: + length = -1 + + self.tile = [ + ( + "jpeg2k", + (0, 0) + self.size, + 0, + (self.codec, self._reduce, self.layers, fd, length), + ) + ] + + def _parse_comment(self) -> None: + hdr = self.fp.read(2) + length = _binary.i16be(hdr) + self.fp.seek(length - 2, os.SEEK_CUR) + + while True: + marker = self.fp.read(2) + if not marker: + break + typ = marker[1] + if typ in (0x90, 0xD9): + # Start of tile or end of codestream + break + hdr = self.fp.read(2) + length = _binary.i16be(hdr) + if typ == 0x64: + # Comment + self.info["comment"] = self.fp.read(length - 2)[2:] + break + else: + self.fp.seek(length - 2, os.SEEK_CUR) + + @property + def reduce(self): + # https://github.com/python-pillow/Pillow/issues/4343 found that the + # new Image 'reduce' method was shadowed by this plugin's 'reduce' + # property. This attempts to allow for both scenarios + return self._reduce or super().reduce + + @reduce.setter + def reduce(self, value): + self._reduce = value + + def load(self): + if self.tile and self._reduce: + power = 1 << self._reduce + adjust = power >> 1 + self._size = ( + int((self.size[0] + adjust) / power), + int((self.size[1] + adjust) / power), + ) + + # Update the reduce and layers settings + t = self.tile[0] + t3 = (t[3][0], self._reduce, self.layers, t[3][3], t[3][4]) + self.tile = [(t[0], (0, 0) + self.size, t[2], t3)] + + return ImageFile.ImageFile.load(self) + + +def _accept(prefix: bytes) -> bool: + return ( + prefix[:4] == b"\xff\x4f\xff\x51" + or prefix[:12] == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" + ) + + +# ------------------------------------------------------------ +# Save support + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + # Get the keyword arguments + info = im.encoderinfo + + if isinstance(filename, str): + filename = filename.encode() + if filename.endswith(b".j2k") or info.get("no_jp2", False): + kind = "j2k" + else: + kind = "jp2" + + offset = info.get("offset", None) + tile_offset = info.get("tile_offset", None) + tile_size = info.get("tile_size", None) + quality_mode = info.get("quality_mode", "rates") + quality_layers = info.get("quality_layers", None) + if quality_layers is not None and not ( + isinstance(quality_layers, (list, tuple)) + and all( + isinstance(quality_layer, (int, float)) for quality_layer in quality_layers + ) + ): + msg = "quality_layers must be a sequence of numbers" + raise ValueError(msg) + + num_resolutions = info.get("num_resolutions", 0) + cblk_size = info.get("codeblock_size", None) + precinct_size = info.get("precinct_size", None) + irreversible = info.get("irreversible", False) + progression = info.get("progression", "LRCP") + cinema_mode = info.get("cinema_mode", "no") + mct = info.get("mct", 0) + signed = info.get("signed", False) + comment = info.get("comment") + if isinstance(comment, str): + comment = comment.encode() + plt = info.get("plt", False) + + fd = -1 + if hasattr(fp, "fileno"): + try: + fd = fp.fileno() + except Exception: + fd = -1 + + im.encoderconfig = ( + offset, + tile_offset, + tile_size, + quality_mode, + quality_layers, + num_resolutions, + cblk_size, + precinct_size, + irreversible, + progression, + cinema_mode, + mct, + signed, + fd, + comment, + plt, + ) + + ImageFile._save(im, fp, [("jpeg2k", (0, 0) + im.size, 0, kind)]) + + +# ------------------------------------------------------------ +# Registry stuff + + +Image.register_open(Jpeg2KImageFile.format, Jpeg2KImageFile, _accept) +Image.register_save(Jpeg2KImageFile.format, _save) + +Image.register_extensions( + Jpeg2KImageFile.format, [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"] +) + +Image.register_mime(Jpeg2KImageFile.format, "image/jp2") diff --git a/.venv/lib/python3.12/site-packages/PIL/JpegImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/JpegImagePlugin.py new file mode 100644 index 0000000..b15bf06 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/JpegImagePlugin.py @@ -0,0 +1,861 @@ +# +# The Python Imaging Library. +# $Id$ +# +# JPEG (JFIF) file handling +# +# See "Digital Compression and Coding of Continuous-Tone Still Images, +# Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1) +# +# History: +# 1995-09-09 fl Created +# 1995-09-13 fl Added full parser +# 1996-03-25 fl Added hack to use the IJG command line utilities +# 1996-05-05 fl Workaround Photoshop 2.5 CMYK polarity bug +# 1996-05-28 fl Added draft support, JFIF version (0.1) +# 1996-12-30 fl Added encoder options, added progression property (0.2) +# 1997-08-27 fl Save mode 1 images as BW (0.3) +# 1998-07-12 fl Added YCbCr to draft and save methods (0.4) +# 1998-10-19 fl Don't hang on files using 16-bit DQT's (0.4.1) +# 2001-04-16 fl Extract DPI settings from JFIF files (0.4.2) +# 2002-07-01 fl Skip pad bytes before markers; identify Exif files (0.4.3) +# 2003-04-25 fl Added experimental EXIF decoder (0.5) +# 2003-06-06 fl Added experimental EXIF GPSinfo decoder +# 2003-09-13 fl Extract COM markers +# 2009-09-06 fl Added icc_profile support (from Florian Hoech) +# 2009-03-06 fl Changed CMYK handling; always use Adobe polarity (0.6) +# 2009-03-08 fl Added subsampling support (from Justin Huff). +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1995-1996 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import array +import io +import math +import os +import struct +import subprocess +import sys +import tempfile +import warnings +from typing import IO, Any + +from . import Image, ImageFile +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._binary import o8 +from ._binary import o16be as o16 +from .JpegPresets import presets + +# +# Parser + + +def Skip(self: JpegImageFile, marker: int) -> None: + n = i16(self.fp.read(2)) - 2 + ImageFile._safe_read(self.fp, n) + + +def APP(self, marker): + # + # Application marker. Store these in the APP dictionary. + # Also look for well-known application markers. + + n = i16(self.fp.read(2)) - 2 + s = ImageFile._safe_read(self.fp, n) + + app = "APP%d" % (marker & 15) + + self.app[app] = s # compatibility + self.applist.append((app, s)) + + if marker == 0xFFE0 and s[:4] == b"JFIF": + # extract JFIF information + self.info["jfif"] = version = i16(s, 5) # version + self.info["jfif_version"] = divmod(version, 256) + # extract JFIF properties + try: + jfif_unit = s[7] + jfif_density = i16(s, 8), i16(s, 10) + except Exception: + pass + else: + if jfif_unit == 1: + self.info["dpi"] = jfif_density + self.info["jfif_unit"] = jfif_unit + self.info["jfif_density"] = jfif_density + elif marker == 0xFFE1 and s[:6] == b"Exif\0\0": + # extract EXIF information + if "exif" in self.info: + self.info["exif"] += s[6:] + else: + self.info["exif"] = s + self._exif_offset = self.fp.tell() - n + 6 + elif marker == 0xFFE1 and s[:29] == b"http://ns.adobe.com/xap/1.0/\x00": + self.info["xmp"] = s.split(b"\x00", 1)[1] + elif marker == 0xFFE2 and s[:5] == b"FPXR\0": + # extract FlashPix information (incomplete) + self.info["flashpix"] = s # FIXME: value will change + elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0": + # Since an ICC profile can be larger than the maximum size of + # a JPEG marker (64K), we need provisions to split it into + # multiple markers. The format defined by the ICC specifies + # one or more APP2 markers containing the following data: + # Identifying string ASCII "ICC_PROFILE\0" (12 bytes) + # Marker sequence number 1, 2, etc (1 byte) + # Number of markers Total of APP2's used (1 byte) + # Profile data (remainder of APP2 data) + # Decoders should use the marker sequence numbers to + # reassemble the profile, rather than assuming that the APP2 + # markers appear in the correct sequence. + self.icclist.append(s) + elif marker == 0xFFED and s[:14] == b"Photoshop 3.0\x00": + # parse the image resource block + offset = 14 + photoshop = self.info.setdefault("photoshop", {}) + while s[offset : offset + 4] == b"8BIM": + try: + offset += 4 + # resource code + code = i16(s, offset) + offset += 2 + # resource name (usually empty) + name_len = s[offset] + # name = s[offset+1:offset+1+name_len] + offset += 1 + name_len + offset += offset & 1 # align + # resource data block + size = i32(s, offset) + offset += 4 + data = s[offset : offset + size] + if code == 0x03ED: # ResolutionInfo + data = { + "XResolution": i32(data, 0) / 65536, + "DisplayedUnitsX": i16(data, 4), + "YResolution": i32(data, 8) / 65536, + "DisplayedUnitsY": i16(data, 12), + } + photoshop[code] = data + offset += size + offset += offset & 1 # align + except struct.error: + break # insufficient data + + elif marker == 0xFFEE and s[:5] == b"Adobe": + self.info["adobe"] = i16(s, 5) + # extract Adobe custom properties + try: + adobe_transform = s[11] + except IndexError: + pass + else: + self.info["adobe_transform"] = adobe_transform + elif marker == 0xFFE2 and s[:4] == b"MPF\0": + # extract MPO information + self.info["mp"] = s[4:] + # offset is current location minus buffer size + # plus constant header size + self.info["mpoffset"] = self.fp.tell() - n + 4 + + +def COM(self: JpegImageFile, marker: int) -> None: + # + # Comment marker. Store these in the APP dictionary. + n = i16(self.fp.read(2)) - 2 + s = ImageFile._safe_read(self.fp, n) + + self.info["comment"] = s + self.app["COM"] = s # compatibility + self.applist.append(("COM", s)) + + +def SOF(self: JpegImageFile, marker: int) -> None: + # + # Start of frame marker. Defines the size and mode of the + # image. JPEG is colour blind, so we use some simple + # heuristics to map the number of layers to an appropriate + # mode. Note that this could be made a bit brighter, by + # looking for JFIF and Adobe APP markers. + + n = i16(self.fp.read(2)) - 2 + s = ImageFile._safe_read(self.fp, n) + self._size = i16(s, 3), i16(s, 1) + + self.bits = s[0] + if self.bits != 8: + msg = f"cannot handle {self.bits}-bit layers" + raise SyntaxError(msg) + + self.layers = s[5] + if self.layers == 1: + self._mode = "L" + elif self.layers == 3: + self._mode = "RGB" + elif self.layers == 4: + self._mode = "CMYK" + else: + msg = f"cannot handle {self.layers}-layer images" + raise SyntaxError(msg) + + if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: + self.info["progressive"] = self.info["progression"] = 1 + + if self.icclist: + # fixup icc profile + self.icclist.sort() # sort by sequence number + if self.icclist[0][13] == len(self.icclist): + profile = [p[14:] for p in self.icclist] + icc_profile = b"".join(profile) + else: + icc_profile = None # wrong number of fragments + self.info["icc_profile"] = icc_profile + self.icclist = [] + + for i in range(6, len(s), 3): + t = s[i : i + 3] + # 4-tuples: id, vsamp, hsamp, qtable + self.layer.append((t[0], t[1] // 16, t[1] & 15, t[2])) + + +def DQT(self: JpegImageFile, marker: int) -> None: + # + # Define quantization table. Note that there might be more + # than one table in each marker. + + # FIXME: The quantization tables can be used to estimate the + # compression quality. + + n = i16(self.fp.read(2)) - 2 + s = ImageFile._safe_read(self.fp, n) + while len(s): + v = s[0] + precision = 1 if (v // 16 == 0) else 2 # in bytes + qt_length = 1 + precision * 64 + if len(s) < qt_length: + msg = "bad quantization table marker" + raise SyntaxError(msg) + data = array.array("B" if precision == 1 else "H", s[1:qt_length]) + if sys.byteorder == "little" and precision > 1: + data.byteswap() # the values are always big-endian + self.quantization[v & 15] = [data[i] for i in zigzag_index] + s = s[qt_length:] + + +# +# JPEG marker table + +MARKER = { + 0xFFC0: ("SOF0", "Baseline DCT", SOF), + 0xFFC1: ("SOF1", "Extended Sequential DCT", SOF), + 0xFFC2: ("SOF2", "Progressive DCT", SOF), + 0xFFC3: ("SOF3", "Spatial lossless", SOF), + 0xFFC4: ("DHT", "Define Huffman table", Skip), + 0xFFC5: ("SOF5", "Differential sequential DCT", SOF), + 0xFFC6: ("SOF6", "Differential progressive DCT", SOF), + 0xFFC7: ("SOF7", "Differential spatial", SOF), + 0xFFC8: ("JPG", "Extension", None), + 0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF), + 0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF), + 0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF), + 0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip), + 0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF), + 0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF), + 0xFFCF: ("SOF15", "Differential spatial (AC)", SOF), + 0xFFD0: ("RST0", "Restart 0", None), + 0xFFD1: ("RST1", "Restart 1", None), + 0xFFD2: ("RST2", "Restart 2", None), + 0xFFD3: ("RST3", "Restart 3", None), + 0xFFD4: ("RST4", "Restart 4", None), + 0xFFD5: ("RST5", "Restart 5", None), + 0xFFD6: ("RST6", "Restart 6", None), + 0xFFD7: ("RST7", "Restart 7", None), + 0xFFD8: ("SOI", "Start of image", None), + 0xFFD9: ("EOI", "End of image", None), + 0xFFDA: ("SOS", "Start of scan", Skip), + 0xFFDB: ("DQT", "Define quantization table", DQT), + 0xFFDC: ("DNL", "Define number of lines", Skip), + 0xFFDD: ("DRI", "Define restart interval", Skip), + 0xFFDE: ("DHP", "Define hierarchical progression", SOF), + 0xFFDF: ("EXP", "Expand reference component", Skip), + 0xFFE0: ("APP0", "Application segment 0", APP), + 0xFFE1: ("APP1", "Application segment 1", APP), + 0xFFE2: ("APP2", "Application segment 2", APP), + 0xFFE3: ("APP3", "Application segment 3", APP), + 0xFFE4: ("APP4", "Application segment 4", APP), + 0xFFE5: ("APP5", "Application segment 5", APP), + 0xFFE6: ("APP6", "Application segment 6", APP), + 0xFFE7: ("APP7", "Application segment 7", APP), + 0xFFE8: ("APP8", "Application segment 8", APP), + 0xFFE9: ("APP9", "Application segment 9", APP), + 0xFFEA: ("APP10", "Application segment 10", APP), + 0xFFEB: ("APP11", "Application segment 11", APP), + 0xFFEC: ("APP12", "Application segment 12", APP), + 0xFFED: ("APP13", "Application segment 13", APP), + 0xFFEE: ("APP14", "Application segment 14", APP), + 0xFFEF: ("APP15", "Application segment 15", APP), + 0xFFF0: ("JPG0", "Extension 0", None), + 0xFFF1: ("JPG1", "Extension 1", None), + 0xFFF2: ("JPG2", "Extension 2", None), + 0xFFF3: ("JPG3", "Extension 3", None), + 0xFFF4: ("JPG4", "Extension 4", None), + 0xFFF5: ("JPG5", "Extension 5", None), + 0xFFF6: ("JPG6", "Extension 6", None), + 0xFFF7: ("JPG7", "Extension 7", None), + 0xFFF8: ("JPG8", "Extension 8", None), + 0xFFF9: ("JPG9", "Extension 9", None), + 0xFFFA: ("JPG10", "Extension 10", None), + 0xFFFB: ("JPG11", "Extension 11", None), + 0xFFFC: ("JPG12", "Extension 12", None), + 0xFFFD: ("JPG13", "Extension 13", None), + 0xFFFE: ("COM", "Comment", COM), +} + + +def _accept(prefix: bytes) -> bool: + # Magic number was taken from https://en.wikipedia.org/wiki/JPEG + return prefix[:3] == b"\xFF\xD8\xFF" + + +## +# Image plugin for JPEG and JFIF images. + + +class JpegImageFile(ImageFile.ImageFile): + format = "JPEG" + format_description = "JPEG (ISO 10918)" + + def _open(self): + s = self.fp.read(3) + + if not _accept(s): + msg = "not a JPEG file" + raise SyntaxError(msg) + s = b"\xFF" + + # Create attributes + self.bits = self.layers = 0 + + # JPEG specifics (internal) + self.layer = [] + self.huffman_dc = {} + self.huffman_ac = {} + self.quantization = {} + self.app = {} # compatibility + self.applist = [] + self.icclist = [] + + while True: + i = s[0] + if i == 0xFF: + s = s + self.fp.read(1) + i = i16(s) + else: + # Skip non-0xFF junk + s = self.fp.read(1) + continue + + if i in MARKER: + name, description, handler = MARKER[i] + if handler is not None: + handler(self, i) + if i == 0xFFDA: # start of scan + rawmode = self.mode + if self.mode == "CMYK": + rawmode = "CMYK;I" # assume adobe conventions + self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))] + # self.__offset = self.fp.tell() + break + s = self.fp.read(1) + elif i in {0, 0xFFFF}: + # padded marker or junk; move on + s = b"\xff" + elif i == 0xFF00: # Skip extraneous data (escaped 0xFF) + s = self.fp.read(1) + else: + msg = "no marker found" + raise SyntaxError(msg) + + self._read_dpi_from_exif() + + def load_read(self, read_bytes: int) -> bytes: + """ + internal: read more image data + For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker + so libjpeg can finish decoding + """ + s = self.fp.read(read_bytes) + + if not s and ImageFile.LOAD_TRUNCATED_IMAGES and not hasattr(self, "_ended"): + # Premature EOF. + # Pretend file is finished adding EOI marker + self._ended = True + return b"\xFF\xD9" + + return s + + def draft( + self, mode: str | None, size: tuple[int, int] | None + ) -> tuple[str, tuple[int, int, float, float]] | None: + if len(self.tile) != 1: + return None + + # Protect from second call + if self.decoderconfig: + return None + + d, e, o, a = self.tile[0] + scale = 1 + original_size = self.size + + if a[0] == "RGB" and mode in ["L", "YCbCr"]: + self._mode = mode + a = mode, "" + + if size: + scale = min(self.size[0] // size[0], self.size[1] // size[1]) + for s in [8, 4, 2, 1]: + if scale >= s: + break + e = ( + e[0], + e[1], + (e[2] - e[0] + s - 1) // s + e[0], + (e[3] - e[1] + s - 1) // s + e[1], + ) + self._size = ((self.size[0] + s - 1) // s, (self.size[1] + s - 1) // s) + scale = s + + self.tile = [(d, e, o, a)] + self.decoderconfig = (scale, 0) + + box = (0, 0, original_size[0] / scale, original_size[1] / scale) + return self.mode, box + + def load_djpeg(self) -> None: + # ALTERNATIVE: handle JPEGs via the IJG command line utilities + + f, path = tempfile.mkstemp() + os.close(f) + if os.path.exists(self.filename): + subprocess.check_call(["djpeg", "-outfile", path, self.filename]) + else: + try: + os.unlink(path) + except OSError: + pass + + msg = "Invalid Filename" + raise ValueError(msg) + + try: + with Image.open(path) as _im: + _im.load() + self.im = _im.im + finally: + try: + os.unlink(path) + except OSError: + pass + + self._mode = self.im.mode + self._size = self.im.size + + self.tile = [] + + def _getexif(self) -> dict[str, Any] | None: + return _getexif(self) + + def _read_dpi_from_exif(self) -> None: + # If DPI isn't in JPEG header, fetch from EXIF + if "dpi" in self.info or "exif" not in self.info: + return + try: + exif = self.getexif() + resolution_unit = exif[0x0128] + x_resolution = exif[0x011A] + try: + dpi = float(x_resolution[0]) / x_resolution[1] + except TypeError: + dpi = x_resolution + if math.isnan(dpi): + msg = "DPI is not a number" + raise ValueError(msg) + if resolution_unit == 3: # cm + # 1 dpcm = 2.54 dpi + dpi *= 2.54 + self.info["dpi"] = dpi, dpi + except ( + struct.error, # truncated EXIF + KeyError, # dpi not included + SyntaxError, # invalid/unreadable EXIF + TypeError, # dpi is an invalid float + ValueError, # dpi is an invalid float + ZeroDivisionError, # invalid dpi rational value + ): + self.info["dpi"] = 72, 72 + + def _getmp(self): + return _getmp(self) + + +def _getexif(self) -> dict[str, Any] | None: + if "exif" not in self.info: + return None + return self.getexif()._get_merged_dict() + + +def _getmp(self): + # Extract MP information. This method was inspired by the "highly + # experimental" _getexif version that's been in use for years now, + # itself based on the ImageFileDirectory class in the TIFF plugin. + + # The MP record essentially consists of a TIFF file embedded in a JPEG + # application marker. + try: + data = self.info["mp"] + except KeyError: + return None + file_contents = io.BytesIO(data) + head = file_contents.read(8) + endianness = ">" if head[:4] == b"\x4d\x4d\x00\x2a" else "<" + # process dictionary + from . import TiffImagePlugin + + try: + info = TiffImagePlugin.ImageFileDirectory_v2(head) + file_contents.seek(info.next) + info.load(file_contents) + mp = dict(info) + except Exception as e: + msg = "malformed MP Index (unreadable directory)" + raise SyntaxError(msg) from e + # it's an error not to have a number of images + try: + quant = mp[0xB001] + except KeyError as e: + msg = "malformed MP Index (no number of images)" + raise SyntaxError(msg) from e + # get MP entries + mpentries = [] + try: + rawmpentries = mp[0xB002] + for entrynum in range(0, quant): + unpackedentry = struct.unpack_from( + f"{endianness}LLLHH", rawmpentries, entrynum * 16 + ) + labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2") + mpentry = dict(zip(labels, unpackedentry)) + mpentryattr = { + "DependentParentImageFlag": bool(mpentry["Attribute"] & (1 << 31)), + "DependentChildImageFlag": bool(mpentry["Attribute"] & (1 << 30)), + "RepresentativeImageFlag": bool(mpentry["Attribute"] & (1 << 29)), + "Reserved": (mpentry["Attribute"] & (3 << 27)) >> 27, + "ImageDataFormat": (mpentry["Attribute"] & (7 << 24)) >> 24, + "MPType": mpentry["Attribute"] & 0x00FFFFFF, + } + if mpentryattr["ImageDataFormat"] == 0: + mpentryattr["ImageDataFormat"] = "JPEG" + else: + msg = "unsupported picture format in MPO" + raise SyntaxError(msg) + mptypemap = { + 0x000000: "Undefined", + 0x010001: "Large Thumbnail (VGA Equivalent)", + 0x010002: "Large Thumbnail (Full HD Equivalent)", + 0x020001: "Multi-Frame Image (Panorama)", + 0x020002: "Multi-Frame Image: (Disparity)", + 0x020003: "Multi-Frame Image: (Multi-Angle)", + 0x030000: "Baseline MP Primary Image", + } + mpentryattr["MPType"] = mptypemap.get(mpentryattr["MPType"], "Unknown") + mpentry["Attribute"] = mpentryattr + mpentries.append(mpentry) + mp[0xB002] = mpentries + except KeyError as e: + msg = "malformed MP Index (bad MP Entry)" + raise SyntaxError(msg) from e + # Next we should try and parse the individual image unique ID list; + # we don't because I've never seen this actually used in a real MPO + # file and so can't test it. + return mp + + +# -------------------------------------------------------------------- +# stuff to save JPEG files + +RAWMODE = { + "1": "L", + "L": "L", + "RGB": "RGB", + "RGBX": "RGB", + "CMYK": "CMYK;I", # assume adobe conventions + "YCbCr": "YCbCr", +} + +# fmt: off +zigzag_index = ( + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63, +) + +samplings = { + (1, 1, 1, 1, 1, 1): 0, + (2, 1, 1, 1, 1, 1): 1, + (2, 2, 1, 1, 1, 1): 2, +} +# fmt: on + + +def get_sampling(im): + # There's no subsampling when images have only 1 layer + # (grayscale images) or when they are CMYK (4 layers), + # so set subsampling to the default value. + # + # NOTE: currently Pillow can't encode JPEG to YCCK format. + # If YCCK support is added in the future, subsampling code will have + # to be updated (here and in JpegEncode.c) to deal with 4 layers. + if not hasattr(im, "layers") or im.layers in (1, 4): + return -1 + sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3] + return samplings.get(sampling, -1) + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.width == 0 or im.height == 0: + msg = "cannot write empty image as JPEG" + raise ValueError(msg) + + try: + rawmode = RAWMODE[im.mode] + except KeyError as e: + msg = f"cannot write mode {im.mode} as JPEG" + raise OSError(msg) from e + + info = im.encoderinfo + + dpi = [round(x) for x in info.get("dpi", (0, 0))] + + quality = info.get("quality", -1) + subsampling = info.get("subsampling", -1) + qtables = info.get("qtables") + + if quality == "keep": + quality = -1 + subsampling = "keep" + qtables = "keep" + elif quality in presets: + preset = presets[quality] + quality = -1 + subsampling = preset.get("subsampling", -1) + qtables = preset.get("quantization") + elif not isinstance(quality, int): + msg = "Invalid quality setting" + raise ValueError(msg) + else: + if subsampling in presets: + subsampling = presets[subsampling].get("subsampling", -1) + if isinstance(qtables, str) and qtables in presets: + qtables = presets[qtables].get("quantization") + + if subsampling == "4:4:4": + subsampling = 0 + elif subsampling == "4:2:2": + subsampling = 1 + elif subsampling == "4:2:0": + subsampling = 2 + elif subsampling == "4:1:1": + # For compatibility. Before Pillow 4.3, 4:1:1 actually meant 4:2:0. + # Set 4:2:0 if someone is still using that value. + subsampling = 2 + elif subsampling == "keep": + if im.format != "JPEG": + msg = "Cannot use 'keep' when original image is not a JPEG" + raise ValueError(msg) + subsampling = get_sampling(im) + + def validate_qtables(qtables): + if qtables is None: + return qtables + if isinstance(qtables, str): + try: + lines = [ + int(num) + for line in qtables.splitlines() + for num in line.split("#", 1)[0].split() + ] + except ValueError as e: + msg = "Invalid quantization table" + raise ValueError(msg) from e + else: + qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)] + if isinstance(qtables, (tuple, list, dict)): + if isinstance(qtables, dict): + qtables = [ + qtables[key] for key in range(len(qtables)) if key in qtables + ] + elif isinstance(qtables, tuple): + qtables = list(qtables) + if not (0 < len(qtables) < 5): + msg = "None or too many quantization tables" + raise ValueError(msg) + for idx, table in enumerate(qtables): + try: + if len(table) != 64: + msg = "Invalid quantization table" + raise TypeError(msg) + table = array.array("H", table) + except TypeError as e: + msg = "Invalid quantization table" + raise ValueError(msg) from e + else: + qtables[idx] = list(table) + return qtables + + if qtables == "keep": + if im.format != "JPEG": + msg = "Cannot use 'keep' when original image is not a JPEG" + raise ValueError(msg) + qtables = getattr(im, "quantization", None) + qtables = validate_qtables(qtables) + + extra = info.get("extra", b"") + + MAX_BYTES_IN_MARKER = 65533 + icc_profile = info.get("icc_profile") + if icc_profile: + ICC_OVERHEAD_LEN = 14 + MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN + markers = [] + while icc_profile: + markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER]) + icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:] + i = 1 + for marker in markers: + size = o16(2 + ICC_OVERHEAD_LEN + len(marker)) + extra += ( + b"\xFF\xE2" + + size + + b"ICC_PROFILE\0" + + o8(i) + + o8(len(markers)) + + marker + ) + i += 1 + + comment = info.get("comment", im.info.get("comment")) + + # "progressive" is the official name, but older documentation + # says "progression" + # FIXME: issue a warning if the wrong form is used (post-1.1.7) + progressive = info.get("progressive", False) or info.get("progression", False) + + optimize = info.get("optimize", False) + + exif = info.get("exif", b"") + if isinstance(exif, Image.Exif): + exif = exif.tobytes() + if len(exif) > MAX_BYTES_IN_MARKER: + msg = "EXIF data is too long" + raise ValueError(msg) + + # get keyword arguments + im.encoderconfig = ( + quality, + progressive, + info.get("smooth", 0), + optimize, + info.get("keep_rgb", False), + info.get("streamtype", 0), + dpi[0], + dpi[1], + subsampling, + info.get("restart_marker_blocks", 0), + info.get("restart_marker_rows", 0), + qtables, + comment, + extra, + exif, + ) + + # if we optimize, libjpeg needs a buffer big enough to hold the whole image + # in a shot. Guessing on the size, at im.size bytes. (raw pixel size is + # channels*size, this is a value that's been used in a django patch. + # https://github.com/matthewwithanm/django-imagekit/issues/50 + bufsize = 0 + if optimize or progressive: + # CMYK can be bigger + if im.mode == "CMYK": + bufsize = 4 * im.size[0] * im.size[1] + # keep sets quality to -1, but the actual value may be high. + elif quality >= 95 or quality == -1: + bufsize = 2 * im.size[0] * im.size[1] + else: + bufsize = im.size[0] * im.size[1] + if exif: + bufsize += len(exif) + 5 + if extra: + bufsize += len(extra) + 1 + else: + # The EXIF info needs to be written as one block, + APP1, + one spare byte. + # Ensure that our buffer is big enough. Same with the icc_profile block. + bufsize = max(bufsize, len(exif) + 5, len(extra) + 1) + + ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize) + + +def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + # ALTERNATIVE: handle JPEGs via the IJG command line utilities. + tempfile = im._dump() + subprocess.check_call(["cjpeg", "-outfile", filename, tempfile]) + try: + os.unlink(tempfile) + except OSError: + pass + + +## +# Factory for making JPEG and MPO instances +def jpeg_factory(fp=None, filename=None): + im = JpegImageFile(fp, filename) + try: + mpheader = im._getmp() + if mpheader[45057] > 1: + for segment, content in im.applist: + if segment == "APP1" and b' hdrgm:Version="' in content: + # Ultra HDR images are not yet supported + return im + # It's actually an MPO + from .MpoImagePlugin import MpoImageFile + + # Don't reload everything, just convert it. + im = MpoImageFile.adopt(im, mpheader) + except (TypeError, IndexError): + # It is really a JPEG + pass + except SyntaxError: + warnings.warn( + "Image appears to be a malformed MPO file, it will be " + "interpreted as a base JPEG file" + ) + return im + + +# --------------------------------------------------------------------- +# Registry stuff + +Image.register_open(JpegImageFile.format, jpeg_factory, _accept) +Image.register_save(JpegImageFile.format, _save) + +Image.register_extensions(JpegImageFile.format, [".jfif", ".jpe", ".jpg", ".jpeg"]) + +Image.register_mime(JpegImageFile.format, "image/jpeg") diff --git a/.venv/lib/python3.12/site-packages/PIL/JpegPresets.py b/.venv/lib/python3.12/site-packages/PIL/JpegPresets.py new file mode 100644 index 0000000..3aefa07 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/JpegPresets.py @@ -0,0 +1,242 @@ +""" +JPEG quality settings equivalent to the Photoshop settings. +Can be used when saving JPEG files. + +The following presets are available by default: +``web_low``, ``web_medium``, ``web_high``, ``web_very_high``, ``web_maximum``, +``low``, ``medium``, ``high``, ``maximum``. +More presets can be added to the :py:data:`presets` dict if needed. + +To apply the preset, specify:: + + quality="preset_name" + +To apply only the quantization table:: + + qtables="preset_name" + +To apply only the subsampling setting:: + + subsampling="preset_name" + +Example:: + + im.save("image_name.jpg", quality="web_high") + +Subsampling +----------- + +Subsampling is the practice of encoding images by implementing less resolution +for chroma information than for luma information. +(ref.: https://en.wikipedia.org/wiki/Chroma_subsampling) + +Possible subsampling values are 0, 1 and 2 that correspond to 4:4:4, 4:2:2 and +4:2:0. + +You can get the subsampling of a JPEG with the +:func:`.JpegImagePlugin.get_sampling` function. + +In JPEG compressed data a JPEG marker is used instead of an EXIF tag. +(ref.: https://web.archive.org/web/20240227115053/https://exiv2.org/tags.html) + + +Quantization tables +------------------- + +They are values use by the DCT (Discrete cosine transform) to remove +*unnecessary* information from the image (the lossy part of the compression). +(ref.: https://en.wikipedia.org/wiki/Quantization_matrix#Quantization_matrices, +https://en.wikipedia.org/wiki/JPEG#Quantization) + +You can get the quantization tables of a JPEG with:: + + im.quantization + +This will return a dict with a number of lists. You can pass this dict +directly as the qtables argument when saving a JPEG. + +The quantization table format in presets is a list with sublists. These formats +are interchangeable. + +Libjpeg ref.: +https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html + +""" + +from __future__ import annotations + +# fmt: off +presets = { + 'web_low': {'subsampling': 2, # "4:2:0" + 'quantization': [ + [20, 16, 25, 39, 50, 46, 62, 68, + 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, + 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, + 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68], + [21, 25, 32, 38, 54, 68, 68, 68, + 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, + 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68] + ]}, + 'web_medium': {'subsampling': 2, # "4:2:0" + 'quantization': [ + [16, 11, 11, 16, 23, 27, 31, 30, + 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, + 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, + 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, + 30, 30, 47, 64, 64, 64, 64, 64], + [17, 15, 17, 21, 20, 26, 38, 48, + 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, + 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, + 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, + 48, 43, 53, 64, 64, 64, 64, 64] + ]}, + 'web_high': {'subsampling': 0, # "4:4:4" + 'quantization': [ + [6, 4, 4, 6, 9, 11, 12, 16, + 4, 5, 5, 6, 8, 10, 12, 12, + 4, 5, 5, 6, 10, 12, 14, 19, + 6, 6, 6, 11, 12, 15, 19, 28, + 9, 8, 10, 12, 16, 20, 27, 31, + 11, 10, 12, 15, 20, 27, 31, 31, + 12, 12, 14, 19, 27, 31, 31, 31, + 16, 12, 19, 28, 31, 31, 31, 31], + [7, 7, 13, 24, 26, 31, 31, 31, + 7, 12, 16, 21, 31, 31, 31, 31, + 13, 16, 17, 31, 31, 31, 31, 31, + 24, 21, 31, 31, 31, 31, 31, 31, + 26, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31] + ]}, + 'web_very_high': {'subsampling': 0, # "4:4:4" + 'quantization': [ + [2, 2, 2, 2, 3, 4, 5, 6, + 2, 2, 2, 2, 3, 4, 5, 6, + 2, 2, 2, 2, 4, 5, 7, 9, + 2, 2, 2, 4, 5, 7, 9, 12, + 3, 3, 4, 5, 8, 10, 12, 12, + 4, 4, 5, 7, 10, 12, 12, 12, + 5, 5, 7, 9, 12, 12, 12, 12, + 6, 6, 9, 12, 12, 12, 12, 12], + [3, 3, 5, 9, 13, 15, 15, 15, + 3, 4, 6, 11, 14, 12, 12, 12, + 5, 6, 9, 14, 12, 12, 12, 12, + 9, 11, 14, 12, 12, 12, 12, 12, + 13, 14, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12] + ]}, + 'web_maximum': {'subsampling': 0, # "4:4:4" + 'quantization': [ + [1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 1, 1, 2, 2, 3, + 1, 1, 1, 1, 2, 2, 3, 3, + 1, 1, 1, 2, 2, 3, 3, 3, + 1, 1, 2, 2, 3, 3, 3, 3], + [1, 1, 1, 2, 2, 3, 3, 3, + 1, 1, 1, 2, 3, 3, 3, 3, + 1, 1, 1, 3, 3, 3, 3, 3, + 2, 2, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3] + ]}, + 'low': {'subsampling': 2, # "4:2:0" + 'quantization': [ + [18, 14, 14, 21, 30, 35, 34, 17, + 14, 16, 16, 19, 26, 23, 12, 12, + 14, 16, 17, 21, 23, 12, 12, 12, + 21, 19, 21, 23, 12, 12, 12, 12, + 30, 26, 23, 12, 12, 12, 12, 12, + 35, 23, 12, 12, 12, 12, 12, 12, + 34, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12], + [20, 19, 22, 27, 20, 20, 17, 17, + 19, 25, 23, 14, 14, 12, 12, 12, + 22, 23, 14, 14, 12, 12, 12, 12, + 27, 14, 14, 12, 12, 12, 12, 12, + 20, 14, 12, 12, 12, 12, 12, 12, + 20, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12] + ]}, + 'medium': {'subsampling': 2, # "4:2:0" + 'quantization': [ + [12, 8, 8, 12, 17, 21, 24, 17, + 8, 9, 9, 11, 15, 19, 12, 12, + 8, 9, 10, 12, 19, 12, 12, 12, + 12, 11, 12, 21, 12, 12, 12, 12, + 17, 15, 19, 12, 12, 12, 12, 12, + 21, 19, 12, 12, 12, 12, 12, 12, + 24, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12], + [13, 11, 13, 16, 20, 20, 17, 17, + 11, 14, 14, 14, 14, 12, 12, 12, + 13, 14, 14, 14, 12, 12, 12, 12, + 16, 14, 14, 12, 12, 12, 12, 12, + 20, 14, 12, 12, 12, 12, 12, 12, + 20, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12] + ]}, + 'high': {'subsampling': 0, # "4:4:4" + 'quantization': [ + [6, 4, 4, 6, 9, 11, 12, 16, + 4, 5, 5, 6, 8, 10, 12, 12, + 4, 5, 5, 6, 10, 12, 12, 12, + 6, 6, 6, 11, 12, 12, 12, 12, + 9, 8, 10, 12, 12, 12, 12, 12, + 11, 10, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 16, 12, 12, 12, 12, 12, 12, 12], + [7, 7, 13, 24, 20, 20, 17, 17, + 7, 12, 16, 14, 14, 12, 12, 12, + 13, 16, 14, 14, 12, 12, 12, 12, + 24, 14, 14, 12, 12, 12, 12, 12, + 20, 14, 12, 12, 12, 12, 12, 12, + 20, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12] + ]}, + 'maximum': {'subsampling': 0, # "4:4:4" + 'quantization': [ + [2, 2, 2, 2, 3, 4, 5, 6, + 2, 2, 2, 2, 3, 4, 5, 6, + 2, 2, 2, 2, 4, 5, 7, 9, + 2, 2, 2, 4, 5, 7, 9, 12, + 3, 3, 4, 5, 8, 10, 12, 12, + 4, 4, 5, 7, 10, 12, 12, 12, + 5, 5, 7, 9, 12, 12, 12, 12, + 6, 6, 9, 12, 12, 12, 12, 12], + [3, 3, 5, 9, 13, 15, 15, 15, + 3, 4, 6, 10, 14, 12, 12, 12, + 5, 6, 9, 14, 12, 12, 12, 12, + 9, 10, 14, 12, 12, 12, 12, 12, + 13, 14, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12, + 15, 12, 12, 12, 12, 12, 12, 12] + ]}, +} +# fmt: on diff --git a/.venv/lib/python3.12/site-packages/PIL/McIdasImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/McIdasImagePlugin.py new file mode 100644 index 0000000..2797223 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/McIdasImagePlugin.py @@ -0,0 +1,78 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Basic McIdas support for PIL +# +# History: +# 1997-05-05 fl Created (8-bit images only) +# 2009-03-08 fl Added 16/32-bit support. +# +# Thanks to Richard Jones and Craig Swank for specs and samples. +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import struct + +from . import Image, ImageFile + + +def _accept(prefix: bytes) -> bool: + return prefix[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04" + + +## +# Image plugin for McIdas area images. + + +class McIdasImageFile(ImageFile.ImageFile): + format = "MCIDAS" + format_description = "McIdas area file" + + def _open(self) -> None: + # parse area file directory + assert self.fp is not None + + s = self.fp.read(256) + if not _accept(s) or len(s) != 256: + msg = "not an McIdas area file" + raise SyntaxError(msg) + + self.area_descriptor_raw = s + self.area_descriptor = w = [0] + list(struct.unpack("!64i", s)) + + # get mode + if w[11] == 1: + mode = rawmode = "L" + elif w[11] == 2: + # FIXME: add memory map support + mode = "I" + rawmode = "I;16B" + elif w[11] == 4: + # FIXME: add memory map support + mode = "I" + rawmode = "I;32B" + else: + msg = "unsupported McIdas format" + raise SyntaxError(msg) + + self._mode = mode + self._size = w[10], w[9] + + offset = w[34] + w[15] + stride = w[15] + w[10] * w[11] * w[14] + + self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))] + + +# -------------------------------------------------------------------- +# registry + +Image.register_open(McIdasImageFile.format, McIdasImageFile, _accept) + +# no default extension diff --git a/.venv/lib/python3.12/site-packages/PIL/MicImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/MicImagePlugin.py new file mode 100644 index 0000000..0723988 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/MicImagePlugin.py @@ -0,0 +1,107 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Microsoft Image Composer support for PIL +# +# Notes: +# uses TiffImagePlugin.py to read the actual image streams +# +# History: +# 97-01-20 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import olefile + +from . import Image, TiffImagePlugin + +# +# -------------------------------------------------------------------- + + +def _accept(prefix: bytes) -> bool: + return prefix[:8] == olefile.MAGIC + + +## +# Image plugin for Microsoft's Image Composer file format. + + +class MicImageFile(TiffImagePlugin.TiffImageFile): + format = "MIC" + format_description = "Microsoft Image Composer" + _close_exclusive_fp_after_loading = False + + def _open(self) -> None: + # read the OLE directory and see if this is a likely + # to be a Microsoft Image Composer file + + try: + self.ole = olefile.OleFileIO(self.fp) + except OSError as e: + msg = "not an MIC file; invalid OLE file" + raise SyntaxError(msg) from e + + # find ACI subfiles with Image members (maybe not the + # best way to identify MIC files, but what the... ;-) + + self.images = [ + path + for path in self.ole.listdir() + if path[1:] and path[0][-4:] == ".ACI" and path[1] == "Image" + ] + + # if we didn't find any images, this is probably not + # an MIC file. + if not self.images: + msg = "not an MIC file; no image entries" + raise SyntaxError(msg) + + self.frame = -1 + self._n_frames = len(self.images) + self.is_animated = self._n_frames > 1 + + self.__fp = self.fp + self.seek(0) + + def seek(self, frame): + if not self._seek_check(frame): + return + try: + filename = self.images[frame] + except IndexError as e: + msg = "no such frame" + raise EOFError(msg) from e + + self.fp = self.ole.openstream(filename) + + TiffImagePlugin.TiffImageFile._open(self) + + self.frame = frame + + def tell(self) -> int: + return self.frame + + def close(self) -> None: + self.__fp.close() + self.ole.close() + super().close() + + def __exit__(self, *args: object) -> None: + self.__fp.close() + self.ole.close() + super().__exit__() + + +# +# -------------------------------------------------------------------- + +Image.register_open(MicImageFile.format, MicImageFile, _accept) + +Image.register_extension(MicImageFile.format, ".mic") diff --git a/.venv/lib/python3.12/site-packages/PIL/MpegImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/MpegImagePlugin.py new file mode 100644 index 0000000..ad4d3e9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/MpegImagePlugin.py @@ -0,0 +1,88 @@ +# +# The Python Imaging Library. +# $Id$ +# +# MPEG file handling +# +# History: +# 95-09-09 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1995. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image, ImageFile +from ._binary import i8 +from ._typing import SupportsRead + +# +# Bitstream parser + + +class BitStream: + def __init__(self, fp: SupportsRead[bytes]) -> None: + self.fp = fp + self.bits = 0 + self.bitbuffer = 0 + + def next(self) -> int: + return i8(self.fp.read(1)) + + def peek(self, bits: int) -> int: + while self.bits < bits: + c = self.next() + if c < 0: + self.bits = 0 + continue + self.bitbuffer = (self.bitbuffer << 8) + c + self.bits += 8 + return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1 + + def skip(self, bits: int) -> None: + while self.bits < bits: + self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1)) + self.bits += 8 + self.bits = self.bits - bits + + def read(self, bits: int) -> int: + v = self.peek(bits) + self.bits = self.bits - bits + return v + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"\x00\x00\x01\xb3" + + +## +# Image plugin for MPEG streams. This plugin can identify a stream, +# but it cannot read it. + + +class MpegImageFile(ImageFile.ImageFile): + format = "MPEG" + format_description = "MPEG" + + def _open(self) -> None: + assert self.fp is not None + + s = BitStream(self.fp) + if s.read(32) != 0x1B3: + msg = "not an MPEG file" + raise SyntaxError(msg) + + self._mode = "RGB" + self._size = s.read(12), s.read(12) + + +# -------------------------------------------------------------------- +# Registry stuff + +Image.register_open(MpegImageFile.format, MpegImageFile, _accept) + +Image.register_extensions(MpegImageFile.format, [".mpg", ".mpeg"]) + +Image.register_mime(MpegImageFile.format, "video/mpeg") diff --git a/.venv/lib/python3.12/site-packages/PIL/MpoImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/MpoImagePlugin.py new file mode 100644 index 0000000..f215706 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/MpoImagePlugin.py @@ -0,0 +1,180 @@ +# +# The Python Imaging Library. +# $Id$ +# +# MPO file handling +# +# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the +# Camera & Imaging Products Association) +# +# The multi-picture object combines multiple JPEG images (with a modified EXIF +# data format) into a single file. While it can theoretically be used much like +# a GIF animation, it is commonly used to represent 3D photographs and is (as +# of this writing) the most commonly used format by 3D cameras. +# +# History: +# 2014-03-13 Feneric Created +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import itertools +import os +import struct +from typing import IO + +from . import ( + Image, + ImageSequence, + JpegImagePlugin, + TiffImagePlugin, +) +from ._binary import o32le + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + JpegImagePlugin._save(im, fp, filename) + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + append_images = im.encoderinfo.get("append_images", []) + if not append_images and not getattr(im, "is_animated", False): + _save(im, fp, filename) + return + + mpf_offset = 28 + offsets: list[int] = [] + for imSequence in itertools.chain([im], append_images): + for im_frame in ImageSequence.Iterator(imSequence): + if not offsets: + # APP2 marker + im_frame.encoderinfo["extra"] = ( + b"\xFF\xE2" + struct.pack(">H", 6 + 82) + b"MPF\0" + b" " * 82 + ) + exif = im_frame.encoderinfo.get("exif") + if isinstance(exif, Image.Exif): + exif = exif.tobytes() + im_frame.encoderinfo["exif"] = exif + if exif: + mpf_offset += 4 + len(exif) + + JpegImagePlugin._save(im_frame, fp, filename) + offsets.append(fp.tell()) + else: + im_frame.save(fp, "JPEG") + offsets.append(fp.tell() - offsets[-1]) + + ifd = TiffImagePlugin.ImageFileDirectory_v2() + ifd[0xB000] = b"0100" + ifd[0xB001] = len(offsets) + + mpentries = b"" + data_offset = 0 + for i, size in enumerate(offsets): + if i == 0: + mptype = 0x030000 # Baseline MP Primary Image + else: + mptype = 0x000000 # Undefined + mpentries += struct.pack(" None: + self.fp.seek(0) # prep the fp in order to pass the JPEG test + JpegImagePlugin.JpegImageFile._open(self) + self._after_jpeg_open() + + def _after_jpeg_open(self, mpheader=None): + self.mpinfo = mpheader if mpheader is not None else self._getmp() + self.n_frames = self.mpinfo[0xB001] + self.__mpoffsets = [ + mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002] + ] + self.__mpoffsets[0] = 0 + # Note that the following assertion will only be invalid if something + # gets broken within JpegImagePlugin. + assert self.n_frames == len(self.__mpoffsets) + del self.info["mpoffset"] # no longer needed + self.is_animated = self.n_frames > 1 + self._fp = self.fp # FIXME: hack + self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame + self.__frame = 0 + self.offset = 0 + # for now we can only handle reading and individual frame extraction + self.readonly = 1 + + def load_seek(self, pos: int) -> None: + self._fp.seek(pos) + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + self.fp = self._fp + self.offset = self.__mpoffsets[frame] + + original_exif = self.info.get("exif") + if "exif" in self.info: + del self.info["exif"] + + self.fp.seek(self.offset + 2) # skip SOI marker + if not self.fp.read(2): + msg = "No data found for frame" + raise ValueError(msg) + self.fp.seek(self.offset) + JpegImagePlugin.JpegImageFile._open(self) + if self.info.get("exif") != original_exif: + self._reload_exif() + + self.tile = [("jpeg", (0, 0) + self.size, self.offset, self.tile[0][-1])] + self.__frame = frame + + def tell(self) -> int: + return self.__frame + + @staticmethod + def adopt(jpeg_instance, mpheader=None): + """ + Transform the instance of JpegImageFile into + an instance of MpoImageFile. + After the call, the JpegImageFile is extended + to be an MpoImageFile. + + This is essentially useful when opening a JPEG + file that reveals itself as an MPO, to avoid + double call to _open. + """ + jpeg_instance.__class__ = MpoImageFile + jpeg_instance._after_jpeg_open(mpheader) + return jpeg_instance + + +# --------------------------------------------------------------------- +# Registry stuff + +# Note that since MPO shares a factory with JPEG, we do not need to do a +# separate registration for it here. +# Image.register_open(MpoImageFile.format, +# JpegImagePlugin.jpeg_factory, _accept) +Image.register_save(MpoImageFile.format, _save) +Image.register_save_all(MpoImageFile.format, _save_all) + +Image.register_extension(MpoImageFile.format, ".mpo") + +Image.register_mime(MpoImageFile.format, "image/mpo") diff --git a/.venv/lib/python3.12/site-packages/PIL/MspImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/MspImagePlugin.py new file mode 100644 index 0000000..0a75c86 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/MspImagePlugin.py @@ -0,0 +1,200 @@ +# +# The Python Imaging Library. +# +# MSP file handling +# +# This is the format used by the Paint program in Windows 1 and 2. +# +# History: +# 95-09-05 fl Created +# 97-01-03 fl Read/write MSP images +# 17-02-21 es Fixed RLE interpretation +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1995-97. +# Copyright (c) Eric Soroos 2017. +# +# See the README file for information on usage and redistribution. +# +# More info on this format: https://archive.org/details/gg243631 +# Page 313: +# Figure 205. Windows Paint Version 1: "DanM" Format +# Figure 206. Windows Paint Version 2: "LinS" Format. Used in Windows V2.03 +# +# See also: https://www.fileformat.info/format/mspaint/egff.htm +from __future__ import annotations + +import io +import struct +from typing import IO + +from . import Image, ImageFile +from ._binary import i16le as i16 +from ._binary import o16le as o16 + +# +# read MSP files + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] in [b"DanM", b"LinS"] + + +## +# Image plugin for Windows MSP images. This plugin supports both +# uncompressed (Windows 1.0). + + +class MspImageFile(ImageFile.ImageFile): + format = "MSP" + format_description = "Windows Paint" + + def _open(self) -> None: + # Header + assert self.fp is not None + + s = self.fp.read(32) + if not _accept(s): + msg = "not an MSP file" + raise SyntaxError(msg) + + # Header checksum + checksum = 0 + for i in range(0, 32, 2): + checksum = checksum ^ i16(s, i) + if checksum != 0: + msg = "bad MSP checksum" + raise SyntaxError(msg) + + self._mode = "1" + self._size = i16(s, 4), i16(s, 6) + + if s[:4] == b"DanM": + self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))] + else: + self.tile = [("MSP", (0, 0) + self.size, 32, None)] + + +class MspDecoder(ImageFile.PyDecoder): + # The algo for the MSP decoder is from + # https://www.fileformat.info/format/mspaint/egff.htm + # cc-by-attribution -- That page references is taken from the + # Encyclopedia of Graphics File Formats and is licensed by + # O'Reilly under the Creative Common/Attribution license + # + # For RLE encoded files, the 32byte header is followed by a scan + # line map, encoded as one 16bit word of encoded byte length per + # line. + # + # NOTE: the encoded length of the line can be 0. This was not + # handled in the previous version of this encoder, and there's no + # mention of how to handle it in the documentation. From the few + # examples I've seen, I've assumed that it is a fill of the + # background color, in this case, white. + # + # + # Pseudocode of the decoder: + # Read a BYTE value as the RunType + # If the RunType value is zero + # Read next byte as the RunCount + # Read the next byte as the RunValue + # Write the RunValue byte RunCount times + # If the RunType value is non-zero + # Use this value as the RunCount + # Read and write the next RunCount bytes literally + # + # e.g.: + # 0x00 03 ff 05 00 01 02 03 04 + # would yield the bytes: + # 0xff ff ff 00 01 02 03 04 + # + # which are then interpreted as a bit packed mode '1' image + + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + + img = io.BytesIO() + blank_line = bytearray((0xFF,) * ((self.state.xsize + 7) // 8)) + try: + self.fd.seek(32) + rowmap = struct.unpack_from( + f"<{self.state.ysize}H", self.fd.read(self.state.ysize * 2) + ) + except struct.error as e: + msg = "Truncated MSP file in row map" + raise OSError(msg) from e + + for x, rowlen in enumerate(rowmap): + try: + if rowlen == 0: + img.write(blank_line) + continue + row = self.fd.read(rowlen) + if len(row) != rowlen: + msg = f"Truncated MSP file, expected {rowlen} bytes on row {x}" + raise OSError(msg) + idx = 0 + while idx < rowlen: + runtype = row[idx] + idx += 1 + if runtype == 0: + (runcount, runval) = struct.unpack_from("Bc", row, idx) + img.write(runval * runcount) + idx += 2 + else: + runcount = runtype + img.write(row[idx : idx + runcount]) + idx += runcount + + except struct.error as e: + msg = f"Corrupted MSP file in row {x}" + raise OSError(msg) from e + + self.set_as_raw(img.getvalue(), ("1", 0, 1)) + + return -1, 0 + + +Image.register_decoder("MSP", MspDecoder) + + +# +# write MSP files (uncompressed only) + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode != "1": + msg = f"cannot write mode {im.mode} as MSP" + raise OSError(msg) + + # create MSP header + header = [0] * 16 + + header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1 + header[2], header[3] = im.size + header[4], header[5] = 1, 1 + header[6], header[7] = 1, 1 + header[8], header[9] = im.size + + checksum = 0 + for h in header: + checksum = checksum ^ h + header[12] = checksum # FIXME: is this the right field? + + # header + for h in header: + fp.write(o16(h)) + + # image body + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))]) + + +# +# registry + +Image.register_open(MspImageFile.format, MspImageFile, _accept) +Image.register_save(MspImageFile.format, _save) + +Image.register_extension(MspImageFile.format, ".msp") diff --git a/.venv/lib/python3.12/site-packages/PIL/PSDraw.py b/.venv/lib/python3.12/site-packages/PIL/PSDraw.py new file mode 100644 index 0000000..673eae1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PSDraw.py @@ -0,0 +1,237 @@ +# +# The Python Imaging Library +# $Id$ +# +# Simple PostScript graphics interface +# +# History: +# 1996-04-20 fl Created +# 1999-01-10 fl Added gsave/grestore to image method +# 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge) +# +# Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved. +# Copyright (c) 1996 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import sys +from typing import TYPE_CHECKING + +from . import EpsImagePlugin + +## +# Simple PostScript graphics interface. + + +class PSDraw: + """ + Sets up printing to the given file. If ``fp`` is omitted, + ``sys.stdout.buffer`` or ``sys.stdout`` is assumed. + """ + + def __init__(self, fp=None): + if not fp: + try: + fp = sys.stdout.buffer + except AttributeError: + fp = sys.stdout + self.fp = fp + + def begin_document(self, id: str | None = None) -> None: + """Set up printing of a document. (Write PostScript DSC header.)""" + # FIXME: incomplete + self.fp.write( + b"%!PS-Adobe-3.0\n" + b"save\n" + b"/showpage { } def\n" + b"%%EndComments\n" + b"%%BeginDocument\n" + ) + # self.fp.write(ERROR_PS) # debugging! + self.fp.write(EDROFF_PS) + self.fp.write(VDI_PS) + self.fp.write(b"%%EndProlog\n") + self.isofont: dict[bytes, int] = {} + + def end_document(self) -> None: + """Ends printing. (Write PostScript DSC footer.)""" + self.fp.write(b"%%EndDocument\nrestore showpage\n%%End\n") + if hasattr(self.fp, "flush"): + self.fp.flush() + + def setfont(self, font: str, size: int) -> None: + """ + Selects which font to use. + + :param font: A PostScript font name + :param size: Size in points. + """ + font_bytes = bytes(font, "UTF-8") + if font_bytes not in self.isofont: + # reencode font + self.fp.write( + b"/PSDraw-%s ISOLatin1Encoding /%s E\n" % (font_bytes, font_bytes) + ) + self.isofont[font_bytes] = 1 + # rough + self.fp.write(b"/F0 %d /PSDraw-%s F\n" % (size, font_bytes)) + + def line(self, xy0: tuple[int, int], xy1: tuple[int, int]) -> None: + """ + Draws a line between the two points. Coordinates are given in + PostScript point coordinates (72 points per inch, (0, 0) is the lower + left corner of the page). + """ + self.fp.write(b"%d %d %d %d Vl\n" % (*xy0, *xy1)) + + def rectangle(self, box: tuple[int, int, int, int]) -> None: + """ + Draws a rectangle. + + :param box: A tuple of four integers, specifying left, bottom, width and + height. + """ + self.fp.write(b"%d %d M 0 %d %d Vr\n" % box) + + def text(self, xy: tuple[int, int], text: str) -> None: + """ + Draws text at the given position. You must use + :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method. + """ + text_bytes = bytes(text, "UTF-8") + text_bytes = b"\\(".join(text_bytes.split(b"(")) + text_bytes = b"\\)".join(text_bytes.split(b")")) + self.fp.write(b"%d %d M (%s) S\n" % (xy + (text_bytes,))) + + if TYPE_CHECKING: + from . import Image + + def image( + self, box: tuple[int, int, int, int], im: Image.Image, dpi: int | None = None + ) -> None: + """Draw a PIL image, centered in the given box.""" + # default resolution depends on mode + if not dpi: + if im.mode == "1": + dpi = 200 # fax + else: + dpi = 100 # grayscale + # image size (on paper) + x = im.size[0] * 72 / dpi + y = im.size[1] * 72 / dpi + # max allowed size + xmax = float(box[2] - box[0]) + ymax = float(box[3] - box[1]) + if x > xmax: + y = y * xmax / x + x = xmax + if y > ymax: + x = x * ymax / y + y = ymax + dx = (xmax - x) / 2 + box[0] + dy = (ymax - y) / 2 + box[1] + self.fp.write(b"gsave\n%f %f translate\n" % (dx, dy)) + if (x, y) != im.size: + # EpsImagePlugin._save prints the image at (0,0,xsize,ysize) + sx = x / im.size[0] + sy = y / im.size[1] + self.fp.write(b"%f %f scale\n" % (sx, sy)) + EpsImagePlugin._save(im, self.fp, "", 0) + self.fp.write(b"\ngrestore\n") + + +# -------------------------------------------------------------------- +# PostScript driver + +# +# EDROFF.PS -- PostScript driver for Edroff 2 +# +# History: +# 94-01-25 fl: created (edroff 2.04) +# +# Copyright (c) Fredrik Lundh 1994. +# + + +EDROFF_PS = b"""\ +/S { show } bind def +/P { moveto show } bind def +/M { moveto } bind def +/X { 0 rmoveto } bind def +/Y { 0 exch rmoveto } bind def +/E { findfont + dup maxlength dict begin + { + 1 index /FID ne { def } { pop pop } ifelse + } forall + /Encoding exch def + dup /FontName exch def + currentdict end definefont pop +} bind def +/F { findfont exch scalefont dup setfont + [ exch /setfont cvx ] cvx bind def +} bind def +""" + +# +# VDI.PS -- PostScript driver for VDI meta commands +# +# History: +# 94-01-25 fl: created (edroff 2.04) +# +# Copyright (c) Fredrik Lundh 1994. +# + +VDI_PS = b"""\ +/Vm { moveto } bind def +/Va { newpath arcn stroke } bind def +/Vl { moveto lineto stroke } bind def +/Vc { newpath 0 360 arc closepath } bind def +/Vr { exch dup 0 rlineto + exch dup 0 exch rlineto + exch neg 0 rlineto + 0 exch neg rlineto + setgray fill } bind def +/Tm matrix def +/Ve { Tm currentmatrix pop + translate scale newpath 0 0 .5 0 360 arc closepath + Tm setmatrix +} bind def +/Vf { currentgray exch setgray fill setgray } bind def +""" + +# +# ERROR.PS -- Error handler +# +# History: +# 89-11-21 fl: created (pslist 1.10) +# + +ERROR_PS = b"""\ +/landscape false def +/errorBUF 200 string def +/errorNL { currentpoint 10 sub exch pop 72 exch moveto } def +errordict begin /handleerror { + initmatrix /Courier findfont 10 scalefont setfont + newpath 72 720 moveto $error begin /newerror false def + (PostScript Error) show errorNL errorNL + (Error: ) show + /errorname load errorBUF cvs show errorNL errorNL + (Command: ) show + /command load dup type /stringtype ne { errorBUF cvs } if show + errorNL errorNL + (VMstatus: ) show + vmstatus errorBUF cvs show ( bytes available, ) show + errorBUF cvs show ( bytes used at level ) show + errorBUF cvs show errorNL errorNL + (Operand stargck: ) show errorNL /ostargck load { + dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL + } forall errorNL + (Execution stargck: ) show errorNL /estargck load { + dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL + } forall + end showpage +} def end +""" diff --git a/.venv/lib/python3.12/site-packages/PIL/PaletteFile.py b/.venv/lib/python3.12/site-packages/PIL/PaletteFile.py new file mode 100644 index 0000000..81652e5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PaletteFile.py @@ -0,0 +1,54 @@ +# +# Python Imaging Library +# $Id$ +# +# stuff to read simple, teragon-style palette files +# +# History: +# 97-08-23 fl Created +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from typing import IO + +from ._binary import o8 + + +class PaletteFile: + """File handler for Teragon-style palette files.""" + + rawmode = "RGB" + + def __init__(self, fp: IO[bytes]) -> None: + palette = [o8(i) * 3 for i in range(256)] + + while True: + s = fp.readline() + + if not s: + break + if s[:1] == b"#": + continue + if len(s) > 100: + msg = "bad palette file" + raise SyntaxError(msg) + + v = [int(x) for x in s.split()] + try: + [i, r, g, b] = v + except ValueError: + [i, r] = v + g = b = r + + if 0 <= i <= 255: + palette[i] = o8(r) + o8(g) + o8(b) + + self.palette = b"".join(palette) + + def getpalette(self) -> tuple[bytes, str]: + return self.palette, self.rawmode diff --git a/.venv/lib/python3.12/site-packages/PIL/PalmImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PalmImagePlugin.py new file mode 100644 index 0000000..1735070 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PalmImagePlugin.py @@ -0,0 +1,229 @@ +# +# The Python Imaging Library. +# $Id$ +# + +## +# Image plugin for Palm pixmap images (output only). +## +from __future__ import annotations + +from typing import IO + +from . import Image, ImageFile +from ._binary import o8 +from ._binary import o16be as o16b + +# fmt: off +_Palm8BitColormapValues = ( + (255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255), + (255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204), + (255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204), + (255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153), + (255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255), + (204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255), + (204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204), + (204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153), + (204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153), + (153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255), + (153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204), + (153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204), + (153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153), + (153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255), + (102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255), + (102, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204), + (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153), + (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153), + (51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255), + (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204), + (51, 153, 204), (51, 102, 204), (51, 51, 204), (51, 0, 204), + (51, 255, 153), (51, 204, 153), (51, 153, 153), (51, 102, 153), + (51, 51, 153), (51, 0, 153), (0, 255, 255), (0, 204, 255), + (0, 153, 255), (0, 102, 255), (0, 51, 255), (0, 0, 255), + (0, 255, 204), (0, 204, 204), (0, 153, 204), (0, 102, 204), + (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153), + (0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153), + (255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102), + (255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51), + (255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51), + (255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0), + (255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102), + (204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102), + (204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51), + (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0), + (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), + (153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102), + (153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51), + (153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51), + (153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0), + (153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102), + (102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102), + (102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51), + (102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0), + (102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0), + (51, 255, 102), (51, 204, 102), (51, 153, 102), (51, 102, 102), + (51, 51, 102), (51, 0, 102), (51, 255, 51), (51, 204, 51), + (51, 153, 51), (51, 102, 51), (51, 51, 51), (51, 0, 51), + (51, 255, 0), (51, 204, 0), (51, 153, 0), (51, 102, 0), + (51, 51, 0), (51, 0, 0), (0, 255, 102), (0, 204, 102), + (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102), + (0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51), + (0, 51, 51), (0, 0, 51), (0, 255, 0), (0, 204, 0), + (0, 153, 0), (0, 102, 0), (0, 51, 0), (17, 17, 17), + (34, 34, 34), (68, 68, 68), (85, 85, 85), (119, 119, 119), + (136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221), + (238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128), + (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), + (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)) +# fmt: on + + +# so build a prototype image to be used for palette resampling +def build_prototype_image() -> Image.Image: + image = Image.new("L", (1, len(_Palm8BitColormapValues))) + image.putdata(list(range(len(_Palm8BitColormapValues)))) + palettedata: tuple[int, ...] = () + for colormapValue in _Palm8BitColormapValues: + palettedata += colormapValue + palettedata += (0, 0, 0) * (256 - len(_Palm8BitColormapValues)) + image.putpalette(palettedata) + return image + + +Palm8BitColormapImage = build_prototype_image() + +# OK, we now have in Palm8BitColormapImage, +# a "P"-mode image with the right palette +# +# -------------------------------------------------------------------- + +_FLAGS = {"custom-colormap": 0x4000, "is-compressed": 0x8000, "has-transparent": 0x2000} + +_COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00} + + +# +# -------------------------------------------------------------------- + +## +# (Internal) Image save plugin for the Palm format. + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode == "P": + # we assume this is a color Palm image with the standard colormap, + # unless the "info" dict has a "custom-colormap" field + + rawmode = "P" + bpp = 8 + version = 1 + + elif im.mode == "L": + if im.encoderinfo.get("bpp") in (1, 2, 4): + # this is 8-bit grayscale, so we shift it to get the high-order bits, + # and invert it because + # Palm does grayscale from white (0) to black (1) + bpp = im.encoderinfo["bpp"] + maxval = (1 << bpp) - 1 + shift = 8 - bpp + im = im.point(lambda x: maxval - (x >> shift)) + elif im.info.get("bpp") in (1, 2, 4): + # here we assume that even though the inherent mode is 8-bit grayscale, + # only the lower bpp bits are significant. + # We invert them to match the Palm. + bpp = im.info["bpp"] + maxval = (1 << bpp) - 1 + im = im.point(lambda x: maxval - (x & maxval)) + else: + msg = f"cannot write mode {im.mode} as Palm" + raise OSError(msg) + + # we ignore the palette here + im._mode = "P" + rawmode = f"P;{bpp}" + version = 1 + + elif im.mode == "1": + # monochrome -- write it inverted, as is the Palm standard + rawmode = "1;I" + bpp = 1 + version = 0 + + else: + msg = f"cannot write mode {im.mode} as Palm" + raise OSError(msg) + + # + # make sure image data is available + im.load() + + # write header + + cols = im.size[0] + rows = im.size[1] + + rowbytes = int((cols + (16 // bpp - 1)) / (16 // bpp)) * 2 + transparent_index = 0 + compression_type = _COMPRESSION_TYPES["none"] + + flags = 0 + if im.mode == "P" and "custom-colormap" in im.info: + flags = flags & _FLAGS["custom-colormap"] + colormapsize = 4 * 256 + 2 + colormapmode = im.palette.mode + colormap = im.getdata().getpalette() + else: + colormapsize = 0 + + if "offset" in im.info: + offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4 + else: + offset = 0 + + fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags)) + fp.write(o8(bpp)) + fp.write(o8(version)) + fp.write(o16b(offset)) + fp.write(o8(transparent_index)) + fp.write(o8(compression_type)) + fp.write(o16b(0)) # reserved by Palm + + # now write colormap if necessary + + if colormapsize > 0: + fp.write(o16b(256)) + for i in range(256): + fp.write(o8(i)) + if colormapmode == "RGB": + fp.write( + o8(colormap[3 * i]) + + o8(colormap[3 * i + 1]) + + o8(colormap[3 * i + 2]) + ) + elif colormapmode == "RGBA": + fp.write( + o8(colormap[4 * i]) + + o8(colormap[4 * i + 1]) + + o8(colormap[4 * i + 2]) + ) + + # now convert data to raw form + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))]) + + if hasattr(fp, "flush"): + fp.flush() + + +# +# -------------------------------------------------------------------- + +Image.register_save("Palm", _save) + +Image.register_extension("Palm", ".palm") + +Image.register_mime("Palm", "image/palm") diff --git a/.venv/lib/python3.12/site-packages/PIL/PcdImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PcdImagePlugin.py new file mode 100644 index 0000000..1cd5c4a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PcdImagePlugin.py @@ -0,0 +1,66 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PCD file handling +# +# History: +# 96-05-10 fl Created +# 96-05-27 fl Added draft mode (128x192, 256x384) +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image, ImageFile + +## +# Image plugin for PhotoCD images. This plugin only reads the 768x512 +# image from the file; higher resolutions are encoded in a proprietary +# encoding. + + +class PcdImageFile(ImageFile.ImageFile): + format = "PCD" + format_description = "Kodak PhotoCD" + + def _open(self) -> None: + # rough + assert self.fp is not None + + self.fp.seek(2048) + s = self.fp.read(2048) + + if s[:4] != b"PCD_": + msg = "not a PCD file" + raise SyntaxError(msg) + + orientation = s[1538] & 3 + self.tile_post_rotate = None + if orientation == 1: + self.tile_post_rotate = 90 + elif orientation == 3: + self.tile_post_rotate = -90 + + self._mode = "RGB" + self._size = 768, 512 # FIXME: not correct for rotated images! + self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)] + + def load_end(self) -> None: + if self.tile_post_rotate: + # Handle rotated PCDs + assert self.im is not None + + self.im = self.im.rotate(self.tile_post_rotate) + self._size = self.im.size + + +# +# registry + +Image.register_open(PcdImageFile.format, PcdImageFile) + +Image.register_extension(PcdImageFile.format, ".pcd") diff --git a/.venv/lib/python3.12/site-packages/PIL/PcfFontFile.py b/.venv/lib/python3.12/site-packages/PIL/PcfFontFile.py new file mode 100644 index 0000000..0d1968b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PcfFontFile.py @@ -0,0 +1,254 @@ +# +# THIS IS WORK IN PROGRESS +# +# The Python Imaging Library +# $Id$ +# +# portable compiled font file parser +# +# history: +# 1997-08-19 fl created +# 2003-09-13 fl fixed loading of unicode fonts +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1997-2003 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +from typing import BinaryIO, Callable + +from . import FontFile, Image +from ._binary import i8 +from ._binary import i16be as b16 +from ._binary import i16le as l16 +from ._binary import i32be as b32 +from ._binary import i32le as l32 + +# -------------------------------------------------------------------- +# declarations + +PCF_MAGIC = 0x70636601 # "\x01fcp" + +PCF_PROPERTIES = 1 << 0 +PCF_ACCELERATORS = 1 << 1 +PCF_METRICS = 1 << 2 +PCF_BITMAPS = 1 << 3 +PCF_INK_METRICS = 1 << 4 +PCF_BDF_ENCODINGS = 1 << 5 +PCF_SWIDTHS = 1 << 6 +PCF_GLYPH_NAMES = 1 << 7 +PCF_BDF_ACCELERATORS = 1 << 8 + +BYTES_PER_ROW: list[Callable[[int], int]] = [ + lambda bits: ((bits + 7) >> 3), + lambda bits: ((bits + 15) >> 3) & ~1, + lambda bits: ((bits + 31) >> 3) & ~3, + lambda bits: ((bits + 63) >> 3) & ~7, +] + + +def sz(s: bytes, o: int) -> bytes: + return s[o : s.index(b"\0", o)] + + +class PcfFontFile(FontFile.FontFile): + """Font file plugin for the X11 PCF format.""" + + name = "name" + + def __init__(self, fp: BinaryIO, charset_encoding: str = "iso8859-1"): + self.charset_encoding = charset_encoding + + magic = l32(fp.read(4)) + if magic != PCF_MAGIC: + msg = "not a PCF file" + raise SyntaxError(msg) + + super().__init__() + + count = l32(fp.read(4)) + self.toc = {} + for i in range(count): + type = l32(fp.read(4)) + self.toc[type] = l32(fp.read(4)), l32(fp.read(4)), l32(fp.read(4)) + + self.fp = fp + + self.info = self._load_properties() + + metrics = self._load_metrics() + bitmaps = self._load_bitmaps(metrics) + encoding = self._load_encoding() + + # + # create glyph structure + + for ch, ix in enumerate(encoding): + if ix is not None: + ( + xsize, + ysize, + left, + right, + width, + ascent, + descent, + attributes, + ) = metrics[ix] + self.glyph[ch] = ( + (width, 0), + (left, descent - ysize, xsize + left, descent), + (0, 0, xsize, ysize), + bitmaps[ix], + ) + + def _getformat( + self, tag: int + ) -> tuple[BinaryIO, int, Callable[[bytes], int], Callable[[bytes], int]]: + format, size, offset = self.toc[tag] + + fp = self.fp + fp.seek(offset) + + format = l32(fp.read(4)) + + if format & 4: + i16, i32 = b16, b32 + else: + i16, i32 = l16, l32 + + return fp, format, i16, i32 + + def _load_properties(self) -> dict[bytes, bytes | int]: + # + # font properties + + properties = {} + + fp, format, i16, i32 = self._getformat(PCF_PROPERTIES) + + nprops = i32(fp.read(4)) + + # read property description + p = [(i32(fp.read(4)), i8(fp.read(1)), i32(fp.read(4))) for _ in range(nprops)] + + if nprops & 3: + fp.seek(4 - (nprops & 3), io.SEEK_CUR) # pad + + data = fp.read(i32(fp.read(4))) + + for k, s, v in p: + property_value: bytes | int = sz(data, v) if s else v + properties[sz(data, k)] = property_value + + return properties + + def _load_metrics(self) -> list[tuple[int, int, int, int, int, int, int, int]]: + # + # font metrics + + metrics: list[tuple[int, int, int, int, int, int, int, int]] = [] + + fp, format, i16, i32 = self._getformat(PCF_METRICS) + + append = metrics.append + + if (format & 0xFF00) == 0x100: + # "compressed" metrics + for i in range(i16(fp.read(2))): + left = i8(fp.read(1)) - 128 + right = i8(fp.read(1)) - 128 + width = i8(fp.read(1)) - 128 + ascent = i8(fp.read(1)) - 128 + descent = i8(fp.read(1)) - 128 + xsize = right - left + ysize = ascent + descent + append((xsize, ysize, left, right, width, ascent, descent, 0)) + + else: + # "jumbo" metrics + for i in range(i32(fp.read(4))): + left = i16(fp.read(2)) + right = i16(fp.read(2)) + width = i16(fp.read(2)) + ascent = i16(fp.read(2)) + descent = i16(fp.read(2)) + attributes = i16(fp.read(2)) + xsize = right - left + ysize = ascent + descent + append((xsize, ysize, left, right, width, ascent, descent, attributes)) + + return metrics + + def _load_bitmaps( + self, metrics: list[tuple[int, int, int, int, int, int, int, int]] + ) -> list[Image.Image]: + # + # bitmap data + + fp, format, i16, i32 = self._getformat(PCF_BITMAPS) + + nbitmaps = i32(fp.read(4)) + + if nbitmaps != len(metrics): + msg = "Wrong number of bitmaps" + raise OSError(msg) + + offsets = [i32(fp.read(4)) for _ in range(nbitmaps)] + + bitmap_sizes = [i32(fp.read(4)) for _ in range(4)] + + # byteorder = format & 4 # non-zero => MSB + bitorder = format & 8 # non-zero => MSB + padindex = format & 3 + + bitmapsize = bitmap_sizes[padindex] + offsets.append(bitmapsize) + + data = fp.read(bitmapsize) + + pad = BYTES_PER_ROW[padindex] + mode = "1;R" + if bitorder: + mode = "1" + + bitmaps = [] + for i in range(nbitmaps): + xsize, ysize = metrics[i][:2] + b, e = offsets[i : i + 2] + bitmaps.append( + Image.frombytes("1", (xsize, ysize), data[b:e], "raw", mode, pad(xsize)) + ) + + return bitmaps + + def _load_encoding(self) -> list[int | None]: + fp, format, i16, i32 = self._getformat(PCF_BDF_ENCODINGS) + + first_col, last_col = i16(fp.read(2)), i16(fp.read(2)) + first_row, last_row = i16(fp.read(2)), i16(fp.read(2)) + + i16(fp.read(2)) # default + + nencoding = (last_col - first_col + 1) * (last_row - first_row + 1) + + # map character code to bitmap index + encoding: list[int | None] = [None] * min(256, nencoding) + + encoding_offsets = [i16(fp.read(2)) for _ in range(nencoding)] + + for i in range(first_col, len(encoding)): + try: + encoding_offset = encoding_offsets[ + ord(bytearray([i]).decode(self.charset_encoding)) + ] + if encoding_offset != 0xFFFF: + encoding[i] = encoding_offset + except UnicodeDecodeError: + # character is not supported in selected encoding + pass + + return encoding diff --git a/.venv/lib/python3.12/site-packages/PIL/PcxImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PcxImagePlugin.py new file mode 100644 index 0000000..dd42003 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PcxImagePlugin.py @@ -0,0 +1,227 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PCX file handling +# +# This format was originally used by ZSoft's popular PaintBrush +# program for the IBM PC. It is also supported by many MS-DOS and +# Windows applications, including the Windows PaintBrush program in +# Windows 3. +# +# history: +# 1995-09-01 fl Created +# 1996-05-20 fl Fixed RGB support +# 1997-01-03 fl Fixed 2-bit and 4-bit support +# 1999-02-03 fl Fixed 8-bit support (broken in 1.0b1) +# 1999-02-07 fl Added write support +# 2002-06-09 fl Made 2-bit and 4-bit support a bit more robust +# 2002-07-30 fl Seek from to current position, not beginning of file +# 2003-06-03 fl Extract DPI settings (info["dpi"]) +# +# Copyright (c) 1997-2003 by Secret Labs AB. +# Copyright (c) 1995-2003 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import logging +from typing import IO + +from . import Image, ImageFile, ImagePalette +from ._binary import i16le as i16 +from ._binary import o8 +from ._binary import o16le as o16 + +logger = logging.getLogger(__name__) + + +def _accept(prefix: bytes) -> bool: + return prefix[0] == 10 and prefix[1] in [0, 2, 3, 5] + + +## +# Image plugin for Paintbrush images. + + +class PcxImageFile(ImageFile.ImageFile): + format = "PCX" + format_description = "Paintbrush" + + def _open(self) -> None: + # header + assert self.fp is not None + + s = self.fp.read(128) + if not _accept(s): + msg = "not a PCX file" + raise SyntaxError(msg) + + # image + bbox = i16(s, 4), i16(s, 6), i16(s, 8) + 1, i16(s, 10) + 1 + if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]: + msg = "bad PCX image size" + raise SyntaxError(msg) + logger.debug("BBox: %s %s %s %s", *bbox) + + # format + version = s[1] + bits = s[3] + planes = s[65] + provided_stride = i16(s, 66) + logger.debug( + "PCX version %s, bits %s, planes %s, stride %s", + version, + bits, + planes, + provided_stride, + ) + + self.info["dpi"] = i16(s, 12), i16(s, 14) + + if bits == 1 and planes == 1: + mode = rawmode = "1" + + elif bits == 1 and planes in (2, 4): + mode = "P" + rawmode = "P;%dL" % planes + self.palette = ImagePalette.raw("RGB", s[16:64]) + + elif version == 5 and bits == 8 and planes == 1: + mode = rawmode = "L" + # FIXME: hey, this doesn't work with the incremental loader !!! + self.fp.seek(-769, io.SEEK_END) + s = self.fp.read(769) + if len(s) == 769 and s[0] == 12: + # check if the palette is linear grayscale + for i in range(256): + if s[i * 3 + 1 : i * 3 + 4] != o8(i) * 3: + mode = rawmode = "P" + break + if mode == "P": + self.palette = ImagePalette.raw("RGB", s[1:]) + self.fp.seek(128) + + elif version == 5 and bits == 8 and planes == 3: + mode = "RGB" + rawmode = "RGB;L" + + else: + msg = "unknown PCX mode" + raise OSError(msg) + + self._mode = mode + self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] + + # Don't trust the passed in stride. + # Calculate the approximate position for ourselves. + # CVE-2020-35653 + stride = (self._size[0] * bits + 7) // 8 + + # While the specification states that this must be even, + # not all images follow this + if provided_stride != stride: + stride += stride % 2 + + bbox = (0, 0) + self.size + logger.debug("size: %sx%s", *self.size) + + self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))] + + +# -------------------------------------------------------------------- +# save PCX files + + +SAVE = { + # mode: (version, bits, planes, raw mode) + "1": (2, 1, 1, "1"), + "L": (5, 8, 1, "L"), + "P": (5, 8, 1, "P"), + "RGB": (5, 8, 3, "RGB;L"), +} + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + try: + version, bits, planes, rawmode = SAVE[im.mode] + except KeyError as e: + msg = f"Cannot save {im.mode} images as PCX" + raise ValueError(msg) from e + + # bytes per plane + stride = (im.size[0] * bits + 7) // 8 + # stride should be even + stride += stride % 2 + # Stride needs to be kept in sync with the PcxEncode.c version. + # Ideally it should be passed in in the state, but the bytes value + # gets overwritten. + + logger.debug( + "PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d", + im.size[0], + bits, + stride, + ) + + # under windows, we could determine the current screen size with + # "Image.core.display_mode()[1]", but I think that's overkill... + + screen = im.size + + dpi = 100, 100 + + # PCX header + fp.write( + o8(10) + + o8(version) + + o8(1) + + o8(bits) + + o16(0) + + o16(0) + + o16(im.size[0] - 1) + + o16(im.size[1] - 1) + + o16(dpi[0]) + + o16(dpi[1]) + + b"\0" * 24 + + b"\xFF" * 24 + + b"\0" + + o8(planes) + + o16(stride) + + o16(1) + + o16(screen[0]) + + o16(screen[1]) + + b"\0" * 54 + ) + + assert fp.tell() == 128 + + ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))]) + + if im.mode == "P": + # colour palette + assert im.im is not None + + fp.write(o8(12)) + palette = im.im.getpalette("RGB", "RGB") + palette += b"\x00" * (768 - len(palette)) + fp.write(palette) # 768 bytes + elif im.mode == "L": + # grayscale palette + fp.write(o8(12)) + for i in range(256): + fp.write(o8(i) * 3) + + +# -------------------------------------------------------------------- +# registry + + +Image.register_open(PcxImageFile.format, PcxImageFile, _accept) +Image.register_save(PcxImageFile.format, _save) + +Image.register_extension(PcxImageFile.format, ".pcx") + +Image.register_mime(PcxImageFile.format, "image/x-pcx") diff --git a/.venv/lib/python3.12/site-packages/PIL/PdfImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PdfImagePlugin.py new file mode 100644 index 0000000..f0da1e0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PdfImagePlugin.py @@ -0,0 +1,304 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PDF (Acrobat) file handling +# +# History: +# 1996-07-16 fl Created +# 1997-01-18 fl Fixed header +# 2004-02-21 fl Fixes for 1/L/CMYK images, etc. +# 2004-02-24 fl Fixes for 1 and P images. +# +# Copyright (c) 1997-2004 by Secret Labs AB. All rights reserved. +# Copyright (c) 1996-1997 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + +## +# Image plugin for PDF images (output only). +## +from __future__ import annotations + +import io +import math +import os +import time +from typing import IO + +from . import Image, ImageFile, ImageSequence, PdfParser, __version__, features + +# +# -------------------------------------------------------------------- + +# object ids: +# 1. catalogue +# 2. pages +# 3. image +# 4. page +# 5. page contents + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + _save(im, fp, filename, save_all=True) + + +## +# (Internal) Image save plugin for the PDF format. + + +def _write_image(im, filename, existing_pdf, image_refs): + # FIXME: Should replace ASCIIHexDecode with RunLengthDecode + # (packbits) or LZWDecode (tiff/lzw compression). Note that + # PDF 1.2 also supports Flatedecode (zip compression). + + params = None + decode = None + + # + # Get image characteristics + + width, height = im.size + + dict_obj = {"BitsPerComponent": 8} + if im.mode == "1": + if features.check("libtiff"): + filter = "CCITTFaxDecode" + dict_obj["BitsPerComponent"] = 1 + params = PdfParser.PdfArray( + [ + PdfParser.PdfDict( + { + "K": -1, + "BlackIs1": True, + "Columns": width, + "Rows": height, + } + ) + ] + ) + else: + filter = "DCTDecode" + dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray") + procset = "ImageB" # grayscale + elif im.mode == "L": + filter = "DCTDecode" + # params = f"<< /Predictor 15 /Columns {width-2} >>" + dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray") + procset = "ImageB" # grayscale + elif im.mode == "LA": + filter = "JPXDecode" + # params = f"<< /Predictor 15 /Columns {width-2} >>" + procset = "ImageB" # grayscale + dict_obj["SMaskInData"] = 1 + elif im.mode == "P": + filter = "ASCIIHexDecode" + palette = im.getpalette() + dict_obj["ColorSpace"] = [ + PdfParser.PdfName("Indexed"), + PdfParser.PdfName("DeviceRGB"), + len(palette) // 3 - 1, + PdfParser.PdfBinary(palette), + ] + procset = "ImageI" # indexed color + + if "transparency" in im.info: + smask = im.convert("LA").getchannel("A") + smask.encoderinfo = {} + + image_ref = _write_image(smask, filename, existing_pdf, image_refs)[0] + dict_obj["SMask"] = image_ref + elif im.mode == "RGB": + filter = "DCTDecode" + dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceRGB") + procset = "ImageC" # color images + elif im.mode == "RGBA": + filter = "JPXDecode" + procset = "ImageC" # color images + dict_obj["SMaskInData"] = 1 + elif im.mode == "CMYK": + filter = "DCTDecode" + dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceCMYK") + procset = "ImageC" # color images + decode = [1, 0, 1, 0, 1, 0, 1, 0] + else: + msg = f"cannot save mode {im.mode}" + raise ValueError(msg) + + # + # image + + op = io.BytesIO() + + if filter == "ASCIIHexDecode": + ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)]) + elif filter == "CCITTFaxDecode": + im.save( + op, + "TIFF", + compression="group4", + # use a single strip + strip_size=math.ceil(width / 8) * height, + ) + elif filter == "DCTDecode": + Image.SAVE["JPEG"](im, op, filename) + elif filter == "JPXDecode": + del dict_obj["BitsPerComponent"] + Image.SAVE["JPEG2000"](im, op, filename) + else: + msg = f"unsupported PDF filter ({filter})" + raise ValueError(msg) + + stream = op.getvalue() + if filter == "CCITTFaxDecode": + stream = stream[8:] + filter = PdfParser.PdfArray([PdfParser.PdfName(filter)]) + else: + filter = PdfParser.PdfName(filter) + + image_ref = image_refs.pop(0) + existing_pdf.write_obj( + image_ref, + stream=stream, + Type=PdfParser.PdfName("XObject"), + Subtype=PdfParser.PdfName("Image"), + Width=width, # * 72.0 / x_resolution, + Height=height, # * 72.0 / y_resolution, + Filter=filter, + Decode=decode, + DecodeParms=params, + **dict_obj, + ) + + return image_ref, procset + + +def _save(im, fp, filename, save_all=False): + is_appending = im.encoderinfo.get("append", False) + if is_appending: + existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="r+b") + else: + existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b") + + dpi = im.encoderinfo.get("dpi") + if dpi: + x_resolution = dpi[0] + y_resolution = dpi[1] + else: + x_resolution = y_resolution = im.encoderinfo.get("resolution", 72.0) + + info = { + "title": ( + None if is_appending else os.path.splitext(os.path.basename(filename))[0] + ), + "author": None, + "subject": None, + "keywords": None, + "creator": None, + "producer": None, + "creationDate": None if is_appending else time.gmtime(), + "modDate": None if is_appending else time.gmtime(), + } + for k, default in info.items(): + v = im.encoderinfo.get(k) if k in im.encoderinfo else default + if v: + existing_pdf.info[k[0].upper() + k[1:]] = v + + # + # make sure image data is available + im.load() + + existing_pdf.start_writing() + existing_pdf.write_header() + existing_pdf.write_comment(f"created by Pillow {__version__} PDF driver") + + # + # pages + ims = [im] + if save_all: + append_images = im.encoderinfo.get("append_images", []) + for append_im in append_images: + append_im.encoderinfo = im.encoderinfo.copy() + ims.append(append_im) + number_of_pages = 0 + image_refs = [] + page_refs = [] + contents_refs = [] + for im in ims: + im_number_of_pages = 1 + if save_all: + try: + im_number_of_pages = im.n_frames + except AttributeError: + # Image format does not have n_frames. + # It is a single frame image + pass + number_of_pages += im_number_of_pages + for i in range(im_number_of_pages): + image_refs.append(existing_pdf.next_object_id(0)) + if im.mode == "P" and "transparency" in im.info: + image_refs.append(existing_pdf.next_object_id(0)) + + page_refs.append(existing_pdf.next_object_id(0)) + contents_refs.append(existing_pdf.next_object_id(0)) + existing_pdf.pages.append(page_refs[-1]) + + # + # catalog and list of pages + existing_pdf.write_catalog() + + page_number = 0 + for im_sequence in ims: + im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence] + for im in im_pages: + image_ref, procset = _write_image(im, filename, existing_pdf, image_refs) + + # + # page + + existing_pdf.write_page( + page_refs[page_number], + Resources=PdfParser.PdfDict( + ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)], + XObject=PdfParser.PdfDict(image=image_ref), + ), + MediaBox=[ + 0, + 0, + im.width * 72.0 / x_resolution, + im.height * 72.0 / y_resolution, + ], + Contents=contents_refs[page_number], + ) + + # + # page contents + + page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % ( + im.width * 72.0 / x_resolution, + im.height * 72.0 / y_resolution, + ) + + existing_pdf.write_obj(contents_refs[page_number], stream=page_contents) + + page_number += 1 + + # + # trailer + existing_pdf.write_xref_and_trailer() + if hasattr(fp, "flush"): + fp.flush() + existing_pdf.close() + + +# +# -------------------------------------------------------------------- + + +Image.register_save("PDF", _save) +Image.register_save_all("PDF", _save_all) + +Image.register_extension("PDF", ".pdf") + +Image.register_mime("PDF", "application/pdf") diff --git a/.venv/lib/python3.12/site-packages/PIL/PdfParser.py b/.venv/lib/python3.12/site-packages/PIL/PdfParser.py new file mode 100644 index 0000000..9e22313 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PdfParser.py @@ -0,0 +1,1003 @@ +from __future__ import annotations + +import calendar +import codecs +import collections +import mmap +import os +import re +import time +import zlib +from typing import TYPE_CHECKING, Any, List, NamedTuple, Union + + +# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set +# on page 656 +def encode_text(s: str) -> bytes: + return codecs.BOM_UTF16_BE + s.encode("utf_16_be") + + +PDFDocEncoding = { + 0x16: "\u0017", + 0x18: "\u02D8", + 0x19: "\u02C7", + 0x1A: "\u02C6", + 0x1B: "\u02D9", + 0x1C: "\u02DD", + 0x1D: "\u02DB", + 0x1E: "\u02DA", + 0x1F: "\u02DC", + 0x80: "\u2022", + 0x81: "\u2020", + 0x82: "\u2021", + 0x83: "\u2026", + 0x84: "\u2014", + 0x85: "\u2013", + 0x86: "\u0192", + 0x87: "\u2044", + 0x88: "\u2039", + 0x89: "\u203A", + 0x8A: "\u2212", + 0x8B: "\u2030", + 0x8C: "\u201E", + 0x8D: "\u201C", + 0x8E: "\u201D", + 0x8F: "\u2018", + 0x90: "\u2019", + 0x91: "\u201A", + 0x92: "\u2122", + 0x93: "\uFB01", + 0x94: "\uFB02", + 0x95: "\u0141", + 0x96: "\u0152", + 0x97: "\u0160", + 0x98: "\u0178", + 0x99: "\u017D", + 0x9A: "\u0131", + 0x9B: "\u0142", + 0x9C: "\u0153", + 0x9D: "\u0161", + 0x9E: "\u017E", + 0xA0: "\u20AC", +} + + +def decode_text(b): + if b[: len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE: + return b[len(codecs.BOM_UTF16_BE) :].decode("utf_16_be") + else: + return "".join(PDFDocEncoding.get(byte, chr(byte)) for byte in b) + + +class PdfFormatError(RuntimeError): + """An error that probably indicates a syntactic or semantic error in the + PDF file structure""" + + pass + + +def check_format_condition(condition: bool, error_message: str) -> None: + if not condition: + raise PdfFormatError(error_message) + + +class IndirectReferenceTuple(NamedTuple): + object_id: int + generation: int + + +class IndirectReference(IndirectReferenceTuple): + def __str__(self) -> str: + return f"{self.object_id} {self.generation} R" + + def __bytes__(self) -> bytes: + return self.__str__().encode("us-ascii") + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return False + assert isinstance(other, IndirectReference) + return other.object_id == self.object_id and other.generation == self.generation + + def __ne__(self, other): + return not (self == other) + + def __hash__(self) -> int: + return hash((self.object_id, self.generation)) + + +class IndirectObjectDef(IndirectReference): + def __str__(self) -> str: + return f"{self.object_id} {self.generation} obj" + + +class XrefTable: + def __init__(self): + self.existing_entries = {} # object ID => (offset, generation) + self.new_entries = {} # object ID => (offset, generation) + self.deleted_entries = {0: 65536} # object ID => generation + self.reading_finished = False + + def __setitem__(self, key, value): + if self.reading_finished: + self.new_entries[key] = value + else: + self.existing_entries[key] = value + if key in self.deleted_entries: + del self.deleted_entries[key] + + def __getitem__(self, key): + try: + return self.new_entries[key] + except KeyError: + return self.existing_entries[key] + + def __delitem__(self, key): + if key in self.new_entries: + generation = self.new_entries[key][1] + 1 + del self.new_entries[key] + self.deleted_entries[key] = generation + elif key in self.existing_entries: + generation = self.existing_entries[key][1] + 1 + self.deleted_entries[key] = generation + elif key in self.deleted_entries: + generation = self.deleted_entries[key] + else: + msg = f"object ID {key} cannot be deleted because it doesn't exist" + raise IndexError(msg) + + def __contains__(self, key): + return key in self.existing_entries or key in self.new_entries + + def __len__(self) -> int: + return len( + set(self.existing_entries.keys()) + | set(self.new_entries.keys()) + | set(self.deleted_entries.keys()) + ) + + def keys(self): + return ( + set(self.existing_entries.keys()) - set(self.deleted_entries.keys()) + ) | set(self.new_entries.keys()) + + def write(self, f): + keys = sorted(set(self.new_entries.keys()) | set(self.deleted_entries.keys())) + deleted_keys = sorted(set(self.deleted_entries.keys())) + startxref = f.tell() + f.write(b"xref\n") + while keys: + # find a contiguous sequence of object IDs + prev = None + for index, key in enumerate(keys): + if prev is None or prev + 1 == key: + prev = key + else: + contiguous_keys = keys[:index] + keys = keys[index:] + break + else: + contiguous_keys = keys + keys = None + f.write(b"%d %d\n" % (contiguous_keys[0], len(contiguous_keys))) + for object_id in contiguous_keys: + if object_id in self.new_entries: + f.write(b"%010d %05d n \n" % self.new_entries[object_id]) + else: + this_deleted_object_id = deleted_keys.pop(0) + check_format_condition( + object_id == this_deleted_object_id, + f"expected the next deleted object ID to be {object_id}, " + f"instead found {this_deleted_object_id}", + ) + try: + next_in_linked_list = deleted_keys[0] + except IndexError: + next_in_linked_list = 0 + f.write( + b"%010d %05d f \n" + % (next_in_linked_list, self.deleted_entries[object_id]) + ) + return startxref + + +class PdfName: + def __init__(self, name): + if isinstance(name, PdfName): + self.name = name.name + elif isinstance(name, bytes): + self.name = name + else: + self.name = name.encode("us-ascii") + + def name_as_str(self) -> str: + return self.name.decode("us-ascii") + + def __eq__(self, other): + return ( + isinstance(other, PdfName) and other.name == self.name + ) or other == self.name + + def __hash__(self) -> int: + return hash(self.name) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({repr(self.name)})" + + @classmethod + def from_pdf_stream(cls, data): + return cls(PdfParser.interpret_name(data)) + + allowed_chars = set(range(33, 127)) - {ord(c) for c in "#%/()<>[]{}"} + + def __bytes__(self) -> bytes: + result = bytearray(b"/") + for b in self.name: + if b in self.allowed_chars: + result.append(b) + else: + result.extend(b"#%02X" % b) + return bytes(result) + + +class PdfArray(List[Any]): + def __bytes__(self) -> bytes: + return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]" + + +if TYPE_CHECKING: + _DictBase = collections.UserDict[Union[str, bytes], Any] +else: + _DictBase = collections.UserDict + + +class PdfDict(_DictBase): + def __setattr__(self, key, value): + if key == "data": + collections.UserDict.__setattr__(self, key, value) + else: + self[key.encode("us-ascii")] = value + + def __getattr__(self, key): + try: + value = self[key.encode("us-ascii")] + except KeyError as e: + raise AttributeError(key) from e + if isinstance(value, bytes): + value = decode_text(value) + if key.endswith("Date"): + if value.startswith("D:"): + value = value[2:] + + relationship = "Z" + if len(value) > 17: + relationship = value[14] + offset = int(value[15:17]) * 60 + if len(value) > 20: + offset += int(value[18:20]) + + format = "%Y%m%d%H%M%S"[: len(value) - 2] + value = time.strptime(value[: len(format) + 2], format) + if relationship in ["+", "-"]: + offset *= 60 + if relationship == "+": + offset *= -1 + value = time.gmtime(calendar.timegm(value) + offset) + return value + + def __bytes__(self) -> bytes: + out = bytearray(b"<<") + for key, value in self.items(): + if value is None: + continue + value = pdf_repr(value) + out.extend(b"\n") + out.extend(bytes(PdfName(key))) + out.extend(b" ") + out.extend(value) + out.extend(b"\n>>") + return bytes(out) + + +class PdfBinary: + def __init__(self, data): + self.data = data + + def __bytes__(self) -> bytes: + return b"<%s>" % b"".join(b"%02X" % b for b in self.data) + + +class PdfStream: + def __init__(self, dictionary, buf): + self.dictionary = dictionary + self.buf = buf + + def decode(self): + try: + filter = self.dictionary.Filter + except AttributeError: + return self.buf + if filter == b"FlateDecode": + try: + expected_length = self.dictionary.DL + except AttributeError: + expected_length = self.dictionary.Length + return zlib.decompress(self.buf, bufsize=int(expected_length)) + else: + msg = f"stream filter {repr(self.dictionary.Filter)} unknown/unsupported" + raise NotImplementedError(msg) + + +def pdf_repr(x): + if x is True: + return b"true" + elif x is False: + return b"false" + elif x is None: + return b"null" + elif isinstance(x, (PdfName, PdfDict, PdfArray, PdfBinary)): + return bytes(x) + elif isinstance(x, (int, float)): + return str(x).encode("us-ascii") + elif isinstance(x, time.struct_time): + return b"(D:" + time.strftime("%Y%m%d%H%M%SZ", x).encode("us-ascii") + b")" + elif isinstance(x, dict): + return bytes(PdfDict(x)) + elif isinstance(x, list): + return bytes(PdfArray(x)) + elif isinstance(x, str): + return pdf_repr(encode_text(x)) + elif isinstance(x, bytes): + # XXX escape more chars? handle binary garbage + x = x.replace(b"\\", b"\\\\") + x = x.replace(b"(", b"\\(") + x = x.replace(b")", b"\\)") + return b"(" + x + b")" + else: + return bytes(x) + + +class PdfParser: + """Based on + https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf + Supports PDF up to 1.4 + """ + + def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"): + if buf and f: + msg = "specify buf or f or filename, but not both buf and f" + raise RuntimeError(msg) + self.filename = filename + self.buf = buf + self.f = f + self.start_offset = start_offset + self.should_close_buf = False + self.should_close_file = False + if filename is not None and f is None: + self.f = f = open(filename, mode) + self.should_close_file = True + if f is not None: + self.buf = buf = self.get_buf_from_file(f) + self.should_close_buf = True + if not filename and hasattr(f, "name"): + self.filename = f.name + self.cached_objects = {} + if buf: + self.read_pdf_info() + else: + self.file_size_total = self.file_size_this = 0 + self.root = PdfDict() + self.root_ref = None + self.info = PdfDict() + self.info_ref = None + self.page_tree_root = {} + self.pages = [] + self.orig_pages = [] + self.pages_ref = None + self.last_xref_section_offset = None + self.trailer_dict = {} + self.xref_table = XrefTable() + self.xref_table.reading_finished = True + if f: + self.seek_end() + + def __enter__(self) -> PdfParser: + return self + + def __exit__(self, *args: object) -> None: + self.close() + + def start_writing(self) -> None: + self.close_buf() + self.seek_end() + + def close_buf(self) -> None: + try: + self.buf.close() + except AttributeError: + pass + self.buf = None + + def close(self) -> None: + if self.should_close_buf: + self.close_buf() + if self.f is not None and self.should_close_file: + self.f.close() + self.f = None + + def seek_end(self) -> None: + self.f.seek(0, os.SEEK_END) + + def write_header(self) -> None: + self.f.write(b"%PDF-1.4\n") + + def write_comment(self, s): + self.f.write(f"% {s}\n".encode()) + + def write_catalog(self) -> IndirectReference: + self.del_root() + self.root_ref = self.next_object_id(self.f.tell()) + self.pages_ref = self.next_object_id(0) + self.rewrite_pages() + self.write_obj(self.root_ref, Type=PdfName(b"Catalog"), Pages=self.pages_ref) + self.write_obj( + self.pages_ref, + Type=PdfName(b"Pages"), + Count=len(self.pages), + Kids=self.pages, + ) + return self.root_ref + + def rewrite_pages(self) -> None: + pages_tree_nodes_to_delete = [] + for i, page_ref in enumerate(self.orig_pages): + page_info = self.cached_objects[page_ref] + del self.xref_table[page_ref.object_id] + pages_tree_nodes_to_delete.append(page_info[PdfName(b"Parent")]) + if page_ref not in self.pages: + # the page has been deleted + continue + # make dict keys into strings for passing to write_page + stringified_page_info = {} + for key, value in page_info.items(): + # key should be a PdfName + stringified_page_info[key.name_as_str()] = value + stringified_page_info["Parent"] = self.pages_ref + new_page_ref = self.write_page(None, **stringified_page_info) + for j, cur_page_ref in enumerate(self.pages): + if cur_page_ref == page_ref: + # replace the page reference with the new one + self.pages[j] = new_page_ref + # delete redundant Pages tree nodes from xref table + for pages_tree_node_ref in pages_tree_nodes_to_delete: + while pages_tree_node_ref: + pages_tree_node = self.cached_objects[pages_tree_node_ref] + if pages_tree_node_ref.object_id in self.xref_table: + del self.xref_table[pages_tree_node_ref.object_id] + pages_tree_node_ref = pages_tree_node.get(b"Parent", None) + self.orig_pages = [] + + def write_xref_and_trailer(self, new_root_ref=None): + if new_root_ref: + self.del_root() + self.root_ref = new_root_ref + if self.info: + self.info_ref = self.write_obj(None, self.info) + start_xref = self.xref_table.write(self.f) + num_entries = len(self.xref_table) + trailer_dict = {b"Root": self.root_ref, b"Size": num_entries} + if self.last_xref_section_offset is not None: + trailer_dict[b"Prev"] = self.last_xref_section_offset + if self.info: + trailer_dict[b"Info"] = self.info_ref + self.last_xref_section_offset = start_xref + self.f.write( + b"trailer\n" + + bytes(PdfDict(trailer_dict)) + + b"\nstartxref\n%d\n%%%%EOF" % start_xref + ) + + def write_page(self, ref, *objs, **dict_obj): + if isinstance(ref, int): + ref = self.pages[ref] + if "Type" not in dict_obj: + dict_obj["Type"] = PdfName(b"Page") + if "Parent" not in dict_obj: + dict_obj["Parent"] = self.pages_ref + return self.write_obj(ref, *objs, **dict_obj) + + def write_obj(self, ref, *objs, **dict_obj): + f = self.f + if ref is None: + ref = self.next_object_id(f.tell()) + else: + self.xref_table[ref.object_id] = (f.tell(), ref.generation) + f.write(bytes(IndirectObjectDef(*ref))) + stream = dict_obj.pop("stream", None) + if stream is not None: + dict_obj["Length"] = len(stream) + if dict_obj: + f.write(pdf_repr(dict_obj)) + for obj in objs: + f.write(pdf_repr(obj)) + if stream is not None: + f.write(b"stream\n") + f.write(stream) + f.write(b"\nendstream\n") + f.write(b"endobj\n") + return ref + + def del_root(self) -> None: + if self.root_ref is None: + return + del self.xref_table[self.root_ref.object_id] + del self.xref_table[self.root[b"Pages"].object_id] + + @staticmethod + def get_buf_from_file(f): + if hasattr(f, "getbuffer"): + return f.getbuffer() + elif hasattr(f, "getvalue"): + return f.getvalue() + else: + try: + return mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) + except ValueError: # cannot mmap an empty file + return b"" + + def read_pdf_info(self) -> None: + self.file_size_total = len(self.buf) + self.file_size_this = self.file_size_total - self.start_offset + self.read_trailer() + self.root_ref = self.trailer_dict[b"Root"] + self.info_ref = self.trailer_dict.get(b"Info", None) + self.root = PdfDict(self.read_indirect(self.root_ref)) + if self.info_ref is None: + self.info = PdfDict() + else: + self.info = PdfDict(self.read_indirect(self.info_ref)) + check_format_condition(b"Type" in self.root, "/Type missing in Root") + check_format_condition( + self.root[b"Type"] == b"Catalog", "/Type in Root is not /Catalog" + ) + check_format_condition(b"Pages" in self.root, "/Pages missing in Root") + check_format_condition( + isinstance(self.root[b"Pages"], IndirectReference), + "/Pages in Root is not an indirect reference", + ) + self.pages_ref = self.root[b"Pages"] + self.page_tree_root = self.read_indirect(self.pages_ref) + self.pages = self.linearize_page_tree(self.page_tree_root) + # save the original list of page references + # in case the user modifies, adds or deletes some pages + # and we need to rewrite the pages and their list + self.orig_pages = self.pages[:] + + def next_object_id(self, offset=None): + try: + # TODO: support reuse of deleted objects + reference = IndirectReference(max(self.xref_table.keys()) + 1, 0) + except ValueError: + reference = IndirectReference(1, 0) + if offset is not None: + self.xref_table[reference.object_id] = (offset, 0) + return reference + + delimiter = rb"[][()<>{}/%]" + delimiter_or_ws = rb"[][()<>{}/%\000\011\012\014\015\040]" + whitespace = rb"[\000\011\012\014\015\040]" + whitespace_or_hex = rb"[\000\011\012\014\015\0400-9a-fA-F]" + whitespace_optional = whitespace + b"*" + whitespace_mandatory = whitespace + b"+" + # No "\012" aka "\n" or "\015" aka "\r": + whitespace_optional_no_nl = rb"[\000\011\014\040]*" + newline_only = rb"[\r\n]+" + newline = whitespace_optional_no_nl + newline_only + whitespace_optional_no_nl + re_trailer_end = re.compile( + whitespace_mandatory + + rb"trailer" + + whitespace_optional + + rb"<<(.*>>)" + + newline + + rb"startxref" + + newline + + rb"([0-9]+)" + + newline + + rb"%%EOF" + + whitespace_optional + + rb"$", + re.DOTALL, + ) + re_trailer_prev = re.compile( + whitespace_optional + + rb"trailer" + + whitespace_optional + + rb"<<(.*?>>)" + + newline + + rb"startxref" + + newline + + rb"([0-9]+)" + + newline + + rb"%%EOF" + + whitespace_optional, + re.DOTALL, + ) + + def read_trailer(self): + search_start_offset = len(self.buf) - 16384 + if search_start_offset < self.start_offset: + search_start_offset = self.start_offset + m = self.re_trailer_end.search(self.buf, search_start_offset) + check_format_condition(m, "trailer end not found") + # make sure we found the LAST trailer + last_match = m + while m: + last_match = m + m = self.re_trailer_end.search(self.buf, m.start() + 16) + if not m: + m = last_match + trailer_data = m.group(1) + self.last_xref_section_offset = int(m.group(2)) + self.trailer_dict = self.interpret_trailer(trailer_data) + self.xref_table = XrefTable() + self.read_xref_table(xref_section_offset=self.last_xref_section_offset) + if b"Prev" in self.trailer_dict: + self.read_prev_trailer(self.trailer_dict[b"Prev"]) + + def read_prev_trailer(self, xref_section_offset): + trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset) + m = self.re_trailer_prev.search( + self.buf[trailer_offset : trailer_offset + 16384] + ) + check_format_condition(m, "previous trailer not found") + trailer_data = m.group(1) + check_format_condition( + int(m.group(2)) == xref_section_offset, + "xref section offset in previous trailer doesn't match what was expected", + ) + trailer_dict = self.interpret_trailer(trailer_data) + if b"Prev" in trailer_dict: + self.read_prev_trailer(trailer_dict[b"Prev"]) + + re_whitespace_optional = re.compile(whitespace_optional) + re_name = re.compile( + whitespace_optional + + rb"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?=" + + delimiter_or_ws + + rb")" + ) + re_dict_start = re.compile(whitespace_optional + rb"<<") + re_dict_end = re.compile(whitespace_optional + rb">>" + whitespace_optional) + + @classmethod + def interpret_trailer(cls, trailer_data): + trailer = {} + offset = 0 + while True: + m = cls.re_name.match(trailer_data, offset) + if not m: + m = cls.re_dict_end.match(trailer_data, offset) + check_format_condition( + m and m.end() == len(trailer_data), + "name not found in trailer, remaining data: " + + repr(trailer_data[offset:]), + ) + break + key = cls.interpret_name(m.group(1)) + value, offset = cls.get_value(trailer_data, m.end()) + trailer[key] = value + check_format_condition( + b"Size" in trailer and isinstance(trailer[b"Size"], int), + "/Size not in trailer or not an integer", + ) + check_format_condition( + b"Root" in trailer and isinstance(trailer[b"Root"], IndirectReference), + "/Root not in trailer or not an indirect reference", + ) + return trailer + + re_hashes_in_name = re.compile(rb"([^#]*)(#([0-9a-fA-F]{2}))?") + + @classmethod + def interpret_name(cls, raw, as_text=False): + name = b"" + for m in cls.re_hashes_in_name.finditer(raw): + if m.group(3): + name += m.group(1) + bytearray.fromhex(m.group(3).decode("us-ascii")) + else: + name += m.group(1) + if as_text: + return name.decode("utf-8") + else: + return bytes(name) + + re_null = re.compile(whitespace_optional + rb"null(?=" + delimiter_or_ws + rb")") + re_true = re.compile(whitespace_optional + rb"true(?=" + delimiter_or_ws + rb")") + re_false = re.compile(whitespace_optional + rb"false(?=" + delimiter_or_ws + rb")") + re_int = re.compile( + whitespace_optional + rb"([-+]?[0-9]+)(?=" + delimiter_or_ws + rb")" + ) + re_real = re.compile( + whitespace_optional + + rb"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?=" + + delimiter_or_ws + + rb")" + ) + re_array_start = re.compile(whitespace_optional + rb"\[") + re_array_end = re.compile(whitespace_optional + rb"]") + re_string_hex = re.compile( + whitespace_optional + rb"<(" + whitespace_or_hex + rb"*)>" + ) + re_string_lit = re.compile(whitespace_optional + rb"\(") + re_indirect_reference = re.compile( + whitespace_optional + + rb"([-+]?[0-9]+)" + + whitespace_mandatory + + rb"([-+]?[0-9]+)" + + whitespace_mandatory + + rb"R(?=" + + delimiter_or_ws + + rb")" + ) + re_indirect_def_start = re.compile( + whitespace_optional + + rb"([-+]?[0-9]+)" + + whitespace_mandatory + + rb"([-+]?[0-9]+)" + + whitespace_mandatory + + rb"obj(?=" + + delimiter_or_ws + + rb")" + ) + re_indirect_def_end = re.compile( + whitespace_optional + rb"endobj(?=" + delimiter_or_ws + rb")" + ) + re_comment = re.compile( + rb"(" + whitespace_optional + rb"%[^\r\n]*" + newline + rb")*" + ) + re_stream_start = re.compile(whitespace_optional + rb"stream\r?\n") + re_stream_end = re.compile( + whitespace_optional + rb"endstream(?=" + delimiter_or_ws + rb")" + ) + + @classmethod + def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1): + if max_nesting == 0: + return None, None + m = cls.re_comment.match(data, offset) + if m: + offset = m.end() + m = cls.re_indirect_def_start.match(data, offset) + if m: + check_format_condition( + int(m.group(1)) > 0, + "indirect object definition: object ID must be greater than 0", + ) + check_format_condition( + int(m.group(2)) >= 0, + "indirect object definition: generation must be non-negative", + ) + check_format_condition( + expect_indirect is None + or expect_indirect + == IndirectReference(int(m.group(1)), int(m.group(2))), + "indirect object definition different than expected", + ) + object, offset = cls.get_value(data, m.end(), max_nesting=max_nesting - 1) + if offset is None: + return object, None + m = cls.re_indirect_def_end.match(data, offset) + check_format_condition(m, "indirect object definition end not found") + return object, m.end() + check_format_condition( + not expect_indirect, "indirect object definition not found" + ) + m = cls.re_indirect_reference.match(data, offset) + if m: + check_format_condition( + int(m.group(1)) > 0, + "indirect object reference: object ID must be greater than 0", + ) + check_format_condition( + int(m.group(2)) >= 0, + "indirect object reference: generation must be non-negative", + ) + return IndirectReference(int(m.group(1)), int(m.group(2))), m.end() + m = cls.re_dict_start.match(data, offset) + if m: + offset = m.end() + result = {} + m = cls.re_dict_end.match(data, offset) + while not m: + key, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) + if offset is None: + return result, None + value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) + result[key] = value + if offset is None: + return result, None + m = cls.re_dict_end.match(data, offset) + offset = m.end() + m = cls.re_stream_start.match(data, offset) + if m: + try: + stream_len_str = result.get(b"Length") + stream_len = int(stream_len_str) + except (TypeError, ValueError) as e: + msg = f"bad or missing Length in stream dict ({stream_len_str})" + raise PdfFormatError(msg) from e + stream_data = data[m.end() : m.end() + stream_len] + m = cls.re_stream_end.match(data, m.end() + stream_len) + check_format_condition(m, "stream end not found") + offset = m.end() + result = PdfStream(PdfDict(result), stream_data) + else: + result = PdfDict(result) + return result, offset + m = cls.re_array_start.match(data, offset) + if m: + offset = m.end() + result = [] + m = cls.re_array_end.match(data, offset) + while not m: + value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) + result.append(value) + if offset is None: + return result, None + m = cls.re_array_end.match(data, offset) + return result, m.end() + m = cls.re_null.match(data, offset) + if m: + return None, m.end() + m = cls.re_true.match(data, offset) + if m: + return True, m.end() + m = cls.re_false.match(data, offset) + if m: + return False, m.end() + m = cls.re_name.match(data, offset) + if m: + return PdfName(cls.interpret_name(m.group(1))), m.end() + m = cls.re_int.match(data, offset) + if m: + return int(m.group(1)), m.end() + m = cls.re_real.match(data, offset) + if m: + # XXX Decimal instead of float??? + return float(m.group(1)), m.end() + m = cls.re_string_hex.match(data, offset) + if m: + # filter out whitespace + hex_string = bytearray( + b for b in m.group(1) if b in b"0123456789abcdefABCDEF" + ) + if len(hex_string) % 2 == 1: + # append a 0 if the length is not even - yes, at the end + hex_string.append(ord(b"0")) + return bytearray.fromhex(hex_string.decode("us-ascii")), m.end() + m = cls.re_string_lit.match(data, offset) + if m: + return cls.get_literal_string(data, m.end()) + # return None, offset # fallback (only for debugging) + msg = f"unrecognized object: {repr(data[offset : offset + 32])}" + raise PdfFormatError(msg) + + re_lit_str_token = re.compile( + rb"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))" + ) + escaped_chars = { + b"n": b"\n", + b"r": b"\r", + b"t": b"\t", + b"b": b"\b", + b"f": b"\f", + b"(": b"(", + b")": b")", + b"\\": b"\\", + ord(b"n"): b"\n", + ord(b"r"): b"\r", + ord(b"t"): b"\t", + ord(b"b"): b"\b", + ord(b"f"): b"\f", + ord(b"("): b"(", + ord(b")"): b")", + ord(b"\\"): b"\\", + } + + @classmethod + def get_literal_string(cls, data, offset): + nesting_depth = 0 + result = bytearray() + for m in cls.re_lit_str_token.finditer(data, offset): + result.extend(data[offset : m.start()]) + if m.group(1): + result.extend(cls.escaped_chars[m.group(1)[1]]) + elif m.group(2): + result.append(int(m.group(2)[1:], 8)) + elif m.group(3): + pass + elif m.group(5): + result.extend(b"\n") + elif m.group(6): + result.extend(b"(") + nesting_depth += 1 + elif m.group(7): + if nesting_depth == 0: + return bytes(result), m.end() + result.extend(b")") + nesting_depth -= 1 + offset = m.end() + msg = "unfinished literal string" + raise PdfFormatError(msg) + + re_xref_section_start = re.compile(whitespace_optional + rb"xref" + newline) + re_xref_subsection_start = re.compile( + whitespace_optional + + rb"([0-9]+)" + + whitespace_mandatory + + rb"([0-9]+)" + + whitespace_optional + + newline_only + ) + re_xref_entry = re.compile(rb"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)") + + def read_xref_table(self, xref_section_offset): + subsection_found = False + m = self.re_xref_section_start.match( + self.buf, xref_section_offset + self.start_offset + ) + check_format_condition(m, "xref section start not found") + offset = m.end() + while True: + m = self.re_xref_subsection_start.match(self.buf, offset) + if not m: + check_format_condition( + subsection_found, "xref subsection start not found" + ) + break + subsection_found = True + offset = m.end() + first_object = int(m.group(1)) + num_objects = int(m.group(2)) + for i in range(first_object, first_object + num_objects): + m = self.re_xref_entry.match(self.buf, offset) + check_format_condition(m, "xref entry not found") + offset = m.end() + is_free = m.group(3) == b"f" + if not is_free: + generation = int(m.group(2)) + new_entry = (int(m.group(1)), generation) + if i not in self.xref_table: + self.xref_table[i] = new_entry + return offset + + def read_indirect(self, ref, max_nesting=-1): + offset, generation = self.xref_table[ref[0]] + check_format_condition( + generation == ref[1], + f"expected to find generation {ref[1]} for object ID {ref[0]} in xref " + f"table, instead found generation {generation} at offset {offset}", + ) + value = self.get_value( + self.buf, + offset + self.start_offset, + expect_indirect=IndirectReference(*ref), + max_nesting=max_nesting, + )[0] + self.cached_objects[ref] = value + return value + + def linearize_page_tree(self, node=None): + if node is None: + node = self.page_tree_root + check_format_condition( + node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages" + ) + pages = [] + for kid in node[b"Kids"]: + kid_object = self.read_indirect(kid) + if kid_object[b"Type"] == b"Page": + pages.append(kid) + else: + pages.extend(self.linearize_page_tree(node=kid_object)) + return pages diff --git a/.venv/lib/python3.12/site-packages/PIL/PixarImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PixarImagePlugin.py new file mode 100644 index 0000000..887b656 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PixarImagePlugin.py @@ -0,0 +1,72 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PIXAR raster support for PIL +# +# history: +# 97-01-29 fl Created +# +# notes: +# This is incomplete; it is based on a few samples created with +# Photoshop 2.5 and 3.0, and a summary description provided by +# Greg Coats . Hopefully, "L" and +# "RGBA" support will be added in future versions. +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1997. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image, ImageFile +from ._binary import i16le as i16 + +# +# helpers + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"\200\350\000\000" + + +## +# Image plugin for PIXAR raster images. + + +class PixarImageFile(ImageFile.ImageFile): + format = "PIXAR" + format_description = "PIXAR raster image" + + def _open(self) -> None: + # assuming a 4-byte magic label + assert self.fp is not None + + s = self.fp.read(4) + if not _accept(s): + msg = "not a PIXAR file" + raise SyntaxError(msg) + + # read rest of header + s = s + self.fp.read(508) + + self._size = i16(s, 418), i16(s, 416) + + # get channel/depth descriptions + mode = i16(s, 424), i16(s, 426) + + if mode == (14, 2): + self._mode = "RGB" + # FIXME: to be continued... + + # create tile descriptor (assuming "dumped") + self.tile = [("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1))] + + +# +# -------------------------------------------------------------------- + +Image.register_open(PixarImageFile.format, PixarImageFile, _accept) + +Image.register_extension(PixarImageFile.format, ".pxr") diff --git a/.venv/lib/python3.12/site-packages/PIL/PngImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PngImagePlugin.py new file mode 100644 index 0000000..d283492 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PngImagePlugin.py @@ -0,0 +1,1489 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PNG support code +# +# See "PNG (Portable Network Graphics) Specification, version 1.0; +# W3C Recommendation", 1996-10-01, Thomas Boutell (ed.). +# +# history: +# 1996-05-06 fl Created (couldn't resist it) +# 1996-12-14 fl Upgraded, added read and verify support (0.2) +# 1996-12-15 fl Separate PNG stream parser +# 1996-12-29 fl Added write support, added getchunks +# 1996-12-30 fl Eliminated circular references in decoder (0.3) +# 1998-07-12 fl Read/write 16-bit images as mode I (0.4) +# 2001-02-08 fl Added transparency support (from Zircon) (0.5) +# 2001-04-16 fl Don't close data source in "open" method (0.6) +# 2004-02-24 fl Don't even pretend to support interlaced files (0.7) +# 2004-08-31 fl Do basic sanity check on chunk identifiers (0.8) +# 2004-09-20 fl Added PngInfo chunk container +# 2004-12-18 fl Added DPI read support (based on code by Niki Spahiev) +# 2008-08-13 fl Added tRNS support for RGB images +# 2009-03-06 fl Support for preserving ICC profiles (by Florian Hoech) +# 2009-03-08 fl Added zTXT support (from Lowell Alleman) +# 2009-03-29 fl Read interlaced PNG files (from Conrado Porto Lopes Gouvua) +# +# Copyright (c) 1997-2009 by Secret Labs AB +# Copyright (c) 1996 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import itertools +import logging +import re +import struct +import warnings +import zlib +from enum import IntEnum +from typing import IO, TYPE_CHECKING, Any, NoReturn + +from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._binary import o8 +from ._binary import o16be as o16 +from ._binary import o32be as o32 + +if TYPE_CHECKING: + from . import _imaging + +logger = logging.getLogger(__name__) + +is_cid = re.compile(rb"\w\w\w\w").match + + +_MAGIC = b"\211PNG\r\n\032\n" + + +_MODES = { + # supported bits/color combinations, and corresponding modes/rawmodes + # Grayscale + (1, 0): ("1", "1"), + (2, 0): ("L", "L;2"), + (4, 0): ("L", "L;4"), + (8, 0): ("L", "L"), + (16, 0): ("I;16", "I;16B"), + # Truecolour + (8, 2): ("RGB", "RGB"), + (16, 2): ("RGB", "RGB;16B"), + # Indexed-colour + (1, 3): ("P", "P;1"), + (2, 3): ("P", "P;2"), + (4, 3): ("P", "P;4"), + (8, 3): ("P", "P"), + # Grayscale with alpha + (8, 4): ("LA", "LA"), + (16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available + # Truecolour with alpha + (8, 6): ("RGBA", "RGBA"), + (16, 6): ("RGBA", "RGBA;16B"), +} + + +_simple_palette = re.compile(b"^\xff*\x00\xff*$") + +MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK +""" +Maximum decompressed size for a iTXt or zTXt chunk. +Eliminates decompression bombs where compressed chunks can expand 1000x. +See :ref:`Text in PNG File Format`. +""" +MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK +""" +Set the maximum total text chunk size. +See :ref:`Text in PNG File Format`. +""" + + +# APNG frame disposal modes +class Disposal(IntEnum): + OP_NONE = 0 + """ + No disposal is done on this frame before rendering the next frame. + See :ref:`Saving APNG sequences`. + """ + OP_BACKGROUND = 1 + """ + This frame’s modified region is cleared to fully transparent black before rendering + the next frame. + See :ref:`Saving APNG sequences`. + """ + OP_PREVIOUS = 2 + """ + This frame’s modified region is reverted to the previous frame’s contents before + rendering the next frame. + See :ref:`Saving APNG sequences`. + """ + + +# APNG frame blend modes +class Blend(IntEnum): + OP_SOURCE = 0 + """ + All color components of this frame, including alpha, overwrite the previous output + image contents. + See :ref:`Saving APNG sequences`. + """ + OP_OVER = 1 + """ + This frame should be alpha composited with the previous output image contents. + See :ref:`Saving APNG sequences`. + """ + + +def _safe_zlib_decompress(s): + dobj = zlib.decompressobj() + plaintext = dobj.decompress(s, MAX_TEXT_CHUNK) + if dobj.unconsumed_tail: + msg = "Decompressed Data Too Large" + raise ValueError(msg) + return plaintext + + +def _crc32(data, seed=0): + return zlib.crc32(data, seed) & 0xFFFFFFFF + + +# -------------------------------------------------------------------- +# Support classes. Suitable for PNG and related formats like MNG etc. + + +class ChunkStream: + def __init__(self, fp: IO[bytes]) -> None: + self.fp: IO[bytes] | None = fp + self.queue: list[tuple[bytes, int, int]] | None = [] + + def read(self) -> tuple[bytes, int, int]: + """Fetch a new chunk. Returns header information.""" + cid = None + + assert self.fp is not None + if self.queue: + cid, pos, length = self.queue.pop() + self.fp.seek(pos) + else: + s = self.fp.read(8) + cid = s[4:] + pos = self.fp.tell() + length = i32(s) + + if not is_cid(cid): + if not ImageFile.LOAD_TRUNCATED_IMAGES: + msg = f"broken PNG file (chunk {repr(cid)})" + raise SyntaxError(msg) + + return cid, pos, length + + def __enter__(self) -> ChunkStream: + return self + + def __exit__(self, *args: object) -> None: + self.close() + + def close(self) -> None: + self.queue = self.fp = None + + def push(self, cid: bytes, pos: int, length: int) -> None: + assert self.queue is not None + self.queue.append((cid, pos, length)) + + def call(self, cid, pos, length): + """Call the appropriate chunk handler""" + + logger.debug("STREAM %r %s %s", cid, pos, length) + return getattr(self, f"chunk_{cid.decode('ascii')}")(pos, length) + + def crc(self, cid: bytes, data: bytes) -> None: + """Read and verify checksum""" + + # Skip CRC checks for ancillary chunks if allowed to load truncated + # images + # 5th byte of first char is 1 [specs, section 5.4] + if ImageFile.LOAD_TRUNCATED_IMAGES and (cid[0] >> 5 & 1): + self.crc_skip(cid, data) + return + + assert self.fp is not None + try: + crc1 = _crc32(data, _crc32(cid)) + crc2 = i32(self.fp.read(4)) + if crc1 != crc2: + msg = f"broken PNG file (bad header checksum in {repr(cid)})" + raise SyntaxError(msg) + except struct.error as e: + msg = f"broken PNG file (incomplete checksum in {repr(cid)})" + raise SyntaxError(msg) from e + + def crc_skip(self, cid: bytes, data: bytes) -> None: + """Read checksum""" + + assert self.fp is not None + self.fp.read(4) + + def verify(self, endchunk: bytes = b"IEND") -> list[bytes]: + # Simple approach; just calculate checksum for all remaining + # blocks. Must be called directly after open. + + cids = [] + + while True: + try: + cid, pos, length = self.read() + except struct.error as e: + msg = "truncated PNG file" + raise OSError(msg) from e + + if cid == endchunk: + break + self.crc(cid, ImageFile._safe_read(self.fp, length)) + cids.append(cid) + + return cids + + +class iTXt(str): + """ + Subclass of string to allow iTXt chunks to look like strings while + keeping their extra information + + """ + + lang: str | bytes | None + tkey: str | bytes | None + + @staticmethod + def __new__(cls, text, lang=None, tkey=None): + """ + :param cls: the class to use when creating the instance + :param text: value for this key + :param lang: language code + :param tkey: UTF-8 version of the key name + """ + + self = str.__new__(cls, text) + self.lang = lang + self.tkey = tkey + return self + + +class PngInfo: + """ + PNG chunk container (for use with save(pnginfo=)) + + """ + + def __init__(self) -> None: + self.chunks: list[tuple[bytes, bytes, bool]] = [] + + def add(self, cid: bytes, data: bytes, after_idat: bool = False) -> None: + """Appends an arbitrary chunk. Use with caution. + + :param cid: a byte string, 4 bytes long. + :param data: a byte string of the encoded data + :param after_idat: for use with private chunks. Whether the chunk + should be written after IDAT + + """ + + self.chunks.append((cid, data, after_idat)) + + def add_itxt( + self, + key: str | bytes, + value: str | bytes, + lang: str | bytes = "", + tkey: str | bytes = "", + zip: bool = False, + ) -> None: + """Appends an iTXt chunk. + + :param key: latin-1 encodable text key name + :param value: value for this key + :param lang: language code + :param tkey: UTF-8 version of the key name + :param zip: compression flag + + """ + + if not isinstance(key, bytes): + key = key.encode("latin-1", "strict") + if not isinstance(value, bytes): + value = value.encode("utf-8", "strict") + if not isinstance(lang, bytes): + lang = lang.encode("utf-8", "strict") + if not isinstance(tkey, bytes): + tkey = tkey.encode("utf-8", "strict") + + if zip: + self.add( + b"iTXt", + key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" + zlib.compress(value), + ) + else: + self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value) + + def add_text( + self, key: str | bytes, value: str | bytes | iTXt, zip: bool = False + ) -> None: + """Appends a text chunk. + + :param key: latin-1 encodable text key name + :param value: value for this key, text or an + :py:class:`PIL.PngImagePlugin.iTXt` instance + :param zip: compression flag + + """ + if isinstance(value, iTXt): + return self.add_itxt( + key, + value, + value.lang if value.lang is not None else b"", + value.tkey if value.tkey is not None else b"", + zip=zip, + ) + + # The tEXt chunk stores latin-1 text + if not isinstance(value, bytes): + try: + value = value.encode("latin-1", "strict") + except UnicodeError: + return self.add_itxt(key, value, zip=zip) + + if not isinstance(key, bytes): + key = key.encode("latin-1", "strict") + + if zip: + self.add(b"zTXt", key + b"\0\0" + zlib.compress(value)) + else: + self.add(b"tEXt", key + b"\0" + value) + + +# -------------------------------------------------------------------- +# PNG image stream (IHDR/IEND) + + +class PngStream(ChunkStream): + def __init__(self, fp): + super().__init__(fp) + + # local copies of Image attributes + self.im_info = {} + self.im_text = {} + self.im_size = (0, 0) + self.im_mode = None + self.im_tile = None + self.im_palette = None + self.im_custom_mimetype = None + self.im_n_frames = None + self._seq_num = None + self.rewind_state = None + + self.text_memory = 0 + + def check_text_memory(self, chunklen: int) -> None: + self.text_memory += chunklen + if self.text_memory > MAX_TEXT_MEMORY: + msg = ( + "Too much memory used in text chunks: " + f"{self.text_memory}>MAX_TEXT_MEMORY" + ) + raise ValueError(msg) + + def save_rewind(self) -> None: + self.rewind_state = { + "info": self.im_info.copy(), + "tile": self.im_tile, + "seq_num": self._seq_num, + } + + def rewind(self) -> None: + self.im_info = self.rewind_state["info"].copy() + self.im_tile = self.rewind_state["tile"] + self._seq_num = self.rewind_state["seq_num"] + + def chunk_iCCP(self, pos: int, length: int) -> bytes: + # ICC profile + s = ImageFile._safe_read(self.fp, length) + # according to PNG spec, the iCCP chunk contains: + # Profile name 1-79 bytes (character string) + # Null separator 1 byte (null character) + # Compression method 1 byte (0) + # Compressed profile n bytes (zlib with deflate compression) + i = s.find(b"\0") + logger.debug("iCCP profile name %r", s[:i]) + comp_method = s[i + 1] + logger.debug("Compression method %s", comp_method) + if comp_method != 0: + msg = f"Unknown compression method {comp_method} in iCCP chunk" + raise SyntaxError(msg) + try: + icc_profile = _safe_zlib_decompress(s[i + 2 :]) + except ValueError: + if ImageFile.LOAD_TRUNCATED_IMAGES: + icc_profile = None + else: + raise + except zlib.error: + icc_profile = None # FIXME + self.im_info["icc_profile"] = icc_profile + return s + + def chunk_IHDR(self, pos: int, length: int) -> bytes: + # image header + s = ImageFile._safe_read(self.fp, length) + if length < 13: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "Truncated IHDR chunk" + raise ValueError(msg) + self.im_size = i32(s, 0), i32(s, 4) + try: + self.im_mode, self.im_rawmode = _MODES[(s[8], s[9])] + except Exception: + pass + if s[12]: + self.im_info["interlace"] = 1 + if s[11]: + msg = "unknown filter category" + raise SyntaxError(msg) + return s + + def chunk_IDAT(self, pos: int, length: int) -> NoReturn: + # image data + if "bbox" in self.im_info: + tile = [("zip", self.im_info["bbox"], pos, self.im_rawmode)] + else: + if self.im_n_frames is not None: + self.im_info["default_image"] = True + tile = [("zip", (0, 0) + self.im_size, pos, self.im_rawmode)] + self.im_tile = tile + self.im_idat = length + msg = "image data found" + raise EOFError(msg) + + def chunk_IEND(self, pos: int, length: int) -> NoReturn: + msg = "end of PNG image" + raise EOFError(msg) + + def chunk_PLTE(self, pos: int, length: int) -> bytes: + # palette + s = ImageFile._safe_read(self.fp, length) + if self.im_mode == "P": + self.im_palette = "RGB", s + return s + + def chunk_tRNS(self, pos: int, length: int) -> bytes: + # transparency + s = ImageFile._safe_read(self.fp, length) + if self.im_mode == "P": + if _simple_palette.match(s): + # tRNS contains only one full-transparent entry, + # other entries are full opaque + i = s.find(b"\0") + if i >= 0: + self.im_info["transparency"] = i + else: + # otherwise, we have a byte string with one alpha value + # for each palette entry + self.im_info["transparency"] = s + elif self.im_mode in ("1", "L", "I;16"): + self.im_info["transparency"] = i16(s) + elif self.im_mode == "RGB": + self.im_info["transparency"] = i16(s), i16(s, 2), i16(s, 4) + return s + + def chunk_gAMA(self, pos: int, length: int) -> bytes: + # gamma setting + s = ImageFile._safe_read(self.fp, length) + self.im_info["gamma"] = i32(s) / 100000.0 + return s + + def chunk_cHRM(self, pos: int, length: int) -> bytes: + # chromaticity, 8 unsigned ints, actual value is scaled by 100,000 + # WP x,y, Red x,y, Green x,y Blue x,y + + s = ImageFile._safe_read(self.fp, length) + raw_vals = struct.unpack(">%dI" % (len(s) // 4), s) + self.im_info["chromaticity"] = tuple(elt / 100000.0 for elt in raw_vals) + return s + + def chunk_sRGB(self, pos: int, length: int) -> bytes: + # srgb rendering intent, 1 byte + # 0 perceptual + # 1 relative colorimetric + # 2 saturation + # 3 absolute colorimetric + + s = ImageFile._safe_read(self.fp, length) + if length < 1: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "Truncated sRGB chunk" + raise ValueError(msg) + self.im_info["srgb"] = s[0] + return s + + def chunk_pHYs(self, pos: int, length: int) -> bytes: + # pixels per unit + s = ImageFile._safe_read(self.fp, length) + if length < 9: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "Truncated pHYs chunk" + raise ValueError(msg) + px, py = i32(s, 0), i32(s, 4) + unit = s[8] + if unit == 1: # meter + dpi = px * 0.0254, py * 0.0254 + self.im_info["dpi"] = dpi + elif unit == 0: + self.im_info["aspect"] = px, py + return s + + def chunk_tEXt(self, pos: int, length: int) -> bytes: + # text + s = ImageFile._safe_read(self.fp, length) + try: + k, v = s.split(b"\0", 1) + except ValueError: + # fallback for broken tEXt tags + k = s + v = b"" + if k: + k = k.decode("latin-1", "strict") + v_str = v.decode("latin-1", "replace") + + self.im_info[k] = v if k == "exif" else v_str + self.im_text[k] = v_str + self.check_text_memory(len(v_str)) + + return s + + def chunk_zTXt(self, pos: int, length: int) -> bytes: + # compressed text + s = ImageFile._safe_read(self.fp, length) + try: + k, v = s.split(b"\0", 1) + except ValueError: + k = s + v = b"" + if v: + comp_method = v[0] + else: + comp_method = 0 + if comp_method != 0: + msg = f"Unknown compression method {comp_method} in zTXt chunk" + raise SyntaxError(msg) + try: + v = _safe_zlib_decompress(v[1:]) + except ValueError: + if ImageFile.LOAD_TRUNCATED_IMAGES: + v = b"" + else: + raise + except zlib.error: + v = b"" + + if k: + k = k.decode("latin-1", "strict") + v = v.decode("latin-1", "replace") + + self.im_info[k] = self.im_text[k] = v + self.check_text_memory(len(v)) + + return s + + def chunk_iTXt(self, pos: int, length: int) -> bytes: + # international text + r = s = ImageFile._safe_read(self.fp, length) + try: + k, r = r.split(b"\0", 1) + except ValueError: + return s + if len(r) < 2: + return s + cf, cm, r = r[0], r[1], r[2:] + try: + lang, tk, v = r.split(b"\0", 2) + except ValueError: + return s + if cf != 0: + if cm == 0: + try: + v = _safe_zlib_decompress(v) + except ValueError: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + else: + raise + except zlib.error: + return s + else: + return s + if k == b"XML:com.adobe.xmp": + self.im_info["xmp"] = v + try: + k = k.decode("latin-1", "strict") + lang = lang.decode("utf-8", "strict") + tk = tk.decode("utf-8", "strict") + v = v.decode("utf-8", "strict") + except UnicodeError: + return s + + self.im_info[k] = self.im_text[k] = iTXt(v, lang, tk) + self.check_text_memory(len(v)) + + return s + + def chunk_eXIf(self, pos: int, length: int) -> bytes: + s = ImageFile._safe_read(self.fp, length) + self.im_info["exif"] = b"Exif\x00\x00" + s + return s + + # APNG chunks + def chunk_acTL(self, pos: int, length: int) -> bytes: + s = ImageFile._safe_read(self.fp, length) + if length < 8: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "APNG contains truncated acTL chunk" + raise ValueError(msg) + if self.im_n_frames is not None: + self.im_n_frames = None + warnings.warn("Invalid APNG, will use default PNG image if possible") + return s + n_frames = i32(s) + if n_frames == 0 or n_frames > 0x80000000: + warnings.warn("Invalid APNG, will use default PNG image if possible") + return s + self.im_n_frames = n_frames + self.im_info["loop"] = i32(s, 4) + self.im_custom_mimetype = "image/apng" + return s + + def chunk_fcTL(self, pos: int, length: int) -> bytes: + s = ImageFile._safe_read(self.fp, length) + if length < 26: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "APNG contains truncated fcTL chunk" + raise ValueError(msg) + seq = i32(s) + if (self._seq_num is None and seq != 0) or ( + self._seq_num is not None and self._seq_num != seq - 1 + ): + msg = "APNG contains frame sequence errors" + raise SyntaxError(msg) + self._seq_num = seq + width, height = i32(s, 4), i32(s, 8) + px, py = i32(s, 12), i32(s, 16) + im_w, im_h = self.im_size + if px + width > im_w or py + height > im_h: + msg = "APNG contains invalid frames" + raise SyntaxError(msg) + self.im_info["bbox"] = (px, py, px + width, py + height) + delay_num, delay_den = i16(s, 20), i16(s, 22) + if delay_den == 0: + delay_den = 100 + self.im_info["duration"] = float(delay_num) / float(delay_den) * 1000 + self.im_info["disposal"] = s[24] + self.im_info["blend"] = s[25] + return s + + def chunk_fdAT(self, pos: int, length: int) -> bytes: + if length < 4: + if ImageFile.LOAD_TRUNCATED_IMAGES: + s = ImageFile._safe_read(self.fp, length) + return s + msg = "APNG contains truncated fDAT chunk" + raise ValueError(msg) + s = ImageFile._safe_read(self.fp, 4) + seq = i32(s) + if self._seq_num != seq - 1: + msg = "APNG contains frame sequence errors" + raise SyntaxError(msg) + self._seq_num = seq + return self.chunk_IDAT(pos + 4, length - 4) + + +# -------------------------------------------------------------------- +# PNG reader + + +def _accept(prefix: bytes) -> bool: + return prefix[:8] == _MAGIC + + +## +# Image plugin for PNG images. + + +class PngImageFile(ImageFile.ImageFile): + format = "PNG" + format_description = "Portable network graphics" + + def _open(self) -> None: + if not _accept(self.fp.read(8)): + msg = "not a PNG file" + raise SyntaxError(msg) + self._fp = self.fp + self.__frame = 0 + + # + # Parse headers up to the first IDAT or fDAT chunk + + self.private_chunks: list[tuple[bytes, bytes] | tuple[bytes, bytes, bool]] = [] + self.png: PngStream | None = PngStream(self.fp) + + while True: + # + # get next chunk + + cid, pos, length = self.png.read() + + try: + s = self.png.call(cid, pos, length) + except EOFError: + break + except AttributeError: + logger.debug("%r %s %s (unknown)", cid, pos, length) + s = ImageFile._safe_read(self.fp, length) + if cid[1:2].islower(): + self.private_chunks.append((cid, s)) + + self.png.crc(cid, s) + + # + # Copy relevant attributes from the PngStream. An alternative + # would be to let the PngStream class modify these attributes + # directly, but that introduces circular references which are + # difficult to break if things go wrong in the decoder... + # (believe me, I've tried ;-) + + self._mode = self.png.im_mode + self._size = self.png.im_size + self.info = self.png.im_info + self._text = None + self.tile = self.png.im_tile + self.custom_mimetype = self.png.im_custom_mimetype + self.n_frames = self.png.im_n_frames or 1 + self.default_image = self.info.get("default_image", False) + + if self.png.im_palette: + rawmode, data = self.png.im_palette + self.palette = ImagePalette.raw(rawmode, data) + + if cid == b"fdAT": + self.__prepare_idat = length - 4 + else: + self.__prepare_idat = length # used by load_prepare() + + if self.png.im_n_frames is not None: + self._close_exclusive_fp_after_loading = False + self.png.save_rewind() + self.__rewind_idat = self.__prepare_idat + self.__rewind = self._fp.tell() + if self.default_image: + # IDAT chunk contains default image and not first animation frame + self.n_frames += 1 + self._seek(0) + self.is_animated = self.n_frames > 1 + + @property + def text(self): + # experimental + if self._text is None: + # iTxt, tEXt and zTXt chunks may appear at the end of the file + # So load the file to ensure that they are read + if self.is_animated: + frame = self.__frame + # for APNG, seek to the final frame before loading + self.seek(self.n_frames - 1) + self.load() + if self.is_animated: + self.seek(frame) + return self._text + + def verify(self) -> None: + """Verify PNG file""" + + if self.fp is None: + msg = "verify must be called directly after open" + raise RuntimeError(msg) + + # back up to beginning of IDAT block + self.fp.seek(self.tile[0][2] - 8) + + assert self.png is not None + self.png.verify() + self.png.close() + + if self._exclusive_fp: + self.fp.close() + self.fp = None + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + if frame < self.__frame: + self._seek(0, True) + + last_frame = self.__frame + for f in range(self.__frame + 1, frame + 1): + try: + self._seek(f) + except EOFError as e: + self.seek(last_frame) + msg = "no more images in APNG file" + raise EOFError(msg) from e + + def _seek(self, frame: int, rewind: bool = False) -> None: + assert self.png is not None + + self.dispose: _imaging.ImagingCore | None + if frame == 0: + if rewind: + self._fp.seek(self.__rewind) + self.png.rewind() + self.__prepare_idat = self.__rewind_idat + self.im = None + if self.pyaccess: + self.pyaccess = None + self.info = self.png.im_info + self.tile = self.png.im_tile + self.fp = self._fp + self._prev_im = None + self.dispose = None + self.default_image = self.info.get("default_image", False) + self.dispose_op = self.info.get("disposal") + self.blend_op = self.info.get("blend") + self.dispose_extent = self.info.get("bbox") + self.__frame = 0 + else: + if frame != self.__frame + 1: + msg = f"cannot seek to frame {frame}" + raise ValueError(msg) + + # ensure previous frame was loaded + self.load() + + if self.dispose: + self.im.paste(self.dispose, self.dispose_extent) + self._prev_im = self.im.copy() + + self.fp = self._fp + + # advance to the next frame + if self.__prepare_idat: + ImageFile._safe_read(self.fp, self.__prepare_idat) + self.__prepare_idat = 0 + frame_start = False + while True: + self.fp.read(4) # CRC + + try: + cid, pos, length = self.png.read() + except (struct.error, SyntaxError): + break + + if cid == b"IEND": + msg = "No more images in APNG file" + raise EOFError(msg) + if cid == b"fcTL": + if frame_start: + # there must be at least one fdAT chunk between fcTL chunks + msg = "APNG missing frame data" + raise SyntaxError(msg) + frame_start = True + + try: + self.png.call(cid, pos, length) + except UnicodeDecodeError: + break + except EOFError: + if cid == b"fdAT": + length -= 4 + if frame_start: + self.__prepare_idat = length + break + ImageFile._safe_read(self.fp, length) + except AttributeError: + logger.debug("%r %s %s (unknown)", cid, pos, length) + ImageFile._safe_read(self.fp, length) + + self.__frame = frame + self.tile = self.png.im_tile + self.dispose_op = self.info.get("disposal") + self.blend_op = self.info.get("blend") + self.dispose_extent = self.info.get("bbox") + + if not self.tile: + msg = "image not found in APNG frame" + raise EOFError(msg) + + # setup frame disposal (actual disposal done when needed in the next _seek()) + if self._prev_im is None and self.dispose_op == Disposal.OP_PREVIOUS: + self.dispose_op = Disposal.OP_BACKGROUND + + self.dispose = None + if self.dispose_op == Disposal.OP_PREVIOUS: + if self._prev_im: + self.dispose = self._prev_im.copy() + self.dispose = self._crop(self.dispose, self.dispose_extent) + elif self.dispose_op == Disposal.OP_BACKGROUND: + self.dispose = Image.core.fill(self.mode, self.size) + self.dispose = self._crop(self.dispose, self.dispose_extent) + + def tell(self) -> int: + return self.__frame + + def load_prepare(self) -> None: + """internal: prepare to read PNG file""" + + if self.info.get("interlace"): + self.decoderconfig = self.decoderconfig + (1,) + + self.__idat = self.__prepare_idat # used by load_read() + ImageFile.ImageFile.load_prepare(self) + + def load_read(self, read_bytes: int) -> bytes: + """internal: read more image data""" + + assert self.png is not None + while self.__idat == 0: + # end of chunk, skip forward to next one + + self.fp.read(4) # CRC + + cid, pos, length = self.png.read() + + if cid not in [b"IDAT", b"DDAT", b"fdAT"]: + self.png.push(cid, pos, length) + return b"" + + if cid == b"fdAT": + try: + self.png.call(cid, pos, length) + except EOFError: + pass + self.__idat = length - 4 # sequence_num has already been read + else: + self.__idat = length # empty chunks are allowed + + # read more data from this chunk + if read_bytes <= 0: + read_bytes = self.__idat + else: + read_bytes = min(read_bytes, self.__idat) + + self.__idat = self.__idat - read_bytes + + return self.fp.read(read_bytes) + + def load_end(self) -> None: + """internal: finished reading image data""" + assert self.png is not None + if self.__idat != 0: + self.fp.read(self.__idat) + while True: + self.fp.read(4) # CRC + + try: + cid, pos, length = self.png.read() + except (struct.error, SyntaxError): + break + + if cid == b"IEND": + break + elif cid == b"fcTL" and self.is_animated: + # start of the next frame, stop reading + self.__prepare_idat = 0 + self.png.push(cid, pos, length) + break + + try: + self.png.call(cid, pos, length) + except UnicodeDecodeError: + break + except EOFError: + if cid == b"fdAT": + length -= 4 + try: + ImageFile._safe_read(self.fp, length) + except OSError as e: + if ImageFile.LOAD_TRUNCATED_IMAGES: + break + else: + raise e + except AttributeError: + logger.debug("%r %s %s (unknown)", cid, pos, length) + s = ImageFile._safe_read(self.fp, length) + if cid[1:2].islower(): + self.private_chunks.append((cid, s, True)) + self._text = self.png.im_text + if not self.is_animated: + self.png.close() + self.png = None + else: + if self._prev_im and self.blend_op == Blend.OP_OVER: + updated = self._crop(self.im, self.dispose_extent) + if self.im.mode == "RGB" and "transparency" in self.info: + mask = updated.convert_transparent( + "RGBA", self.info["transparency"] + ) + else: + mask = updated.convert("RGBA") + self._prev_im.paste(updated, self.dispose_extent, mask) + self.im = self._prev_im + if self.pyaccess: + self.pyaccess = None + + def _getexif(self) -> dict[str, Any] | None: + if "exif" not in self.info: + self.load() + if "exif" not in self.info and "Raw profile type exif" not in self.info: + return None + return self.getexif()._get_merged_dict() + + def getexif(self) -> Image.Exif: + if "exif" not in self.info: + self.load() + + return super().getexif() + + +# -------------------------------------------------------------------- +# PNG writer + +_OUTMODES = { + # supported PIL modes, and corresponding rawmode, bit depth and color type + "1": ("1", b"\x01", b"\x00"), + "L;1": ("L;1", b"\x01", b"\x00"), + "L;2": ("L;2", b"\x02", b"\x00"), + "L;4": ("L;4", b"\x04", b"\x00"), + "L": ("L", b"\x08", b"\x00"), + "LA": ("LA", b"\x08", b"\x04"), + "I": ("I;16B", b"\x10", b"\x00"), + "I;16": ("I;16B", b"\x10", b"\x00"), + "I;16B": ("I;16B", b"\x10", b"\x00"), + "P;1": ("P;1", b"\x01", b"\x03"), + "P;2": ("P;2", b"\x02", b"\x03"), + "P;4": ("P;4", b"\x04", b"\x03"), + "P": ("P", b"\x08", b"\x03"), + "RGB": ("RGB", b"\x08", b"\x02"), + "RGBA": ("RGBA", b"\x08", b"\x06"), +} + + +def putchunk(fp, cid, *data): + """Write a PNG chunk (including CRC field)""" + + data = b"".join(data) + + fp.write(o32(len(data)) + cid) + fp.write(data) + crc = _crc32(data, _crc32(cid)) + fp.write(o32(crc)) + + +class _idat: + # wrap output from the encoder in IDAT chunks + + def __init__(self, fp, chunk): + self.fp = fp + self.chunk = chunk + + def write(self, data: bytes) -> None: + self.chunk(self.fp, b"IDAT", data) + + +class _fdat: + # wrap encoder output in fdAT chunks + + def __init__(self, fp, chunk, seq_num): + self.fp = fp + self.chunk = chunk + self.seq_num = seq_num + + def write(self, data: bytes) -> None: + self.chunk(self.fp, b"fdAT", o32(self.seq_num), data) + self.seq_num += 1 + + +def _write_multiple_frames(im, fp, chunk, mode, rawmode, default_image, append_images): + duration = im.encoderinfo.get("duration") + loop = im.encoderinfo.get("loop", im.info.get("loop", 0)) + disposal = im.encoderinfo.get("disposal", im.info.get("disposal", Disposal.OP_NONE)) + blend = im.encoderinfo.get("blend", im.info.get("blend", Blend.OP_SOURCE)) + + if default_image: + chain = itertools.chain(append_images) + else: + chain = itertools.chain([im], append_images) + + im_frames = [] + frame_count = 0 + for im_seq in chain: + for im_frame in ImageSequence.Iterator(im_seq): + if im_frame.mode == mode: + im_frame = im_frame.copy() + else: + im_frame = im_frame.convert(mode) + encoderinfo = im.encoderinfo.copy() + if isinstance(duration, (list, tuple)): + encoderinfo["duration"] = duration[frame_count] + elif duration is None and "duration" in im_frame.info: + encoderinfo["duration"] = im_frame.info["duration"] + if isinstance(disposal, (list, tuple)): + encoderinfo["disposal"] = disposal[frame_count] + if isinstance(blend, (list, tuple)): + encoderinfo["blend"] = blend[frame_count] + frame_count += 1 + + if im_frames: + previous = im_frames[-1] + prev_disposal = previous["encoderinfo"].get("disposal") + prev_blend = previous["encoderinfo"].get("blend") + if prev_disposal == Disposal.OP_PREVIOUS and len(im_frames) < 2: + prev_disposal = Disposal.OP_BACKGROUND + + if prev_disposal == Disposal.OP_BACKGROUND: + base_im = previous["im"].copy() + dispose = Image.core.fill("RGBA", im.size, (0, 0, 0, 0)) + bbox = previous["bbox"] + if bbox: + dispose = dispose.crop(bbox) + else: + bbox = (0, 0) + im.size + base_im.paste(dispose, bbox) + elif prev_disposal == Disposal.OP_PREVIOUS: + base_im = im_frames[-2]["im"] + else: + base_im = previous["im"] + delta = ImageChops.subtract_modulo( + im_frame.convert("RGBA"), base_im.convert("RGBA") + ) + bbox = delta.getbbox(alpha_only=False) + if ( + not bbox + and prev_disposal == encoderinfo.get("disposal") + and prev_blend == encoderinfo.get("blend") + and "duration" in encoderinfo + ): + previous["encoderinfo"]["duration"] += encoderinfo["duration"] + continue + else: + bbox = None + im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo}) + + if len(im_frames) == 1 and not default_image: + return im_frames[0]["im"] + + # animation control + chunk( + fp, + b"acTL", + o32(len(im_frames)), # 0: num_frames + o32(loop), # 4: num_plays + ) + + # default image IDAT (if it exists) + if default_image: + if im.mode != mode: + im = im.convert(mode) + ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) + + seq_num = 0 + for frame, frame_data in enumerate(im_frames): + im_frame = frame_data["im"] + if not frame_data["bbox"]: + bbox = (0, 0) + im_frame.size + else: + bbox = frame_data["bbox"] + im_frame = im_frame.crop(bbox) + size = im_frame.size + encoderinfo = frame_data["encoderinfo"] + frame_duration = int(round(encoderinfo.get("duration", 0))) + frame_disposal = encoderinfo.get("disposal", disposal) + frame_blend = encoderinfo.get("blend", blend) + # frame control + chunk( + fp, + b"fcTL", + o32(seq_num), # sequence_number + o32(size[0]), # width + o32(size[1]), # height + o32(bbox[0]), # x_offset + o32(bbox[1]), # y_offset + o16(frame_duration), # delay_numerator + o16(1000), # delay_denominator + o8(frame_disposal), # dispose_op + o8(frame_blend), # blend_op + ) + seq_num += 1 + # frame data + if frame == 0 and not default_image: + # first frame must be in IDAT chunks for backwards compatibility + ImageFile._save( + im_frame, + _idat(fp, chunk), + [("zip", (0, 0) + im_frame.size, 0, rawmode)], + ) + else: + fdat_chunks = _fdat(fp, chunk, seq_num) + ImageFile._save( + im_frame, + fdat_chunks, + [("zip", (0, 0) + im_frame.size, 0, rawmode)], + ) + seq_num = fdat_chunks.seq_num + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + _save(im, fp, filename, save_all=True) + + +def _save(im, fp, filename, chunk=putchunk, save_all=False): + # save an image to disk (called by the save method) + + if save_all: + default_image = im.encoderinfo.get( + "default_image", im.info.get("default_image") + ) + modes = set() + sizes = set() + append_images = im.encoderinfo.get("append_images", []) + for im_seq in itertools.chain([im], append_images): + for im_frame in ImageSequence.Iterator(im_seq): + modes.add(im_frame.mode) + sizes.add(im_frame.size) + for mode in ("RGBA", "RGB", "P"): + if mode in modes: + break + else: + mode = modes.pop() + size = tuple(max(frame_size[i] for frame_size in sizes) for i in range(2)) + else: + size = im.size + mode = im.mode + + outmode = mode + if mode == "P": + # + # attempt to minimize storage requirements for palette images + if "bits" in im.encoderinfo: + # number of bits specified by user + colors = min(1 << im.encoderinfo["bits"], 256) + else: + # check palette contents + if im.palette: + colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 1) + else: + colors = 256 + + if colors <= 16: + if colors <= 2: + bits = 1 + elif colors <= 4: + bits = 2 + else: + bits = 4 + outmode += f";{bits}" + + # encoder options + im.encoderconfig = ( + im.encoderinfo.get("optimize", False), + im.encoderinfo.get("compress_level", -1), + im.encoderinfo.get("compress_type", -1), + im.encoderinfo.get("dictionary", b""), + ) + + # get the corresponding PNG mode + try: + rawmode, bit_depth, color_type = _OUTMODES[outmode] + except KeyError as e: + msg = f"cannot write mode {mode} as PNG" + raise OSError(msg) from e + + # + # write minimal PNG file + + fp.write(_MAGIC) + + chunk( + fp, + b"IHDR", + o32(size[0]), # 0: size + o32(size[1]), + bit_depth, + color_type, + b"\0", # 10: compression + b"\0", # 11: filter category + b"\0", # 12: interlace flag + ) + + chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"] + + icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile")) + if icc: + # ICC profile + # according to PNG spec, the iCCP chunk contains: + # Profile name 1-79 bytes (character string) + # Null separator 1 byte (null character) + # Compression method 1 byte (0) + # Compressed profile n bytes (zlib with deflate compression) + name = b"ICC Profile" + data = name + b"\0\0" + zlib.compress(icc) + chunk(fp, b"iCCP", data) + + # You must either have sRGB or iCCP. + # Disallow sRGB chunks when an iCCP-chunk has been emitted. + chunks.remove(b"sRGB") + + info = im.encoderinfo.get("pnginfo") + if info: + chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"] + for info_chunk in info.chunks: + cid, data = info_chunk[:2] + if cid in chunks: + chunks.remove(cid) + chunk(fp, cid, data) + elif cid in chunks_multiple_allowed: + chunk(fp, cid, data) + elif cid[1:2].islower(): + # Private chunk + after_idat = len(info_chunk) == 3 and info_chunk[2] + if not after_idat: + chunk(fp, cid, data) + + if im.mode == "P": + palette_byte_number = colors * 3 + palette_bytes = im.im.getpalette("RGB")[:palette_byte_number] + while len(palette_bytes) < palette_byte_number: + palette_bytes += b"\0" + chunk(fp, b"PLTE", palette_bytes) + + transparency = im.encoderinfo.get("transparency", im.info.get("transparency", None)) + + if transparency or transparency == 0: + if im.mode == "P": + # limit to actual palette size + alpha_bytes = colors + if isinstance(transparency, bytes): + chunk(fp, b"tRNS", transparency[:alpha_bytes]) + else: + transparency = max(0, min(255, transparency)) + alpha = b"\xFF" * transparency + b"\0" + chunk(fp, b"tRNS", alpha[:alpha_bytes]) + elif im.mode in ("1", "L", "I", "I;16"): + transparency = max(0, min(65535, transparency)) + chunk(fp, b"tRNS", o16(transparency)) + elif im.mode == "RGB": + red, green, blue = transparency + chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue)) + else: + if "transparency" in im.encoderinfo: + # don't bother with transparency if it's an RGBA + # and it's in the info dict. It's probably just stale. + msg = "cannot use transparency for this mode" + raise OSError(msg) + else: + if im.mode == "P" and im.im.getpalettemode() == "RGBA": + alpha = im.im.getpalette("RGBA", "A") + alpha_bytes = colors + chunk(fp, b"tRNS", alpha[:alpha_bytes]) + + dpi = im.encoderinfo.get("dpi") + if dpi: + chunk( + fp, + b"pHYs", + o32(int(dpi[0] / 0.0254 + 0.5)), + o32(int(dpi[1] / 0.0254 + 0.5)), + b"\x01", + ) + + if info: + chunks = [b"bKGD", b"hIST"] + for info_chunk in info.chunks: + cid, data = info_chunk[:2] + if cid in chunks: + chunks.remove(cid) + chunk(fp, cid, data) + + exif = im.encoderinfo.get("exif") + if exif: + if isinstance(exif, Image.Exif): + exif = exif.tobytes(8) + if exif.startswith(b"Exif\x00\x00"): + exif = exif[6:] + chunk(fp, b"eXIf", exif) + + if save_all: + im = _write_multiple_frames( + im, fp, chunk, mode, rawmode, default_image, append_images + ) + if im: + ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) + + if info: + for info_chunk in info.chunks: + cid, data = info_chunk[:2] + if cid[1:2].islower(): + # Private chunk + after_idat = len(info_chunk) == 3 and info_chunk[2] + if after_idat: + chunk(fp, cid, data) + + chunk(fp, b"IEND", b"") + + if hasattr(fp, "flush"): + fp.flush() + + +# -------------------------------------------------------------------- +# PNG chunk converter + + +def getchunks(im, **params): + """Return a list of PNG chunks representing this image.""" + + class collector: + data = [] + + def write(self, data: bytes) -> None: + pass + + def append(self, chunk: bytes) -> None: + self.data.append(chunk) + + def append(fp, cid, *data): + data = b"".join(data) + crc = o32(_crc32(data, _crc32(cid))) + fp.append((cid, data, crc)) + + fp = collector() + + try: + im.encoderinfo = params + _save(im, fp, None, append) + finally: + del im.encoderinfo + + return fp.data + + +# -------------------------------------------------------------------- +# Registry + +Image.register_open(PngImageFile.format, PngImageFile, _accept) +Image.register_save(PngImageFile.format, _save) +Image.register_save_all(PngImageFile.format, _save_all) + +Image.register_extensions(PngImageFile.format, [".png", ".apng"]) + +Image.register_mime(PngImageFile.format, "image/png") diff --git a/.venv/lib/python3.12/site-packages/PIL/PpmImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PpmImagePlugin.py new file mode 100644 index 0000000..16c9ccb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PpmImagePlugin.py @@ -0,0 +1,371 @@ +# +# The Python Imaging Library. +# $Id$ +# +# PPM support for PIL +# +# History: +# 96-03-24 fl Created +# 98-03-06 fl Write RGBA images (as RGB, that is) +# +# Copyright (c) Secret Labs AB 1997-98. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import math +from typing import IO + +from . import Image, ImageFile +from ._binary import i16be as i16 +from ._binary import o8 +from ._binary import o32le as o32 + +# +# -------------------------------------------------------------------- + +b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d" + +MODES = { + # standard + b"P1": "1", + b"P2": "L", + b"P3": "RGB", + b"P4": "1", + b"P5": "L", + b"P6": "RGB", + # extensions + b"P0CMYK": "CMYK", + b"Pf": "F", + # PIL extensions (for test purposes only) + b"PyP": "P", + b"PyRGBA": "RGBA", + b"PyCMYK": "CMYK", +} + + +def _accept(prefix: bytes) -> bool: + return prefix[0:1] == b"P" and prefix[1] in b"0123456fy" + + +## +# Image plugin for PBM, PGM, and PPM images. + + +class PpmImageFile(ImageFile.ImageFile): + format = "PPM" + format_description = "Pbmplus image" + + def _read_magic(self) -> bytes: + assert self.fp is not None + + magic = b"" + # read until whitespace or longest available magic number + for _ in range(6): + c = self.fp.read(1) + if not c or c in b_whitespace: + break + magic += c + return magic + + def _read_token(self) -> bytes: + assert self.fp is not None + + token = b"" + while len(token) <= 10: # read until next whitespace or limit of 10 characters + c = self.fp.read(1) + if not c: + break + elif c in b_whitespace: # token ended + if not token: + # skip whitespace at start + continue + break + elif c == b"#": + # ignores rest of the line; stops at CR, LF or EOF + while self.fp.read(1) not in b"\r\n": + pass + continue + token += c + if not token: + # Token was not even 1 byte + msg = "Reached EOF while reading header" + raise ValueError(msg) + elif len(token) > 10: + msg = f"Token too long in file header: {token.decode()}" + raise ValueError(msg) + return token + + def _open(self) -> None: + assert self.fp is not None + + magic_number = self._read_magic() + try: + mode = MODES[magic_number] + except KeyError: + msg = "not a PPM file" + raise SyntaxError(msg) + self._mode = mode + + if magic_number in (b"P1", b"P4"): + self.custom_mimetype = "image/x-portable-bitmap" + elif magic_number in (b"P2", b"P5"): + self.custom_mimetype = "image/x-portable-graymap" + elif magic_number in (b"P3", b"P6"): + self.custom_mimetype = "image/x-portable-pixmap" + + self._size = int(self._read_token()), int(self._read_token()) + + decoder_name = "raw" + if magic_number in (b"P1", b"P2", b"P3"): + decoder_name = "ppm_plain" + + args: str | tuple[str | int, ...] + if mode == "1": + args = "1;I" + elif mode == "F": + scale = float(self._read_token()) + if scale == 0.0 or not math.isfinite(scale): + msg = "scale must be finite and non-zero" + raise ValueError(msg) + self.info["scale"] = abs(scale) + + rawmode = "F;32F" if scale < 0 else "F;32BF" + args = (rawmode, 0, -1) + else: + maxval = int(self._read_token()) + if not 0 < maxval < 65536: + msg = "maxval must be greater than 0 and less than 65536" + raise ValueError(msg) + if maxval > 255 and mode == "L": + self._mode = "I" + + rawmode = mode + if decoder_name != "ppm_plain": + # If maxval matches a bit depth, use the raw decoder directly + if maxval == 65535 and mode == "L": + rawmode = "I;16B" + elif maxval != 255: + decoder_name = "ppm" + + args = rawmode if decoder_name == "raw" else (rawmode, maxval) + self.tile = [(decoder_name, (0, 0) + self.size, self.fp.tell(), args)] + + +# +# -------------------------------------------------------------------- + + +class PpmPlainDecoder(ImageFile.PyDecoder): + _pulls_fd = True + _comment_spans: bool + + def _read_block(self) -> bytes: + assert self.fd is not None + + return self.fd.read(ImageFile.SAFEBLOCK) + + def _find_comment_end(self, block: bytes, start: int = 0) -> int: + a = block.find(b"\n", start) + b = block.find(b"\r", start) + return min(a, b) if a * b > 0 else max(a, b) # lowest nonnegative index (or -1) + + def _ignore_comments(self, block: bytes) -> bytes: + if self._comment_spans: + # Finish current comment + while block: + comment_end = self._find_comment_end(block) + if comment_end != -1: + # Comment ends in this block + # Delete tail of comment + block = block[comment_end + 1 :] + break + else: + # Comment spans whole block + # So read the next block, looking for the end + block = self._read_block() + + # Search for any further comments + self._comment_spans = False + while True: + comment_start = block.find(b"#") + if comment_start == -1: + # No comment found + break + comment_end = self._find_comment_end(block, comment_start) + if comment_end != -1: + # Comment ends in this block + # Delete comment + block = block[:comment_start] + block[comment_end + 1 :] + else: + # Comment continues to next block(s) + block = block[:comment_start] + self._comment_spans = True + break + return block + + def _decode_bitonal(self) -> bytearray: + """ + This is a separate method because in the plain PBM format, all data tokens are + exactly one byte, so the inter-token whitespace is optional. + """ + data = bytearray() + total_bytes = self.state.xsize * self.state.ysize + + while len(data) != total_bytes: + block = self._read_block() # read next block + if not block: + # eof + break + + block = self._ignore_comments(block) + + tokens = b"".join(block.split()) + for token in tokens: + if token not in (48, 49): + msg = b"Invalid token for this mode: %s" % bytes([token]) + raise ValueError(msg) + data = (data + tokens)[:total_bytes] + invert = bytes.maketrans(b"01", b"\xFF\x00") + return data.translate(invert) + + def _decode_blocks(self, maxval: int) -> bytearray: + data = bytearray() + max_len = 10 + out_byte_count = 4 if self.mode == "I" else 1 + out_max = 65535 if self.mode == "I" else 255 + bands = Image.getmodebands(self.mode) + total_bytes = self.state.xsize * self.state.ysize * bands * out_byte_count + + half_token = b"" + while len(data) != total_bytes: + block = self._read_block() # read next block + if not block: + if half_token: + block = bytearray(b" ") # flush half_token + else: + # eof + break + + block = self._ignore_comments(block) + + if half_token: + block = half_token + block # stitch half_token to new block + half_token = b"" + + tokens = block.split() + + if block and not block[-1:].isspace(): # block might split token + half_token = tokens.pop() # save half token for later + if len(half_token) > max_len: # prevent buildup of half_token + msg = ( + b"Token too long found in data: %s" % half_token[: max_len + 1] + ) + raise ValueError(msg) + + for token in tokens: + if len(token) > max_len: + msg = b"Token too long found in data: %s" % token[: max_len + 1] + raise ValueError(msg) + value = int(token) + if value < 0: + msg_str = f"Channel value is negative: {value}" + raise ValueError(msg_str) + if value > maxval: + msg_str = f"Channel value too large for this mode: {value}" + raise ValueError(msg_str) + value = round(value / maxval * out_max) + data += o32(value) if self.mode == "I" else o8(value) + if len(data) == total_bytes: # finished! + break + return data + + def decode(self, buffer: bytes) -> tuple[int, int]: + self._comment_spans = False + if self.mode == "1": + data = self._decode_bitonal() + rawmode = "1;8" + else: + maxval = self.args[-1] + data = self._decode_blocks(maxval) + rawmode = "I;32" if self.mode == "I" else self.mode + self.set_as_raw(bytes(data), rawmode) + return -1, 0 + + +class PpmDecoder(ImageFile.PyDecoder): + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + + data = bytearray() + maxval = self.args[-1] + in_byte_count = 1 if maxval < 256 else 2 + out_byte_count = 4 if self.mode == "I" else 1 + out_max = 65535 if self.mode == "I" else 255 + bands = Image.getmodebands(self.mode) + dest_length = self.state.xsize * self.state.ysize * bands * out_byte_count + while len(data) < dest_length: + pixels = self.fd.read(in_byte_count * bands) + if len(pixels) < in_byte_count * bands: + # eof + break + for b in range(bands): + value = ( + pixels[b] if in_byte_count == 1 else i16(pixels, b * in_byte_count) + ) + value = min(out_max, round(value / maxval * out_max)) + data += o32(value) if self.mode == "I" else o8(value) + rawmode = "I;32" if self.mode == "I" else self.mode + self.set_as_raw(bytes(data), rawmode) + return -1, 0 + + +# +# -------------------------------------------------------------------- + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode == "1": + rawmode, head = "1;I", b"P4" + elif im.mode == "L": + rawmode, head = "L", b"P5" + elif im.mode == "I": + rawmode, head = "I;16B", b"P5" + elif im.mode in ("RGB", "RGBA"): + rawmode, head = "RGB", b"P6" + elif im.mode == "F": + rawmode, head = "F;32F", b"Pf" + else: + msg = f"cannot write mode {im.mode} as PPM" + raise OSError(msg) + fp.write(head + b"\n%d %d\n" % im.size) + if head == b"P6": + fp.write(b"255\n") + elif head == b"P5": + if rawmode == "L": + fp.write(b"255\n") + else: + fp.write(b"65535\n") + elif head == b"Pf": + fp.write(b"-1.0\n") + row_order = -1 if im.mode == "F" else 1 + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, row_order))]) + + +# +# -------------------------------------------------------------------- + + +Image.register_open(PpmImageFile.format, PpmImageFile, _accept) +Image.register_save(PpmImageFile.format, _save) + +Image.register_decoder("ppm", PpmDecoder) +Image.register_decoder("ppm_plain", PpmPlainDecoder) + +Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm", ".pnm", ".pfm"]) + +Image.register_mime(PpmImageFile.format, "image/x-portable-anymap") diff --git a/.venv/lib/python3.12/site-packages/PIL/PsdImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/PsdImagePlugin.py new file mode 100644 index 0000000..edf698b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PsdImagePlugin.py @@ -0,0 +1,326 @@ +# +# The Python Imaging Library +# $Id$ +# +# Adobe PSD 2.5/3.0 file handling +# +# History: +# 1995-09-01 fl Created +# 1997-01-03 fl Read most PSD images +# 1997-01-18 fl Fixed P and CMYK support +# 2001-10-21 fl Added seek/tell support (for layers) +# +# Copyright (c) 1997-2001 by Secret Labs AB. +# Copyright (c) 1995-2001 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +from functools import cached_property + +from . import Image, ImageFile, ImagePalette +from ._binary import i8 +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._binary import si16be as si16 +from ._binary import si32be as si32 + +MODES = { + # (photoshop mode, bits) -> (pil mode, required channels) + (0, 1): ("1", 1), + (0, 8): ("L", 1), + (1, 8): ("L", 1), + (2, 8): ("P", 1), + (3, 8): ("RGB", 3), + (4, 8): ("CMYK", 4), + (7, 8): ("L", 1), # FIXME: multilayer + (8, 8): ("L", 1), # duotone + (9, 8): ("LAB", 3), +} + + +# --------------------------------------------------------------------. +# read PSD images + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"8BPS" + + +## +# Image plugin for Photoshop images. + + +class PsdImageFile(ImageFile.ImageFile): + format = "PSD" + format_description = "Adobe Photoshop" + _close_exclusive_fp_after_loading = False + + def _open(self) -> None: + read = self.fp.read + + # + # header + + s = read(26) + if not _accept(s) or i16(s, 4) != 1: + msg = "not a PSD file" + raise SyntaxError(msg) + + psd_bits = i16(s, 22) + psd_channels = i16(s, 12) + psd_mode = i16(s, 24) + + mode, channels = MODES[(psd_mode, psd_bits)] + + if channels > psd_channels: + msg = "not enough channels" + raise OSError(msg) + if mode == "RGB" and psd_channels == 4: + mode = "RGBA" + channels = 4 + + self._mode = mode + self._size = i32(s, 18), i32(s, 14) + + # + # color mode data + + size = i32(read(4)) + if size: + data = read(size) + if mode == "P" and size == 768: + self.palette = ImagePalette.raw("RGB;L", data) + + # + # image resources + + self.resources = [] + + size = i32(read(4)) + if size: + # load resources + end = self.fp.tell() + size + while self.fp.tell() < end: + read(4) # signature + id = i16(read(2)) + name = read(i8(read(1))) + if not (len(name) & 1): + read(1) # padding + data = read(i32(read(4))) + if len(data) & 1: + read(1) # padding + self.resources.append((id, name, data)) + if id == 1039: # ICC profile + self.info["icc_profile"] = data + + # + # layer and mask information + + self._layers_position = None + + size = i32(read(4)) + if size: + end = self.fp.tell() + size + size = i32(read(4)) + if size: + self._layers_position = self.fp.tell() + self._layers_size = size + self.fp.seek(end) + self._n_frames: int | None = None + + # + # image descriptor + + self.tile = _maketile(self.fp, mode, (0, 0) + self.size, channels) + + # keep the file open + self._fp = self.fp + self.frame = 1 + self._min_frame = 1 + + @cached_property + def layers(self): + layers = [] + if self._layers_position is not None: + self._fp.seek(self._layers_position) + _layer_data = io.BytesIO(ImageFile._safe_read(self._fp, self._layers_size)) + layers = _layerinfo(_layer_data, self._layers_size) + self._n_frames = len(layers) + return layers + + @property + def n_frames(self) -> int: + if self._n_frames is None: + self._n_frames = len(self.layers) + return self._n_frames + + @property + def is_animated(self) -> bool: + return len(self.layers) > 1 + + def seek(self, layer: int) -> None: + if not self._seek_check(layer): + return + + # seek to given layer (1..max) + try: + _, mode, _, tile = self.layers[layer - 1] + self._mode = mode + self.tile = tile + self.frame = layer + self.fp = self._fp + except IndexError as e: + msg = "no such layer" + raise EOFError(msg) from e + + def tell(self) -> int: + # return layer number (0=image, 1..max=layers) + return self.frame + + +def _layerinfo(fp, ct_bytes): + # read layerinfo block + layers = [] + + def read(size): + return ImageFile._safe_read(fp, size) + + ct = si16(read(2)) + + # sanity check + if ct_bytes < (abs(ct) * 20): + msg = "Layer block too short for number of layers requested" + raise SyntaxError(msg) + + for _ in range(abs(ct)): + # bounding box + y0 = si32(read(4)) + x0 = si32(read(4)) + y1 = si32(read(4)) + x1 = si32(read(4)) + + # image info + mode = [] + ct_types = i16(read(2)) + if ct_types > 4: + fp.seek(ct_types * 6 + 12, io.SEEK_CUR) + size = i32(read(4)) + fp.seek(size, io.SEEK_CUR) + continue + + for _ in range(ct_types): + type = i16(read(2)) + + if type == 65535: + m = "A" + else: + m = "RGBA"[type] + + mode.append(m) + read(4) # size + + # figure out the image mode + mode.sort() + if mode == ["R"]: + mode = "L" + elif mode == ["B", "G", "R"]: + mode = "RGB" + elif mode == ["A", "B", "G", "R"]: + mode = "RGBA" + else: + mode = None # unknown + + # skip over blend flags and extra information + read(12) # filler + name = "" + size = i32(read(4)) # length of the extra data field + if size: + data_end = fp.tell() + size + + length = i32(read(4)) + if length: + fp.seek(length - 16, io.SEEK_CUR) + + length = i32(read(4)) + if length: + fp.seek(length, io.SEEK_CUR) + + length = i8(read(1)) + if length: + # Don't know the proper encoding, + # Latin-1 should be a good guess + name = read(length).decode("latin-1", "replace") + + fp.seek(data_end) + layers.append((name, mode, (x0, y0, x1, y1))) + + # get tiles + for i, (name, mode, bbox) in enumerate(layers): + tile = [] + for m in mode: + t = _maketile(fp, m, bbox, 1) + if t: + tile.extend(t) + layers[i] = name, mode, bbox, tile + + return layers + + +def _maketile(file, mode, bbox, channels): + tile = None + read = file.read + + compression = i16(read(2)) + + xsize = bbox[2] - bbox[0] + ysize = bbox[3] - bbox[1] + + offset = file.tell() + + if compression == 0: + # + # raw compression + tile = [] + for channel in range(channels): + layer = mode[channel] + if mode == "CMYK": + layer += ";I" + tile.append(("raw", bbox, offset, layer)) + offset = offset + xsize * ysize + + elif compression == 1: + # + # packbits compression + i = 0 + tile = [] + bytecount = read(channels * ysize * 2) + offset = file.tell() + for channel in range(channels): + layer = mode[channel] + if mode == "CMYK": + layer += ";I" + tile.append(("packbits", bbox, offset, layer)) + for y in range(ysize): + offset = offset + i16(bytecount, i) + i += 2 + + file.seek(offset) + + if offset & 1: + read(1) # padding + + return tile + + +# -------------------------------------------------------------------- +# registry + + +Image.register_open(PsdImageFile.format, PsdImageFile, _accept) + +Image.register_extension(PsdImageFile.format, ".psd") + +Image.register_mime(PsdImageFile.format, "image/vnd.adobe.photoshop") diff --git a/.venv/lib/python3.12/site-packages/PIL/PyAccess.py b/.venv/lib/python3.12/site-packages/PIL/PyAccess.py new file mode 100644 index 0000000..3be1cca --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/PyAccess.py @@ -0,0 +1,381 @@ +# +# The Python Imaging Library +# Pillow fork +# +# Python implementation of the PixelAccess Object +# +# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved. +# Copyright (c) 1995-2009 by Fredrik Lundh. +# Copyright (c) 2013 Eric Soroos +# +# See the README file for information on usage and redistribution +# + +# Notes: +# +# * Implements the pixel access object following Access.c +# * Taking only the tuple form, which is used from python. +# * Fill.c uses the integer form, but it's still going to use the old +# Access.c implementation. +# +from __future__ import annotations + +import logging +import sys +from typing import TYPE_CHECKING + +from ._deprecate import deprecate + +FFI: type +try: + from cffi import FFI + + defs = """ + struct Pixel_RGBA { + unsigned char r,g,b,a; + }; + struct Pixel_I16 { + unsigned char l,r; + }; + """ + ffi = FFI() + ffi.cdef(defs) +except ImportError as ex: + # Allow error import for doc purposes, but error out when accessing + # anything in core. + from ._util import DeferredError + + FFI = ffi = DeferredError.new(ex) + +logger = logging.getLogger(__name__) + +if TYPE_CHECKING: + from . import Image + + +class PyAccess: + def __init__(self, img: Image.Image, readonly: bool = False) -> None: + deprecate("PyAccess", 11) + vals = dict(img.im.unsafe_ptrs) + self.readonly = readonly + self.image8 = ffi.cast("unsigned char **", vals["image8"]) + self.image32 = ffi.cast("int **", vals["image32"]) + self.image = ffi.cast("unsigned char **", vals["image"]) + self.xsize, self.ysize = img.im.size + self._img = img + + # Keep pointer to im object to prevent dereferencing. + self._im = img.im + if self._im.mode in ("P", "PA"): + self._palette = img.palette + + # Debugging is polluting test traces, only useful here + # when hacking on PyAccess + # logger.debug("%s", vals) + self._post_init() + + def _post_init(self) -> None: + pass + + def __setitem__( + self, + xy: tuple[int, int] | list[int], + color: float | tuple[int, ...] | list[int], + ) -> None: + """ + Modifies the pixel at x,y. The color is given as a single + numerical value for single band images, and a tuple for + multi-band images. In addition to this, RGB and RGBA tuples + are accepted for P and PA images. + + :param xy: The pixel coordinate, given as (x, y). See + :ref:`coordinate-system`. + :param color: The pixel value. + """ + if self.readonly: + msg = "Attempt to putpixel a read only image" + raise ValueError(msg) + (x, y) = xy + if x < 0: + x = self.xsize + x + if y < 0: + y = self.ysize + y + (x, y) = self.check_xy((x, y)) + + if ( + self._im.mode in ("P", "PA") + and isinstance(color, (list, tuple)) + and len(color) in [3, 4] + ): + # RGB or RGBA value for a P or PA image + if self._im.mode == "PA": + alpha = color[3] if len(color) == 4 else 255 + color = color[:3] + palette_index = self._palette.getcolor(color, self._img) + color = (palette_index, alpha) if self._im.mode == "PA" else palette_index + + return self.set_pixel(x, y, color) + + def __getitem__(self, xy: tuple[int, int] | list[int]) -> float | tuple[int, ...]: + """ + Returns the pixel at x,y. The pixel is returned as a single + value for single band images or a tuple for multiple band + images + + :param xy: The pixel coordinate, given as (x, y). See + :ref:`coordinate-system`. + :returns: a pixel value for single band images, a tuple of + pixel values for multiband images. + """ + (x, y) = xy + if x < 0: + x = self.xsize + x + if y < 0: + y = self.ysize + y + (x, y) = self.check_xy((x, y)) + return self.get_pixel(x, y) + + putpixel = __setitem__ + getpixel = __getitem__ + + def check_xy(self, xy: tuple[int, int]) -> tuple[int, int]: + (x, y) = xy + if not (0 <= x < self.xsize and 0 <= y < self.ysize): + msg = "pixel location out of range" + raise ValueError(msg) + return xy + + def get_pixel(self, x: int, y: int) -> float | tuple[int, ...]: + raise NotImplementedError() + + def set_pixel( + self, x: int, y: int, color: float | tuple[int, ...] | list[int] + ) -> None: + raise NotImplementedError() + + +class _PyAccess32_2(PyAccess): + """PA, LA, stored in first and last bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.a + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.a = min(color[1], 255) + + +class _PyAccess32_3(PyAccess): + """RGB and friends, stored in the first three bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.g, pixel.b + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.g = min(color[1], 255) + pixel.b = min(color[2], 255) + pixel.a = 255 + + +class _PyAccess32_4(PyAccess): + """RGBA etc, all 4 bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int, int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.g, pixel.b, pixel.a + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.g = min(color[1], 255) + pixel.b = min(color[2], 255) + pixel.a = min(color[3], 255) + + +class _PyAccess8(PyAccess): + """1, L, P, 8 bit images stored as uint8""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image8 + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # integer + self.pixels[y][x] = min(color, 255) + except TypeError: + # tuple + self.pixels[y][x] = min(color[0], 255) + + +class _PyAccessI16_N(PyAccess): + """I;16 access, native bitendian without conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("unsigned short **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # integer + self.pixels[y][x] = min(color, 65535) + except TypeError: + # tuple + self.pixels[y][x] = min(color[0], 65535) + + +class _PyAccessI16_L(PyAccess): + """I;16L access, with conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_I16 **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + pixel = self.pixels[y][x] + return pixel.l + pixel.r * 256 + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + try: + color = min(color, 65535) + except TypeError: + color = min(color[0], 65535) + + pixel.l = color & 0xFF + pixel.r = color >> 8 + + +class _PyAccessI16_B(PyAccess): + """I;16B access, with conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_I16 **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + pixel = self.pixels[y][x] + return pixel.l * 256 + pixel.r + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + try: + color = min(color, 65535) + except Exception: + color = min(color[0], 65535) + + pixel.l = color >> 8 + pixel.r = color & 0xFF + + +class _PyAccessI32_N(PyAccess): + """Signed Int32 access, native endian""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image32 + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + self.pixels[y][x] = color + + +class _PyAccessI32_Swap(PyAccess): + """I;32L/B access, with byteswapping conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image32 + + def reverse(self, i): + orig = ffi.new("int *", i) + chars = ffi.cast("unsigned char *", orig) + chars[0], chars[1], chars[2], chars[3] = chars[3], chars[2], chars[1], chars[0] + return ffi.cast("int *", chars)[0] + + def get_pixel(self, x: int, y: int) -> int: + return self.reverse(self.pixels[y][x]) + + def set_pixel(self, x, y, color): + self.pixels[y][x] = self.reverse(color) + + +class _PyAccessF(PyAccess): + """32 bit float access""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("float **", self.image32) + + def get_pixel(self, x: int, y: int) -> float: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # not a tuple + self.pixels[y][x] = color + except TypeError: + # tuple + self.pixels[y][x] = color[0] + + +mode_map = { + "1": _PyAccess8, + "L": _PyAccess8, + "P": _PyAccess8, + "I;16N": _PyAccessI16_N, + "LA": _PyAccess32_2, + "La": _PyAccess32_2, + "PA": _PyAccess32_2, + "RGB": _PyAccess32_3, + "LAB": _PyAccess32_3, + "HSV": _PyAccess32_3, + "YCbCr": _PyAccess32_3, + "RGBA": _PyAccess32_4, + "RGBa": _PyAccess32_4, + "RGBX": _PyAccess32_4, + "CMYK": _PyAccess32_4, + "F": _PyAccessF, + "I": _PyAccessI32_N, +} + +if sys.byteorder == "little": + mode_map["I;16"] = _PyAccessI16_N + mode_map["I;16L"] = _PyAccessI16_N + mode_map["I;16B"] = _PyAccessI16_B + + mode_map["I;32L"] = _PyAccessI32_N + mode_map["I;32B"] = _PyAccessI32_Swap +else: + mode_map["I;16"] = _PyAccessI16_L + mode_map["I;16L"] = _PyAccessI16_L + mode_map["I;16B"] = _PyAccessI16_N + + mode_map["I;32L"] = _PyAccessI32_Swap + mode_map["I;32B"] = _PyAccessI32_N + + +def new(img: Image.Image, readonly: bool = False) -> PyAccess | None: + access_type = mode_map.get(img.mode, None) + if not access_type: + logger.debug("PyAccess Not Implemented: %s", img.mode) + return None + return access_type(img, readonly) diff --git a/.venv/lib/python3.12/site-packages/PIL/QoiImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/QoiImagePlugin.py new file mode 100644 index 0000000..202ef52 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/QoiImagePlugin.py @@ -0,0 +1,115 @@ +# +# The Python Imaging Library. +# +# QOI support for PIL +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import os + +from . import Image, ImageFile +from ._binary import i32be as i32 + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] == b"qoif" + + +class QoiImageFile(ImageFile.ImageFile): + format = "QOI" + format_description = "Quite OK Image" + + def _open(self) -> None: + if not _accept(self.fp.read(4)): + msg = "not a QOI file" + raise SyntaxError(msg) + + self._size = tuple(i32(self.fp.read(4)) for i in range(2)) + + channels = self.fp.read(1)[0] + self._mode = "RGB" if channels == 3 else "RGBA" + + self.fp.seek(1, os.SEEK_CUR) # colorspace + self.tile = [("qoi", (0, 0) + self._size, self.fp.tell(), None)] + + +class QoiDecoder(ImageFile.PyDecoder): + _pulls_fd = True + _previous_pixel: bytes | bytearray | None = None + _previously_seen_pixels: dict[int, bytes | bytearray] = {} + + def _add_to_previous_pixels(self, value: bytes | bytearray) -> None: + self._previous_pixel = value + + r, g, b, a = value + hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64 + self._previously_seen_pixels[hash_value] = value + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + + self._previously_seen_pixels = {} + self._add_to_previous_pixels(bytearray((0, 0, 0, 255))) + + data = bytearray() + bands = Image.getmodebands(self.mode) + dest_length = self.state.xsize * self.state.ysize * bands + while len(data) < dest_length: + byte = self.fd.read(1)[0] + value: bytes | bytearray + if byte == 0b11111110 and self._previous_pixel: # QOI_OP_RGB + value = bytearray(self.fd.read(3)) + self._previous_pixel[3:] + elif byte == 0b11111111: # QOI_OP_RGBA + value = self.fd.read(4) + else: + op = byte >> 6 + if op == 0: # QOI_OP_INDEX + op_index = byte & 0b00111111 + value = self._previously_seen_pixels.get( + op_index, bytearray((0, 0, 0, 0)) + ) + elif op == 1 and self._previous_pixel: # QOI_OP_DIFF + value = bytearray( + ( + (self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2) + % 256, + (self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2) + % 256, + (self._previous_pixel[2] + (byte & 0b00000011) - 2) % 256, + self._previous_pixel[3], + ) + ) + elif op == 2 and self._previous_pixel: # QOI_OP_LUMA + second_byte = self.fd.read(1)[0] + diff_green = (byte & 0b00111111) - 32 + diff_red = ((second_byte & 0b11110000) >> 4) - 8 + diff_blue = (second_byte & 0b00001111) - 8 + + value = bytearray( + tuple( + (self._previous_pixel[i] + diff_green + diff) % 256 + for i, diff in enumerate((diff_red, 0, diff_blue)) + ) + ) + value += self._previous_pixel[3:] + elif op == 3 and self._previous_pixel: # QOI_OP_RUN + run_length = (byte & 0b00111111) + 1 + value = self._previous_pixel + if bands == 3: + value = value[:3] + data += value * run_length + continue + self._add_to_previous_pixels(value) + + if bands == 3: + value = value[:3] + data += value + self.set_as_raw(data) + return -1, 0 + + +Image.register_open(QoiImageFile.format, QoiImageFile, _accept) +Image.register_decoder("qoi", QoiDecoder) +Image.register_extension(QoiImageFile.format, ".qoi") diff --git a/.venv/lib/python3.12/site-packages/PIL/SgiImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/SgiImagePlugin.py new file mode 100644 index 0000000..50d9791 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/SgiImagePlugin.py @@ -0,0 +1,238 @@ +# +# The Python Imaging Library. +# $Id$ +# +# SGI image file handling +# +# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli. +# +# +# +# History: +# 2017-22-07 mb Add RLE decompression +# 2016-16-10 mb Add save method without compression +# 1995-09-10 fl Created +# +# Copyright (c) 2016 by Mickael Bonfill. +# Copyright (c) 2008 by Karsten Hiddemann. +# Copyright (c) 1997 by Secret Labs AB. +# Copyright (c) 1995 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import os +import struct +from typing import IO + +from . import Image, ImageFile +from ._binary import i16be as i16 +from ._binary import o8 + + +def _accept(prefix: bytes) -> bool: + return len(prefix) >= 2 and i16(prefix) == 474 + + +MODES = { + (1, 1, 1): "L", + (1, 2, 1): "L", + (2, 1, 1): "L;16B", + (2, 2, 1): "L;16B", + (1, 3, 3): "RGB", + (2, 3, 3): "RGB;16B", + (1, 3, 4): "RGBA", + (2, 3, 4): "RGBA;16B", +} + + +## +# Image plugin for SGI images. +class SgiImageFile(ImageFile.ImageFile): + format = "SGI" + format_description = "SGI Image File Format" + + def _open(self) -> None: + # HEAD + assert self.fp is not None + + headlen = 512 + s = self.fp.read(headlen) + + if not _accept(s): + msg = "Not an SGI image file" + raise ValueError(msg) + + # compression : verbatim or RLE + compression = s[2] + + # bpc : 1 or 2 bytes (8bits or 16bits) + bpc = s[3] + + # dimension : 1, 2 or 3 (depending on xsize, ysize and zsize) + dimension = i16(s, 4) + + # xsize : width + xsize = i16(s, 6) + + # ysize : height + ysize = i16(s, 8) + + # zsize : channels count + zsize = i16(s, 10) + + # layout + layout = bpc, dimension, zsize + + # determine mode from bits/zsize + rawmode = "" + try: + rawmode = MODES[layout] + except KeyError: + pass + + if rawmode == "": + msg = "Unsupported SGI image mode" + raise ValueError(msg) + + self._size = xsize, ysize + self._mode = rawmode.split(";")[0] + if self.mode == "RGB": + self.custom_mimetype = "image/rgb" + + # orientation -1 : scanlines begins at the bottom-left corner + orientation = -1 + + # decoder info + if compression == 0: + pagesize = xsize * ysize * bpc + if bpc == 2: + self.tile = [ + ("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation)) + ] + else: + self.tile = [] + offset = headlen + for layer in self.mode: + self.tile.append( + ("raw", (0, 0) + self.size, offset, (layer, 0, orientation)) + ) + offset += pagesize + elif compression == 1: + self.tile = [ + ("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc)) + ] + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode not in {"RGB", "RGBA", "L"}: + msg = "Unsupported SGI image mode" + raise ValueError(msg) + + # Get the keyword arguments + info = im.encoderinfo + + # Byte-per-pixel precision, 1 = 8bits per pixel + bpc = info.get("bpc", 1) + + if bpc not in (1, 2): + msg = "Unsupported number of bytes per pixel" + raise ValueError(msg) + + # Flip the image, since the origin of SGI file is the bottom-left corner + orientation = -1 + # Define the file as SGI File Format + magic_number = 474 + # Run-Length Encoding Compression - Unsupported at this time + rle = 0 + + # Number of dimensions (x,y,z) + dim = 3 + # X Dimension = width / Y Dimension = height + x, y = im.size + if im.mode == "L" and y == 1: + dim = 1 + elif im.mode == "L": + dim = 2 + # Z Dimension: Number of channels + z = len(im.mode) + + if dim in {1, 2}: + z = 1 + + # assert we've got the right number of bands. + if len(im.getbands()) != z: + msg = f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}" + raise ValueError(msg) + + # Minimum Byte value + pinmin = 0 + # Maximum Byte value (255 = 8bits per pixel) + pinmax = 255 + # Image name (79 characters max, truncated below in write) + img_name = os.path.splitext(os.path.basename(filename))[0] + if isinstance(img_name, str): + img_name = img_name.encode("ascii", "ignore") + # Standard representation of pixel in the file + colormap = 0 + fp.write(struct.pack(">h", magic_number)) + fp.write(o8(rle)) + fp.write(o8(bpc)) + fp.write(struct.pack(">H", dim)) + fp.write(struct.pack(">H", x)) + fp.write(struct.pack(">H", y)) + fp.write(struct.pack(">H", z)) + fp.write(struct.pack(">l", pinmin)) + fp.write(struct.pack(">l", pinmax)) + fp.write(struct.pack("4s", b"")) # dummy + fp.write(struct.pack("79s", img_name)) # truncates to 79 chars + fp.write(struct.pack("s", b"")) # force null byte after img_name + fp.write(struct.pack(">l", colormap)) + fp.write(struct.pack("404s", b"")) # dummy + + rawmode = "L" + if bpc == 2: + rawmode = "L;16B" + + for channel in im.split(): + fp.write(channel.tobytes("raw", rawmode, 0, orientation)) + + if hasattr(fp, "flush"): + fp.flush() + + +class SGI16Decoder(ImageFile.PyDecoder): + _pulls_fd = True + + def decode(self, buffer: bytes) -> tuple[int, int]: + assert self.fd is not None + assert self.im is not None + + rawmode, stride, orientation = self.args + pagesize = self.state.xsize * self.state.ysize + zsize = len(self.mode) + self.fd.seek(512) + + for band in range(zsize): + channel = Image.new("L", (self.state.xsize, self.state.ysize)) + channel.frombytes( + self.fd.read(2 * pagesize), "raw", "L;16B", stride, orientation + ) + self.im.putband(channel.im, band) + + return -1, 0 + + +# +# registry + + +Image.register_decoder("SGI16", SGI16Decoder) +Image.register_open(SgiImageFile.format, SgiImageFile, _accept) +Image.register_save(SgiImageFile.format, _save) +Image.register_mime(SgiImageFile.format, "image/sgi") + +Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"]) + +# End of file diff --git a/.venv/lib/python3.12/site-packages/PIL/SpiderImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/SpiderImagePlugin.py new file mode 100644 index 0000000..f5a09c3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/SpiderImagePlugin.py @@ -0,0 +1,325 @@ +# +# The Python Imaging Library. +# +# SPIDER image file handling +# +# History: +# 2004-08-02 Created BB +# 2006-03-02 added save method +# 2006-03-13 added support for stack images +# +# Copyright (c) 2004 by Health Research Inc. (HRI) RENSSELAER, NY 12144. +# Copyright (c) 2004 by William Baxter. +# Copyright (c) 2004 by Secret Labs AB. +# Copyright (c) 2004 by Fredrik Lundh. +# + +## +# Image plugin for the Spider image format. This format is used +# by the SPIDER software, in processing image data from electron +# microscopy and tomography. +## + +# +# SpiderImagePlugin.py +# +# The Spider image format is used by SPIDER software, in processing +# image data from electron microscopy and tomography. +# +# Spider home page: +# https://spider.wadsworth.org/spider_doc/spider/docs/spider.html +# +# Details about the Spider image format: +# https://spider.wadsworth.org/spider_doc/spider/docs/image_doc.html +# +from __future__ import annotations + +import os +import struct +import sys +from typing import IO, TYPE_CHECKING, Any, Tuple, cast + +from . import Image, ImageFile + + +def isInt(f: Any) -> int: + try: + i = int(f) + if f - i == 0: + return 1 + else: + return 0 + except (ValueError, OverflowError): + return 0 + + +iforms = [1, 3, -11, -12, -21, -22] + + +# There is no magic number to identify Spider files, so just check a +# series of header locations to see if they have reasonable values. +# Returns no. of bytes in the header, if it is a valid Spider header, +# otherwise returns 0 + + +def isSpiderHeader(t: tuple[float, ...]) -> int: + h = (99,) + t # add 1 value so can use spider header index start=1 + # header values 1,2,5,12,13,22,23 should be integers + for i in [1, 2, 5, 12, 13, 22, 23]: + if not isInt(h[i]): + return 0 + # check iform + iform = int(h[5]) + if iform not in iforms: + return 0 + # check other header values + labrec = int(h[13]) # no. records in file header + labbyt = int(h[22]) # total no. of bytes in header + lenbyt = int(h[23]) # record length in bytes + if labbyt != (labrec * lenbyt): + return 0 + # looks like a valid header + return labbyt + + +def isSpiderImage(filename: str) -> int: + with open(filename, "rb") as fp: + f = fp.read(92) # read 23 * 4 bytes + t = struct.unpack(">23f", f) # try big-endian first + hdrlen = isSpiderHeader(t) + if hdrlen == 0: + t = struct.unpack("<23f", f) # little-endian + hdrlen = isSpiderHeader(t) + return hdrlen + + +class SpiderImageFile(ImageFile.ImageFile): + format = "SPIDER" + format_description = "Spider 2D image" + _close_exclusive_fp_after_loading = False + + def _open(self) -> None: + # check header + n = 27 * 4 # read 27 float values + f = self.fp.read(n) + + try: + self.bigendian = 1 + t = struct.unpack(">27f", f) # try big-endian first + hdrlen = isSpiderHeader(t) + if hdrlen == 0: + self.bigendian = 0 + t = struct.unpack("<27f", f) # little-endian + hdrlen = isSpiderHeader(t) + if hdrlen == 0: + msg = "not a valid Spider file" + raise SyntaxError(msg) + except struct.error as e: + msg = "not a valid Spider file" + raise SyntaxError(msg) from e + + h = (99,) + t # add 1 value : spider header index starts at 1 + iform = int(h[5]) + if iform != 1: + msg = "not a Spider 2D image" + raise SyntaxError(msg) + + self._size = int(h[12]), int(h[2]) # size in pixels (width, height) + self.istack = int(h[24]) + self.imgnumber = int(h[27]) + + if self.istack == 0 and self.imgnumber == 0: + # stk=0, img=0: a regular 2D image + offset = hdrlen + self._nimages = 1 + elif self.istack > 0 and self.imgnumber == 0: + # stk>0, img=0: Opening the stack for the first time + self.imgbytes = int(h[12]) * int(h[2]) * 4 + self.hdrlen = hdrlen + self._nimages = int(h[26]) + # Point to the first image in the stack + offset = hdrlen * 2 + self.imgnumber = 1 + elif self.istack == 0 and self.imgnumber > 0: + # stk=0, img>0: an image within the stack + offset = hdrlen + self.stkoffset + self.istack = 2 # So Image knows it's still a stack + else: + msg = "inconsistent stack header values" + raise SyntaxError(msg) + + if self.bigendian: + self.rawmode = "F;32BF" + else: + self.rawmode = "F;32F" + self._mode = "F" + + self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))] + self._fp = self.fp # FIXME: hack + + @property + def n_frames(self) -> int: + return self._nimages + + @property + def is_animated(self) -> bool: + return self._nimages > 1 + + # 1st image index is zero (although SPIDER imgnumber starts at 1) + def tell(self) -> int: + if self.imgnumber < 1: + return 0 + else: + return self.imgnumber - 1 + + def seek(self, frame: int) -> None: + if self.istack == 0: + msg = "attempt to seek in a non-stack file" + raise EOFError(msg) + if not self._seek_check(frame): + return + self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes) + self.fp = self._fp + self.fp.seek(self.stkoffset) + self._open() + + # returns a byte image after rescaling to 0..255 + def convert2byte(self, depth: int = 255) -> Image.Image: + extrema = self.getextrema() + assert isinstance(extrema[0], float) + minimum, maximum = cast(Tuple[float, float], extrema) + m: float = 1 + if maximum != minimum: + m = depth / (maximum - minimum) + b = -m * minimum + return self.point(lambda i: i * m + b).convert("L") + + if TYPE_CHECKING: + from . import ImageTk + + # returns a ImageTk.PhotoImage object, after rescaling to 0..255 + def tkPhotoImage(self) -> ImageTk.PhotoImage: + from . import ImageTk + + return ImageTk.PhotoImage(self.convert2byte(), palette=256) + + +# -------------------------------------------------------------------- +# Image series + + +# given a list of filenames, return a list of images +def loadImageSeries(filelist: list[str] | None = None) -> list[SpiderImageFile] | None: + """create a list of :py:class:`~PIL.Image.Image` objects for use in a montage""" + if filelist is None or len(filelist) < 1: + return None + + imglist = [] + for img in filelist: + if not os.path.exists(img): + print(f"unable to find {img}") + continue + try: + with Image.open(img) as im: + im = im.convert2byte() + except Exception: + if not isSpiderImage(img): + print(f"{img} is not a Spider image file") + continue + im.info["filename"] = img + imglist.append(im) + return imglist + + +# -------------------------------------------------------------------- +# For saving images in Spider format + + +def makeSpiderHeader(im: Image.Image) -> list[bytes]: + nsam, nrow = im.size + lenbyt = nsam * 4 # There are labrec records in the header + labrec = int(1024 / lenbyt) + if 1024 % lenbyt != 0: + labrec += 1 + labbyt = labrec * lenbyt + nvalues = int(labbyt / 4) + if nvalues < 23: + return [] + + hdr = [0.0] * nvalues + + # NB these are Fortran indices + hdr[1] = 1.0 # nslice (=1 for an image) + hdr[2] = float(nrow) # number of rows per slice + hdr[3] = float(nrow) # number of records in the image + hdr[5] = 1.0 # iform for 2D image + hdr[12] = float(nsam) # number of pixels per line + hdr[13] = float(labrec) # number of records in file header + hdr[22] = float(labbyt) # total number of bytes in header + hdr[23] = float(lenbyt) # record length in bytes + + # adjust for Fortran indexing + hdr = hdr[1:] + hdr.append(0.0) + # pack binary data into a string + return [struct.pack("f", v) for v in hdr] + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode[0] != "F": + im = im.convert("F") + + hdr = makeSpiderHeader(im) + if len(hdr) < 256: + msg = "Error creating Spider header" + raise OSError(msg) + + # write the SPIDER header + fp.writelines(hdr) + + rawmode = "F;32NF" # 32-bit native floating point + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))]) + + +def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + # get the filename extension and register it with Image + filename_ext = os.path.splitext(filename)[1] + ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext + Image.register_extension(SpiderImageFile.format, ext) + _save(im, fp, filename) + + +# -------------------------------------------------------------------- + + +Image.register_open(SpiderImageFile.format, SpiderImageFile) +Image.register_save(SpiderImageFile.format, _save_spider) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Syntax: python3 SpiderImagePlugin.py [infile] [outfile]") + sys.exit() + + filename = sys.argv[1] + if not isSpiderImage(filename): + print("input image must be in Spider format") + sys.exit() + + with Image.open(filename) as im: + print(f"image: {im}") + print(f"format: {im.format}") + print(f"size: {im.size}") + print(f"mode: {im.mode}") + print("max, min: ", end=" ") + print(im.getextrema()) + + if len(sys.argv) > 2: + outfile = sys.argv[2] + + # perform some image operation + im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + print( + f"saving a flipped version of {os.path.basename(filename)} " + f"as {outfile} " + ) + im.save(outfile, SpiderImageFile.format) diff --git a/.venv/lib/python3.12/site-packages/PIL/SunImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/SunImagePlugin.py new file mode 100644 index 0000000..4e09847 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/SunImagePlugin.py @@ -0,0 +1,141 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Sun image file handling +# +# History: +# 1995-09-10 fl Created +# 1996-05-28 fl Fixed 32-bit alignment +# 1998-12-29 fl Import ImagePalette module +# 2001-12-18 fl Fixed palette loading (from Jean-Claude Rimbault) +# +# Copyright (c) 1997-2001 by Secret Labs AB +# Copyright (c) 1995-1996 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +from . import Image, ImageFile, ImagePalette +from ._binary import i32be as i32 + + +def _accept(prefix: bytes) -> bool: + return len(prefix) >= 4 and i32(prefix) == 0x59A66A95 + + +## +# Image plugin for Sun raster files. + + +class SunImageFile(ImageFile.ImageFile): + format = "SUN" + format_description = "Sun Raster File" + + def _open(self) -> None: + # The Sun Raster file header is 32 bytes in length + # and has the following format: + + # typedef struct _SunRaster + # { + # DWORD MagicNumber; /* Magic (identification) number */ + # DWORD Width; /* Width of image in pixels */ + # DWORD Height; /* Height of image in pixels */ + # DWORD Depth; /* Number of bits per pixel */ + # DWORD Length; /* Size of image data in bytes */ + # DWORD Type; /* Type of raster file */ + # DWORD ColorMapType; /* Type of color map */ + # DWORD ColorMapLength; /* Size of the color map in bytes */ + # } SUNRASTER; + + assert self.fp is not None + + # HEAD + s = self.fp.read(32) + if not _accept(s): + msg = "not an SUN raster file" + raise SyntaxError(msg) + + offset = 32 + + self._size = i32(s, 4), i32(s, 8) + + depth = i32(s, 12) + # data_length = i32(s, 16) # unreliable, ignore. + file_type = i32(s, 20) + palette_type = i32(s, 24) # 0: None, 1: RGB, 2: Raw/arbitrary + palette_length = i32(s, 28) + + if depth == 1: + self._mode, rawmode = "1", "1;I" + elif depth == 4: + self._mode, rawmode = "L", "L;4" + elif depth == 8: + self._mode = rawmode = "L" + elif depth == 24: + if file_type == 3: + self._mode, rawmode = "RGB", "RGB" + else: + self._mode, rawmode = "RGB", "BGR" + elif depth == 32: + if file_type == 3: + self._mode, rawmode = "RGB", "RGBX" + else: + self._mode, rawmode = "RGB", "BGRX" + else: + msg = "Unsupported Mode/Bit Depth" + raise SyntaxError(msg) + + if palette_length: + if palette_length > 1024: + msg = "Unsupported Color Palette Length" + raise SyntaxError(msg) + + if palette_type != 1: + msg = "Unsupported Palette Type" + raise SyntaxError(msg) + + offset = offset + palette_length + self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length)) + if self.mode == "L": + self._mode = "P" + rawmode = rawmode.replace("L", "P") + + # 16 bit boundaries on stride + stride = ((self.size[0] * depth + 15) // 16) * 2 + + # file type: Type is the version (or flavor) of the bitmap + # file. The following values are typically found in the Type + # field: + # 0000h Old + # 0001h Standard + # 0002h Byte-encoded + # 0003h RGB format + # 0004h TIFF format + # 0005h IFF format + # FFFFh Experimental + + # Old and standard are the same, except for the length tag. + # byte-encoded is run-length-encoded + # RGB looks similar to standard, but RGB byte order + # TIFF and IFF mean that they were converted from T/IFF + # Experimental means that it's something else. + # (https://www.fileformat.info/format/sunraster/egff.htm) + + if file_type in (0, 1, 3, 4, 5): + self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride))] + elif file_type == 2: + self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)] + else: + msg = "Unsupported Sun Raster file type" + raise SyntaxError(msg) + + +# +# registry + + +Image.register_open(SunImageFile.format, SunImageFile, _accept) + +Image.register_extension(SunImageFile.format, ".ras") diff --git a/.venv/lib/python3.12/site-packages/PIL/TarIO.py b/.venv/lib/python3.12/site-packages/PIL/TarIO.py new file mode 100644 index 0000000..cba26d4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/TarIO.py @@ -0,0 +1,67 @@ +# +# The Python Imaging Library. +# $Id$ +# +# read files from within a tar file +# +# History: +# 95-06-18 fl Created +# 96-05-28 fl Open files in binary mode +# +# Copyright (c) Secret Labs AB 1997. +# Copyright (c) Fredrik Lundh 1995-96. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io + +from . import ContainerIO + + +class TarIO(ContainerIO.ContainerIO[bytes]): + """A file object that provides read access to a given member of a TAR file.""" + + def __init__(self, tarfile: str, file: str) -> None: + """ + Create file object. + + :param tarfile: Name of TAR file. + :param file: Name of member file. + """ + self.fh = open(tarfile, "rb") + + while True: + s = self.fh.read(512) + if len(s) != 512: + msg = "unexpected end of tar file" + raise OSError(msg) + + name = s[:100].decode("utf-8") + i = name.find("\0") + if i == 0: + msg = "cannot find subfile" + raise OSError(msg) + if i > 0: + name = name[:i] + + size = int(s[124:135], 8) + + if file == name: + break + + self.fh.seek((size + 511) & (~511), io.SEEK_CUR) + + # Open region + super().__init__(self.fh, self.fh.tell(), size) + + # Context manager support + def __enter__(self) -> TarIO: + return self + + def __exit__(self, *args: object) -> None: + self.close() + + def close(self) -> None: + self.fh.close() diff --git a/.venv/lib/python3.12/site-packages/PIL/TgaImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/TgaImagePlugin.py new file mode 100644 index 0000000..39104ae --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/TgaImagePlugin.py @@ -0,0 +1,262 @@ +# +# The Python Imaging Library. +# $Id$ +# +# TGA file handling +# +# History: +# 95-09-01 fl created (reads 24-bit files only) +# 97-01-04 fl support more TGA versions, including compressed images +# 98-07-04 fl fixed orientation and alpha layer bugs +# 98-09-11 fl fixed orientation for runlength decoder +# +# Copyright (c) Secret Labs AB 1997-98. +# Copyright (c) Fredrik Lundh 1995-97. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import warnings +from typing import IO + +from . import Image, ImageFile, ImagePalette +from ._binary import i16le as i16 +from ._binary import o8 +from ._binary import o16le as o16 + +# +# -------------------------------------------------------------------- +# Read RGA file + + +MODES = { + # map imagetype/depth to rawmode + (1, 8): "P", + (3, 1): "1", + (3, 8): "L", + (3, 16): "LA", + (2, 16): "BGRA;15Z", + (2, 24): "BGR", + (2, 32): "BGRA", +} + + +## +# Image plugin for Targa files. + + +class TgaImageFile(ImageFile.ImageFile): + format = "TGA" + format_description = "Targa" + + def _open(self) -> None: + # process header + assert self.fp is not None + + s = self.fp.read(18) + + id_len = s[0] + + colormaptype = s[1] + imagetype = s[2] + + depth = s[16] + + flags = s[17] + + self._size = i16(s, 12), i16(s, 14) + + # validate header fields + if ( + colormaptype not in (0, 1) + or self.size[0] <= 0 + or self.size[1] <= 0 + or depth not in (1, 8, 16, 24, 32) + ): + msg = "not a TGA file" + raise SyntaxError(msg) + + # image mode + if imagetype in (3, 11): + self._mode = "L" + if depth == 1: + self._mode = "1" # ??? + elif depth == 16: + self._mode = "LA" + elif imagetype in (1, 9): + self._mode = "P" if colormaptype else "L" + elif imagetype in (2, 10): + self._mode = "RGB" if depth == 24 else "RGBA" + else: + msg = "unknown TGA mode" + raise SyntaxError(msg) + + # orientation + orientation = flags & 0x30 + self._flip_horizontally = orientation in [0x10, 0x30] + if orientation in [0x20, 0x30]: + orientation = 1 + elif orientation in [0, 0x10]: + orientation = -1 + else: + msg = "unknown TGA orientation" + raise SyntaxError(msg) + + self.info["orientation"] = orientation + + if imagetype & 8: + self.info["compression"] = "tga_rle" + + if id_len: + self.info["id_section"] = self.fp.read(id_len) + + if colormaptype: + # read palette + start, size, mapdepth = i16(s, 3), i16(s, 5), s[7] + if mapdepth == 16: + self.palette = ImagePalette.raw( + "BGRA;15Z", bytes(2 * start) + self.fp.read(2 * size) + ) + self.palette.mode = "RGBA" + elif mapdepth == 24: + self.palette = ImagePalette.raw( + "BGR", bytes(3 * start) + self.fp.read(3 * size) + ) + elif mapdepth == 32: + self.palette = ImagePalette.raw( + "BGRA", bytes(4 * start) + self.fp.read(4 * size) + ) + else: + msg = "unknown TGA map depth" + raise SyntaxError(msg) + + # setup tile descriptor + try: + rawmode = MODES[(imagetype & 7, depth)] + if imagetype & 8: + # compressed + self.tile = [ + ( + "tga_rle", + (0, 0) + self.size, + self.fp.tell(), + (rawmode, orientation, depth), + ) + ] + else: + self.tile = [ + ( + "raw", + (0, 0) + self.size, + self.fp.tell(), + (rawmode, 0, orientation), + ) + ] + except KeyError: + pass # cannot decode + + def load_end(self) -> None: + if self._flip_horizontally: + assert self.im is not None + self.im = self.im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + + +# +# -------------------------------------------------------------------- +# Write TGA file + + +SAVE = { + "1": ("1", 1, 0, 3), + "L": ("L", 8, 0, 3), + "LA": ("LA", 16, 0, 3), + "P": ("P", 8, 1, 1), + "RGB": ("BGR", 24, 0, 2), + "RGBA": ("BGRA", 32, 0, 2), +} + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + try: + rawmode, bits, colormaptype, imagetype = SAVE[im.mode] + except KeyError as e: + msg = f"cannot write mode {im.mode} as TGA" + raise OSError(msg) from e + + if "rle" in im.encoderinfo: + rle = im.encoderinfo["rle"] + else: + compression = im.encoderinfo.get("compression", im.info.get("compression")) + rle = compression == "tga_rle" + if rle: + imagetype += 8 + + id_section = im.encoderinfo.get("id_section", im.info.get("id_section", "")) + id_len = len(id_section) + if id_len > 255: + id_len = 255 + id_section = id_section[:255] + warnings.warn("id_section has been trimmed to 255 characters") + + if colormaptype: + assert im.im is not None + palette = im.im.getpalette("RGB", "BGR") + colormaplength, colormapentry = len(palette) // 3, 24 + else: + colormaplength, colormapentry = 0, 0 + + if im.mode in ("LA", "RGBA"): + flags = 8 + else: + flags = 0 + + orientation = im.encoderinfo.get("orientation", im.info.get("orientation", -1)) + if orientation > 0: + flags = flags | 0x20 + + fp.write( + o8(id_len) + + o8(colormaptype) + + o8(imagetype) + + o16(0) # colormapfirst + + o16(colormaplength) + + o8(colormapentry) + + o16(0) + + o16(0) + + o16(im.size[0]) + + o16(im.size[1]) + + o8(bits) + + o8(flags) + ) + + if id_section: + fp.write(id_section) + + if colormaptype: + fp.write(palette) + + if rle: + ImageFile._save( + im, fp, [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))] + ) + else: + ImageFile._save( + im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))] + ) + + # write targa version 2 footer + fp.write(b"\000" * 8 + b"TRUEVISION-XFILE." + b"\000") + + +# +# -------------------------------------------------------------------- +# Registry + + +Image.register_open(TgaImageFile.format, TgaImageFile) +Image.register_save(TgaImageFile.format, _save) + +Image.register_extensions(TgaImageFile.format, [".tga", ".icb", ".vda", ".vst"]) + +Image.register_mime(TgaImageFile.format, "image/x-tga") diff --git a/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py new file mode 100644 index 0000000..ac5b63c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py @@ -0,0 +1,2200 @@ +# +# The Python Imaging Library. +# $Id$ +# +# TIFF file handling +# +# TIFF is a flexible, if somewhat aged, image file format originally +# defined by Aldus. Although TIFF supports a wide variety of pixel +# layouts and compression methods, the name doesn't really stand for +# "thousands of incompatible file formats," it just feels that way. +# +# To read TIFF data from a stream, the stream must be seekable. For +# progressive decoding, make sure to use TIFF files where the tag +# directory is placed first in the file. +# +# History: +# 1995-09-01 fl Created +# 1996-05-04 fl Handle JPEGTABLES tag +# 1996-05-18 fl Fixed COLORMAP support +# 1997-01-05 fl Fixed PREDICTOR support +# 1997-08-27 fl Added support for rational tags (from Perry Stoll) +# 1998-01-10 fl Fixed seek/tell (from Jan Blom) +# 1998-07-15 fl Use private names for internal variables +# 1999-06-13 fl Rewritten for PIL 1.0 (1.0) +# 2000-10-11 fl Additional fixes for Python 2.0 (1.1) +# 2001-04-17 fl Fixed rewind support (seek to frame 0) (1.2) +# 2001-05-12 fl Added write support for more tags (from Greg Couch) (1.3) +# 2001-12-18 fl Added workaround for broken Matrox library +# 2002-01-18 fl Don't mess up if photometric tag is missing (D. Alan Stewart) +# 2003-05-19 fl Check FILLORDER tag +# 2003-09-26 fl Added RGBa support +# 2004-02-24 fl Added DPI support; fixed rational write support +# 2005-02-07 fl Added workaround for broken Corel Draw 10 files +# 2006-01-09 fl Added support for float/double tags (from Russell Nelson) +# +# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved. +# Copyright (c) 1995-1997 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import io +import itertools +import logging +import math +import os +import struct +import warnings +from collections.abc import MutableMapping +from fractions import Fraction +from numbers import Number, Rational +from typing import IO, TYPE_CHECKING, Any, Callable, NoReturn + +from . import ExifTags, Image, ImageFile, ImageOps, ImagePalette, TiffTags +from ._binary import i16be as i16 +from ._binary import i32be as i32 +from ._binary import o8 +from ._deprecate import deprecate +from .TiffTags import TYPES + +logger = logging.getLogger(__name__) + +# Set these to true to force use of libtiff for reading or writing. +READ_LIBTIFF = False +WRITE_LIBTIFF = False +IFD_LEGACY_API = True +STRIP_SIZE = 65536 + +II = b"II" # little-endian (Intel style) +MM = b"MM" # big-endian (Motorola style) + +# +# -------------------------------------------------------------------- +# Read TIFF files + +# a few tag names, just to make the code below a bit more readable +OSUBFILETYPE = 255 +IMAGEWIDTH = 256 +IMAGELENGTH = 257 +BITSPERSAMPLE = 258 +COMPRESSION = 259 +PHOTOMETRIC_INTERPRETATION = 262 +FILLORDER = 266 +IMAGEDESCRIPTION = 270 +STRIPOFFSETS = 273 +SAMPLESPERPIXEL = 277 +ROWSPERSTRIP = 278 +STRIPBYTECOUNTS = 279 +X_RESOLUTION = 282 +Y_RESOLUTION = 283 +PLANAR_CONFIGURATION = 284 +RESOLUTION_UNIT = 296 +TRANSFERFUNCTION = 301 +SOFTWARE = 305 +DATE_TIME = 306 +ARTIST = 315 +PREDICTOR = 317 +COLORMAP = 320 +TILEWIDTH = 322 +TILELENGTH = 323 +TILEOFFSETS = 324 +TILEBYTECOUNTS = 325 +SUBIFD = 330 +EXTRASAMPLES = 338 +SAMPLEFORMAT = 339 +JPEGTABLES = 347 +YCBCRSUBSAMPLING = 530 +REFERENCEBLACKWHITE = 532 +COPYRIGHT = 33432 +IPTC_NAA_CHUNK = 33723 # newsphoto properties +PHOTOSHOP_CHUNK = 34377 # photoshop properties +ICCPROFILE = 34675 +EXIFIFD = 34665 +XMP = 700 +JPEGQUALITY = 65537 # pseudo-tag by libtiff + +# https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/io/TiffDecoder.java +IMAGEJ_META_DATA_BYTE_COUNTS = 50838 +IMAGEJ_META_DATA = 50839 + +COMPRESSION_INFO = { + # Compression => pil compression name + 1: "raw", + 2: "tiff_ccitt", + 3: "group3", + 4: "group4", + 5: "tiff_lzw", + 6: "tiff_jpeg", # obsolete + 7: "jpeg", + 8: "tiff_adobe_deflate", + 32771: "tiff_raw_16", # 16-bit padding + 32773: "packbits", + 32809: "tiff_thunderscan", + 32946: "tiff_deflate", + 34676: "tiff_sgilog", + 34677: "tiff_sgilog24", + 34925: "lzma", + 50000: "zstd", + 50001: "webp", +} + +COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()} + +OPEN_INFO = { + # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample, + # ExtraSamples) => mode, rawmode + (II, 0, (1,), 1, (1,), ()): ("1", "1;I"), + (MM, 0, (1,), 1, (1,), ()): ("1", "1;I"), + (II, 0, (1,), 2, (1,), ()): ("1", "1;IR"), + (MM, 0, (1,), 2, (1,), ()): ("1", "1;IR"), + (II, 1, (1,), 1, (1,), ()): ("1", "1"), + (MM, 1, (1,), 1, (1,), ()): ("1", "1"), + (II, 1, (1,), 2, (1,), ()): ("1", "1;R"), + (MM, 1, (1,), 2, (1,), ()): ("1", "1;R"), + (II, 0, (1,), 1, (2,), ()): ("L", "L;2I"), + (MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"), + (II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"), + (MM, 0, (1,), 2, (2,), ()): ("L", "L;2IR"), + (II, 1, (1,), 1, (2,), ()): ("L", "L;2"), + (MM, 1, (1,), 1, (2,), ()): ("L", "L;2"), + (II, 1, (1,), 2, (2,), ()): ("L", "L;2R"), + (MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"), + (II, 0, (1,), 1, (4,), ()): ("L", "L;4I"), + (MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"), + (II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"), + (MM, 0, (1,), 2, (4,), ()): ("L", "L;4IR"), + (II, 1, (1,), 1, (4,), ()): ("L", "L;4"), + (MM, 1, (1,), 1, (4,), ()): ("L", "L;4"), + (II, 1, (1,), 2, (4,), ()): ("L", "L;4R"), + (MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"), + (II, 0, (1,), 1, (8,), ()): ("L", "L;I"), + (MM, 0, (1,), 1, (8,), ()): ("L", "L;I"), + (II, 0, (1,), 2, (8,), ()): ("L", "L;IR"), + (MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"), + (II, 1, (1,), 1, (8,), ()): ("L", "L"), + (MM, 1, (1,), 1, (8,), ()): ("L", "L"), + (II, 1, (2,), 1, (8,), ()): ("L", "L"), + (MM, 1, (2,), 1, (8,), ()): ("L", "L"), + (II, 1, (1,), 2, (8,), ()): ("L", "L;R"), + (MM, 1, (1,), 2, (8,), ()): ("L", "L;R"), + (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"), + (II, 0, (1,), 1, (16,), ()): ("I;16", "I;16"), + (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"), + (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"), + (II, 1, (1,), 2, (16,), ()): ("I;16", "I;16R"), + (II, 1, (2,), 1, (16,), ()): ("I", "I;16S"), + (MM, 1, (2,), 1, (16,), ()): ("I", "I;16BS"), + (II, 0, (3,), 1, (32,), ()): ("F", "F;32F"), + (MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"), + (II, 1, (1,), 1, (32,), ()): ("I", "I;32N"), + (II, 1, (2,), 1, (32,), ()): ("I", "I;32S"), + (MM, 1, (2,), 1, (32,), ()): ("I", "I;32BS"), + (II, 1, (3,), 1, (32,), ()): ("F", "F;32F"), + (MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"), + (II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"), + (MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"), + (II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"), + (MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"), + (II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"), + (MM, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"), + (II, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples + (MM, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples + (II, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"), + (MM, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"), + (II, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), + (MM, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"), + (II, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), + (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"), + (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"), + (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"), + (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 + (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 + (II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"), + (MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"), + (II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"), + (MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"), + (II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGB", "RGBX;16L"), + (MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGB", "RGBX;16B"), + (II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"), + (MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"), + (II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"), + (MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"), + (II, 3, (1,), 1, (1,), ()): ("P", "P;1"), + (MM, 3, (1,), 1, (1,), ()): ("P", "P;1"), + (II, 3, (1,), 2, (1,), ()): ("P", "P;1R"), + (MM, 3, (1,), 2, (1,), ()): ("P", "P;1R"), + (II, 3, (1,), 1, (2,), ()): ("P", "P;2"), + (MM, 3, (1,), 1, (2,), ()): ("P", "P;2"), + (II, 3, (1,), 2, (2,), ()): ("P", "P;2R"), + (MM, 3, (1,), 2, (2,), ()): ("P", "P;2R"), + (II, 3, (1,), 1, (4,), ()): ("P", "P;4"), + (MM, 3, (1,), 1, (4,), ()): ("P", "P;4"), + (II, 3, (1,), 2, (4,), ()): ("P", "P;4R"), + (MM, 3, (1,), 2, (4,), ()): ("P", "P;4R"), + (II, 3, (1,), 1, (8,), ()): ("P", "P"), + (MM, 3, (1,), 1, (8,), ()): ("P", "P"), + (II, 3, (1,), 1, (8, 8), (0,)): ("P", "PX"), + (II, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"), + (MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"), + (II, 3, (1,), 2, (8,), ()): ("P", "P;R"), + (MM, 3, (1,), 2, (8,), ()): ("P", "P;R"), + (II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), + (MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), + (II, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"), + (MM, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"), + (II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"), + (MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"), + (II, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16L"), + (II, 6, (1,), 1, (8,), ()): ("L", "L"), + (MM, 6, (1,), 1, (8,), ()): ("L", "L"), + # JPEG compressed images handled by LibTiff and auto-converted to RGBX + # Minimal Baseline TIFF requires YCbCr images to have 3 SamplesPerPixel + (II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"), + (MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"), + (II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"), + (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"), +} + +MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO) + +PREFIXES = [ + b"MM\x00\x2A", # Valid TIFF header with big-endian byte order + b"II\x2A\x00", # Valid TIFF header with little-endian byte order + b"MM\x2A\x00", # Invalid TIFF header, assume big-endian + b"II\x00\x2A", # Invalid TIFF header, assume little-endian + b"MM\x00\x2B", # BigTIFF with big-endian byte order + b"II\x2B\x00", # BigTIFF with little-endian byte order +] + +if not getattr(Image.core, "libtiff_support_custom_tags", True): + deprecate("Support for LibTIFF earlier than version 4", 12) + + +def _accept(prefix: bytes) -> bool: + return prefix[:4] in PREFIXES + + +def _limit_rational(val, max_val): + inv = abs(val) > 1 + n_d = IFDRational(1 / val if inv else val).limit_rational(max_val) + return n_d[::-1] if inv else n_d + + +def _limit_signed_rational(val, max_val, min_val): + frac = Fraction(val) + n_d = frac.numerator, frac.denominator + + if min(n_d) < min_val: + n_d = _limit_rational(val, abs(min_val)) + + if max(n_d) > max_val: + val = Fraction(*n_d) + n_d = _limit_rational(val, max_val) + + return n_d + + +## +# Wrapper for TIFF IFDs. + +_load_dispatch = {} +_write_dispatch = {} + + +def _delegate(op): + def delegate(self, *args): + return getattr(self._val, op)(*args) + + return delegate + + +class IFDRational(Rational): + """Implements a rational class where 0/0 is a legal value to match + the in the wild use of exif rationals. + + e.g., DigitalZoomRatio - 0.00/0.00 indicates that no digital zoom was used + """ + + """ If the denominator is 0, store this as a float('nan'), otherwise store + as a fractions.Fraction(). Delegate as appropriate + + """ + + __slots__ = ("_numerator", "_denominator", "_val") + + def __init__(self, value, denominator=1): + """ + :param value: either an integer numerator, a + float/rational/other number, or an IFDRational + :param denominator: Optional integer denominator + """ + if isinstance(value, IFDRational): + self._numerator = value.numerator + self._denominator = value.denominator + self._val = value._val + return + + if isinstance(value, Fraction): + self._numerator = value.numerator + self._denominator = value.denominator + else: + self._numerator = value + self._denominator = denominator + + if denominator == 0: + self._val = float("nan") + elif denominator == 1: + self._val = Fraction(value) + else: + self._val = Fraction(value, denominator) + + @property + def numerator(self): + return self._numerator + + @property + def denominator(self): + return self._denominator + + def limit_rational(self, max_denominator): + """ + + :param max_denominator: Integer, the maximum denominator value + :returns: Tuple of (numerator, denominator) + """ + + if self.denominator == 0: + return self.numerator, self.denominator + + f = self._val.limit_denominator(max_denominator) + return f.numerator, f.denominator + + def __repr__(self) -> str: + return str(float(self._val)) + + def __hash__(self) -> int: + return self._val.__hash__() + + def __eq__(self, other: object) -> bool: + val = self._val + if isinstance(other, IFDRational): + other = other._val + if isinstance(other, float): + val = float(val) + return val == other + + def __getstate__(self): + return [self._val, self._numerator, self._denominator] + + def __setstate__(self, state): + IFDRational.__init__(self, 0) + _val, _numerator, _denominator = state + self._val = _val + self._numerator = _numerator + self._denominator = _denominator + + """ a = ['add','radd', 'sub', 'rsub', 'mul', 'rmul', + 'truediv', 'rtruediv', 'floordiv', 'rfloordiv', + 'mod','rmod', 'pow','rpow', 'pos', 'neg', + 'abs', 'trunc', 'lt', 'gt', 'le', 'ge', 'bool', + 'ceil', 'floor', 'round'] + print("\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a)) + """ + + __add__ = _delegate("__add__") + __radd__ = _delegate("__radd__") + __sub__ = _delegate("__sub__") + __rsub__ = _delegate("__rsub__") + __mul__ = _delegate("__mul__") + __rmul__ = _delegate("__rmul__") + __truediv__ = _delegate("__truediv__") + __rtruediv__ = _delegate("__rtruediv__") + __floordiv__ = _delegate("__floordiv__") + __rfloordiv__ = _delegate("__rfloordiv__") + __mod__ = _delegate("__mod__") + __rmod__ = _delegate("__rmod__") + __pow__ = _delegate("__pow__") + __rpow__ = _delegate("__rpow__") + __pos__ = _delegate("__pos__") + __neg__ = _delegate("__neg__") + __abs__ = _delegate("__abs__") + __trunc__ = _delegate("__trunc__") + __lt__ = _delegate("__lt__") + __gt__ = _delegate("__gt__") + __le__ = _delegate("__le__") + __ge__ = _delegate("__ge__") + __bool__ = _delegate("__bool__") + __ceil__ = _delegate("__ceil__") + __floor__ = _delegate("__floor__") + __round__ = _delegate("__round__") + # Python >= 3.11 + if hasattr(Fraction, "__int__"): + __int__ = _delegate("__int__") + + +def _register_loader(idx, size): + def decorator(func): + from .TiffTags import TYPES + + if func.__name__.startswith("load_"): + TYPES[idx] = func.__name__[5:].replace("_", " ") + _load_dispatch[idx] = size, func # noqa: F821 + return func + + return decorator + + +def _register_writer(idx): + def decorator(func): + _write_dispatch[idx] = func # noqa: F821 + return func + + return decorator + + +def _register_basic(idx_fmt_name): + from .TiffTags import TYPES + + idx, fmt, name = idx_fmt_name + TYPES[idx] = name + size = struct.calcsize(f"={fmt}") + _load_dispatch[idx] = ( # noqa: F821 + size, + lambda self, data, legacy_api=True: ( + self._unpack(f"{len(data) // size}{fmt}", data) + ), + ) + _write_dispatch[idx] = lambda self, *values: ( # noqa: F821 + b"".join(self._pack(fmt, value) for value in values) + ) + + +if TYPE_CHECKING: + _IFDv2Base = MutableMapping[int, Any] +else: + _IFDv2Base = MutableMapping + + +class ImageFileDirectory_v2(_IFDv2Base): + """This class represents a TIFF tag directory. To speed things up, we + don't decode tags unless they're asked for. + + Exposes a dictionary interface of the tags in the directory:: + + ifd = ImageFileDirectory_v2() + ifd[key] = 'Some Data' + ifd.tagtype[key] = TiffTags.ASCII + print(ifd[key]) + 'Some Data' + + Individual values are returned as the strings or numbers, sequences are + returned as tuples of the values. + + The tiff metadata type of each item is stored in a dictionary of + tag types in + :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype`. The types + are read from a tiff file, guessed from the type added, or added + manually. + + Data Structures: + + * ``self.tagtype = {}`` + + * Key: numerical TIFF tag number + * Value: integer corresponding to the data type from + :py:data:`.TiffTags.TYPES` + + .. versionadded:: 3.0.0 + + 'Internal' data structures: + + * ``self._tags_v2 = {}`` + + * Key: numerical TIFF tag number + * Value: decoded data, as tuple for multiple values + + * ``self._tagdata = {}`` + + * Key: numerical TIFF tag number + * Value: undecoded byte string from file + + * ``self._tags_v1 = {}`` + + * Key: numerical TIFF tag number + * Value: decoded data in the v1 format + + Tags will be found in the private attributes ``self._tagdata``, and in + ``self._tags_v2`` once decoded. + + ``self.legacy_api`` is a value for internal use, and shouldn't be changed + from outside code. In cooperation with + :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`, if ``legacy_api`` + is true, then decoded tags will be populated into both ``_tags_v1`` and + ``_tags_v2``. ``_tags_v2`` will be used if this IFD is used in the TIFF + save routine. Tags should be read from ``_tags_v1`` if + ``legacy_api == true``. + + """ + + _load_dispatch: dict[int, Callable[[ImageFileDirectory_v2, bytes, bool], Any]] = {} + _write_dispatch: dict[int, Callable[..., Any]] = {} + + def __init__( + self, + ifh: bytes = b"II\052\0\0\0\0\0", + prefix: bytes | None = None, + group: int | None = None, + ) -> None: + """Initialize an ImageFileDirectory. + + To construct an ImageFileDirectory from a real file, pass the 8-byte + magic header to the constructor. To only set the endianness, pass it + as the 'prefix' keyword argument. + + :param ifh: One of the accepted magic headers (cf. PREFIXES); also sets + endianness. + :param prefix: Override the endianness of the file. + """ + if not _accept(ifh): + msg = f"not a TIFF file (header {repr(ifh)} not valid)" + raise SyntaxError(msg) + self._prefix = prefix if prefix is not None else ifh[:2] + if self._prefix == MM: + self._endian = ">" + elif self._prefix == II: + self._endian = "<" + else: + msg = "not a TIFF IFD" + raise SyntaxError(msg) + self._bigtiff = ifh[2] == 43 + self.group = group + self.tagtype: dict[int, int] = {} + """ Dictionary of tag types """ + self.reset() + (self.next,) = ( + self._unpack("Q", ifh[8:]) if self._bigtiff else self._unpack("L", ifh[4:]) + ) + self._legacy_api = False + + prefix = property(lambda self: self._prefix) + offset = property(lambda self: self._offset) + + @property + def legacy_api(self) -> bool: + return self._legacy_api + + @legacy_api.setter + def legacy_api(self, value: bool) -> NoReturn: + msg = "Not allowing setting of legacy api" + raise Exception(msg) + + def reset(self) -> None: + self._tags_v1: dict[int, Any] = {} # will remain empty if legacy_api is false + self._tags_v2: dict[int, Any] = {} # main tag storage + self._tagdata: dict[int, bytes] = {} + self.tagtype = {} # added 2008-06-05 by Florian Hoech + self._next = None + self._offset = None + + def __str__(self) -> str: + return str(dict(self)) + + def named(self): + """ + :returns: dict of name|key: value + + Returns the complete tag dictionary, with named tags where possible. + """ + return { + TiffTags.lookup(code, self.group).name: value + for code, value in self.items() + } + + def __len__(self) -> int: + return len(set(self._tagdata) | set(self._tags_v2)) + + def __getitem__(self, tag): + if tag not in self._tags_v2: # unpack on the fly + data = self._tagdata[tag] + typ = self.tagtype[tag] + size, handler = self._load_dispatch[typ] + self[tag] = handler(self, data, self.legacy_api) # check type + val = self._tags_v2[tag] + if self.legacy_api and not isinstance(val, (tuple, bytes)): + val = (val,) + return val + + def __contains__(self, tag): + return tag in self._tags_v2 or tag in self._tagdata + + def __setitem__(self, tag, value): + self._setitem(tag, value, self.legacy_api) + + def _setitem(self, tag, value, legacy_api): + basetypes = (Number, bytes, str) + + info = TiffTags.lookup(tag, self.group) + values = [value] if isinstance(value, basetypes) else value + + if tag not in self.tagtype: + if info.type: + self.tagtype[tag] = info.type + else: + self.tagtype[tag] = TiffTags.UNDEFINED + if all(isinstance(v, IFDRational) for v in values): + self.tagtype[tag] = ( + TiffTags.RATIONAL + if all(v >= 0 for v in values) + else TiffTags.SIGNED_RATIONAL + ) + elif all(isinstance(v, int) for v in values): + if all(0 <= v < 2**16 for v in values): + self.tagtype[tag] = TiffTags.SHORT + elif all(-(2**15) < v < 2**15 for v in values): + self.tagtype[tag] = TiffTags.SIGNED_SHORT + else: + self.tagtype[tag] = ( + TiffTags.LONG + if all(v >= 0 for v in values) + else TiffTags.SIGNED_LONG + ) + elif all(isinstance(v, float) for v in values): + self.tagtype[tag] = TiffTags.DOUBLE + elif all(isinstance(v, str) for v in values): + self.tagtype[tag] = TiffTags.ASCII + elif all(isinstance(v, bytes) for v in values): + self.tagtype[tag] = TiffTags.BYTE + + if self.tagtype[tag] == TiffTags.UNDEFINED: + values = [ + v.encode("ascii", "replace") if isinstance(v, str) else v + for v in values + ] + elif self.tagtype[tag] == TiffTags.RATIONAL: + values = [float(v) if isinstance(v, int) else v for v in values] + + is_ifd = self.tagtype[tag] == TiffTags.LONG and isinstance(values, dict) + if not is_ifd: + values = tuple(info.cvt_enum(value) for value in values) + + dest = self._tags_v1 if legacy_api else self._tags_v2 + + # Three branches: + # Spec'd length == 1, Actual length 1, store as element + # Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed. + # No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple. + # Don't mess with the legacy api, since it's frozen. + if not is_ifd and ( + (info.length == 1) + or self.tagtype[tag] == TiffTags.BYTE + or (info.length is None and len(values) == 1 and not legacy_api) + ): + # Don't mess with the legacy api, since it's frozen. + if legacy_api and self.tagtype[tag] in [ + TiffTags.RATIONAL, + TiffTags.SIGNED_RATIONAL, + ]: # rationals + values = (values,) + try: + (dest[tag],) = values + except ValueError: + # We've got a builtin tag with 1 expected entry + warnings.warn( + f"Metadata Warning, tag {tag} had too many entries: " + f"{len(values)}, expected 1" + ) + dest[tag] = values[0] + + else: + # Spec'd length > 1 or undefined + # Unspec'd, and length > 1 + dest[tag] = values + + def __delitem__(self, tag: int) -> None: + self._tags_v2.pop(tag, None) + self._tags_v1.pop(tag, None) + self._tagdata.pop(tag, None) + + def __iter__(self): + return iter(set(self._tagdata) | set(self._tags_v2)) + + def _unpack(self, fmt, data): + return struct.unpack(self._endian + fmt, data) + + def _pack(self, fmt, *values): + return struct.pack(self._endian + fmt, *values) + + list( + map( + _register_basic, + [ + (TiffTags.SHORT, "H", "short"), + (TiffTags.LONG, "L", "long"), + (TiffTags.SIGNED_BYTE, "b", "signed byte"), + (TiffTags.SIGNED_SHORT, "h", "signed short"), + (TiffTags.SIGNED_LONG, "l", "signed long"), + (TiffTags.FLOAT, "f", "float"), + (TiffTags.DOUBLE, "d", "double"), + (TiffTags.IFD, "L", "long"), + (TiffTags.LONG8, "Q", "long8"), + ], + ) + ) + + @_register_loader(1, 1) # Basic type, except for the legacy API. + def load_byte(self, data, legacy_api=True): + return data + + @_register_writer(1) # Basic type, except for the legacy API. + def write_byte(self, data): + if isinstance(data, IFDRational): + data = int(data) + if isinstance(data, int): + data = bytes((data,)) + return data + + @_register_loader(2, 1) + def load_string(self, data, legacy_api=True): + if data.endswith(b"\0"): + data = data[:-1] + return data.decode("latin-1", "replace") + + @_register_writer(2) + def write_string(self, value): + # remerge of https://github.com/python-pillow/Pillow/pull/1416 + if isinstance(value, int): + value = str(value) + if not isinstance(value, bytes): + value = value.encode("ascii", "replace") + return value + b"\0" + + @_register_loader(5, 8) + def load_rational(self, data, legacy_api=True): + vals = self._unpack(f"{len(data) // 4}L", data) + + def combine(a, b): + return (a, b) if legacy_api else IFDRational(a, b) + + return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) + + @_register_writer(5) + def write_rational(self, *values): + return b"".join( + self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values + ) + + @_register_loader(7, 1) + def load_undefined(self, data, legacy_api=True): + return data + + @_register_writer(7) + def write_undefined(self, value): + if isinstance(value, IFDRational): + value = int(value) + if isinstance(value, int): + value = str(value).encode("ascii", "replace") + return value + + @_register_loader(10, 8) + def load_signed_rational(self, data, legacy_api=True): + vals = self._unpack(f"{len(data) // 4}l", data) + + def combine(a, b): + return (a, b) if legacy_api else IFDRational(a, b) + + return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) + + @_register_writer(10) + def write_signed_rational(self, *values): + return b"".join( + self._pack("2l", *_limit_signed_rational(frac, 2**31 - 1, -(2**31))) + for frac in values + ) + + def _ensure_read(self, fp, size): + ret = fp.read(size) + if len(ret) != size: + msg = ( + "Corrupt EXIF data. " + f"Expecting to read {size} bytes but only got {len(ret)}. " + ) + raise OSError(msg) + return ret + + def load(self, fp): + self.reset() + self._offset = fp.tell() + + try: + tag_count = ( + self._unpack("Q", self._ensure_read(fp, 8)) + if self._bigtiff + else self._unpack("H", self._ensure_read(fp, 2)) + )[0] + for i in range(tag_count): + tag, typ, count, data = ( + self._unpack("HHQ8s", self._ensure_read(fp, 20)) + if self._bigtiff + else self._unpack("HHL4s", self._ensure_read(fp, 12)) + ) + + tagname = TiffTags.lookup(tag, self.group).name + typname = TYPES.get(typ, "unknown") + msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" + + try: + unit_size, handler = self._load_dispatch[typ] + except KeyError: + logger.debug("%s - unsupported type %s", msg, typ) + continue # ignore unsupported type + size = count * unit_size + if size > (8 if self._bigtiff else 4): + here = fp.tell() + (offset,) = self._unpack("Q" if self._bigtiff else "L", data) + msg += f" Tag Location: {here} - Data Location: {offset}" + fp.seek(offset) + data = ImageFile._safe_read(fp, size) + fp.seek(here) + else: + data = data[:size] + + if len(data) != size: + warnings.warn( + "Possibly corrupt EXIF data. " + f"Expecting to read {size} bytes but only got {len(data)}." + f" Skipping tag {tag}" + ) + logger.debug(msg) + continue + + if not data: + logger.debug(msg) + continue + + self._tagdata[tag] = data + self.tagtype[tag] = typ + + msg += " - value: " + ( + "" % size if size > 32 else repr(data) + ) + logger.debug(msg) + + (self.next,) = ( + self._unpack("Q", self._ensure_read(fp, 8)) + if self._bigtiff + else self._unpack("L", self._ensure_read(fp, 4)) + ) + except OSError as msg: + warnings.warn(str(msg)) + return + + def tobytes(self, offset=0): + # FIXME What about tagdata? + result = self._pack("H", len(self._tags_v2)) + + entries = [] + offset = offset + len(result) + len(self._tags_v2) * 12 + 4 + stripoffsets = None + + # pass 1: convert tags to binary format + # always write tags in ascending order + for tag, value in sorted(self._tags_v2.items()): + if tag == STRIPOFFSETS: + stripoffsets = len(entries) + typ = self.tagtype.get(tag) + logger.debug("Tag %s, Type: %s, Value: %s", tag, typ, repr(value)) + is_ifd = typ == TiffTags.LONG and isinstance(value, dict) + if is_ifd: + if self._endian == "<": + ifh = b"II\x2A\x00\x08\x00\x00\x00" + else: + ifh = b"MM\x00\x2A\x00\x00\x00\x08" + ifd = ImageFileDirectory_v2(ifh, group=tag) + values = self._tags_v2[tag] + for ifd_tag, ifd_value in values.items(): + ifd[ifd_tag] = ifd_value + data = ifd.tobytes(offset) + else: + values = value if isinstance(value, tuple) else (value,) + data = self._write_dispatch[typ](self, *values) + + tagname = TiffTags.lookup(tag, self.group).name + typname = "ifd" if is_ifd else TYPES.get(typ, "unknown") + msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})" + msg += " - value: " + ( + "" % len(data) if len(data) >= 16 else str(values) + ) + logger.debug(msg) + + # count is sum of lengths for string and arbitrary data + if is_ifd: + count = 1 + elif typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]: + count = len(data) + else: + count = len(values) + # figure out if data fits into the entry + if len(data) <= 4: + entries.append((tag, typ, count, data.ljust(4, b"\0"), b"")) + else: + entries.append((tag, typ, count, self._pack("L", offset), data)) + offset += (len(data) + 1) // 2 * 2 # pad to word + + # update strip offset data to point beyond auxiliary data + if stripoffsets is not None: + tag, typ, count, value, data = entries[stripoffsets] + if data: + msg = "multistrip support not yet implemented" + raise NotImplementedError(msg) + value = self._pack("L", self._unpack("L", value)[0] + offset) + entries[stripoffsets] = tag, typ, count, value, data + + # pass 2: write entries to file + for tag, typ, count, value, data in entries: + logger.debug("%s %s %s %s %s", tag, typ, count, repr(value), repr(data)) + result += self._pack("HHL4s", tag, typ, count, value) + + # -- overwrite here for multi-page -- + result += b"\0\0\0\0" # end of entries + + # pass 3: write auxiliary data to file + for tag, typ, count, value, data in entries: + result += data + if len(data) & 1: + result += b"\0" + + return result + + def save(self, fp): + if fp.tell() == 0: # skip TIFF header on subsequent pages + # tiff header -- PIL always starts the first IFD at offset 8 + fp.write(self._prefix + self._pack("HL", 42, 8)) + + offset = fp.tell() + result = self.tobytes(offset) + fp.write(result) + return offset + len(result) + + +ImageFileDirectory_v2._load_dispatch = _load_dispatch +ImageFileDirectory_v2._write_dispatch = _write_dispatch +for idx, name in TYPES.items(): + name = name.replace(" ", "_") + setattr(ImageFileDirectory_v2, f"load_{name}", _load_dispatch[idx][1]) + setattr(ImageFileDirectory_v2, f"write_{name}", _write_dispatch[idx]) +del _load_dispatch, _write_dispatch, idx, name + + +# Legacy ImageFileDirectory support. +class ImageFileDirectory_v1(ImageFileDirectory_v2): + """This class represents the **legacy** interface to a TIFF tag directory. + + Exposes a dictionary interface of the tags in the directory:: + + ifd = ImageFileDirectory_v1() + ifd[key] = 'Some Data' + ifd.tagtype[key] = TiffTags.ASCII + print(ifd[key]) + ('Some Data',) + + Also contains a dictionary of tag types as read from the tiff image file, + :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v1.tagtype`. + + Values are returned as a tuple. + + .. deprecated:: 3.0.0 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._legacy_api = True + + tags = property(lambda self: self._tags_v1) + tagdata = property(lambda self: self._tagdata) + + # defined in ImageFileDirectory_v2 + tagtype: dict[int, int] + """Dictionary of tag types""" + + @classmethod + def from_v2(cls, original): + """Returns an + :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1` + instance with the same data as is contained in the original + :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2` + instance. + + :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1` + + """ + + ifd = cls(prefix=original.prefix) + ifd._tagdata = original._tagdata + ifd.tagtype = original.tagtype + ifd.next = original.next # an indicator for multipage tiffs + return ifd + + def to_v2(self) -> ImageFileDirectory_v2: + """Returns an + :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2` + instance with the same data as is contained in the original + :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1` + instance. + + :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2` + + """ + + ifd = ImageFileDirectory_v2(prefix=self.prefix) + ifd._tagdata = dict(self._tagdata) + ifd.tagtype = dict(self.tagtype) + ifd._tags_v2 = dict(self._tags_v2) + return ifd + + def __contains__(self, tag): + return tag in self._tags_v1 or tag in self._tagdata + + def __len__(self) -> int: + return len(set(self._tagdata) | set(self._tags_v1)) + + def __iter__(self): + return iter(set(self._tagdata) | set(self._tags_v1)) + + def __setitem__(self, tag, value): + for legacy_api in (False, True): + self._setitem(tag, value, legacy_api) + + def __getitem__(self, tag): + if tag not in self._tags_v1: # unpack on the fly + data = self._tagdata[tag] + typ = self.tagtype[tag] + size, handler = self._load_dispatch[typ] + for legacy in (False, True): + self._setitem(tag, handler(self, data, legacy), legacy) + val = self._tags_v1[tag] + if not isinstance(val, (tuple, bytes)): + val = (val,) + return val + + +# undone -- switch this pointer when IFD_LEGACY_API == False +ImageFileDirectory = ImageFileDirectory_v1 + + +## +# Image plugin for TIFF files. + + +class TiffImageFile(ImageFile.ImageFile): + format = "TIFF" + format_description = "Adobe TIFF" + _close_exclusive_fp_after_loading = False + + def __init__(self, fp=None, filename=None): + self.tag_v2 = None + """ Image file directory (tag dictionary) """ + + self.tag = None + """ Legacy tag entries """ + + super().__init__(fp, filename) + + def _open(self) -> None: + """Open the first image in a TIFF file""" + + # Header + ifh = self.fp.read(8) + if ifh[2] == 43: + ifh += self.fp.read(8) + + self.tag_v2 = ImageFileDirectory_v2(ifh) + + # legacy IFD entries will be filled in later + self.ifd = None + + # setup frame pointers + self.__first = self.__next = self.tag_v2.next + self.__frame = -1 + self._fp = self.fp + self._frame_pos: list[int] = [] + self._n_frames: int | None = None + + logger.debug("*** TiffImageFile._open ***") + logger.debug("- __first: %s", self.__first) + logger.debug("- ifh: %s", repr(ifh)) # Use repr to avoid str(bytes) + + # and load the first frame + self._seek(0) + + @property + def n_frames(self): + if self._n_frames is None: + current = self.tell() + self._seek(len(self._frame_pos)) + while self._n_frames is None: + self._seek(self.tell() + 1) + self.seek(current) + return self._n_frames + + def seek(self, frame: int) -> None: + """Select a given frame as current image""" + if not self._seek_check(frame): + return + self._seek(frame) + # Create a new core image object on second and + # subsequent frames in the image. Image may be + # different size/mode. + Image._decompression_bomb_check(self.size) + self.im = Image.core.new(self.mode, self.size) + + def _seek(self, frame: int) -> None: + self.fp = self._fp + + # reset buffered io handle in case fp + # was passed to libtiff, invalidating the buffer + self.fp.tell() + + while len(self._frame_pos) <= frame: + if not self.__next: + msg = "no more images in TIFF file" + raise EOFError(msg) + logger.debug( + "Seeking to frame %s, on frame %s, __next %s, location: %s", + frame, + self.__frame, + self.__next, + self.fp.tell(), + ) + if self.__next >= 2**63: + msg = "Unable to seek to frame" + raise ValueError(msg) + self.fp.seek(self.__next) + self._frame_pos.append(self.__next) + logger.debug("Loading tags, location: %s", self.fp.tell()) + self.tag_v2.load(self.fp) + if self.tag_v2.next in self._frame_pos: + # This IFD has already been processed + # Declare this to be the end of the image + self.__next = 0 + else: + self.__next = self.tag_v2.next + if self.__next == 0: + self._n_frames = frame + 1 + if len(self._frame_pos) == 1: + self.is_animated = self.__next != 0 + self.__frame += 1 + self.fp.seek(self._frame_pos[frame]) + self.tag_v2.load(self.fp) + if XMP in self.tag_v2: + self.info["xmp"] = self.tag_v2[XMP] + elif "xmp" in self.info: + del self.info["xmp"] + self._reload_exif() + # fill the legacy tag/ifd entries + self.tag = self.ifd = ImageFileDirectory_v1.from_v2(self.tag_v2) + self.__frame = frame + self._setup() + + def tell(self) -> int: + """Return the current frame number""" + return self.__frame + + def get_photoshop_blocks(self): + """ + Returns a dictionary of Photoshop "Image Resource Blocks". + The keys are the image resource ID. For more information, see + https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037727 + + :returns: Photoshop "Image Resource Blocks" in a dictionary. + """ + blocks = {} + val = self.tag_v2.get(ExifTags.Base.ImageResources) + if val: + while val[:4] == b"8BIM": + id = i16(val[4:6]) + n = math.ceil((val[6] + 1) / 2) * 2 + size = i32(val[6 + n : 10 + n]) + data = val[10 + n : 10 + n + size] + blocks[id] = {"data": data} + + val = val[math.ceil((10 + n + size) / 2) * 2 :] + return blocks + + def load(self): + if self.tile and self.use_load_libtiff: + return self._load_libtiff() + return super().load() + + def load_end(self) -> None: + # allow closing if we're on the first frame, there's no next + # This is the ImageFile.load path only, libtiff specific below. + if not self.is_animated: + self._close_exclusive_fp_after_loading = True + + # reset buffered io handle in case fp + # was passed to libtiff, invalidating the buffer + self.fp.tell() + + # load IFD data from fp before it is closed + exif = self.getexif() + for key in TiffTags.TAGS_V2_GROUPS: + if key not in exif: + continue + exif.get_ifd(key) + + ImageOps.exif_transpose(self, in_place=True) + if ExifTags.Base.Orientation in self.tag_v2: + del self.tag_v2[ExifTags.Base.Orientation] + + def _load_libtiff(self): + """Overload method triggered when we detect a compressed tiff + Calls out to libtiff""" + + Image.Image.load(self) + + self.load_prepare() + + if not len(self.tile) == 1: + msg = "Not exactly one tile" + raise OSError(msg) + + # (self._compression, (extents tuple), + # 0, (rawmode, self._compression, fp)) + extents = self.tile[0][1] + args = list(self.tile[0][3]) + + # To be nice on memory footprint, if there's a + # file descriptor, use that instead of reading + # into a string in python. + try: + fp = hasattr(self.fp, "fileno") and self.fp.fileno() + # flush the file descriptor, prevents error on pypy 2.4+ + # should also eliminate the need for fp.tell + # in _seek + if hasattr(self.fp, "flush"): + self.fp.flush() + except OSError: + # io.BytesIO have a fileno, but returns an OSError if + # it doesn't use a file descriptor. + fp = False + + if fp: + args[2] = fp + + decoder = Image._getdecoder( + self.mode, "libtiff", tuple(args), self.decoderconfig + ) + try: + decoder.setimage(self.im, extents) + except ValueError as e: + msg = "Couldn't set the image" + raise OSError(msg) from e + + close_self_fp = self._exclusive_fp and not self.is_animated + if hasattr(self.fp, "getvalue"): + # We've got a stringio like thing passed in. Yay for all in memory. + # The decoder needs the entire file in one shot, so there's not + # a lot we can do here other than give it the entire file. + # unless we could do something like get the address of the + # underlying string for stringio. + # + # Rearranging for supporting byteio items, since they have a fileno + # that returns an OSError if there's no underlying fp. Easier to + # deal with here by reordering. + logger.debug("have getvalue. just sending in a string from getvalue") + n, err = decoder.decode(self.fp.getvalue()) + elif fp: + # we've got a actual file on disk, pass in the fp. + logger.debug("have fileno, calling fileno version of the decoder.") + if not close_self_fp: + self.fp.seek(0) + # 4 bytes, otherwise the trace might error out + n, err = decoder.decode(b"fpfp") + else: + # we have something else. + logger.debug("don't have fileno or getvalue. just reading") + self.fp.seek(0) + # UNDONE -- so much for that buffer size thing. + n, err = decoder.decode(self.fp.read()) + + self.tile = [] + self.readonly = 0 + + self.load_end() + + if close_self_fp: + self.fp.close() + self.fp = None # might be shared + + if err < 0: + raise OSError(err) + + return Image.Image.load(self) + + def _setup(self): + """Setup this image object based on current tags""" + + if 0xBC01 in self.tag_v2: + msg = "Windows Media Photo files not yet supported" + raise OSError(msg) + + # extract relevant tags + self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)] + self._planar_configuration = self.tag_v2.get(PLANAR_CONFIGURATION, 1) + + # photometric is a required tag, but not everyone is reading + # the specification + photo = self.tag_v2.get(PHOTOMETRIC_INTERPRETATION, 0) + + # old style jpeg compression images most certainly are YCbCr + if self._compression == "tiff_jpeg": + photo = 6 + + fillorder = self.tag_v2.get(FILLORDER, 1) + + logger.debug("*** Summary ***") + logger.debug("- compression: %s", self._compression) + logger.debug("- photometric_interpretation: %s", photo) + logger.debug("- planar_configuration: %s", self._planar_configuration) + logger.debug("- fill_order: %s", fillorder) + logger.debug("- YCbCr subsampling: %s", self.tag.get(YCBCRSUBSAMPLING)) + + # size + xsize = int(self.tag_v2.get(IMAGEWIDTH)) + ysize = int(self.tag_v2.get(IMAGELENGTH)) + self._size = xsize, ysize + + logger.debug("- size: %s", self.size) + + sample_format = self.tag_v2.get(SAMPLEFORMAT, (1,)) + if len(sample_format) > 1 and max(sample_format) == min(sample_format) == 1: + # SAMPLEFORMAT is properly per band, so an RGB image will + # be (1,1,1). But, we don't support per band pixel types, + # and anything more than one band is a uint8. So, just + # take the first element. Revisit this if adding support + # for more exotic images. + sample_format = (1,) + + bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,)) + extra_tuple = self.tag_v2.get(EXTRASAMPLES, ()) + if photo in (2, 6, 8): # RGB, YCbCr, LAB + bps_count = 3 + elif photo == 5: # CMYK + bps_count = 4 + else: + bps_count = 1 + bps_count += len(extra_tuple) + bps_actual_count = len(bps_tuple) + samples_per_pixel = self.tag_v2.get( + SAMPLESPERPIXEL, + 3 if self._compression == "tiff_jpeg" and photo in (2, 6) else 1, + ) + + if samples_per_pixel > MAX_SAMPLESPERPIXEL: + # DOS check, samples_per_pixel can be a Long, and we extend the tuple below + logger.error( + "More samples per pixel than can be decoded: %s", samples_per_pixel + ) + msg = "Invalid value for samples per pixel" + raise SyntaxError(msg) + + if samples_per_pixel < bps_actual_count: + # If a file has more values in bps_tuple than expected, + # remove the excess. + bps_tuple = bps_tuple[:samples_per_pixel] + elif samples_per_pixel > bps_actual_count and bps_actual_count == 1: + # If a file has only one value in bps_tuple, when it should have more, + # presume it is the same number of bits for all of the samples. + bps_tuple = bps_tuple * samples_per_pixel + + if len(bps_tuple) != samples_per_pixel: + msg = "unknown data organization" + raise SyntaxError(msg) + + # mode: check photometric interpretation and bits per pixel + key = ( + self.tag_v2.prefix, + photo, + sample_format, + fillorder, + bps_tuple, + extra_tuple, + ) + logger.debug("format key: %s", key) + try: + self._mode, rawmode = OPEN_INFO[key] + except KeyError as e: + logger.debug("- unsupported format") + msg = "unknown pixel mode" + raise SyntaxError(msg) from e + + logger.debug("- raw mode: %s", rawmode) + logger.debug("- pil mode: %s", self.mode) + + self.info["compression"] = self._compression + + xres = self.tag_v2.get(X_RESOLUTION, 1) + yres = self.tag_v2.get(Y_RESOLUTION, 1) + + if xres and yres: + resunit = self.tag_v2.get(RESOLUTION_UNIT) + if resunit == 2: # dots per inch + self.info["dpi"] = (xres, yres) + elif resunit == 3: # dots per centimeter. convert to dpi + self.info["dpi"] = (xres * 2.54, yres * 2.54) + elif resunit is None: # used to default to 1, but now 2) + self.info["dpi"] = (xres, yres) + # For backward compatibility, + # we also preserve the old behavior + self.info["resolution"] = xres, yres + else: # No absolute unit of measurement + self.info["resolution"] = xres, yres + + # build tile descriptors + x = y = layer = 0 + self.tile = [] + self.use_load_libtiff = READ_LIBTIFF or self._compression != "raw" + if self.use_load_libtiff: + # Decoder expects entire file as one tile. + # There's a buffer size limit in load (64k) + # so large g4 images will fail if we use that + # function. + # + # Setup the one tile for the whole image, then + # use the _load_libtiff function. + + # libtiff handles the fillmode for us, so 1;IR should + # actually be 1;I. Including the R double reverses the + # bits, so stripes of the image are reversed. See + # https://github.com/python-pillow/Pillow/issues/279 + if fillorder == 2: + # Replace fillorder with fillorder=1 + key = key[:3] + (1,) + key[4:] + logger.debug("format key: %s", key) + # this should always work, since all the + # fillorder==2 modes have a corresponding + # fillorder=1 mode + self._mode, rawmode = OPEN_INFO[key] + # libtiff always returns the bytes in native order. + # we're expecting image byte order. So, if the rawmode + # contains I;16, we need to convert from native to image + # byte order. + if rawmode == "I;16": + rawmode = "I;16N" + if ";16B" in rawmode: + rawmode = rawmode.replace(";16B", ";16N") + if ";16L" in rawmode: + rawmode = rawmode.replace(";16L", ";16N") + + # YCbCr images with new jpeg compression with pixels in one plane + # unpacked straight into RGB values + if ( + photo == 6 + and self._compression == "jpeg" + and self._planar_configuration == 1 + ): + rawmode = "RGB" + + # Offset in the tile tuple is 0, we go from 0,0 to + # w,h, and we only do this once -- eds + a = (rawmode, self._compression, False, self.tag_v2.offset) + self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a)) + + elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2: + # striped image + if STRIPOFFSETS in self.tag_v2: + offsets = self.tag_v2[STRIPOFFSETS] + h = self.tag_v2.get(ROWSPERSTRIP, ysize) + w = self.size[0] + else: + # tiled image + offsets = self.tag_v2[TILEOFFSETS] + w = self.tag_v2.get(TILEWIDTH) + h = self.tag_v2.get(TILELENGTH) + + for offset in offsets: + if x + w > xsize: + stride = w * sum(bps_tuple) / 8 # bytes per line + else: + stride = 0 + + tile_rawmode = rawmode + if self._planar_configuration == 2: + # each band on it's own layer + tile_rawmode = rawmode[layer] + # adjust stride width accordingly + stride /= bps_count + + a = (tile_rawmode, int(stride), 1) + self.tile.append( + ( + self._compression, + (x, y, min(x + w, xsize), min(y + h, ysize)), + offset, + a, + ) + ) + x = x + w + if x >= self.size[0]: + x, y = 0, y + h + if y >= self.size[1]: + x = y = 0 + layer += 1 + else: + logger.debug("- unsupported data organization") + msg = "unknown data organization" + raise SyntaxError(msg) + + # Fix up info. + if ICCPROFILE in self.tag_v2: + self.info["icc_profile"] = self.tag_v2[ICCPROFILE] + + # fixup palette descriptor + + if self.mode in ["P", "PA"]: + palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]] + self.palette = ImagePalette.raw("RGB;L", b"".join(palette)) + + +# +# -------------------------------------------------------------------- +# Write TIFF files + +# little endian is default except for image modes with +# explicit big endian byte-order + +SAVE_INFO = { + # mode => rawmode, byteorder, photometrics, + # sampleformat, bitspersample, extra + "1": ("1", II, 1, 1, (1,), None), + "L": ("L", II, 1, 1, (8,), None), + "LA": ("LA", II, 1, 1, (8, 8), 2), + "P": ("P", II, 3, 1, (8,), None), + "PA": ("PA", II, 3, 1, (8, 8), 2), + "I": ("I;32S", II, 1, 2, (32,), None), + "I;16": ("I;16", II, 1, 1, (16,), None), + "I;16S": ("I;16S", II, 1, 2, (16,), None), + "F": ("F;32F", II, 1, 3, (32,), None), + "RGB": ("RGB", II, 2, 1, (8, 8, 8), None), + "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0), + "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2), + "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None), + "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None), + "LAB": ("LAB", II, 8, 1, (8, 8, 8), None), + "I;32BS": ("I;32BS", MM, 1, 2, (32,), None), + "I;16B": ("I;16B", MM, 1, 1, (16,), None), + "I;16BS": ("I;16BS", MM, 1, 2, (16,), None), + "F;32BF": ("F;32BF", MM, 1, 3, (32,), None), +} + + +def _save(im, fp, filename): + try: + rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] + except KeyError as e: + msg = f"cannot write mode {im.mode} as TIFF" + raise OSError(msg) from e + + ifd = ImageFileDirectory_v2(prefix=prefix) + + encoderinfo = im.encoderinfo + encoderconfig = im.encoderconfig + try: + compression = encoderinfo["compression"] + except KeyError: + compression = im.info.get("compression") + if isinstance(compression, int): + # compression value may be from BMP. Ignore it + compression = None + if compression is None: + compression = "raw" + elif compression == "tiff_jpeg": + # OJPEG is obsolete, so use new-style JPEG compression instead + compression = "jpeg" + elif compression == "tiff_deflate": + compression = "tiff_adobe_deflate" + + libtiff = WRITE_LIBTIFF or compression != "raw" + + # required for color libtiff images + ifd[PLANAR_CONFIGURATION] = 1 + + ifd[IMAGEWIDTH] = im.size[0] + ifd[IMAGELENGTH] = im.size[1] + + # write any arbitrary tags passed in as an ImageFileDirectory + if "tiffinfo" in encoderinfo: + info = encoderinfo["tiffinfo"] + elif "exif" in encoderinfo: + info = encoderinfo["exif"] + if isinstance(info, bytes): + exif = Image.Exif() + exif.load(info) + info = exif + else: + info = {} + logger.debug("Tiffinfo Keys: %s", list(info)) + if isinstance(info, ImageFileDirectory_v1): + info = info.to_v2() + for key in info: + if isinstance(info, Image.Exif) and key in TiffTags.TAGS_V2_GROUPS: + ifd[key] = info.get_ifd(key) + else: + ifd[key] = info.get(key) + try: + ifd.tagtype[key] = info.tagtype[key] + except Exception: + pass # might not be an IFD. Might not have populated type + + legacy_ifd = {} + if hasattr(im, "tag"): + legacy_ifd = im.tag.to_v2() + + supplied_tags = {**legacy_ifd, **getattr(im, "tag_v2", {})} + for tag in ( + # IFD offset that may not be correct in the saved image + EXIFIFD, + # Determined by the image format and should not be copied from legacy_ifd. + SAMPLEFORMAT, + ): + if tag in supplied_tags: + del supplied_tags[tag] + + # additions written by Greg Couch, gregc@cgl.ucsf.edu + # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com + if hasattr(im, "tag_v2"): + # preserve tags from original TIFF image file + for key in ( + RESOLUTION_UNIT, + X_RESOLUTION, + Y_RESOLUTION, + IPTC_NAA_CHUNK, + PHOTOSHOP_CHUNK, + XMP, + ): + if key in im.tag_v2: + if key == IPTC_NAA_CHUNK and im.tag_v2.tagtype[key] not in ( + TiffTags.BYTE, + TiffTags.UNDEFINED, + ): + del supplied_tags[key] + else: + ifd[key] = im.tag_v2[key] + ifd.tagtype[key] = im.tag_v2.tagtype[key] + + # preserve ICC profile (should also work when saving other formats + # which support profiles as TIFF) -- 2008-06-06 Florian Hoech + icc = encoderinfo.get("icc_profile", im.info.get("icc_profile")) + if icc: + ifd[ICCPROFILE] = icc + + for key, name in [ + (IMAGEDESCRIPTION, "description"), + (X_RESOLUTION, "resolution"), + (Y_RESOLUTION, "resolution"), + (X_RESOLUTION, "x_resolution"), + (Y_RESOLUTION, "y_resolution"), + (RESOLUTION_UNIT, "resolution_unit"), + (SOFTWARE, "software"), + (DATE_TIME, "date_time"), + (ARTIST, "artist"), + (COPYRIGHT, "copyright"), + ]: + if name in encoderinfo: + ifd[key] = encoderinfo[name] + + dpi = encoderinfo.get("dpi") + if dpi: + ifd[RESOLUTION_UNIT] = 2 + ifd[X_RESOLUTION] = dpi[0] + ifd[Y_RESOLUTION] = dpi[1] + + if bits != (1,): + ifd[BITSPERSAMPLE] = bits + if len(bits) != 1: + ifd[SAMPLESPERPIXEL] = len(bits) + if extra is not None: + ifd[EXTRASAMPLES] = extra + if format != 1: + ifd[SAMPLEFORMAT] = format + + if PHOTOMETRIC_INTERPRETATION not in ifd: + ifd[PHOTOMETRIC_INTERPRETATION] = photo + elif im.mode in ("1", "L") and ifd[PHOTOMETRIC_INTERPRETATION] == 0: + if im.mode == "1": + inverted_im = im.copy() + px = inverted_im.load() + for y in range(inverted_im.height): + for x in range(inverted_im.width): + px[x, y] = 0 if px[x, y] == 255 else 255 + im = inverted_im + else: + im = ImageOps.invert(im) + + if im.mode in ["P", "PA"]: + lut = im.im.getpalette("RGB", "RGB;L") + colormap = [] + colors = len(lut) // 3 + for i in range(3): + colormap += [v * 256 for v in lut[colors * i : colors * (i + 1)]] + colormap += [0] * (256 - colors) + ifd[COLORMAP] = colormap + # data orientation + w, h = ifd[IMAGEWIDTH], ifd[IMAGELENGTH] + stride = len(bits) * ((w * bits[0] + 7) // 8) + if ROWSPERSTRIP not in ifd: + # aim for given strip size (64 KB by default) when using libtiff writer + if libtiff: + im_strip_size = encoderinfo.get("strip_size", STRIP_SIZE) + rows_per_strip = 1 if stride == 0 else min(im_strip_size // stride, h) + # JPEG encoder expects multiple of 8 rows + if compression == "jpeg": + rows_per_strip = min(((rows_per_strip + 7) // 8) * 8, h) + else: + rows_per_strip = h + if rows_per_strip == 0: + rows_per_strip = 1 + ifd[ROWSPERSTRIP] = rows_per_strip + strip_byte_counts = 1 if stride == 0 else stride * ifd[ROWSPERSTRIP] + strips_per_image = (h + ifd[ROWSPERSTRIP] - 1) // ifd[ROWSPERSTRIP] + if strip_byte_counts >= 2**16: + ifd.tagtype[STRIPBYTECOUNTS] = TiffTags.LONG + ifd[STRIPBYTECOUNTS] = (strip_byte_counts,) * (strips_per_image - 1) + ( + stride * h - strip_byte_counts * (strips_per_image - 1), + ) + ifd[STRIPOFFSETS] = tuple( + range(0, strip_byte_counts * strips_per_image, strip_byte_counts) + ) # this is adjusted by IFD writer + # no compression by default: + ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1) + + if im.mode == "YCbCr": + for tag, value in { + YCBCRSUBSAMPLING: (1, 1), + REFERENCEBLACKWHITE: (0, 255, 128, 255, 128, 255), + }.items(): + ifd.setdefault(tag, value) + + blocklist = [TILEWIDTH, TILELENGTH, TILEOFFSETS, TILEBYTECOUNTS] + if libtiff: + if "quality" in encoderinfo: + quality = encoderinfo["quality"] + if not isinstance(quality, int) or quality < 0 or quality > 100: + msg = "Invalid quality setting" + raise ValueError(msg) + if compression != "jpeg": + msg = "quality setting only supported for 'jpeg' compression" + raise ValueError(msg) + ifd[JPEGQUALITY] = quality + + logger.debug("Saving using libtiff encoder") + logger.debug("Items: %s", sorted(ifd.items())) + _fp = 0 + if hasattr(fp, "fileno"): + try: + fp.seek(0) + _fp = os.dup(fp.fileno()) + except io.UnsupportedOperation: + pass + + # optional types for non core tags + types = {} + # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library + # based on the data in the strip. + # OSUBFILETYPE is deprecated. + # The other tags expect arrays with a certain length (fixed or depending on + # BITSPERSAMPLE, etc), passing arrays with a different length will result in + # segfaults. Block these tags until we add extra validation. + # SUBIFD may also cause a segfault. + blocklist += [ + OSUBFILETYPE, + REFERENCEBLACKWHITE, + STRIPBYTECOUNTS, + STRIPOFFSETS, + TRANSFERFUNCTION, + SUBIFD, + ] + + # bits per sample is a single short in the tiff directory, not a list. + atts = {BITSPERSAMPLE: bits[0]} + # Merge the ones that we have with (optional) more bits from + # the original file, e.g x,y resolution so that we can + # save(load('')) == original file. + for tag, value in itertools.chain(ifd.items(), supplied_tags.items()): + # Libtiff can only process certain core items without adding + # them to the custom dictionary. + # Custom items are supported for int, float, unicode, string and byte + # values. Other types and tuples require a tagtype. + if tag not in TiffTags.LIBTIFF_CORE: + if not getattr(Image.core, "libtiff_support_custom_tags", False): + continue + + if tag in ifd.tagtype: + types[tag] = ifd.tagtype[tag] + elif not (isinstance(value, (int, float, str, bytes))): + continue + else: + type = TiffTags.lookup(tag).type + if type: + types[tag] = type + if tag not in atts and tag not in blocklist: + if isinstance(value, str): + atts[tag] = value.encode("ascii", "replace") + b"\0" + elif isinstance(value, IFDRational): + atts[tag] = float(value) + else: + atts[tag] = value + + if SAMPLEFORMAT in atts and len(atts[SAMPLEFORMAT]) == 1: + atts[SAMPLEFORMAT] = atts[SAMPLEFORMAT][0] + + logger.debug("Converted items: %s", sorted(atts.items())) + + # libtiff always expects the bytes in native order. + # we're storing image byte order. So, if the rawmode + # contains I;16, we need to convert from native to image + # byte order. + if im.mode in ("I;16B", "I;16"): + rawmode = "I;16N" + + # Pass tags as sorted list so that the tags are set in a fixed order. + # This is required by libtiff for some tags. For example, the JPEGQUALITY + # pseudo tag requires that the COMPRESS tag was already set. + tags = list(atts.items()) + tags.sort() + a = (rawmode, compression, _fp, filename, tags, types) + encoder = Image._getencoder(im.mode, "libtiff", a, encoderconfig) + encoder.setimage(im.im, (0, 0) + im.size) + while True: + # undone, change to self.decodermaxblock: + errcode, data = encoder.encode(16 * 1024)[1:] + if not _fp: + fp.write(data) + if errcode: + break + if _fp: + try: + os.close(_fp) + except OSError: + pass + if errcode < 0: + msg = f"encoder error {errcode} when writing image file" + raise OSError(msg) + + else: + for tag in blocklist: + del ifd[tag] + offset = ifd.save(fp) + + ImageFile._save( + im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))] + ) + + # -- helper for multi-page save -- + if "_debug_multipage" in encoderinfo: + # just to access o32 and o16 (using correct byte order) + im._debug_multipage = ifd + + +class AppendingTiffWriter: + fieldSizes = [ + 0, # None + 1, # byte + 1, # ascii + 2, # short + 4, # long + 8, # rational + 1, # sbyte + 1, # undefined + 2, # sshort + 4, # slong + 8, # srational + 4, # float + 8, # double + 4, # ifd + 2, # unicode + 4, # complex + 8, # long8 + ] + + Tags = { + 273, # StripOffsets + 288, # FreeOffsets + 324, # TileOffsets + 519, # JPEGQTables + 520, # JPEGDCTables + 521, # JPEGACTables + } + + def __init__(self, fn, new=False): + if hasattr(fn, "read"): + self.f = fn + self.close_fp = False + else: + self.name = fn + self.close_fp = True + try: + self.f = open(fn, "w+b" if new else "r+b") + except OSError: + self.f = open(fn, "w+b") + self.beginning = self.f.tell() + self.setup() + + def setup(self) -> None: + # Reset everything. + self.f.seek(self.beginning, os.SEEK_SET) + + self.whereToWriteNewIFDOffset = None + self.offsetOfNewPage = 0 + + self.IIMM = iimm = self.f.read(4) + if not iimm: + # empty file - first page + self.isFirst = True + return + + self.isFirst = False + if iimm == b"II\x2a\x00": + self.setEndian("<") + elif iimm == b"MM\x00\x2a": + self.setEndian(">") + else: + msg = "Invalid TIFF file header" + raise RuntimeError(msg) + + self.skipIFDs() + self.goToEnd() + + def finalize(self) -> None: + if self.isFirst: + return + + # fix offsets + self.f.seek(self.offsetOfNewPage) + + iimm = self.f.read(4) + if not iimm: + # Make it easy to finish a frame without committing to a new one. + return + + if iimm != self.IIMM: + msg = "IIMM of new page doesn't match IIMM of first page" + raise RuntimeError(msg) + + ifd_offset = self.readLong() + ifd_offset += self.offsetOfNewPage + self.f.seek(self.whereToWriteNewIFDOffset) + self.writeLong(ifd_offset) + self.f.seek(ifd_offset) + self.fixIFD() + + def newFrame(self) -> None: + # Call this to finish a frame. + self.finalize() + self.setup() + + def __enter__(self) -> AppendingTiffWriter: + return self + + def __exit__(self, *args: object) -> None: + if self.close_fp: + self.close() + + def tell(self) -> int: + return self.f.tell() - self.offsetOfNewPage + + def seek(self, offset, whence=io.SEEK_SET): + if whence == os.SEEK_SET: + offset += self.offsetOfNewPage + + self.f.seek(offset, whence) + return self.tell() + + def goToEnd(self) -> None: + self.f.seek(0, os.SEEK_END) + pos = self.f.tell() + + # pad to 16 byte boundary + pad_bytes = 16 - pos % 16 + if 0 < pad_bytes < 16: + self.f.write(bytes(pad_bytes)) + self.offsetOfNewPage = self.f.tell() + + def setEndian(self, endian: str) -> None: + self.endian = endian + self.longFmt = f"{self.endian}L" + self.shortFmt = f"{self.endian}H" + self.tagFormat = f"{self.endian}HHL" + + def skipIFDs(self) -> None: + while True: + ifd_offset = self.readLong() + if ifd_offset == 0: + self.whereToWriteNewIFDOffset = self.f.tell() - 4 + break + + self.f.seek(ifd_offset) + num_tags = self.readShort() + self.f.seek(num_tags * 12, os.SEEK_CUR) + + def write(self, data: bytes) -> int | None: + return self.f.write(data) + + def readShort(self) -> int: + (value,) = struct.unpack(self.shortFmt, self.f.read(2)) + return value + + def readLong(self) -> int: + (value,) = struct.unpack(self.longFmt, self.f.read(4)) + return value + + def rewriteLastShortToLong(self, value: int) -> None: + self.f.seek(-2, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) + + def rewriteLastShort(self, value: int) -> None: + self.f.seek(-2, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.shortFmt, value)) + if bytes_written is not None and bytes_written != 2: + msg = f"wrote only {bytes_written} bytes but wanted 2" + raise RuntimeError(msg) + + def rewriteLastLong(self, value: int) -> None: + self.f.seek(-4, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) + + def writeShort(self, value: int) -> None: + bytes_written = self.f.write(struct.pack(self.shortFmt, value)) + if bytes_written is not None and bytes_written != 2: + msg = f"wrote only {bytes_written} bytes but wanted 2" + raise RuntimeError(msg) + + def writeLong(self, value: int) -> None: + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) + + def close(self) -> None: + self.finalize() + self.f.close() + + def fixIFD(self) -> None: + num_tags = self.readShort() + + for i in range(num_tags): + tag, field_type, count = struct.unpack(self.tagFormat, self.f.read(8)) + + field_size = self.fieldSizes[field_type] + total_size = field_size * count + is_local = total_size <= 4 + offset: int | None + if not is_local: + offset = self.readLong() + self.offsetOfNewPage + self.rewriteLastLong(offset) + + if tag in self.Tags: + cur_pos = self.f.tell() + + if is_local: + self.fixOffsets( + count, isShort=(field_size == 2), isLong=(field_size == 4) + ) + self.f.seek(cur_pos + 4) + else: + self.f.seek(offset) + self.fixOffsets( + count, isShort=(field_size == 2), isLong=(field_size == 4) + ) + self.f.seek(cur_pos) + + offset = cur_pos = None + + elif is_local: + # skip the locally stored value that is not an offset + self.f.seek(4, os.SEEK_CUR) + + def fixOffsets( + self, count: int, isShort: bool = False, isLong: bool = False + ) -> None: + if not isShort and not isLong: + msg = "offset is neither short nor long" + raise RuntimeError(msg) + + for i in range(count): + offset = self.readShort() if isShort else self.readLong() + offset += self.offsetOfNewPage + if isShort and offset >= 65536: + # offset is now too large - we must convert shorts to longs + if count != 1: + msg = "not implemented" + raise RuntimeError(msg) # XXX TODO + + # simple case - the offset is just one and therefore it is + # local (not referenced with another offset) + self.rewriteLastShortToLong(offset) + self.f.seek(-10, os.SEEK_CUR) + self.writeShort(TiffTags.LONG) # rewrite the type to LONG + self.f.seek(8, os.SEEK_CUR) + elif isShort: + self.rewriteLastShort(offset) + else: + self.rewriteLastLong(offset) + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + encoderinfo = im.encoderinfo.copy() + encoderconfig = im.encoderconfig + append_images = list(encoderinfo.get("append_images", [])) + if not hasattr(im, "n_frames") and not append_images: + return _save(im, fp, filename) + + cur_idx = im.tell() + try: + with AppendingTiffWriter(fp) as tf: + for ims in [im] + append_images: + ims.encoderinfo = encoderinfo + ims.encoderconfig = encoderconfig + if not hasattr(ims, "n_frames"): + nfr = 1 + else: + nfr = ims.n_frames + + for idx in range(nfr): + ims.seek(idx) + ims.load() + _save(ims, tf, filename) + tf.newFrame() + finally: + im.seek(cur_idx) + + +# +# -------------------------------------------------------------------- +# Register + +Image.register_open(TiffImageFile.format, TiffImageFile, _accept) +Image.register_save(TiffImageFile.format, _save) +Image.register_save_all(TiffImageFile.format, _save_all) + +Image.register_extensions(TiffImageFile.format, [".tif", ".tiff"]) + +Image.register_mime(TiffImageFile.format, "image/tiff") diff --git a/.venv/lib/python3.12/site-packages/PIL/TiffTags.py b/.venv/lib/python3.12/site-packages/PIL/TiffTags.py new file mode 100644 index 0000000..e318c87 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/TiffTags.py @@ -0,0 +1,555 @@ +# +# The Python Imaging Library. +# $Id$ +# +# TIFF tags +# +# This module provides clear-text names for various well-known +# TIFF tags. the TIFF codec works just fine without it. +# +# Copyright (c) Secret Labs AB 1999. +# +# See the README file for information on usage and redistribution. +# + +## +# This module provides constants and clear-text names for various +# well-known TIFF tags. +## +from __future__ import annotations + +from typing import NamedTuple + + +class _TagInfo(NamedTuple): + value: int | None + name: str + type: int | None + length: int | None + enum: dict[str, int] + + +class TagInfo(_TagInfo): + __slots__: list[str] = [] + + def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None): + return super().__new__(cls, value, name, type, length, enum or {}) + + def cvt_enum(self, value): + # Using get will call hash(value), which can be expensive + # for some types (e.g. Fraction). Since self.enum is rarely + # used, it's usually better to test it first. + return self.enum.get(value, value) if self.enum else value + + +def lookup(tag, group=None): + """ + :param tag: Integer tag number + :param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in + + .. versionadded:: 8.3.0 + + :returns: Taginfo namedtuple, From the ``TAGS_V2`` info if possible, + otherwise just populating the value and name from ``TAGS``. + If the tag is not recognized, "unknown" is returned for the name + + """ + + if group is not None: + info = TAGS_V2_GROUPS[group].get(tag) if group in TAGS_V2_GROUPS else None + else: + info = TAGS_V2.get(tag) + return info or TagInfo(tag, TAGS.get(tag, "unknown")) + + +## +# Map tag numbers to tag info. +# +# id: (Name, Type, Length[, enum_values]) +# +# The length here differs from the length in the tiff spec. For +# numbers, the tiff spec is for the number of fields returned. We +# agree here. For string-like types, the tiff spec uses the length of +# field in bytes. In Pillow, we are using the number of expected +# fields, in general 1 for string-like types. + + +BYTE = 1 +ASCII = 2 +SHORT = 3 +LONG = 4 +RATIONAL = 5 +SIGNED_BYTE = 6 +UNDEFINED = 7 +SIGNED_SHORT = 8 +SIGNED_LONG = 9 +SIGNED_RATIONAL = 10 +FLOAT = 11 +DOUBLE = 12 +IFD = 13 +LONG8 = 16 + +_tags_v2 = { + 254: ("NewSubfileType", LONG, 1), + 255: ("SubfileType", SHORT, 1), + 256: ("ImageWidth", LONG, 1), + 257: ("ImageLength", LONG, 1), + 258: ("BitsPerSample", SHORT, 0), + 259: ( + "Compression", + SHORT, + 1, + { + "Uncompressed": 1, + "CCITT 1d": 2, + "Group 3 Fax": 3, + "Group 4 Fax": 4, + "LZW": 5, + "JPEG": 6, + "PackBits": 32773, + }, + ), + 262: ( + "PhotometricInterpretation", + SHORT, + 1, + { + "WhiteIsZero": 0, + "BlackIsZero": 1, + "RGB": 2, + "RGB Palette": 3, + "Transparency Mask": 4, + "CMYK": 5, + "YCbCr": 6, + "CieLAB": 8, + "CFA": 32803, # TIFF/EP, Adobe DNG + "LinearRaw": 32892, # Adobe DNG + }, + ), + 263: ("Threshholding", SHORT, 1), + 264: ("CellWidth", SHORT, 1), + 265: ("CellLength", SHORT, 1), + 266: ("FillOrder", SHORT, 1), + 269: ("DocumentName", ASCII, 1), + 270: ("ImageDescription", ASCII, 1), + 271: ("Make", ASCII, 1), + 272: ("Model", ASCII, 1), + 273: ("StripOffsets", LONG, 0), + 274: ("Orientation", SHORT, 1), + 277: ("SamplesPerPixel", SHORT, 1), + 278: ("RowsPerStrip", LONG, 1), + 279: ("StripByteCounts", LONG, 0), + 280: ("MinSampleValue", SHORT, 0), + 281: ("MaxSampleValue", SHORT, 0), + 282: ("XResolution", RATIONAL, 1), + 283: ("YResolution", RATIONAL, 1), + 284: ("PlanarConfiguration", SHORT, 1, {"Contiguous": 1, "Separate": 2}), + 285: ("PageName", ASCII, 1), + 286: ("XPosition", RATIONAL, 1), + 287: ("YPosition", RATIONAL, 1), + 288: ("FreeOffsets", LONG, 1), + 289: ("FreeByteCounts", LONG, 1), + 290: ("GrayResponseUnit", SHORT, 1), + 291: ("GrayResponseCurve", SHORT, 0), + 292: ("T4Options", LONG, 1), + 293: ("T6Options", LONG, 1), + 296: ("ResolutionUnit", SHORT, 1, {"none": 1, "inch": 2, "cm": 3}), + 297: ("PageNumber", SHORT, 2), + 301: ("TransferFunction", SHORT, 0), + 305: ("Software", ASCII, 1), + 306: ("DateTime", ASCII, 1), + 315: ("Artist", ASCII, 1), + 316: ("HostComputer", ASCII, 1), + 317: ("Predictor", SHORT, 1, {"none": 1, "Horizontal Differencing": 2}), + 318: ("WhitePoint", RATIONAL, 2), + 319: ("PrimaryChromaticities", RATIONAL, 6), + 320: ("ColorMap", SHORT, 0), + 321: ("HalftoneHints", SHORT, 2), + 322: ("TileWidth", LONG, 1), + 323: ("TileLength", LONG, 1), + 324: ("TileOffsets", LONG, 0), + 325: ("TileByteCounts", LONG, 0), + 330: ("SubIFDs", LONG, 0), + 332: ("InkSet", SHORT, 1), + 333: ("InkNames", ASCII, 1), + 334: ("NumberOfInks", SHORT, 1), + 336: ("DotRange", SHORT, 0), + 337: ("TargetPrinter", ASCII, 1), + 338: ("ExtraSamples", SHORT, 0), + 339: ("SampleFormat", SHORT, 0), + 340: ("SMinSampleValue", DOUBLE, 0), + 341: ("SMaxSampleValue", DOUBLE, 0), + 342: ("TransferRange", SHORT, 6), + 347: ("JPEGTables", UNDEFINED, 1), + # obsolete JPEG tags + 512: ("JPEGProc", SHORT, 1), + 513: ("JPEGInterchangeFormat", LONG, 1), + 514: ("JPEGInterchangeFormatLength", LONG, 1), + 515: ("JPEGRestartInterval", SHORT, 1), + 517: ("JPEGLosslessPredictors", SHORT, 0), + 518: ("JPEGPointTransforms", SHORT, 0), + 519: ("JPEGQTables", LONG, 0), + 520: ("JPEGDCTables", LONG, 0), + 521: ("JPEGACTables", LONG, 0), + 529: ("YCbCrCoefficients", RATIONAL, 3), + 530: ("YCbCrSubSampling", SHORT, 2), + 531: ("YCbCrPositioning", SHORT, 1), + 532: ("ReferenceBlackWhite", RATIONAL, 6), + 700: ("XMP", BYTE, 0), + 33432: ("Copyright", ASCII, 1), + 33723: ("IptcNaaInfo", UNDEFINED, 1), + 34377: ("PhotoshopInfo", BYTE, 0), + # FIXME add more tags here + 34665: ("ExifIFD", LONG, 1), + 34675: ("ICCProfile", UNDEFINED, 1), + 34853: ("GPSInfoIFD", LONG, 1), + 36864: ("ExifVersion", UNDEFINED, 1), + 37724: ("ImageSourceData", UNDEFINED, 1), + 40965: ("InteroperabilityIFD", LONG, 1), + 41730: ("CFAPattern", UNDEFINED, 1), + # MPInfo + 45056: ("MPFVersion", UNDEFINED, 1), + 45057: ("NumberOfImages", LONG, 1), + 45058: ("MPEntry", UNDEFINED, 1), + 45059: ("ImageUIDList", UNDEFINED, 0), # UNDONE, check + 45060: ("TotalFrames", LONG, 1), + 45313: ("MPIndividualNum", LONG, 1), + 45569: ("PanOrientation", LONG, 1), + 45570: ("PanOverlap_H", RATIONAL, 1), + 45571: ("PanOverlap_V", RATIONAL, 1), + 45572: ("BaseViewpointNum", LONG, 1), + 45573: ("ConvergenceAngle", SIGNED_RATIONAL, 1), + 45574: ("BaselineLength", RATIONAL, 1), + 45575: ("VerticalDivergence", SIGNED_RATIONAL, 1), + 45576: ("AxisDistance_X", SIGNED_RATIONAL, 1), + 45577: ("AxisDistance_Y", SIGNED_RATIONAL, 1), + 45578: ("AxisDistance_Z", SIGNED_RATIONAL, 1), + 45579: ("YawAngle", SIGNED_RATIONAL, 1), + 45580: ("PitchAngle", SIGNED_RATIONAL, 1), + 45581: ("RollAngle", SIGNED_RATIONAL, 1), + 40960: ("FlashPixVersion", UNDEFINED, 1), + 50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}), + 50780: ("BestQualityScale", RATIONAL, 1), + 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one + 50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006 +} +TAGS_V2_GROUPS = { + # ExifIFD + 34665: { + 36864: ("ExifVersion", UNDEFINED, 1), + 40960: ("FlashPixVersion", UNDEFINED, 1), + 40965: ("InteroperabilityIFD", LONG, 1), + 41730: ("CFAPattern", UNDEFINED, 1), + }, + # GPSInfoIFD + 34853: { + 0: ("GPSVersionID", BYTE, 4), + 1: ("GPSLatitudeRef", ASCII, 2), + 2: ("GPSLatitude", RATIONAL, 3), + 3: ("GPSLongitudeRef", ASCII, 2), + 4: ("GPSLongitude", RATIONAL, 3), + 5: ("GPSAltitudeRef", BYTE, 1), + 6: ("GPSAltitude", RATIONAL, 1), + 7: ("GPSTimeStamp", RATIONAL, 3), + 8: ("GPSSatellites", ASCII, 0), + 9: ("GPSStatus", ASCII, 2), + 10: ("GPSMeasureMode", ASCII, 2), + 11: ("GPSDOP", RATIONAL, 1), + 12: ("GPSSpeedRef", ASCII, 2), + 13: ("GPSSpeed", RATIONAL, 1), + 14: ("GPSTrackRef", ASCII, 2), + 15: ("GPSTrack", RATIONAL, 1), + 16: ("GPSImgDirectionRef", ASCII, 2), + 17: ("GPSImgDirection", RATIONAL, 1), + 18: ("GPSMapDatum", ASCII, 0), + 19: ("GPSDestLatitudeRef", ASCII, 2), + 20: ("GPSDestLatitude", RATIONAL, 3), + 21: ("GPSDestLongitudeRef", ASCII, 2), + 22: ("GPSDestLongitude", RATIONAL, 3), + 23: ("GPSDestBearingRef", ASCII, 2), + 24: ("GPSDestBearing", RATIONAL, 1), + 25: ("GPSDestDistanceRef", ASCII, 2), + 26: ("GPSDestDistance", RATIONAL, 1), + 27: ("GPSProcessingMethod", UNDEFINED, 0), + 28: ("GPSAreaInformation", UNDEFINED, 0), + 29: ("GPSDateStamp", ASCII, 11), + 30: ("GPSDifferential", SHORT, 1), + }, + # InteroperabilityIFD + 40965: {1: ("InteropIndex", ASCII, 1), 2: ("InteropVersion", UNDEFINED, 1)}, +} + +# Legacy Tags structure +# these tags aren't included above, but were in the previous versions +TAGS = { + 347: "JPEGTables", + 700: "XMP", + # Additional Exif Info + 32932: "Wang Annotation", + 33434: "ExposureTime", + 33437: "FNumber", + 33445: "MD FileTag", + 33446: "MD ScalePixel", + 33447: "MD ColorTable", + 33448: "MD LabName", + 33449: "MD SampleInfo", + 33450: "MD PrepDate", + 33451: "MD PrepTime", + 33452: "MD FileUnits", + 33550: "ModelPixelScaleTag", + 33723: "IptcNaaInfo", + 33918: "INGR Packet Data Tag", + 33919: "INGR Flag Registers", + 33920: "IrasB Transformation Matrix", + 33922: "ModelTiepointTag", + 34264: "ModelTransformationTag", + 34377: "PhotoshopInfo", + 34735: "GeoKeyDirectoryTag", + 34736: "GeoDoubleParamsTag", + 34737: "GeoAsciiParamsTag", + 34850: "ExposureProgram", + 34852: "SpectralSensitivity", + 34855: "ISOSpeedRatings", + 34856: "OECF", + 34864: "SensitivityType", + 34865: "StandardOutputSensitivity", + 34866: "RecommendedExposureIndex", + 34867: "ISOSpeed", + 34868: "ISOSpeedLatitudeyyy", + 34869: "ISOSpeedLatitudezzz", + 34908: "HylaFAX FaxRecvParams", + 34909: "HylaFAX FaxSubAddress", + 34910: "HylaFAX FaxRecvTime", + 36864: "ExifVersion", + 36867: "DateTimeOriginal", + 36868: "DateTimeDigitized", + 37121: "ComponentsConfiguration", + 37122: "CompressedBitsPerPixel", + 37724: "ImageSourceData", + 37377: "ShutterSpeedValue", + 37378: "ApertureValue", + 37379: "BrightnessValue", + 37380: "ExposureBiasValue", + 37381: "MaxApertureValue", + 37382: "SubjectDistance", + 37383: "MeteringMode", + 37384: "LightSource", + 37385: "Flash", + 37386: "FocalLength", + 37396: "SubjectArea", + 37500: "MakerNote", + 37510: "UserComment", + 37520: "SubSec", + 37521: "SubSecTimeOriginal", + 37522: "SubsecTimeDigitized", + 40960: "FlashPixVersion", + 40961: "ColorSpace", + 40962: "PixelXDimension", + 40963: "PixelYDimension", + 40964: "RelatedSoundFile", + 40965: "InteroperabilityIFD", + 41483: "FlashEnergy", + 41484: "SpatialFrequencyResponse", + 41486: "FocalPlaneXResolution", + 41487: "FocalPlaneYResolution", + 41488: "FocalPlaneResolutionUnit", + 41492: "SubjectLocation", + 41493: "ExposureIndex", + 41495: "SensingMethod", + 41728: "FileSource", + 41729: "SceneType", + 41730: "CFAPattern", + 41985: "CustomRendered", + 41986: "ExposureMode", + 41987: "WhiteBalance", + 41988: "DigitalZoomRatio", + 41989: "FocalLengthIn35mmFilm", + 41990: "SceneCaptureType", + 41991: "GainControl", + 41992: "Contrast", + 41993: "Saturation", + 41994: "Sharpness", + 41995: "DeviceSettingDescription", + 41996: "SubjectDistanceRange", + 42016: "ImageUniqueID", + 42032: "CameraOwnerName", + 42033: "BodySerialNumber", + 42034: "LensSpecification", + 42035: "LensMake", + 42036: "LensModel", + 42037: "LensSerialNumber", + 42112: "GDAL_METADATA", + 42113: "GDAL_NODATA", + 42240: "Gamma", + 50215: "Oce Scanjob Description", + 50216: "Oce Application Selector", + 50217: "Oce Identification Number", + 50218: "Oce ImageLogic Characteristics", + # Adobe DNG + 50706: "DNGVersion", + 50707: "DNGBackwardVersion", + 50708: "UniqueCameraModel", + 50709: "LocalizedCameraModel", + 50710: "CFAPlaneColor", + 50711: "CFALayout", + 50712: "LinearizationTable", + 50713: "BlackLevelRepeatDim", + 50714: "BlackLevel", + 50715: "BlackLevelDeltaH", + 50716: "BlackLevelDeltaV", + 50717: "WhiteLevel", + 50718: "DefaultScale", + 50719: "DefaultCropOrigin", + 50720: "DefaultCropSize", + 50721: "ColorMatrix1", + 50722: "ColorMatrix2", + 50723: "CameraCalibration1", + 50724: "CameraCalibration2", + 50725: "ReductionMatrix1", + 50726: "ReductionMatrix2", + 50727: "AnalogBalance", + 50728: "AsShotNeutral", + 50729: "AsShotWhiteXY", + 50730: "BaselineExposure", + 50731: "BaselineNoise", + 50732: "BaselineSharpness", + 50733: "BayerGreenSplit", + 50734: "LinearResponseLimit", + 50735: "CameraSerialNumber", + 50736: "LensInfo", + 50737: "ChromaBlurRadius", + 50738: "AntiAliasStrength", + 50740: "DNGPrivateData", + 50778: "CalibrationIlluminant1", + 50779: "CalibrationIlluminant2", + 50784: "Alias Layer Metadata", +} + +TAGS_V2: dict[int, TagInfo] = {} + + +def _populate(): + for k, v in _tags_v2.items(): + # Populate legacy structure. + TAGS[k] = v[0] + if len(v) == 4: + for sk, sv in v[3].items(): + TAGS[(k, sv)] = sk + + TAGS_V2[k] = TagInfo(k, *v) + + for tags in TAGS_V2_GROUPS.values(): + for k, v in tags.items(): + tags[k] = TagInfo(k, *v) + + +_populate() +## +# Map type numbers to type names -- defined in ImageFileDirectory. + +TYPES: dict[int, str] = {} + +# +# These tags are handled by default in libtiff, without +# adding to the custom dictionary. From tif_dir.c, searching for +# case TIFFTAG in the _TIFFVSetField function: +# Line: item. +# 148: case TIFFTAG_SUBFILETYPE: +# 151: case TIFFTAG_IMAGEWIDTH: +# 154: case TIFFTAG_IMAGELENGTH: +# 157: case TIFFTAG_BITSPERSAMPLE: +# 181: case TIFFTAG_COMPRESSION: +# 202: case TIFFTAG_PHOTOMETRIC: +# 205: case TIFFTAG_THRESHHOLDING: +# 208: case TIFFTAG_FILLORDER: +# 214: case TIFFTAG_ORIENTATION: +# 221: case TIFFTAG_SAMPLESPERPIXEL: +# 228: case TIFFTAG_ROWSPERSTRIP: +# 238: case TIFFTAG_MINSAMPLEVALUE: +# 241: case TIFFTAG_MAXSAMPLEVALUE: +# 244: case TIFFTAG_SMINSAMPLEVALUE: +# 247: case TIFFTAG_SMAXSAMPLEVALUE: +# 250: case TIFFTAG_XRESOLUTION: +# 256: case TIFFTAG_YRESOLUTION: +# 262: case TIFFTAG_PLANARCONFIG: +# 268: case TIFFTAG_XPOSITION: +# 271: case TIFFTAG_YPOSITION: +# 274: case TIFFTAG_RESOLUTIONUNIT: +# 280: case TIFFTAG_PAGENUMBER: +# 284: case TIFFTAG_HALFTONEHINTS: +# 288: case TIFFTAG_COLORMAP: +# 294: case TIFFTAG_EXTRASAMPLES: +# 298: case TIFFTAG_MATTEING: +# 305: case TIFFTAG_TILEWIDTH: +# 316: case TIFFTAG_TILELENGTH: +# 327: case TIFFTAG_TILEDEPTH: +# 333: case TIFFTAG_DATATYPE: +# 344: case TIFFTAG_SAMPLEFORMAT: +# 361: case TIFFTAG_IMAGEDEPTH: +# 364: case TIFFTAG_SUBIFD: +# 376: case TIFFTAG_YCBCRPOSITIONING: +# 379: case TIFFTAG_YCBCRSUBSAMPLING: +# 383: case TIFFTAG_TRANSFERFUNCTION: +# 389: case TIFFTAG_REFERENCEBLACKWHITE: +# 393: case TIFFTAG_INKNAMES: + +# Following pseudo-tags are also handled by default in libtiff: +# TIFFTAG_JPEGQUALITY 65537 + +# some of these are not in our TAGS_V2 dict and were included from tiff.h + +# This list also exists in encode.c +LIBTIFF_CORE = { + 255, + 256, + 257, + 258, + 259, + 262, + 263, + 266, + 274, + 277, + 278, + 280, + 281, + 340, + 341, + 282, + 283, + 284, + 286, + 287, + 296, + 297, + 321, + 320, + 338, + 32995, + 322, + 323, + 32998, + 32996, + 339, + 32997, + 330, + 531, + 530, + 301, + 532, + 333, + # as above + 269, # this has been in our tests forever, and works + 65537, +} + +LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes +LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff +LIBTIFF_CORE.remove(323) # Tiled images +LIBTIFF_CORE.remove(333) # Ink Names either + +# Note to advanced users: There may be combinations of these +# parameters and values that when added properly, will work and +# produce valid tiff images that may work in your application. +# It is safe to add and remove tags from this set from Pillow's point +# of view so long as you test against libtiff. diff --git a/.venv/lib/python3.12/site-packages/PIL/WalImageFile.py b/.venv/lib/python3.12/site-packages/PIL/WalImageFile.py new file mode 100644 index 0000000..fbd7be6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/WalImageFile.py @@ -0,0 +1,124 @@ +# +# The Python Imaging Library. +# $Id$ +# +# WAL file handling +# +# History: +# 2003-04-23 fl created +# +# Copyright (c) 2003 by Fredrik Lundh. +# +# See the README file for information on usage and redistribution. +# + +""" +This reader is based on the specification available from: +https://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml +and has been tested with a few sample files found using google. + +.. note:: + This format cannot be automatically recognized, so the reader + is not registered for use with :py:func:`PIL.Image.open()`. + To open a WAL file, use the :py:func:`PIL.WalImageFile.open()` function instead. +""" +from __future__ import annotations + +from . import Image, ImageFile +from ._binary import i32le as i32 + + +class WalImageFile(ImageFile.ImageFile): + format = "WAL" + format_description = "Quake2 Texture" + + def _open(self) -> None: + self._mode = "P" + + # read header fields + header = self.fp.read(32 + 24 + 32 + 12) + self._size = i32(header, 32), i32(header, 36) + Image._decompression_bomb_check(self.size) + + # load pixel data + offset = i32(header, 40) + self.fp.seek(offset) + + # strings are null-terminated + self.info["name"] = header[:32].split(b"\0", 1)[0] + next_name = header[56 : 56 + 32].split(b"\0", 1)[0] + if next_name: + self.info["next_name"] = next_name + + def load(self): + if not self.im: + self.im = Image.core.new(self.mode, self.size) + self.frombytes(self.fp.read(self.size[0] * self.size[1])) + self.putpalette(quake2palette) + return Image.Image.load(self) + + +def open(filename): + """ + Load texture from a Quake2 WAL texture file. + + By default, a Quake2 standard palette is attached to the texture. + To override the palette, use the :py:func:`PIL.Image.Image.putpalette()` method. + + :param filename: WAL file name, or an opened file handle. + :returns: An image instance. + """ + return WalImageFile(filename) + + +quake2palette = ( + # default palette taken from piffo 0.93 by Hans Häggström + b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e" + b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f" + b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c" + b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b" + b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10" + b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07" + b"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f" + b"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16" + b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d" + b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31" + b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28" + b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07" + b"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27" + b"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b" + b"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01" + b"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21" + b"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14" + b"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07" + b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14" + b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f" + b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34" + b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d" + b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14" + b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01" + b"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24" + b"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10" + b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01" + b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27" + b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c" + b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a" + b"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26" + b"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d" + b"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01" + b"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20" + b"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17" + b"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07" + b"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25" + b"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c" + b"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01" + b"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23" + b"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f" + b"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b" + b"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37" + b"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b" + b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01" + b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10" + b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b" + b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20" +) diff --git a/.venv/lib/python3.12/site-packages/PIL/WebPImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/WebPImagePlugin.py new file mode 100644 index 0000000..59be5bf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/WebPImagePlugin.py @@ -0,0 +1,363 @@ +from __future__ import annotations + +from io import BytesIO +from typing import IO, Any + +from . import Image, ImageFile + +try: + from . import _webp + + SUPPORTED = True +except ImportError: + SUPPORTED = False + + +_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True} + +_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True} + +_VP8_MODES_BY_IDENTIFIER = { + b"VP8 ": "RGB", + b"VP8X": "RGBA", + b"VP8L": "RGBA", # lossless +} + + +def _accept(prefix: bytes) -> bool | str: + is_riff_file_format = prefix[:4] == b"RIFF" + is_webp_file = prefix[8:12] == b"WEBP" + is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER + + if is_riff_file_format and is_webp_file and is_valid_vp8_mode: + if not SUPPORTED: + return ( + "image file could not be identified because WEBP support not installed" + ) + return True + return False + + +class WebPImageFile(ImageFile.ImageFile): + format = "WEBP" + format_description = "WebP image" + __loaded = 0 + __logical_frame = 0 + + def _open(self) -> None: + if not _webp.HAVE_WEBPANIM: + # Legacy mode + data, width, height, self._mode, icc_profile, exif = _webp.WebPDecode( + self.fp.read() + ) + if icc_profile: + self.info["icc_profile"] = icc_profile + if exif: + self.info["exif"] = exif + self._size = width, height + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + self.n_frames = 1 + self.is_animated = False + return + + # Use the newer AnimDecoder API to parse the (possibly) animated file, + # and access muxed chunks like ICC/EXIF/XMP. + self._decoder = _webp.WebPAnimDecoder(self.fp.read()) + + # Get info from decoder + width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info() + self._size = width, height + self.info["loop"] = loop_count + bg_a, bg_r, bg_g, bg_b = ( + (bgcolor >> 24) & 0xFF, + (bgcolor >> 16) & 0xFF, + (bgcolor >> 8) & 0xFF, + bgcolor & 0xFF, + ) + self.info["background"] = (bg_r, bg_g, bg_b, bg_a) + self.n_frames = frame_count + self.is_animated = self.n_frames > 1 + self._mode = "RGB" if mode == "RGBX" else mode + self.rawmode = mode + self.tile = [] + + # Attempt to read ICC / EXIF / XMP chunks from file + icc_profile = self._decoder.get_chunk("ICCP") + exif = self._decoder.get_chunk("EXIF") + xmp = self._decoder.get_chunk("XMP ") + if icc_profile: + self.info["icc_profile"] = icc_profile + if exif: + self.info["exif"] = exif + if xmp: + self.info["xmp"] = xmp + + # Initialize seek state + self._reset(reset=False) + + def _getexif(self) -> dict[str, Any] | None: + if "exif" not in self.info: + return None + return self.getexif()._get_merged_dict() + + def seek(self, frame: int) -> None: + if not self._seek_check(frame): + return + + # Set logical frame to requested position + self.__logical_frame = frame + + def _reset(self, reset: bool = True) -> None: + if reset: + self._decoder.reset() + self.__physical_frame = 0 + self.__loaded = -1 + self.__timestamp = 0 + + def _get_next(self): + # Get next frame + ret = self._decoder.get_next() + self.__physical_frame += 1 + + # Check if an error occurred + if ret is None: + self._reset() # Reset just to be safe + self.seek(0) + msg = "failed to decode next frame in WebP file" + raise EOFError(msg) + + # Compute duration + data, timestamp = ret + duration = timestamp - self.__timestamp + self.__timestamp = timestamp + + # libwebp gives frame end, adjust to start of frame + timestamp -= duration + return data, timestamp, duration + + def _seek(self, frame: int) -> None: + if self.__physical_frame == frame: + return # Nothing to do + if frame < self.__physical_frame: + self._reset() # Rewind to beginning + while self.__physical_frame < frame: + self._get_next() # Advance to the requested frame + + def load(self): + if _webp.HAVE_WEBPANIM: + if self.__loaded != self.__logical_frame: + self._seek(self.__logical_frame) + + # We need to load the image data for this frame + data, timestamp, duration = self._get_next() + self.info["timestamp"] = timestamp + self.info["duration"] = duration + self.__loaded = self.__logical_frame + + # Set tile + if self.fp and self._exclusive_fp: + self.fp.close() + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)] + + return super().load() + + def load_seek(self, pos: int) -> None: + pass + + def tell(self) -> int: + if not _webp.HAVE_WEBPANIM: + return super().tell() + + return self.__logical_frame + + +def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + encoderinfo = im.encoderinfo.copy() + append_images = list(encoderinfo.get("append_images", [])) + + # If total frame count is 1, then save using the legacy API, which + # will preserve non-alpha modes + total = 0 + for ims in [im] + append_images: + total += getattr(ims, "n_frames", 1) + if total == 1: + _save(im, fp, filename) + return + + background: int | tuple[int, ...] = (0, 0, 0, 0) + if "background" in encoderinfo: + background = encoderinfo["background"] + elif "background" in im.info: + background = im.info["background"] + if isinstance(background, int): + # GifImagePlugin stores a global color table index in + # info["background"]. So it must be converted to an RGBA value + palette = im.getpalette() + if palette: + r, g, b = palette[background * 3 : (background + 1) * 3] + background = (r, g, b, 255) + else: + background = (background, background, background, 255) + + duration = im.encoderinfo.get("duration", im.info.get("duration", 0)) + loop = im.encoderinfo.get("loop", 0) + minimize_size = im.encoderinfo.get("minimize_size", False) + kmin = im.encoderinfo.get("kmin", None) + kmax = im.encoderinfo.get("kmax", None) + allow_mixed = im.encoderinfo.get("allow_mixed", False) + verbose = False + lossless = im.encoderinfo.get("lossless", False) + quality = im.encoderinfo.get("quality", 80) + alpha_quality = im.encoderinfo.get("alpha_quality", 100) + method = im.encoderinfo.get("method", 0) + icc_profile = im.encoderinfo.get("icc_profile") or "" + exif = im.encoderinfo.get("exif", "") + if isinstance(exif, Image.Exif): + exif = exif.tobytes() + xmp = im.encoderinfo.get("xmp", "") + if allow_mixed: + lossless = False + + # Sensible keyframe defaults are from gif2webp.c script + if kmin is None: + kmin = 9 if lossless else 3 + if kmax is None: + kmax = 17 if lossless else 5 + + # Validate background color + if ( + not isinstance(background, (list, tuple)) + or len(background) != 4 + or not all(0 <= v < 256 for v in background) + ): + msg = f"Background color is not an RGBA tuple clamped to (0-255): {background}" + raise OSError(msg) + + # Convert to packed uint + bg_r, bg_g, bg_b, bg_a = background + background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0) + + # Setup the WebP animation encoder + enc = _webp.WebPAnimEncoder( + im.size[0], + im.size[1], + background, + loop, + minimize_size, + kmin, + kmax, + allow_mixed, + verbose, + ) + + # Add each frame + frame_idx = 0 + timestamp = 0 + cur_idx = im.tell() + try: + for ims in [im] + append_images: + # Get # of frames in this image + nfr = getattr(ims, "n_frames", 1) + + for idx in range(nfr): + ims.seek(idx) + ims.load() + + # Make sure image mode is supported + frame = ims + rawmode = ims.mode + if ims.mode not in _VALID_WEBP_MODES: + alpha = ( + "A" in ims.mode + or "a" in ims.mode + or (ims.mode == "P" and "A" in ims.im.getpalettemode()) + ) + rawmode = "RGBA" if alpha else "RGB" + frame = ims.convert(rawmode) + + if rawmode == "RGB": + # For faster conversion, use RGBX + rawmode = "RGBX" + + # Append the frame to the animation encoder + enc.add( + frame.tobytes("raw", rawmode), + round(timestamp), + frame.size[0], + frame.size[1], + rawmode, + lossless, + quality, + alpha_quality, + method, + ) + + # Update timestamp and frame index + if isinstance(duration, (list, tuple)): + timestamp += duration[frame_idx] + else: + timestamp += duration + frame_idx += 1 + + finally: + im.seek(cur_idx) + + # Force encoder to flush frames + enc.add(None, round(timestamp), 0, 0, "", lossless, quality, alpha_quality, 0) + + # Get the final output from the encoder + data = enc.assemble(icc_profile, exif, xmp) + if data is None: + msg = "cannot write file as WebP (encoder returned None)" + raise OSError(msg) + + fp.write(data) + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + lossless = im.encoderinfo.get("lossless", False) + quality = im.encoderinfo.get("quality", 80) + alpha_quality = im.encoderinfo.get("alpha_quality", 100) + icc_profile = im.encoderinfo.get("icc_profile") or "" + exif = im.encoderinfo.get("exif", b"") + if isinstance(exif, Image.Exif): + exif = exif.tobytes() + if exif.startswith(b"Exif\x00\x00"): + exif = exif[6:] + xmp = im.encoderinfo.get("xmp", "") + method = im.encoderinfo.get("method", 4) + exact = 1 if im.encoderinfo.get("exact") else 0 + + if im.mode not in _VALID_WEBP_LEGACY_MODES: + im = im.convert("RGBA" if im.has_transparency_data else "RGB") + + data = _webp.WebPEncode( + im.tobytes(), + im.size[0], + im.size[1], + lossless, + float(quality), + float(alpha_quality), + im.mode, + icc_profile, + method, + exact, + exif, + xmp, + ) + if data is None: + msg = "cannot write file as WebP (encoder returned None)" + raise OSError(msg) + + fp.write(data) + + +Image.register_open(WebPImageFile.format, WebPImageFile, _accept) +if SUPPORTED: + Image.register_save(WebPImageFile.format, _save) + if _webp.HAVE_WEBPANIM: + Image.register_save_all(WebPImageFile.format, _save_all) + Image.register_extension(WebPImageFile.format, ".webp") + Image.register_mime(WebPImageFile.format, "image/webp") diff --git a/.venv/lib/python3.12/site-packages/PIL/WmfImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/WmfImagePlugin.py new file mode 100644 index 0000000..3d5cddc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/WmfImagePlugin.py @@ -0,0 +1,181 @@ +# +# The Python Imaging Library +# $Id$ +# +# WMF stub codec +# +# history: +# 1996-12-14 fl Created +# 2004-02-22 fl Turned into a stub driver +# 2004-02-23 fl Added EMF support +# +# Copyright (c) Secret Labs AB 1997-2004. All rights reserved. +# Copyright (c) Fredrik Lundh 1996. +# +# See the README file for information on usage and redistribution. +# +# WMF/EMF reference documentation: +# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf +# http://wvware.sourceforge.net/caolan/index.html +# http://wvware.sourceforge.net/caolan/ora-wmf.html +from __future__ import annotations + +from typing import IO + +from . import Image, ImageFile +from ._binary import i16le as word +from ._binary import si16le as short +from ._binary import si32le as _long + +_handler = None + + +def register_handler(handler: ImageFile.StubHandler | None) -> None: + """ + Install application-specific WMF image handler. + + :param handler: Handler object. + """ + global _handler + _handler = handler + + +if hasattr(Image.core, "drawwmf"): + # install default handler (windows only) + + class WmfHandler(ImageFile.StubHandler): + def open(self, im: ImageFile.StubImageFile) -> None: + im._mode = "RGB" + self.bbox = im.info["wmf_bbox"] + + def load(self, im: ImageFile.StubImageFile) -> Image.Image: + im.fp.seek(0) # rewind + return Image.frombytes( + "RGB", + im.size, + Image.core.drawwmf(im.fp.read(), im.size, self.bbox), + "raw", + "BGR", + (im.size[0] * 3 + 3) & -4, + -1, + ) + + register_handler(WmfHandler()) + +# +# -------------------------------------------------------------------- +# Read WMF file + + +def _accept(prefix: bytes) -> bool: + return ( + prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00" + ) + + +## +# Image plugin for Windows metafiles. + + +class WmfStubImageFile(ImageFile.StubImageFile): + format = "WMF" + format_description = "Windows Metafile" + + def _open(self) -> None: + self._inch = None + + # check placable header + s = self.fp.read(80) + + if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00": + # placeable windows metafile + + # get units per inch + self._inch = word(s, 14) + + # get bounding box + x0 = short(s, 6) + y0 = short(s, 8) + x1 = short(s, 10) + y1 = short(s, 12) + + # normalize size to 72 dots per inch + self.info["dpi"] = 72 + size = ( + (x1 - x0) * self.info["dpi"] // self._inch, + (y1 - y0) * self.info["dpi"] // self._inch, + ) + + self.info["wmf_bbox"] = x0, y0, x1, y1 + + # sanity check (standard metafile header) + if s[22:26] != b"\x01\x00\t\x00": + msg = "Unsupported WMF file format" + raise SyntaxError(msg) + + elif s[:4] == b"\x01\x00\x00\x00" and s[40:44] == b" EMF": + # enhanced metafile + + # get bounding box + x0 = _long(s, 8) + y0 = _long(s, 12) + x1 = _long(s, 16) + y1 = _long(s, 20) + + # get frame (in 0.01 millimeter units) + frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36) + + size = x1 - x0, y1 - y0 + + # calculate dots per inch from bbox and frame + xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0]) + ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1]) + + self.info["wmf_bbox"] = x0, y0, x1, y1 + + if xdpi == ydpi: + self.info["dpi"] = xdpi + else: + self.info["dpi"] = xdpi, ydpi + + else: + msg = "Unsupported file format" + raise SyntaxError(msg) + + self._mode = "RGB" + self._size = size + + loader = self._load() + if loader: + loader.open(self) + + def _load(self) -> ImageFile.StubHandler | None: + return _handler + + def load(self, dpi=None): + if dpi is not None and self._inch is not None: + self.info["dpi"] = dpi + x0, y0, x1, y1 = self.info["wmf_bbox"] + self._size = ( + (x1 - x0) * self.info["dpi"] // self._inch, + (y1 - y0) * self.info["dpi"] // self._inch, + ) + return super().load() + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if _handler is None or not hasattr(_handler, "save"): + msg = "WMF save handler not installed" + raise OSError(msg) + _handler.save(im, fp, filename) + + +# +# -------------------------------------------------------------------- +# Registry stuff + + +Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept) +Image.register_save(WmfStubImageFile.format, _save) + +Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"]) diff --git a/.venv/lib/python3.12/site-packages/PIL/XVThumbImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/XVThumbImagePlugin.py new file mode 100644 index 0000000..c84adac --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/XVThumbImagePlugin.py @@ -0,0 +1,81 @@ +# +# The Python Imaging Library. +# $Id$ +# +# XV Thumbnail file handler by Charles E. "Gene" Cash +# (gcash@magicnet.net) +# +# see xvcolor.c and xvbrowse.c in the sources to John Bradley's XV, +# available from ftp://ftp.cis.upenn.edu/pub/xv/ +# +# history: +# 98-08-15 cec created (b/w only) +# 98-12-09 cec added color palette +# 98-12-28 fl added to PIL (with only a few very minor modifications) +# +# To do: +# FIXME: make save work (this requires quantization support) +# +from __future__ import annotations + +from . import Image, ImageFile, ImagePalette +from ._binary import o8 + +_MAGIC = b"P7 332" + +# standard color palette for thumbnails (RGB332) +PALETTE = b"" +for r in range(8): + for g in range(8): + for b in range(4): + PALETTE = PALETTE + ( + o8((r * 255) // 7) + o8((g * 255) // 7) + o8((b * 255) // 3) + ) + + +def _accept(prefix: bytes) -> bool: + return prefix[:6] == _MAGIC + + +## +# Image plugin for XV thumbnail images. + + +class XVThumbImageFile(ImageFile.ImageFile): + format = "XVThumb" + format_description = "XV thumbnail image" + + def _open(self) -> None: + # check magic + assert self.fp is not None + + if not _accept(self.fp.read(6)): + msg = "not an XV thumbnail file" + raise SyntaxError(msg) + + # Skip to beginning of next line + self.fp.readline() + + # skip info comments + while True: + s = self.fp.readline() + if not s: + msg = "Unexpected EOF reading XV thumbnail file" + raise SyntaxError(msg) + if s[0] != 35: # ie. when not a comment: '#' + break + + # parse header line (already read) + s = s.strip().split() + + self._mode = "P" + self._size = int(s[0]), int(s[1]) + + self.palette = ImagePalette.raw("RGB", PALETTE) + + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))] + + +# -------------------------------------------------------------------- + +Image.register_open(XVThumbImageFile.format, XVThumbImageFile, _accept) diff --git a/.venv/lib/python3.12/site-packages/PIL/XbmImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/XbmImagePlugin.py new file mode 100644 index 0000000..6d11bbf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/XbmImagePlugin.py @@ -0,0 +1,98 @@ +# +# The Python Imaging Library. +# $Id$ +# +# XBM File handling +# +# History: +# 1995-09-08 fl Created +# 1996-11-01 fl Added save support +# 1997-07-07 fl Made header parser more tolerant +# 1997-07-22 fl Fixed yet another parser bug +# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4) +# 2001-05-13 fl Added hotspot handling (based on code from Bernhard Herzog) +# 2004-02-24 fl Allow some whitespace before first #define +# +# Copyright (c) 1997-2004 by Secret Labs AB +# Copyright (c) 1996-1997 by Fredrik Lundh +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import re +from typing import IO + +from . import Image, ImageFile + +# XBM header +xbm_head = re.compile( + rb"\s*#define[ \t]+.*_width[ \t]+(?P[0-9]+)[\r\n]+" + b"#define[ \t]+.*_height[ \t]+(?P[0-9]+)[\r\n]+" + b"(?P" + b"#define[ \t]+[^_]*_x_hot[ \t]+(?P[0-9]+)[\r\n]+" + b"#define[ \t]+[^_]*_y_hot[ \t]+(?P[0-9]+)[\r\n]+" + b")?" + rb"[\000-\377]*_bits\[]" +) + + +def _accept(prefix: bytes) -> bool: + return prefix.lstrip()[:7] == b"#define" + + +## +# Image plugin for X11 bitmaps. + + +class XbmImageFile(ImageFile.ImageFile): + format = "XBM" + format_description = "X11 Bitmap" + + def _open(self) -> None: + assert self.fp is not None + + m = xbm_head.match(self.fp.read(512)) + + if not m: + msg = "not a XBM file" + raise SyntaxError(msg) + + xsize = int(m.group("width")) + ysize = int(m.group("height")) + + if m.group("hotspot"): + self.info["hotspot"] = (int(m.group("xhot")), int(m.group("yhot"))) + + self._mode = "1" + self._size = xsize, ysize + + self.tile = [("xbm", (0, 0) + self.size, m.end(), None)] + + +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + if im.mode != "1": + msg = f"cannot write mode {im.mode} as XBM" + raise OSError(msg) + + fp.write(f"#define im_width {im.size[0]}\n".encode("ascii")) + fp.write(f"#define im_height {im.size[1]}\n".encode("ascii")) + + hotspot = im.encoderinfo.get("hotspot") + if hotspot: + fp.write(f"#define im_x_hot {hotspot[0]}\n".encode("ascii")) + fp.write(f"#define im_y_hot {hotspot[1]}\n".encode("ascii")) + + fp.write(b"static char im_bits[] = {\n") + + ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)]) + + fp.write(b"};\n") + + +Image.register_open(XbmImageFile.format, XbmImageFile, _accept) +Image.register_save(XbmImageFile.format, _save) + +Image.register_extension(XbmImageFile.format, ".xbm") + +Image.register_mime(XbmImageFile.format, "image/xbm") diff --git a/.venv/lib/python3.12/site-packages/PIL/XpmImagePlugin.py b/.venv/lib/python3.12/site-packages/PIL/XpmImagePlugin.py new file mode 100644 index 0000000..8d56331 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/XpmImagePlugin.py @@ -0,0 +1,125 @@ +# +# The Python Imaging Library. +# $Id$ +# +# XPM File handling +# +# History: +# 1996-12-29 fl Created +# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7) +# +# Copyright (c) Secret Labs AB 1997-2001. +# Copyright (c) Fredrik Lundh 1996-2001. +# +# See the README file for information on usage and redistribution. +# +from __future__ import annotations + +import re + +from . import Image, ImageFile, ImagePalette +from ._binary import o8 + +# XPM header +xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)') + + +def _accept(prefix: bytes) -> bool: + return prefix[:9] == b"/* XPM */" + + +## +# Image plugin for X11 pixel maps. + + +class XpmImageFile(ImageFile.ImageFile): + format = "XPM" + format_description = "X11 Pixel Map" + + def _open(self) -> None: + if not _accept(self.fp.read(9)): + msg = "not an XPM file" + raise SyntaxError(msg) + + # skip forward to next string + while True: + s = self.fp.readline() + if not s: + msg = "broken XPM file" + raise SyntaxError(msg) + m = xpm_head.match(s) + if m: + break + + self._size = int(m.group(1)), int(m.group(2)) + + pal = int(m.group(3)) + bpp = int(m.group(4)) + + if pal > 256 or bpp != 1: + msg = "cannot read this XPM file" + raise ValueError(msg) + + # + # load palette description + + palette = [b"\0\0\0"] * 256 + + for _ in range(pal): + s = self.fp.readline() + if s[-2:] == b"\r\n": + s = s[:-2] + elif s[-1:] in b"\r\n": + s = s[:-1] + + c = s[1] + s = s[2:-2].split() + + for i in range(0, len(s), 2): + if s[i] == b"c": + # process colour key + rgb = s[i + 1] + if rgb == b"None": + self.info["transparency"] = c + elif rgb[:1] == b"#": + # FIXME: handle colour names (see ImagePalette.py) + rgb = int(rgb[1:], 16) + palette[c] = ( + o8((rgb >> 16) & 255) + o8((rgb >> 8) & 255) + o8(rgb & 255) + ) + else: + # unknown colour + msg = "cannot read this XPM file" + raise ValueError(msg) + break + + else: + # missing colour key + msg = "cannot read this XPM file" + raise ValueError(msg) + + self._mode = "P" + self.palette = ImagePalette.raw("RGB", b"".join(palette)) + + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))] + + def load_read(self, read_bytes: int) -> bytes: + # + # load all image data in one chunk + + xsize, ysize = self.size + + s = [self.fp.readline()[1 : xsize + 1].ljust(xsize) for i in range(ysize)] + + return b"".join(s) + + +# +# Registry + + +Image.register_open(XpmImageFile.format, XpmImageFile, _accept) + +Image.register_extension(XpmImageFile.format, ".xpm") + +Image.register_mime(XpmImageFile.format, "image/xpm") diff --git a/.venv/lib/python3.12/site-packages/PIL/__init__.py b/.venv/lib/python3.12/site-packages/PIL/__init__.py new file mode 100644 index 0000000..09546fe --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/__init__.py @@ -0,0 +1,86 @@ +"""Pillow (Fork of the Python Imaging Library) + +Pillow is the friendly PIL fork by Jeffrey A. Clark and contributors. + https://github.com/python-pillow/Pillow/ + +Pillow is forked from PIL 1.1.7. + +PIL is the Python Imaging Library by Fredrik Lundh and contributors. +Copyright (c) 1999 by Secret Labs AB. + +Use PIL.__version__ for this Pillow version. + +;-) +""" + +from __future__ import annotations + +from . import _version + +# VERSION was removed in Pillow 6.0.0. +# PILLOW_VERSION was removed in Pillow 9.0.0. +# Use __version__ instead. +__version__ = _version.__version__ +del _version + + +_plugins = [ + "BlpImagePlugin", + "BmpImagePlugin", + "BufrStubImagePlugin", + "CurImagePlugin", + "DcxImagePlugin", + "DdsImagePlugin", + "EpsImagePlugin", + "FitsImagePlugin", + "FliImagePlugin", + "FpxImagePlugin", + "FtexImagePlugin", + "GbrImagePlugin", + "GifImagePlugin", + "GribStubImagePlugin", + "Hdf5StubImagePlugin", + "IcnsImagePlugin", + "IcoImagePlugin", + "ImImagePlugin", + "ImtImagePlugin", + "IptcImagePlugin", + "JpegImagePlugin", + "Jpeg2KImagePlugin", + "McIdasImagePlugin", + "MicImagePlugin", + "MpegImagePlugin", + "MpoImagePlugin", + "MspImagePlugin", + "PalmImagePlugin", + "PcdImagePlugin", + "PcxImagePlugin", + "PdfImagePlugin", + "PixarImagePlugin", + "PngImagePlugin", + "PpmImagePlugin", + "PsdImagePlugin", + "QoiImagePlugin", + "SgiImagePlugin", + "SpiderImagePlugin", + "SunImagePlugin", + "TgaImagePlugin", + "TiffImagePlugin", + "WebPImagePlugin", + "WmfImagePlugin", + "XbmImagePlugin", + "XpmImagePlugin", + "XVThumbImagePlugin", +] + + +class UnidentifiedImageError(OSError): + """ + Raised in :py:meth:`PIL.Image.open` if an image cannot be opened and identified. + + If a PNG image raises this error, setting :data:`.ImageFile.LOAD_TRUNCATED_IMAGES` + to true may allow the image to be opened after all. The setting will ignore missing + data and checksum failures. + """ + + pass diff --git a/.venv/lib/python3.12/site-packages/PIL/__main__.py b/.venv/lib/python3.12/site-packages/PIL/__main__.py new file mode 100644 index 0000000..043156e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/__main__.py @@ -0,0 +1,7 @@ +from __future__ import annotations + +import sys + +from .features import pilinfo + +pilinfo(supported_formats="--report" not in sys.argv) diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc new file mode 100644 index 0000000..f9a5a59 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..681ce91 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..4521b7c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..345deac Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc new file mode 100644 index 0000000..b2dec63 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..d09436b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..6a10219 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..ae51b6f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..9259c66 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc new file mode 100644 index 0000000..a053ed0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..e00522e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..1614ae5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc new file mode 100644 index 0000000..c6c6b03 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..0d4a52b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..1e70aa4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..5cbb78f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc new file mode 100644 index 0000000..d6f71fe Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..f69ea26 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc new file mode 100644 index 0000000..90443c3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc new file mode 100644 index 0000000..08fa3b7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..1073c5a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..d886427 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..5838900 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..cab7ccb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..56e08b1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/Image.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Image.cpython-312.pyc new file mode 100644 index 0000000..1e67cb4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Image.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc new file mode 100644 index 0000000..32f9e41 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc new file mode 100644 index 0000000..712751f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc new file mode 100644 index 0000000..3508e41 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc new file mode 100644 index 0000000..420ae94 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc new file mode 100644 index 0000000..f898450 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc new file mode 100644 index 0000000..11cefdc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc new file mode 100644 index 0000000..ad98d09 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc new file mode 100644 index 0000000..b678fa4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc new file mode 100644 index 0000000..52f5346 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc new file mode 100644 index 0000000..e0b8e32 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc new file mode 100644 index 0000000..18f8e9e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc new file mode 100644 index 0000000..0d40afc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc new file mode 100644 index 0000000..54a8c88 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc new file mode 100644 index 0000000..657beb3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc new file mode 100644 index 0000000..a5a77f6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc new file mode 100644 index 0000000..f27ef55 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc new file mode 100644 index 0000000..9a7b8ef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc new file mode 100644 index 0000000..4e975d6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc new file mode 100644 index 0000000..8677ce3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc new file mode 100644 index 0000000..1854115 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc new file mode 100644 index 0000000..6bfab13 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc new file mode 100644 index 0000000..9f795d3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc new file mode 100644 index 0000000..644dbaf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..b4deb00 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..e71b466 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..23338a3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..a935429 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc new file mode 100644 index 0000000..5c99c6a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..ea27e7e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..fdd3a23 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..7eef6c6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..5d06ee5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..629888f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc new file mode 100644 index 0000000..7800ea9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc new file mode 100644 index 0000000..047f0ce Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..36a27ea Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..f1e7dd7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc new file mode 100644 index 0000000..df248cb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..1d38af5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..9fa0442 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc new file mode 100644 index 0000000..ec38f29 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..ee2435d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..0d3c350 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..946d3aa Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..ca50feb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc new file mode 100644 index 0000000..629c769 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..2839aae Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..cf82dd5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..84aa921 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..f03b25a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc new file mode 100644 index 0000000..0f9d90c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..ffca7e3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..1e1e9bb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc new file mode 100644 index 0000000..befe113 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc new file mode 100644 index 0000000..2cb3630 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..0100422 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..107cb66 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..4aa0eef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..3057a86 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc new file mode 100644 index 0000000..c200cdb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4328040 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..8b1bed9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/__main__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_binary.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_binary.cpython-312.pyc new file mode 100644 index 0000000..b5a98b5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_binary.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc new file mode 100644 index 0000000..90aa385 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc new file mode 100644 index 0000000..cce4199 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_typing.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_typing.cpython-312.pyc new file mode 100644 index 0000000..46faac8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_typing.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_util.cpython-312.pyc new file mode 100644 index 0000000..6c6caef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_util.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/_version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_version.cpython-312.pyc new file mode 100644 index 0000000..cdc58fc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/_version.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/features.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/features.cpython-312.pyc new file mode 100644 index 0000000..41d057a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/features.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/__pycache__/report.cpython-312.pyc b/.venv/lib/python3.12/site-packages/PIL/__pycache__/report.cpython-312.pyc new file mode 100644 index 0000000..1163a99 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/__pycache__/report.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_binary.py b/.venv/lib/python3.12/site-packages/PIL/_binary.py new file mode 100644 index 0000000..4594ccc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_binary.py @@ -0,0 +1,112 @@ +# +# The Python Imaging Library. +# $Id$ +# +# Binary input/output support routines. +# +# Copyright (c) 1997-2003 by Secret Labs AB +# Copyright (c) 1995-2003 by Fredrik Lundh +# Copyright (c) 2012 by Brian Crowell +# +# See the README file for information on usage and redistribution. +# + + +"""Binary input/output support routines.""" +from __future__ import annotations + +from struct import pack, unpack_from + + +def i8(c: bytes) -> int: + return c[0] + + +def o8(i: int) -> bytes: + return bytes((i & 255,)) + + +# Input, le = little endian, be = big endian +def i16le(c: bytes, o: int = 0) -> int: + """ + Converts a 2-bytes (16 bits) string to an unsigned integer. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(" int: + """ + Converts a 2-bytes (16 bits) string to a signed integer. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(" int: + """ + Converts a 2-bytes (16 bits) string to a signed integer, big endian. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(">h", c, o)[0] + + +def i32le(c: bytes, o: int = 0) -> int: + """ + Converts a 4-bytes (32 bits) string to an unsigned integer. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(" int: + """ + Converts a 4-bytes (32 bits) string to a signed integer. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(" int: + """ + Converts a 4-bytes (32 bits) string to a signed integer, big endian. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(">i", c, o)[0] + + +def i16be(c: bytes, o: int = 0) -> int: + return unpack_from(">H", c, o)[0] + + +def i32be(c: bytes, o: int = 0) -> int: + return unpack_from(">I", c, o)[0] + + +# Output, le = little endian, be = big endian +def o16le(i: int) -> bytes: + return pack(" bytes: + return pack(" bytes: + return pack(">H", i) + + +def o32be(i: int) -> bytes: + return pack(">I", i) diff --git a/.venv/lib/python3.12/site-packages/PIL/_deprecate.py b/.venv/lib/python3.12/site-packages/PIL/_deprecate.py new file mode 100644 index 0000000..33a0e07 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_deprecate.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +import warnings + +from . import __version__ + + +def deprecate( + deprecated: str, + when: int | None, + replacement: str | None = None, + *, + action: str | None = None, + plural: bool = False, +) -> None: + """ + Deprecations helper. + + :param deprecated: Name of thing to be deprecated. + :param when: Pillow major version to be removed in. + :param replacement: Name of replacement. + :param action: Instead of "replacement", give a custom call to action + e.g. "Upgrade to new thing". + :param plural: if the deprecated thing is plural, needing "are" instead of "is". + + Usually of the form: + + "[deprecated] is deprecated and will be removed in Pillow [when] (yyyy-mm-dd). + Use [replacement] instead." + + You can leave out the replacement sentence: + + "[deprecated] is deprecated and will be removed in Pillow [when] (yyyy-mm-dd)" + + Or with another call to action: + + "[deprecated] is deprecated and will be removed in Pillow [when] (yyyy-mm-dd). + [action]." + """ + + is_ = "are" if plural else "is" + + if when is None: + removed = "a future version" + elif when <= int(__version__.split(".")[0]): + msg = f"{deprecated} {is_} deprecated and should be removed." + raise RuntimeError(msg) + elif when == 11: + removed = "Pillow 11 (2024-10-15)" + elif when == 12: + removed = "Pillow 12 (2025-10-15)" + else: + msg = f"Unknown removal version: {when}. Update {__name__}?" + raise ValueError(msg) + + if replacement and action: + msg = "Use only one of 'replacement' and 'action'" + raise ValueError(msg) + + if replacement: + action = f". Use {replacement} instead." + elif action: + action = f". {action.rstrip('.')}." + else: + action = "" + + warnings.warn( + f"{deprecated} {is_} deprecated and will be removed in {removed}{action}", + DeprecationWarning, + stacklevel=3, + ) diff --git a/.venv/lib/python3.12/site-packages/PIL/_imaging.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imaging.cpython-312-darwin.so new file mode 100755 index 0000000..d1f66ba Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imaging.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_imaging.pyi b/.venv/lib/python3.12/site-packages/PIL/_imaging.pyi new file mode 100644 index 0000000..8cccd3a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_imaging.pyi @@ -0,0 +1,30 @@ +from typing import Any + +class ImagingCore: + def __getattr__(self, name: str) -> Any: ... + +class ImagingFont: + def __getattr__(self, name: str) -> Any: ... + +class ImagingDraw: + def __getattr__(self, name: str) -> Any: ... + +class PixelAccess: + def __getitem__(self, xy: tuple[int, int]) -> float | tuple[int, ...]: ... + def __setitem__( + self, xy: tuple[int, int], color: float | tuple[int, ...] + ) -> None: ... + +class ImagingDecoder: + def __getattr__(self, name: str) -> Any: ... + +class ImagingEncoder: + def __getattr__(self, name: str) -> Any: ... + +class _Outline: + def close(self) -> None: ... + def __getattr__(self, name: str) -> Any: ... + +def font(image: ImagingCore, glyphdata: bytes) -> ImagingFont: ... +def outline() -> _Outline: ... +def __getattr__(name: str) -> Any: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingcms.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imagingcms.cpython-312-darwin.so new file mode 100755 index 0000000..15b1186 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imagingcms.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingcms.pyi b/.venv/lib/python3.12/site-packages/PIL/_imagingcms.pyi new file mode 100644 index 0000000..2abd6d0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_imagingcms.pyi @@ -0,0 +1,141 @@ +import datetime +import sys +from typing import Literal, SupportsFloat, TypedDict + +littlecms_version: str | None + +_Tuple3f = tuple[float, float, float] +_Tuple2x3f = tuple[_Tuple3f, _Tuple3f] +_Tuple3x3f = tuple[_Tuple3f, _Tuple3f, _Tuple3f] + +class _IccMeasurementCondition(TypedDict): + observer: int + backing: _Tuple3f + geo: str + flare: float + illuminant_type: str + +class _IccViewingCondition(TypedDict): + illuminant: _Tuple3f + surround: _Tuple3f + illuminant_type: str + +class CmsProfile: + @property + def rendering_intent(self) -> int: ... + @property + def creation_date(self) -> datetime.datetime | None: ... + @property + def copyright(self) -> str | None: ... + @property + def target(self) -> str | None: ... + @property + def manufacturer(self) -> str | None: ... + @property + def model(self) -> str | None: ... + @property + def profile_description(self) -> str | None: ... + @property + def screening_description(self) -> str | None: ... + @property + def viewing_condition(self) -> str | None: ... + @property + def version(self) -> float: ... + @property + def icc_version(self) -> int: ... + @property + def attributes(self) -> int: ... + @property + def header_flags(self) -> int: ... + @property + def header_manufacturer(self) -> str: ... + @property + def header_model(self) -> str: ... + @property + def device_class(self) -> str: ... + @property + def connection_space(self) -> str: ... + @property + def xcolor_space(self) -> str: ... + @property + def profile_id(self) -> bytes: ... + @property + def is_matrix_shaper(self) -> bool: ... + @property + def technology(self) -> str | None: ... + @property + def colorimetric_intent(self) -> str | None: ... + @property + def perceptual_rendering_intent_gamut(self) -> str | None: ... + @property + def saturation_rendering_intent_gamut(self) -> str | None: ... + @property + def red_colorant(self) -> _Tuple2x3f | None: ... + @property + def green_colorant(self) -> _Tuple2x3f | None: ... + @property + def blue_colorant(self) -> _Tuple2x3f | None: ... + @property + def red_primary(self) -> _Tuple2x3f | None: ... + @property + def green_primary(self) -> _Tuple2x3f | None: ... + @property + def blue_primary(self) -> _Tuple2x3f | None: ... + @property + def media_white_point_temperature(self) -> float | None: ... + @property + def media_white_point(self) -> _Tuple2x3f | None: ... + @property + def media_black_point(self) -> _Tuple2x3f | None: ... + @property + def luminance(self) -> _Tuple2x3f | None: ... + @property + def chromatic_adaptation(self) -> tuple[_Tuple3x3f, _Tuple3x3f] | None: ... + @property + def chromaticity(self) -> _Tuple3x3f | None: ... + @property + def colorant_table(self) -> list[str] | None: ... + @property + def colorant_table_out(self) -> list[str] | None: ... + @property + def intent_supported(self) -> dict[int, tuple[bool, bool, bool]] | None: ... + @property + def clut(self) -> dict[int, tuple[bool, bool, bool]] | None: ... + @property + def icc_measurement_condition(self) -> _IccMeasurementCondition | None: ... + @property + def icc_viewing_condition(self) -> _IccViewingCondition | None: ... + def is_intent_supported(self, intent: int, direction: int, /) -> int: ... + +class CmsTransform: + def apply(self, id_in: int, id_out: int) -> int: ... + +def profile_open(profile: str, /) -> CmsProfile: ... +def profile_frombytes(profile: bytes, /) -> CmsProfile: ... +def profile_tobytes(profile: CmsProfile, /) -> bytes: ... +def buildTransform( + input_profile: CmsProfile, + output_profile: CmsProfile, + in_mode: str, + out_mode: str, + rendering_intent: int = 0, + cms_flags: int = 0, + /, +) -> CmsTransform: ... +def buildProofTransform( + input_profile: CmsProfile, + output_profile: CmsProfile, + proof_profile: CmsProfile, + in_mode: str, + out_mode: str, + rendering_intent: int = 0, + proof_intent: int = 0, + cms_flags: int = 0, + /, +) -> CmsTransform: ... +def createProfile( + color_space: Literal["LAB", "XYZ", "sRGB"], color_temp: SupportsFloat = 0.0, / +) -> CmsProfile: ... + +if sys.platform == "win32": + def get_display_profile_win32(handle: int = 0, is_dc: int = 0, /) -> str | None: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingft.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imagingft.cpython-312-darwin.so new file mode 100755 index 0000000..336ffd1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imagingft.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingft.pyi b/.venv/lib/python3.12/site-packages/PIL/_imagingft.pyi new file mode 100644 index 0000000..5e97b40 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_imagingft.pyi @@ -0,0 +1,69 @@ +from typing import Any, TypedDict + +from . import _imaging + +class _Axis(TypedDict): + minimum: int | None + default: int | None + maximum: int | None + name: bytes | None + +class Font: + @property + def family(self) -> str | None: ... + @property + def style(self) -> str | None: ... + @property + def ascent(self) -> int: ... + @property + def descent(self) -> int: ... + @property + def height(self) -> int: ... + @property + def x_ppem(self) -> int: ... + @property + def y_ppem(self) -> int: ... + @property + def glyphs(self) -> int: ... + def render( + self, + string: str | bytes, + fill, + mode=..., + dir=..., + features=..., + lang=..., + stroke_width=..., + anchor=..., + foreground_ink_long=..., + x_start=..., + y_start=..., + /, + ) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ... + def getsize( + self, + string: str | bytes | bytearray, + mode=..., + dir=..., + features=..., + lang=..., + anchor=..., + /, + ) -> tuple[tuple[int, int], tuple[int, int]]: ... + def getlength( + self, string: str | bytes, mode=..., dir=..., features=..., lang=..., / + ) -> float: ... + def getvarnames(self) -> list[bytes]: ... + def getvaraxes(self) -> list[_Axis] | None: ... + def setvarname(self, instance_index: int, /) -> None: ... + def setvaraxes(self, axes: list[float], /) -> None: ... + +def getfont( + filename: str | bytes, + size: float, + index=..., + encoding=..., + font_bytes=..., + layout_engine=..., +) -> Font: ... +def __getattr__(name: str) -> Any: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingmath.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imagingmath.cpython-312-darwin.so new file mode 100755 index 0000000..a272e87 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imagingmath.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingmath.pyi b/.venv/lib/python3.12/site-packages/PIL/_imagingmath.pyi new file mode 100644 index 0000000..e27843e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_imagingmath.pyi @@ -0,0 +1,3 @@ +from typing import Any + +def __getattr__(name: str) -> Any: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.cpython-312-darwin.so new file mode 100755 index 0000000..c664495 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.pyi b/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.pyi new file mode 100644 index 0000000..e27843e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_imagingmorph.pyi @@ -0,0 +1,3 @@ +from typing import Any + +def __getattr__(name: str) -> Any: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/_imagingtk.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_imagingtk.cpython-312-darwin.so new file mode 100755 index 0000000..9ee873d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_imagingtk.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_tkinter_finder.py b/.venv/lib/python3.12/site-packages/PIL/_tkinter_finder.py new file mode 100644 index 0000000..beddfb0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_tkinter_finder.py @@ -0,0 +1,21 @@ +""" Find compiled module linking to Tcl / Tk libraries +""" + +from __future__ import annotations + +import sys +import tkinter + +tk = getattr(tkinter, "_tkinter") + +try: + if hasattr(sys, "pypy_find_executable"): + TKINTER_LIB = tk.tklib_cffi.__file__ + else: + TKINTER_LIB = tk.__file__ +except AttributeError: + # _tkinter may be compiled directly into Python, in which case __file__ is + # not available. load_tkinter_funcs will check the binary first in any case. + TKINTER_LIB = None + +tk_version = str(tkinter.TkVersion) diff --git a/.venv/lib/python3.12/site-packages/PIL/_typing.py b/.venv/lib/python3.12/site-packages/PIL/_typing.py new file mode 100644 index 0000000..09ece18 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_typing.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import os +import sys +from typing import Any, Protocol, Sequence, TypeVar, Union + +try: + import numpy.typing as npt + + NumpyArray = npt.NDArray[Any] +except ImportError: + pass + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + try: + from typing_extensions import TypeGuard + except ImportError: + + class TypeGuard: # type: ignore[no-redef] + def __class_getitem__(cls, item: Any) -> type[bool]: + return bool + + +Coords = Union[Sequence[float], Sequence[Sequence[float]]] + + +_T_co = TypeVar("_T_co", covariant=True) + + +class SupportsRead(Protocol[_T_co]): + def read(self, __length: int = ...) -> _T_co: ... + + +StrOrBytesPath = Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"] + + +__all__ = ["TypeGuard", "StrOrBytesPath", "SupportsRead"] diff --git a/.venv/lib/python3.12/site-packages/PIL/_util.py b/.venv/lib/python3.12/site-packages/PIL/_util.py new file mode 100644 index 0000000..6bc7628 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_util.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import os +from typing import Any, NoReturn + +from ._typing import StrOrBytesPath, TypeGuard + + +def is_path(f: Any) -> TypeGuard[StrOrBytesPath]: + return isinstance(f, (bytes, str, os.PathLike)) + + +def is_directory(f: Any) -> TypeGuard[StrOrBytesPath]: + """Checks if an object is a string, and that it points to a directory.""" + return is_path(f) and os.path.isdir(f) + + +class DeferredError: + def __init__(self, ex: BaseException): + self.ex = ex + + def __getattr__(self, elt: str) -> NoReturn: + raise self.ex + + @staticmethod + def new(ex: BaseException) -> Any: + """ + Creates an object that raises the wrapped exception ``ex`` when used, + and casts it to :py:obj:`~typing.Any` type. + """ + return DeferredError(ex) diff --git a/.venv/lib/python3.12/site-packages/PIL/_version.py b/.venv/lib/python3.12/site-packages/PIL/_version.py new file mode 100644 index 0000000..cebfd86 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_version.py @@ -0,0 +1,4 @@ +# Master version for Pillow +from __future__ import annotations + +__version__ = "10.4.0" diff --git a/.venv/lib/python3.12/site-packages/PIL/_webp.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/PIL/_webp.cpython-312-darwin.so new file mode 100755 index 0000000..e5da313 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/PIL/_webp.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/PIL/_webp.pyi b/.venv/lib/python3.12/site-packages/PIL/_webp.pyi new file mode 100644 index 0000000..e27843e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/_webp.pyi @@ -0,0 +1,3 @@ +from typing import Any + +def __getattr__(name: str) -> Any: ... diff --git a/.venv/lib/python3.12/site-packages/PIL/features.py b/.venv/lib/python3.12/site-packages/PIL/features.py new file mode 100644 index 0000000..13908c4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/features.py @@ -0,0 +1,340 @@ +from __future__ import annotations + +import collections +import os +import sys +import warnings +from typing import IO + +import PIL + +from . import Image + +modules = { + "pil": ("PIL._imaging", "PILLOW_VERSION"), + "tkinter": ("PIL._tkinter_finder", "tk_version"), + "freetype2": ("PIL._imagingft", "freetype2_version"), + "littlecms2": ("PIL._imagingcms", "littlecms_version"), + "webp": ("PIL._webp", "webpdecoder_version"), +} + + +def check_module(feature: str) -> bool: + """ + Checks if a module is available. + + :param feature: The module to check for. + :returns: ``True`` if available, ``False`` otherwise. + :raises ValueError: If the module is not defined in this version of Pillow. + """ + if feature not in modules: + msg = f"Unknown module {feature}" + raise ValueError(msg) + + module, ver = modules[feature] + + try: + __import__(module) + return True + except ModuleNotFoundError: + return False + except ImportError as ex: + warnings.warn(str(ex)) + return False + + +def version_module(feature: str) -> str | None: + """ + :param feature: The module to check for. + :returns: + The loaded version number as a string, or ``None`` if unknown or not available. + :raises ValueError: If the module is not defined in this version of Pillow. + """ + if not check_module(feature): + return None + + module, ver = modules[feature] + + return getattr(__import__(module, fromlist=[ver]), ver) + + +def get_supported_modules() -> list[str]: + """ + :returns: A list of all supported modules. + """ + return [f for f in modules if check_module(f)] + + +codecs = { + "jpg": ("jpeg", "jpeglib"), + "jpg_2000": ("jpeg2k", "jp2klib"), + "zlib": ("zip", "zlib"), + "libtiff": ("libtiff", "libtiff"), +} + + +def check_codec(feature: str) -> bool: + """ + Checks if a codec is available. + + :param feature: The codec to check for. + :returns: ``True`` if available, ``False`` otherwise. + :raises ValueError: If the codec is not defined in this version of Pillow. + """ + if feature not in codecs: + msg = f"Unknown codec {feature}" + raise ValueError(msg) + + codec, lib = codecs[feature] + + return f"{codec}_encoder" in dir(Image.core) + + +def version_codec(feature: str) -> str | None: + """ + :param feature: The codec to check for. + :returns: + The version number as a string, or ``None`` if not available. + Checked at compile time for ``jpg``, run-time otherwise. + :raises ValueError: If the codec is not defined in this version of Pillow. + """ + if not check_codec(feature): + return None + + codec, lib = codecs[feature] + + version = getattr(Image.core, f"{lib}_version") + + if feature == "libtiff": + return version.split("\n")[0].split("Version ")[1] + + return version + + +def get_supported_codecs() -> list[str]: + """ + :returns: A list of all supported codecs. + """ + return [f for f in codecs if check_codec(f)] + + +features = { + "webp_anim": ("PIL._webp", "HAVE_WEBPANIM", None), + "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), + "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), + "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), + "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"), + "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"), + "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), + "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), + "xcb": ("PIL._imaging", "HAVE_XCB", None), +} + + +def check_feature(feature: str) -> bool | None: + """ + Checks if a feature is available. + + :param feature: The feature to check for. + :returns: ``True`` if available, ``False`` if unavailable, ``None`` if unknown. + :raises ValueError: If the feature is not defined in this version of Pillow. + """ + if feature not in features: + msg = f"Unknown feature {feature}" + raise ValueError(msg) + + module, flag, ver = features[feature] + + try: + imported_module = __import__(module, fromlist=["PIL"]) + return getattr(imported_module, flag) + except ModuleNotFoundError: + return None + except ImportError as ex: + warnings.warn(str(ex)) + return None + + +def version_feature(feature: str) -> str | None: + """ + :param feature: The feature to check for. + :returns: The version number as a string, or ``None`` if not available. + :raises ValueError: If the feature is not defined in this version of Pillow. + """ + if not check_feature(feature): + return None + + module, flag, ver = features[feature] + + if ver is None: + return None + + return getattr(__import__(module, fromlist=[ver]), ver) + + +def get_supported_features() -> list[str]: + """ + :returns: A list of all supported features. + """ + return [f for f in features if check_feature(f)] + + +def check(feature: str) -> bool | None: + """ + :param feature: A module, codec, or feature name. + :returns: + ``True`` if the module, codec, or feature is available, + ``False`` or ``None`` otherwise. + """ + + if feature in modules: + return check_module(feature) + if feature in codecs: + return check_codec(feature) + if feature in features: + return check_feature(feature) + warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2) + return False + + +def version(feature: str) -> str | None: + """ + :param feature: + The module, codec, or feature to check for. + :returns: + The version number as a string, or ``None`` if unknown or not available. + """ + if feature in modules: + return version_module(feature) + if feature in codecs: + return version_codec(feature) + if feature in features: + return version_feature(feature) + return None + + +def get_supported() -> list[str]: + """ + :returns: A list of all supported modules, features, and codecs. + """ + + ret = get_supported_modules() + ret.extend(get_supported_features()) + ret.extend(get_supported_codecs()) + return ret + + +def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: + """ + Prints information about this installation of Pillow. + This function can be called with ``python3 -m PIL``. + It can also be called with ``python3 -m PIL.report`` or ``python3 -m PIL --report`` + to have "supported_formats" set to ``False``, omitting the list of all supported + image file formats. + + :param out: + The output stream to print to. Defaults to ``sys.stdout`` if ``None``. + :param supported_formats: + If ``True``, a list of all supported image file formats will be printed. + """ + + if out is None: + out = sys.stdout + + Image.init() + + print("-" * 68, file=out) + print(f"Pillow {PIL.__version__}", file=out) + py_version_lines = sys.version.splitlines() + print(f"Python {py_version_lines[0].strip()}", file=out) + for py_version in py_version_lines[1:]: + print(f" {py_version.strip()}", file=out) + print("-" * 68, file=out) + print(f"Python executable is {sys.executable or 'unknown'}", file=out) + if sys.prefix != sys.base_prefix: + print(f"Environment Python files loaded from {sys.prefix}", file=out) + print(f"System Python files loaded from {sys.base_prefix}", file=out) + print("-" * 68, file=out) + print( + f"Python Pillow modules loaded from {os.path.dirname(Image.__file__)}", + file=out, + ) + print( + f"Binary Pillow modules loaded from {os.path.dirname(Image.core.__file__)}", + file=out, + ) + print("-" * 68, file=out) + + for name, feature in [ + ("pil", "PIL CORE"), + ("tkinter", "TKINTER"), + ("freetype2", "FREETYPE2"), + ("littlecms2", "LITTLECMS2"), + ("webp", "WEBP"), + ("transp_webp", "WEBP Transparency"), + ("webp_mux", "WEBPMUX"), + ("webp_anim", "WEBP Animation"), + ("jpg", "JPEG"), + ("jpg_2000", "OPENJPEG (JPEG2000)"), + ("zlib", "ZLIB (PNG/ZIP)"), + ("libtiff", "LIBTIFF"), + ("raqm", "RAQM (Bidirectional Text)"), + ("libimagequant", "LIBIMAGEQUANT (Quantization method)"), + ("xcb", "XCB (X protocol)"), + ]: + if check(name): + v: str | None = None + if name == "jpg": + libjpeg_turbo_version = version_feature("libjpeg_turbo") + if libjpeg_turbo_version is not None: + v = "libjpeg-turbo " + libjpeg_turbo_version + if v is None: + v = version(name) + if v is not None: + version_static = name in ("pil", "jpg") + if name == "littlecms2": + # this check is also in src/_imagingcms.c:setup_module() + version_static = tuple(int(x) for x in v.split(".")) < (2, 7) + t = "compiled for" if version_static else "loaded" + if name == "raqm": + for f in ("fribidi", "harfbuzz"): + v2 = version_feature(f) + if v2 is not None: + v += f", {f} {v2}" + print("---", feature, "support ok,", t, v, file=out) + else: + print("---", feature, "support ok", file=out) + else: + print("***", feature, "support not installed", file=out) + print("-" * 68, file=out) + + if supported_formats: + extensions = collections.defaultdict(list) + for ext, i in Image.EXTENSION.items(): + extensions[i].append(ext) + + for i in sorted(Image.ID): + line = f"{i}" + if i in Image.MIME: + line = f"{line} {Image.MIME[i]}" + print(line, file=out) + + if i in extensions: + print( + "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out + ) + + features = [] + if i in Image.OPEN: + features.append("open") + if i in Image.SAVE: + features.append("save") + if i in Image.SAVE_ALL: + features.append("save_all") + if i in Image.DECODERS: + features.append("decode") + if i in Image.ENCODERS: + features.append("encode") + + print("Features: {}".format(", ".join(features)), file=out) + print("-" * 68, file=out) diff --git a/.venv/lib/python3.12/site-packages/PIL/py.typed b/.venv/lib/python3.12/site-packages/PIL/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/PIL/report.py b/.venv/lib/python3.12/site-packages/PIL/report.py new file mode 100644 index 0000000..d2815e8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/PIL/report.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +from .features import pilinfo + +pilinfo(supported_formats=False) diff --git a/.venv/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc new file mode 100644 index 0000000..fbe010c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..79c9825 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2010 Jason Kirtland + +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. diff --git a/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA new file mode 100644 index 0000000..6d343f5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.3 +Name: blinker +Version: 1.9.0 +Summary: Fast, simple object-to-object and broadcast signaling +Author: Jason Kirtland +Maintainer-email: Pallets Ecosystem +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://blinker.readthedocs.io +Project-URL: Source, https://github.com/pallets-eco/blinker/ + +# Blinker + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + + +## Pallets Community Ecosystem + +> [!IMPORTANT]\ +> This project is part of the Pallets Community Ecosystem. Pallets is the open +> source organization that maintains Flask; Pallets-Eco enables community +> maintenance of related projects. If you are interested in helping maintain +> this project, please reach out on [the Pallets Discord server][discord]. +> +> [discord]: https://discord.gg/pallets + + +## Example + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + +```pycon +>>> from blinker import signal +>>> started = signal('round-started') +>>> def each(round): +... print(f"Round {round}") +... +>>> started.connect(each) + +>>> def round_two(round): +... print("This is round two.") +... +>>> started.connect(round_two, sender=2) + +>>> for round in range(1, 4): +... started.send(round) +... +Round 1! +Round 2! +This is round two. +Round 3! +``` + diff --git a/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD new file mode 100644 index 0000000..7cfb714 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD @@ -0,0 +1,12 @@ +blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 +blinker-1.9.0.dist-info/RECORD,, +blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 +blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 +blinker/__pycache__/__init__.cpython-312.pyc,, +blinker/__pycache__/_utilities.cpython-312.pyc,, +blinker/__pycache__/base.cpython-312.pyc,, +blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 +blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL new file mode 100644 index 0000000..e3c6fee --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.10.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.12/site-packages/blinker/__init__.py b/.venv/lib/python3.12/site-packages/blinker/__init__.py new file mode 100644 index 0000000..1772fa4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker/__init__.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from .base import ANY +from .base import default_namespace +from .base import NamedSignal +from .base import Namespace +from .base import Signal +from .base import signal + +__all__ = [ + "ANY", + "default_namespace", + "NamedSignal", + "Namespace", + "Signal", + "signal", +] diff --git a/.venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..62dc505 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc b/.venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc new file mode 100644 index 0000000..58bb124 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000..44ce83a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/blinker/_utilities.py b/.venv/lib/python3.12/site-packages/blinker/_utilities.py new file mode 100644 index 0000000..000c902 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker/_utilities.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import collections.abc as c +import inspect +import typing as t +from weakref import ref +from weakref import WeakMethod + +T = t.TypeVar("T") + + +class Symbol: + """A constant symbol, nicer than ``object()``. Repeated calls return the + same instance. + + >>> Symbol('foo') is Symbol('foo') + True + >>> Symbol('foo') + foo + """ + + symbols: t.ClassVar[dict[str, Symbol]] = {} + + def __new__(cls, name: str) -> Symbol: + if name in cls.symbols: + return cls.symbols[name] + + obj = super().__new__(cls) + cls.symbols[name] = obj + return obj + + def __init__(self, name: str) -> None: + self.name = name + + def __repr__(self) -> str: + return self.name + + def __getnewargs__(self) -> tuple[t.Any, ...]: + return (self.name,) + + +def make_id(obj: object) -> c.Hashable: + """Get a stable identifier for a receiver or sender, to be used as a dict + key or in a set. + """ + if inspect.ismethod(obj): + # The id of a bound method is not stable, but the id of the unbound + # function and instance are. + return id(obj.__func__), id(obj.__self__) + + if isinstance(obj, (str, int)): + # Instances with the same value always compare equal and have the same + # hash, even if the id may change. + return obj + + # Assume other types are not hashable but will always be the same instance. + return id(obj) + + +def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: + if inspect.ismethod(obj): + return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] + + return ref(obj, callback) diff --git a/.venv/lib/python3.12/site-packages/blinker/base.py b/.venv/lib/python3.12/site-packages/blinker/base.py new file mode 100644 index 0000000..d051b94 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/blinker/base.py @@ -0,0 +1,512 @@ +from __future__ import annotations + +import collections.abc as c +import sys +import typing as t +import weakref +from collections import defaultdict +from contextlib import contextmanager +from functools import cached_property +from inspect import iscoroutinefunction + +from ._utilities import make_id +from ._utilities import make_ref +from ._utilities import Symbol + +F = t.TypeVar("F", bound=c.Callable[..., t.Any]) + +ANY = Symbol("ANY") +"""Symbol for "any sender".""" + +ANY_ID = 0 + + +class Signal: + """A notification emitter. + + :param doc: The docstring for the signal. + """ + + ANY = ANY + """An alias for the :data:`~blinker.ANY` sender symbol.""" + + set_class: type[set[t.Any]] = set + """The set class to use for tracking connected receivers and senders. + Python's ``set`` is unordered. If receivers must be dispatched in the order + they were connected, an ordered set implementation can be used. + + .. versionadded:: 1.7 + """ + + @cached_property + def receiver_connected(self) -> Signal: + """Emitted at the end of each :meth:`connect` call. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: ``receiver``, ``sender``, and ``weak``. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver connects.") + + @cached_property + def receiver_disconnected(self) -> Signal: + """Emitted at the end of each :meth:`disconnect` call. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: ``receiver`` and ``sender``. + + This signal is emitted **only** when :meth:`disconnect` is called + explicitly. This signal cannot be emitted by an automatic disconnect + when a weakly referenced receiver or sender goes out of scope, as the + instance is no longer be available to be used as the sender for this + signal. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc: str | None = None) -> None: + if doc: + self.__doc__ = doc + + self.receivers: dict[ + t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] + ] = {} + """The map of connected receivers. Useful to quickly check if any + receivers are connected to the signal: ``if s.receivers:``. The + structure and data is not part of the public API, but checking its + boolean value is. + """ + + self.is_muted: bool = False + self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} + + def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: + """Connect ``receiver`` to be called when the signal is sent by + ``sender``. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends. + """ + receiver_id = make_id(receiver) + sender_id = ANY_ID if sender is ANY else make_id(sender) + + if weak: + self.receivers[receiver_id] = make_ref( + receiver, self._make_cleanup_receiver(receiver_id) + ) + else: + self.receivers[receiver_id] = receiver + + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + + if sender is not ANY and sender_id not in self._weak_senders: + # store a cleanup for weakref-able senders + try: + self._weak_senders[sender_id] = make_ref( + sender, self._make_cleanup_sender(sender_id) + ) + except TypeError: + pass + + if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: + try: + self.receiver_connected.send( + self, receiver=receiver, sender=sender, weak=weak + ) + except TypeError: + # TODO no explanation or test for this + self.disconnect(receiver, sender) + raise + + return receiver + + def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: + """Connect the decorated function to be called when the signal is sent + by ``sender``. + + The decorated function will be called when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument along + with any extra keyword arguments. + + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends.= + + .. versionadded:: 1.1 + """ + + def decorator(fn: F) -> F: + self.connect(fn, sender, weak) + return fn + + return decorator + + @contextmanager + def connected_to( + self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY + ) -> c.Generator[None, None, None]: + """A context manager that temporarily connects ``receiver`` to the + signal while a ``with`` block executes. When the block exits, the + receiver is disconnected. Useful for tests. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. + + .. versionadded:: 1.1 + """ + self.connect(receiver, sender=sender, weak=False) + + try: + yield None + finally: + self.disconnect(receiver) + + @contextmanager + def muted(self) -> c.Generator[None, None, None]: + """A context manager that temporarily disables the signal. No receivers + will be called if the signal is sent, until the ``with`` block exits. + Useful for tests. + """ + self.is_muted = True + + try: + yield None + finally: + self.is_muted = False + + def send( + self, + sender: t.Any | None = None, + /, + *, + _async_wrapper: c.Callable[ + [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Call all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _async_wrapper: Will be called on any receivers that are async + coroutines to turn them into sync callables. For example, could run + the receiver with an event loop. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionchanged:: 1.7 + Added the ``_async_wrapper`` argument. + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if iscoroutinefunction(receiver): + if _async_wrapper is None: + raise RuntimeError("Cannot send to a coroutine function.") + + result = _async_wrapper(receiver)(sender, **kwargs) + else: + result = receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + async def send_async( + self, + sender: t.Any | None = None, + /, + *, + _sync_wrapper: c.Callable[ + [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Await all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _sync_wrapper: Will be called on any receivers that are sync + callables to turn them into async coroutines. For example, + could call the receiver in a thread. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionadded:: 1.7 + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if not iscoroutinefunction(receiver): + if _sync_wrapper is None: + raise RuntimeError("Cannot send to a non-coroutine function.") + + result = await _sync_wrapper(receiver)(sender, **kwargs) + else: + result = await receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + def has_receivers_for(self, sender: t.Any) -> bool: + """Check if there is at least one receiver that will be called with the + given ``sender``. A receiver connected to :data:`ANY` will always be + called, regardless of sender. Does not check if weakly referenced + receivers are still live. See :meth:`receivers_for` for a stronger + search. + + :param sender: Check for receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + if not self.receivers: + return False + + if self._by_sender[ANY_ID]: + return True + + if sender is ANY: + return False + + return make_id(sender) in self._by_sender + + def receivers_for( + self, sender: t.Any + ) -> c.Generator[c.Callable[..., t.Any], None, None]: + """Yield each receiver to be called for ``sender``, in addition to those + to be called for :data:`ANY`. Weakly referenced receivers that are not + live will be disconnected and skipped. + + :param sender: Yield receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + # TODO: test receivers_for(ANY) + if not self.receivers: + return + + sender_id = make_id(sender) + + if sender_id in self._by_sender: + ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] + else: + ids = self._by_sender[ANY_ID].copy() + + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + + if receiver is None: + continue + + if isinstance(receiver, weakref.ref): + strong = receiver() + + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + + yield strong + else: + yield receiver + + def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: + """Disconnect ``receiver`` from being called when the signal is sent by + ``sender``. + + :param receiver: A connected receiver callable. + :param sender: Disconnect from only this sender. By default, disconnect + from all senders. + """ + sender_id: c.Hashable + + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = make_id(sender) + + receiver_id = make_id(receiver) + self._disconnect(receiver_id, sender_id) + + if ( + "receiver_disconnected" in self.__dict__ + and self.receiver_disconnected.receivers + ): + self.receiver_disconnected.send(self, receiver=receiver, sender=sender) + + def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, None) is not None: + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _make_cleanup_receiver( + self, receiver_id: c.Hashable + ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: + """Create a callback function to disconnect a weakly referenced + receiver when it is garbage collected. + """ + + def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: + # If the interpreter is shutting down, disconnecting can result in a + # weird ignored exception. Don't call it in that case. + if not sys.is_finalizing(): + self._disconnect(receiver_id, ANY_ID) + + return cleanup + + def _make_cleanup_sender( + self, sender_id: c.Hashable + ) -> c.Callable[[weakref.ref[t.Any]], None]: + """Create a callback function to disconnect all receivers for a weakly + referenced sender when it is garbage collected. + """ + assert sender_id != ANY_ID + + def cleanup(ref: weakref.ref[t.Any]) -> None: + self._weak_senders.pop(sender_id, None) + + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + return cleanup + + def _cleanup_bookkeeping(self) -> None: + """Prune unused sender/receiver bookkeeping. Not threadsafe. + + Connecting & disconnecting leaves behind a small amount of bookkeeping + data. Typical workloads using Blinker, for example in most web apps, + Flask, CLI scripts, etc., are not adversely affected by this + bookkeeping. + + With a long-running process performing dynamic signal routing with high + volume, e.g. connecting to function closures, senders are all unique + object instances. Doing all of this over and over may cause memory usage + to grow due to extraneous bookkeeping. (An empty ``set`` for each stale + sender/receiver pair.) + + This method will prune that bookkeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that failure + mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for ident, bucket in list(mapping.items()): + if not bucket: + mapping.pop(ident, None) + + def _clear_state(self) -> None: + """Disconnect all receivers and senders. Useful for tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +class NamedSignal(Signal): + """A named generic notification emitter. The name is not used by the signal + itself, but matches the key in the :class:`Namespace` that it belongs to. + + :param name: The name of the signal within the namespace. + :param doc: The docstring for the signal. + """ + + def __init__(self, name: str, doc: str | None = None) -> None: + super().__init__(doc) + + #: The name of this signal. + self.name: str = name + + def __repr__(self) -> str: + base = super().__repr__() + return f"{base[:-1]}; {self.name!r}>" # noqa: E702 + + +class Namespace(dict[str, NamedSignal]): + """A dict mapping names to signals.""" + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` for the given ``name``, creating it + if required. Repeated calls with the same name return the same signal. + + :param name: The name of the signal. + :param doc: The docstring of the signal. + """ + if name not in self: + self[name] = NamedSignal(name, doc) + + return self[name] + + +class _PNamespaceSignal(t.Protocol): + def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... + + +default_namespace: Namespace = Namespace() +"""A default :class:`Namespace` for creating named signals. :func:`signal` +creates a :class:`NamedSignal` in this namespace. +""" + +signal: _PNamespaceSignal = default_namespace.signal +"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given +``name``, creating it if required. Repeated calls with the same name return the +same signal. +""" diff --git a/.venv/lib/python3.12/site-packages/blinker/py.typed b/.venv/lib/python3.12/site-packages/blinker/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/METADATA b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/METADATA new file mode 100644 index 0000000..3f433af --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/METADATA @@ -0,0 +1,84 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.3.1 +Summary: Composable command line interface toolkit +Maintainer-email: Pallets +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: colorama; platform_system == 'Windows' +Project-URL: Changes, https://click.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/click/ + +

+ +# Click + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +## A Simple Example + +```python +import click + +@click.command() +@click.option("--count", default=1, help="Number of greetings.") +@click.option("--name", prompt="Your name", help="The person to greet.") +def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + +if __name__ == '__main__': + hello() +``` + +``` +$ python hello.py --count=3 +Your name: Click +Hello, Click! +Hello, Click! +Hello, Click! +``` + + +## Donate + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/RECORD b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/RECORD new file mode 100644 index 0000000..77e5c98 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/RECORD @@ -0,0 +1,40 @@ +click-8.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.3.1.dist-info/METADATA,sha256=XZeBrMAE0ghTE88SjfrSDuSyNCpBPplxJR1tbwD9oZg,2621 +click-8.3.1.dist-info/RECORD,, +click-8.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.3.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 +click/__pycache__/__init__.cpython-312.pyc,, +click/__pycache__/_compat.cpython-312.pyc,, +click/__pycache__/_termui_impl.cpython-312.pyc,, +click/__pycache__/_textwrap.cpython-312.pyc,, +click/__pycache__/_utils.cpython-312.pyc,, +click/__pycache__/_winconsole.cpython-312.pyc,, +click/__pycache__/core.cpython-312.pyc,, +click/__pycache__/decorators.cpython-312.pyc,, +click/__pycache__/exceptions.cpython-312.pyc,, +click/__pycache__/formatting.cpython-312.pyc,, +click/__pycache__/globals.cpython-312.pyc,, +click/__pycache__/parser.cpython-312.pyc,, +click/__pycache__/shell_completion.cpython-312.pyc,, +click/__pycache__/termui.cpython-312.pyc,, +click/__pycache__/testing.cpython-312.pyc,, +click/__pycache__/types.cpython-312.pyc,, +click/__pycache__/utils.cpython-312.pyc,, +click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 +click/_termui_impl.py,sha256=rgCb3On8X5A4200rA5L6i13u5iapmFer7sru57Jy6zA,27093 +click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 +click/_utils.py,sha256=kZwtTf5gMuCilJJceS2iTCvRvCY-0aN5rJq8gKw7p8g,943 +click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 +click/core.py,sha256=U6Bfxt8GkjNDqyJ0HqXvluJHtyZ4sY5USAvM1Cdq7mQ,132105 +click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 +click/exceptions.py,sha256=8utf8w6V5hJXMnO_ic1FNrtbwuEn1NUu1aDwV8UqnG4,9954 +click/formatting.py,sha256=RVfwwr0rwWNpgGr8NaHodPzkIr7_tUyVh_nDdanLMNc,9730 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=Q31pH0FlQZEq-UXE_ABRzlygEfvxPTuZbWNh4xfXmzw,19010 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=Cc4GQUFuWpfQBa9sF5qXeeYI7n3tI_1k6ZdSn4BZbT0,20994 +click/termui.py,sha256=hqCEjNndU-nzW08nRAkBaVgfZp_FdCA9KxfIWlKYaMc,31037 +click/testing.py,sha256=EERbzcl1br0mW0qBS9EqkknfNfXB9WQEW0ELIpkvuSs,19102 +click/types.py,sha256=ek54BNSFwPKsqtfT7jsqcc4WHui8AIFVMKM4oVZIXhc,39927 +click/utils.py,sha256=gCUoewdAhA-QLBUUHxrLh4uj6m7T1WjZZMNPvR0I7YA,20257 diff --git a/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/lib/python3.12/site-packages/click/__init__.py b/.venv/lib/python3.12/site-packages/click/__init__.py new file mode 100644 index 0000000..1aa547c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/__init__.py @@ -0,0 +1,123 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" + +from __future__ import annotations + +from .core import Argument as Argument +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + from .core import _BaseCommand + + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + from .core import _MultiCommand + + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + if name == "OptionParser": + from .parser import _OptionParser + + warnings.warn( + "'OptionParser' is deprecated and will be removed in Click 9.0. The" + " old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return _OptionParser + + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Click 9.1. Use feature detection or" + " 'importlib.metadata.version(\"click\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("click") + + raise AttributeError(name) diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..cdad52d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc new file mode 100644 index 0000000..c2d06f2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc new file mode 100644 index 0000000..c5faec4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc new file mode 100644 index 0000000..7e9400f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/_utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/_utils.cpython-312.pyc new file mode 100644 index 0000000..bb104fe Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/_utils.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc new file mode 100644 index 0000000..c7ed669 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000..6c9554d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc new file mode 100644 index 0000000..e7a0f06 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000..42b17e1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc new file mode 100644 index 0000000..a7526e9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc new file mode 100644 index 0000000..9137423 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000..9926527 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc new file mode 100644 index 0000000..2ac3f6c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc new file mode 100644 index 0000000..6c67c7f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000..2cc1c2f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000..f38193a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000..fa6370a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/click/_compat.py b/.venv/lib/python3.12/site-packages/click/_compat.py new file mode 100644 index 0000000..f2726b9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/_compat.py @@ -0,0 +1,622 @@ +from __future__ import annotations + +import codecs +import collections.abc as cabc +import io +import os +import re +import sys +import typing as t +from types import TracebackType +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write(b"") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: str | None, errors: str | None +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: str | None, + errors: str | None, + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: str | os.PathLike[str] | int, + mode: str, + encoding: str | None, + errors: str | None, +) -> t.IO[t.Any]: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, +) -> tuple[t.IO[t.Any], bool]: + binary = "b" in mode + filename = os.fspath(filename) + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: int | None = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[t.Any], af), True + + +class _AtomicFile: + def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> _AtomicFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s: str) -> int: + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write # type: ignore[method-assign] + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None + ) -> t.TextIO | None: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO | None], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.TextIO | None]: + cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO | None: + stream = src_func() + + if stream is None: + return None + + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/.venv/lib/python3.12/site-packages/click/_termui_impl.py b/.venv/lib/python3.12/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..ee8225c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/_termui_impl.py @@ -0,0 +1,852 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" + +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import math +import os +import shlex +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +from pathlib import Path +from types import TracebackType + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: cabc.Iterable[V] | None, + length: int | None = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + label: str | None = None, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.hidden = hidden + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: str = label or "" + + if file is None: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + file = StringIO() + + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width: int = width + self.autowidth: bool = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast("cabc.Iterable[V]", range(length)) + self.iter: cabc.Iterable[V] = iter(iterable) + self.length = length + self.pos: int = 0 + self.avg: list[float] = [] + self.last_eta: float + self.start: float + self.start = self.last_eta = time.time() + self.eta_known: bool = False + self.finished: bool = False + self.max_width: int | None = None + self.entered: bool = False + self.current_item: V | None = None + self._is_atty = isatty(self.file) + self._last_line: str | None = None + + def __enter__(self) -> ProgressBar[V]: + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.render_finish() + + def __iter__(self) -> cabc.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.hidden or not self._is_atty: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + if self.hidden: + return + + if not self._is_atty: + # Only output the label once if the output is not a TTY. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + import shutil + + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width and self.max_width is not None: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: V | None = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> cabc.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if not self._is_atty: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: cabc.Iterable[str], color: bool | None = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if stdout is None: + stdout = StringIO() + + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + + # Split and normalize the pager command into parts. + pager_cmd_parts = shlex.split(os.environ.get("PAGER", ""), posix=False) + if pager_cmd_parts: + if WIN: + if _tempfilepager(generator, pager_cmd_parts, color): + return + elif _pipepager(generator, pager_cmd_parts, color): + return + + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if (WIN or sys.platform.startswith("os2")) and _tempfilepager( + generator, ["more"], color + ): + return + if _pipepager(generator, ["less"], color): + return + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if _pipepager(generator, ["more"], color): + return + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + cmd_params = cmd_parts[1:] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + + # Produces a normalized absolute path string. + # multi-call binaries such as busybox derive their identity from the symlink + # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) + cmd_path = Path(cmd_filepath).absolute() + cmd_name = cmd_path.name + + import subprocess + + # Make a local copy of the environment to not affect the global one. + env = dict(os.environ) + + # If we're piping to less and the user hasn't decided on colors, we enable + # them by default we find the -R flag in the command line arguments. + if color is None and cmd_name == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_params)}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen( + [str(cmd_path)] + cmd_params, + shell=False, + stdin=subprocess.PIPE, + env=env, + errors="replace", + text=True, + ) + assert c.stdin is not None + try: + for text in generator: + if not color: + text = strip_ansi(text) + + c.stdin.write(text) + except BrokenPipeError: + # In case the pager exited unexpectedly, ignore the broken pipe error. + pass + except Exception as e: + # In case there is an exception we want to close the pager immediately + # and let the caller handle it. + # Otherwise the pager will keep running, and the user may not notice + # the error message, or worse yet it may leave the terminal in a broken state. + c.terminate() + raise e + finally: + # We must close stdin and wait for the pager to exit before we continue + try: + c.stdin.close() + # Close implies flush, so it might throw a BrokenPipeError if the pager + # process exited already. + except BrokenPipeError: + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + return True + + +def _tempfilepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by invoking a program on a temporary file. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + # Produces a normalized absolute path string. + # multi-call binaries such as busybox derive their identity from the symlink + # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) + cmd_path = Path(cmd_filepath).absolute() + + import subprocess + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + subprocess.call([str(cmd_path), filename]) + except OSError: + # Command not found + pass + finally: + os.close(fd) + os.unlink(filename) + + return True + + +def _nullpager( + stream: t.TextIO, generator: cabc.Iterable[str], color: bool | None +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + + from shutil import which + + for editor in "sensible-editor", "vim", "nano": + if which(editor) is not None: + return editor + return "vi" + + def edit_files(self, filenames: cabc.Iterable[str]) -> None: + import subprocess + + editor = self.get_editor() + environ: dict[str, str] | None = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + exc_filename = " ".join(f'"{filename}"' for filename in filenames) + + try: + c = subprocess.Popen( + args=f"{editor} {exc_filename}", env=environ, shell=True + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + @t.overload + def edit(self, text: bytes | bytearray) -> bytes | None: ... + + # We cannot know whether or not the type expected is str or bytes when None + # is passed, so str is returned as that was what was done before. + @t.overload + def edit(self, text: str | None) -> str | None: ... + + def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: + import tempfile + + if text is None: + data: bytes | bytearray = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_files((name,)) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = ["explorer", f"/select,{url}"] + else: + args = ["start"] + if wait: + args.append("/WAIT") + args.append("") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> None: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if sys.platform == "win32": + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + + if echo: + func = t.cast(t.Callable[[], str], msvcrt.getwche) + else: + func = t.cast(t.Callable[[], str], msvcrt.getwch) + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import termios + import tty + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + f: t.TextIO | None + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/.venv/lib/python3.12/site-packages/click/_textwrap.py b/.venv/lib/python3.12/site-packages/click/_textwrap.py new file mode 100644 index 0000000..97fbee3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/_textwrap.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import collections.abc as cabc +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: list[str], + cur_line: list[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> cabc.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/.venv/lib/python3.12/site-packages/click/_utils.py b/.venv/lib/python3.12/site-packages/click/_utils.py new file mode 100644 index 0000000..09fb008 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/_utils.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import enum +import typing as t + + +class Sentinel(enum.Enum): + """Enum used to define sentinel values. + + .. seealso:: + + `PEP 661 - Sentinel Values `_. + """ + + UNSET = object() + FLAG_NEEDS_VALUE = object() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}.{self.name}" + + +UNSET = Sentinel.UNSET +"""Sentinel used to indicate that a value is not set.""" + +FLAG_NEEDS_VALUE = Sentinel.FLAG_NEEDS_VALUE +"""Sentinel used to indicate an option was passed as a flag without a +value but is not a flag option. + +``Option.consume_value`` uses this to prompt or use the ``flag_value``. +""" + +T_UNSET = t.Literal[UNSET] # type: ignore[valid-type] +"""Type hint for the :data:`UNSET` sentinel value.""" + +T_FLAG_NEEDS_VALUE = t.Literal[FLAG_NEEDS_VALUE] # type: ignore[valid-type] +"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/.venv/lib/python3.12/site-packages/click/_winconsole.py b/.venv/lib/python3.12/site-packages/click/_winconsole.py new file mode 100644 index 0000000..e56c7c6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/_winconsole.py @@ -0,0 +1,296 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +from __future__ import annotations + +import collections.abc as cabc +import io +import sys +import time +import typing as t +from ctypes import Array +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +if t.TYPE_CHECKING: + try: + # Using `typing_extensions.Buffer` instead of `collections.abc` + # on Windows for some reason does not have `Sized` implemented. + from collections.abc import Buffer # type: ignore + except ImportError: + from typing_extensions import Buffer + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ # noqa: RUF012 + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: + buf = Py_buffer() + flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + out: Array[c_char] = buffer_type.from_address(buf.buf) + return out + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle: int | None) -> None: + self.handle = handle + + def isatty(self) -> t.Literal[True]: + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self) -> t.Literal[True]: + return True + + def readinto(self, b: Buffer) -> int: + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self) -> t.Literal[True]: + return True + + @staticmethod + def _get_error_message(errno: int) -> str: + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b: Buffer) -> int: + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self) -> str: + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None +) -> t.TextIO | None: + if ( + get_buffer is None + or encoding not in {"utf-16-le", None} + or errors not in {"strict", None} + or not _is_console(f) + ): + return None + + func = _stream_factories.get(f.fileno()) + if func is None: + return None + + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/.venv/lib/python3.12/site-packages/click/core.py b/.venv/lib/python3.12/site-packages/click/core.py new file mode 100644 index 0000000..57f549c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/core.py @@ -0,0 +1,3415 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from collections import Counter +from contextlib import AbstractContextManager +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import NoArgsIsHelpError +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _OptionParser +from .parser import _split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound="t.Callable[..., t.Any]") +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: Context, incomplete: str +) -> cabc.Iterator[tuple[str, Command]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(Group, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_nested_chain( + base_command: Group, cmd_name: str, cmd: Command, register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, Group): + return + + if register: + message = ( + f"It is not possible to add the group {cmd_name!r} to another" + f" group {base_command.name!r} that is in chain mode." + ) + else: + message = ( + f"Found the group {cmd_name!r} as subcommand to another group " + f" {base_command.name!r} that is in chain mode. This is not supported." + ) + + raise RuntimeError(message) + + +def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size), strict=False)) + + +@contextmanager +def augment_usage_errors( + ctx: Context, param: Parameter | None = None +) -> cabc.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: cabc.Sequence[Parameter], + declaration_order: cabc.Sequence[Parameter], +) -> list[Parameter]: + """Returns all declared parameters in the order they should be processed. + + The declared parameters are re-shuffled depending on the order in which + they were invoked, as well as the eagerness of each parameters. + + The invocation order takes precedence over the declaration order. I.e. the + order in which the user provided them to the CLI is respected. + + This behavior and its effect on callback evaluation is detailed at: + https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order + """ + + def sort_key(item: Parameter) -> tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.2 + The ``protected_args`` attribute is deprecated and will be removed in + Click 9.0. ``args`` will contain remaining unparsed tokens. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: type[HelpFormatter] = HelpFormatter + + def __init__( + self, + command: Command, + parent: Context | None = None, + info_name: str | None = None, + obj: t.Any | None = None, + auto_envvar_prefix: str | None = None, + default_map: cabc.MutableMapping[str, t.Any] | None = None, + terminal_width: int | None = None, + max_content_width: int | None = None, + resilient_parsing: bool = False, + allow_extra_args: bool | None = None, + allow_interspersed_args: bool | None = None, + ignore_unknown_options: bool | None = None, + help_option_names: list[str] | None = None, + token_normalize_func: t.Callable[[str], str] | None = None, + color: bool | None = None, + show_default: bool | None = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: dict[str, t.Any] = {} + #: the leftover arguments. + self.args: list[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self._protected_args: list[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: str | None = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: int | None = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: int | None = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: list[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: str | None = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: bool | None = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: bool | None = show_default + + self._close_callbacks: list[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + @property + def protected_args(self) -> list[str]: + import warnings + + warnings.warn( + "'protected_args' is deprecated and will be removed in Click 9.0." + " 'args' will contain remaining unparsed tokens.", + DeprecationWarning, + stacklevel=2, + ) + return self._protected_args + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> Context: + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + self._depth -= 1 + exit_result: bool | None = None + if self._depth == 0: + exit_result = self._close_with_exception_info(exc_type, exc_value, tb) + pop_context() + + return exit_result + + @contextmanager + def scope(self, cleanup: bool = True) -> cabc.Iterator[Context]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: AbstractContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._close_with_exception_info(None, None, None) + + def _close_with_exception_info( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + """Unwind the exit stack by calling its :meth:`__exit__` providing the exception + information to allow for exception handling by the various resources registered + using :meth;`with_resource` + + :return: Whatever ``exit_stack.__exit__()`` returns. + """ + exit_result = self._exit_stack.__exit__(exc_type, exc_value, tb) + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + return exit_result + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> Context: + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: type[V]) -> V | None: + """Finds the closest object of a given type.""" + node: Context | None = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[False] = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def lookup_default(self, name: str, call: bool = True) -> t.Any | None: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name, UNSET) + + if call and callable(value): + return value() + + return value + + return UNSET + + def fail(self, message: str) -> t.NoReturn: + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> t.NoReturn: + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> t.NoReturn: + """Exits the application with a given exit code. + + .. versionchanged:: 8.2 + Callbacks and context managers registered with :meth:`call_on_close` + and :meth:`with_resource` are closed before exiting. + """ + self.close() + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: Command) -> Context: + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + @t.overload + def invoke( + self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> V: ... + + @t.overload + def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... + + def invoke( + self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> t.Any | V: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + + .. versionchanged:: 3.2 + A new context is created, and missing arguments use default values. + """ + if isinstance(callback, Command): + other_cmd = callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + callback = t.cast("t.Callable[..., V]", other_cmd.callback) + + ctx = self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + default_value = param.get_default(ctx) + # We explicitly hide the :attr:`UNSET` value to the user, as we + # choose to make it an implementation detail. And because ``invoke`` + # has been designed as part of Click public API, we return ``None`` + # instead. Refs: + # https://github.com/pallets/click/issues/3066 + # https://github.com/pallets/click/issues/3065 + # https://github.com/pallets/click/pull/3068 + if default_value is UNSET: + default_value = None + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, default_value + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = self + + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(cmd, Command): + raise TypeError("Callback is not a command.") + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> ParameterSource | None: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class Command: + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the command is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. + + .. versionchanged:: 8.2 + This is the base class for all commands, not ``BaseCommand``. + ``deprecated`` can be set to a string as well to customize the + deprecation message. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: type[Context] = Context + + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: str | None, + context_settings: cabc.MutableMapping[str, t.Any] | None = None, + callback: t.Callable[..., t.Any] | None = None, + params: list[Parameter] | None = None, + help: str | None = None, + epilog: str | None = None, + short_help: str | None = None, + options_metavar: str | None = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool | str = False, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: cabc.MutableMapping[str, t.Any] = context_settings + + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: list[Parameter] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self._help_option = None + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + return { + "name": self.name, + "params": [param.to_info_dict() for param in self.get_params(ctx)], + "help": self.help, + "epilog": self.epilog, + "short_help": self.short_help, + "hidden": self.hidden, + "deprecated": self.deprecated, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> list[Parameter]: + params = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + params = [*params, help_option] + + if __debug__: + import warnings + + opts = [opt for param in params for opt in param.opts] + opts_counter = Counter(opts) + duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) + + for duplicate_opt in duplicate_opts: + warnings.warn( + ( + f"The parameter {duplicate_opt} is used more than once. " + "Remove its duplicate as parameters should be unique." + ), + stacklevel=3, + ) + + return params + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> list[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> Option | None: + """Returns the help option object. + + Skipped if :attr:`add_help_option` is ``False``. + + .. versionchanged:: 8.1.8 + The help option is now cached to avoid creating it multiple times. + """ + help_option_names = self.get_help_option_names(ctx) + + if not help_option_names or not self.add_help_option: + return None + + # Cache the help option object in private _help_option attribute to + # avoid creating it multiple times. Not doing this will break the + # callback odering by iter_params_for_processing(), which relies on + # object comparison. + if self._help_option is None: + # Avoid circular import. + from .decorators import help_option + + # Apply help_option decorator and pop resulting option + help_option(*help_option_names)(self) + self._help_option = self.params.pop() # type: ignore[assignment] + + return self._help_option + + def make_parser(self, ctx: Context) -> _OptionParser: + """Creates the underlying option parser for this command.""" + parser = _OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: Context | None = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + _, args = param.handle_parse_result(ctx, opts, args) + + # We now have all parameters' values into `ctx.params`, but the data may contain + # the `UNSET` sentinel. + # Convert `UNSET` to `None` to ensure that the user doesn't see `UNSET`. + # + # Waiting until after the initial parse to convert allows us to treat `UNSET` + # more like a missing value when multiple params use the same name. + # Refs: + # https://github.com/pallets/click/issues/3071 + # https://github.com/pallets/click/pull/3079 + for name, value in ctx.params.items(): + if value is UNSET: + ctx.params[name] = None + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" + ).format(name=self.name, extra_message=extra_message) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: list[CompletionItem] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, Group) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx._protected_args + ) + + return results + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: t.Literal[True] = True, + **extra: t.Any, + ) -> t.NoReturn: ... + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: ... + + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) as e: + echo(file=sys.stderr) + raise Abort() from e + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str | None = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. versionchanged:: 8.2.0 + Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). + """ + if complete_var is None: + complete_name = prog_name.replace("-", "_").replace(".", "_") + complete_var = f"_{complete_name}_COMPLETE".upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: type) -> bool: + return issubclass(subclass, cls.__bases__[0]) + + def __instancecheck__(cls, instance: t.Any) -> bool: + return isinstance(instance, cls.__bases__[0]) + + +class _BaseCommand(Command, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Command`` instead. + """ + + +class Group(Command): + """A group is a command that nests other commands (or more groups). + + :param name: The name of the group command. + :param commands: Map names to :class:`Command` objects. Can be a list, which + will use :attr:`Command.name` as the keys. + :param invoke_without_command: Invoke the group's callback even if a + subcommand is not given. + :param no_args_is_help: If no arguments are given, show the group's help and + exit. Defaults to the opposite of ``invoke_without_command``. + :param subcommand_metavar: How to represent the subcommand argument in help. + The default will represent whether ``chain`` is set or not. + :param chain: Allow passing more than one subcommand argument. After parsing + a command's arguments, if any arguments remain another command will be + matched, and so on. + :param result_callback: A function to call after the group's and + subcommand's callbacks. The value returned by the subcommand is passed. + If ``chain`` is enabled, the value will be a list of values returned by + all the commands. If ``invoke_without_command`` is enabled, the value + will be the value returned by the group's callback, or an empty list if + ``chain`` is enabled. + :param kwargs: Other arguments passed to :class:`Command`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + + .. versionchanged:: 8.2 + Merged with and replaces the ``MultiCommand`` base class. + """ + + allow_extra_args = True + allow_interspersed_args = False + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: type[Command] | None = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: type[Group] | type[type] | None = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: str | None = None, + commands: cabc.MutableMapping[str, Command] + | cabc.Sequence[Command] + | None = None, + invoke_without_command: bool = False, + no_args_is_help: bool | None = None, + subcommand_metavar: str | None = None, + chain: bool = False, + result_callback: t.Callable[..., t.Any] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: cabc.MutableMapping[str, Command] = commands + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "A group in chain mode cannot have optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def add_command(self, cmd: Command, name: str | None = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_nested_chain(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'command(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> Group: ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'group(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> Group: + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + inner = old_callback(value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv # type: ignore[return-value] + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Given a context and a command name, this returns a :class:`Command` + object if it exists or returns ``None``. + """ + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> list[str]: + """Returns a list of subcommand names in the order they should appear.""" + return sorted(self.commands) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx._protected_args = rest + ctx.args = [] + elif rest: + ctx._protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx._protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx._protected_args, *ctx.args] + ctx.args = [] + ctx._protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if _split_opt(cmd_name)[0]: + self.parse_args(ctx, args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class _MultiCommand(Group, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Group`` instead. + """ + + +class CommandCollection(Group): + """A :class:`Group` that looks up subcommands on other groups. If a command + is not found on this group, each registered source is checked in order. + Parameters on a source are not added to this group, and a source's callback + is not invoked when invoking its commands. In other words, this "flattens" + commands in many groups into this one group. + + :param name: The name of the group command. + :param sources: A list of :class:`Group` objects to look up commands from. + :param kwargs: Other arguments passed to :class:`Group`. + + .. versionchanged:: 8.2 + This is a subclass of ``Group``. Commands are looked up first on this + group, then each of its sources. + """ + + def __init__( + self, + name: str | None = None, + sources: list[Group] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + #: The list of registered groups. + self.sources: list[Group] = sources or [] + + def add_source(self, group: Group) -> None: + """Add a group as a source of commands.""" + self.sources.append(group) + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + rv = super().get_command(ctx, cmd_name) + + if rv is not None: + return rv + + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_nested_chain(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> list[str]: + rv: set[str] = set(super().list_commands(ctx)) + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The latter is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: environment variable(s) that are used to provide a default value for + this parameter. This can be a string or a sequence of strings. If a sequence is + given, only the first non-empty environment variable is used for the parameter. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the argument is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. A deprecated parameter + cannot be required, a ValueError will be raised otherwise. + + .. versionchanged:: 8.2.0 + Introduction of ``deprecated``. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + type: types.ParamType | t.Any | None = None, + required: bool = False, + # XXX The default historically embed two concepts: + # - the declaration of a Parameter object carrying the default (handy to + # arbitrage the default value of coupled Parameters sharing the same + # self.name, like flag options), + # - and the actual value of the default. + # It is confusing and is the source of many issues discussed in: + # https://github.com/pallets/click/pull/3030 + # In the future, we might think of splitting it in two, not unlike + # Option.is_flag and Option.flag_value: we could have something like + # Parameter.is_default and Parameter.default_value. + default: t.Any | t.Callable[[], t.Any] | None = UNSET, + callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, + nargs: int | None = None, + multiple: bool = False, + metavar: str | None = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: str | cabc.Sequence[str] | None = None, + shell_complete: t.Callable[ + [Context, Parameter, str], list[CompletionItem] | list[str] + ] + | None = None, + deprecated: bool | str = False, + ) -> None: + self.name: str | None + self.opts: list[str] + self.secondary_opts: list[str] + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type: types.ParamType = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default: t.Any | t.Callable[[], t.Any] | None = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + self.deprecated = deprecated + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + if required and deprecated: + raise ValueError( + f"The {self.param_type_name} '{self.human_readable_name}' " + "is deprecated and still required. A deprecated " + f"{self.param_type_name} cannot be required." + ) + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`default` if it was not set. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + # We explicitly hide the :attr:`UNSET` value to the user, as we choose to + # make it an implementation detail. And because ``to_info_dict`` has been + # designed for documentation purposes, we return ``None`` instead. + "default": self.default if self.default is not UNSET else None, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(param=self, ctx=ctx) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is UNSET: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, t.Any] + ) -> tuple[t.Any, ParameterSource]: + """Returns the parameter value produced by the parser. + + If the parser did not produce a value from user input, the value is either + sourced from the environment variable, the default map, or the parameter's + default value. In that order of precedence. + + If no value is found, an internal sentinel value is returned. + + :meta private: + """ + # Collect from the parse the value passed by the user to the CLI. + value = opts.get(self.name, UNSET) # type: ignore + # If the value is set, it means it was sourced from the command line by the + # parser, otherwise it left unset by default. + source = ( + ParameterSource.COMMANDLINE + if value is not UNSET + else ParameterSource.DEFAULT + ) + + if value is UNSET: + envvar_value = self.value_from_envvar(ctx) + if envvar_value is not None: + value = envvar_value + source = ParameterSource.ENVIRONMENT + + if value is UNSET: + default_map_value = ctx.lookup_default(self.name) # type: ignore + if default_map_value is not UNSET: + value = default_map_value + source = ParameterSource.DEFAULT_MAP + + if value is UNSET: + default_value = self.get_default(ctx) + if default_value is not UNSET: + value = default_value + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the parameter's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + if self.multiple or self.nargs == -1: + return () + else: + return value + + def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + # Define the conversion function based on nargs and type. + + if self.nargs == 1 or self.type.is_composite: + + def convert(value: t.Any) -> t.Any: + return self.type(value, param=self, ctx=ctx) + + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + """A value is considered missing if: + + - it is :attr:`UNSET`, + - or if it is an empty sequence while the parameter is suppose to have + non-single value (i.e. :attr:`nargs` is not ``1`` or :attr:`multiple` is + set). + + :meta private: + """ + if value is UNSET: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + """Process the value of this parameter: + + 1. Type cast the value using :meth:`type_cast_value`. + 2. Check if the value is missing (see: :meth:`value_is_missing`), and raise + :exc:`MissingParameter` if it is required. + 3. If a :attr:`callback` is set, call it to have the value replaced by the + result of the callback. If the value was not set, the callback receive + ``None``. This keep the legacy behavior as it was before the introduction of + the :attr:`UNSET` sentinel. + + :meta private: + """ + # shelter `type_cast_value` from ever seeing an `UNSET` value by handling the + # cases in which `UNSET` gets special treatment explicitly at this layer + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if value is UNSET: + if self.multiple or self.nargs == -1: + value = () + else: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + # Legacy case: UNSET is not exposed directly to the callback, but converted + # to None. + if value is UNSET: + value = None + + # Search for parameters with UNSET values in the context. + unset_keys = {k: None for k, v in ctx.params.items() if v is UNSET} + # No UNSET values, call the callback as usual. + if not unset_keys: + value = self.callback(ctx, self, value) + + # Legacy case: provide a temporarily manipulated context to the callback + # to hide UNSET values as None. + # + # Refs: + # https://github.com/pallets/click/issues/3136 + # https://github.com/pallets/click/pull/3137 + else: + # Add another layer to the context stack to clearly hint that the + # context is temporarily modified. + with ctx: + # Update the context parameters to replace UNSET with None. + ctx.params.update(unset_keys) + # Feed these fake context parameters to the callback. + value = self.callback(ctx, self, value) + # Restore the UNSET values in the context parameters. + ctx.params.update( + { + k: UNSET + for k in unset_keys + # Only restore keys that are present and still None, in case + # the callback modified other parameters. + if k in ctx.params and ctx.params[k] is None + } + ) + + return value + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """Returns the value found in the environment variable(s) attached to this + parameter. + + Environment variables values are `always returned as strings + `_. + + This method returns ``None`` if: + + - the :attr:`envvar` property is not set on the :class:`Parameter`, + - the environment variable is not found in the environment, + - the variable is found in the environment but its value is empty (i.e. the + environment variable is present but has an empty string). + + If :attr:`envvar` is setup with multiple environment variables, + then only the first non-empty value is returned. + + .. caution:: + + The raw value extracted from the environment is not normalized and is + returned as-is. Any normalization or reconciliation is performed later by + the :class:`Parameter`'s :attr:`type`. + + :meta private: + """ + if not self.envvar: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + # Return the first non-empty value of the list of environment variables. + if rv: + return rv + # Else, absence of value is interpreted as an environment variable that + # is not set, so proceed to the next one. + + return None + + def value_from_envvar(self, ctx: Context) -> str | cabc.Sequence[str] | None: + """Process the raw environment variable string for this parameter. + + Returns the string as-is or splits it into a sequence of strings if the + parameter is expecting multiple values (i.e. its :attr:`nargs` property is set + to a value other than ``1``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + return self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] + ) -> tuple[t.Any, list[str]]: + """Process the value produced by the parser from user input. + + Always process the value through the Parameter's :attr:`type`, wherever it + comes from. + + If the parameter is deprecated, this method warn the user about it. But only if + the value has been explicitly set by the user (and as such, is not coming from + a default). + + :meta private: + """ + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + ctx.set_parameter_source(self.name, source) # type: ignore + + # Display a deprecation warning if necessary. + if ( + self.deprecated + and value is not UNSET + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ): + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The {param_type} {name!r} is deprecated." + "{extra_message}" + ).format( + param_type=self.param_type_name, + name=self.human_readable_name, + extra_message=extra_message, + ) + echo(style(message, fg="red"), err=True) + + # Process the value through the parameter's type. + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + # In resilient parsing mode, we do not want to fail the command if the + # value is incompatible with the parameter type, so we reset the value + # to UNSET, which will be interpreted as a missing value. + value = UNSET + + # Add parameter's value to the context. + if ( + self.expose_value + # We skip adding the value if it was previously set by another parameter + # targeting the same variable name. This prevents parameters competing for + # the same name to override each other. + and (self.name not in ctx.params or ctx.params[self.name] is UNSET) + ): + # Click is logically enforcing that the name is None if the parameter is + # not to be exposed. We still assert it here to please the type checker. + assert self.name is not None, ( + f"{self!r} parameter's name should not be None when exposing value." + ) + ctx.params[self.name] = value + + return value, args + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + pass + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast("list[CompletionItem]", results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page and error messages. + Normally, environment variables are not shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. A deprecated option cannot be + prompted. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.2 + ``envvar`` used with ``flag_value`` will always use the ``flag_value``, + previously it would use the value of the environment variable. + + .. versionchanged:: 8.1 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + show_default: bool | str | None = None, + prompt: bool | str = False, + confirmation_prompt: bool | str = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: bool | None = None, + flag_value: t.Any = UNSET, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: types.ParamType | t.Any | None = None, + help: str | None = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + deprecated: bool | str = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + super().__init__( + param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs + ) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: str | None = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + if deprecated: + deprecated_message = ( + f"(DEPRECATED: {deprecated})" + if isinstance(deprecated, str) + else "(DEPRECATED)" + ) + help = help + deprecated_message if help is not None else deprecated_message + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # The _flag_needs_value property tells the parser that this option is a flag + # that cannot be used standalone and needs a value. With this information, the + # parser can determine whether to consider the next user-provided argument in + # the CLI as a value for this flag or as a new option. + # If prompt is enabled but not required, then it opens the possibility for the + # option to gets its value from the user. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + # Auto-detect if this is a flag or not. + if is_flag is None: + # Implicitly a flag because flag_value was set. + if flag_value is not UNSET: + is_flag = True + # Not a flag, but when used as a flag it shows a prompt. + elif self._flag_needs_value: + is_flag = False + # Implicitly a flag because secondary options names were given. + elif self.secondary_opts: + is_flag = True + # The option is explicitly not a flag. But we do not know yet if it needs a + # value or not. So we look at the default value to determine it. + elif is_flag is False and not self._flag_needs_value: + self._flag_needs_value = self.default is UNSET + + if is_flag: + # Set missing default for flags if not explicitly required or prompted. + if self.default is UNSET and not self.required and not self.prompt: + if multiple: + self.default = () + + # Auto-detect the type of the flag based on the flag_value. + if type is None: + # A flag without a flag_value is a boolean flag. + if flag_value is UNSET: + self.type: types.ParamType = types.BoolParamType() + # If the flag value is a boolean, use BoolParamType. + elif isinstance(flag_value, bool): + self.type = types.BoolParamType() + # Otherwise, guess the type from the flag value. + else: + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = bool(is_flag) + self.is_bool_flag: bool = bool( + is_flag and isinstance(self.type, types.BoolParamType) + ) + self.flag_value: t.Any = flag_value + + # Set boolean flag default to False if unset and not required. + if self.is_bool_flag: + if self.default is UNSET and not self.required: + self.default = False + + # Support the special case of aligning the default value with the flag_value + # for flags whose default is explicitly set to True. Note that as long as we + # have this condition, there is no way a flag can have a default set to True, + # and a flag_value set to something else. Refs: + # https://github.com/pallets/click/issues/3024#issuecomment-3146199461 + # https://github.com/pallets/click/pull/3030/commits/06847da + if self.default is True and self.flag_value is not UNSET: + self.default = self.flag_value + + # Set the default flag_value if it is not set. + if self.flag_value is UNSET: + if self.is_flag: + self.flag_value = True + else: + self.flag_value = None + + # Counting. + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if self.default is UNSET: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if deprecated and prompt: + raise ValueError("`deprecated` options cannot use `prompt`.") + + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + def to_info_dict(self) -> dict[str, t.Any]: + """ + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`flag_value` if it was not set. + """ + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + # We explicitly hide the :attr:`UNSET` value to the user, as we choose to + # make it an implementation detail. And because ``to_info_dict`` has been + # designed for documentation purposes, we return ``None`` instead. + flag_value=self.flag_value if self.flag_value is not UNSET else None, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def get_error_hint(self, ctx: Context) -> str: + result = super().get_error_hint(ctx) + if self.show_envvar and self.envvar is not None: + result += f" (env var: '{self.envvar}')" + return result + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(_split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(_split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError( + f"Could not determine name for option with declarations {decls!r}" + ) + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: cabc.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar(ctx=ctx)}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + + extra = self.get_help_extra(ctx) + extra_items = [] + if "envvars" in extra: + extra_items.append( + _("env var: {var}").format(var=", ".join(extra["envvars"])) + ) + if "default" in extra: + extra_items.append(_("default: {default}").format(default=extra["default"])) + if "range" in extra: + extra_items.append(extra["range"]) + if "required" in extra: + extra_items.append(_(extra["required"])) + + if extra_items: + extra_str = "; ".join(extra_items) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: + extra: types.OptionHelpExtra = {} + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + if isinstance(envvar, str): + extra["envvars"] = (envvar,) + else: + extra["envvars"] = tuple(str(d) for d in envvar) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or ( + show_default and (default_value not in (None, UNSET)) + ): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif isinstance(default_value, enum.Enum): + default_string = default_value.name + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = _split_opt( + (self.opts if default_value else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + elif default_value == "": + default_string = '""' + else: + default_string = str(default_value) + + if default_string: + extra["default"] = default_string + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra["range"] = range_str + + if self.required: + extra["required"] = "required" + + return extra + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to lock in the value before + # attempting any user interaction. + default = self.get_default(ctx) + + # A boolean flag can use a simplified [y/n] confirmation prompt. + if self.is_bool_flag: + # If we have no boolean default, we force the user to explicitly provide + # one. + if default in (UNSET, None): + default = None + # Nothing prevent you to declare an option that is simultaneously: + # 1) auto-detected as a boolean flag, + # 2) allowed to prompt, and + # 3) still declare a non-boolean default. + # This forced casting into a boolean is necessary to align any non-boolean + # default to the prompt, which is going to be a [y/n]-style confirmation + # because the option is still a boolean flag. That way, instead of [y/n], + # we get [Y/n] or [y/N] depending on the truthy value of the default. + # Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249 + else: + default = bool(default) + return confirm(self.prompt, default) + + # If show_default is set to True/False, provide this to `prompt` as well. For + # non-bool values of `show_default`, we use `prompt`'s default behavior + prompt_kwargs: t.Any = {} + if isinstance(self.show_default, bool): + prompt_kwargs["show_default"] = self.show_default + + return prompt( + self.prompt, + # Use ``None`` to inform the prompt() function to reiterate until a valid + # value is provided by the user if we have no default. + default=None if default is UNSET else default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + **prompt_kwargs, + ) + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """:class:`Option` resolves its environment variable the same way as + :func:`Parameter.resolve_envvar_value`, but it also supports + :attr:`Context.auto_envvar_prefix`. If we could not find an environment from + the :attr:`envvar` property, we fallback on :attr:`Context.auto_envvar_prefix` + to build dynamiccaly the environment variable name using the + :python:`{ctx.auto_envvar_prefix}_{self.name.upper()}` template. + + :meta private: + """ + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any: + """For :class:`Option`, this method processes the raw environment variable + string the same way as :func:`Parameter.value_from_envvar` does. + + But in the case of non-boolean flags, the value is analyzed to determine if the + flag is activated or not, and returns a boolean of its activation, or the + :attr:`flag_value` if the latter is set. + + This method also takes care of repeated options (i.e. options with + :attr:`multiple` set to ``True``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + # Absent environment variable or an empty string is interpreted as unset. + if rv is None: + return None + + # Non-boolean flags are more liberal in what they accept. But a flag being a + # flag, its envvar value still needs to be analyzed to determine if the flag is + # activated or not. + if self.is_flag and not self.is_bool_flag: + # If the flag_value is set and match the envvar value, return it + # directly. + if self.flag_value is not UNSET and rv == self.flag_value: + return self.flag_value + # Analyze the envvar value as a boolean to know if the flag is + # activated or not. + return types.BoolParamType.str_to_bool(rv) + + # Split the envvar value if it is allowed to be repeated. + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0: + multi_rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + multi_rv = batch(multi_rv, self.nargs) # type: ignore[assignment] + + return multi_rv + + return rv + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, Parameter] + ) -> tuple[t.Any, ParameterSource]: + """For :class:`Option`, the value can be collected from an interactive prompt + if the option is a flag that needs a value (and the :attr:`prompt` property is + set). + + Additionally, this method handles flag option that are activated without a + value, in which case the :attr:`flag_value` is returned. + + :meta private: + """ + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option is allowed to as a flag + # without a value. + if value is FLAG_NEEDS_VALUE: + # If the option allows for a prompt, we start an interaction with the user. + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + # Else the flag takes its flag_value as value. + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + # A flag which is activated always returns the flag value, unless the value + # comes from the explicitly sets default. + elif ( + self.is_flag + and value is True + and not self.is_bool_flag + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ): + value = self.flag_value + + # Re-interpret a multiple option which has been sent as-is by the parser. + # Here we replace each occurrence of value-less flags (marked by the + # FLAG_NEEDS_VALUE sentinel) with the flag_value. + elif ( + self.multiple + and value is not UNSET + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + and any(v is FLAG_NEEDS_VALUE for v in value) + ): + value = [self.flag_value if v is FLAG_NEEDS_VALUE else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt for one to the user + # if prompting is enabled. + elif ( + ( + value is UNSET + or source in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ) + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + # process_value has to be overridden on Options in order to capture + # `value == UNSET` cases before `type_cast_value()` gets called. + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if self.is_flag and not self.required and self.is_bool_flag and value is UNSET: + value = False + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + # in the normal case, rely on Parameter.process_value + return super().process_value(ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the constructor of :class:`Parameter`. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: cabc.Sequence[str], + required: bool | None = None, + **attrs: t.Any, + ) -> None: + # Auto-detect the requirement status of the argument if not explicitly set. + if required is None: + # The argument gets automatically required if it has no explicit default + # value set and is setup to match at least one value. + if attrs.get("default", UNSET) is UNSET: + required = attrs.get("nargs", 1) > 0 + # If the argument has a default value, it is not required. + else: + required = False + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(param=self, ctx=ctx) + if not var: + var = self.name.upper() # type: ignore + if self.deprecated: + var += "!" + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Argument is marked as exposed, but does not have a name.") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}: {decls}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [self.make_metavar(ctx)] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar(ctx)}'" + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + raise AttributeError(name) diff --git a/.venv/lib/python3.12/site-packages/click/decorators.py b/.venv/lib/python3.12/site-packages/click/decorators.py new file mode 100644 index 0000000..21f4c34 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/decorators.py @@ -0,0 +1,551 @@ +from __future__ import annotations + +import inspect +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") +T = t.TypeVar("T") +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound="_AnyCallable | Command") + + +def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator( + object_type: type[T], ensure: bool = False +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + + obj: T | None + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: str | None = None +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +# variant: no call, directly as decorator for a function. +@t.overload +def command(name: _AnyCallable) -> Command: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) +@t.overload +def command( + name: str | None, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) +@t.overload +def command( + name: None = None, + *, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: ... + + +def command( + name: str | _AnyCallable | None = None, + cls: type[CmdType] | None = None, + **attrs: t.Any, +) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function, converted to + lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes + ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, + ``init_data_command`` becomes ``init-data``. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: The name of the command. Defaults to modifying the function's + name as described above. + :param cls: The command class to create. Defaults to :class:`Command`. + + .. versionchanged:: 8.2 + The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are + removed when generating the name. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Callable[[_AnyCallable], t.Any] | None = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast("type[CmdType]", Command) + + def decorator(f: _AnyCallable) -> CmdType: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + if t.TYPE_CHECKING: + assert cls is not None + assert not callable(name) + + if name is not None: + cmd_name = name + else: + cmd_name = f.__name__.lower().replace("_", "-") + cmd_left, sep, suffix = cmd_name.rpartition("-") + + if sep and suffix in {"command", "cmd", "group", "grp"}: + cmd_name = cmd_left + + cmd = cls(name=cmd_name, callback=f, params=params, **attrs) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +GrpType = t.TypeVar("GrpType", bound=Group) + + +# variant: no call, directly as decorator for a function. +@t.overload +def group(name: _AnyCallable) -> Group: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) +@t.overload +def group( + name: str | None, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) +@t.overload +def group( + name: None = None, + *, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: ... + + +def group( + name: str | _AnyCallable | None = None, + cls: type[GrpType] | None = None, + **attrs: t.Any, +) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if cls is None: + cls = t.cast("type[GrpType]", Group) + + if callable(name): + return command(cls=cls, **attrs)(name) + + return command(name, cls, **attrs) + + +def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument( + *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default argument class, refer to :class:`Argument` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Argument + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def option( + *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default option class, refer to :class:`Option` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Option + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: str | None = None, + *param_decls: str, + package_name: str | None = None, + prog_name: str | None = None, + message: str | None = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + import importlib.metadata + + try: + version = importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Pre-configured ``--help`` option which immediately prints the help page + and exits the program. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", show_help) + + return option(*param_decls, **kwargs) diff --git a/.venv/lib/python3.12/site-packages/click/exceptions.py b/.venv/lib/python3.12/site-packages/click/exceptions.py new file mode 100644 index 0000000..4d782ee --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/exceptions.py @@ -0,0 +1,308 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .globals import resolve_color_default +from .utils import echo +from .utils import format_filename + +if t.TYPE_CHECKING: + from .core import Command + from .core import Context + from .core import Parameter + + +def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + # The context will be removed by the time we print the message, so cache + # the color settings here to be used later on (in `show`) + self.show_color: bool | None = resolve_color_default() + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=self.show_color, + ) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: Context | None = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: Command | None = self.ctx.command if self.ctx else None + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: str | None = None, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + param_type: str | None = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: cabc.Sequence[str] | str | None = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message( + param=self.param, ctx=self.ctx + ) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: str | None = None, + possibilities: cabc.Sequence[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: Context | None = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class NoArgsIsHelpError(UsageError): + def __init__(self, ctx: Context) -> None: + self.ctx: Context + super().__init__(ctx.get_help(), ctx=ctx) + + def show(self, file: t.IO[t.Any] | None = None) -> None: + echo(self.format_message(), file=file, err=True, color=self.ctx.color) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: str | None = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: str = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code: int = code diff --git a/.venv/lib/python3.12/site-packages/click/formatting.py b/.venv/lib/python3.12/site-packages/click/formatting.py new file mode 100644 index 0000000..0b64f83 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +import collections.abc as cabc +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import _split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: int | None = None + + +def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: + widths: dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: cabc.Iterable[tuple[str, str]], col_count: int +) -> cabc.Iterator[tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: list[tuple[int, bool, str]] = [] + buf: list[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: int | None = None, + max_width: int | None = None, + ) -> None: + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + import shutil + + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent: int = 0 + self.buffer: list[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: cabc.Sequence[tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> cabc.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> cabc.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = _split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/.venv/lib/python3.12/site-packages/click/globals.py b/.venv/lib/python3.12/site-packages/click/globals.py new file mode 100644 index 0000000..a2f9172 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/globals.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import typing as t +from threading import local + +if t.TYPE_CHECKING: + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: t.Literal[False] = False) -> Context: ... + + +@t.overload +def get_current_context(silent: bool = ...) -> Context | None: ... + + +def get_current_context(silent: bool = False) -> Context | None: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: Context) -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: bool | None = None) -> bool | None: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/.venv/lib/python3.12/site-packages/click/parser.py b/.venv/lib/python3.12/site-packages/click/parser.py new file mode 100644 index 0000000..1ea1f71 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/parser.py @@ -0,0 +1,532 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" + +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + from ._utils import T_FLAG_NEEDS_VALUE + from ._utils import T_UNSET + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + + +def _unpack_args( + args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] +) -> tuple[cabc.Sequence[str | cabc.Sequence[str | None] | None], list[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with ``UNSET``. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: list[str | tuple[str | T_UNSET, ...] | T_UNSET] = [] + spos: int | None = None + + def _fetch(c: deque[V]) -> V | T_UNSET: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return UNSET + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) # type: ignore[arg-type] + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(UNSET) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def _split_opt(opt: str) -> tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def _normalize_opt(opt: str, ctx: Context | None) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = _split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +class _Option: + def __init__( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: set[str] = set() + + for opt in opts: + prefix, value = _split_opt(opt) + if not prefix: + raise ValueError(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: t.Any, state: _ParsingState) -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class _Argument: + def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: str | cabc.Sequence[str | None] | None | T_UNSET, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert isinstance(value, cabc.Sequence) + holes = sum(1 for x in value if x is UNSET) + if holes == len(value): + value = UNSET + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + # We failed to collect any argument value so we consider the argument as unset. + if value == (): + value = UNSET + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class _ParsingState: + def __init__(self, rargs: list[str]) -> None: + self.opts: dict[str, t.Any] = {} + self.largs: list[str] = [] + self.rargs = rargs + self.order: list[CoreParameter] = [] + + +class _OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + + .. deprecated:: 8.2 + Will be removed in Click 9.0. + """ + + def __init__(self, ctx: Context | None = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args: bool = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options: bool = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: dict[str, _Option] = {} + self._long_opt: dict[str, _Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: list[_Argument] = [] + + def add_option( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [_normalize_opt(opt, self.ctx) for opt in opts] + option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(_Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: list[str] + ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = _ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: _ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: _ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: str | None, state: _ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = UNSET + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: _ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = _normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = UNSET + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we recombine the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: _Option, state: _ParsingState + ) -> str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE: + nargs = option.nargs + + value: str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = FLAG_NEEDS_VALUE + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = FLAG_NEEDS_VALUE + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: _ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = _normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) + + +def __getattr__(name: str) -> object: + import warnings + + if name in { + "OptionParser", + "Argument", + "Option", + "split_opt", + "normalize_opt", + "ParsingState", + }: + warnings.warn( + f"'parser.{name}' is deprecated and will be removed in Click 9.0." + " The old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return globals()[f"_{name}"] + + if name == "split_arg_string": + from .shell_completion import split_arg_string + + warnings.warn( + "Importing 'parser.split_arg_string' is deprecated, it will only be" + " available in 'shell_completion' in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return split_arg_string + + raise AttributeError(name) diff --git a/.venv/lib/python3.12/site-packages/click/py.typed b/.venv/lib/python3.12/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/click/shell_completion.py b/.venv/lib/python3.12/site-packages/click/shell_completion.py new file mode 100644 index 0000000..8f1564c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/shell_completion.py @@ -0,0 +1,667 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .utils import echo + + +def shell_complete( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: str | None = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: str | None = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +# See ZshComplete.format_completion below, and issue #2703, before +# changing this script. +# +# (TL;DR: _describe is picky about the format, but this Zsh script snippet +# is already widely deployed. So freeze this script, and use clever-ish +# handling of colons in ZshComplet.format_completion.) +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +if [[ $zsh_eval_context[-1] == loadautofunc ]]; then + # autoload from fpath, call function directly + %(complete_func)s "$@" +else + # eval/source/. command, register function for later + compdef %(complete_func)s %(prog_name)s +fi +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> tuple[list[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import shutil + import subprocess + + bash_exe = shutil.which("bash") + + if bash_exe is None: + match = None + else: + output = subprocess.run( + [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], + stdout=subprocess.PIPE, + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + echo( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ), + err=True, + ) + else: + echo( + _("Couldn't detect Bash version, shell completion is not supported."), + err=True, + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + help_ = item.help or "_" + # The zsh completion script uses `_describe` on items with help + # texts (which splits the item help from the item value at the + # first unescaped colon) and `compadd` on items without help + # text (which uses the item value as-is and does not support + # colon escaping). So escape colons in the item value if and + # only if the item help is not the sentinel "_" value, as used + # by the completion script. + # + # (The zsh completion script is potentially widely deployed, and + # thus harder to fix than this method.) + # + # See issue #1812 and issue #2703 for further context. + value = item.value.replace(":", r"\:") if help_ != "_" else item.value + return f"{item.type}\n{value}\n{help_}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + if incomplete: + incomplete = split_arg_string(incomplete)[0] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") + + +_available_shells: dict[str, type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: str | None = None +) -> ShellCompleteType: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + return cls + + +def get_completion_class(shell: str) -> type[ShellComplete] | None: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def split_arg_string(string: str) -> list[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + + .. versionchanged:: 8.2 + Moved to ``shell_completion`` from ``parser``. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + # Will be None if expose_value is False. + value = ctx.params.get(param.name) + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + break + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + args: list[str], +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: + args = ctx._protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, Group): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, args, parent=ctx, resilient_parsing=True + ) as sub_ctx: + ctx = sub_ctx + args = ctx._protected_args + ctx.args + else: + sub_ctx = ctx + + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) as sub_sub_ctx: + sub_ctx = sub_sub_ctx + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx._protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: list[str], incomplete: str +) -> tuple[Command | Parameter, str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/.venv/lib/python3.12/site-packages/click/termui.py b/.venv/lib/python3.12/site-packages/click/termui.py new file mode 100644 index 0000000..2e98a07 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/termui.py @@ -0,0 +1,883 @@ +from __future__ import annotations + +import collections.abc as cabc +import inspect +import io +import itertools +import sys +import typing as t +from contextlib import AbstractContextManager +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Any | None = None, + show_choices: bool = True, + type: ParamType | None = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text: str, + default: t.Any | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType | t.Any | None = None, + value_proc: t.Callable[[str], t.Any] | None = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text[:-1], nl=False, err=err) + # Echo the last character to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(text[-1:]) + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: bool | None = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt[:-1], nl=False, err=err) + # Echo the last character to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(prompt[-1:]).lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, + color: bool | None = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +@t.overload +def progressbar( + *, + length: int, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[int]: ... + + +@t.overload +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: ... + + +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param hidden: hide the progressbar. Defaults to ``False``. When no tty is + detected, it will only print the progressbar label. Setting this to + ``False`` also disables that. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionadded:: 8.2 + The ``hidden`` argument. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + The ``update_min_steps`` parameter. + + .. versionadded:: 4.0 + The ``color`` parameter and ``update`` method. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + hidden=hidden, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor + echo("\033[2J\033[1;1H", nl=False) + + +def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: int | tuple[int, int, int] | str | None = None, + bg: int | tuple[int, int, int] | str | None = None, + bold: bool | None = None, + dim: bool | None = None, + underline: bool | None = None, + overline: bool | None = None, + italic: bool | None = None, + blink: bool | None = None, + reverse: bool | None = None, + strikethrough: bool | None = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Any | None = None, + file: t.IO[t.AnyStr] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +@t.overload +def edit( + text: bytes | bytearray, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = False, + extension: str = ".txt", +) -> bytes | None: ... + + +@t.overload +def edit( + text: str, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", +) -> str | None: ... + + +@t.overload +def edit( + text: None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> None: ... + + +def edit( + text: str | bytes | bytearray | None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> str | bytes | bytearray | None: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. If the editor supports + editing multiple files at once, a sequence of files may be + passed as well. Invoke `click.file` once per file instead + if multiple files cannot be managed at once or editing the + files serially is desired. + + .. versionchanged:: 8.2.0 + ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` + if the ``editor`` supports editing multiple files at once. + + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + if isinstance(filename, str): + filename = (filename,) + + ed.edit_files(filenames=filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Callable[[bool], str] | None = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> AbstractContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: str | None = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/.venv/lib/python3.12/site-packages/click/testing.py b/.venv/lib/python3.12/site-packages/click/testing.py new file mode 100644 index 0000000..f6f60b8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/testing.py @@ -0,0 +1,577 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +import shlex +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import _compat +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from _typeshed import ReadableBuffer + + from .core import Command + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> list[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> cabc.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class BytesIOCopy(io.BytesIO): + """Patch ``io.BytesIO`` to let the written stream be copied to another. + + .. versionadded:: 8.2 + """ + + def __init__(self, copy_to: io.BytesIO) -> None: + super().__init__() + self.copy_to = copy_to + + def flush(self) -> None: + super().flush() + self.copy_to.flush() + + def write(self, b: ReadableBuffer) -> int: + self.copy_to.write(b) + return super().write(b) + + +class StreamMixer: + """Mixes `` and `` streams. + + The result is available in the ``output`` attribute. + + .. versionadded:: 8.2 + """ + + def __init__(self) -> None: + self.output: io.BytesIO = io.BytesIO() + self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) + self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) + + def __del__(self) -> None: + """ + Guarantee that embedded file-like objects are closed in a + predictable order, protecting against races between + self.output being closed and other streams being flushed on close + + .. versionadded:: 8.2.2 + """ + self.stderr.close() + self.stdout.close() + self.output.close() + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: str | bytes | t.IO[t.Any] | None, charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(input) + + +class Result: + """Holds the captured result of an invoked CLI script. + + :param runner: The runner that created the result + :param stdout_bytes: The standard output as bytes. + :param stderr_bytes: The standard error as bytes. + :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the + user would see it in its terminal. + :param return_value: The value returned from the invoked command. + :param exit_code: The exit code as integer. + :param exception: The exception that happened if one did. + :param exc_info: Exception information (exception type, exception instance, + traceback type). + + .. versionchanged:: 8.2 + ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and + ``mix_stderr`` has been removed. + + .. versionadded:: 8.0 + Added ``return_value``. + """ + + def __init__( + self, + runner: CliRunner, + stdout_bytes: bytes, + stderr_bytes: bytes, + output_bytes: bytes, + return_value: t.Any, + exit_code: int, + exception: BaseException | None, + exc_info: tuple[type[BaseException], BaseException, TracebackType] + | None = None, + ): + self.runner = runner + self.stdout_bytes = stdout_bytes + self.stderr_bytes = stderr_bytes + self.output_bytes = output_bytes + self.return_value = return_value + self.exit_code = exit_code + self.exception = exception + self.exc_info = exc_info + + @property + def output(self) -> str: + """The terminal output as unicode string, as the user would see it. + + .. versionchanged:: 8.2 + No longer a proxy for ``self.stdout``. Now has its own independent stream + that is mixing `` and ``, in the order they were written. + """ + return self.output_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string. + + .. versionchanged:: 8.2 + No longer raise an exception, always returns the `` string. + """ + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from `` writes + to ``. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param catch_exceptions: Whether to catch any exceptions other than + ``SystemExit`` when running :meth:`~CliRunner.invoke`. + + .. versionchanged:: 8.2 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 8.2 + ``mix_stderr`` parameter has been removed. + """ + + def __init__( + self, + charset: str = "utf-8", + env: cabc.Mapping[str, str | None] | None = None, + echo_stdin: bool = False, + catch_exceptions: bool = True, + ) -> None: + self.charset = charset + self.env: cabc.Mapping[str, str | None] = env or {} + self.echo_stdin = echo_stdin + self.catch_exceptions = catch_exceptions + + def get_default_prog_name(self, cli: Command) -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: cabc.Mapping[str, str | None] | None = None + ) -> cabc.Mapping[str, str | None]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + color: bool = False, + ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up `` with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into `sys.stdin`. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + An additional output stream is returned, which is a mix of + `` and `` streams. + + .. versionchanged:: 8.2 + Always returns the `` stream. + + .. versionchanged:: 8.0 + `` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + stream_mixer = StreamMixer() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + stream_mixer.stdout, encoding=self.charset, name="", mode="w" + ) + + sys.stderr = _NamedTextIOWrapper( + stream_mixer.stderr, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: str | None = None) -> str: + sys.stdout.write(prompt or "") + try: + val = next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: str | None = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + try: + return next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + old__compat_should_strip_ansi = _compat.should_strip_ansi + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + _compat.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + _compat.should_strip_ansi = old__compat_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: Command, + args: str | cabc.Sequence[str] | None = None, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + catch_exceptions: bool | None = None, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. If :data:`None`, the value + from :class:`CliRunner` is used. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + The result object has the ``output_bytes`` attribute with + the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would + see it in its terminal. + + .. versionchanged:: 8.2 + The result object always returns the ``stderr_bytes`` stream. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + if catch_exceptions is None: + catch_exceptions = self.catch_exceptions + + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: BaseException | None = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast("int | t.Any | None", e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + sys.stderr.flush() + stdout = outstreams[0].getvalue() + stderr = outstreams[1].getvalue() + output = outstreams[2].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + output_bytes=output, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: str | os.PathLike[str] | None = None + ) -> cabc.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + import shutil + + try: + shutil.rmtree(dt) + except OSError: + pass diff --git a/.venv/lib/python3.12/site-packages/click/types.py b/.venv/lib/python3.12/site-packages/click/types.py new file mode 100644 index 0000000..e71c1c2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/types.py @@ -0,0 +1,1209 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import os +import stat +import sys +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import format_filename +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + +ParamTypeValue = t.TypeVar("ParamTypeValue") + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[str | None] = None + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.NoReturn: + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name: str = func.__name__ + self.func = func + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = sys.getfilesystemencoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType, t.Generic[ParamTypeValue]): + """The choice type allows a value to be checked against a fixed set + of supported values. + + You may pass any iterable value which will be converted to a tuple + and thus will only be iterated once. + + The resulting value will always be one of the originally passed choices. + See :meth:`normalize_choice` for more info on the mapping of strings + to choices. See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + + .. versionchanged:: 8.2.0 + Non-``str`` ``choices`` are now supported. It can additionally be any + iterable. Before you were not recommended to pass anything but a list or + tuple. + + .. versionadded:: 8.2.0 + Choice normalization can be overridden via :meth:`normalize_choice`. + """ + + name = "choice" + + def __init__( + self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True + ) -> None: + self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def _normalized_mapping( + self, ctx: Context | None = None + ) -> cabc.Mapping[ParamTypeValue, str]: + """ + Returns mapping where keys are the original choices and the values are + the normalized values that are accepted via the command line. + + This is a simple wrapper around :meth:`normalize_choice`, use that + instead which is supported. + """ + return { + choice: self.normalize_choice( + choice=choice, + ctx=ctx, + ) + for choice in self.choices + } + + def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: + """ + Normalize a choice value, used to map a passed string to a choice. + Each choice must have a unique normalized value. + + By default uses :meth:`Context.token_normalize_func` and if not case + sensitive, convert it to a casefolded value. + + .. versionadded:: 8.2.0 + """ + normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(normed_value) + + if not self.case_sensitive: + normed_value = normed_value.casefold() + + return normed_value + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + if param.param_type_name == "option" and not param.show_choices: # type: ignore + choice_metavars = [ + convert_type(type(choice)).name.upper() for choice in self.choices + ] + choices_str = "|".join([*dict.fromkeys(choice_metavars)]) + else: + choices_str = "|".join( + [str(i) for i in self._normalized_mapping(ctx=ctx).values()] + ) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: + """ + Message shown when no choice is passed. + + .. versionchanged:: 8.2.0 Added ``ctx`` argument. + """ + return _("Choose from:\n\t{choices}").format( + choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) + ) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> ParamTypeValue: + """ + For a given value from the parser, normalize it and find its + matching normalized value in the list of choices. Then return the + matched "original" choice. + """ + normed_value = self.normalize_choice(choice=value, ctx=ctx) + normalized_mapping = self._normalized_mapping(ctx=ctx) + + try: + return next( + original + for original, normalized in normalized_mapping.items() + if normalized == normed_value + ) + except StopIteration: + self.fail( + self.get_invalid_choice_message(value=value, ctx=ctx), + param=param, + ctx=ctx, + ) + + def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: + """Get the error message when the given choice is invalid. + + :param value: The invalid value. + + .. versionadded:: 8.2 + """ + choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) + return ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: cabc.Sequence[str] | None = None): + self.formats: cabc.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[type[t.Any]] + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: t.Literal[1, -1], open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + if not open: + return bound + + # Could use math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + bool_states: dict[str, bool] = { + "1": True, + "0": False, + "yes": True, + "no": False, + "true": True, + "false": False, + "on": True, + "off": False, + "t": True, + "f": False, + "y": True, + "n": False, + # Absence of value is considered False. + "": False, + } + """A mapping of string values to boolean states. + + Mapping is inspired by :py:attr:`configparser.ConfigParser.BOOLEAN_STATES` + and extends it. + + .. caution:: + String values are lower-cased, as the ``str_to_bool`` comparison function + below is case-insensitive. + + .. warning:: + The mapping is not exhaustive, and does not cover all possible boolean strings + representations. It will remains as it is to avoid endless bikeshedding. + + Future work my be considered to make this mapping user-configurable from public + API. + """ + + @staticmethod + def str_to_bool(value: str | bool) -> bool | None: + """Convert a string to a boolean value. + + If the value is already a boolean, it is returned as-is. If the value is a + string, it is stripped of whitespaces and lower-cased, then checked against + the known boolean states pre-defined in the `BoolParamType.bool_states` mapping + above. + + Returns `None` if the value does not match any known boolean state. + """ + if isinstance(value, bool): + return value + return BoolParamType.bool_states.get(value.strip().lower()) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> bool: + normalized = self.str_to_bool(value) + if normalized is None: + self.fail( + _( + "{value!r} is not a valid boolean. Recognized values: {states}" + ).format(value=value, states=", ".join(sorted(self.bool_states))), + param, + ctx, + ) + return normalized + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Files can also be opened atomically in which case all writes go into a + separate file in the same folder and upon completion the file will + be moved over to the original location. This is useful if a file + regularly read by other users is modified. + + See :ref:`file-args` for more information. + + .. versionchanged:: 2.0 + Added the ``atomic`` parameter. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool | None = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: + if self.lazy is not None: + return self.lazy + if os.fspath(value) == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, + value: str | os.PathLike[str] | t.IO[t.Any], + param: Parameter | None, + ctx: Context | None, + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("str | os.PathLike[str]", value) + + try: + lazy = self.resolve_lazy_flag(value) + + if lazy: + lf = LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + if ctx is not None: + ctx.call_on_close(lf.close_intelligently) + + return t.cast("t.IO[t.Any]", lf) + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: + return hasattr(value, "read") or hasattr(value, "write") + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``path_type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: type[t.Any] | None = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name: str = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result( + self, value: str | os.PathLike[str] + ) -> str | bytes | os.PathLike[str]: + if self.type is not None and not isinstance(value, self.type): + if self.type is str: + return os.fsdecode(value) + elif self.type is bytes: + return os.fsencode(value) + else: + return t.cast("os.PathLike[str]", self.type(value)) + + return value + + def convert( + self, + value: str | os.PathLike[str], + param: Parameter | None, + ctx: Context | None, + ) -> str | bytes | os.PathLike[str]: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} {filename!r} is a directory.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: + self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple( + ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) + ) + + +def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() + + +class OptionHelpExtra(t.TypedDict, total=False): + envvars: tuple[str, ...] + default: str + range: str + required: str diff --git a/.venv/lib/python3.12/site-packages/click/utils.py b/.venv/lib/python3.12/site-packages/click/utils.py new file mode 100644 index 0000000..beae26f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/click/utils.py @@ -0,0 +1,627 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType +from types import TracebackType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: + try: + return func(*args, **kwargs) + except Exception: + pass + return None + + return update_wrapper(wrapper, func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(sys.getfilesystemencoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, + ): + self.name: str = os.fspath(filename) + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.IO[t.Any] | None + self.should_close: bool + + if self.name == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO[t.Any]: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> LazyFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close_intelligently() + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO[t.Any]) -> None: + self._file: t.IO[t.Any] = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> KeepOpenFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Any | None = None, + file: t.IO[t.Any] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + return + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: str | bytes | bytearray | None = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file, color) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: t.Literal["stdin", "stdout", "stderr"], + encoding: str | None = None, + errors: str | None = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[t.Any]: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name or Path of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast( + "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) + ) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) + + return f + + +def format_filename( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], + shorten: bool = False, +) -> str: + """Format a filename as a string for display. Ensures the filename can be + displayed by replacing any invalid bytes or surrogate escapes in the name + with the replacement character ``�``. + + Invalid bytes or surrogate escapes will raise an error when written to a + stream with ``errors="strict"``. This will typically happen with ``stdout`` + when the locale is something like ``en_GB.UTF-8``. + + Many scenarios *are* safe to write surrogates though, due to PEP 538 and + PEP 540, including: + + - Writing to ``stderr``, which uses ``errors="backslashreplace"``. + - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens + stdout and stderr with ``errors="surrogateescape"``. + - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. + - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. + Python opens stdout and stderr with ``errors="surrogateescape"``. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + else: + filename = os.fspath(filename) + + if isinstance(filename, bytes): + filename = filename.decode(sys.getfilesystemencoding(), "replace") + else: + filename = filename.encode("utf-8", "surrogateescape").decode( + "utf-8", "replace" + ) + + return filename + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no effect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO[t.Any]) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: str | None = None, _main: ModuleType | None = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # It is set to "" inside a Shiv or PEX zipapp. + if getattr(_main, "__package__", None) in {None, ""} or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: cabc.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> list[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/LICENSE b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/LICENSE new file mode 100644 index 0000000..33a7767 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Manfred Moitzi + +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. diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/METADATA b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/METADATA new file mode 100644 index 0000000..3a34c35 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/METADATA @@ -0,0 +1,285 @@ +Metadata-Version: 2.1 +Name: ezdxf +Version: 1.3.4 +Summary: A Python package to create/manipulate DXF drawings. +Author-email: Manfred Moitzi +Project-URL: Repository, https://github.com/mozman/ezdxf +Project-URL: Documentation, https://ezdxf.readthedocs.io +Project-URL: Changelog, https://ezdxf.mozman.at/notes/#/page/changelog +Project-URL: Forum, https://github.com/mozman/ezdxf/discussions +Project-URL: Issues, https://github.com/mozman/ezdxf/issues +Project-URL: Website, https://ezdxf.mozman.at +Project-URL: Download, https://pypi.org/project/ezdxf +Keywords: DXF,CAD +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Typing :: Typed +Provides: ezdxf +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: pyparsing>=2.0.1 +Requires-Dist: typing-extensions>=4.6.0 +Requires-Dist: numpy +Requires-Dist: fonttools +Provides-Extra: dev +Requires-Dist: PySide6; extra == "dev" +Requires-Dist: setuptools; extra == "dev" +Requires-Dist: wheel; extra == "dev" +Requires-Dist: Cython; extra == "dev" +Requires-Dist: pytest; extra == "dev" +Requires-Dist: Pillow; extra == "dev" +Requires-Dist: matplotlib; extra == "dev" +Requires-Dist: PyMuPDF>=1.20.0; extra == "dev" +Provides-Extra: dev5 +Requires-Dist: PyQt5; extra == "dev5" +Requires-Dist: setuptools; extra == "dev5" +Requires-Dist: wheel; extra == "dev5" +Requires-Dist: Cython; extra == "dev5" +Requires-Dist: pytest; extra == "dev5" +Requires-Dist: Pillow; extra == "dev5" +Requires-Dist: matplotlib; extra == "dev5" +Requires-Dist: PyMuPDF>=1.20.0; extra == "dev5" +Provides-Extra: draw +Requires-Dist: PySide6; extra == "draw" +Requires-Dist: matplotlib; extra == "draw" +Requires-Dist: PyMuPDF>=1.20.0; extra == "draw" +Requires-Dist: Pillow; extra == "draw" +Provides-Extra: draw5 +Requires-Dist: PyQt5; extra == "draw5" +Requires-Dist: matplotlib; extra == "draw5" +Requires-Dist: PyMuPDF>=1.20.0; extra == "draw5" +Requires-Dist: Pillow; extra == "draw5" + + +# ezdxf + +## Abstract + +This Python package is designed to facilitate the creation and manipulation of DXF +documents, with compatibility across various DXF versions. It empowers users to +seamlessly load and edit DXF files while preserving all content, except for comments. + +Any unfamiliar DXF tags encountered in the document are gracefully ignored but retained +for future modifications. This feature enables the processing of DXF documents +containing data from third-party applications without any loss of valuable information. + +## Quick-Info + +- `ezdxf` is a Python package to create new DXF files and read/modify/write + existing DXF documents +- MIT-License +- the intended audience are programmers +- requires at least Python 3.9 +- OS independent +- tested with CPython and pypy3 +- has type annotations and passes `mypy --ignore-missing-imports -p ezdxf` successful +- additional required packages for the core package without add-ons + - [typing_extensions](https://pypi.org/project/typing-extensions/) + - [pyparsing](https://pypi.org/project/pyparsing/) + - [numpy](https://pypi.org/project/numpy/) + - [fontTools](https://pypi.org/project/fonttools/) +- read/write/new support for DXF versions: R12, R2000, R2004, R2007, R2010, R2013 and R2018 +- additional read-only support for DXF versions R13/R14 (upgraded to R2000) +- additional read-only support for older DXF versions than R12 (upgraded to R12) +- read/write support for ASCII DXF and Binary DXF +- retains third-party DXF content +- optional C-extensions for CPython are included in the binary wheels, available + on [PyPI](https://pypi.org/project/ezdxf/) for Windows, Linux and macOS +- command line script `ezdxf` to display, convert and inspect DXF files + +## Included Extensions + +Additional packages required for these add-ons are not automatically installed +during the *basic* setup, for more information about the setup & dependencies +visit the [documentation](https://ezdxf.mozman.at/docs/setup.html). + +- The `drawing` add-on is a translation layer to send DXF data to a render backend, + interfaces to [matplotlib](https://pypi.org/project/matplotlib/), which can export + images as PNG, PDF or SVG, and [PyQt5](https://pypi.org/project/PyQt5/) are implemented. +- `r12writer` add-on to write basic DXF entities direct and fast into a DXF R12 + file or stream +- `iterdxf` add-on to iterate over DXF entities from the modelspace of huge DXF + files (> 5GB) which do not fit into memory +- `Importer` add-on to import entities, blocks and table entries from another DXF document +- `dxf2code` add-on to generate Python code for DXF structures loaded from DXF + documents as starting point for parametric DXF entity creation +- `acadctb` add-on to read/write plot style files (CTB/STB) +- `pycsg` add-on for basic Constructive Solid Geometry (CSG) modeling +- `MTextExplode` add-on for exploding MTEXT entities into single-line TEXT entities +- `text2path` add-on to convert text into outline paths +- `geo` add-on to support the [`__geo_interface__`](https://gist.github.com/sgillies/2217756) +- `meshex` for exchanging meshes with other tools as STL, OFF or OBJ files +- `openscad` add-on, an interface to [OpenSCAD](https://openscad.org) +- `odafc` add-on, an interface to the [ODA File Converter](https://www.opendesign.com/guestfiles/oda_file_converter) + to read and write DWG files +- `hpgl2` add-on for converting HPGL/2 plot files to DXF, SVG and PDF + +A simple example: + +```Python +import ezdxf +from ezdxf import colors +from ezdxf.enums import TextEntityAlignment + +# Create a new DXF document. +doc = ezdxf.new(dxfversion="R2010") + +# Create new table entries (layers, linetypes, text styles, ...). +doc.layers.add("TEXTLAYER", color=colors.RED) + +# DXF entities (LINE, TEXT, ...) reside in a layout (modelspace, +# paperspace layout or block definition). +msp = doc.modelspace() + +# Add entities to a layout by factory methods: layout.add_...() +msp.add_line((0, 0), (10, 0), dxfattribs={"color": colors.YELLOW}) +msp.add_text( + "Test", + dxfattribs={ + "layer": "TEXTLAYER" + }).set_placement((0, 0.2), align=TextEntityAlignment.CENTER) + +# Save the DXF document. +doc.saveas("test.dxf") +``` + +Example for the *r12writer*, which writes a simple DXF R12 file without +in-memory structures: + +```Python +from random import random +from ezdxf.addons import r12writer + +MAX_X_COORD = 1000 +MAX_Y_COORD = 1000 + +with r12writer("many_circles.dxf") as doc: + for _ in range(100000): + doc.add_circle((MAX_X_COORD*random(), MAX_Y_COORD*random()), radius=2) +``` + +The r12writer supports only the ENTITIES section of a DXF R12 drawing, no HEADER, +TABLES or BLOCKS section is present, except FIXED-TABLES are written, than some +additional predefined text styles and line types are available. + +## Installation + +Basic installation by pip including the optional C-extensions from PyPI as +binary wheels: + + pip install ezdxf + +Full installation with all dependencies (matplotlib, PySide6) for using the +drawing add-on: + + pip install ezdxf[draw] + +For more information about the setup & dependencies visit the +[documentation](https://ezdxf.mozman.at/docs/setup.html). + +## Command Line + +Use `python -m ezdxf ...` if your shell can't find the `ezdxf` script. + +Get additional help for a sub-command: + + ezdxf -h + +Preview DXF files in a graphical window: + + ezdxf view + +Export the modelspace of DXF files as PNG|SVG|PDF: + + ezdxf draw -o file. + +Print basic information about DXF files: + + ezdxf info + +Show detailed information and structures of DXF files: + + ezdxf browse + +Audit DXF files: + + ezdxf audit + +Preview and convert HPGL/2 plot files: + + ezdxf hpgl + + +## Website + +https://ezdxf.mozman.at/ + +## Documentation + +Documentation of the development version at https://ezdxf.mozman.at/docs + +Documentation of the latest release at https://ezdxf.readthedocs.io/ + +## Knowledge Graph + +The knowledge graph contains additional information beyond the documentation and is +managed by [logseq](https://logseq.com/). The source data is included in the repository +in the folder `ezdxf/notes`. There is also a [HTML export](https://ezdxf.mozman.at/notes/#/page/ezdxf) +on the website which gets regular updates. + + +## Contribution + +The source code of *ezdxf* can be found at __GitHub__, target your pull requests +to the `master` branch: + +https://github.com/mozman/ezdxf.git + + +## Feedback + +Questions and feedback at __GitHub Discussions__: + +https://github.com/mozman/ezdxf/discussions + +Questions at __Stack Overflow__: + +Post questions at [stack overflow](https://stackoverflow.com/) and use the tag `dxf` or `ezdxf`. + +Issue tracker at __GitHub__: + +http://github.com/mozman/ezdxf/issues + +## Release Notes + +The [release notes](https://ezdxf.mozman.at/notes/#/page/release%20notes) are included +in the knowledge graph. + +## Changelog + +The [changelog](https://ezdxf.mozman.at/notes/#/page/changelog) is included +in the knowledge graph. + + +## Contact + +Please __always__ post questions at the [forum](https://github.com/mozman/ezdxf/discussions) +or [stack overflow](https://stackoverflow.com/) to make answers +available to other users as well. + +ezdxf@mozman.at + +Feedback is greatly appreciated. + +Manfred diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/RECORD b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/RECORD new file mode 100644 index 0000000..46a78a1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/RECORD @@ -0,0 +1,739 @@ +../../../bin/ezdxf,sha256=MrqFTaWqCpTvt49-AO83iwvEBiuAhva0l_ih658ON5A,247 +ezdxf-1.3.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +ezdxf-1.3.4.dist-info/LICENSE,sha256=25fKQm_A0rgSQUXeDzYYHbc-bnE85kLUL-0u_EQu3xk,1071 +ezdxf-1.3.4.dist-info/METADATA,sha256=JvsiTr_73F2jWwpxXa9hUHlUHmTNsqlW7MRTJ1CZC0Q,9823 +ezdxf-1.3.4.dist-info/RECORD,, +ezdxf-1.3.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +ezdxf-1.3.4.dist-info/WHEEL,sha256=lWey-nzGdePMz7fsIJ1fIMVKiFg5IkOcUVqkuIpdbws,109 +ezdxf-1.3.4.dist-info/entry_points.txt,sha256=Mxa4CfzxalQCVrE5K4LnCmYrMHNvdVold1cn05O8MbM,46 +ezdxf-1.3.4.dist-info/top_level.txt,sha256=jDpbvSz92tkSe1t8mGnMMWQp6VOaxtRxpmcpNEWe6IM,6 +ezdxf/__init__.py,sha256=l-Yhd1UeKqpbHKGlrFPbpsZxHl398BZh5cOZ1HUW48s,3032 +ezdxf/__main__.py,sha256=HyzvMb5cKnIg2R0kEjpzYi9tVTrK5PLnTLYCQi-IAjI,3139 +ezdxf/__pycache__/__init__.cpython-312.pyc,, +ezdxf/__pycache__/__main__.cpython-312.pyc,, +ezdxf/__pycache__/_options.cpython-312.pyc,, +ezdxf/__pycache__/appsettings.cpython-312.pyc,, +ezdxf/__pycache__/audit.cpython-312.pyc,, +ezdxf/__pycache__/bbox.cpython-312.pyc,, +ezdxf/__pycache__/blkrefs.cpython-312.pyc,, +ezdxf/__pycache__/colors.cpython-312.pyc,, +ezdxf/__pycache__/commands.cpython-312.pyc,, +ezdxf/__pycache__/comments.cpython-312.pyc,, +ezdxf/__pycache__/disassemble.cpython-312.pyc,, +ezdxf/__pycache__/document.cpython-312.pyc,, +ezdxf/__pycache__/dwginfo.cpython-312.pyc,, +ezdxf/__pycache__/dynblkhelper.cpython-312.pyc,, +ezdxf/__pycache__/edgeminer.cpython-312.pyc,, +ezdxf/__pycache__/edgesmith.cpython-312.pyc,, +ezdxf/__pycache__/entitydb.cpython-312.pyc,, +ezdxf/__pycache__/enums.cpython-312.pyc,, +ezdxf/__pycache__/explode.cpython-312.pyc,, +ezdxf/__pycache__/eztypes.cpython-312.pyc,, +ezdxf/__pycache__/filemanagement.cpython-312.pyc,, +ezdxf/__pycache__/gfxattribs.cpython-312.pyc,, +ezdxf/__pycache__/graphicsfactory.cpython-312.pyc,, +ezdxf/__pycache__/groupby.cpython-312.pyc,, +ezdxf/__pycache__/messenger.cpython-312.pyc,, +ezdxf/__pycache__/msgtypes.cpython-312.pyc,, +ezdxf/__pycache__/npshapes.cpython-312.pyc,, +ezdxf/__pycache__/protocols.cpython-312.pyc,, +ezdxf/__pycache__/proxygraphic.cpython-312.pyc,, +ezdxf/__pycache__/query.cpython-312.pyc,, +ezdxf/__pycache__/queryparser.cpython-312.pyc,, +ezdxf/__pycache__/r12strict.cpython-312.pyc,, +ezdxf/__pycache__/recover.cpython-312.pyc,, +ezdxf/__pycache__/reorder.cpython-312.pyc,, +ezdxf/__pycache__/revcloud.cpython-312.pyc,, +ezdxf/__pycache__/select.cpython-312.pyc,, +ezdxf/__pycache__/transform.cpython-312.pyc,, +ezdxf/__pycache__/units.cpython-312.pyc,, +ezdxf/__pycache__/upright.cpython-312.pyc,, +ezdxf/__pycache__/urecord.cpython-312.pyc,, +ezdxf/__pycache__/version.cpython-312.pyc,, +ezdxf/__pycache__/xclip.cpython-312.pyc,, +ezdxf/__pycache__/xref.cpython-312.pyc,, +ezdxf/__pycache__/zoom.cpython-312.pyc,, +ezdxf/_options.py,sha256=Eg3jipDnqQuDjpAFN520JEcMFP6s3J-qccMo0yaXmuY,10563 +ezdxf/acc/__init__.py,sha256=6A57wOpq0goZScvZhCKsUImkapXBhRaCNDoqwunYFjY,1226 +ezdxf/acc/__pycache__/__init__.cpython-312.pyc,, +ezdxf/acc/bezier3p.c,sha256=IMhpS2dE1B1p0hH6mKWRPrKFeulOjAiZK_pFSW4Cs6U,543200 +ezdxf/acc/bezier3p.cpython-312-darwin.so,sha256=qWCI9mKAyg7bBK047pkNyAihj7P8vfdFXjZI9NXRjW8,125104 +ezdxf/acc/bezier3p.pyx,sha256=ihwT1ejKHaxy5gh3lp6j5eQiPIAaB43vn2_8wCtjr5Y,6566 +ezdxf/acc/bezier4p.c,sha256=fx_Tq0X5K_4aqkD-mRDIPLbBy919-W_KTjRBzvuQ7nI,751078 +ezdxf/acc/bezier4p.cpython-312-darwin.so,sha256=tVVMWjYb209GtAuKByYpVZiBRXuJuNm87LNBdAuNuVs,167008 +ezdxf/acc/bezier4p.pyx,sha256=c-tlaAi-lFzBGUNa6kodAca3EtuBOYzk9N0gbIMps5s,11131 +ezdxf/acc/bspline.c,sha256=PMsu_KQPuNygvd5R0aTCqMIsOefysiVfvmzuPkYTtzA,774387 +ezdxf/acc/bspline.cpython-312-darwin.so,sha256=fxbFj9lxGlUde5S77Y2r2Rq9cKM_i2zmE6uddErYXek,183840 +ezdxf/acc/bspline.pyx,sha256=0OcZaMvTz77kqyFVsXaY3N7_B4BUvM7sjpVNfewQi5g,13648 +ezdxf/acc/constants.h,sha256=JvAaWl6LBubuuZMh18Zu1PLbjwJvEFoIhObY_S9vMY8,244 +ezdxf/acc/construct.c,sha256=nx4q4kw6DfqYg8UDfAeiYIyYCs2lvFN1ASuGESO7iK8,469847 +ezdxf/acc/construct.cpython-312-darwin.so,sha256=KM3aAyXbecTpeh0mD6V3uYuCZcJi361xPLeTm130BMo,121264 +ezdxf/acc/construct.pyx,sha256=H4anrrevB2HI-0kY9B9Td5FnqmuTS8ujyH3kKK2N8_w,11486 +ezdxf/acc/linetypes.c,sha256=LkQVlvkdstygjn3C4Fjjwa1nPNKpuuNe1RX9ZyOz-HY,448437 +ezdxf/acc/linetypes.cpython-312-darwin.so,sha256=jgme2H-ik25VDcqM9PaWNEJ9UAiH-WIAbwHbcwWEV7k,124784 +ezdxf/acc/linetypes.pyx,sha256=msIJPqEpnsQGc7ktLe8K6YrV-8_XKKtJFz6hMQM5b5Y,3070 +ezdxf/acc/mapbox_earcut.c,sha256=tfnjVCwBdQS1M9-djWMKCCfmTYyMdo32Z6zYJMWC23A,592444 +ezdxf/acc/mapbox_earcut.cpython-312-darwin.so,sha256=klW5wgW3ZC5fbNQ4R6z4Xc2w--jtyIQgNeOprHDTxds,118272 +ezdxf/acc/mapbox_earcut.pyx,sha256=qHE8ukGi7NCHGqLRZZiNdtYFtthVwiVBgBvsYzsSjxk,23141 +ezdxf/acc/matrix44.c,sha256=D3CRAerATrsc01vPnD1aBshEgAaH3XDe1zLvjIt_VWg,1823919 +ezdxf/acc/matrix44.cpython-312-darwin.so,sha256=d0QJxCBd40cP_TfRCRj6GkFOslfxZ8R1_b-1Dwp-n3o,347520 +ezdxf/acc/matrix44.pxd,sha256=JJCSLlwXknv1r-r1GUMQhZcCh3fA1QWrk7Pxp9mlvUU,371 +ezdxf/acc/matrix44.pyx,sha256=jMGw9Ug64Cz44c6dLB2_29OKK2FcJ9pQD69QNItd1b8,23027 +ezdxf/acc/np_support.c,sha256=NUPOqxzfvT621_ffys5RK8F__vpeH_f3jEvcFmB55j4,1091468 +ezdxf/acc/np_support.cpython-312-darwin.so,sha256=R_V78o5OupqzTc1vx7tb0bbq79xoPL7MPqBLRugukyQ,223136 +ezdxf/acc/np_support.pyx,sha256=z74akgfzYIE4eZi_nNC1F_es3p6Zknd2M4pnaETutK4,4528 +ezdxf/acc/vector.c,sha256=IGWMhPQrtRll8ByLjdSHsweb65TL3Ux3P2xgFyqKWc8,1282307 +ezdxf/acc/vector.cpython-312-darwin.so,sha256=jm-xn2NznFrAuK70QMX7_9ttBQJVZG_lT1V5Nq2Vi7k,249744 +ezdxf/acc/vector.pxd,sha256=iV_NNQ2_Wfzju7RXEvQO3v-KH4F6Q7ttONthWXnNRgA,1670 +ezdxf/acc/vector.pyx,sha256=1DjzL8d_c7BkXfnF6GT-jvPV20JODFKDMtEgJvEWtCw,22539 +ezdxf/acis/__init__.py,sha256=LumXqj8kBH6TrgmoqgF88LmTWRsnh8vR4YyqxkoGGrE,117 +ezdxf/acis/__pycache__/__init__.cpython-312.pyc,, +ezdxf/acis/__pycache__/abstract.cpython-312.pyc,, +ezdxf/acis/__pycache__/api.cpython-312.pyc,, +ezdxf/acis/__pycache__/cache.cpython-312.pyc,, +ezdxf/acis/__pycache__/const.cpython-312.pyc,, +ezdxf/acis/__pycache__/dbg.cpython-312.pyc,, +ezdxf/acis/__pycache__/dxf.cpython-312.pyc,, +ezdxf/acis/__pycache__/entities.cpython-312.pyc,, +ezdxf/acis/__pycache__/hdr.cpython-312.pyc,, +ezdxf/acis/__pycache__/mesh.cpython-312.pyc,, +ezdxf/acis/__pycache__/sab.cpython-312.pyc,, +ezdxf/acis/__pycache__/sat.cpython-312.pyc,, +ezdxf/acis/__pycache__/type_hints.cpython-312.pyc,, +ezdxf/acis/abstract.py,sha256=mmt82FvfnrWvsGShzdlJD93vo0lBje54fZu88mrmbzk,6174 +ezdxf/acis/api.py,sha256=P2NVgPyVi4k2PwXHg3P8GNDkXPsgK7g7BTp3HOKHwGk,907 +ezdxf/acis/cache.py,sha256=zNjDI0gTbD5pQaYlYkPZ0fUfGqzg21elBNuW-FXXbtQ,1733 +ezdxf/acis/const.py,sha256=CsXe8jKlXNTLb0kDvU6f5A16koSyPr0hJDE3pj6gDJU,5306 +ezdxf/acis/dbg.py,sha256=Z9MbCH3_unno26gjNTo95vHRzDbRjHF63dY_KNDybGI,6538 +ezdxf/acis/dxf.py,sha256=OVioKoHjkmZzAWuHYOBVbUFx7RFkojt1fiB4tCGgY1o,2903 +ezdxf/acis/entities.py,sha256=YRN-J3RuPzs-MiVqorOysB6_pvPaLnsUyr5CQATnMGg,27948 +ezdxf/acis/hdr.py,sha256=jRQ4KN0ewrZWWYEd9c2PCu3fIBQGvfkNNOZMAFUZMos,3983 +ezdxf/acis/mesh.py,sha256=m-MrPh9HG5bod5Fjjq8ORpD_Bx1lJzBcKYAiBtgP3ns,15151 +ezdxf/acis/sab.py,sha256=VPIm6ybeIDppWJonhYQuhYidUKW32ML3KkIckI1aOTI,18168 +ezdxf/acis/sat.py,sha256=OqCuajqhLBWYrIQKColyIiid0tnt1AieJwVy9EaEIFI,12758 +ezdxf/acis/type_hints.py,sha256=DIpayCTj0vwEhJTBpGTkydblbh_U_jKED4pswkqTCEA,240 +ezdxf/addons/__init__.py,sha256=3ZTRNtrdtox-5wq1jKu4Vcgzjm-1IMgDgymuMM5xqZY,443 +ezdxf/addons/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/__pycache__/acadctb.cpython-312.pyc,, +ezdxf/addons/__pycache__/binpacking.cpython-312.pyc,, +ezdxf/addons/__pycache__/dimlines.cpython-312.pyc,, +ezdxf/addons/__pycache__/dxf2code.cpython-312.pyc,, +ezdxf/addons/__pycache__/genetic_algorithm.cpython-312.pyc,, +ezdxf/addons/__pycache__/geo.cpython-312.pyc,, +ezdxf/addons/__pycache__/gerber_D6673.cpython-312.pyc,, +ezdxf/addons/__pycache__/importer.cpython-312.pyc,, +ezdxf/addons/__pycache__/iterdxf.cpython-312.pyc,, +ezdxf/addons/__pycache__/menger_sponge.cpython-312.pyc,, +ezdxf/addons/__pycache__/meshex.cpython-312.pyc,, +ezdxf/addons/__pycache__/mixins.cpython-312.pyc,, +ezdxf/addons/__pycache__/mtextsurrogate.cpython-312.pyc,, +ezdxf/addons/__pycache__/mtxpl.cpython-312.pyc,, +ezdxf/addons/__pycache__/odafc.cpython-312.pyc,, +ezdxf/addons/__pycache__/openscad.cpython-312.pyc,, +ezdxf/addons/__pycache__/pycsg.cpython-312.pyc,, +ezdxf/addons/__pycache__/r12export.cpython-312.pyc,, +ezdxf/addons/__pycache__/r12writer.cpython-312.pyc,, +ezdxf/addons/__pycache__/sierpinski_pyramid.cpython-312.pyc,, +ezdxf/addons/__pycache__/tablepainter.cpython-312.pyc,, +ezdxf/addons/__pycache__/text2path.cpython-312.pyc,, +ezdxf/addons/__pycache__/xplayer.cpython-312.pyc,, +ezdxf/addons/__pycache__/xqt.cpython-312.pyc,, +ezdxf/addons/acadctb.py,sha256=mU1IXPnJDcvhnJP-EqB_QZQI2sRM6ZdSzaUWKr_3Ve8,25987 +ezdxf/addons/acisbrowser/__init__.py,sha256=fDQ7wDl4R_pMX_CHJ5O6JUZLoBm04YcquUR9AkVLE7o,62 +ezdxf/addons/acisbrowser/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/acisbrowser/__pycache__/browser.cpython-312.pyc,, +ezdxf/addons/acisbrowser/__pycache__/data.cpython-312.pyc,, +ezdxf/addons/acisbrowser/browser.py,sha256=looDJfme-RFIKpl5wES1mfh2d-sMuJLyY1qpGZ9TcRs,9678 +ezdxf/addons/acisbrowser/data.py,sha256=yKG_W9UBrEoSRDaRXn-hUmsz2iuH0r-f_-WIOYfYZSs,1847 +ezdxf/addons/binpacking.py,sha256=sVXSxqCJyzJiyVpXkJwKT9NclxUL2lTqZ-K8zW57skA,21513 +ezdxf/addons/browser/__init__.py,sha256=_o3jB7kZd9z_tFemgVWbxDzwLnGzrS8rlYR5NgvW0TE,127 +ezdxf/addons/browser/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/bookmarks.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/browser.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/data.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/find_dialog.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/loader.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/model.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/reflinks.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/tags.cpython-312.pyc,, +ezdxf/addons/browser/__pycache__/views.cpython-312.pyc,, +ezdxf/addons/browser/bookmarks.py,sha256=i5V3NdlaDuPnWjCP7a7alSEJH84SSu2vW1px_chjTis,787 +ezdxf/addons/browser/browser.py,sha256=PT4DyYSfqn7__d9xDc0lwMmsYtzJUYN6cKkIaE2SXxk,28551 +ezdxf/addons/browser/data.py,sha256=7zhv0KQuQKRQG7MevLbVfxzygtNMShKzQM8ievjjKfk,14463 +ezdxf/addons/browser/find_dialog.py,sha256=FfI3ChEb7nhc8bjX3RKLofQL1Q8rD9rKhwMdVOiCyVg,10822 +ezdxf/addons/browser/loader.py,sha256=2KntX9NQQReA3aE3J6Jseyx0FzgrYauQTiscqKy4PQk,1213 +ezdxf/addons/browser/model.py,sha256=nt01snJSUl9BHBA2Kmmrls6CcrcLtA0W-i1cevZLL4o,20537 +ezdxf/addons/browser/reflinks.py,sha256=LzG_KS6oARzt_pnP7ntikL43ccZgrZ7v8-hJOPd_yKo,6779 +ezdxf/addons/browser/tags.py,sha256=k2I5OpMz-aabPpgrdFcrZ0wlMS176w_BSDcl_sGacJo,2143 +ezdxf/addons/browser/views.py,sha256=kcwiwWTq-AEA8tmphX0eTndgS4b3QdJWbY952P3xAOk,1325 +ezdxf/addons/dimlines.py,sha256=2pgQWfIn3sgIN6FUSHRjzl-ducvubcSxgyqBfsEjo1Q,26926 +ezdxf/addons/drawing/__init__.py,sha256=K_I-4w71JrpVZDAYaqOVCgUPcAAQITDoQlLkaWp5D50,166 +ezdxf/addons/drawing/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/backend.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/config.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/debug_backend.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/debug_utils.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/dxf.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/file_output.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/frontend.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/gfxproxy.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/hpgl2.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/json.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/layout.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/matplotlib.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/mtext_complex.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/pipeline.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/properties.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/pymupdf.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/pyqt.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/qtviewer.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/recorder.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/svg.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/text.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/text_renderer.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/type_hints.cpython-312.pyc,, +ezdxf/addons/drawing/__pycache__/unified_text_renderer.cpython-312.pyc,, +ezdxf/addons/drawing/backend.py,sha256=7keMHuK3GStQXF1BdCX2XZFvlbJSkPcUE593FtvmNTg,9000 +ezdxf/addons/drawing/config.py,sha256=2w23wH-vNo9qoBvfHIQqLofQZOGQ6xj0KHOG_UOgv4k,10821 +ezdxf/addons/drawing/debug_backend.py,sha256=Ll2KVaB0pddQV4P5DDtqsy_lfvJJiAx_ThsvOWutNUM,1704 +ezdxf/addons/drawing/debug_utils.py,sha256=JSikPHVsjZioPA4FiibbMObZ0ZdkUp8ABfzz9s03WdQ,499 +ezdxf/addons/drawing/dxf.py,sha256=7RIhjXpCrA9lEmEznFRRX0N93-yLbk9v_wMv1aCjczc,7168 +ezdxf/addons/drawing/file_output.py,sha256=n3W57_y6eDgo_K_dSktcU-o7-RAteteDDoxvjuwLJ7k,7525 +ezdxf/addons/drawing/frontend.py,sha256=kg8BZiAE3y3_XMy912fwqGIcTNfhVPjq-3q-mYf3sv4,43729 +ezdxf/addons/drawing/gfxproxy.py,sha256=DwEorryhbImnG2D1GpOuwe0hqX_7kczVU_9m6WlD18A,1829 +ezdxf/addons/drawing/hpgl2.py,sha256=_u_bnNcpowhlZzKgRPq33y10F-bJg7wJ_4Vz2fdViY8,20285 +ezdxf/addons/drawing/json.py,sha256=GAyiPfiKjxPybN4tPv3YJOxF2OrjYuDMT-IbW2oo4Pg,19511 +ezdxf/addons/drawing/layout.py,sha256=tdCszLGNbVvOKlORpHu6XpEYi0UxF6cTk6jPrMc5SUY,18440 +ezdxf/addons/drawing/matplotlib.py,sha256=qdC9MqanMEr3WCXtEq0VodknJDdmjt_sk2TGWobzPmY,12848 +ezdxf/addons/drawing/mtext_complex.py,sha256=5i7BglzBsn8Fj9QiPejp-y3a_P8oVCvGdKSfihr0ZPM,9552 +ezdxf/addons/drawing/pipeline.py,sha256=eea6aHGU_nQQqApQZcylkFhxFQzFyK8sU_PDW8eb_Mc,31559 +ezdxf/addons/drawing/properties.py,sha256=Ac3Pk7-7XeRWJZzkkI9G2i1UZ8Ck8Xx4OvQ4d5Y1h7c,39281 +ezdxf/addons/drawing/pymupdf.py,sha256=0p4MRGRO2QdgvVfoH-XMxqgg_qTVBUhjJDz_PrXELQQ,18497 +ezdxf/addons/drawing/pyqt.py,sha256=cVV9WPNwKT4ufhHgJWchoZt2pIOAOhO43RxwF011MFE,11263 +ezdxf/addons/drawing/qtviewer.py,sha256=vxImoyAaIJ9LNvVnHh6DcsFmpx--yPFqyB1t3Xw1FHs,22090 +ezdxf/addons/drawing/recorder.py,sha256=t9ILNwzzz_KmdVdYCKkme4rlRCeUedP23u1d693_DQE,15987 +ezdxf/addons/drawing/svg.py,sha256=xeyBSTIqNNaqQf1PgL-HVUcOEqZp42ZgavG7CY5Lktg,15801 +ezdxf/addons/drawing/text.py,sha256=h1R96mdiAArLnCsbvAydk2Mv5WST6LRpdhjKwqofD6A,12672 +ezdxf/addons/drawing/text_renderer.py,sha256=l9lmBBozkMgCXhX7cDlai7GirVjsb8yGrzgrfmauXS4,1148 +ezdxf/addons/drawing/type_hints.py,sha256=QQ2OqbTyJaIr7gYoW0rwy63cBGQaBngzIjyXamLgmss,304 +ezdxf/addons/drawing/unified_text_renderer.py,sha256=aZDlUJq69eu_C2AtkXkEzH8pCylDYl6o8apQoVQW5ao,2487 +ezdxf/addons/dwg/__init__.py,sha256=EVNuNTgPsO8UKaKEvmPMlwC2AbYN4b88JYwpxceo6g4,136 +ezdxf/addons/dwg/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/classes_section.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/const.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/crc.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/fileheader.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/header_section.cpython-312.pyc,, +ezdxf/addons/dwg/__pycache__/loader.cpython-312.pyc,, +ezdxf/addons/dwg/classes_section.py,sha256=ywuE7vTLFBYZUW9GlJ0Rf3iHfOprLGIbAWtiv1Q7t1I,3030 +ezdxf/addons/dwg/const.py,sha256=L3qzZmbhyFzuQpIOgmYuk8a2Y1R-O5_v-1Yu5yLkvrw,718 +ezdxf/addons/dwg/crc.py,sha256=Ka6mHI8O8zSjxyNB_aVWWLurncUuRjX3BMv_oWvVsig,6008 +ezdxf/addons/dwg/fileheader.py,sha256=dUEKVFaPPqjwaKv5R8lEGiQZQP18s3jzLvtzs5oiwfQ,3068 +ezdxf/addons/dwg/header_section.py,sha256=GLAlCf_LiE-Cncp6tJUv2EShqrAkefkkWOfEMRO02Is,14194 +ezdxf/addons/dwg/loader.py,sha256=yPXw2aBp0nAgyUE17cJwcIJCn2myfolopiNjeWnhurA,2888 +ezdxf/addons/dxf2code.py,sha256=x2Q4bUkI0adUJ0K80kDfaaUZW59oCLSFQCXaHDP7Zdk,30793 +ezdxf/addons/genetic_algorithm.py,sha256=o0T2LQX_albB0L7n3chdLOQTgfsENAXzP8cWBg2VVAQ,21284 +ezdxf/addons/geo.py,sha256=usgF926NEt8_FNluXMohWNo9En__rqJgvAZ7zeJdEIU,37351 +ezdxf/addons/gerber_D6673.py,sha256=lR0fNB43TulhlSOKVHpVvYobSGTlvV9lFYUefyUdSUE,2605 +ezdxf/addons/hpgl2/__init__.py,sha256=AzF9D_tSprdO4wjFUDH_aTI-5MiIVABghLuBRESreII,157 +ezdxf/addons/hpgl2/__pycache__/__init__.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/api.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/backend.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/deps.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/interpreter.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/page.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/plotter.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/polygon_buffer.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/properties.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/tokenizer.cpython-312.pyc,, +ezdxf/addons/hpgl2/__pycache__/viewer.cpython-312.pyc,, +ezdxf/addons/hpgl2/api.py,sha256=0aaWqx7ZySnJQCZ2BUXLkEO6MBpHaMzM1jz5pvaYLEA,13045 +ezdxf/addons/hpgl2/backend.py,sha256=w_MjDeivmhf0iL-nOI2jVEUK7dxTRC3gc5oTo4J6pFY,8317 +ezdxf/addons/hpgl2/deps.py,sha256=88PMt_a4o9NH-qWddTh3Sz48xvNBGRFRQwG3T7IQUCE,548 +ezdxf/addons/hpgl2/interpreter.py,sha256=HvR0DuZ3gLL2i1rvlBkgkZi8CeGcpOVTitq8eAYhLkk,15621 +ezdxf/addons/hpgl2/page.py,sha256=SdBo7SMlutgXIkoN8DAwmtTqkLtv0KXl7z7tmu9C1FM,4702 +ezdxf/addons/hpgl2/plotter.py,sha256=LMMFpcEpwU9ugSJqto1XyByL6oAHLonHOGMXxQyEOY0,11451 +ezdxf/addons/hpgl2/polygon_buffer.py,sha256=yratUhVxEmoXEEkCJuCUdxVzmrYwBC-qIhwPa_yK0Co,1645 +ezdxf/addons/hpgl2/properties.py,sha256=hDcKIjr0NZq7WOZkoDfm-T-oL2vnmAaZsabFulTehA8,5440 +ezdxf/addons/hpgl2/tokenizer.py,sha256=n_kI7WbgB9AzvCLPEeKljIAGi6i02o1JtDoFaXqskNU,5998 +ezdxf/addons/hpgl2/viewer.py,sha256=DOKuRtzz61ej3bRg2vQIn9q6s-e47jzdJqnIoFkFkbs,18913 +ezdxf/addons/importer.py,sha256=ohK991QxqYi0w9UOyDT3ArJO9qQ4k1B_n6GjpYdb0gM,24808 +ezdxf/addons/iterdxf.py,sha256=7ZZRWHB0l3cidXb4JXmH4JD2FrSxl8yVRozH_AGxuO4,16875 +ezdxf/addons/menger_sponge.py,sha256=bAmGtdamYclv025bMPFg7UACimYeP9aUl6CFlkONFA0,8680 +ezdxf/addons/meshex.py,sha256=vQ5XSLbvESMb6zFKzgqOLjy2ZFjXVef0dqc7GV4pnPU,24112 +ezdxf/addons/mixins.py,sha256=kVnpr8H1vZgT9lG48892djBcQn0uWhZ9J0sWYPku_Po,473 +ezdxf/addons/mtextsurrogate.py,sha256=shNC-qeYwWm0jmkDQyHsY5FyQ9nwoJR-OOkvCLv0_TQ,6029 +ezdxf/addons/mtxpl.py,sha256=U45waek-UG7p7b2nn1XYZnIt3H-VtTsIPXihdq6dpNc,13140 +ezdxf/addons/odafc.py,sha256=tZXwwgFfIDcjveSz2_yN7N2mtkgbn5_IQFbdQGLUd-s,15852 +ezdxf/addons/openscad.py,sha256=dA7SaiD0AvKmZW7uiyvpjDnlaS3g_FsxwSI0tf_YJNs,9389 +ezdxf/addons/pycsg.py,sha256=mDhsSSxcj1EOdkzUh06DvsyvqXvOSXP0broWoz4_cGU,15434 +ezdxf/addons/r12export.py,sha256=ujk6ogAW1O1oNJOOCWzTiCaP3GqFfc02UWaNi0SquNk,21665 +ezdxf/addons/r12writer.py,sha256=MEghiMHb0NSTkrnGdNHf5SoJhiRym0ZES91C6b8MbxA,25958 +ezdxf/addons/sierpinski_pyramid.py,sha256=8tIedR9aVCoM2uMEylTupbJViy5KzEEIZZ8sE1gN8ZE,7370 +ezdxf/addons/tablepainter.py,sha256=XOjwM5NGspmArCJGNiS36LLFg7dDntxuMNAYhTC465o,32240 +ezdxf/addons/text2path.py,sha256=4raio53vMolTbhewzK5CZBtB4lv1oUptGPPVD0gvbi8,12410 +ezdxf/addons/xplayer.py,sha256=vqAphNOmQo8Ji6xnPh7MyMhO4IQhWuc1l73HRaPVKzg,3245 +ezdxf/addons/xqt.py,sha256=FSQTMjHP8n4lHVJarU1KBJLQt4HbyQT6TfVPxPg4CKU,2226 +ezdxf/appsettings.py,sha256=fDIfzyGSg0br_focwxmb-0JBGGxzYBP3SqyTu6llsFs,4700 +ezdxf/audit.py,sha256=4cYR0Imvqye4XdvVmH-uzHfnc2aW2zo5lVI49OnpF7Q,19431 +ezdxf/bbox.py,sha256=qv22ZlNcsFTutFU8xH07-DhanQL42c1XELf49KiuCec,5149 +ezdxf/blkrefs.py,sha256=JLmBDulumxxMimVmBFZ6Fl8J50_NoqzOD9-tOIVuPdw,7663 +ezdxf/colors.py,sha256=aFCJ1REK8I2y7FVD3l6XOOMm6Pwzvun39E7xEez5w_M,16258 +ezdxf/commands.py,sha256=RHL-HCy3G01un6q902xf_vi323BohTtVeJOcWlu3s38,32580 +ezdxf/comments.py,sha256=JGfD8EgJWP4AP4HK3YRJFeFFG56HMjac0N5nHTCL4Vg,1506 +ezdxf/disassemble.py,sha256=sgsgPXzptUL3GCphOnG65bQLyLtZqhU6aAmSGH5yeG8,21694 +ezdxf/document.py,sha256=HVAeusZO8pnFVVzy972F3Ytbekq4XHaWeeBicpoF01A,53771 +ezdxf/dwginfo.py,sha256=iI5SraX7TeoXVnVx3fcYd_5l8FjcQivMI0MybGJKlic,805 +ezdxf/dynblkhelper.py,sha256=4RRe4SOtBnVQylmkFLuZ8YVNEECYGbMz2OEEVHooxZo,2405 +ezdxf/edgeminer.py,sha256=dlEBG8z6NH7mC2flFzuWLhdXfFGL56Ct0S2YYgtwmno,39137 +ezdxf/edgesmith.py,sha256=CNtHWF71WoeF6zIU7T9WKQUyEuPOaq5ZbEZjjjijkUk,11266 +ezdxf/entities/__init__.py,sha256=PaYCbFiZLDYWoeYQemKnjdztvzI-MgcGZiKTIfRice8,3080 +ezdxf/entities/__pycache__/__init__.cpython-312.pyc,, +ezdxf/entities/__pycache__/acad_proxy_entity.cpython-312.pyc,, +ezdxf/entities/__pycache__/acad_table.cpython-312.pyc,, +ezdxf/entities/__pycache__/acad_xrec_roundtrip.cpython-312.pyc,, +ezdxf/entities/__pycache__/acis.cpython-312.pyc,, +ezdxf/entities/__pycache__/appdata.cpython-312.pyc,, +ezdxf/entities/__pycache__/appid.cpython-312.pyc,, +ezdxf/entities/__pycache__/arc.cpython-312.pyc,, +ezdxf/entities/__pycache__/attrib.cpython-312.pyc,, +ezdxf/entities/__pycache__/block.cpython-312.pyc,, +ezdxf/entities/__pycache__/blockrecord.cpython-312.pyc,, +ezdxf/entities/__pycache__/boundary_paths.cpython-312.pyc,, +ezdxf/entities/__pycache__/circle.cpython-312.pyc,, +ezdxf/entities/__pycache__/copy.cpython-312.pyc,, +ezdxf/entities/__pycache__/dictionary.cpython-312.pyc,, +ezdxf/entities/__pycache__/dimension.cpython-312.pyc,, +ezdxf/entities/__pycache__/dimstyle.cpython-312.pyc,, +ezdxf/entities/__pycache__/dimstyleoverride.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfclass.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfentity.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfgfx.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfgroups.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfns.cpython-312.pyc,, +ezdxf/entities/__pycache__/dxfobj.cpython-312.pyc,, +ezdxf/entities/__pycache__/ellipse.cpython-312.pyc,, +ezdxf/entities/__pycache__/factory.cpython-312.pyc,, +ezdxf/entities/__pycache__/geodata.cpython-312.pyc,, +ezdxf/entities/__pycache__/gradient.cpython-312.pyc,, +ezdxf/entities/__pycache__/hatch.cpython-312.pyc,, +ezdxf/entities/__pycache__/helix.cpython-312.pyc,, +ezdxf/entities/__pycache__/idbuffer.cpython-312.pyc,, +ezdxf/entities/__pycache__/image.cpython-312.pyc,, +ezdxf/entities/__pycache__/insert.cpython-312.pyc,, +ezdxf/entities/__pycache__/layer.cpython-312.pyc,, +ezdxf/entities/__pycache__/layout.cpython-312.pyc,, +ezdxf/entities/__pycache__/leader.cpython-312.pyc,, +ezdxf/entities/__pycache__/light.cpython-312.pyc,, +ezdxf/entities/__pycache__/line.cpython-312.pyc,, +ezdxf/entities/__pycache__/ltype.cpython-312.pyc,, +ezdxf/entities/__pycache__/lwpolyline.cpython-312.pyc,, +ezdxf/entities/__pycache__/material.cpython-312.pyc,, +ezdxf/entities/__pycache__/mesh.cpython-312.pyc,, +ezdxf/entities/__pycache__/mleader.cpython-312.pyc,, +ezdxf/entities/__pycache__/mline.cpython-312.pyc,, +ezdxf/entities/__pycache__/mpolygon.cpython-312.pyc,, +ezdxf/entities/__pycache__/mtext.cpython-312.pyc,, +ezdxf/entities/__pycache__/mtext_columns.cpython-312.pyc,, +ezdxf/entities/__pycache__/objectcollection.cpython-312.pyc,, +ezdxf/entities/__pycache__/oleframe.cpython-312.pyc,, +ezdxf/entities/__pycache__/pattern.cpython-312.pyc,, +ezdxf/entities/__pycache__/point.cpython-312.pyc,, +ezdxf/entities/__pycache__/polygon.cpython-312.pyc,, +ezdxf/entities/__pycache__/polyline.cpython-312.pyc,, +ezdxf/entities/__pycache__/shape.cpython-312.pyc,, +ezdxf/entities/__pycache__/solid.cpython-312.pyc,, +ezdxf/entities/__pycache__/spatial_filter.cpython-312.pyc,, +ezdxf/entities/__pycache__/spline.cpython-312.pyc,, +ezdxf/entities/__pycache__/subentity.cpython-312.pyc,, +ezdxf/entities/__pycache__/sun.cpython-312.pyc,, +ezdxf/entities/__pycache__/table.cpython-312.pyc,, +ezdxf/entities/__pycache__/temporary_transform.cpython-312.pyc,, +ezdxf/entities/__pycache__/text.cpython-312.pyc,, +ezdxf/entities/__pycache__/textstyle.cpython-312.pyc,, +ezdxf/entities/__pycache__/tolerance.cpython-312.pyc,, +ezdxf/entities/__pycache__/ucs.cpython-312.pyc,, +ezdxf/entities/__pycache__/underlay.cpython-312.pyc,, +ezdxf/entities/__pycache__/view.cpython-312.pyc,, +ezdxf/entities/__pycache__/viewport.cpython-312.pyc,, +ezdxf/entities/__pycache__/visualstyle.cpython-312.pyc,, +ezdxf/entities/__pycache__/vport.cpython-312.pyc,, +ezdxf/entities/__pycache__/xdata.cpython-312.pyc,, +ezdxf/entities/__pycache__/xdict.cpython-312.pyc,, +ezdxf/entities/__pycache__/xline.cpython-312.pyc,, +ezdxf/entities/acad_proxy_entity.py,sha256=k0Txnw3JwrNyrdc-Sa0ESxFHG7qvaU7X2Sc5J9s1V5s,5563 +ezdxf/entities/acad_table.py,sha256=ZiCdFQk3AI8Lw4fJyqVBjCavTiAXUKsv-fvKTkr0n_8,21102 +ezdxf/entities/acad_xrec_roundtrip.py,sha256=cun_M61SUwiZRb7GCxmZg3bbOY8jHxVOGZo4okFtCrI,2751 +ezdxf/entities/acis.py,sha256=ZePkt3TzXVdQQlDPg7iSjnwMgZv5lktCeoNbG_GEHYw,29430 +ezdxf/entities/appdata.py,sha256=LJGmiIQVAdmVHG1J0Fuqabd1NVdokgnUBbARcoFrh_I,4847 +ezdxf/entities/appid.py,sha256=5e9cgFB7VCu-WC1xq6XkK4WYI4k4DOBV0AEyzCbL1BQ,1892 +ezdxf/entities/arc.py,sha256=jTsVeQgl0ZJW435gqIRx-hrn-u4iDhOaO-HSRvZdwCU,4794 +ezdxf/entities/attrib.py,sha256=gko-sq0SwO6Zk8B1iVg2eLFhmyVbOA8uOVU1Zz3PtPA,26382 +ezdxf/entities/block.py,sha256=KMnroNxI7ThnMqjXbDMVQHNRqVH0GRmJq-aCaK6B0W4,8704 +ezdxf/entities/blockrecord.py,sha256=4dyR9zqtWRbqI1hLvHFi4wQEY4Ny9PXvgyd0iRjK53A,10271 +ezdxf/entities/boundary_paths.py,sha256=2K0orVr0iZ16HcyyFSTJbg7G-t_APfM3-4M1jSmHXbQ,49637 +ezdxf/entities/circle.py,sha256=g2JRPzcEnvU9_ymmkN4pDyGujJvGsXhYCsO3ZhnXdp0,7715 +ezdxf/entities/copy.py,sha256=weAQSpuusAM_wJath0snmIwFO_mAJ6Iurxj3dqCW2v4,3112 +ezdxf/entities/dictionary.py,sha256=hPavwKBJBrouu0KzUU1-UjGhGY7W_C-EFa3y_77c9Hk,24293 +ezdxf/entities/dimension.py,sha256=Onz4OBAclhdTq0L1kSV2RSCVUBXunFytAWN8eCHmpzs,47487 +ezdxf/entities/dimstyle.py,sha256=lYbb5XWfWMVxu30ytYnFKe0DcD5RRqh36s8wygmOQ18,34084 +ezdxf/entities/dimstyleoverride.py,sha256=qy8zAzMnmyuwkDKVsXUTCY2b8HwqMX_p3pMQWoHIxLQ,23230 +ezdxf/entities/dxfclass.py,sha256=qsbi4-BrnseE4BbggY274U2HJ70VYqG3qfPzMZTP7tY,4276 +ezdxf/entities/dxfentity.py,sha256=uqSLjt9FzqDp8x4iwi2yaM2dggMTv7vTgupOocmqG8c,39499 +ezdxf/entities/dxfgfx.py,sha256=QW7jqF9cv5vIkdokibZJHDEMncIsXMFFe4H__-zBIew,26572 +ezdxf/entities/dxfgroups.py,sha256=JZF-UHNQwMnQKGXWg-qTUyv7QwuMRYOdmqQ15stsOoA,16016 +ezdxf/entities/dxfns.py,sha256=dOJPUPJtEzMn6nWJcpkOwNZWEw0Erwdye3MGJwKQaJ0,23031 +ezdxf/entities/dxfobj.py,sha256=RCb8vA-RBv_eJI1D6a68u0pQ6dsDTidHirTgmI8MxZw,13510 +ezdxf/entities/ellipse.py,sha256=gufHDNWF2JNA_Myy3MWAbzlrqk3KYU7ufJyLr2WA9hs,10866 +ezdxf/entities/factory.py,sha256=vqveDMuzM7YrJP5lz-JpUno5OXL47mQLUHVKoRY31j0,4002 +ezdxf/entities/geodata.py,sha256=mLJ2eW8csUJ-nt-9l5AZvGEctf_wUKZjTXMw84nk5FU,23124 +ezdxf/entities/gradient.py,sha256=airxBqEOMd31VJEov1Hlox6fL3ej_Wp7HTA9CIS0w6E,3902 +ezdxf/entities/hatch.py,sha256=n__tR1h50jil-GkSGrG37VPUTgBBkzlCgqDk0mm26x8,11940 +ezdxf/entities/helix.py,sha256=lDStumPEGF0q9i9O-VmpKQgmhBI7Gx3Sg9wCB5wCvR4,3822 +ezdxf/entities/idbuffer.py,sha256=L9O-YOZSedI9G2qAhEpONSJ5MNCNN_6ZLcVnB1i4wZo,4699 +ezdxf/entities/image.py,sha256=q6nDqESS4MxHc2lxvXBmyHXCSTQWn4WKaOjRd_5Fyy8,26365 +ezdxf/entities/insert.py,sha256=Y5Q0SPwVyo7bAaT9sb-evl9RszT--VsvCr8VmkBO6v4,27382 +ezdxf/entities/layer.py,sha256=PDoSlurplXfzSEutc-Es1BcGoz6IuzmZmSAB0lTd15Y,27904 +ezdxf/entities/layout.py,sha256=rUyA6I9ea9xlC1Wn52_LdAVrWtcCeYwxEDDtSnte64E,13964 +ezdxf/entities/leader.py,sha256=kY4gocMUL3OT1pEU_5vUIGWjPJhX_ecji_hkc37Rgjw,12710 +ezdxf/entities/light.py,sha256=557KDdPCJP0mFyC4mvq6081v6XrgK21kWTGKNMWAA3I,4566 +ezdxf/entities/line.py,sha256=9e1fM2iWwPcDlmYrQCrqiTBKgA6P1B-e4RJb9OwW0mQ,3608 +ezdxf/entities/ltype.py,sha256=k4JMNhH3ZQWhbhXhySBBgWEVXeCbW64lNClL4ruJ3Vk,9493 +ezdxf/entities/lwpolyline.py,sha256=xPXikzoB_i32eUczX_-fix16Zsdt0UwcaknuAS9B8DU,18516 +ezdxf/entities/material.py,sha256=1ZD1HPKeLH79XcUaxTBkbO2OFZpHqZxSM9iaLaT_hWU,18920 +ezdxf/entities/mesh.py,sha256=0Kj1j_Rm7JVZZ78EDt7LTlGc4I6Mn5hqa8G9NfRVdTY,16957 +ezdxf/entities/mleader.py,sha256=seiLPFQ-3jHbWnHVrSWVNJ7zfqOmD1De6zn2n3TgP9M,55975 +ezdxf/entities/mline.py,sha256=7uRs2j0dLj-gU89EePC8Dtiz342FazhJCyxEb1e8YDg,36262 +ezdxf/entities/mpolygon.py,sha256=4sgv9axllTQU1UNY1ok2iqPoXmqS2OByLH7-bPhm-jc,8144 +ezdxf/entities/mtext.py,sha256=Nl478O-UJi7f0EOGAMNacF3pNTEnAfKT2e8HuOjDn5o,46978 +ezdxf/entities/mtext_columns.py,sha256=UJ-lLnv_dCndGyYgh3aeMwWIEa9UBS2pSKxRN11-Zqo,4197 +ezdxf/entities/objectcollection.py,sha256=H36yRD74xRHRFulPtsy7sYlJD7YptkBTl1Oh89I650g,6037 +ezdxf/entities/oleframe.py,sha256=o8Mbec7LoIilrH5C5f5wdeaePURPrRDzz1fyE5YO12U,2094 +ezdxf/entities/pattern.py,sha256=WOOA6gRNwaepm1DPhMjlcXeyNBjmlJ3pvri4GPIrtJI,4198 +ezdxf/entities/point.py,sha256=KEmbPtHnXhhSU8jBPa_DJoXIevUIqyuTHV8Wk5a9vd8,5093 +ezdxf/entities/polygon.py,sha256=UndK5P2ddtWIXFeVSU_-gK5Gemkm9ng_pRYQMMeWuvM,16516 +ezdxf/entities/polyline.py,sha256=KynS-Tb3i1uamjESujpVe5BFIZ-J1QDc50MLgl3m_Oc,38984 +ezdxf/entities/shape.py,sha256=7cmHVRy8mW7EJw4eEiHWuotYKBOLhT7mCM-hLWMxvQU,4684 +ezdxf/entities/solid.py,sha256=ql58Sduwmjop6io69bCU5CQm41pqQPxhSdzJCkPGha4,10206 +ezdxf/entities/spatial_filter.py,sha256=kLCRY4d70HYNDG34_odwmUJ6JW1VaVW9kqgfQXUyctU,7789 +ezdxf/entities/spline.py,sha256=XBnvruO5xtv_7BqG0xoCjKkwtpY_arrHwDOVgl9kTF0,23184 +ezdxf/entities/subentity.py,sha256=q1nbMTljeMAUixFHI839MM4MFGSoB-Dh8-hrep3tAOk,8165 +ezdxf/entities/sun.py,sha256=AshVsCplyOZ_OX2xAiDUUumXJwgMxc6A0sHeuBdMonM,5042 +ezdxf/entities/table.py,sha256=kVt8qZjNVqNyUKyXYrGQMOxgBoo0zStyZAp51dndPEg,2378 +ezdxf/entities/temporary_transform.py,sha256=A4-Y6IeqR7CPmSdJu9um7RVVHTKqHTBTFiRC6RUIjH8,1292 +ezdxf/entities/text.py,sha256=L9DoBIgkA1kkGmU0Ax1_C7BxtRbPsWfxb7j5JJzcnuA,17150 +ezdxf/entities/textstyle.py,sha256=qYkBvQf_7v940wjxm7gk0vU0vUYXTZjvwhN4cnqzdSA,8805 +ezdxf/entities/tolerance.py,sha256=oZ1vKmO-3zYGrWv3QNWTGtzz7Qx2TUhotrCc0sIGi6w,3512 +ezdxf/entities/ucs.py,sha256=z6nsc9Vl7ZWsKe-KktZAC4HDZm2TNBIQWhdln5igtOc,2618 +ezdxf/entities/underlay.py,sha256=nHFcTU3_XEqUuqbP0QWfTUJM0U071m5vZXMILTfIMGQ,14006 +ezdxf/entities/view.py,sha256=mRDuYa6tjhhF-52MAS-J9lhFTN2CFc-xQ8jTmncyJMM,5864 +ezdxf/entities/viewport.py,sha256=9e6rOyuDKqWSnuxk_2G4YGsOhfuM342rT2YdIIBLCuE,27679 +ezdxf/entities/visualstyle.py,sha256=RF1aGelaGYF6tTHnw3Po1vJ5PuguQ_Dm6a6thoS_gJA,7723 +ezdxf/entities/vport.py,sha256=UnLUIbH2QCf6qTE9YOLR9dLFPn89SIueRQ0MNVAAbcg,9711 +ezdxf/entities/xdata.py,sha256=m9hQq_iC4T1DXMLr4THoQqr04k8tkA1k4cvri4MBZII,16493 +ezdxf/entities/xdict.py,sha256=HpaHgXUqwSrp9E9krLreccZjfcdMX8NvZDL5sZT6gi4,8290 +ezdxf/entities/xline.py,sha256=Y_0Choa2Gl99zWEyvKp9PCAs4Ik8uTwehWz23cKUhfA,2967 +ezdxf/entitydb.py,sha256=vXnG0PCEzWc1WrJ8gw8AcyKgGcvDTAlqi6_R27ELCRI,15822 +ezdxf/enums.py,sha256=z99GMOCnsbJTZAtM9YGEMpQZJn9oRNhwanieLyy2CoM,7242 +ezdxf/explode.py,sha256=vXdLJvuWggnYjXgB9udHp3Y1x4emlS8aHr-AdGBRrqM,14117 +ezdxf/eztypes.py,sha256=j1Er5NWEZFh799rv-z-oH2kUc4RkisqBX89fz_T1wV4,1590 +ezdxf/filemanagement.py,sha256=RtO1ZXOJ3ojImcNOfDYc40nw32yszT_apGYdnDtvnnc,10088 +ezdxf/fonts/__init__.py,sha256=rKDBFaBNLWqK3LvQyYFAPqdLAdMcudPIgvAXHDDYPno,62 +ezdxf/fonts/__pycache__/__init__.cpython-312.pyc,, +ezdxf/fonts/__pycache__/font_face.cpython-312.pyc,, +ezdxf/fonts/__pycache__/font_manager.cpython-312.pyc,, +ezdxf/fonts/__pycache__/font_measurements.cpython-312.pyc,, +ezdxf/fonts/__pycache__/font_synonyms.cpython-312.pyc,, +ezdxf/fonts/__pycache__/fonts.cpython-312.pyc,, +ezdxf/fonts/__pycache__/glyphs.cpython-312.pyc,, +ezdxf/fonts/__pycache__/lff.cpython-312.pyc,, +ezdxf/fonts/__pycache__/shapefile.cpython-312.pyc,, +ezdxf/fonts/__pycache__/ttfonts.cpython-312.pyc,, +ezdxf/fonts/font_face.py,sha256=657LenF0Q5gSuKNVaTt0H-uLfjroqfw-_lvXhQcgWEk,2164 +ezdxf/fonts/font_manager.py,sha256=_NT3V3X5d_Oj9ikgEH47gyh3e91Aaof3azS0qzdLzyc,18094 +ezdxf/fonts/font_measurements.py,sha256=3zlfzJOB45q88EjE9RKoPYIObLKsRXh_0ewssZibkOs,1648 +ezdxf/fonts/font_synonyms.py,sha256=M7zeZsCVSJBtF4Pb_gXsF_qOB8cl6_uSIbxUBQ9VvyE,278 +ezdxf/fonts/fonts.py,sha256=f-j6KJ4Z-zaUpRclucfOD9ut1G6cRijXeMRBZP13qQo,25592 +ezdxf/fonts/glyphs.py,sha256=DmMV9mR2BMztFY30_X52LlDZ27Yh4PkbU24ecWXdzEg,1136 +ezdxf/fonts/lff.py,sha256=V3m1_WCq3NLqoj02we0pRd7Uie0YJIaW9K9Pl8CfEmk,10439 +ezdxf/fonts/shapefile.py,sha256=vFcaINhysG-CNnS7raeTLXjAES7spbzNclZbkguX8WY,34369 +ezdxf/fonts/ttfonts.py,sha256=agU5nJXg_Krbj9PMMRFfHFQLp9FNwLMRToHUPY9uYT0,7038 +ezdxf/gfxattribs.py,sha256=-14ORlpVdRCH7M3WLgP5cvi29uMAFNfMFSKJRMYIZi4,11830 +ezdxf/graphicsfactory.py,sha256=nmIBlqJSfKMCtzmhcvl_ms4OZdEcxvY8fHCaA-a1-Lg,104834 +ezdxf/groupby.py,sha256=LL3J5V-Fj6mfXaL4WXnpB6EVxxJ_rTUnWjLxM0hKAtc,3322 +ezdxf/layouts/__init__.py,sha256=y3FjuUOMXUxOXb-nfN-p3MTF090Xy6IJcKsYD_vEaHo,226 +ezdxf/layouts/__pycache__/__init__.cpython-312.pyc,, +ezdxf/layouts/__pycache__/base.cpython-312.pyc,, +ezdxf/layouts/__pycache__/blocklayout.cpython-312.pyc,, +ezdxf/layouts/__pycache__/layout.cpython-312.pyc,, +ezdxf/layouts/__pycache__/layouts.cpython-312.pyc,, +ezdxf/layouts/base.py,sha256=5ULPqepB_fRXX3NAx0ja4u7uWd-A0fP21JCJ4WSZ9rM,16496 +ezdxf/layouts/blocklayout.py,sha256=vyMh9LP4JmBGSUG7sh9khBWkGHJS2mngjs4V0mHiO9M,4211 +ezdxf/layouts/layout.py,sha256=_W0EUTDYSxzCb5jsY979HWCwCPDt0USXyYHrbT0siWw,31598 +ezdxf/layouts/layouts.py,sha256=9sllgDS53XtrpgS0FEdkw3dkSyVjq5jACZ1NGHsg4CM,14930 +ezdxf/lldxf/__init__.py,sha256=XymM7BIVJ7315eruh5rosbEjYvYAHqc1lOOznifkPas,89 +ezdxf/lldxf/__pycache__/__init__.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/attributes.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/const.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/encoding.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/extendedtags.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/fileindex.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/hdrvars.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/loader.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/packedtags.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/repair.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/tagger.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/tags.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/tagwriter.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/types.cpython-312.pyc,, +ezdxf/lldxf/__pycache__/validator.cpython-312.pyc,, +ezdxf/lldxf/attributes.py,sha256=_rZ4r478SJa3l-vTgIk7buGz-HYu5D5Vyk0gqz-AD-I,8072 +ezdxf/lldxf/const.py,sha256=DWcMkvQriTmwOSFHfIJ2a01QKhBslQ6-eUgck4orhO8,15858 +ezdxf/lldxf/encoding.py,sha256=IDrrERO5gph7d2bc1xCTOCGkzX71qogA8AVWX9XJIe4,2630 +ezdxf/lldxf/extendedtags.py,sha256=qTtQxVEqlx8NrhjmbbLgJ7EubBx9Og8OgGByprJBeKk,16534 +ezdxf/lldxf/fileindex.py,sha256=su8fwkZgQdlYqFZXgdRvItUCZg8193lP9FkcudSQNB0,5205 +ezdxf/lldxf/hdrvars.py,sha256=K5K9bgC9oasLrjjHhe1GD1Mg1jH9gF2lHqbfGCcCYqw,701 +ezdxf/lldxf/loader.py,sha256=PquVaNtY_Y2fCcAnJKLMiupH8FymH5eF0nR-iJAN83M,5313 +ezdxf/lldxf/packedtags.py,sha256=ZabJ8qsfuM-KX5xJikhpsu-dhkZmw5f9juOakDV2yIk,6944 +ezdxf/lldxf/repair.py,sha256=kD8rAufIseS2RiNKNIRqZlP2xCwM8ZTc7CEKrgt9lCU,6159 +ezdxf/lldxf/tagger.py,sha256=A8Xq-tX16CVwq3KBW7EH5anvQE2jbgRs3Ml0LrWU6X0,14125 +ezdxf/lldxf/tags.py,sha256=9TB0-OtlHKLKeX9v9w-VMsmNOio4tvyfXMJTlab-XC4,13867 +ezdxf/lldxf/tagwriter.py,sha256=LK9PtXpxNxrBTJGQjcfKB_dXqyJmcF5p4HpjmNaRCGg,10738 +ezdxf/lldxf/types.py,sha256=ay1zuRlBkOwG3rj2iHnAe86rwx_tMnG6F1oqq5t0m0Q,11528 +ezdxf/lldxf/validator.py,sha256=yW058HhQCrXKXDz_Ezk0HFBGerKYkBHlzcJ_nu6ebRk,16761 +ezdxf/math/__init__.py,sha256=FGp-mTRXuGAOstYmZpLmeb1D09iBCCsYFWOFiK3SdcE,1913 +ezdxf/math/__pycache__/__init__.cpython-312.pyc,, +ezdxf/math/__pycache__/_bezier3p.cpython-312.pyc,, +ezdxf/math/__pycache__/_bezier4p.cpython-312.pyc,, +ezdxf/math/__pycache__/_bspline.cpython-312.pyc,, +ezdxf/math/__pycache__/_construct.cpython-312.pyc,, +ezdxf/math/__pycache__/_ctypes.cpython-312.pyc,, +ezdxf/math/__pycache__/_mapbox_earcut.cpython-312.pyc,, +ezdxf/math/__pycache__/_matrix44.cpython-312.pyc,, +ezdxf/math/__pycache__/_vector.cpython-312.pyc,, +ezdxf/math/__pycache__/arc.cpython-312.pyc,, +ezdxf/math/__pycache__/bbox.cpython-312.pyc,, +ezdxf/math/__pycache__/bezier.cpython-312.pyc,, +ezdxf/math/__pycache__/bezier_interpolation.cpython-312.pyc,, +ezdxf/math/__pycache__/box.cpython-312.pyc,, +ezdxf/math/__pycache__/bspline.cpython-312.pyc,, +ezdxf/math/__pycache__/bulge.cpython-312.pyc,, +ezdxf/math/__pycache__/circle.cpython-312.pyc,, +ezdxf/math/__pycache__/clipping.cpython-312.pyc,, +ezdxf/math/__pycache__/clustering.cpython-312.pyc,, +ezdxf/math/__pycache__/construct2d.cpython-312.pyc,, +ezdxf/math/__pycache__/construct3d.cpython-312.pyc,, +ezdxf/math/__pycache__/cspline.cpython-312.pyc,, +ezdxf/math/__pycache__/curvetools.cpython-312.pyc,, +ezdxf/math/__pycache__/ellipse.cpython-312.pyc,, +ezdxf/math/__pycache__/eulerspiral.cpython-312.pyc,, +ezdxf/math/__pycache__/legacy.cpython-312.pyc,, +ezdxf/math/__pycache__/linalg.cpython-312.pyc,, +ezdxf/math/__pycache__/line.cpython-312.pyc,, +ezdxf/math/__pycache__/offset2d.cpython-312.pyc,, +ezdxf/math/__pycache__/parametrize.cpython-312.pyc,, +ezdxf/math/__pycache__/perlin.cpython-312.pyc,, +ezdxf/math/__pycache__/polyline.cpython-312.pyc,, +ezdxf/math/__pycache__/rtree.cpython-312.pyc,, +ezdxf/math/__pycache__/shape.cpython-312.pyc,, +ezdxf/math/__pycache__/transformtools.cpython-312.pyc,, +ezdxf/math/__pycache__/triangulation.cpython-312.pyc,, +ezdxf/math/__pycache__/ucs.cpython-312.pyc,, +ezdxf/math/_bezier3p.py,sha256=VDj3qgzkLUTUV4wRNMdkvqghA32uAr1Ckh7k5P_g7_Q,6510 +ezdxf/math/_bezier4p.py,sha256=I8X-ahppGS4qsFjr8G8W626HRRdfsVYcUtYYrFCqW6M,11540 +ezdxf/math/_bspline.py,sha256=aIicF3m2-0TeV0DV2z2st47f4r9VXWHYzxWMVRDr-2Q,9165 +ezdxf/math/_construct.py,sha256=3e7RYmXbhvI1HkjKfz3Ue07XPXN7Zr925kIwvPlya5w,12115 +ezdxf/math/_ctypes.py,sha256=VhSkTg4oPSv7W4G2lDbKa8gxRr1vgfuGOc5wP3CChTc,2447 +ezdxf/math/_mapbox_earcut.py,sha256=zTy1ZJjLgEhwGMcjPBexl9SKbOlUyymLr_ulWIJHFok,23981 +ezdxf/math/_matrix44.py,sha256=rARL85Y_lcLOQuAS_o-ovLoSVpVRNUCiu1qaSGQLH6I,22039 +ezdxf/math/_vector.py,sha256=7CTxQIoy5v3F6yPV-yBeVdhU-W3vxuj-N1fS612GcIU,25057 +ezdxf/math/arc.py,sha256=JPfQFfxOtDRCJdyIctNsSzZcM2j3hYBV-lyau-Flh1g,18672 +ezdxf/math/bbox.py,sha256=Ph5fT35cn5AlKbZcYhYSOVvrSnfcahmB-nwuyqKmFHQ,15075 +ezdxf/math/bezier.py,sha256=LXqoi2zHEX4ack4nVRV4jwYIf76zxh8WlzXTa57-NLg,9050 +ezdxf/math/bezier_interpolation.py,sha256=n3DPzcoIH41TUjlywX23KkYTkDBCo3NbvDno3pd2bFM,2382 +ezdxf/math/box.py,sha256=8voKOf7S4HD-P1dGuzT6jW6X2bURTaLdaqCHnmpl_3w,8462 +ezdxf/math/bspline.py,sha256=nBDMj5zvm9qJvAkMWR9hZ_Zc4g8oYs0SBFCoI5NxCYw,51603 +ezdxf/math/bulge.py,sha256=UO8qPZIoqDuKZ0wbGEAbDER_J_CLCKd1iK2lnHaQtYw,5423 +ezdxf/math/circle.py,sha256=u3YCtrE6wFzCAJ_2UKi9DVXHKpd0ffSJ5Is1vPI0Bpw,8886 +ezdxf/math/clipping.py,sha256=yLL5aCLTo2ukRG2dTdhSxF-GLEXNxsSbIJ1P4cgWHlM,33803 +ezdxf/math/clustering.py,sha256=14ICSNKs6y2KXdR1AbjFDdtTvm9mMeroJzOfjDDRLZk,4178 +ezdxf/math/construct2d.py,sha256=B1NX85k7chzXpljMS-CaR7rN5-ld125RB0F0hf1Xpm4,11238 +ezdxf/math/construct3d.py,sha256=jUjtUlxaU2nAcW_spHEludaVAnv9yUCUWOaRB8g1cZ8,25407 +ezdxf/math/cspline.py,sha256=4JC-aofxlPrY0Jmuv4Ik32ta27tLvnpWEw7vHLc4_8M,1233 +ezdxf/math/curvetools.py,sha256=RyQKxKRd3S1bWbwnc-wWQKcE1NCd_Ebdl5zQfDY0504,8828 +ezdxf/math/ellipse.py,sha256=U1aFFjtOHh-0_FgzUI0EwIV0JdmkYCQLelxITnlP-gg,21124 +ezdxf/math/eulerspiral.py,sha256=E8m1-BmoTfxF6pFrszyRYC-Ktrmq9in0LE3gnJ-3aZo,4270 +ezdxf/math/legacy.py,sha256=6oUJfduDjDLSc5i9LBFgyj2F8bL7vQpeXok6bwNnd5Y,12773 +ezdxf/math/linalg.py,sha256=_LKo7v6oHWexSvF5kh0REI3-DZM-bRTYweq64Q49Jeg,26356 +ezdxf/math/line.py,sha256=Hewiv4a48nLLHLHSZ2lN_hdiXCQRDtsZa28Hrlu4Yys,9903 +ezdxf/math/offset2d.py,sha256=Y_cus09Uf4GSyDy-nPybJC_cdnGzS3qh_1W3By72Ozw,2978 +ezdxf/math/parametrize.py,sha256=ghTH7S7kZVnVqdw2J5Z6fN1UVFMgN3nW71QHKu5TWKc,7916 +ezdxf/math/perlin.py,sha256=MgtvqMQyRwg1KkJTrr_kxFsn58d1PD9FQ17o-WpgzqU,15176 +ezdxf/math/polyline.py,sha256=SBQqrBxZmDEL8KCr3qgk1bXXZ--NHXwiK3IUNEc30o4,15460 +ezdxf/math/rtree.py,sha256=2VGk-DcWr0g4__-a_T9V_W92w9o7Cdi9Ql9tLlY4U-E,11370 +ezdxf/math/shape.py,sha256=cNi8ElC55dcq6UDpasTKqzgGLfiH7q50tiUjut2tmX8,4650 +ezdxf/math/transformtools.py,sha256=3WYL4b8bhWMX1bbkS-wR_TxcGhfY9dzcBLNSciV9cDM,11808 +ezdxf/math/triangulation.py,sha256=ksI4-rIFG7lqQ5QE4MUPGtMl3ssaRRcv9FPX3R3oPko,3433 +ezdxf/math/ucs.py,sha256=pNcQgIlZo6UDrTeaQMTR1U1XZxCHg0uhKsczNXqr9Ow,16599 +ezdxf/messenger.py,sha256=dILPbxkuP-So7Q-rcaVmhajPhbpq4_SJcsZDYdzlkTw,639 +ezdxf/msgtypes.py,sha256=Iz-O-Kwc1bvc0kWT0U6a9tF_YEX4GdJvbtEqgnhAc7I,264 +ezdxf/npshapes.py,sha256=wtqMjPJKTpMR5kroMRcHZI7c10SuqITa2VPzFx0a8ww,19935 +ezdxf/path/__init__.py,sha256=IHMlqFX_q_VzvlSceZwa8pLyoIZfoJRhgOXqCUsOVhQ,371 +ezdxf/path/__pycache__/__init__.cpython-312.pyc,, +ezdxf/path/__pycache__/commands.cpython-312.pyc,, +ezdxf/path/__pycache__/converter.cpython-312.pyc,, +ezdxf/path/__pycache__/nesting.cpython-312.pyc,, +ezdxf/path/__pycache__/path.cpython-312.pyc,, +ezdxf/path/__pycache__/shapes.cpython-312.pyc,, +ezdxf/path/__pycache__/tools.cpython-312.pyc,, +ezdxf/path/commands.py,sha256=shqssckUalqNH1NVXG4u3_6soBYH5N71LK2nWX7Axsg,1242 +ezdxf/path/converter.py,sha256=zj8C9-wFmq1KcthWyWn4vbPyZ0OjYQivzSnr1few2PI,30333 +ezdxf/path/nesting.py,sha256=GUHz5Fi4jbGj32c8Hd1UvjJRF-dd7uP3vinau0SpT0s,5699 +ezdxf/path/path.py,sha256=lKabV_DAhzfYikBmIekVIm8UPnhxbb0T-JUA7ObZLwE,17717 +ezdxf/path/shapes.py,sha256=KdxTK17ensT0uCv4HL4mNiL_cCqCRRd69xWAPdV9q8Y,9823 +ezdxf/path/tools.py,sha256=pQeFifDmBauG3PxuYQN5EU2vcER-EzTlQYmFBIagAyQ,33196 +ezdxf/protocols.py,sha256=XX-EDbfp2V8TCvj4KoT5r9qK_lM6wDFWienXAnr6WzE,2934 +ezdxf/proxygraphic.py,sha256=5v_gHc8_RDWv48Bn53dUo3YIgTLKJliqnEEoTPfImPg,34329 +ezdxf/py.typed,sha256=UaCuPFa3H8UAakbt-5G8SPacldTOGvJv18pPjUJ5gDY,93 +ezdxf/query.py,sha256=69kTX5HeX-_nbyiq6j-7YwBHDPpUbJX_QQLMrGgnj20,21868 +ezdxf/queryparser.py,sha256=uNMn4gZeLkCzDrmgjD7_m6qHkvR4MC6Gl9Wrt6KicXk,2702 +ezdxf/r12strict.py,sha256=FZ2yCea3hs2vZbckV15mX22bf-ue6QTASKgzPkPBZx8,9306 +ezdxf/recover.py,sha256=EVEuxJll7iLprPSM2e6IRGsiv48kJ5to7J4KSwdQztI,30923 +ezdxf/render/__init__.py,sha256=WYBFfY_pr8YSN9JO9guhHZBBgcCdSp_gyeWXO-krYMQ,748 +ezdxf/render/__pycache__/__init__.cpython-312.pyc,, +ezdxf/render/__pycache__/_linetypes.cpython-312.pyc,, +ezdxf/render/__pycache__/abstract_mtext_renderer.cpython-312.pyc,, +ezdxf/render/__pycache__/arrows.cpython-312.pyc,, +ezdxf/render/__pycache__/curves.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_base.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_curved.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_diameter.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_linear.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_ordinate.cpython-312.pyc,, +ezdxf/render/__pycache__/dim_radius.cpython-312.pyc,, +ezdxf/render/__pycache__/dimension.cpython-312.pyc,, +ezdxf/render/__pycache__/forms.cpython-312.pyc,, +ezdxf/render/__pycache__/hatching.cpython-312.pyc,, +ezdxf/render/__pycache__/leader.cpython-312.pyc,, +ezdxf/render/__pycache__/linetypes.cpython-312.pyc,, +ezdxf/render/__pycache__/mesh.cpython-312.pyc,, +ezdxf/render/__pycache__/mleader.cpython-312.pyc,, +ezdxf/render/__pycache__/mline.cpython-312.pyc,, +ezdxf/render/__pycache__/point.cpython-312.pyc,, +ezdxf/render/__pycache__/polyline.cpython-312.pyc,, +ezdxf/render/__pycache__/r12spline.cpython-312.pyc,, +ezdxf/render/__pycache__/trace.cpython-312.pyc,, +ezdxf/render/_linetypes.py,sha256=sPCkFOhgVmia1tK2nk_mEA0A6EK6LxRIcfrsZPQgUh4,2805 +ezdxf/render/abstract_mtext_renderer.py,sha256=TwqtrtpUbr-58yIr-fGhYLyVGMensvwVHlJkB2U-qRI,9868 +ezdxf/render/arrows.py,sha256=W0Mn2VcXzpxsLd01KieJpNyiAzdfCUhf6a4shVOD2fg,19869 +ezdxf/render/curves.py,sha256=l-o7j-WuQ3AAx3tBrkLcyg6cpZt0-1EtxN9jLv-ecY8,17241 +ezdxf/render/dim_base.py,sha256=_Ovsk6PDhBv61-vsyy4qCU4pMWVc9E3HknKEIq28B3s,50093 +ezdxf/render/dim_curved.py,sha256=HBgENuRUZQ190M73Wvj-n97SLnPgpPtSwqxS0ivQlkU,34725 +ezdxf/render/dim_diameter.py,sha256=xg-GlGuvQ0JYTz7M3RBjtKmjyQ30bXLYbHZUIiiwcD4,6719 +ezdxf/render/dim_linear.py,sha256=s5g6i4-oIM9hSHLyjVR4vIPWDCnEyfqy8TGJg3YyOas,24102 +ezdxf/render/dim_ordinate.py,sha256=It1tMg7Fyfqqh-h7GfHNe3GCzMNEChdoEKOsfEmcvQ0,7875 +ezdxf/render/dim_radius.py,sha256=BQIM-43FGZ36ikF1GXTpIEoeRyyJoUIo557JT7BcJGg,19807 +ezdxf/render/dimension.py,sha256=BDBq8ELlzdzlrTN-BBlR6cpXK0eR4-gQ56nsQFKt8gA,3923 +ezdxf/render/forms.py,sha256=XwHx9F_rm5WlKBEQNrGOnchsAPqMvwVGSS47JYWtQj0,45736 +ezdxf/render/hatching.py,sha256=pgHElSxUDJfq4xFRc_fT-BJhK9PZAhDJbbHhmg6803k,25080 +ezdxf/render/leader.py,sha256=LnP_0HnGpVm9IwLvZFsvgIvdJFT8Mm9iIHKPE-EU9nc,4602 +ezdxf/render/linetypes.py,sha256=Y-Iuyntx7psmmWalfKC2Mky2BnNMlVjTzVGG74mAxss,643 +ezdxf/render/mesh.py,sha256=pWsRBb3rbPKvFu-6cLZzjr2FY0yASAaL-00eIYZ6RnM,63455 +ezdxf/render/mleader.py,sha256=nxip4oeq11UT72NniB14FncwUhZj1kLXuVWAP0CGLJs,59270 +ezdxf/render/mline.py,sha256=w8G9O-O45Bz3EBsDZdjtU12eiiZDYSc4Q6qaL2wRPAo,8208 +ezdxf/render/point.py,sha256=C3Bu9XahAWcEAuQmWB6yleCvl8NB-s0i_QAGJu16hzQ,2876 +ezdxf/render/polyline.py,sha256=yoZEawVhxlSjFWDgxfrRrGujtCfIzIK7IiN0V8H8GvI,8488 +ezdxf/render/r12spline.py,sha256=OVG943a_0Bci4C8rjLp0dJPz6B3GvSH8ggtPAS8gQyA,7650 +ezdxf/render/trace.py,sha256=HkeSsLJyiMMzCaUJgMo_yy4byZ0wRi2EoEPa4WU7b_M,21679 +ezdxf/reorder.py,sha256=_tDv3Wvicavwl6NaOuTNQm7xyJMqIqzb9u2RxCxDALQ,3415 +ezdxf/resources/16x16.png,sha256=ylZOyLGbIIB2ZelGT8wHuQ5_TlHP30qtebpY0mp4TAk,1050 +ezdxf/resources/24x24.png,sha256=Un0JyM8ttmSnW1jPsqIvnAvkPH36-ZtBJuQKMkBoX2E,1420 +ezdxf/resources/256x256.png,sha256=yj9AbmFwTPYVia0Q7Adet69E68zYwaH1YEe9lXoG7m0,10638 +ezdxf/resources/32x32.png,sha256=sDgIMCJQqAjG_eZ_NFHwrltZT3ltBXpaOrglMzbUNh8,1758 +ezdxf/resources/48x48.png,sha256=VJZ58M-arTIOZfqSjWaBuXv5_TmXRnzGMuIhMhP-9Bo,2335 +ezdxf/resources/64x64.png,sha256=uuO4j37xy0Zre1aqfKRjMIkRBfYGK6koDifouWOSIC0,3050 +ezdxf/resources/icon-copy-64px.png,sha256=AzeuLIbmWpundE3BkLHwppWjzsT6QRmjdeWmWqYz4IM,2090 +ezdxf/resources/icon-find-64px.png,sha256=CPCRoS9u13uoi919iArUnMIb3oEmVE6tWxq-7AUiZKU,3109 +ezdxf/resources/icon-goto-bookmark-64px.png,sha256=xqTPI9F9qgNY8CMKC-DEmrTYPhDN4zaJBKhBCs29etg,2388 +ezdxf/resources/icon-goto-handle-64px.png,sha256=7kpPV5aA7i-D-_ZIqRslSgtiPKVCPN-sJ4IWEA36f48,2519 +ezdxf/resources/icon-goto-line-64px.png,sha256=2A21DQiIsE9kGf9ry95ohKabGj-xVElxtAOCZ2A9ocE,2409 +ezdxf/resources/icon-left-arrow-64px.png,sha256=8dLQb5RbVHcm3mkGGiNdwm7T1L96b3PDaeTnnyN--oM,2231 +ezdxf/resources/icon-next-entity-64px.png,sha256=9hL5rlHD-EQSvRweNC1SlW1QYdOjxDJPwDrQSxWSq_I,2322 +ezdxf/resources/icon-prev-entity-64px.png,sha256=qYlnHwtUgErMucPLhJv3y9ePfeV5iaR7O9az1TUtkHE,2320 +ezdxf/resources/icon-right-arrow-64px.png,sha256=R8TH9cQw2BxzZnMnWr6AKt2c-hWnH73qqP-kk9VxuJU,2244 +ezdxf/resources/icon-show-in-tree-64px.png,sha256=f0gyr9mDADYKCYyJ72GEcXabrlcuPglakGBtXCBK0P0,2553 +ezdxf/resources/icon-store-bookmark-64px.png,sha256=EyF--EqbC_J6iWi-W0l112TdWFBcHQyVMMqR3F17x_k,2373 +ezdxf/revcloud.py,sha256=YEB95v_H0cE4_6AfaFTvf8xBaf8rMdnWr0w2L9zF-yA,3811 +ezdxf/sections/__init__.py,sha256=6NS2_6vo_R2iN4H-QlIYIi_BoLvJHdo5jhix1uCaElA,65 +ezdxf/sections/__pycache__/__init__.cpython-312.pyc,, +ezdxf/sections/__pycache__/acdsdata.cpython-312.pyc,, +ezdxf/sections/__pycache__/blocks.cpython-312.pyc,, +ezdxf/sections/__pycache__/classes.cpython-312.pyc,, +ezdxf/sections/__pycache__/entities.cpython-312.pyc,, +ezdxf/sections/__pycache__/header.cpython-312.pyc,, +ezdxf/sections/__pycache__/headervars.cpython-312.pyc,, +ezdxf/sections/__pycache__/objects.cpython-312.pyc,, +ezdxf/sections/__pycache__/table.cpython-312.pyc,, +ezdxf/sections/__pycache__/tables.cpython-312.pyc,, +ezdxf/sections/acdsdata.py,sha256=7GuauRe7v9BzH8FA_6txqXpZiK_3tcP1ChePuxe9wkE,10132 +ezdxf/sections/blocks.py,sha256=T88D037wj_8cp_NGWqRr4TodECASDQrHzKyTxzBb1r4,18544 +ezdxf/sections/classes.py,sha256=UfSHiMU5HPYGYr4DByyUqDYI5Tw3oDfZ8XZK6qzYKoE,11315 +ezdxf/sections/entities.py,sha256=pL4lujv33dg0ChzAz1nn4ClK29IFF2OnaowJFR_VAUg,4024 +ezdxf/sections/header.py,sha256=GKwgFF2hKF-rHU2ywZoH-OyQWVZGfftjPe-af75Ue_Q,11566 +ezdxf/sections/headervars.py,sha256=R2pOmqXIFucKw1lBYRwGytYJiBFyzTHJW6fH2jXW4So,58983 +ezdxf/sections/objects.py,sha256=SYDfYdYQHEwP_QY4WLFjievmG1SNtZCL79PamSCfAis,26292 +ezdxf/sections/table.py,sha256=oxu7Ku0KxpUVuZ8cHuFvCzGDAI3oBLhOIa8Jp9_kito,25786 +ezdxf/sections/tables.py,sha256=oL_ZwO_sYdZs02Zh1Lj-6Re3RyavED4t9cuGy2oTHgQ,5118 +ezdxf/select.py,sha256=RuSs39nyAbjabG3pPO9Z0gzoNQiVyO8rig6M743Habw,15477 +ezdxf/tools/__init__.py,sha256=EOp1qhfRVoO7_cBD-1kvljogc3gmjNqJvm-90UOJ_HU,4252 +ezdxf/tools/__pycache__/__init__.cpython-312.pyc,, +ezdxf/tools/__pycache__/_iso_pattern.cpython-312.pyc,, +ezdxf/tools/__pycache__/analyze.cpython-312.pyc,, +ezdxf/tools/__pycache__/binarydata.cpython-312.pyc,, +ezdxf/tools/__pycache__/clipping_portal.cpython-312.pyc,, +ezdxf/tools/__pycache__/codepage.cpython-312.pyc,, +ezdxf/tools/__pycache__/complex_ltype.cpython-312.pyc,, +ezdxf/tools/__pycache__/crypt.cpython-312.pyc,, +ezdxf/tools/__pycache__/debug.cpython-312.pyc,, +ezdxf/tools/__pycache__/difftags.cpython-312.pyc,, +ezdxf/tools/__pycache__/handle.cpython-312.pyc,, +ezdxf/tools/__pycache__/indexing.cpython-312.pyc,, +ezdxf/tools/__pycache__/juliandate.cpython-312.pyc,, +ezdxf/tools/__pycache__/pattern.cpython-312.pyc,, +ezdxf/tools/__pycache__/rawloader.cpython-312.pyc,, +ezdxf/tools/__pycache__/standards.cpython-312.pyc,, +ezdxf/tools/__pycache__/strip.cpython-312.pyc,, +ezdxf/tools/__pycache__/test.cpython-312.pyc,, +ezdxf/tools/__pycache__/text.cpython-312.pyc,, +ezdxf/tools/__pycache__/text_layout.cpython-312.pyc,, +ezdxf/tools/__pycache__/text_size.cpython-312.pyc,, +ezdxf/tools/__pycache__/zipmanager.cpython-312.pyc,, +ezdxf/tools/_iso_pattern.py,sha256=_3rRDsnJzEIBvLmKD2o7COt4CxLqg3vH4iqYBuubmps,138334 +ezdxf/tools/analyze.py,sha256=NiuNYcfN-88yRleDvBKwq6EIhIVp7oVEsr8-VpOyzjs,19135 +ezdxf/tools/binarydata.py,sha256=KaE2Rd9nNgkA8k69zmza9qdjMbNZE9UKc2txrMmc7lA,19834 +ezdxf/tools/clipping_portal.py,sha256=rZR20d84u39x-2KgRtkkYyw7ZiToz02KnXfvW80Tr6w,15572 +ezdxf/tools/codepage.py,sha256=x6tiVdQrH-J2OAfjnw6xi32hIZrH-rSb3ExOi3DV87E,2840 +ezdxf/tools/complex_ltype.py,sha256=07wBNpGKlk75yhQyIltcIaQd-YsWde5OxQpSZtCzz2w,7399 +ezdxf/tools/crypt.py,sha256=TraGUeqr5GxWZZDFaGAt-OOCaK3ris7sysXN-Y0LAcY,1724 +ezdxf/tools/debug.py,sha256=ihcvmzs8xIFxhjssU-kfgx9rGjzXUu1THzwvy949y3E,1457 +ezdxf/tools/difftags.py,sha256=Cw_LjNHj3hP4n1vUZG2CxMwF6YytTXems9QnVxtS-qs,2245 +ezdxf/tools/handle.py,sha256=2uQRFyZIKKuuikjYPuv4-HU6bryVWsPg6AvIuHDibd8,1187 +ezdxf/tools/indexing.py,sha256=C1sfLJ1nZO_N0tXq48wEFAsTBtnQD54TbcyoViRB5-k,751 +ezdxf/tools/juliandate.py,sha256=UHS3NGzKx8RG2I4Gt3KkUkHMTrv9dxQm-6Zpz-EO_58,2074 +ezdxf/tools/pattern.py,sha256=CRvNvLOV4VEWwRWD9rdkGnPeA8oDaOoEm3Xi54cqfAg,5976 +ezdxf/tools/rawloader.py,sha256=ZIoHnVEqkrtoQkdrmPxw_UWA1yNQF7-iXmOLPyysr1c,1188 +ezdxf/tools/standards.py,sha256=87ZL9qjWIxCSWP5qdeuOHR-Gs9f2W2I0KX-qeABMU0A,125172 +ezdxf/tools/strip.py,sha256=K9CR9D3ExdkU2c52LgbbsiG-xq2Hc1OQTRNArPGYN30,5995 +ezdxf/tools/test.py,sha256=fjmi86mgIeQbDvQsB9uTVI9w6iqH0oAxw3Q2SUzcomI,1416 +ezdxf/tools/text.py,sha256=aX1bVFd1IWV1lahw5c_BXQYMaiRC3eRL2PRcA6AvaYw,64190 +ezdxf/tools/text_layout.py,sha256=Y1faYTL_YOxYAVQQ3xhabOeQaF7OwFyFToInQ9b-3vI,52471 +ezdxf/tools/text_size.py,sha256=lnzZ8Xwv6YEmKJhqwfmdnUSJU99UzYSVvvVXmb1rm5U,6695 +ezdxf/tools/zipmanager.py,sha256=Xj49FFPIdfcmybOhBDXnQPcfdUBGXLnd4LNpjLhTBqI,3029 +ezdxf/transform.py,sha256=KOXATb6aHsyiCyY5IRYYPhC_j4cQNxZfKmwVfVqE1uA,12450 +ezdxf/units.py,sha256=mp6NP__Z4j1CgGZa1-T6rbmA3SBvMYiQwy14wqJ-Y_w,5503 +ezdxf/upright.py,sha256=E76ySqkDTjamXdCtytfEzcOWC-POj8czBaLvLmRwiu4,8010 +ezdxf/urecord.py,sha256=K1U0a6B8Uc5uYdWm4Zwc9ydF_gtt4Vp4pMdtAx7LK40,9573 +ezdxf/version.py,sha256=XsPqTQfexGD_O7zBK1w-zPI1wUF0Uo1nIkc78nYEoV0,999 +ezdxf/xclip.py,sha256=wEdGGk7pfAg4t-ZLy0uzD1dEgj9fzXCcWU99ETWrvqY,17830 +ezdxf/xref.py,sha256=_VXPTufKBO6-YHCPznyXWQ4aWlYOgawBck7lnlMZF-c,64075 +ezdxf/zoom.py,sha256=nl_sLzPPEDK3ZXkT8qYU3lJWpXspio8rLnFAUK0wktg,2773 diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/REQUESTED b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/WHEEL new file mode 100644 index 0000000..b0fbf11 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.1.0) +Root-Is-Purelib: false +Tag: cp312-cp312-macosx_11_0_arm64 + diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/entry_points.txt b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/entry_points.txt new file mode 100644 index 0000000..07f59a9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +ezdxf = ezdxf.__main__:main diff --git a/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/top_level.txt b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/top_level.txt new file mode 100644 index 0000000..fb8b6e1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf-1.3.4.dist-info/top_level.txt @@ -0,0 +1 @@ +ezdxf diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/__init__.py new file mode 100644 index 0000000..fc3ee44 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/__init__.py @@ -0,0 +1,106 @@ +# Copyright (C) 2011-2023, Manfred Moitzi +# License: MIT License +"""Ezdxf is an interface library for the DXF file format. + +The package is designed to facilitate the creation and manipulation of DXF +documents, with compatibility across various DXF versions. It empowers users to +seamlessly load and edit DXF files while preserving all content, except for comments. + +Any unfamiliar DXF tags encountered in the document are gracefully ignored but retained +for future modifications. This feature enables the processing of DXF documents +containing data from third-party applications without any loss of valuable information. +""" +from typing import TextIO, Optional +import sys +import os +from .version import version, __version__ + +VERSION = __version__ +__author__ = "mozman " + +TRUE_STATE = {"True", "true", "On", "on", "1"} +PYPY = hasattr(sys, "pypy_version_info") +PYPY_ON_WINDOWS = sys.platform.startswith("win") and PYPY + +# name space imports - do not remove +from ezdxf._options import options, config_files +from ezdxf.colors import ( + int2rgb, + rgb2int, + transparency2float, + float2transparency, +) +from ezdxf.enums import InsertUnits +from ezdxf.lldxf import const +from ezdxf.lldxf.validator import is_dxf_file, is_dxf_stream +from ezdxf.filemanagement import readzip, new, read, readfile, decode_base64 +from ezdxf.tools.standards import ( + setup_linetypes, + setup_styles, + setup_dimstyles, + setup_dimstyle, +) +from ezdxf.tools import pattern +from ezdxf.render.arrows import ARROWS +from ezdxf.lldxf.const import ( + DXFError, + DXFStructureError, + DXFVersionError, + DXFTableEntryError, + DXFAppDataError, + DXFXDataError, + DXFAttributeError, + DXFValueError, + DXFKeyError, + DXFIndexError, + DXFTypeError, + DXFBlockInUseError, + InvalidGeoDataException, + DXF12, + DXF2000, + DXF2004, + DXF2007, + DXF2010, + DXF2013, + DXF2018, +) + +# name space imports - do not remove + +import codecs +from ezdxf.lldxf.encoding import ( + dxf_backslash_replace, + has_dxf_unicode, + decode_dxf_unicode, +) + + +# setup DXF unicode encoder -> '\U+nnnn' +codecs.register_error("dxfreplace", dxf_backslash_replace) + +EZDXF_TEST_FILES = options.test_files +YES_NO = {True: "yes", False: "no"} + + +def print_config(verbose: bool = False, stream: Optional[TextIO] = None) -> None: + from pathlib import Path + + if stream is None: + stream = sys.stdout + stream.writelines( + [ + f"ezdxf {__version__} from {Path(__file__).parent}\n", + f"Python version: {sys.version}\n", + f"using C-extensions: {YES_NO[options.use_c_ext]}\n", + ] + ) + if verbose: + stream.write("\nConfiguration:\n") + options.write(stream) + stream.write("\nEnvironment Variables:\n") + for v in options.CONFIG_VARS: + stream.write(f"{v}={os.environ.get(v, '')}\n") + + stream.write("\nLoaded Config Files:\n") + for path in options.loaded_config_files: + stream.write(str(path.absolute()) + "\n") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__main__.py b/.venv/lib/python3.12/site-packages/ezdxf/__main__.py new file mode 100644 index 0000000..97a61c3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/__main__.py @@ -0,0 +1,120 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +import sys +import argparse +from pathlib import Path +from ezdxf import options, print_config +from ezdxf import commands +from ezdxf.fonts import fonts + +YES_NO = {True: "yes", False: "no"} +options.set(options.CORE, "LOAD_PROXY_GRAPHICS", "true") + + +def add_common_arguments(parser): + parser.add_argument( + "-V", + "--version", + action="store_true", + help="show version and exit", + ) + parser.add_argument( + "-f", + "--fonts", + action="store_true", + help="rebuild system font cache and print all fonts found", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="give more output", + ) + parser.add_argument( + "--config", + action="store", + help="path to a config file", + ) + parser.add_argument( + "--log", + action="store", + help='path to a verbose appending log, "stderr" logs to the ' + "standard error stream", + ) + + +def print_version(verbose=False): + print_config(verbose=verbose, stream=sys.stdout) + + +def print_available_fonts(verbose=False): + from ezdxf.fonts import fonts + print("Rebuilding system font cache.") + fonts.build_system_font_cache() + fonts.font_manager.print_available_fonts(verbose) + + +def setup_log(args): + import logging + from datetime import datetime + from io import StringIO + + level = "DEBUG" if args.verbose else "INFO" + if args.log.lower() == "stderr": + logging.basicConfig(stream=sys.stderr, level=level) + else: + logging.basicConfig(filename=args.log, level=level) + print(f'Appending logs to file "{args.log}", logging level: {level}\n') + logger = logging.getLogger("ezdxf") + logger.info("***** Launch time: " + datetime.now().isoformat() + " *****") + if args.verbose: + s = StringIO() + print_config(verbose=True, stream=s) + logger.info("configuration\n" + s.getvalue()) + + +DESCRIPTION = """ +Command launcher for the Python package "ezdxf": https://pypi.org/project/ezdxf/ + +""" + + +def main(): + parser = argparse.ArgumentParser( + "ezdxf", + description=DESCRIPTION, + ) + add_common_arguments(parser) + subparsers = parser.add_subparsers(dest="command") + commands.add_parsers(subparsers) + + args = parser.parse_args(sys.argv[1:]) + help_ = True + if args.config: + config = Path(args.config) + if config.exists(): + options.read_file(args.config) + if args.verbose: + print(f'using config file: "{config}"') + else: + print(f'config file "{config}" not found') + if args.log: + setup_log(args) + if args.version: + print_version(verbose=args.verbose) + help_ = False + if args.fonts: + print_available_fonts(args.verbose) + help_ = False + + run = commands.get(args.command) + if run: + # For the case automatic font loading is disabled: + fonts.load() + run(args) + elif help_: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..5424ede Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..85b4dc4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/__main__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/_options.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/_options.cpython-312.pyc new file mode 100644 index 0000000..05dc3f0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/_options.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/appsettings.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/appsettings.cpython-312.pyc new file mode 100644 index 0000000..53b02df Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/appsettings.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/audit.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/audit.cpython-312.pyc new file mode 100644 index 0000000..32c1f2e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/audit.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/bbox.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/bbox.cpython-312.pyc new file mode 100644 index 0000000..3e08941 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/bbox.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/blkrefs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/blkrefs.cpython-312.pyc new file mode 100644 index 0000000..d9cf71c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/blkrefs.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/colors.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/colors.cpython-312.pyc new file mode 100644 index 0000000..6ebbf16 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/colors.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/commands.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/commands.cpython-312.pyc new file mode 100644 index 0000000..b9329c6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/commands.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/comments.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/comments.cpython-312.pyc new file mode 100644 index 0000000..e5f32ed Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/comments.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/disassemble.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/disassemble.cpython-312.pyc new file mode 100644 index 0000000..fa435cf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/disassemble.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/document.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/document.cpython-312.pyc new file mode 100644 index 0000000..bed42e7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/document.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dwginfo.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dwginfo.cpython-312.pyc new file mode 100644 index 0000000..6d9cf03 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dwginfo.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dynblkhelper.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dynblkhelper.cpython-312.pyc new file mode 100644 index 0000000..c478e6f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/dynblkhelper.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgeminer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgeminer.cpython-312.pyc new file mode 100644 index 0000000..ec93b7d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgeminer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgesmith.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgesmith.cpython-312.pyc new file mode 100644 index 0000000..01008c4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/edgesmith.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/entitydb.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/entitydb.cpython-312.pyc new file mode 100644 index 0000000..61b53da Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/entitydb.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/enums.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/enums.cpython-312.pyc new file mode 100644 index 0000000..4551689 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/enums.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/explode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/explode.cpython-312.pyc new file mode 100644 index 0000000..9da04a1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/explode.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/eztypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/eztypes.cpython-312.pyc new file mode 100644 index 0000000..2d2fb71 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/eztypes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/filemanagement.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/filemanagement.cpython-312.pyc new file mode 100644 index 0000000..b35152d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/filemanagement.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/gfxattribs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/gfxattribs.cpython-312.pyc new file mode 100644 index 0000000..03c0e64 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/gfxattribs.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/graphicsfactory.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/graphicsfactory.cpython-312.pyc new file mode 100644 index 0000000..7189da4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/graphicsfactory.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/groupby.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/groupby.cpython-312.pyc new file mode 100644 index 0000000..a5b02a0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/groupby.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/messenger.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/messenger.cpython-312.pyc new file mode 100644 index 0000000..b06497f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/messenger.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/msgtypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/msgtypes.cpython-312.pyc new file mode 100644 index 0000000..3c243b8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/msgtypes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/npshapes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/npshapes.cpython-312.pyc new file mode 100644 index 0000000..f74e787 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/npshapes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/protocols.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/protocols.cpython-312.pyc new file mode 100644 index 0000000..96c704f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/protocols.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/proxygraphic.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/proxygraphic.cpython-312.pyc new file mode 100644 index 0000000..a7dd756 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/proxygraphic.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/query.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/query.cpython-312.pyc new file mode 100644 index 0000000..e420b40 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/query.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/queryparser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/queryparser.cpython-312.pyc new file mode 100644 index 0000000..65d9cd5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/queryparser.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/r12strict.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/r12strict.cpython-312.pyc new file mode 100644 index 0000000..92d14b9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/r12strict.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/recover.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/recover.cpython-312.pyc new file mode 100644 index 0000000..a40492d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/recover.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/reorder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/reorder.cpython-312.pyc new file mode 100644 index 0000000..a7c10f0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/reorder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/revcloud.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/revcloud.cpython-312.pyc new file mode 100644 index 0000000..ed7ffad Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/revcloud.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/select.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/select.cpython-312.pyc new file mode 100644 index 0000000..710b591 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/select.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/transform.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/transform.cpython-312.pyc new file mode 100644 index 0000000..8bdc5c2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/transform.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/units.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/units.cpython-312.pyc new file mode 100644 index 0000000..97dee61 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/units.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/upright.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/upright.cpython-312.pyc new file mode 100644 index 0000000..9820b5c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/upright.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/urecord.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/urecord.cpython-312.pyc new file mode 100644 index 0000000..f9d55e5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/urecord.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000..10fb456 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/version.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xclip.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xclip.cpython-312.pyc new file mode 100644 index 0000000..4a9b6a0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xclip.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xref.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xref.cpython-312.pyc new file mode 100644 index 0000000..5c8e5a9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/xref.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/zoom.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/zoom.cpython-312.pyc new file mode 100644 index 0000000..993a5e4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/__pycache__/zoom.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/_options.py b/.venv/lib/python3.12/site-packages/ezdxf/_options.py new file mode 100644 index 0000000..c31e615 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/_options.py @@ -0,0 +1,335 @@ +# Copyright (c) 2011-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TextIO, Sequence +import os +import sys +from pathlib import Path +from configparser import ConfigParser + +# Recommended uses of the global object "options": +# import ezdxf +# value = ezdxf.options. +# +# alternative: +# from ezdxf._options import options + +TRUE_STATE = {"True", "true", "On", "on", "1"} +CORE = "core" +BROWSE_COMMAND = "browse-command" +VIEW_COMMAND = "view-command" +DRAW_COMMAND = "draw-command" +EZDXF_INI = "ezdxf.ini" +EZDXF = "ezdxf" +XDG_CONFIG_HOME = "XDG_CONFIG_HOME" +CONFIG_DIRECTORY = ".config" +ODAFC_ADDON = "odafc-addon" +OPENSCAD_ADDON = "openscad-addon" +DRAWING_ADDON = "drawing-addon" +DIR_SEPARATOR = "\n" + + +def xdg_path(xdg_var: str, directory: str) -> Path: + xdg_home = os.environ.get(xdg_var) + if xdg_home: + # should default to $HOME/ e.g. $HOME/.config + home = Path(xdg_home).expanduser() + else: + # replicate structure + home = Path("~").expanduser() / directory + return home / EZDXF + + +def config_home_path() -> Path: + return xdg_path(XDG_CONFIG_HOME, CONFIG_DIRECTORY) + + +def default_config_files() -> list[Path]: + config_paths = [ + config_home_path() / EZDXF_INI, + Path(f"./{EZDXF_INI}"), + ] + return config_paths + + +def default_config() -> ConfigParser: + config = ConfigParser() + config[CORE] = { + "DEFAULT_DIMENSION_TEXT_STYLE": "OpenSansCondensed-Light", + "TEST_FILES": "", + "SUPPORT_DIRS": "", + "LOAD_PROXY_GRAPHICS": "true", + "STORE_PROXY_GRAPHICS": "true", + "LOG_UNPROCESSED_TAGS": "false", + "FILTER_INVALID_XDATA_GROUP_CODES": "true", + "WRITE_FIXED_META_DATA_FOR_TESTING": "false", + "DISABLE_C_EXT": "false", + } + config[BROWSE_COMMAND] = { + "TEXT_EDITOR": r'"C:\Program Files\Notepad++\notepad++.exe" ' + r'"{filename}" -n{num}', + "ICON_SIZE": "32", + } + config[ODAFC_ADDON] = { + "WIN_EXEC_PATH": r'"C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"', + "UNIX_EXEC_PATH": "", + } + config[OPENSCAD_ADDON] = { + "WIN_EXEC_PATH": r'"C:\Program Files\OpenSCAD\openscad.exe"' + } + config[DRAWING_ADDON] = { + # These options are just for testing scenarios! + "TRY_PYSIDE6": "true", + "TRY_PYQT5": "true", + # Order for resolving SHX fonts: 1. "t"=TrueType; 2. "s"=SHX; 3. "l"=LFF + "SHX_RESOLVE_ORDER": "tsl", + } + return config + + +def config_files() -> list[Path]: + # Loading order for config files: + # 1. user home directory: + # "$XDG_CONFIG_HOME/ezdxf/ezdxf.ini" or + # "~/.config/ezdxf/ezdxf.ini" + # 2. current working directory "./ezdxf.ini" + # 3. config file specified by EZDXF_CONFIG_FILE + + paths = default_config_files() + env_cfg = os.getenv("EZDXF_CONFIG_FILE", "") + if env_cfg: + paths.append(Path(env_cfg)) + return paths + + +def load_config_files(paths: list[Path]) -> ConfigParser: + config = default_config() + try: + config.read(paths, encoding="utf8") + except UnicodeDecodeError as e: + print(str(e)) + print(f"Paths: {paths}") + print("Maybe a file with UTF16 LE-BOM encoding. (Powershell!!!)") + exit(1) + # environment variables override config files + for name, env_name in [ + ("TEST_FILES", "EZDXF_TEST_FILES"), + ("DISABLE_C_EXT", "EZDXF_DISABLE_C_EXT"), + ]: + value = os.environ.get(env_name, "") + if value: + config[CORE][name] = value + return config + + +def boolstr(value: bool) -> str: + return str(value).lower() + + +class Options: + CORE = CORE + BROWSE_COMMAND = BROWSE_COMMAND + VIEW_COMMAND = VIEW_COMMAND + DRAW_COMMAND = DRAW_COMMAND + + CONFIG_VARS = [ + "EZDXF_DISABLE_C_EXT", + "EZDXF_TEST_FILES", + "EZDXF_CONFIG_FILE", + ] + + def __init__(self) -> None: + paths = config_files() + self._loaded_paths: list[Path] = [p for p in paths if p.exists()] + self._config = load_config_files(paths) + # needs fast access: + self.log_unprocessed_tags = True + # Activate/deactivate Matplotlib support (e.g. for testing) + self._use_c_ext = False # set ezdxf.acc.__init__! + self.debug = False + self.update_cached_options() + + def set(self, section: str, key: str, value: str) -> None: + self._config.set(section, key, value) + + def get(self, section: str, key: str, default: str = "") -> str: + return self._config.get(section, key, fallback=default) + + def get_bool(self, section: str, key: str, default: bool = False) -> bool: + return self._config.getboolean(section, key, fallback=default) + + def get_int(self, section: str, key: str, default: int = 0) -> int: + return self._config.getint(section, key, fallback=default) + + def get_float(self, section: str, key: str, default: float = 0.0) -> float: + return self._config.getfloat(section, key, fallback=default) + + def update_cached_options(self) -> None: + self.log_unprocessed_tags = self.get_bool( + Options.CORE, "LOG_UNPROCESSED_TAGS", default=True + ) + + def rewrite_cached_options(self): + # rewrite cached options + self._config.set( + Options.CORE, + "LOG_UNPROCESSED_TAGS", + boolstr(self.log_unprocessed_tags), + ) + + @property + def loaded_config_files(self) -> tuple[Path, ...]: + return tuple(self._loaded_paths) + + def read_file(self, filename: str) -> None: + """Append content from config file `filename`, but does not reset the + configuration. + """ + try: + self._config.read(filename) + except IOError as e: + print(str(e)) + else: + self._loaded_paths.append(Path(filename)) + self.update_cached_options() + + def write(self, fp: TextIO) -> None: + """Write current configuration into given file object, the file object + must be a writeable text file with 'utf8' encoding. + """ + self.rewrite_cached_options() + try: + self._config.write(fp) + except IOError as e: + print(str(e)) + + def write_file(self, filename: str = EZDXF_INI) -> None: + """Write current configuration into file `filename`.""" + with open(os.path.expanduser(filename), "wt", encoding="utf8") as fp: + self.write(fp) + + @property + def filter_invalid_xdata_group_codes(self) -> bool: + return self.get_bool(CORE, "FILTER_INVALID_XDATA_GROUP_CODES", default=True) + + @property + def default_dimension_text_style(self) -> str: + return self.get( + CORE, + "DEFAULT_DIMENSION_TEXT_STYLE", + default="OpenSansCondensed-Light", + ) + + @default_dimension_text_style.setter + def default_dimension_text_style(self, style: str) -> None: + self.set( + CORE, + "DEFAULT_DIMENSION_TEXT_STYLE", + style, + ) + + @property + def support_dirs(self) -> list[str]: + return [d for d in self.get(CORE, "SUPPORT_DIRS", "").split(DIR_SEPARATOR) if d] + + @support_dirs.setter + def support_dirs(self, support_dirs: Sequence[str]) -> None: + self.set(CORE, "SUPPORT_DIRS", DIR_SEPARATOR.join(support_dirs)) + + @property + def test_files(self) -> str: + return os.path.expanduser(self.get(CORE, "TEST_FILES")) + + @property + def test_files_path(self) -> Path: + return Path(self.test_files) + + @property + def load_proxy_graphics(self) -> bool: + return self.get_bool(CORE, "LOAD_PROXY_GRAPHICS", default=True) + + @load_proxy_graphics.setter + def load_proxy_graphics(self, value: bool) -> None: + self.set(CORE, "LOAD_PROXY_GRAPHICS", boolstr(value)) + + @property + def store_proxy_graphics(self) -> bool: + return self.get_bool(CORE, "STORE_PROXY_GRAPHICS", default=True) + + @store_proxy_graphics.setter + def store_proxy_graphics(self, value: bool) -> None: + self.set(CORE, "STORE_PROXY_GRAPHICS", boolstr(value)) + + @property + def write_fixed_meta_data_for_testing(self) -> bool: + # Enable this option to always create same meta data for testing + # scenarios, e.g. to use a diff like tool to compare DXF documents. + return self.get_bool(CORE, "WRITE_FIXED_META_DATA_FOR_TESTING", default=False) + + @write_fixed_meta_data_for_testing.setter + def write_fixed_meta_data_for_testing(self, state: bool) -> None: + self.set(CORE, "write_fixed_meta_data_for_testing", boolstr(state)) + + @property + def disable_c_ext(self) -> bool: + """Disable C-extensions if ``True``.""" + return self.get_bool(CORE, "DISABLE_C_EXT", default=False) + + @property + def use_c_ext(self) -> bool: + """Returns ``True`` if the C-extensions are in use.""" + return self._use_c_ext + + def preserve_proxy_graphics(self, state: bool = True) -> None: + """Enable/disable proxy graphic load/store support.""" + value = boolstr(state) + self.set(CORE, "LOAD_PROXY_GRAPHICS", value) + self.set(CORE, "STORE_PROXY_GRAPHICS", value) + + def print(self): + """Print current configuration to `stdout`.""" + self._config.write(sys.stdout) + + def write_home_config(self): + """Write current configuration into file "~/.config/ezdxf/ezdxf.ini" or + "XDG_CONFIG_HOME/ezdxf/ezdxf.ini". + """ + + home_path = config_home_path() + if not home_path.exists(): + try: + home_path.mkdir(parents=True) + except IOError as e: + print(str(e)) + return + + filename = str(home_path / EZDXF_INI) + try: + self.write_file(filename) + except IOError as e: + print(str(e)) + else: + print(f"created config file: '{filename}'") + + def reset(self): + self._loaded_paths = [] + self._config = default_config() + self.update_cached_options() + + @staticmethod + def delete_default_config_files(): + for file in default_config_files(): + if file.exists(): + try: + file.unlink() + print(f"deleted config file: '{file}'") + except IOError as e: + print(str(e)) + + @staticmethod + def xdg_path(xdg_var: str, directory: str) -> Path: + return xdg_path(xdg_var, directory) + + +# Global Options +options = Options() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/acc/__init__.py new file mode 100644 index 0000000..04082a8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/__init__.py @@ -0,0 +1,39 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +import sys +from ezdxf._options import options + +# Set environment variable EZDXF_DISABLE_C_EXT to '1' or 'True' to disable +# the usage of C extensions implemented by Cython. +# +# Important: If you change the EZDXF_DISABLE_C_EXT state, you have to restart +# the Python interpreter, because C extension integration is done at the +# ezdxf import! +# +# Config files: +# Section: core +# Key: disable_c_ext = 1 +# +# Direct imports from the C extension modules can not be disabled, +# just the usage by the ezdxf core package. +# For an example see ezdxf.math.__init__, if you import Vec3 from ezdxf.math +# the implementation depends on DISABLE_C_EXT and the existence of the C +# extension, but if you import Vec3 from ezdxf.math.vectors, you always get +# the Python implementation. + +USE_C_EXT = not options.disable_c_ext + +# C-extensions are always disabled for pypy because JIT compiled Python code is +# much faster! +PYPY = hasattr(sys, 'pypy_version_info') +if PYPY: + USE_C_EXT = False + +if USE_C_EXT: + try: + from ezdxf.acc import vector + except ImportError: + USE_C_EXT = False + +# set actual state of C-extension usage +options._use_c_ext = USE_C_EXT diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acc/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4b1efbc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.c new file mode 100644 index 0000000..35feeff --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.c @@ -0,0 +1,13516 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.bezier3p", + "sources": [ + "src/ezdxf/acc/bezier3p.pyx" + ] + }, + "module_name": "ezdxf.acc.bezier3p" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__bezier3p +#define __PYX_HAVE_API__ezdxf__acc__bezier3p +/* Early includes */ +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/bezier3p.pyx", + "", + "src/ezdxf/acc/vector.pxd", + "src/ezdxf/acc/matrix44.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44; +struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P; +struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening; +struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "matrix44.pxd":6 + * from .vector cimport Vec3 + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * cdef double m[16] + * cdef Vec3 get_ux(self: Matrix44) + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtab; + double m[16]; +}; + + +/* "ezdxf/acc/bezier3p.pyx":20 + * + * + * cdef class Bezier3P: # <<<<<<<<<<<<<< + * cdef: + * FastQuadCurve curve # pyright: ignore + */ +struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *curve; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *start_point; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *cp1; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *end_point; +}; + + +/* "ezdxf/acc/bezier3p.pyx":121 + * + * + * cdef class _Flattening: # <<<<<<<<<<<<<< + * cdef FastQuadCurve curve # pyright: ignore + * cdef double distance + */ +struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *__pyx_vtab; + struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *curve; + double distance; + PyObject *points; + int _recursion_level; + int _recursion_error; +}; + + +/* "ezdxf/acc/bezier3p.pyx":164 + * + * + * cdef class FastQuadCurve: # <<<<<<<<<<<<<< + * cdef: + * double[3] offset + */ +struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_vtab; + double offset[3]; + double p1[3]; + double p2[3]; +}; + + + +/* "matrix44.pxd":6 + * from .vector cimport Vec3 + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * cdef double m[16] + * cdef Vec3 get_ux(self: Matrix44) + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_ux)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uy)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uz)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44; + + +/* "ezdxf/acc/bezier3p.pyx":121 + * + * + * cdef class _Flattening: # <<<<<<<<<<<<<< + * cdef FastQuadCurve curve # pyright: ignore + * cdef double distance + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening { + PyObject *(*has_recursion_error)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *); + PyObject *(*reset_recursion_check)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *); + PyObject *(*flatten)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *__pyx_vtabptr_5ezdxf_3acc_8bezier3p__Flattening; + + +/* "ezdxf/acc/bezier3p.pyx":164 + * + * + * cdef class FastQuadCurve: # <<<<<<<<<<<<<< + * cdef: + * double[3] offset + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*point)(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *, double); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*tangent)(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *, double); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_vtabptr_5ezdxf_3acc_8bezier3p_FastQuadCurve; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* ImportDottedModule.proto */ +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_has_recursion_error(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_reset_recursion_check(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_flatten(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point, double __pyx_v_start_t, double __pyx_v_end_t); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_point(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, double __pyx_v_t); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_tangent(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, double __pyx_v_t); /* proto*/ + +/* Module declarations from "ezdxf.acc.vector" */ +static int (*__pyx_f_5ezdxf_3acc_6vector_isclose)(double, double, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_add)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static double (*__pyx_f_5ezdxf_3acc_6vector_v3_dist)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_lerp)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ + +/* Module declarations from "ezdxf.acc.matrix44" */ + +/* Module declarations from "ezdxf.acc.bezier3p" */ +static double __pyx_v_5ezdxf_3acc_8bezier3p_RECURSION_LIMIT; +static void __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double *, double); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.bezier3p" +extern int __pyx_module_is_main_ezdxf__acc__bezier3p; +int __pyx_module_is_main_ezdxf__acc__bezier3p = 0; + +/* Implementation of "ezdxf.acc.bezier3p" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_DeprecationWarning; +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_TypeError; +/* #### Code section: string_decls ### */ +static const char __pyx_k_f[] = "f"; +static const char __pyx_k_m[] = "m"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k__6[] = "."; +static const char __pyx_k__7[] = "*"; +static const char __pyx_k_dt[] = "dt"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_p0[] = "p0"; +static const char __pyx_k_p1[] = "p1"; +static const char __pyx_k_p2[] = "p2"; +static const char __pyx_k_t0[] = "t0"; +static const char __pyx_k_t1[] = "t1"; +static const char __pyx_k__28[] = "?"; +static const char __pyx_k_all[] = "__all__"; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_Vec3[] = "Vec3"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_spec[] = "__spec__"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_warn[] = "warn"; +static const char __pyx_k_curve[] = "curve"; +static const char __pyx_k_float[] = "float"; +static const char __pyx_k_point[] = "point"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_length[] = "length"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_delta_t[] = "delta_t"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_reverse[] = "reverse"; +static const char __pyx_k_segment[] = "segment"; +static const char __pyx_k_tangent[] = "tangent"; +static const char __pyx_k_Bezier3P[] = "Bezier3P"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_distance[] = "distance"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_segments[] = "segments"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_warnings[] = "warnings"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_defpoints[] = "defpoints"; +static const char __pyx_k_end_point[] = "end_point"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_list_Vec3[] = "list[Vec3]"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_transform[] = "transform"; +static const char __pyx_k_Flattening[] = "_Flattening"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_flattening[] = "flattening"; +static const char __pyx_k_prev_point[] = "prev_point"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_start_flag[] = "start_flag"; +static const char __pyx_k_approximate[] = "approximate"; +static const char __pyx_k_start_point[] = "start_point"; +static const char __pyx_k_initializing[] = "_initializing"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_FastQuadCurve[] = "FastQuadCurve"; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_Bezier3P_point[] = "Bezier3P.point"; +static const char __pyx_k_RecursionError[] = "RecursionError"; +static const char __pyx_k_control_points[] = "control_points"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_Bezier3P_reverse[] = "Bezier3P.reverse"; +static const char __pyx_k_Bezier3P_tangent[] = "Bezier3P.tangent"; +static const char __pyx_k_Bezier3P___reduce[] = "Bezier3P.__reduce__"; +static const char __pyx_k_Bezier3P_transform[] = "Bezier3P.transform"; +static const char __pyx_k_DeprecationWarning[] = "DeprecationWarning"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ezdxf_acc_bezier3p[] = "ezdxf.acc.bezier3p"; +static const char __pyx_k_transform_vertices[] = "transform_vertices"; +static const char __pyx_k_Bezier3P_flattening[] = "Bezier3P.flattening"; +static const char __pyx_k_approximated_length[] = "approximated_length"; +static const char __pyx_k_Bezier3P_approximate[] = "Bezier3P.approximate"; +static const char __pyx_k_t_not_in_range_0_to_1[] = "t not in range [0 to 1]"; +static const char __pyx_k_Flattening___reduce_cython[] = "_Flattening.__reduce_cython__"; +static const char __pyx_k_src_ezdxf_acc_bezier3p_pyx[] = "src/ezdxf/acc/bezier3p.pyx"; +static const char __pyx_k_Bezier3P_approximated_length[] = "Bezier3P.approximated_length"; +static const char __pyx_k_Flattening___setstate_cython[] = "_Flattening.__setstate_cython__"; +static const char __pyx_k_FastQuadCurve___reduce_cython[] = "FastQuadCurve.__reduce_cython__"; +static const char __pyx_k_Three_control_points_required[] = "Three control points required."; +static const char __pyx_k_Bezier3P_flattening_error_check[] = "Bezier3P flattening error, check for very large coordinates"; +static const char __pyx_k_FastQuadCurve___setstate_cython[] = "FastQuadCurve.__setstate_cython__"; +static const char __pyx_k_Bezier3P_requires_defpoints_of_t[] = "Bezier3P requires defpoints of type Vec2 or Vec3 in the future"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +/* #### Code section: decls ### */ +static int __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, PyObject *__pyx_v_defpoints); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_4point(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_t); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_6tangent(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_t); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_8approximate(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_10flattening(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_distance, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_12approximated_length(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, PyObject *__pyx_v_segments); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14reverse(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_16transform(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_curve, double __pyx_v_distance); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p_Bezier3P(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p__Flattening(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p_FastQuadCurve(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44; + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P; + PyObject *__pyx_type_5ezdxf_3acc_8bezier3p__Flattening; + PyObject *__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve; + PyObject *__pyx_n_s_Bezier3P; + PyObject *__pyx_n_u_Bezier3P; + PyObject *__pyx_n_s_Bezier3P___reduce; + PyObject *__pyx_n_s_Bezier3P_approximate; + PyObject *__pyx_n_s_Bezier3P_approximated_length; + PyObject *__pyx_n_s_Bezier3P_flattening; + PyObject *__pyx_kp_u_Bezier3P_flattening_error_check; + PyObject *__pyx_n_s_Bezier3P_point; + PyObject *__pyx_kp_u_Bezier3P_requires_defpoints_of_t; + PyObject *__pyx_n_s_Bezier3P_reverse; + PyObject *__pyx_n_s_Bezier3P_tangent; + PyObject *__pyx_n_s_Bezier3P_transform; + PyObject *__pyx_n_s_DeprecationWarning; + PyObject *__pyx_n_s_FastQuadCurve; + PyObject *__pyx_n_s_FastQuadCurve___reduce_cython; + PyObject *__pyx_n_s_FastQuadCurve___setstate_cython; + PyObject *__pyx_n_s_Flattening; + PyObject *__pyx_n_s_Flattening___reduce_cython; + PyObject *__pyx_n_s_Flattening___setstate_cython; + PyObject *__pyx_n_s_RecursionError; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_kp_u_Three_control_points_required; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s_Vec3; + PyObject *__pyx_n_s__28; + PyObject *__pyx_kp_u__6; + PyObject *__pyx_n_s__7; + PyObject *__pyx_n_s_all; + PyObject *__pyx_n_s_approximate; + PyObject *__pyx_n_s_approximated_length; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_control_points; + PyObject *__pyx_n_s_curve; + PyObject *__pyx_n_s_defpoints; + PyObject *__pyx_n_s_delta_t; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_distance; + PyObject *__pyx_n_s_dt; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_end_point; + PyObject *__pyx_n_s_ezdxf_acc_bezier3p; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_n_s_f; + PyObject *__pyx_n_s_flattening; + PyObject *__pyx_n_s_float; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_initializing; + PyObject *__pyx_n_s_int; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_length; + PyObject *__pyx_kp_s_list_Vec3; + PyObject *__pyx_n_s_m; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_name; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_p0; + PyObject *__pyx_n_s_p1; + PyObject *__pyx_n_s_p2; + PyObject *__pyx_n_s_point; + PyObject *__pyx_n_s_points; + PyObject *__pyx_n_s_prev_point; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_reverse; + PyObject *__pyx_n_s_segment; + PyObject *__pyx_n_s_segments; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_spec; + PyObject *__pyx_kp_s_src_ezdxf_acc_bezier3p_pyx; + PyObject *__pyx_n_s_start_flag; + PyObject *__pyx_n_s_start_point; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_t; + PyObject *__pyx_n_s_t0; + PyObject *__pyx_n_s_t1; + PyObject *__pyx_kp_u_t_not_in_range_0_to_1; + PyObject *__pyx_n_s_tangent; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_transform; + PyObject *__pyx_n_s_transform_vertices; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_warn; + PyObject *__pyx_n_s_warnings; + PyObject *__pyx_int_4; + PyObject *__pyx_int_128; + PyObject *__pyx_k__5; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__2; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__8; + PyObject *__pyx_tuple__10; + PyObject *__pyx_tuple__13; + PyObject *__pyx_tuple__15; + PyObject *__pyx_tuple__17; + PyObject *__pyx_tuple__18; + PyObject *__pyx_tuple__21; + PyObject *__pyx_tuple__24; + PyObject *__pyx_codeobj__9; + PyObject *__pyx_codeobj__11; + PyObject *__pyx_codeobj__12; + PyObject *__pyx_codeobj__14; + PyObject *__pyx_codeobj__16; + PyObject *__pyx_codeobj__19; + PyObject *__pyx_codeobj__20; + PyObject *__pyx_codeobj__22; + PyObject *__pyx_codeobj__23; + PyObject *__pyx_codeobj__25; + PyObject *__pyx_codeobj__26; + PyObject *__pyx_codeobj__27; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier3p__Flattening); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P); + Py_CLEAR(clear_module_state->__pyx_n_u_Bezier3P); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P___reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_approximate); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_approximated_length); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_flattening); + Py_CLEAR(clear_module_state->__pyx_kp_u_Bezier3P_flattening_error_check); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_point); + Py_CLEAR(clear_module_state->__pyx_kp_u_Bezier3P_requires_defpoints_of_t); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_reverse); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_tangent); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier3P_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_DeprecationWarning); + Py_CLEAR(clear_module_state->__pyx_n_s_FastQuadCurve); + Py_CLEAR(clear_module_state->__pyx_n_s_FastQuadCurve___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_FastQuadCurve___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_RecursionError); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_kp_u_Three_control_points_required); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s__28); + Py_CLEAR(clear_module_state->__pyx_kp_u__6); + Py_CLEAR(clear_module_state->__pyx_n_s__7); + Py_CLEAR(clear_module_state->__pyx_n_s_all); + Py_CLEAR(clear_module_state->__pyx_n_s_approximate); + Py_CLEAR(clear_module_state->__pyx_n_s_approximated_length); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_control_points); + Py_CLEAR(clear_module_state->__pyx_n_s_curve); + Py_CLEAR(clear_module_state->__pyx_n_s_defpoints); + Py_CLEAR(clear_module_state->__pyx_n_s_delta_t); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_distance); + Py_CLEAR(clear_module_state->__pyx_n_s_dt); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_end_point); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_bezier3p); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_n_s_f); + Py_CLEAR(clear_module_state->__pyx_n_s_flattening); + Py_CLEAR(clear_module_state->__pyx_n_s_float); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_initializing); + Py_CLEAR(clear_module_state->__pyx_n_s_int); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_length); + Py_CLEAR(clear_module_state->__pyx_kp_s_list_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_m); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_p0); + Py_CLEAR(clear_module_state->__pyx_n_s_p1); + Py_CLEAR(clear_module_state->__pyx_n_s_p2); + Py_CLEAR(clear_module_state->__pyx_n_s_point); + Py_CLEAR(clear_module_state->__pyx_n_s_points); + Py_CLEAR(clear_module_state->__pyx_n_s_prev_point); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_reverse); + Py_CLEAR(clear_module_state->__pyx_n_s_segment); + Py_CLEAR(clear_module_state->__pyx_n_s_segments); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_spec); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_bezier3p_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start_flag); + Py_CLEAR(clear_module_state->__pyx_n_s_start_point); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_t); + Py_CLEAR(clear_module_state->__pyx_n_s_t0); + Py_CLEAR(clear_module_state->__pyx_n_s_t1); + Py_CLEAR(clear_module_state->__pyx_kp_u_t_not_in_range_0_to_1); + Py_CLEAR(clear_module_state->__pyx_n_s_tangent); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_warn); + Py_CLEAR(clear_module_state->__pyx_n_s_warnings); + Py_CLEAR(clear_module_state->__pyx_int_4); + Py_CLEAR(clear_module_state->__pyx_int_128); + Py_CLEAR(clear_module_state->__pyx_k__5); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__2); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__8); + Py_CLEAR(clear_module_state->__pyx_tuple__10); + Py_CLEAR(clear_module_state->__pyx_tuple__13); + Py_CLEAR(clear_module_state->__pyx_tuple__15); + Py_CLEAR(clear_module_state->__pyx_tuple__17); + Py_CLEAR(clear_module_state->__pyx_tuple__18); + Py_CLEAR(clear_module_state->__pyx_tuple__21); + Py_CLEAR(clear_module_state->__pyx_tuple__24); + Py_CLEAR(clear_module_state->__pyx_codeobj__9); + Py_CLEAR(clear_module_state->__pyx_codeobj__11); + Py_CLEAR(clear_module_state->__pyx_codeobj__12); + Py_CLEAR(clear_module_state->__pyx_codeobj__14); + Py_CLEAR(clear_module_state->__pyx_codeobj__16); + Py_CLEAR(clear_module_state->__pyx_codeobj__19); + Py_CLEAR(clear_module_state->__pyx_codeobj__20); + Py_CLEAR(clear_module_state->__pyx_codeobj__22); + Py_CLEAR(clear_module_state->__pyx_codeobj__23); + Py_CLEAR(clear_module_state->__pyx_codeobj__25); + Py_CLEAR(clear_module_state->__pyx_codeobj__26); + Py_CLEAR(clear_module_state->__pyx_codeobj__27); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier3p__Flattening); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P); + Py_VISIT(traverse_module_state->__pyx_n_u_Bezier3P); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P___reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_approximate); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_approximated_length); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_flattening); + Py_VISIT(traverse_module_state->__pyx_kp_u_Bezier3P_flattening_error_check); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_point); + Py_VISIT(traverse_module_state->__pyx_kp_u_Bezier3P_requires_defpoints_of_t); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_reverse); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_tangent); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier3P_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_DeprecationWarning); + Py_VISIT(traverse_module_state->__pyx_n_s_FastQuadCurve); + Py_VISIT(traverse_module_state->__pyx_n_s_FastQuadCurve___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_FastQuadCurve___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_RecursionError); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_kp_u_Three_control_points_required); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s__28); + Py_VISIT(traverse_module_state->__pyx_kp_u__6); + Py_VISIT(traverse_module_state->__pyx_n_s__7); + Py_VISIT(traverse_module_state->__pyx_n_s_all); + Py_VISIT(traverse_module_state->__pyx_n_s_approximate); + Py_VISIT(traverse_module_state->__pyx_n_s_approximated_length); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_control_points); + Py_VISIT(traverse_module_state->__pyx_n_s_curve); + Py_VISIT(traverse_module_state->__pyx_n_s_defpoints); + Py_VISIT(traverse_module_state->__pyx_n_s_delta_t); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_distance); + Py_VISIT(traverse_module_state->__pyx_n_s_dt); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_end_point); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_bezier3p); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_n_s_f); + Py_VISIT(traverse_module_state->__pyx_n_s_flattening); + Py_VISIT(traverse_module_state->__pyx_n_s_float); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_initializing); + Py_VISIT(traverse_module_state->__pyx_n_s_int); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_length); + Py_VISIT(traverse_module_state->__pyx_kp_s_list_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_m); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_p0); + Py_VISIT(traverse_module_state->__pyx_n_s_p1); + Py_VISIT(traverse_module_state->__pyx_n_s_p2); + Py_VISIT(traverse_module_state->__pyx_n_s_point); + Py_VISIT(traverse_module_state->__pyx_n_s_points); + Py_VISIT(traverse_module_state->__pyx_n_s_prev_point); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_reverse); + Py_VISIT(traverse_module_state->__pyx_n_s_segment); + Py_VISIT(traverse_module_state->__pyx_n_s_segments); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_spec); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_bezier3p_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start_flag); + Py_VISIT(traverse_module_state->__pyx_n_s_start_point); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_t); + Py_VISIT(traverse_module_state->__pyx_n_s_t0); + Py_VISIT(traverse_module_state->__pyx_n_s_t1); + Py_VISIT(traverse_module_state->__pyx_kp_u_t_not_in_range_0_to_1); + Py_VISIT(traverse_module_state->__pyx_n_s_tangent); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_warn); + Py_VISIT(traverse_module_state->__pyx_n_s_warnings); + Py_VISIT(traverse_module_state->__pyx_int_4); + Py_VISIT(traverse_module_state->__pyx_int_128); + Py_VISIT(traverse_module_state->__pyx_k__5); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__2); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__8); + Py_VISIT(traverse_module_state->__pyx_tuple__10); + Py_VISIT(traverse_module_state->__pyx_tuple__13); + Py_VISIT(traverse_module_state->__pyx_tuple__15); + Py_VISIT(traverse_module_state->__pyx_tuple__17); + Py_VISIT(traverse_module_state->__pyx_tuple__18); + Py_VISIT(traverse_module_state->__pyx_tuple__21); + Py_VISIT(traverse_module_state->__pyx_tuple__24); + Py_VISIT(traverse_module_state->__pyx_codeobj__9); + Py_VISIT(traverse_module_state->__pyx_codeobj__11); + Py_VISIT(traverse_module_state->__pyx_codeobj__12); + Py_VISIT(traverse_module_state->__pyx_codeobj__14); + Py_VISIT(traverse_module_state->__pyx_codeobj__16); + Py_VISIT(traverse_module_state->__pyx_codeobj__19); + Py_VISIT(traverse_module_state->__pyx_codeobj__20); + Py_VISIT(traverse_module_state->__pyx_codeobj__22); + Py_VISIT(traverse_module_state->__pyx_codeobj__23); + Py_VISIT(traverse_module_state->__pyx_codeobj__25); + Py_VISIT(traverse_module_state->__pyx_codeobj__26); + Py_VISIT(traverse_module_state->__pyx_codeobj__27); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P +#define __pyx_type_5ezdxf_3acc_8bezier3p__Flattening __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier3p__Flattening +#define __pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve +#endif +#define __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P +#define __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening +#define __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve +#define __pyx_n_s_Bezier3P __pyx_mstate_global->__pyx_n_s_Bezier3P +#define __pyx_n_u_Bezier3P __pyx_mstate_global->__pyx_n_u_Bezier3P +#define __pyx_n_s_Bezier3P___reduce __pyx_mstate_global->__pyx_n_s_Bezier3P___reduce +#define __pyx_n_s_Bezier3P_approximate __pyx_mstate_global->__pyx_n_s_Bezier3P_approximate +#define __pyx_n_s_Bezier3P_approximated_length __pyx_mstate_global->__pyx_n_s_Bezier3P_approximated_length +#define __pyx_n_s_Bezier3P_flattening __pyx_mstate_global->__pyx_n_s_Bezier3P_flattening +#define __pyx_kp_u_Bezier3P_flattening_error_check __pyx_mstate_global->__pyx_kp_u_Bezier3P_flattening_error_check +#define __pyx_n_s_Bezier3P_point __pyx_mstate_global->__pyx_n_s_Bezier3P_point +#define __pyx_kp_u_Bezier3P_requires_defpoints_of_t __pyx_mstate_global->__pyx_kp_u_Bezier3P_requires_defpoints_of_t +#define __pyx_n_s_Bezier3P_reverse __pyx_mstate_global->__pyx_n_s_Bezier3P_reverse +#define __pyx_n_s_Bezier3P_tangent __pyx_mstate_global->__pyx_n_s_Bezier3P_tangent +#define __pyx_n_s_Bezier3P_transform __pyx_mstate_global->__pyx_n_s_Bezier3P_transform +#define __pyx_n_s_DeprecationWarning __pyx_mstate_global->__pyx_n_s_DeprecationWarning +#define __pyx_n_s_FastQuadCurve __pyx_mstate_global->__pyx_n_s_FastQuadCurve +#define __pyx_n_s_FastQuadCurve___reduce_cython __pyx_mstate_global->__pyx_n_s_FastQuadCurve___reduce_cython +#define __pyx_n_s_FastQuadCurve___setstate_cython __pyx_mstate_global->__pyx_n_s_FastQuadCurve___setstate_cython +#define __pyx_n_s_Flattening __pyx_mstate_global->__pyx_n_s_Flattening +#define __pyx_n_s_Flattening___reduce_cython __pyx_mstate_global->__pyx_n_s_Flattening___reduce_cython +#define __pyx_n_s_Flattening___setstate_cython __pyx_mstate_global->__pyx_n_s_Flattening___setstate_cython +#define __pyx_n_s_RecursionError __pyx_mstate_global->__pyx_n_s_RecursionError +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_kp_u_Three_control_points_required __pyx_mstate_global->__pyx_kp_u_Three_control_points_required +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s_Vec3 __pyx_mstate_global->__pyx_n_s_Vec3 +#define __pyx_n_s__28 __pyx_mstate_global->__pyx_n_s__28 +#define __pyx_kp_u__6 __pyx_mstate_global->__pyx_kp_u__6 +#define __pyx_n_s__7 __pyx_mstate_global->__pyx_n_s__7 +#define __pyx_n_s_all __pyx_mstate_global->__pyx_n_s_all +#define __pyx_n_s_approximate __pyx_mstate_global->__pyx_n_s_approximate +#define __pyx_n_s_approximated_length __pyx_mstate_global->__pyx_n_s_approximated_length +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_control_points __pyx_mstate_global->__pyx_n_s_control_points +#define __pyx_n_s_curve __pyx_mstate_global->__pyx_n_s_curve +#define __pyx_n_s_defpoints __pyx_mstate_global->__pyx_n_s_defpoints +#define __pyx_n_s_delta_t __pyx_mstate_global->__pyx_n_s_delta_t +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_distance __pyx_mstate_global->__pyx_n_s_distance +#define __pyx_n_s_dt __pyx_mstate_global->__pyx_n_s_dt +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_end_point __pyx_mstate_global->__pyx_n_s_end_point +#define __pyx_n_s_ezdxf_acc_bezier3p __pyx_mstate_global->__pyx_n_s_ezdxf_acc_bezier3p +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_n_s_f __pyx_mstate_global->__pyx_n_s_f +#define __pyx_n_s_flattening __pyx_mstate_global->__pyx_n_s_flattening +#define __pyx_n_s_float __pyx_mstate_global->__pyx_n_s_float +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing +#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_length __pyx_mstate_global->__pyx_n_s_length +#define __pyx_kp_s_list_Vec3 __pyx_mstate_global->__pyx_kp_s_list_Vec3 +#define __pyx_n_s_m __pyx_mstate_global->__pyx_n_s_m +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_p0 __pyx_mstate_global->__pyx_n_s_p0 +#define __pyx_n_s_p1 __pyx_mstate_global->__pyx_n_s_p1 +#define __pyx_n_s_p2 __pyx_mstate_global->__pyx_n_s_p2 +#define __pyx_n_s_point __pyx_mstate_global->__pyx_n_s_point +#define __pyx_n_s_points __pyx_mstate_global->__pyx_n_s_points +#define __pyx_n_s_prev_point __pyx_mstate_global->__pyx_n_s_prev_point +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_reverse __pyx_mstate_global->__pyx_n_s_reverse +#define __pyx_n_s_segment __pyx_mstate_global->__pyx_n_s_segment +#define __pyx_n_s_segments __pyx_mstate_global->__pyx_n_s_segments +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec +#define __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_bezier3p_pyx +#define __pyx_n_s_start_flag __pyx_mstate_global->__pyx_n_s_start_flag +#define __pyx_n_s_start_point __pyx_mstate_global->__pyx_n_s_start_point +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_t __pyx_mstate_global->__pyx_n_s_t +#define __pyx_n_s_t0 __pyx_mstate_global->__pyx_n_s_t0 +#define __pyx_n_s_t1 __pyx_mstate_global->__pyx_n_s_t1 +#define __pyx_kp_u_t_not_in_range_0_to_1 __pyx_mstate_global->__pyx_kp_u_t_not_in_range_0_to_1 +#define __pyx_n_s_tangent __pyx_mstate_global->__pyx_n_s_tangent +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_transform __pyx_mstate_global->__pyx_n_s_transform +#define __pyx_n_s_transform_vertices __pyx_mstate_global->__pyx_n_s_transform_vertices +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_warn __pyx_mstate_global->__pyx_n_s_warn +#define __pyx_n_s_warnings __pyx_mstate_global->__pyx_n_s_warnings +#define __pyx_int_4 __pyx_mstate_global->__pyx_int_4 +#define __pyx_int_128 __pyx_mstate_global->__pyx_int_128 +#define __pyx_k__5 __pyx_mstate_global->__pyx_k__5 +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__2 __pyx_mstate_global->__pyx_tuple__2 +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8 +#define __pyx_tuple__10 __pyx_mstate_global->__pyx_tuple__10 +#define __pyx_tuple__13 __pyx_mstate_global->__pyx_tuple__13 +#define __pyx_tuple__15 __pyx_mstate_global->__pyx_tuple__15 +#define __pyx_tuple__17 __pyx_mstate_global->__pyx_tuple__17 +#define __pyx_tuple__18 __pyx_mstate_global->__pyx_tuple__18 +#define __pyx_tuple__21 __pyx_mstate_global->__pyx_tuple__21 +#define __pyx_tuple__24 __pyx_mstate_global->__pyx_tuple__24 +#define __pyx_codeobj__9 __pyx_mstate_global->__pyx_codeobj__9 +#define __pyx_codeobj__11 __pyx_mstate_global->__pyx_codeobj__11 +#define __pyx_codeobj__12 __pyx_mstate_global->__pyx_codeobj__12 +#define __pyx_codeobj__14 __pyx_mstate_global->__pyx_codeobj__14 +#define __pyx_codeobj__16 __pyx_mstate_global->__pyx_codeobj__16 +#define __pyx_codeobj__19 __pyx_mstate_global->__pyx_codeobj__19 +#define __pyx_codeobj__20 __pyx_mstate_global->__pyx_codeobj__20 +#define __pyx_codeobj__22 __pyx_mstate_global->__pyx_codeobj__22 +#define __pyx_codeobj__23 __pyx_mstate_global->__pyx_codeobj__23 +#define __pyx_codeobj__25 __pyx_mstate_global->__pyx_codeobj__25 +#define __pyx_codeobj__26 __pyx_mstate_global->__pyx_codeobj__26 +#define __pyx_codeobj__27 __pyx_mstate_global->__pyx_codeobj__27 +/* #### Code section: module_code ### */ + +/* "matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + +static CYTHON_INLINE PyObject *__pyx_f_5ezdxf_3acc_8matrix44_swap(double *__pyx_v_a, double *__pyx_v_b) { + double __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("swap", 1); + + /* "matrix44.pxd":13 + * + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] # <<<<<<<<<<<<<< + * a[0] = b[0] + * b[0] = tmp + */ + __pyx_v_tmp = (__pyx_v_a[0]); + + /* "matrix44.pxd":14 + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] + * a[0] = b[0] # <<<<<<<<<<<<<< + * b[0] = tmp + */ + (__pyx_v_a[0]) = (__pyx_v_b[0]); + + /* "matrix44.pxd":15 + * cdef double tmp = a[0] + * a[0] = b[0] + * b[0] = tmp # <<<<<<<<<<<<<< + */ + (__pyx_v_b[0]) = __pyx_v_tmp; + + /* "matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":27 + * readonly Vec3 end_point + * + * def __cinit__(self, defpoints: Sequence[UVec]): # <<<<<<<<<<<<<< + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_defpoints = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_defpoints,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_defpoints)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 27, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 27, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + } + __pyx_v_defpoints = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 27, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_defpoints); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, PyObject *__pyx_v_defpoints) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + Py_ssize_t __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/bezier3p.pyx":28 + * + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): # <<<<<<<<<<<<<< + * warnings.warn( + * DeprecationWarning, + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_TypeCheck(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (!__pyx_t_3) { + } else { + __pyx_t_2 = __pyx_t_3; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __Pyx_TypeCheck(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = __pyx_t_3; + __pyx_L4_bool_binop_done:; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + + /* "ezdxf/acc/bezier3p.pyx":29 + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( # <<<<<<<<<<<<<< + * DeprecationWarning, + * "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_warnings); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_warn); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":30 + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + * DeprecationWarning, # <<<<<<<<<<<<<< + * "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + * ) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":28 + * + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): # <<<<<<<<<<<<<< + * warnings.warn( + * DeprecationWarning, + */ + } + + /* "ezdxf/acc/bezier3p.pyx":33 + * "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + * ) + * if len(defpoints) == 3: # <<<<<<<<<<<<<< + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + */ + __pyx_t_5 = PyObject_Length(__pyx_v_defpoints); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(0, 33, __pyx_L1_error) + __pyx_t_3 = (__pyx_t_5 == 3); + if (likely(__pyx_t_3)) { + + /* "ezdxf/acc/bezier3p.pyx":34 + * ) + * if len(defpoints) == 3: + * self.start_point = Vec3(defpoints[0]) # <<<<<<<<<<<<<< + * self.cp1 = Vec3(defpoints[1]) + * self.end_point = Vec3(defpoints[2]) + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF((PyObject *)__pyx_v_self->start_point); + __Pyx_DECREF((PyObject *)__pyx_v_self->start_point); + __pyx_v_self->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bezier3p.pyx":35 + * if len(defpoints) == 3: + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) # <<<<<<<<<<<<<< + * self.end_point = Vec3(defpoints[2]) + * + */ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_defpoints, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->cp1); + __Pyx_DECREF((PyObject *)__pyx_v_self->cp1); + __pyx_v_self->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":36 + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + * self.end_point = Vec3(defpoints[2]) # <<<<<<<<<<<<<< + * + * self.curve = FastQuadCurve( + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF((PyObject *)__pyx_v_self->end_point); + __Pyx_DECREF((PyObject *)__pyx_v_self->end_point); + __pyx_v_self->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bezier3p.pyx":38 + * self.end_point = Vec3(defpoints[2]) + * + * self.curve = FastQuadCurve( # <<<<<<<<<<<<<< + * self.start_point, + * self.cp1, + */ + __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 38, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 38, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 38, __pyx_L1_error); + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve), __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->curve); + __Pyx_DECREF((PyObject *)__pyx_v_self->curve); + __pyx_v_self->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":33 + * "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + * ) + * if len(defpoints) == 3: # <<<<<<<<<<<<<< + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + */ + goto __pyx_L6; + } + + /* "ezdxf/acc/bezier3p.pyx":44 + * ) + * else: + * raise ValueError("Three control points required.") # <<<<<<<<<<<<<< + * + * @property + */ + /*else*/ { + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 44, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 44, __pyx_L1_error) + } + __pyx_L6:; + + /* "ezdxf/acc/bezier3p.pyx":27 + * readonly Vec3 end_point + * + * def __cinit__(self, defpoints: Sequence[UVec]): # <<<<<<<<<<<<<< + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":46 + * raise ValueError("Three control points required.") + * + * @property # <<<<<<<<<<<<<< + * def control_points(self) -> tuple[Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.end_point + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bezier3p.pyx":48 + * @property + * def control_points(self) -> tuple[Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.end_point # <<<<<<<<<<<<<< + * + * def __reduce__(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 48, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 48, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 48, __pyx_L1_error); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":46 + * raise ValueError("Three control points required.") + * + * @property # <<<<<<<<<<<<<< + * def control_points(self) -> tuple[Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.end_point + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.control_points.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":50 + * return self.start_point, self.cp1, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier3P, (self.control_points,) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__ = {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_2__reduce__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce__", 1); + + /* "ezdxf/acc/bezier3p.pyx":51 + * + * def __reduce__(self): + * return Bezier3P, (self.control_points,) # <<<<<<<<<<<<<< + * + * def point(self, double t) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_control_points); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 51, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P))) __PYX_ERR(0, 51, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_2)) __PYX_ERR(0, 51, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":50 + * return self.start_point, self.cp1, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier3P, (self.control_points,) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":53 + * return Bezier3P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_5point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_5point = {"point", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_5point, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_5point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_t; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("point (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 53, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "point") < 0)) __PYX_ERR(0, 53, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_t == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 53, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("point", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 53, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_4point(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_4point(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + + /* "ezdxf/acc/bezier3p.pyx":54 + * + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.point(t) + * else: + */ + __pyx_t_1 = (0.0 <= __pyx_v_t); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_t <= 1.0); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier3p.pyx":55 + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) # <<<<<<<<<<<<<< + * else: + * raise ValueError("t not in range [0 to 1]") + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":54 + * + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.point(t) + * else: + */ + } + + /* "ezdxf/acc/bezier3p.pyx":57 + * return self.curve.point(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def tangent(self, double t) -> Vec3: + */ + /*else*/ { + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 57, __pyx_L1_error) + } + + /* "ezdxf/acc/bezier3p.pyx":53 + * return Bezier3P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":59 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent = {"tangent", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_t; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("tangent (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "tangent") < 0)) __PYX_ERR(0, 59, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_t == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("tangent", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 59, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_6tangent(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_6tangent(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tangent", 1); + + /* "ezdxf/acc/bezier3p.pyx":60 + * + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.tangent(t) + * else: + */ + __pyx_t_1 = (0.0 <= __pyx_v_t); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_t <= 1.0); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier3p.pyx":61 + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) # <<<<<<<<<<<<<< + * else: + * raise ValueError("t not in range [0 to 1]") + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self->curve->__pyx_vtab)->tangent(__pyx_v_self->curve, __pyx_v_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":60 + * + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.tangent(t) + * else: + */ + } + + /* "ezdxf/acc/bezier3p.pyx":63 + * return self.curve.tangent(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def approximate(self, int segments) -> list[Vec3]: + */ + /*else*/ { + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 63, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 63, __pyx_L1_error) + } + + /* "ezdxf/acc/bezier3p.pyx":59 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":65 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate = {"approximate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("approximate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "approximate") < 0)) __PYX_ERR(0, 65, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_segments = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("approximate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 65, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.approximate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_8approximate(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_8approximate(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, int __pyx_v_segments) { + double __pyx_v_delta_t; + int __pyx_v_segment; + PyObject *__pyx_v_points = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + unsigned int __pyx_t_9; + int __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("approximate", 1); + + /* "ezdxf/acc/bezier3p.pyx":68 + * cdef double delta_t + * cdef int segment + * cdef list points = [self.start_point] # <<<<<<<<<<<<<< + * + * if segments < 1: + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 68, __pyx_L1_error); + __pyx_v_points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":70 + * cdef list points = [self.start_point] + * + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError(segments) + * delta_t = 1.0 / segments + */ + __pyx_t_2 = (__pyx_v_segments < 1); + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/bezier3p.pyx":71 + * + * if segments < 1: + * raise ValueError(segments) # <<<<<<<<<<<<<< + * delta_t = 1.0 / segments + * for segment in range(1, segments): + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_segments); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 71, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":70 + * cdef list points = [self.start_point] + * + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError(segments) + * delta_t = 1.0 / segments + */ + } + + /* "ezdxf/acc/bezier3p.pyx":72 + * if segments < 1: + * raise ValueError(segments) + * delta_t = 1.0 / segments # <<<<<<<<<<<<<< + * for segment in range(1, segments): + * points.append(self.point(delta_t * segment)) + */ + if (unlikely(__pyx_v_segments == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 72, __pyx_L1_error) + } + __pyx_v_delta_t = (1.0 / ((double)__pyx_v_segments)); + + /* "ezdxf/acc/bezier3p.pyx":73 + * raise ValueError(segments) + * delta_t = 1.0 / segments + * for segment in range(1, segments): # <<<<<<<<<<<<<< + * points.append(self.point(delta_t * segment)) + * points.append(self.end_point) + */ + __pyx_t_4 = __pyx_v_segments; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = 1; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_segment = __pyx_t_6; + + /* "ezdxf/acc/bezier3p.pyx":74 + * delta_t = 1.0 / segments + * for segment in range(1, segments): + * points.append(self.point(delta_t * segment)) # <<<<<<<<<<<<<< + * points.append(self.end_point) + * return points + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_point); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_delta_t * __pyx_v_segment)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = NULL; + __pyx_t_9 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_9 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_8, __pyx_t_7}; + __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_9, 1+__pyx_t_9); + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_points, __pyx_t_3); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + + /* "ezdxf/acc/bezier3p.pyx":75 + * for segment in range(1, segments): + * points.append(self.point(delta_t * segment)) + * points.append(self.end_point) # <<<<<<<<<<<<<< + * return points + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_self->end_point); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_points, __pyx_t_3); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier3p.pyx":76 + * points.append(self.point(delta_t * segment)) + * points.append(self.end_point) + * return points # <<<<<<<<<<<<<< + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_points); + __pyx_r = __pyx_v_points; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":65 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.approximate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_points); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":78 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening = {"flattening", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_distance; + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("flattening (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_distance,&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_distance)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 78, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 78, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "flattening") < 0)) __PYX_ERR(0, 78, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_distance = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 78, __pyx_L3_error) + if (values[1]) { + __pyx_v_segments = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 78, __pyx_L3_error) + } else { + __pyx_v_segments = ((int)4); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("flattening", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 78, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.flattening", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_10flattening(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_distance, __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_10flattening(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, double __pyx_v_distance, int __pyx_v_segments) { + double __pyx_v_dt; + double __pyx_v_t0; + double __pyx_v_t1; + struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_f = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("flattening", 1); + + /* "ezdxf/acc/bezier3p.pyx":79 + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + * cdef double dt = 1.0 / segments # <<<<<<<<<<<<<< + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) + */ + if (unlikely(__pyx_v_segments == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 79, __pyx_L1_error) + } + __pyx_v_dt = (1.0 / ((double)__pyx_v_segments)); + + /* "ezdxf/acc/bezier3p.pyx":80 + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 # <<<<<<<<<<<<<< + * cdef _Flattening f = _Flattening(self, distance) + * cdef Vec3 start_point = self.start_point + */ + __pyx_v_t0 = 0.0; + + /* "ezdxf/acc/bezier3p.pyx":81 + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) # <<<<<<<<<<<<<< + * cdef Vec3 start_point = self.start_point + * cdef Vec3 end_point + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_distance); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 81, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_v_self))) __PYX_ERR(0, 81, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening), __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_f = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":82 + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) + * cdef Vec3 start_point = self.start_point # <<<<<<<<<<<<<< + * cdef Vec3 end_point + * while t0 < 1.0: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->start_point); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":84 + * cdef Vec3 start_point = self.start_point + * cdef Vec3 end_point + * while t0 < 1.0: # <<<<<<<<<<<<<< + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + */ + while (1) { + __pyx_t_3 = (__pyx_v_t0 < 1.0); + if (!__pyx_t_3) break; + + /* "ezdxf/acc/bezier3p.pyx":85 + * cdef Vec3 end_point + * while t0 < 1.0: + * t1 = t0 + dt # <<<<<<<<<<<<<< + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point + */ + __pyx_v_t1 = (__pyx_v_t0 + __pyx_v_dt); + + /* "ezdxf/acc/bezier3p.pyx":86 + * while t0 < 1.0: + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * end_point = self.end_point + * t1 = 1.0 + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_t1, 1.0, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 86, __pyx_L1_error) + if (__pyx_t_3) { + + /* "ezdxf/acc/bezier3p.pyx":87 + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point # <<<<<<<<<<<<<< + * t1 = 1.0 + * else: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->end_point); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_end_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":88 + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point + * t1 = 1.0 # <<<<<<<<<<<<<< + * else: + * end_point = self.curve.point(t1) + */ + __pyx_v_t1 = 1.0; + + /* "ezdxf/acc/bezier3p.pyx":86 + * while t0 < 1.0: + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * end_point = self.end_point + * t1 = 1.0 + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bezier3p.pyx":90 + * t1 = 1.0 + * else: + * end_point = self.curve.point(t1) # <<<<<<<<<<<<<< + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + */ + /*else*/ { + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_t1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_end_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + } + __pyx_L5:; + + /* "ezdxf/acc/bezier3p.pyx":91 + * else: + * end_point = self.curve.point(t1) + * f.reset_recursion_check() # <<<<<<<<<<<<<< + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_f->__pyx_vtab)->reset_recursion_check(__pyx_v_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":92 + * end_point = self.curve.point(t1) + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) # <<<<<<<<<<<<<< + * if f.has_recursion_error(): + * raise RecursionError( + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_f->__pyx_vtab)->flatten(__pyx_v_f, __pyx_v_start_point, __pyx_v_end_point, __pyx_v_t0, __pyx_v_t1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":93 + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): # <<<<<<<<<<<<<< + * raise RecursionError( + * "Bezier3P flattening error, check for very large coordinates" + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_f->__pyx_vtab)->has_recursion_error(__pyx_v_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "ezdxf/acc/bezier3p.pyx":94 + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + * raise RecursionError( # <<<<<<<<<<<<<< + * "Bezier3P flattening error, check for very large coordinates" + * ) + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RecursionError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 94, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":93 + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): # <<<<<<<<<<<<<< + * raise RecursionError( + * "Bezier3P flattening error, check for very large coordinates" + */ + } + + /* "ezdxf/acc/bezier3p.pyx":97 + * "Bezier3P flattening error, check for very large coordinates" + * ) + * t0 = t1 # <<<<<<<<<<<<<< + * start_point = end_point + * return f.points + */ + __pyx_v_t0 = __pyx_v_t1; + + /* "ezdxf/acc/bezier3p.pyx":98 + * ) + * t0 = t1 + * start_point = end_point # <<<<<<<<<<<<<< + * return f.points + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_end_point); + __Pyx_DECREF_SET(__pyx_v_start_point, __pyx_v_end_point); + } + + /* "ezdxf/acc/bezier3p.pyx":99 + * t0 = t1 + * start_point = end_point + * return f.points # <<<<<<<<<<<<<< + * + * def approximated_length(self, segments: int = 128) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_f->points); + __pyx_r = __pyx_v_f->points; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":78 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.flattening", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_f); + __Pyx_XDECREF((PyObject *)__pyx_v_start_point); + __Pyx_XDECREF((PyObject *)__pyx_v_end_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":101 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length = {"approximated_length", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_segments = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("approximated_length (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_segments,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__5); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "approximated_length") < 0)) __PYX_ERR(0, 101, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_segments = ((PyObject*)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("approximated_length", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 101, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.approximated_length", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_segments), (&PyInt_Type), 0, "segments", 1))) __PYX_ERR(0, 101, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_12approximated_length(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_segments); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_12approximated_length(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, PyObject *__pyx_v_segments) { + double __pyx_v_length; + int __pyx_v_start_flag; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_prev_point = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_point = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + Py_ssize_t __pyx_t_5; + PyObject *(*__pyx_t_6)(PyObject *); + double __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("approximated_length", 1); + + /* "ezdxf/acc/bezier3p.pyx":102 + * + * def approximated_length(self, segments: int = 128) -> float: + * cdef double length = 0.0 # <<<<<<<<<<<<<< + * cdef bint start_flag = 0 + * cdef Vec3 prev_point, point + */ + __pyx_v_length = 0.0; + + /* "ezdxf/acc/bezier3p.pyx":103 + * def approximated_length(self, segments: int = 128) -> float: + * cdef double length = 0.0 + * cdef bint start_flag = 0 # <<<<<<<<<<<<<< + * cdef Vec3 prev_point, point + * + */ + __pyx_v_start_flag = 0; + + /* "ezdxf/acc/bezier3p.pyx":106 + * cdef Vec3 prev_point, point + * + * for point in self.approximate(segments): # <<<<<<<<<<<<<< + * if start_flag: + * length += v3_dist(prev_point, point) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_approximate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_segments}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { + __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); + __pyx_t_5 = 0; + __pyx_t_6 = NULL; + } else { + __pyx_t_5 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 106, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + for (;;) { + if (likely(!__pyx_t_6)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 106, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 106, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 106, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 106, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } + } else { + __pyx_t_1 = __pyx_t_6(__pyx_t_2); + if (unlikely(!__pyx_t_1)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 106, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_1); + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":107 + * + * for point in self.approximate(segments): + * if start_flag: # <<<<<<<<<<<<<< + * length += v3_dist(prev_point, point) + * else: + */ + if (__pyx_v_start_flag) { + + /* "ezdxf/acc/bezier3p.pyx":108 + * for point in self.approximate(segments): + * if start_flag: + * length += v3_dist(prev_point, point) # <<<<<<<<<<<<<< + * else: + * start_flag = 1 + */ + if (unlikely(!__pyx_v_prev_point)) { __Pyx_RaiseUnboundLocalError("prev_point"); __PYX_ERR(0, 108, __pyx_L1_error) } + __pyx_t_7 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_prev_point, __pyx_v_point); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 108, __pyx_L1_error) + __pyx_v_length = (__pyx_v_length + __pyx_t_7); + + /* "ezdxf/acc/bezier3p.pyx":107 + * + * for point in self.approximate(segments): + * if start_flag: # <<<<<<<<<<<<<< + * length += v3_dist(prev_point, point) + * else: + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bezier3p.pyx":110 + * length += v3_dist(prev_point, point) + * else: + * start_flag = 1 # <<<<<<<<<<<<<< + * prev_point = point + * return length + */ + /*else*/ { + __pyx_v_start_flag = 1; + } + __pyx_L5:; + + /* "ezdxf/acc/bezier3p.pyx":111 + * else: + * start_flag = 1 + * prev_point = point # <<<<<<<<<<<<<< + * return length + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_point); + __Pyx_XDECREF_SET(__pyx_v_prev_point, __pyx_v_point); + + /* "ezdxf/acc/bezier3p.pyx":106 + * cdef Vec3 prev_point, point + * + * for point in self.approximate(segments): # <<<<<<<<<<<<<< + * if start_flag: + * length += v3_dist(prev_point, point) + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier3p.pyx":112 + * start_flag = 1 + * prev_point = point + * return length # <<<<<<<<<<<<<< + * + * def reverse(self) -> Bezier3P: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_length); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":101 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.approximated_length", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_prev_point); + __Pyx_XDECREF((PyObject *)__pyx_v_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":114 + * return length + * + * def reverse(self) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse = {"reverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("reverse (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("reverse", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "reverse", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14reverse(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_14reverse(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("reverse", 1); + + /* "ezdxf/acc/bezier3p.pyx":115 + * + * def reverse(self) -> Bezier3P: + * return Bezier3P((self.end_point, self.cp1, self.start_point)) # <<<<<<<<<<<<<< + * + * def transform(self, Matrix44 m) -> Bezier3P: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 115, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 115, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 115, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 115, __pyx_L1_error); + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 115, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":114 + * return length + * + * def reverse(self) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.reverse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":117 + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P(tuple(m.transform_vertices(self.control_points))) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform = {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_m,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 117, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform") < 0)) __PYX_ERR(0, 117, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_m = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 117, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, 1, "m", 0))) __PYX_ERR(0, 117, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_16transform(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self), __pyx_v_m); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_16transform(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform", 1); + + /* "ezdxf/acc/bezier3p.pyx":118 + * + * def transform(self, Matrix44 m) -> Bezier3P: + * return Bezier3P(tuple(m.transform_vertices(self.control_points))) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_m), __pyx_n_s_transform_vertices); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_control_points); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P), __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":117 + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P(tuple(m.transform_vertices(self.control_points))) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.Bezier3P.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":23 + * cdef: + * FastQuadCurve curve # pyright: ignore + * readonly Vec3 start_point # <<<<<<<<<<<<<< + * Vec3 cp1 + * readonly Vec3 end_point + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __pyx_r = ((PyObject *)__pyx_v_self->start_point); + goto __pyx_L0; + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":25 + * readonly Vec3 start_point + * Vec3 cp1 + * readonly Vec3 end_point # <<<<<<<<<<<<<< + * + * def __cinit__(self, defpoints: Sequence[UVec]): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __pyx_r = ((PyObject *)__pyx_v_self->end_point); + goto __pyx_L0; + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":128 + * cdef int _recursion_error + * + * def __cinit__(self, Bezier3P curve, double distance): # <<<<<<<<<<<<<< + * self.curve = curve.curve + * self.distance = distance + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_curve = 0; + double __pyx_v_distance; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_curve,&__pyx_n_s_distance,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_curve)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_distance)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, 1); __PYX_ERR(0, 128, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 128, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + } + __pyx_v_curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)values[0]); + __pyx_v_distance = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 128, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_curve), __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, 1, "curve", 0))) __PYX_ERR(0, 128, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_self), __pyx_v_curve, __pyx_v_distance); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *__pyx_v_curve, double __pyx_v_distance) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/bezier3p.pyx":129 + * + * def __cinit__(self, Bezier3P curve, double distance): + * self.curve = curve.curve # <<<<<<<<<<<<<< + * self.distance = distance + * self.points = [curve.start_point] + */ + __pyx_t_1 = ((PyObject *)__pyx_v_curve->curve); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->curve); + __Pyx_DECREF((PyObject *)__pyx_v_self->curve); + __pyx_v_self->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":130 + * def __cinit__(self, Bezier3P curve, double distance): + * self.curve = curve.curve + * self.distance = distance # <<<<<<<<<<<<<< + * self.points = [curve.start_point] + * self._recursion_level = 0 + */ + __pyx_v_self->distance = __pyx_v_distance; + + /* "ezdxf/acc/bezier3p.pyx":131 + * self.curve = curve.curve + * self.distance = distance + * self.points = [curve.start_point] # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_curve->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_curve->start_point); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_curve->start_point))) __PYX_ERR(0, 131, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v_self->points); + __Pyx_DECREF(__pyx_v_self->points); + __pyx_v_self->points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":132 + * self.distance = distance + * self.points = [curve.start_point] + * self._recursion_level = 0 # <<<<<<<<<<<<<< + * self._recursion_error = 0 + * + */ + __pyx_v_self->_recursion_level = 0; + + /* "ezdxf/acc/bezier3p.pyx":133 + * self.points = [curve.start_point] + * self._recursion_level = 0 + * self._recursion_error = 0 # <<<<<<<<<<<<<< + * + * cdef has_recursion_error(self): + */ + __pyx_v_self->_recursion_error = 0; + + /* "ezdxf/acc/bezier3p.pyx":128 + * cdef int _recursion_error + * + * def __cinit__(self, Bezier3P curve, double distance): # <<<<<<<<<<<<<< + * self.curve = curve.curve + * self.distance = distance + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":135 + * self._recursion_error = 0 + * + * cdef has_recursion_error(self): # <<<<<<<<<<<<<< + * return self._recursion_error + * + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_has_recursion_error(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("has_recursion_error", 1); + + /* "ezdxf/acc/bezier3p.pyx":136 + * + * cdef has_recursion_error(self): + * return self._recursion_error # <<<<<<<<<<<<<< + * + * cdef reset_recursion_check(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->_recursion_error); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":135 + * self._recursion_error = 0 + * + * cdef has_recursion_error(self): # <<<<<<<<<<<<<< + * return self._recursion_error + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.has_recursion_error", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":138 + * return self._recursion_error + * + * cdef reset_recursion_check(self): # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_reset_recursion_check(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("reset_recursion_check", 1); + + /* "ezdxf/acc/bezier3p.pyx":139 + * + * cdef reset_recursion_check(self): + * self._recursion_level = 0 # <<<<<<<<<<<<<< + * self._recursion_error = 0 + * + */ + __pyx_v_self->_recursion_level = 0; + + /* "ezdxf/acc/bezier3p.pyx":140 + * cdef reset_recursion_check(self): + * self._recursion_level = 0 + * self._recursion_error = 0 # <<<<<<<<<<<<<< + * + * cdef flatten( + */ + __pyx_v_self->_recursion_error = 0; + + /* "ezdxf/acc/bezier3p.pyx":138 + * return self._recursion_error + * + * cdef reset_recursion_check(self): # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":142 + * self._recursion_error = 0 + * + * cdef flatten( # <<<<<<<<<<<<<< + * self, + * Vec3 start_point, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_flatten(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point, double __pyx_v_start_t, double __pyx_v_end_t) { + double __pyx_v_mid_t; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_mid_point = 0; + double __pyx_v_d; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("flatten", 1); + + /* "ezdxf/acc/bezier3p.pyx":149 + * double end_t + * ): + * if self._recursion_level > RECURSION_LIMIT: # <<<<<<<<<<<<<< + * self._recursion_error = 1 + * return + */ + __pyx_t_1 = (__pyx_v_self->_recursion_level > __pyx_v_5ezdxf_3acc_8bezier3p_RECURSION_LIMIT); + if (__pyx_t_1) { + + /* "ezdxf/acc/bezier3p.pyx":150 + * ): + * if self._recursion_level > RECURSION_LIMIT: + * self._recursion_error = 1 # <<<<<<<<<<<<<< + * return + * self._recursion_level += 1 + */ + __pyx_v_self->_recursion_error = 1; + + /* "ezdxf/acc/bezier3p.pyx":151 + * if self._recursion_level > RECURSION_LIMIT: + * self._recursion_error = 1 + * return # <<<<<<<<<<<<<< + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":149 + * double end_t + * ): + * if self._recursion_level > RECURSION_LIMIT: # <<<<<<<<<<<<<< + * self._recursion_error = 1 + * return + */ + } + + /* "ezdxf/acc/bezier3p.pyx":152 + * self._recursion_error = 1 + * return + * self._recursion_level += 1 # <<<<<<<<<<<<<< + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) + */ + __pyx_v_self->_recursion_level = (__pyx_v_self->_recursion_level + 1); + + /* "ezdxf/acc/bezier3p.pyx":153 + * return + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 # <<<<<<<<<<<<<< + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + */ + __pyx_v_mid_t = ((__pyx_v_start_t + __pyx_v_end_t) * 0.5); + + /* "ezdxf/acc/bezier3p.pyx":154 + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) # <<<<<<<<<<<<<< + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: + */ + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_mid_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_mid_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier3p.pyx":155 + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) # <<<<<<<<<<<<<< + * if d < self.distance: + * self.points.append(end_point) + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_lerp(__pyx_v_start_point, __pyx_v_end_point, 0.5)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_mid_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_d = __pyx_t_3; + + /* "ezdxf/acc/bezier3p.pyx":156 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: # <<<<<<<<<<<<<< + * self.points.append(end_point) + * else: + */ + __pyx_t_1 = (__pyx_v_d < __pyx_v_self->distance); + if (__pyx_t_1) { + + /* "ezdxf/acc/bezier3p.pyx":157 + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: + * self.points.append(end_point) # <<<<<<<<<<<<<< + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) + */ + if (unlikely(__pyx_v_self->points == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append"); + __PYX_ERR(0, 157, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_Append(__pyx_v_self->points, ((PyObject *)__pyx_v_end_point)); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(0, 157, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":156 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: # <<<<<<<<<<<<<< + * self.points.append(end_point) + * else: + */ + goto __pyx_L4; + } + + /* "ezdxf/acc/bezier3p.pyx":159 + * self.points.append(end_point) + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) # <<<<<<<<<<<<<< + * self.flatten(mid_point, end_point, mid_t, end_t) + * self._recursion_level -= 1 + */ + /*else*/ { + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_self->__pyx_vtab)->flatten(__pyx_v_self, __pyx_v_start_point, __pyx_v_mid_point, __pyx_v_start_t, __pyx_v_mid_t); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier3p.pyx":160 + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) + * self.flatten(mid_point, end_point, mid_t, end_t) # <<<<<<<<<<<<<< + * self._recursion_level -= 1 + * + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_self->__pyx_vtab)->flatten(__pyx_v_self, __pyx_v_mid_point, __pyx_v_end_point, __pyx_v_mid_t, __pyx_v_end_t); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_L4:; + + /* "ezdxf/acc/bezier3p.pyx":161 + * self.flatten(start_point, mid_point, start_t, mid_t) + * self.flatten(mid_point, end_point, mid_t, end_t) + * self._recursion_level -= 1 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_self->_recursion_level = (__pyx_v_self->_recursion_level - 1); + + /* "ezdxf/acc/bezier3p.pyx":142 + * self._recursion_error = 0 + * + * cdef flatten( # <<<<<<<<<<<<<< + * self, + * Vec3 start_point, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.flatten", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mid_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_2__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_4__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_11_Flattening_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier3p._Flattening.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":170 + * double[3] p2 + * + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2): # <<<<<<<<<<<<<< + * self.offset[0] = p0.x + * self.offset[1] = p0.y + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2 = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p0,&__pyx_n_s_p1,&__pyx_n_s_p2,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p0)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 170, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p1)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 170, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 3, 3, 1); __PYX_ERR(0, 170, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p2)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 170, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 3, 3, 2); __PYX_ERR(0, 170, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 170, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + } + __pyx_v_p0 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[0]); + __pyx_v_p1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[1]); + __pyx_v_p2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[2]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 170, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p0), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p0", 0))) __PYX_ERR(0, 170, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p1), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p1", 0))) __PYX_ERR(0, 170, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p2), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p2", 0))) __PYX_ERR(0, 170, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self), __pyx_v_p0, __pyx_v_p1, __pyx_v_p2); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2) { + int __pyx_r; + double __pyx_t_1; + + /* "ezdxf/acc/bezier3p.pyx":171 + * + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2): + * self.offset[0] = p0.x # <<<<<<<<<<<<<< + * self.offset[1] = p0.y + * self.offset[2] = p0.z + */ + __pyx_t_1 = __pyx_v_p0->x; + (__pyx_v_self->offset[0]) = __pyx_t_1; + + /* "ezdxf/acc/bezier3p.pyx":172 + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2): + * self.offset[0] = p0.x + * self.offset[1] = p0.y # <<<<<<<<<<<<<< + * self.offset[2] = p0.z + * + */ + __pyx_t_1 = __pyx_v_p0->y; + (__pyx_v_self->offset[1]) = __pyx_t_1; + + /* "ezdxf/acc/bezier3p.pyx":173 + * self.offset[0] = p0.x + * self.offset[1] = p0.y + * self.offset[2] = p0.z # <<<<<<<<<<<<<< + * + * # 1st control point (p0) is always (0, 0, 0) + */ + __pyx_t_1 = __pyx_v_p0->z; + (__pyx_v_self->offset[2]) = __pyx_t_1; + + /* "ezdxf/acc/bezier3p.pyx":176 + * + * # 1st control point (p0) is always (0, 0, 0) + * self.p1[0] = p1.x - p0.x # <<<<<<<<<<<<<< + * self.p1[1] = p1.y - p0.y + * self.p1[2] = p1.z - p0.z + */ + (__pyx_v_self->p1[0]) = (__pyx_v_p1->x - __pyx_v_p0->x); + + /* "ezdxf/acc/bezier3p.pyx":177 + * # 1st control point (p0) is always (0, 0, 0) + * self.p1[0] = p1.x - p0.x + * self.p1[1] = p1.y - p0.y # <<<<<<<<<<<<<< + * self.p1[2] = p1.z - p0.z + * + */ + (__pyx_v_self->p1[1]) = (__pyx_v_p1->y - __pyx_v_p0->y); + + /* "ezdxf/acc/bezier3p.pyx":178 + * self.p1[0] = p1.x - p0.x + * self.p1[1] = p1.y - p0.y + * self.p1[2] = p1.z - p0.z # <<<<<<<<<<<<<< + * + * self.p2[0] = p2.x - p0.x + */ + (__pyx_v_self->p1[2]) = (__pyx_v_p1->z - __pyx_v_p0->z); + + /* "ezdxf/acc/bezier3p.pyx":180 + * self.p1[2] = p1.z - p0.z + * + * self.p2[0] = p2.x - p0.x # <<<<<<<<<<<<<< + * self.p2[1] = p2.y - p0.y + * self.p2[2] = p2.z - p0.z + */ + (__pyx_v_self->p2[0]) = (__pyx_v_p2->x - __pyx_v_p0->x); + + /* "ezdxf/acc/bezier3p.pyx":181 + * + * self.p2[0] = p2.x - p0.x + * self.p2[1] = p2.y - p0.y # <<<<<<<<<<<<<< + * self.p2[2] = p2.z - p0.z + * + */ + (__pyx_v_self->p2[1]) = (__pyx_v_p2->y - __pyx_v_p0->y); + + /* "ezdxf/acc/bezier3p.pyx":182 + * self.p2[0] = p2.x - p0.x + * self.p2[1] = p2.y - p0.y + * self.p2[2] = p2.z - p0.z # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_self->p2[2]) = (__pyx_v_p2->z - __pyx_v_p0->z); + + /* "ezdxf/acc/bezier3p.pyx":170 + * double[3] p2 + * + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2): # <<<<<<<<<<<<<< + * self.offset[0] = p0.x + * self.offset[1] = p0.y + */ + + /* function exit code */ + __pyx_r = 0; + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":185 + * + * + * cdef Vec3 point(self, double t): # <<<<<<<<<<<<<< + * # 1st control point (p0) is always (0, 0, 0) + * # => p0 * a is always (0, 0, 0) + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_point(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_result = 0; + double __pyx_v_b; + double __pyx_v_c; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + + /* "ezdxf/acc/bezier3p.pyx":189 + * # => p0 * a is always (0, 0, 0) + * cdef: + * Vec3 result = Vec3() # <<<<<<<<<<<<<< + * # double a = (1 - t) ** 2 + * double b = 2.0 * t * (1.0 - t) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 189, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":191 + * Vec3 result = Vec3() + * # double a = (1 - t) ** 2 + * double b = 2.0 * t * (1.0 - t) # <<<<<<<<<<<<<< + * double c = t * t + * + */ + __pyx_v_b = ((2.0 * __pyx_v_t) * (1.0 - __pyx_v_t)); + + /* "ezdxf/acc/bezier3p.pyx":192 + * # double a = (1 - t) ** 2 + * double b = 2.0 * t * (1.0 - t) + * double c = t * t # <<<<<<<<<<<<<< + * + * iadd_mul(result, self.p1, b) + */ + __pyx_v_c = (__pyx_v_t * __pyx_v_t); + + /* "ezdxf/acc/bezier3p.pyx":194 + * double c = t * t + * + * iadd_mul(result, self.p1, b) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p2, c) + * + */ + __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(__pyx_v_result, __pyx_v_self->p1, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 194, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":195 + * + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) # <<<<<<<<<<<<<< + * + * # add offset at last - it is maybe very large + */ + __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(__pyx_v_result, __pyx_v_self->p2, __pyx_v_c); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":198 + * + * # add offset at last - it is maybe very large + * result.x += self.offset[0] # <<<<<<<<<<<<<< + * result.y += self.offset[1] + * result.z += self.offset[2] + */ + __pyx_v_result->x = (__pyx_v_result->x + (__pyx_v_self->offset[0])); + + /* "ezdxf/acc/bezier3p.pyx":199 + * # add offset at last - it is maybe very large + * result.x += self.offset[0] + * result.y += self.offset[1] # <<<<<<<<<<<<<< + * result.z += self.offset[2] + * + */ + __pyx_v_result->y = (__pyx_v_result->y + (__pyx_v_self->offset[1])); + + /* "ezdxf/acc/bezier3p.pyx":200 + * result.x += self.offset[0] + * result.y += self.offset[1] + * result.z += self.offset[2] # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->z = (__pyx_v_result->z + (__pyx_v_self->offset[2])); + + /* "ezdxf/acc/bezier3p.pyx":202 + * result.z += self.offset[2] + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":185 + * + * + * cdef Vec3 point(self, double t): # <<<<<<<<<<<<<< + * # 1st control point (p0) is always (0, 0, 0) + * # => p0 * a is always (0, 0, 0) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":205 + * + * + * cdef Vec3 tangent(self, double t): # <<<<<<<<<<<<<< + * # tangent vector is independent from offset location! + * cdef: + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_tangent(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_result = 0; + double __pyx_v_b; + double __pyx_v_c; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tangent", 1); + + /* "ezdxf/acc/bezier3p.pyx":208 + * # tangent vector is independent from offset location! + * cdef: + * Vec3 result = Vec3() # <<<<<<<<<<<<<< + * # double a = -2 * (1 - t) + * double b = 2.0 - 4.0 * t + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier3p.pyx":210 + * Vec3 result = Vec3() + * # double a = -2 * (1 - t) + * double b = 2.0 - 4.0 * t # <<<<<<<<<<<<<< + * double c = 2.0 * t + * + */ + __pyx_v_b = (2.0 - (4.0 * __pyx_v_t)); + + /* "ezdxf/acc/bezier3p.pyx":211 + * # double a = -2 * (1 - t) + * double b = 2.0 - 4.0 * t + * double c = 2.0 * t # <<<<<<<<<<<<<< + * + * iadd_mul(result, self.p1, b) + */ + __pyx_v_c = (2.0 * __pyx_v_t); + + /* "ezdxf/acc/bezier3p.pyx":213 + * double c = 2.0 * t + * + * iadd_mul(result, self.p1, b) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p2, c) + * + */ + __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(__pyx_v_result, __pyx_v_self->p1, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 213, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":214 + * + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(__pyx_v_result, __pyx_v_self->p2, __pyx_v_c); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":216 + * iadd_mul(result, self.p2, c) + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bezier3p.pyx":205 + * + * + * cdef Vec3 tangent(self, double t): # <<<<<<<<<<<<<< + * # tangent vector is independent from offset location! + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_2__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_4__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier3p_13FastQuadCurve_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier3p.FastQuadCurve.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier3p.pyx":219 + * + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): # <<<<<<<<<<<<<< + * a.x += b[0] * c + * a.y += b[1] * c + */ + +static void __pyx_f_5ezdxf_3acc_8bezier3p_iadd_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, double *__pyx_v_b, double __pyx_v_c) { + + /* "ezdxf/acc/bezier3p.pyx":220 + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): + * a.x += b[0] * c # <<<<<<<<<<<<<< + * a.y += b[1] * c + * a.z += b[2] * c + */ + __pyx_v_a->x = (__pyx_v_a->x + ((__pyx_v_b[0]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier3p.pyx":221 + * cdef void iadd_mul(Vec3 a, double[3] b, double c): + * a.x += b[0] * c + * a.y += b[1] * c # <<<<<<<<<<<<<< + * a.z += b[2] * c + */ + __pyx_v_a->y = (__pyx_v_a->y + ((__pyx_v_b[1]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier3p.pyx":222 + * a.x += b[0] * c + * a.y += b[1] * c + * a.z += b[2] * c # <<<<<<<<<<<<<< + */ + __pyx_v_a->z = (__pyx_v_a->z + ((__pyx_v_b[2]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier3p.pyx":219 + * + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): # <<<<<<<<<<<<<< + * a.x += b[0] * c + * a.y += b[1] * c + */ + + /* function exit code */ +} + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p_Bezier3P(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)o); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)Py_None); Py_INCREF(Py_None); + p->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + p->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + p->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_Bezier3P(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_Bezier3P) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->curve); + Py_CLEAR(p->start_point); + Py_CLEAR(p->cp1); + Py_CLEAR(p->end_point); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier3p_Bezier3P(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)o; + if (p->curve) { + e = (*v)(((PyObject *)p->curve), a); if (e) return e; + } + if (p->start_point) { + e = (*v)(((PyObject *)p->start_point), a); if (e) return e; + } + if (p->cp1) { + e = (*v)(((PyObject *)p->cp1), a); if (e) return e; + } + if (p->end_point) { + e = (*v)(((PyObject *)p->end_point), a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8bezier3p_Bezier3P(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P *)o; + tmp = ((PyObject*)p->curve); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->start_point); + p->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->cp1); + p->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->end_point); + p->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_control_points(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_14control_points_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_start_point(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11start_point_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_end_point(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9end_point_1__get__(o); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier3p_Bezier3P[] = { + {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"point", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_5point, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"tangent", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"approximate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"flattening", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"approximated_length", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"reverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_8bezier3p_Bezier3P[] = { + {(char *)"control_points", __pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_control_points, 0, (char *)0, 0}, + {(char *)"start_point", __pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_start_point, 0, (char *)0, 0}, + {(char *)"end_point", __pyx_getprop_5ezdxf_3acc_8bezier3p_8Bezier3P_end_point, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_Bezier3P}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier3p_Bezier3P}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8bezier3p_Bezier3P}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier3p_Bezier3P}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_8bezier3p_Bezier3P}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier3p_Bezier3P}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P_spec = { + "ezdxf.acc.bezier3p.Bezier3P", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier3p.""Bezier3P", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p_Bezier3P), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier3p_Bezier3P, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p__Flattening __pyx_vtable_5ezdxf_3acc_8bezier3p__Flattening; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p__Flattening(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_8bezier3p__Flattening; + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)Py_None); Py_INCREF(Py_None); + p->points = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p__Flattening(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p__Flattening) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->curve); + Py_CLEAR(p->points); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier3p__Flattening(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)o; + if (p->curve) { + e = (*v)(((PyObject *)p->curve), a); if (e) return e; + } + if (p->points) { + e = (*v)(p->points, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8bezier3p__Flattening(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *)o; + tmp = ((PyObject*)p->curve); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->points); + p->points = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier3p__Flattening[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier3p__Flattening_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier3p__Flattening}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier3p__Flattening}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8bezier3p__Flattening}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier3p__Flattening}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier3p__Flattening}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier3p__Flattening_spec = { + "ezdxf.acc.bezier3p._Flattening", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_8bezier3p__Flattening_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier3p__Flattening = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier3p.""_Flattening", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p__Flattening, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier3p__Flattening, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8bezier3p__Flattening, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier3p__Flattening, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier3p__Flattening, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier3p_FastQuadCurve __pyx_vtable_5ezdxf_3acc_8bezier3p_FastQuadCurve; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier3p_FastQuadCurve(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_8bezier3p_FastQuadCurve; + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_FastQuadCurve(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_FastQuadCurve) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier3p_FastQuadCurve[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_FastQuadCurve}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier3p_FastQuadCurve}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier3p_FastQuadCurve}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve_spec = { + "ezdxf.acc.bezier3p.FastQuadCurve", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier3p.""FastQuadCurve", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier3p_FastQuadCurve, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier3p_FastQuadCurve, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier3p_FastQuadCurve, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_Bezier3P, __pyx_k_Bezier3P, sizeof(__pyx_k_Bezier3P), 0, 0, 1, 1}, + {&__pyx_n_u_Bezier3P, __pyx_k_Bezier3P, sizeof(__pyx_k_Bezier3P), 0, 1, 0, 1}, + {&__pyx_n_s_Bezier3P___reduce, __pyx_k_Bezier3P___reduce, sizeof(__pyx_k_Bezier3P___reduce), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier3P_approximate, __pyx_k_Bezier3P_approximate, sizeof(__pyx_k_Bezier3P_approximate), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier3P_approximated_length, __pyx_k_Bezier3P_approximated_length, sizeof(__pyx_k_Bezier3P_approximated_length), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier3P_flattening, __pyx_k_Bezier3P_flattening, sizeof(__pyx_k_Bezier3P_flattening), 0, 0, 1, 1}, + {&__pyx_kp_u_Bezier3P_flattening_error_check, __pyx_k_Bezier3P_flattening_error_check, sizeof(__pyx_k_Bezier3P_flattening_error_check), 0, 1, 0, 0}, + {&__pyx_n_s_Bezier3P_point, __pyx_k_Bezier3P_point, sizeof(__pyx_k_Bezier3P_point), 0, 0, 1, 1}, + {&__pyx_kp_u_Bezier3P_requires_defpoints_of_t, __pyx_k_Bezier3P_requires_defpoints_of_t, sizeof(__pyx_k_Bezier3P_requires_defpoints_of_t), 0, 1, 0, 0}, + {&__pyx_n_s_Bezier3P_reverse, __pyx_k_Bezier3P_reverse, sizeof(__pyx_k_Bezier3P_reverse), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier3P_tangent, __pyx_k_Bezier3P_tangent, sizeof(__pyx_k_Bezier3P_tangent), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier3P_transform, __pyx_k_Bezier3P_transform, sizeof(__pyx_k_Bezier3P_transform), 0, 0, 1, 1}, + {&__pyx_n_s_DeprecationWarning, __pyx_k_DeprecationWarning, sizeof(__pyx_k_DeprecationWarning), 0, 0, 1, 1}, + {&__pyx_n_s_FastQuadCurve, __pyx_k_FastQuadCurve, sizeof(__pyx_k_FastQuadCurve), 0, 0, 1, 1}, + {&__pyx_n_s_FastQuadCurve___reduce_cython, __pyx_k_FastQuadCurve___reduce_cython, sizeof(__pyx_k_FastQuadCurve___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_FastQuadCurve___setstate_cython, __pyx_k_FastQuadCurve___setstate_cython, sizeof(__pyx_k_FastQuadCurve___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening, __pyx_k_Flattening, sizeof(__pyx_k_Flattening), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening___reduce_cython, __pyx_k_Flattening___reduce_cython, sizeof(__pyx_k_Flattening___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening___setstate_cython, __pyx_k_Flattening___setstate_cython, sizeof(__pyx_k_Flattening___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_RecursionError, __pyx_k_RecursionError, sizeof(__pyx_k_RecursionError), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_kp_u_Three_control_points_required, __pyx_k_Three_control_points_required, sizeof(__pyx_k_Three_control_points_required), 0, 1, 0, 0}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3, __pyx_k_Vec3, sizeof(__pyx_k_Vec3), 0, 0, 1, 1}, + {&__pyx_n_s__28, __pyx_k__28, sizeof(__pyx_k__28), 0, 0, 1, 1}, + {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0}, + {&__pyx_n_s__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 0, 1, 1}, + {&__pyx_n_s_all, __pyx_k_all, sizeof(__pyx_k_all), 0, 0, 1, 1}, + {&__pyx_n_s_approximate, __pyx_k_approximate, sizeof(__pyx_k_approximate), 0, 0, 1, 1}, + {&__pyx_n_s_approximated_length, __pyx_k_approximated_length, sizeof(__pyx_k_approximated_length), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_control_points, __pyx_k_control_points, sizeof(__pyx_k_control_points), 0, 0, 1, 1}, + {&__pyx_n_s_curve, __pyx_k_curve, sizeof(__pyx_k_curve), 0, 0, 1, 1}, + {&__pyx_n_s_defpoints, __pyx_k_defpoints, sizeof(__pyx_k_defpoints), 0, 0, 1, 1}, + {&__pyx_n_s_delta_t, __pyx_k_delta_t, sizeof(__pyx_k_delta_t), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_distance, __pyx_k_distance, sizeof(__pyx_k_distance), 0, 0, 1, 1}, + {&__pyx_n_s_dt, __pyx_k_dt, sizeof(__pyx_k_dt), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_end_point, __pyx_k_end_point, sizeof(__pyx_k_end_point), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_bezier3p, __pyx_k_ezdxf_acc_bezier3p, sizeof(__pyx_k_ezdxf_acc_bezier3p), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_n_s_f, __pyx_k_f, sizeof(__pyx_k_f), 0, 0, 1, 1}, + {&__pyx_n_s_flattening, __pyx_k_flattening, sizeof(__pyx_k_flattening), 0, 0, 1, 1}, + {&__pyx_n_s_float, __pyx_k_float, sizeof(__pyx_k_float), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_length, __pyx_k_length, sizeof(__pyx_k_length), 0, 0, 1, 1}, + {&__pyx_kp_s_list_Vec3, __pyx_k_list_Vec3, sizeof(__pyx_k_list_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_m, __pyx_k_m, sizeof(__pyx_k_m), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_p0, __pyx_k_p0, sizeof(__pyx_k_p0), 0, 0, 1, 1}, + {&__pyx_n_s_p1, __pyx_k_p1, sizeof(__pyx_k_p1), 0, 0, 1, 1}, + {&__pyx_n_s_p2, __pyx_k_p2, sizeof(__pyx_k_p2), 0, 0, 1, 1}, + {&__pyx_n_s_point, __pyx_k_point, sizeof(__pyx_k_point), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_prev_point, __pyx_k_prev_point, sizeof(__pyx_k_prev_point), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_reverse, __pyx_k_reverse, sizeof(__pyx_k_reverse), 0, 0, 1, 1}, + {&__pyx_n_s_segment, __pyx_k_segment, sizeof(__pyx_k_segment), 0, 0, 1, 1}, + {&__pyx_n_s_segments, __pyx_k_segments, sizeof(__pyx_k_segments), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_k_src_ezdxf_acc_bezier3p_pyx, sizeof(__pyx_k_src_ezdxf_acc_bezier3p_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start_flag, __pyx_k_start_flag, sizeof(__pyx_k_start_flag), 0, 0, 1, 1}, + {&__pyx_n_s_start_point, __pyx_k_start_point, sizeof(__pyx_k_start_point), 0, 0, 1, 1}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_t0, __pyx_k_t0, sizeof(__pyx_k_t0), 0, 0, 1, 1}, + {&__pyx_n_s_t1, __pyx_k_t1, sizeof(__pyx_k_t1), 0, 0, 1, 1}, + {&__pyx_kp_u_t_not_in_range_0_to_1, __pyx_k_t_not_in_range_0_to_1, sizeof(__pyx_k_t_not_in_range_0_to_1), 0, 1, 0, 0}, + {&__pyx_n_s_tangent, __pyx_k_tangent, sizeof(__pyx_k_tangent), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_transform, __pyx_k_transform, sizeof(__pyx_k_transform), 0, 0, 1, 1}, + {&__pyx_n_s_transform_vertices, __pyx_k_transform_vertices, sizeof(__pyx_k_transform_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_warn, __pyx_k_warn, sizeof(__pyx_k_warn), 0, 0, 1, 1}, + {&__pyx_n_s_warnings, __pyx_k_warnings, sizeof(__pyx_k_warnings), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_DeprecationWarning = __Pyx_GetBuiltinName(__pyx_n_s_DeprecationWarning); if (!__pyx_builtin_DeprecationWarning) __PYX_ERR(0, 30, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 44, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 73, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/bezier3p.pyx":29 + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( # <<<<<<<<<<<<<< + * DeprecationWarning, + * "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + */ + __pyx_tuple_ = PyTuple_Pack(2, __pyx_builtin_DeprecationWarning, __pyx_kp_u_Bezier3P_requires_defpoints_of_t); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "ezdxf/acc/bezier3p.pyx":44 + * ) + * else: + * raise ValueError("Three control points required.") # <<<<<<<<<<<<<< + * + * @property + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_Three_control_points_required); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 44, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "ezdxf/acc/bezier3p.pyx":57 + * return self.curve.point(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def tangent(self, double t) -> Vec3: + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_t_not_in_range_0_to_1); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "ezdxf/acc/bezier3p.pyx":94 + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + * raise RecursionError( # <<<<<<<<<<<<<< + * "Bezier3P flattening error, check for very large coordinates" + * ) + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_Bezier3P_flattening_error_check); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "ezdxf/acc/bezier3p.pyx":50 + * return self.start_point, self.cp1, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier3P, (self.control_points,) + * + */ + __pyx_tuple__8 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_reduce, 50, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 50, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":53 + * return Bezier3P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + __pyx_tuple__10 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_t); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_point, 53, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 53, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":59 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + __pyx_codeobj__12 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_tangent, 59, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__12)) __PYX_ERR(0, 59, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":65 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + __pyx_tuple__13 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_segments, __pyx_n_s_delta_t, __pyx_n_s_segment, __pyx_n_s_points); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 65, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__13); + __Pyx_GIVEREF(__pyx_tuple__13); + __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_approximate, 65, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) __PYX_ERR(0, 65, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":78 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + __pyx_tuple__15 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_distance, __pyx_n_s_segments, __pyx_n_s_dt, __pyx_n_s_t0, __pyx_n_s_t1, __pyx_n_s_f, __pyx_n_s_start_point, __pyx_n_s_end_point); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_flattening, 78, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(0, 78, __pyx_L1_error) + __pyx_tuple__17 = PyTuple_Pack(1, __pyx_int_4); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + + /* "ezdxf/acc/bezier3p.pyx":101 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + __pyx_tuple__18 = PyTuple_Pack(6, __pyx_n_s_self, __pyx_n_s_segments, __pyx_n_s_length, __pyx_n_s_start_flag, __pyx_n_s_prev_point, __pyx_n_s_point); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_approximated_length, 101, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(0, 101, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":114 + * return length + * + * def reverse(self) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + */ + __pyx_codeobj__20 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_reverse, 114, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(0, 114, __pyx_L1_error) + + /* "ezdxf/acc/bezier3p.pyx":117 + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P(tuple(m.transform_vertices(self.control_points))) + * + */ + __pyx_tuple__21 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_m); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__21); + __Pyx_GIVEREF(__pyx_tuple__21); + __pyx_codeobj__22 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__21, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier3p_pyx, __pyx_n_s_transform, 117, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__22)) __PYX_ERR(0, 117, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_tuple__24 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_pyx_state); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__24); + __Pyx_GIVEREF(__pyx_tuple__24); + __pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) __PYX_ERR(1, 3, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_128 = PyInt_FromLong(128); if (unlikely(!__pyx_int_128)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P)) __PYX_ERR(0, 20, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P_spec, __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P = &__pyx_type_5ezdxf_3acc_8bezier3p_Bezier3P; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Bezier3P, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + __pyx_vtabptr_5ezdxf_3acc_8bezier3p__Flattening = &__pyx_vtable_5ezdxf_3acc_8bezier3p__Flattening; + __pyx_vtable_5ezdxf_3acc_8bezier3p__Flattening.has_recursion_error = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *))__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_has_recursion_error; + __pyx_vtable_5ezdxf_3acc_8bezier3p__Flattening.reset_recursion_check = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *))__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_reset_recursion_check; + __pyx_vtable_5ezdxf_3acc_8bezier3p__Flattening.flatten = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier3p__Flattening *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double))__pyx_f_5ezdxf_3acc_8bezier3p_11_Flattening_flatten; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier3p__Flattening_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening)) __PYX_ERR(0, 121, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier3p__Flattening_spec, __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening = &__pyx_type_5ezdxf_3acc_8bezier3p__Flattening; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening, __pyx_vtabptr_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Flattening, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier3p__Flattening) < 0) __PYX_ERR(0, 121, __pyx_L1_error) + #endif + __pyx_vtabptr_5ezdxf_3acc_8bezier3p_FastQuadCurve = &__pyx_vtable_5ezdxf_3acc_8bezier3p_FastQuadCurve; + __pyx_vtable_5ezdxf_3acc_8bezier3p_FastQuadCurve.point = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *, double))__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_point; + __pyx_vtable_5ezdxf_3acc_8bezier3p_FastQuadCurve.tangent = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier3p_FastQuadCurve *, double))__pyx_f_5ezdxf_3acc_8bezier3p_13FastQuadCurve_tangent; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve)) __PYX_ERR(0, 164, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve_spec, __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve = &__pyx_type_5ezdxf_3acc_8bezier3p_FastQuadCurve; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve, __pyx_vtabptr_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_FastQuadCurve, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier3p_FastQuadCurve) < 0) __PYX_ERR(0, 164, __pyx_L1_error) + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.matrix44"); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.matrix44", "Matrix44", sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) __PYX_ERR(3, 6, __pyx_L1_error) + __pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44 = (struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44*)__Pyx_GetVtable(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); if (unlikely(!__pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44)) __PYX_ERR(3, 6, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_add", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_dist", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_dist, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_lerp", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_lerp, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_bezier3p(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_bezier3p}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "bezier3p", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initbezier3p(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initbezier3p(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_bezier3p(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_bezier3p(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_bezier3p(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'bezier3p' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("bezier3p", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "bezier3p" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_bezier3p(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__bezier3p) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.bezier3p")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.bezier3p", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/bezier3p.pyx":4 + * # Copyright (c) 2021-2024 Manfred Moitzi + * # License: MIT License + * from typing import TYPE_CHECKING, Sequence # <<<<<<<<<<<<<< + * from .vector cimport Vec3, isclose, v3_dist, v3_lerp, v3_add, Vec2 + * from .matrix44 cimport Matrix44 + */ + __pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier3p.pyx":7 + * from .vector cimport Vec3, isclose, v3_dist, v3_lerp, v3_add, Vec2 + * from .matrix44 cimport Matrix44 + * import warnings # <<<<<<<<<<<<<< + * if TYPE_CHECKING: + * from ezdxf.math import UVec + */ + __pyx_t_3 = __Pyx_ImportDottedModule(__pyx_n_s_warnings, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_warnings, __pyx_t_3) < 0) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier3p.pyx":8 + * from .matrix44 cimport Matrix44 + * import warnings + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 8, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "ezdxf/acc/bezier3p.pyx":9 + * import warnings + * if TYPE_CHECKING: + * from ezdxf.math import UVec # <<<<<<<<<<<<<< + * + * __all__ = ['Bezier3P'] + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_UVec)) __PYX_ERR(0, 9, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_UVec); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_3) < 0) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier3p.pyx":8 + * from .matrix44 cimport Matrix44 + * import warnings + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + } + + /* "ezdxf/acc/bezier3p.pyx":11 + * from ezdxf.math import UVec + * + * __all__ = ['Bezier3P'] # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_u_Bezier3P); + __Pyx_GIVEREF(__pyx_n_u_Bezier3P); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_u_Bezier3P)) __PYX_ERR(0, 11, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_all, __pyx_t_2) < 0) __PYX_ERR(0, 11, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier3p.pyx":17 + * const double REL_TOL + * + * cdef double RECURSION_LIMIT = 1000 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_5ezdxf_3acc_8bezier3p_RECURSION_LIMIT = 1000.0; + + /* "ezdxf/acc/bezier3p.pyx":50 + * return self.start_point, self.cp1, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier3P, (self.control_points,) + * + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_3__reduce__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P___reduce, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_reduce, __pyx_t_2) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":53 + * return Bezier3P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_5point, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_point, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_point, __pyx_t_3) < 0) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":59 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 59, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_7tangent, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_tangent, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__12)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_tangent, __pyx_t_2) < 0) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":65 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 65, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_list_Vec3) < 0) __PYX_ERR(0, 65, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_9approximate, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_approximate, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__14)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 65, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_approximate, __pyx_t_3) < 0) __PYX_ERR(0, 65, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":78 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_Vec3) < 0) __PYX_ERR(0, 78, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_11flattening, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_flattening, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__16)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__17); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_flattening, __pyx_t_2) < 0) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":101 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_128)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_128))) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_128); + __pyx_k__5 = ((PyObject*)__pyx_int_128); + __Pyx_GIVEREF(__pyx_int_128); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_128)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_128))) __PYX_ERR(0, 101, __pyx_L1_error) + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_int_128); + __Pyx_GIVEREF(__pyx_int_128); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_int_128)) __PYX_ERR(0, 101, __pyx_L1_error); + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_segments, __pyx_n_s_int) < 0) __PYX_ERR(0, 101, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 101, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_13approximated_length, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_approximated_length, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_approximated_length, __pyx_t_5) < 0) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":114 + * return length + * + * def reverse(self) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Bezier3P) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_15reverse, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_reverse, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__20)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_reverse, __pyx_t_3) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "ezdxf/acc/bezier3p.pyx":117 + * return Bezier3P((self.end_point, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier3P: # <<<<<<<<<<<<<< + * return Bezier3P(tuple(m.transform_vertices(self.control_points))) + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Bezier3P) < 0) __PYX_ERR(0, 117, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_8Bezier3P_17transform, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier3P_transform, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__22)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P, __pyx_n_s_transform, __pyx_t_5) < 0) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier3p_Bezier3P); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_11_Flattening_3__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Flattening___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_5) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_11_Flattening_5__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Flattening___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__25)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_5) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_13FastQuadCurve_3__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_FastQuadCurve___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_5) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier3p_13FastQuadCurve_5__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_FastQuadCurve___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bezier3p, __pyx_d, ((PyObject *)__pyx_codeobj__27)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_5) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier3p.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2021-2024 Manfred Moitzi + * # License: MIT License + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_5) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.bezier3p", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.bezier3p"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__6); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* ImportDottedModule */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { + PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; + if (unlikely(PyErr_Occurred())) { + PyErr_Clear(); + } + if (likely(PyTuple_GET_SIZE(parts_tuple) == count)) { + partial_name = name; + } else { + slice = PySequence_GetSlice(parts_tuple, 0, count); + if (unlikely(!slice)) + goto bad; + sep = PyUnicode_FromStringAndSize(".", 1); + if (unlikely(!sep)) + goto bad; + partial_name = PyUnicode_Join(sep, slice); + } + PyErr_Format( +#if PY_MAJOR_VERSION < 3 + PyExc_ImportError, + "No module named '%s'", PyString_AS_STRING(partial_name)); +#else +#if PY_VERSION_HEX >= 0x030600B1 + PyExc_ModuleNotFoundError, +#else + PyExc_ImportError, +#endif + "No module named '%U'", partial_name); +#endif +bad: + Py_XDECREF(sep); + Py_XDECREF(slice); + Py_XDECREF(partial_name); + return NULL; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { + PyObject *imported_module; +#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + return NULL; + imported_module = __Pyx_PyDict_GetItemStr(modules, name); + Py_XINCREF(imported_module); +#else + imported_module = PyImport_GetModule(name); +#endif + return imported_module; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { + Py_ssize_t i, nparts; + nparts = PyTuple_GET_SIZE(parts_tuple); + for (i=1; i < nparts && module; i++) { + PyObject *part, *submodule; +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + part = PyTuple_GET_ITEM(parts_tuple, i); +#else + part = PySequence_ITEM(parts_tuple, i); +#endif + submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); +#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(part); +#endif + Py_DECREF(module); + module = submodule; + } + if (unlikely(!module)) { + return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); + } + return module; +} +#endif +static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if PY_MAJOR_VERSION < 3 + PyObject *module, *from_list, *star = __pyx_n_s__7; + CYTHON_UNUSED_VAR(parts_tuple); + from_list = PyList_New(1); + if (unlikely(!from_list)) + return NULL; + Py_INCREF(star); + PyList_SET_ITEM(from_list, 0, star); + module = __Pyx_Import(name, from_list, 0); + Py_DECREF(from_list); + return module; +#else + PyObject *imported_module; + PyObject *module = __Pyx_Import(name, NULL, 0); + if (!parts_tuple || unlikely(!module)) + return module; + imported_module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(imported_module)) { + Py_DECREF(module); + return imported_module; + } + PyErr_Clear(); + return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); +#endif +} +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1 + PyObject *module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(module)) { + PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_n_s_spec); + if (likely(spec)) { + PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_n_s_initializing); + if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { + Py_DECREF(spec); + spec = NULL; + } + Py_XDECREF(unsafe); + } + if (likely(!spec)) { + PyErr_Clear(); + return module; + } + Py_DECREF(spec); + Py_DECREF(module); + } else if (PyErr_Occurred()) { + PyErr_Clear(); + } +#endif + return __Pyx__ImportDottedModule(name, parts_tuple); +} + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__28); + } + return name; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ +#ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.cpython-312-darwin.so new file mode 100755 index 0000000..5e51934 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.pyx new file mode 100644 index 0000000..49c8b22 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier3p.pyx @@ -0,0 +1,222 @@ +# cython: language_level=3 +# Copyright (c) 2021-2024 Manfred Moitzi +# License: MIT License +from typing import TYPE_CHECKING, Sequence +from .vector cimport Vec3, isclose, v3_dist, v3_lerp, v3_add, Vec2 +from .matrix44 cimport Matrix44 +import warnings +if TYPE_CHECKING: + from ezdxf.math import UVec + +__all__ = ['Bezier3P'] + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + +cdef double RECURSION_LIMIT = 1000 + + +cdef class Bezier3P: + cdef: + FastQuadCurve curve # pyright: ignore + readonly Vec3 start_point + Vec3 cp1 + readonly Vec3 end_point + + def __cinit__(self, defpoints: Sequence[UVec]): + if not isinstance(defpoints[0], (Vec2, Vec3)): + warnings.warn( + DeprecationWarning, + "Bezier3P requires defpoints of type Vec2 or Vec3 in the future", + ) + if len(defpoints) == 3: + self.start_point = Vec3(defpoints[0]) + self.cp1 = Vec3(defpoints[1]) + self.end_point = Vec3(defpoints[2]) + + self.curve = FastQuadCurve( + self.start_point, + self.cp1, + self.end_point + ) + else: + raise ValueError("Three control points required.") + + @property + def control_points(self) -> tuple[Vec3, Vec3, Vec3]: + return self.start_point, self.cp1, self.end_point + + def __reduce__(self): + return Bezier3P, (self.control_points,) + + def point(self, double t) -> Vec3: + if 0.0 <= t <= 1.0: + return self.curve.point(t) + else: + raise ValueError("t not in range [0 to 1]") + + def tangent(self, double t) -> Vec3: + if 0.0 <= t <= 1.0: + return self.curve.tangent(t) + else: + raise ValueError("t not in range [0 to 1]") + + def approximate(self, int segments) -> list[Vec3]: + cdef double delta_t + cdef int segment + cdef list points = [self.start_point] + + if segments < 1: + raise ValueError(segments) + delta_t = 1.0 / segments + for segment in range(1, segments): + points.append(self.point(delta_t * segment)) + points.append(self.end_point) + return points + + def flattening(self, double distance, int segments = 4) -> list[Vec3]: + cdef double dt = 1.0 / segments + cdef double t0 = 0.0, t1 + cdef _Flattening f = _Flattening(self, distance) + cdef Vec3 start_point = self.start_point + cdef Vec3 end_point + while t0 < 1.0: + t1 = t0 + dt + if isclose(t1, 1.0, REL_TOL, ABS_TOL): + end_point = self.end_point + t1 = 1.0 + else: + end_point = self.curve.point(t1) + f.reset_recursion_check() + f.flatten(start_point, end_point, t0, t1) + if f.has_recursion_error(): + raise RecursionError( + "Bezier3P flattening error, check for very large coordinates" + ) + t0 = t1 + start_point = end_point + return f.points + + def approximated_length(self, segments: int = 128) -> float: + cdef double length = 0.0 + cdef bint start_flag = 0 + cdef Vec3 prev_point, point + + for point in self.approximate(segments): + if start_flag: + length += v3_dist(prev_point, point) + else: + start_flag = 1 + prev_point = point + return length + + def reverse(self) -> Bezier3P: + return Bezier3P((self.end_point, self.cp1, self.start_point)) + + def transform(self, Matrix44 m) -> Bezier3P: + return Bezier3P(tuple(m.transform_vertices(self.control_points))) + + +cdef class _Flattening: + cdef FastQuadCurve curve # pyright: ignore + cdef double distance + cdef list points + cdef int _recursion_level + cdef int _recursion_error + + def __cinit__(self, Bezier3P curve, double distance): + self.curve = curve.curve + self.distance = distance + self.points = [curve.start_point] + self._recursion_level = 0 + self._recursion_error = 0 + + cdef has_recursion_error(self): + return self._recursion_error + + cdef reset_recursion_check(self): + self._recursion_level = 0 + self._recursion_error = 0 + + cdef flatten( + self, + Vec3 start_point, + Vec3 end_point, + double start_t, + double end_t + ): + if self._recursion_level > RECURSION_LIMIT: + self._recursion_error = 1 + return + self._recursion_level += 1 + cdef double mid_t = (start_t + end_t) * 0.5 + cdef Vec3 mid_point = self.curve.point(mid_t) + cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + if d < self.distance: + self.points.append(end_point) + else: + self.flatten(start_point, mid_point, start_t, mid_t) + self.flatten(mid_point, end_point, mid_t, end_t) + self._recursion_level -= 1 + + +cdef class FastQuadCurve: + cdef: + double[3] offset + double[3] p1 + double[3] p2 + + def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2): + self.offset[0] = p0.x + self.offset[1] = p0.y + self.offset[2] = p0.z + + # 1st control point (p0) is always (0, 0, 0) + self.p1[0] = p1.x - p0.x + self.p1[1] = p1.y - p0.y + self.p1[2] = p1.z - p0.z + + self.p2[0] = p2.x - p0.x + self.p2[1] = p2.y - p0.y + self.p2[2] = p2.z - p0.z + + + cdef Vec3 point(self, double t): + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + cdef: + Vec3 result = Vec3() + # double a = (1 - t) ** 2 + double b = 2.0 * t * (1.0 - t) + double c = t * t + + iadd_mul(result, self.p1, b) + iadd_mul(result, self.p2, c) + + # add offset at last - it is maybe very large + result.x += self.offset[0] + result.y += self.offset[1] + result.z += self.offset[2] + + return result + + + cdef Vec3 tangent(self, double t): + # tangent vector is independent from offset location! + cdef: + Vec3 result = Vec3() + # double a = -2 * (1 - t) + double b = 2.0 - 4.0 * t + double c = 2.0 * t + + iadd_mul(result, self.p1, b) + iadd_mul(result, self.p2, c) + + return result + + +cdef void iadd_mul(Vec3 a, double[3] b, double c): + a.x += b[0] * c + a.y += b[1] * c + a.z += b[2] * c diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.c new file mode 100644 index 0000000..a8833ef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.c @@ -0,0 +1,18390 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.bezier4p", + "sources": [ + "src/ezdxf/acc/bezier4p.pyx" + ] + }, + "module_name": "ezdxf.acc.bezier4p" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__bezier4p +#define __PYX_HAVE_API__ezdxf__acc__bezier4p +/* Early includes */ +#include +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/bezier4p.pyx", + "", + "src/ezdxf/acc/vector.pxd", + "src/ezdxf/acc/matrix44.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44; +struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P; +struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening; +struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve; +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters; +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc; +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "matrix44.pxd":6 + * from .vector cimport Vec3 + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * cdef double m[16] + * cdef Vec3 get_ux(self: Matrix44) + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtab; + double m[16]; +}; + + +/* "ezdxf/acc/bezier4p.pyx":40 + * + * + * cdef class Bezier4P: # <<<<<<<<<<<<<< + * cdef: + * FastCubicCurve curve # pyright: ignore + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *curve; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *start_point; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *cp1; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *cp2; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *end_point; +}; + + +/* "ezdxf/acc/bezier4p.pyx":145 + * + * + * cdef class _Flattening: # <<<<<<<<<<<<<< + * cdef FastCubicCurve curve # pyright: ignore + * cdef double distance + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *__pyx_vtab; + struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *curve; + double distance; + PyObject *points; + int _recursion_level; + int _recursion_error; +}; + + +/* "ezdxf/acc/bezier4p.pyx":295 + * + * + * cdef class FastCubicCurve: # <<<<<<<<<<<<<< + * cdef: + * double[3] offset + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_vtab; + double offset[3]; + double p1[3]; + double p2[3]; + double p3[3]; +}; + + +/* "ezdxf/acc/bezier4p.pyx":193 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + * @cython.cdivision(True) # <<<<<<<<<<<<<< + * def cubic_bezier_arc_parameters( + * double start_angle, + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters { + PyObject_HEAD + int __pyx_v__; + double __pyx_v_angle; + int __pyx_v_arc_count; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_cp1; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_cp2; + double __pyx_v_delta_angle; + double __pyx_v_end_angle; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point; + double __pyx_v_segment_angle; + int __pyx_v_segments; + double __pyx_v_start_angle; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point; + double __pyx_v_tangent_length; + int __pyx_t_0; + int __pyx_t_1; + int __pyx_t_2; +}; + + +/* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc { + PyObject_HEAD + double __pyx_v_angle_span; + PyObject *__pyx_v_center; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_center_; + PyObject *__pyx_v_control_points; + double __pyx_v_end_angle; + int __pyx_v_i; + double __pyx_v_radius; + PyObject *__pyx_v_res; + double __pyx_v_s; + int __pyx_v_segments; + double __pyx_v_start_angle; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_tmp; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/bezier4p.pyx":256 + * yield Bezier4P(res) + * + * def cubic_bezier_from_ellipse( # <<<<<<<<<<<<<< + * ellipse: ConstructionEllipse, + * int segments = 1 + */ +struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_c_res; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_center; + PyObject *__pyx_v_control_points; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_cp; + PyObject *__pyx_v_ellipse; + double __pyx_v_end_angle; + long __pyx_v_i; + double __pyx_v_param_span; + PyObject *__pyx_v_res; + int __pyx_v_segments; + double __pyx_v_start_angle; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_x_axis; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_y_axis; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + + +/* "matrix44.pxd":6 + * from .vector cimport Vec3 + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * cdef double m[16] + * cdef Vec3 get_ux(self: Matrix44) + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_ux)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uy)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uz)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44; + + +/* "ezdxf/acc/bezier4p.pyx":145 + * + * + * cdef class _Flattening: # <<<<<<<<<<<<<< + * cdef FastCubicCurve curve # pyright: ignore + * cdef double distance + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening { + PyObject *(*has_recursion_error)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *); + PyObject *(*reset_recursion_check)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *); + PyObject *(*flatten)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *__pyx_vtabptr_5ezdxf_3acc_8bezier4p__Flattening; + + +/* "ezdxf/acc/bezier4p.pyx":295 + * + * + * cdef class FastCubicCurve: # <<<<<<<<<<<<<< + * cdef: + * double[3] offset + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*point)(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *, double); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*tangent)(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *, double); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_vtabptr_5ezdxf_3acc_8bezier4p_FastCubicCurve; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* ModFloat[double].proto */ +static CYTHON_INLINE double __Pyx_mod_double(double, double); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* ImportDottedModule.proto */ +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyObjectCall2Args.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* CoroutineBase.proto */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; + PyObject *gi_weakreflist; + PyObject *classobj; + PyObject *yieldfrom; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static PyObject *__Pyx_Coroutine_Close(PyObject *self); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); + +/* PatchModuleWithCoroutine.proto */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code); + +/* PatchGeneratorABC.proto */ +static int __Pyx_patch_abc(void); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_has_recursion_error(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_reset_recursion_check(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_flatten(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point, double __pyx_v_start_t, double __pyx_v_end_t); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_point(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, double __pyx_v_t); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_tangent(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, double __pyx_v_t); /* proto*/ + +/* Module declarations from "cython" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static int (*__pyx_f_5ezdxf_3acc_6vector_isclose)(double, double, double, double); /*proto*/ +static double (*__pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle)(double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_add)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_mul)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static double (*__pyx_f_5ezdxf_3acc_6vector_v3_dist)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_from_angle)(double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_lerp)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ + +/* Module declarations from "ezdxf.acc.matrix44" */ + +/* Module declarations from "libc.math" */ + +/* Module declarations from "ezdxf.acc.bezier4p" */ +static double __pyx_v_5ezdxf_3acc_8bezier4p_DEG2RAD; +static double __pyx_v_5ezdxf_3acc_8bezier4p_RECURSION_LIMIT; +static double __pyx_v_5ezdxf_3acc_8bezier4p_DEFAULT_TANGENT_FACTOR; +static double __pyx_v_5ezdxf_3acc_8bezier4p_OPTIMIZED_TANGENT_FACTOR; +static double __pyx_v_5ezdxf_3acc_8bezier4p_TANGENT_FACTOR; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_v3_add_3(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static void __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double *, double); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.bezier4p" +extern int __pyx_module_is_main_ezdxf__acc__bezier4p; +int __pyx_module_is_main_ezdxf__acc__bezier4p = 0; + +/* Implementation of "ezdxf.acc.bezier4p" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_DeprecationWarning; +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_TypeError; +/* #### Code section: string_decls ### */ +static const char __pyx_k_f[] = "f"; +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_m[] = "m"; +static const char __pyx_k_s[] = "s"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k_cp[] = "cp"; +static const char __pyx_k_dt[] = "dt"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_p0[] = "p0"; +static const char __pyx_k_p1[] = "p1"; +static const char __pyx_k_p2[] = "p2"; +static const char __pyx_k_p3[] = "p3"; +static const char __pyx_k_t0[] = "t0"; +static const char __pyx_k_t1[] = "t1"; +static const char __pyx_k__12[] = "."; +static const char __pyx_k__13[] = "*"; +static const char __pyx_k__32[] = "_"; +static const char __pyx_k__38[] = "?"; +static const char __pyx_k_all[] = "__all__"; +static const char __pyx_k_cp1[] = "cp1"; +static const char __pyx_k_cp2[] = "cp2"; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_tmp[] = "tmp"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_Vec3[] = "Vec3"; +static const char __pyx_k_args[] = "args"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_send[] = "send"; +static const char __pyx_k_spec[] = "__spec__"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_warn[] = "warn"; +static const char __pyx_k_angle[] = "angle"; +static const char __pyx_k_c_res[] = "c_res"; +static const char __pyx_k_close[] = "close"; +static const char __pyx_k_curve[] = "curve"; +static const char __pyx_k_float[] = "float"; +static const char __pyx_k_point[] = "point"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_throw[] = "throw"; +static const char __pyx_k_center[] = "center"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_length[] = "length"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_radius[] = "radius"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_x_axis[] = "x_axis"; +static const char __pyx_k_y_axis[] = "y_axis"; +static const char __pyx_k_delta_t[] = "delta_t"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_ellipse[] = "ellipse"; +static const char __pyx_k_reverse[] = "reverse"; +static const char __pyx_k_segment[] = "segment"; +static const char __pyx_k_tangent[] = "tangent"; +static const char __pyx_k_Bezier4P[] = "Bezier4P"; +static const char __pyx_k_Iterable[] = "Iterable"; +static const char __pyx_k_Iterator[] = "Iterator"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_center_2[] = "center_"; +static const char __pyx_k_distance[] = "distance"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_segments[] = "segments"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_warnings[] = "warnings"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_arc_count[] = "arc_count"; +static const char __pyx_k_construct[] = "construct"; +static const char __pyx_k_defpoints[] = "defpoints"; +static const char __pyx_k_end_angle[] = "end_angle"; +static const char __pyx_k_end_point[] = "end_point"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_list_Vec3[] = "list[Vec3]"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_transform[] = "transform"; +static const char __pyx_k_Flattening[] = "_Flattening"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_angle_span[] = "angle_span"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_flattening[] = "flattening"; +static const char __pyx_k_major_axis[] = "major_axis"; +static const char __pyx_k_minor_axis[] = "minor_axis"; +static const char __pyx_k_param_span[] = "param_span"; +static const char __pyx_k_prev_point[] = "prev_point"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_start_flag[] = "start_flag"; +static const char __pyx_k_approximate[] = "approximate"; +static const char __pyx_k_delta_angle[] = "delta_angle"; +static const char __pyx_k_start_angle[] = "start_angle"; +static const char __pyx_k_start_param[] = "start_param"; +static const char __pyx_k_start_point[] = "start_point"; +static const char __pyx_k_initializing[] = "_initializing"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_segment_angle[] = "segment_angle"; +static const char __pyx_k_Bezier4P_point[] = "Bezier4P.point"; +static const char __pyx_k_FastCubicCurve[] = "FastCubicCurve"; +static const char __pyx_k_RecursionError[] = "RecursionError"; +static const char __pyx_k_control_points[] = "control_points"; +static const char __pyx_k_tangent_length[] = "tangent_length"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_Bezier4P_reverse[] = "Bezier4P.reverse"; +static const char __pyx_k_Bezier4P_tangent[] = "Bezier4P.tangent"; +static const char __pyx_k_Bezier4P___reduce[] = "Bezier4P.__reduce__"; +static const char __pyx_k_Iterable_Bezier4P[] = "Iterable[Bezier4P]"; +static const char __pyx_k_Iterator_Bezier4P[] = "Iterator[Bezier4P]"; +static const char __pyx_k_Bezier4P_transform[] = "Bezier4P.transform"; +static const char __pyx_k_DeprecationWarning[] = "DeprecationWarning"; +static const char __pyx_k_arc_angle_span_deg[] = "arc_angle_span_deg"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ezdxf_acc_bezier4p[] = "ezdxf.acc.bezier4p"; +static const char __pyx_k_ezdxf_math_ellipse[] = "ezdxf.math.ellipse"; +static const char __pyx_k_transform_vertices[] = "transform_vertices"; +static const char __pyx_k_Bezier4P_flattening[] = "Bezier4P.flattening"; +static const char __pyx_k_ConstructionEllipse[] = "ConstructionEllipse"; +static const char __pyx_k_approximated_length[] = "approximated_length"; +static const char __pyx_k_Bezier4P_approximate[] = "Bezier4P.approximate"; +static const char __pyx_k_cubic_bezier_from_arc[] = "cubic_bezier_from_arc"; +static const char __pyx_k_t_not_in_range_0_to_1[] = "t not in range [0 to 1]"; +static const char __pyx_k_cubic_bezier_from_ellipse[] = "cubic_bezier_from_ellipse"; +static const char __pyx_k_Flattening___reduce_cython[] = "_Flattening.__reduce_cython__"; +static const char __pyx_k_src_ezdxf_acc_bezier4p_pyx[] = "src/ezdxf/acc/bezier4p.pyx"; +static const char __pyx_k_Invalid_argument_segments_1[] = "Invalid argument segments (>= 1)."; +static const char __pyx_k_cubic_bezier_arc_parameters[] = "cubic_bezier_arc_parameters"; +static const char __pyx_k_Bezier4P_approximated_length[] = "Bezier4P.approximated_length"; +static const char __pyx_k_Flattening___setstate_cython[] = "_Flattening.__setstate_cython__"; +static const char __pyx_k_Four_control_points_required[] = "Four control points required."; +static const char __pyx_k_FastCubicCurve___reduce_cython[] = "FastCubicCurve.__reduce_cython__"; +static const char __pyx_k_Bezier4P_flattening_error_check[] = "Bezier4P flattening error, check for very large coordinates"; +static const char __pyx_k_Bezier4P_requires_defpoints_of_t[] = "Bezier4P requires defpoints of type Vec2 or Vec3 in the future"; +static const char __pyx_k_Delta_angle_from_start_to_end_an[] = "Delta angle from start- to end angle has to be > 0."; +static const char __pyx_k_FastCubicCurve___setstate_cython[] = "FastCubicCurve.__setstate_cython__"; +static const char __pyx_k_Iterator_tuple_Vec3_Vec3_Vec3_Ve[] = "Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +/* #### Code section: decls ### */ +static int __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, PyObject *__pyx_v_defpoints); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_4point(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_t); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_6tangent(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_t); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_8approximate(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_10flattening(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_distance, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_12approximated_length(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, PyObject *__pyx_v_segments); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14reverse(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_16transform(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_curve, double __pyx_v_distance); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_cubic_bezier_arc_parameters(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start_angle, double __pyx_v_end_angle, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_3cubic_bezier_from_arc(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_center, double __pyx_v_radius, double __pyx_v_start_angle, double __pyx_v_end_angle, int __pyx_v_segments); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_6cubic_bezier_from_ellipse(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_ellipse, int __pyx_v_segments); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p3); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p_Bezier4P(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p__Flattening(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p_FastCubicCurve(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44; + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P; + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p__Flattening; + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve; + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters; + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc; + PyObject *__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse; + PyObject *__pyx_n_s_Bezier4P; + PyObject *__pyx_n_u_Bezier4P; + PyObject *__pyx_n_s_Bezier4P___reduce; + PyObject *__pyx_n_s_Bezier4P_approximate; + PyObject *__pyx_n_s_Bezier4P_approximated_length; + PyObject *__pyx_n_s_Bezier4P_flattening; + PyObject *__pyx_kp_u_Bezier4P_flattening_error_check; + PyObject *__pyx_n_s_Bezier4P_point; + PyObject *__pyx_kp_u_Bezier4P_requires_defpoints_of_t; + PyObject *__pyx_n_s_Bezier4P_reverse; + PyObject *__pyx_n_s_Bezier4P_tangent; + PyObject *__pyx_n_s_Bezier4P_transform; + PyObject *__pyx_n_s_ConstructionEllipse; + PyObject *__pyx_kp_u_Delta_angle_from_start_to_end_an; + PyObject *__pyx_n_s_DeprecationWarning; + PyObject *__pyx_n_s_FastCubicCurve; + PyObject *__pyx_n_s_FastCubicCurve___reduce_cython; + PyObject *__pyx_n_s_FastCubicCurve___setstate_cython; + PyObject *__pyx_n_s_Flattening; + PyObject *__pyx_n_s_Flattening___reduce_cython; + PyObject *__pyx_n_s_Flattening___setstate_cython; + PyObject *__pyx_kp_u_Four_control_points_required; + PyObject *__pyx_kp_u_Invalid_argument_segments_1; + PyObject *__pyx_n_s_Iterable; + PyObject *__pyx_kp_s_Iterable_Bezier4P; + PyObject *__pyx_n_s_Iterator; + PyObject *__pyx_kp_s_Iterator_Bezier4P; + PyObject *__pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve; + PyObject *__pyx_n_s_RecursionError; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s_Vec3; + PyObject *__pyx_kp_u__12; + PyObject *__pyx_n_s__13; + PyObject *__pyx_n_s__32; + PyObject *__pyx_n_s__38; + PyObject *__pyx_n_s_all; + PyObject *__pyx_n_s_angle; + PyObject *__pyx_n_s_angle_span; + PyObject *__pyx_n_s_approximate; + PyObject *__pyx_n_s_approximated_length; + PyObject *__pyx_n_s_arc_angle_span_deg; + PyObject *__pyx_n_s_arc_count; + PyObject *__pyx_n_s_args; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_c_res; + PyObject *__pyx_n_s_center; + PyObject *__pyx_n_s_center_2; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_close; + PyObject *__pyx_n_s_construct; + PyObject *__pyx_n_s_control_points; + PyObject *__pyx_n_s_cp; + PyObject *__pyx_n_s_cp1; + PyObject *__pyx_n_s_cp2; + PyObject *__pyx_n_s_cubic_bezier_arc_parameters; + PyObject *__pyx_n_u_cubic_bezier_arc_parameters; + PyObject *__pyx_n_s_cubic_bezier_from_arc; + PyObject *__pyx_n_u_cubic_bezier_from_arc; + PyObject *__pyx_n_s_cubic_bezier_from_ellipse; + PyObject *__pyx_n_u_cubic_bezier_from_ellipse; + PyObject *__pyx_n_s_curve; + PyObject *__pyx_n_s_defpoints; + PyObject *__pyx_n_s_delta_angle; + PyObject *__pyx_n_s_delta_t; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_distance; + PyObject *__pyx_n_s_dt; + PyObject *__pyx_n_s_ellipse; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_end_angle; + PyObject *__pyx_n_s_end_point; + PyObject *__pyx_n_s_ezdxf_acc_bezier4p; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_n_s_ezdxf_math_ellipse; + PyObject *__pyx_n_s_f; + PyObject *__pyx_n_s_flattening; + PyObject *__pyx_n_s_float; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_n_s_i; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_initializing; + PyObject *__pyx_n_s_int; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_length; + PyObject *__pyx_kp_s_list_Vec3; + PyObject *__pyx_n_s_m; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_major_axis; + PyObject *__pyx_n_s_minor_axis; + PyObject *__pyx_n_s_name; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_p0; + PyObject *__pyx_n_s_p1; + PyObject *__pyx_n_s_p2; + PyObject *__pyx_n_s_p3; + PyObject *__pyx_n_s_param_span; + PyObject *__pyx_n_s_point; + PyObject *__pyx_n_s_points; + PyObject *__pyx_n_s_prev_point; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_radius; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_res; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_reverse; + PyObject *__pyx_n_s_s; + PyObject *__pyx_n_s_segment; + PyObject *__pyx_n_s_segment_angle; + PyObject *__pyx_n_s_segments; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_send; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_spec; + PyObject *__pyx_kp_s_src_ezdxf_acc_bezier4p_pyx; + PyObject *__pyx_n_s_start_angle; + PyObject *__pyx_n_s_start_flag; + PyObject *__pyx_n_s_start_param; + PyObject *__pyx_n_s_start_point; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_t; + PyObject *__pyx_n_s_t0; + PyObject *__pyx_n_s_t1; + PyObject *__pyx_kp_u_t_not_in_range_0_to_1; + PyObject *__pyx_n_s_tangent; + PyObject *__pyx_n_s_tangent_length; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_throw; + PyObject *__pyx_n_s_tmp; + PyObject *__pyx_n_s_transform; + PyObject *__pyx_n_s_transform_vertices; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_warn; + PyObject *__pyx_n_s_warnings; + PyObject *__pyx_n_s_x_axis; + PyObject *__pyx_n_s_y_axis; + PyObject *__pyx_int_0; + PyObject *__pyx_int_4; + PyObject *__pyx_int_128; + PyObject *__pyx_k__5; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__2; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__7; + PyObject *__pyx_tuple__8; + PyObject *__pyx_tuple__9; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__16; + PyObject *__pyx_tuple__19; + PyObject *__pyx_tuple__21; + PyObject *__pyx_tuple__23; + PyObject *__pyx_tuple__24; + PyObject *__pyx_tuple__27; + PyObject *__pyx_tuple__30; + PyObject *__pyx_tuple__33; + PyObject *__pyx_tuple__34; + PyObject *__pyx_tuple__35; + PyObject *__pyx_codeobj__6; + PyObject *__pyx_codeobj__10; + PyObject *__pyx_codeobj__11; + PyObject *__pyx_codeobj__15; + PyObject *__pyx_codeobj__17; + PyObject *__pyx_codeobj__18; + PyObject *__pyx_codeobj__20; + PyObject *__pyx_codeobj__22; + PyObject *__pyx_codeobj__25; + PyObject *__pyx_codeobj__26; + PyObject *__pyx_codeobj__28; + PyObject *__pyx_codeobj__29; + PyObject *__pyx_codeobj__31; + PyObject *__pyx_codeobj__36; + PyObject *__pyx_codeobj__37; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p__Flattening); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_n_u_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P___reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_approximate); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_approximated_length); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_flattening); + Py_CLEAR(clear_module_state->__pyx_kp_u_Bezier4P_flattening_error_check); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_point); + Py_CLEAR(clear_module_state->__pyx_kp_u_Bezier4P_requires_defpoints_of_t); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_reverse); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_tangent); + Py_CLEAR(clear_module_state->__pyx_n_s_Bezier4P_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_ConstructionEllipse); + Py_CLEAR(clear_module_state->__pyx_kp_u_Delta_angle_from_start_to_end_an); + Py_CLEAR(clear_module_state->__pyx_n_s_DeprecationWarning); + Py_CLEAR(clear_module_state->__pyx_n_s_FastCubicCurve); + Py_CLEAR(clear_module_state->__pyx_n_s_FastCubicCurve___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_FastCubicCurve___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Flattening___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_kp_u_Four_control_points_required); + Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_argument_segments_1); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterable); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterator); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Bezier4P); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve); + Py_CLEAR(clear_module_state->__pyx_n_s_RecursionError); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3); + Py_CLEAR(clear_module_state->__pyx_kp_u__12); + Py_CLEAR(clear_module_state->__pyx_n_s__13); + Py_CLEAR(clear_module_state->__pyx_n_s__32); + Py_CLEAR(clear_module_state->__pyx_n_s__38); + Py_CLEAR(clear_module_state->__pyx_n_s_all); + Py_CLEAR(clear_module_state->__pyx_n_s_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_span); + Py_CLEAR(clear_module_state->__pyx_n_s_approximate); + Py_CLEAR(clear_module_state->__pyx_n_s_approximated_length); + Py_CLEAR(clear_module_state->__pyx_n_s_arc_angle_span_deg); + Py_CLEAR(clear_module_state->__pyx_n_s_arc_count); + Py_CLEAR(clear_module_state->__pyx_n_s_args); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_c_res); + Py_CLEAR(clear_module_state->__pyx_n_s_center); + Py_CLEAR(clear_module_state->__pyx_n_s_center_2); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_close); + Py_CLEAR(clear_module_state->__pyx_n_s_construct); + Py_CLEAR(clear_module_state->__pyx_n_s_control_points); + Py_CLEAR(clear_module_state->__pyx_n_s_cp); + Py_CLEAR(clear_module_state->__pyx_n_s_cp1); + Py_CLEAR(clear_module_state->__pyx_n_s_cp2); + Py_CLEAR(clear_module_state->__pyx_n_s_cubic_bezier_arc_parameters); + Py_CLEAR(clear_module_state->__pyx_n_u_cubic_bezier_arc_parameters); + Py_CLEAR(clear_module_state->__pyx_n_s_cubic_bezier_from_arc); + Py_CLEAR(clear_module_state->__pyx_n_u_cubic_bezier_from_arc); + Py_CLEAR(clear_module_state->__pyx_n_s_cubic_bezier_from_ellipse); + Py_CLEAR(clear_module_state->__pyx_n_u_cubic_bezier_from_ellipse); + Py_CLEAR(clear_module_state->__pyx_n_s_curve); + Py_CLEAR(clear_module_state->__pyx_n_s_defpoints); + Py_CLEAR(clear_module_state->__pyx_n_s_delta_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_delta_t); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_distance); + Py_CLEAR(clear_module_state->__pyx_n_s_dt); + Py_CLEAR(clear_module_state->__pyx_n_s_ellipse); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_end_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_end_point); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_bezier4p); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math_ellipse); + Py_CLEAR(clear_module_state->__pyx_n_s_f); + Py_CLEAR(clear_module_state->__pyx_n_s_flattening); + Py_CLEAR(clear_module_state->__pyx_n_s_float); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_n_s_i); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_initializing); + Py_CLEAR(clear_module_state->__pyx_n_s_int); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_length); + Py_CLEAR(clear_module_state->__pyx_kp_s_list_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_m); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_major_axis); + Py_CLEAR(clear_module_state->__pyx_n_s_minor_axis); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_p0); + Py_CLEAR(clear_module_state->__pyx_n_s_p1); + Py_CLEAR(clear_module_state->__pyx_n_s_p2); + Py_CLEAR(clear_module_state->__pyx_n_s_p3); + Py_CLEAR(clear_module_state->__pyx_n_s_param_span); + Py_CLEAR(clear_module_state->__pyx_n_s_point); + Py_CLEAR(clear_module_state->__pyx_n_s_points); + Py_CLEAR(clear_module_state->__pyx_n_s_prev_point); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_radius); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_res); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_reverse); + Py_CLEAR(clear_module_state->__pyx_n_s_s); + Py_CLEAR(clear_module_state->__pyx_n_s_segment); + Py_CLEAR(clear_module_state->__pyx_n_s_segment_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_segments); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_send); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_spec); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_bezier4p_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_start_flag); + Py_CLEAR(clear_module_state->__pyx_n_s_start_param); + Py_CLEAR(clear_module_state->__pyx_n_s_start_point); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_t); + Py_CLEAR(clear_module_state->__pyx_n_s_t0); + Py_CLEAR(clear_module_state->__pyx_n_s_t1); + Py_CLEAR(clear_module_state->__pyx_kp_u_t_not_in_range_0_to_1); + Py_CLEAR(clear_module_state->__pyx_n_s_tangent); + Py_CLEAR(clear_module_state->__pyx_n_s_tangent_length); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_throw); + Py_CLEAR(clear_module_state->__pyx_n_s_tmp); + Py_CLEAR(clear_module_state->__pyx_n_s_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_warn); + Py_CLEAR(clear_module_state->__pyx_n_s_warnings); + Py_CLEAR(clear_module_state->__pyx_n_s_x_axis); + Py_CLEAR(clear_module_state->__pyx_n_s_y_axis); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_4); + Py_CLEAR(clear_module_state->__pyx_int_128); + Py_CLEAR(clear_module_state->__pyx_k__5); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__2); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__7); + Py_CLEAR(clear_module_state->__pyx_tuple__8); + Py_CLEAR(clear_module_state->__pyx_tuple__9); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__16); + Py_CLEAR(clear_module_state->__pyx_tuple__19); + Py_CLEAR(clear_module_state->__pyx_tuple__21); + Py_CLEAR(clear_module_state->__pyx_tuple__23); + Py_CLEAR(clear_module_state->__pyx_tuple__24); + Py_CLEAR(clear_module_state->__pyx_tuple__27); + Py_CLEAR(clear_module_state->__pyx_tuple__30); + Py_CLEAR(clear_module_state->__pyx_tuple__33); + Py_CLEAR(clear_module_state->__pyx_tuple__34); + Py_CLEAR(clear_module_state->__pyx_tuple__35); + Py_CLEAR(clear_module_state->__pyx_codeobj__6); + Py_CLEAR(clear_module_state->__pyx_codeobj__10); + Py_CLEAR(clear_module_state->__pyx_codeobj__11); + Py_CLEAR(clear_module_state->__pyx_codeobj__15); + Py_CLEAR(clear_module_state->__pyx_codeobj__17); + Py_CLEAR(clear_module_state->__pyx_codeobj__18); + Py_CLEAR(clear_module_state->__pyx_codeobj__20); + Py_CLEAR(clear_module_state->__pyx_codeobj__22); + Py_CLEAR(clear_module_state->__pyx_codeobj__25); + Py_CLEAR(clear_module_state->__pyx_codeobj__26); + Py_CLEAR(clear_module_state->__pyx_codeobj__28); + Py_CLEAR(clear_module_state->__pyx_codeobj__29); + Py_CLEAR(clear_module_state->__pyx_codeobj__31); + Py_CLEAR(clear_module_state->__pyx_codeobj__36); + Py_CLEAR(clear_module_state->__pyx_codeobj__37); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p__Flattening); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_n_u_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P___reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_approximate); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_approximated_length); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_flattening); + Py_VISIT(traverse_module_state->__pyx_kp_u_Bezier4P_flattening_error_check); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_point); + Py_VISIT(traverse_module_state->__pyx_kp_u_Bezier4P_requires_defpoints_of_t); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_reverse); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_tangent); + Py_VISIT(traverse_module_state->__pyx_n_s_Bezier4P_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_ConstructionEllipse); + Py_VISIT(traverse_module_state->__pyx_kp_u_Delta_angle_from_start_to_end_an); + Py_VISIT(traverse_module_state->__pyx_n_s_DeprecationWarning); + Py_VISIT(traverse_module_state->__pyx_n_s_FastCubicCurve); + Py_VISIT(traverse_module_state->__pyx_n_s_FastCubicCurve___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_FastCubicCurve___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Flattening___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_kp_u_Four_control_points_required); + Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_argument_segments_1); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterable); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterator); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Bezier4P); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve); + Py_VISIT(traverse_module_state->__pyx_n_s_RecursionError); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3); + Py_VISIT(traverse_module_state->__pyx_kp_u__12); + Py_VISIT(traverse_module_state->__pyx_n_s__13); + Py_VISIT(traverse_module_state->__pyx_n_s__32); + Py_VISIT(traverse_module_state->__pyx_n_s__38); + Py_VISIT(traverse_module_state->__pyx_n_s_all); + Py_VISIT(traverse_module_state->__pyx_n_s_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_span); + Py_VISIT(traverse_module_state->__pyx_n_s_approximate); + Py_VISIT(traverse_module_state->__pyx_n_s_approximated_length); + Py_VISIT(traverse_module_state->__pyx_n_s_arc_angle_span_deg); + Py_VISIT(traverse_module_state->__pyx_n_s_arc_count); + Py_VISIT(traverse_module_state->__pyx_n_s_args); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_c_res); + Py_VISIT(traverse_module_state->__pyx_n_s_center); + Py_VISIT(traverse_module_state->__pyx_n_s_center_2); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_close); + Py_VISIT(traverse_module_state->__pyx_n_s_construct); + Py_VISIT(traverse_module_state->__pyx_n_s_control_points); + Py_VISIT(traverse_module_state->__pyx_n_s_cp); + Py_VISIT(traverse_module_state->__pyx_n_s_cp1); + Py_VISIT(traverse_module_state->__pyx_n_s_cp2); + Py_VISIT(traverse_module_state->__pyx_n_s_cubic_bezier_arc_parameters); + Py_VISIT(traverse_module_state->__pyx_n_u_cubic_bezier_arc_parameters); + Py_VISIT(traverse_module_state->__pyx_n_s_cubic_bezier_from_arc); + Py_VISIT(traverse_module_state->__pyx_n_u_cubic_bezier_from_arc); + Py_VISIT(traverse_module_state->__pyx_n_s_cubic_bezier_from_ellipse); + Py_VISIT(traverse_module_state->__pyx_n_u_cubic_bezier_from_ellipse); + Py_VISIT(traverse_module_state->__pyx_n_s_curve); + Py_VISIT(traverse_module_state->__pyx_n_s_defpoints); + Py_VISIT(traverse_module_state->__pyx_n_s_delta_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_delta_t); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_distance); + Py_VISIT(traverse_module_state->__pyx_n_s_dt); + Py_VISIT(traverse_module_state->__pyx_n_s_ellipse); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_end_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_end_point); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_bezier4p); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math_ellipse); + Py_VISIT(traverse_module_state->__pyx_n_s_f); + Py_VISIT(traverse_module_state->__pyx_n_s_flattening); + Py_VISIT(traverse_module_state->__pyx_n_s_float); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_n_s_i); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_initializing); + Py_VISIT(traverse_module_state->__pyx_n_s_int); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_length); + Py_VISIT(traverse_module_state->__pyx_kp_s_list_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_m); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_major_axis); + Py_VISIT(traverse_module_state->__pyx_n_s_minor_axis); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_p0); + Py_VISIT(traverse_module_state->__pyx_n_s_p1); + Py_VISIT(traverse_module_state->__pyx_n_s_p2); + Py_VISIT(traverse_module_state->__pyx_n_s_p3); + Py_VISIT(traverse_module_state->__pyx_n_s_param_span); + Py_VISIT(traverse_module_state->__pyx_n_s_point); + Py_VISIT(traverse_module_state->__pyx_n_s_points); + Py_VISIT(traverse_module_state->__pyx_n_s_prev_point); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_radius); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_res); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_reverse); + Py_VISIT(traverse_module_state->__pyx_n_s_s); + Py_VISIT(traverse_module_state->__pyx_n_s_segment); + Py_VISIT(traverse_module_state->__pyx_n_s_segment_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_segments); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_send); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_spec); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_bezier4p_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_start_flag); + Py_VISIT(traverse_module_state->__pyx_n_s_start_param); + Py_VISIT(traverse_module_state->__pyx_n_s_start_point); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_t); + Py_VISIT(traverse_module_state->__pyx_n_s_t0); + Py_VISIT(traverse_module_state->__pyx_n_s_t1); + Py_VISIT(traverse_module_state->__pyx_kp_u_t_not_in_range_0_to_1); + Py_VISIT(traverse_module_state->__pyx_n_s_tangent); + Py_VISIT(traverse_module_state->__pyx_n_s_tangent_length); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_throw); + Py_VISIT(traverse_module_state->__pyx_n_s_tmp); + Py_VISIT(traverse_module_state->__pyx_n_s_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_warn); + Py_VISIT(traverse_module_state->__pyx_n_s_warnings); + Py_VISIT(traverse_module_state->__pyx_n_s_x_axis); + Py_VISIT(traverse_module_state->__pyx_n_s_y_axis); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_4); + Py_VISIT(traverse_module_state->__pyx_int_128); + Py_VISIT(traverse_module_state->__pyx_k__5); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__2); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__7); + Py_VISIT(traverse_module_state->__pyx_tuple__8); + Py_VISIT(traverse_module_state->__pyx_tuple__9); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__16); + Py_VISIT(traverse_module_state->__pyx_tuple__19); + Py_VISIT(traverse_module_state->__pyx_tuple__21); + Py_VISIT(traverse_module_state->__pyx_tuple__23); + Py_VISIT(traverse_module_state->__pyx_tuple__24); + Py_VISIT(traverse_module_state->__pyx_tuple__27); + Py_VISIT(traverse_module_state->__pyx_tuple__30); + Py_VISIT(traverse_module_state->__pyx_tuple__33); + Py_VISIT(traverse_module_state->__pyx_tuple__34); + Py_VISIT(traverse_module_state->__pyx_tuple__35); + Py_VISIT(traverse_module_state->__pyx_codeobj__6); + Py_VISIT(traverse_module_state->__pyx_codeobj__10); + Py_VISIT(traverse_module_state->__pyx_codeobj__11); + Py_VISIT(traverse_module_state->__pyx_codeobj__15); + Py_VISIT(traverse_module_state->__pyx_codeobj__17); + Py_VISIT(traverse_module_state->__pyx_codeobj__18); + Py_VISIT(traverse_module_state->__pyx_codeobj__20); + Py_VISIT(traverse_module_state->__pyx_codeobj__22); + Py_VISIT(traverse_module_state->__pyx_codeobj__25); + Py_VISIT(traverse_module_state->__pyx_codeobj__26); + Py_VISIT(traverse_module_state->__pyx_codeobj__28); + Py_VISIT(traverse_module_state->__pyx_codeobj__29); + Py_VISIT(traverse_module_state->__pyx_codeobj__31); + Py_VISIT(traverse_module_state->__pyx_codeobj__36); + Py_VISIT(traverse_module_state->__pyx_codeobj__37); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P +#define __pyx_type_5ezdxf_3acc_8bezier4p__Flattening __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p__Flattening +#define __pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve +#define __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters +#define __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc +#define __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse +#endif +#define __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P +#define __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening +#define __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve +#define __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters +#define __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc +#define __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse +#define __pyx_n_s_Bezier4P __pyx_mstate_global->__pyx_n_s_Bezier4P +#define __pyx_n_u_Bezier4P __pyx_mstate_global->__pyx_n_u_Bezier4P +#define __pyx_n_s_Bezier4P___reduce __pyx_mstate_global->__pyx_n_s_Bezier4P___reduce +#define __pyx_n_s_Bezier4P_approximate __pyx_mstate_global->__pyx_n_s_Bezier4P_approximate +#define __pyx_n_s_Bezier4P_approximated_length __pyx_mstate_global->__pyx_n_s_Bezier4P_approximated_length +#define __pyx_n_s_Bezier4P_flattening __pyx_mstate_global->__pyx_n_s_Bezier4P_flattening +#define __pyx_kp_u_Bezier4P_flattening_error_check __pyx_mstate_global->__pyx_kp_u_Bezier4P_flattening_error_check +#define __pyx_n_s_Bezier4P_point __pyx_mstate_global->__pyx_n_s_Bezier4P_point +#define __pyx_kp_u_Bezier4P_requires_defpoints_of_t __pyx_mstate_global->__pyx_kp_u_Bezier4P_requires_defpoints_of_t +#define __pyx_n_s_Bezier4P_reverse __pyx_mstate_global->__pyx_n_s_Bezier4P_reverse +#define __pyx_n_s_Bezier4P_tangent __pyx_mstate_global->__pyx_n_s_Bezier4P_tangent +#define __pyx_n_s_Bezier4P_transform __pyx_mstate_global->__pyx_n_s_Bezier4P_transform +#define __pyx_n_s_ConstructionEllipse __pyx_mstate_global->__pyx_n_s_ConstructionEllipse +#define __pyx_kp_u_Delta_angle_from_start_to_end_an __pyx_mstate_global->__pyx_kp_u_Delta_angle_from_start_to_end_an +#define __pyx_n_s_DeprecationWarning __pyx_mstate_global->__pyx_n_s_DeprecationWarning +#define __pyx_n_s_FastCubicCurve __pyx_mstate_global->__pyx_n_s_FastCubicCurve +#define __pyx_n_s_FastCubicCurve___reduce_cython __pyx_mstate_global->__pyx_n_s_FastCubicCurve___reduce_cython +#define __pyx_n_s_FastCubicCurve___setstate_cython __pyx_mstate_global->__pyx_n_s_FastCubicCurve___setstate_cython +#define __pyx_n_s_Flattening __pyx_mstate_global->__pyx_n_s_Flattening +#define __pyx_n_s_Flattening___reduce_cython __pyx_mstate_global->__pyx_n_s_Flattening___reduce_cython +#define __pyx_n_s_Flattening___setstate_cython __pyx_mstate_global->__pyx_n_s_Flattening___setstate_cython +#define __pyx_kp_u_Four_control_points_required __pyx_mstate_global->__pyx_kp_u_Four_control_points_required +#define __pyx_kp_u_Invalid_argument_segments_1 __pyx_mstate_global->__pyx_kp_u_Invalid_argument_segments_1 +#define __pyx_n_s_Iterable __pyx_mstate_global->__pyx_n_s_Iterable +#define __pyx_kp_s_Iterable_Bezier4P __pyx_mstate_global->__pyx_kp_s_Iterable_Bezier4P +#define __pyx_n_s_Iterator __pyx_mstate_global->__pyx_n_s_Iterator +#define __pyx_kp_s_Iterator_Bezier4P __pyx_mstate_global->__pyx_kp_s_Iterator_Bezier4P +#define __pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve __pyx_mstate_global->__pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve +#define __pyx_n_s_RecursionError __pyx_mstate_global->__pyx_n_s_RecursionError +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s_Vec3 __pyx_mstate_global->__pyx_n_s_Vec3 +#define __pyx_kp_u__12 __pyx_mstate_global->__pyx_kp_u__12 +#define __pyx_n_s__13 __pyx_mstate_global->__pyx_n_s__13 +#define __pyx_n_s__32 __pyx_mstate_global->__pyx_n_s__32 +#define __pyx_n_s__38 __pyx_mstate_global->__pyx_n_s__38 +#define __pyx_n_s_all __pyx_mstate_global->__pyx_n_s_all +#define __pyx_n_s_angle __pyx_mstate_global->__pyx_n_s_angle +#define __pyx_n_s_angle_span __pyx_mstate_global->__pyx_n_s_angle_span +#define __pyx_n_s_approximate __pyx_mstate_global->__pyx_n_s_approximate +#define __pyx_n_s_approximated_length __pyx_mstate_global->__pyx_n_s_approximated_length +#define __pyx_n_s_arc_angle_span_deg __pyx_mstate_global->__pyx_n_s_arc_angle_span_deg +#define __pyx_n_s_arc_count __pyx_mstate_global->__pyx_n_s_arc_count +#define __pyx_n_s_args __pyx_mstate_global->__pyx_n_s_args +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_c_res __pyx_mstate_global->__pyx_n_s_c_res +#define __pyx_n_s_center __pyx_mstate_global->__pyx_n_s_center +#define __pyx_n_s_center_2 __pyx_mstate_global->__pyx_n_s_center_2 +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_close __pyx_mstate_global->__pyx_n_s_close +#define __pyx_n_s_construct __pyx_mstate_global->__pyx_n_s_construct +#define __pyx_n_s_control_points __pyx_mstate_global->__pyx_n_s_control_points +#define __pyx_n_s_cp __pyx_mstate_global->__pyx_n_s_cp +#define __pyx_n_s_cp1 __pyx_mstate_global->__pyx_n_s_cp1 +#define __pyx_n_s_cp2 __pyx_mstate_global->__pyx_n_s_cp2 +#define __pyx_n_s_cubic_bezier_arc_parameters __pyx_mstate_global->__pyx_n_s_cubic_bezier_arc_parameters +#define __pyx_n_u_cubic_bezier_arc_parameters __pyx_mstate_global->__pyx_n_u_cubic_bezier_arc_parameters +#define __pyx_n_s_cubic_bezier_from_arc __pyx_mstate_global->__pyx_n_s_cubic_bezier_from_arc +#define __pyx_n_u_cubic_bezier_from_arc __pyx_mstate_global->__pyx_n_u_cubic_bezier_from_arc +#define __pyx_n_s_cubic_bezier_from_ellipse __pyx_mstate_global->__pyx_n_s_cubic_bezier_from_ellipse +#define __pyx_n_u_cubic_bezier_from_ellipse __pyx_mstate_global->__pyx_n_u_cubic_bezier_from_ellipse +#define __pyx_n_s_curve __pyx_mstate_global->__pyx_n_s_curve +#define __pyx_n_s_defpoints __pyx_mstate_global->__pyx_n_s_defpoints +#define __pyx_n_s_delta_angle __pyx_mstate_global->__pyx_n_s_delta_angle +#define __pyx_n_s_delta_t __pyx_mstate_global->__pyx_n_s_delta_t +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_distance __pyx_mstate_global->__pyx_n_s_distance +#define __pyx_n_s_dt __pyx_mstate_global->__pyx_n_s_dt +#define __pyx_n_s_ellipse __pyx_mstate_global->__pyx_n_s_ellipse +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_end_angle __pyx_mstate_global->__pyx_n_s_end_angle +#define __pyx_n_s_end_point __pyx_mstate_global->__pyx_n_s_end_point +#define __pyx_n_s_ezdxf_acc_bezier4p __pyx_mstate_global->__pyx_n_s_ezdxf_acc_bezier4p +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_n_s_ezdxf_math_ellipse __pyx_mstate_global->__pyx_n_s_ezdxf_math_ellipse +#define __pyx_n_s_f __pyx_mstate_global->__pyx_n_s_f +#define __pyx_n_s_flattening __pyx_mstate_global->__pyx_n_s_flattening +#define __pyx_n_s_float __pyx_mstate_global->__pyx_n_s_float +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_n_s_i __pyx_mstate_global->__pyx_n_s_i +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing +#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_length __pyx_mstate_global->__pyx_n_s_length +#define __pyx_kp_s_list_Vec3 __pyx_mstate_global->__pyx_kp_s_list_Vec3 +#define __pyx_n_s_m __pyx_mstate_global->__pyx_n_s_m +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_major_axis __pyx_mstate_global->__pyx_n_s_major_axis +#define __pyx_n_s_minor_axis __pyx_mstate_global->__pyx_n_s_minor_axis +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_p0 __pyx_mstate_global->__pyx_n_s_p0 +#define __pyx_n_s_p1 __pyx_mstate_global->__pyx_n_s_p1 +#define __pyx_n_s_p2 __pyx_mstate_global->__pyx_n_s_p2 +#define __pyx_n_s_p3 __pyx_mstate_global->__pyx_n_s_p3 +#define __pyx_n_s_param_span __pyx_mstate_global->__pyx_n_s_param_span +#define __pyx_n_s_point __pyx_mstate_global->__pyx_n_s_point +#define __pyx_n_s_points __pyx_mstate_global->__pyx_n_s_points +#define __pyx_n_s_prev_point __pyx_mstate_global->__pyx_n_s_prev_point +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_radius __pyx_mstate_global->__pyx_n_s_radius +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_res __pyx_mstate_global->__pyx_n_s_res +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_reverse __pyx_mstate_global->__pyx_n_s_reverse +#define __pyx_n_s_s __pyx_mstate_global->__pyx_n_s_s +#define __pyx_n_s_segment __pyx_mstate_global->__pyx_n_s_segment +#define __pyx_n_s_segment_angle __pyx_mstate_global->__pyx_n_s_segment_angle +#define __pyx_n_s_segments __pyx_mstate_global->__pyx_n_s_segments +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_send __pyx_mstate_global->__pyx_n_s_send +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec +#define __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_bezier4p_pyx +#define __pyx_n_s_start_angle __pyx_mstate_global->__pyx_n_s_start_angle +#define __pyx_n_s_start_flag __pyx_mstate_global->__pyx_n_s_start_flag +#define __pyx_n_s_start_param __pyx_mstate_global->__pyx_n_s_start_param +#define __pyx_n_s_start_point __pyx_mstate_global->__pyx_n_s_start_point +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_t __pyx_mstate_global->__pyx_n_s_t +#define __pyx_n_s_t0 __pyx_mstate_global->__pyx_n_s_t0 +#define __pyx_n_s_t1 __pyx_mstate_global->__pyx_n_s_t1 +#define __pyx_kp_u_t_not_in_range_0_to_1 __pyx_mstate_global->__pyx_kp_u_t_not_in_range_0_to_1 +#define __pyx_n_s_tangent __pyx_mstate_global->__pyx_n_s_tangent +#define __pyx_n_s_tangent_length __pyx_mstate_global->__pyx_n_s_tangent_length +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_throw __pyx_mstate_global->__pyx_n_s_throw +#define __pyx_n_s_tmp __pyx_mstate_global->__pyx_n_s_tmp +#define __pyx_n_s_transform __pyx_mstate_global->__pyx_n_s_transform +#define __pyx_n_s_transform_vertices __pyx_mstate_global->__pyx_n_s_transform_vertices +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_warn __pyx_mstate_global->__pyx_n_s_warn +#define __pyx_n_s_warnings __pyx_mstate_global->__pyx_n_s_warnings +#define __pyx_n_s_x_axis __pyx_mstate_global->__pyx_n_s_x_axis +#define __pyx_n_s_y_axis __pyx_mstate_global->__pyx_n_s_y_axis +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_4 __pyx_mstate_global->__pyx_int_4 +#define __pyx_int_128 __pyx_mstate_global->__pyx_int_128 +#define __pyx_k__5 __pyx_mstate_global->__pyx_k__5 +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__2 __pyx_mstate_global->__pyx_tuple__2 +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7 +#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8 +#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__16 __pyx_mstate_global->__pyx_tuple__16 +#define __pyx_tuple__19 __pyx_mstate_global->__pyx_tuple__19 +#define __pyx_tuple__21 __pyx_mstate_global->__pyx_tuple__21 +#define __pyx_tuple__23 __pyx_mstate_global->__pyx_tuple__23 +#define __pyx_tuple__24 __pyx_mstate_global->__pyx_tuple__24 +#define __pyx_tuple__27 __pyx_mstate_global->__pyx_tuple__27 +#define __pyx_tuple__30 __pyx_mstate_global->__pyx_tuple__30 +#define __pyx_tuple__33 __pyx_mstate_global->__pyx_tuple__33 +#define __pyx_tuple__34 __pyx_mstate_global->__pyx_tuple__34 +#define __pyx_tuple__35 __pyx_mstate_global->__pyx_tuple__35 +#define __pyx_codeobj__6 __pyx_mstate_global->__pyx_codeobj__6 +#define __pyx_codeobj__10 __pyx_mstate_global->__pyx_codeobj__10 +#define __pyx_codeobj__11 __pyx_mstate_global->__pyx_codeobj__11 +#define __pyx_codeobj__15 __pyx_mstate_global->__pyx_codeobj__15 +#define __pyx_codeobj__17 __pyx_mstate_global->__pyx_codeobj__17 +#define __pyx_codeobj__18 __pyx_mstate_global->__pyx_codeobj__18 +#define __pyx_codeobj__20 __pyx_mstate_global->__pyx_codeobj__20 +#define __pyx_codeobj__22 __pyx_mstate_global->__pyx_codeobj__22 +#define __pyx_codeobj__25 __pyx_mstate_global->__pyx_codeobj__25 +#define __pyx_codeobj__26 __pyx_mstate_global->__pyx_codeobj__26 +#define __pyx_codeobj__28 __pyx_mstate_global->__pyx_codeobj__28 +#define __pyx_codeobj__29 __pyx_mstate_global->__pyx_codeobj__29 +#define __pyx_codeobj__31 __pyx_mstate_global->__pyx_codeobj__31 +#define __pyx_codeobj__36 __pyx_mstate_global->__pyx_codeobj__36 +#define __pyx_codeobj__37 __pyx_mstate_global->__pyx_codeobj__37 +/* #### Code section: module_code ### */ + +/* "matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + +static CYTHON_INLINE PyObject *__pyx_f_5ezdxf_3acc_8matrix44_swap(double *__pyx_v_a, double *__pyx_v_b) { + double __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("swap", 1); + + /* "matrix44.pxd":13 + * + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] # <<<<<<<<<<<<<< + * a[0] = b[0] + * b[0] = tmp + */ + __pyx_v_tmp = (__pyx_v_a[0]); + + /* "matrix44.pxd":14 + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] + * a[0] = b[0] # <<<<<<<<<<<<<< + * b[0] = tmp + */ + (__pyx_v_a[0]) = (__pyx_v_b[0]); + + /* "matrix44.pxd":15 + * cdef double tmp = a[0] + * a[0] = b[0] + * b[0] = tmp # <<<<<<<<<<<<<< + */ + (__pyx_v_b[0]) = __pyx_v_tmp; + + /* "matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":48 + * readonly Vec3 end_point + * + * def __cinit__(self, defpoints: Sequence[UVec]): # <<<<<<<<<<<<<< + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_defpoints = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_defpoints,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_defpoints)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 48, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 48, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + } + __pyx_v_defpoints = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 48, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_defpoints); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, PyObject *__pyx_v_defpoints) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + Py_ssize_t __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/bezier4p.pyx":49 + * + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): # <<<<<<<<<<<<<< + * warnings.warn( + * DeprecationWarning, + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_TypeCheck(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (!__pyx_t_3) { + } else { + __pyx_t_2 = __pyx_t_3; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __Pyx_TypeCheck(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = __pyx_t_3; + __pyx_L4_bool_binop_done:; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + + /* "ezdxf/acc/bezier4p.pyx":50 + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( # <<<<<<<<<<<<<< + * DeprecationWarning, + * "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_warnings); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_warn); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":51 + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + * DeprecationWarning, # <<<<<<<<<<<<<< + * "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + * ) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":49 + * + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): # <<<<<<<<<<<<<< + * warnings.warn( + * DeprecationWarning, + */ + } + + /* "ezdxf/acc/bezier4p.pyx":54 + * "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + * ) + * if len(defpoints) == 4: # <<<<<<<<<<<<<< + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + */ + __pyx_t_5 = PyObject_Length(__pyx_v_defpoints); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(0, 54, __pyx_L1_error) + __pyx_t_3 = (__pyx_t_5 == 4); + if (likely(__pyx_t_3)) { + + /* "ezdxf/acc/bezier4p.pyx":55 + * ) + * if len(defpoints) == 4: + * self.start_point = Vec3(defpoints[0]) # <<<<<<<<<<<<<< + * self.cp1 = Vec3(defpoints[1]) + * self.cp2 = Vec3(defpoints[2]) + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF((PyObject *)__pyx_v_self->start_point); + __Pyx_DECREF((PyObject *)__pyx_v_self->start_point); + __pyx_v_self->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bezier4p.pyx":56 + * if len(defpoints) == 4: + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) # <<<<<<<<<<<<<< + * self.cp2 = Vec3(defpoints[2]) + * self.end_point = Vec3(defpoints[3]) + */ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_defpoints, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->cp1); + __Pyx_DECREF((PyObject *)__pyx_v_self->cp1); + __pyx_v_self->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":57 + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + * self.cp2 = Vec3(defpoints[2]) # <<<<<<<<<<<<<< + * self.end_point = Vec3(defpoints[3]) + * + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_defpoints, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF((PyObject *)__pyx_v_self->cp2); + __Pyx_DECREF((PyObject *)__pyx_v_self->cp2); + __pyx_v_self->cp2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bezier4p.pyx":58 + * self.cp1 = Vec3(defpoints[1]) + * self.cp2 = Vec3(defpoints[2]) + * self.end_point = Vec3(defpoints[3]) # <<<<<<<<<<<<<< + * + * self.curve = FastCubicCurve( + */ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_defpoints, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->end_point); + __Pyx_DECREF((PyObject *)__pyx_v_self->end_point); + __pyx_v_self->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":60 + * self.end_point = Vec3(defpoints[3]) + * + * self.curve = FastCubicCurve( # <<<<<<<<<<<<<< + * self.start_point, + * self.cp1, + */ + __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 60, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 60, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp2); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_v_self->cp2))) __PYX_ERR(0, 60, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 3, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 60, __pyx_L1_error); + __pyx_t_4 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve), __pyx_t_1, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF((PyObject *)__pyx_v_self->curve); + __Pyx_DECREF((PyObject *)__pyx_v_self->curve); + __pyx_v_self->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bezier4p.pyx":54 + * "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + * ) + * if len(defpoints) == 4: # <<<<<<<<<<<<<< + * self.start_point = Vec3(defpoints[0]) + * self.cp1 = Vec3(defpoints[1]) + */ + goto __pyx_L6; + } + + /* "ezdxf/acc/bezier4p.pyx":67 + * ) + * else: + * raise ValueError("Four control points required.") # <<<<<<<<<<<<<< + * + * @property + */ + /*else*/ { + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 67, __pyx_L1_error) + } + __pyx_L6:; + + /* "ezdxf/acc/bezier4p.pyx":48 + * readonly Vec3 end_point + * + * def __cinit__(self, defpoints: Sequence[UVec]): # <<<<<<<<<<<<<< + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":69 + * raise ValueError("Four control points required.") + * + * @property # <<<<<<<<<<<<<< + * def control_points(self) -> tuple[Vec3, Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.cp2, self.end_point + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bezier4p.pyx":71 + * @property + * def control_points(self) -> tuple[Vec3, Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.cp2, self.end_point # <<<<<<<<<<<<<< + * + * def __reduce__(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 71, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 71, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp2); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_v_self->cp2))) __PYX_ERR(0, 71, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 3, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 71, __pyx_L1_error); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":69 + * raise ValueError("Four control points required.") + * + * @property # <<<<<<<<<<<<<< + * def control_points(self) -> tuple[Vec3, Vec3, Vec3, Vec3]: + * return self.start_point, self.cp1, self.cp2, self.end_point + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.control_points.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":73 + * return self.start_point, self.cp1, self.cp2, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier4P, (self.control_points,) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__ = {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_2__reduce__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce__", 1); + + /* "ezdxf/acc/bezier4p.pyx":74 + * + * def __reduce__(self): + * return Bezier4P, (self.control_points,) # <<<<<<<<<<<<<< + * + * def point(self, double t) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_control_points); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P))) __PYX_ERR(0, 74, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_2)) __PYX_ERR(0, 74, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":73 + * return self.start_point, self.cp1, self.cp2, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier4P, (self.control_points,) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":76 + * return Bezier4P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_5point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_5point = {"point", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_5point, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_5point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_t; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("point (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 76, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "point") < 0)) __PYX_ERR(0, 76, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_t == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 76, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("point", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 76, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_4point(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_4point(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + + /* "ezdxf/acc/bezier4p.pyx":77 + * + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.point(t) + * else: + */ + __pyx_t_1 = (0.0 <= __pyx_v_t); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_t <= 1.0); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier4p.pyx":78 + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) # <<<<<<<<<<<<<< + * else: + * raise ValueError("t not in range [0 to 1]") + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":77 + * + * def point(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.point(t) + * else: + */ + } + + /* "ezdxf/acc/bezier4p.pyx":80 + * return self.curve.point(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def tangent(self, double t) -> Vec3: + */ + /*else*/ { + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 80, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 80, __pyx_L1_error) + } + + /* "ezdxf/acc/bezier4p.pyx":76 + * return Bezier4P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":82 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent = {"tangent", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_t; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("tangent (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 82, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "tangent") < 0)) __PYX_ERR(0, 82, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_t == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 82, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("tangent", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 82, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_6tangent(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_6tangent(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tangent", 1); + + /* "ezdxf/acc/bezier4p.pyx":83 + * + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.tangent(t) + * else: + */ + __pyx_t_1 = (0.0 <= __pyx_v_t); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_t <= 1.0); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier4p.pyx":84 + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) # <<<<<<<<<<<<<< + * else: + * raise ValueError("t not in range [0 to 1]") + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self->curve->__pyx_vtab)->tangent(__pyx_v_self->curve, __pyx_v_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 84, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":83 + * + * def tangent(self, double t) -> Vec3: + * if 0.0 <= t <= 1.0: # <<<<<<<<<<<<<< + * return self.curve.tangent(t) + * else: + */ + } + + /* "ezdxf/acc/bezier4p.pyx":86 + * return self.curve.tangent(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def approximate(self, int segments) -> list[Vec3]: + */ + /*else*/ { + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 86, __pyx_L1_error) + } + + /* "ezdxf/acc/bezier4p.pyx":82 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":88 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate = {"approximate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("approximate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 88, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "approximate") < 0)) __PYX_ERR(0, 88, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_segments = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 88, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("approximate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 88, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.approximate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_8approximate(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_8approximate(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, int __pyx_v_segments) { + double __pyx_v_delta_t; + int __pyx_v_segment; + PyObject *__pyx_v_points = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("approximate", 1); + + /* "ezdxf/acc/bezier4p.pyx":91 + * cdef double delta_t + * cdef int segment + * cdef list points = [self.start_point] # <<<<<<<<<<<<<< + * + * if segments < 1: + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 91, __pyx_L1_error); + __pyx_v_points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":93 + * cdef list points = [self.start_point] + * + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError(segments) + * delta_t = 1.0 / segments + */ + __pyx_t_2 = (__pyx_v_segments < 1); + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/bezier4p.pyx":94 + * + * if segments < 1: + * raise ValueError(segments) # <<<<<<<<<<<<<< + * delta_t = 1.0 / segments + * for segment in range(1, segments): + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_segments); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 94, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":93 + * cdef list points = [self.start_point] + * + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError(segments) + * delta_t = 1.0 / segments + */ + } + + /* "ezdxf/acc/bezier4p.pyx":95 + * if segments < 1: + * raise ValueError(segments) + * delta_t = 1.0 / segments # <<<<<<<<<<<<<< + * for segment in range(1, segments): + * points.append(self.curve.point(delta_t * segment)) + */ + if (unlikely(__pyx_v_segments == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 95, __pyx_L1_error) + } + __pyx_v_delta_t = (1.0 / ((double)__pyx_v_segments)); + + /* "ezdxf/acc/bezier4p.pyx":96 + * raise ValueError(segments) + * delta_t = 1.0 / segments + * for segment in range(1, segments): # <<<<<<<<<<<<<< + * points.append(self.curve.point(delta_t * segment)) + * points.append(self.end_point) + */ + __pyx_t_4 = __pyx_v_segments; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = 1; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_segment = __pyx_t_6; + + /* "ezdxf/acc/bezier4p.pyx":97 + * delta_t = 1.0 / segments + * for segment in range(1, segments): + * points.append(self.curve.point(delta_t * segment)) # <<<<<<<<<<<<<< + * points.append(self.end_point) + * return points + */ + __pyx_t_3 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, (__pyx_v_delta_t * __pyx_v_segment))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 97, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyList_Append(__pyx_v_points, __pyx_t_3); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 97, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + + /* "ezdxf/acc/bezier4p.pyx":98 + * for segment in range(1, segments): + * points.append(self.curve.point(delta_t * segment)) + * points.append(self.end_point) # <<<<<<<<<<<<<< + * return points + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_self->end_point); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyList_Append(__pyx_v_points, __pyx_t_3); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 98, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier4p.pyx":99 + * points.append(self.curve.point(delta_t * segment)) + * points.append(self.end_point) + * return points # <<<<<<<<<<<<<< + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_points); + __pyx_r = __pyx_v_points; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":88 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.approximate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_points); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":101 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening = {"flattening", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_distance; + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("flattening (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_distance,&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_distance)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "flattening") < 0)) __PYX_ERR(0, 101, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_distance = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L3_error) + if (values[1]) { + __pyx_v_segments = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L3_error) + } else { + __pyx_v_segments = ((int)4); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("flattening", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 101, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.flattening", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_10flattening(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_distance, __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_10flattening(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, double __pyx_v_distance, int __pyx_v_segments) { + double __pyx_v_dt; + double __pyx_v_t0; + double __pyx_v_t1; + struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_f = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("flattening", 1); + + /* "ezdxf/acc/bezier4p.pyx":102 + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + * cdef double dt = 1.0 / segments # <<<<<<<<<<<<<< + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) + */ + if (unlikely(__pyx_v_segments == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 102, __pyx_L1_error) + } + __pyx_v_dt = (1.0 / ((double)__pyx_v_segments)); + + /* "ezdxf/acc/bezier4p.pyx":103 + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 # <<<<<<<<<<<<<< + * cdef _Flattening f = _Flattening(self, distance) + * cdef Vec3 start_point = self.start_point + */ + __pyx_v_t0 = 0.0; + + /* "ezdxf/acc/bezier4p.pyx":104 + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) # <<<<<<<<<<<<<< + * cdef Vec3 start_point = self.start_point + * cdef Vec3 end_point + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_distance); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_v_self))) __PYX_ERR(0, 104, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening), __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_f = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":105 + * cdef double t0 = 0.0, t1 + * cdef _Flattening f = _Flattening(self, distance) + * cdef Vec3 start_point = self.start_point # <<<<<<<<<<<<<< + * cdef Vec3 end_point + * while t0 < 1.0: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->start_point); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":107 + * cdef Vec3 start_point = self.start_point + * cdef Vec3 end_point + * while t0 < 1.0: # <<<<<<<<<<<<<< + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + */ + while (1) { + __pyx_t_3 = (__pyx_v_t0 < 1.0); + if (!__pyx_t_3) break; + + /* "ezdxf/acc/bezier4p.pyx":108 + * cdef Vec3 end_point + * while t0 < 1.0: + * t1 = t0 + dt # <<<<<<<<<<<<<< + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point + */ + __pyx_v_t1 = (__pyx_v_t0 + __pyx_v_dt); + + /* "ezdxf/acc/bezier4p.pyx":109 + * while t0 < 1.0: + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * end_point = self.end_point + * t1 = 1.0 + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_t1, 1.0, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 109, __pyx_L1_error) + if (__pyx_t_3) { + + /* "ezdxf/acc/bezier4p.pyx":110 + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point # <<<<<<<<<<<<<< + * t1 = 1.0 + * else: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->end_point); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_end_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":111 + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): + * end_point = self.end_point + * t1 = 1.0 # <<<<<<<<<<<<<< + * else: + * end_point = self.curve.point(t1) + */ + __pyx_v_t1 = 1.0; + + /* "ezdxf/acc/bezier4p.pyx":109 + * while t0 < 1.0: + * t1 = t0 + dt + * if isclose(t1, 1.0, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * end_point = self.end_point + * t1 = 1.0 + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bezier4p.pyx":113 + * t1 = 1.0 + * else: + * end_point = self.curve.point(t1) # <<<<<<<<<<<<<< + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + */ + /*else*/ { + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_t1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_end_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + } + __pyx_L5:; + + /* "ezdxf/acc/bezier4p.pyx":114 + * else: + * end_point = self.curve.point(t1) + * f.reset_recursion_check() # <<<<<<<<<<<<<< + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_f->__pyx_vtab)->reset_recursion_check(__pyx_v_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":115 + * end_point = self.curve.point(t1) + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) # <<<<<<<<<<<<<< + * if f.has_recursion_error(): + * raise RecursionError( + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_f->__pyx_vtab)->flatten(__pyx_v_f, __pyx_v_start_point, __pyx_v_end_point, __pyx_v_t0, __pyx_v_t1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 115, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":116 + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): # <<<<<<<<<<<<<< + * raise RecursionError( + * "Bezier4P flattening error, check for very large coordinates" + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_f->__pyx_vtab)->has_recursion_error(__pyx_v_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "ezdxf/acc/bezier4p.pyx":117 + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + * raise RecursionError( # <<<<<<<<<<<<<< + * "Bezier4P flattening error, check for very large coordinates" + * ) + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RecursionError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 117, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":116 + * f.reset_recursion_check() + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): # <<<<<<<<<<<<<< + * raise RecursionError( + * "Bezier4P flattening error, check for very large coordinates" + */ + } + + /* "ezdxf/acc/bezier4p.pyx":120 + * "Bezier4P flattening error, check for very large coordinates" + * ) + * t0 = t1 # <<<<<<<<<<<<<< + * start_point = end_point + * + */ + __pyx_v_t0 = __pyx_v_t1; + + /* "ezdxf/acc/bezier4p.pyx":121 + * ) + * t0 = t1 + * start_point = end_point # <<<<<<<<<<<<<< + * + * return f.points + */ + __Pyx_INCREF((PyObject *)__pyx_v_end_point); + __Pyx_DECREF_SET(__pyx_v_start_point, __pyx_v_end_point); + } + + /* "ezdxf/acc/bezier4p.pyx":123 + * start_point = end_point + * + * return f.points # <<<<<<<<<<<<<< + * + * def approximated_length(self, segments: int = 128) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_f->points); + __pyx_r = __pyx_v_f->points; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":101 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.flattening", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_f); + __Pyx_XDECREF((PyObject *)__pyx_v_start_point); + __Pyx_XDECREF((PyObject *)__pyx_v_end_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":125 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length = {"approximated_length", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_segments = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("approximated_length (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_segments,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__5); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 125, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "approximated_length") < 0)) __PYX_ERR(0, 125, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_segments = ((PyObject*)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("approximated_length", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 125, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.approximated_length", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_segments), (&PyInt_Type), 0, "segments", 1))) __PYX_ERR(0, 125, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_12approximated_length(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_segments); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_12approximated_length(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, PyObject *__pyx_v_segments) { + double __pyx_v_length; + int __pyx_v_start_flag; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_prev_point = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_point = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + Py_ssize_t __pyx_t_5; + PyObject *(*__pyx_t_6)(PyObject *); + double __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("approximated_length", 1); + + /* "ezdxf/acc/bezier4p.pyx":126 + * + * def approximated_length(self, segments: int = 128) -> float: + * cdef double length = 0.0 # <<<<<<<<<<<<<< + * cdef bint start_flag = 0 + * cdef Vec3 prev_point, point + */ + __pyx_v_length = 0.0; + + /* "ezdxf/acc/bezier4p.pyx":127 + * def approximated_length(self, segments: int = 128) -> float: + * cdef double length = 0.0 + * cdef bint start_flag = 0 # <<<<<<<<<<<<<< + * cdef Vec3 prev_point, point + * + */ + __pyx_v_start_flag = 0; + + /* "ezdxf/acc/bezier4p.pyx":130 + * cdef Vec3 prev_point, point + * + * for point in self.approximate(segments): # <<<<<<<<<<<<<< + * if start_flag: + * length += v3_dist(prev_point, point) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_approximate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_segments}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { + __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); + __pyx_t_5 = 0; + __pyx_t_6 = NULL; + } else { + __pyx_t_5 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 130, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + for (;;) { + if (likely(!__pyx_t_6)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 130, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 130, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 130, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 130, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } + } else { + __pyx_t_1 = __pyx_t_6(__pyx_t_2); + if (unlikely(!__pyx_t_1)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 130, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_1); + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":131 + * + * for point in self.approximate(segments): + * if start_flag: # <<<<<<<<<<<<<< + * length += v3_dist(prev_point, point) + * else: + */ + if (__pyx_v_start_flag) { + + /* "ezdxf/acc/bezier4p.pyx":132 + * for point in self.approximate(segments): + * if start_flag: + * length += v3_dist(prev_point, point) # <<<<<<<<<<<<<< + * else: + * start_flag = 1 + */ + if (unlikely(!__pyx_v_prev_point)) { __Pyx_RaiseUnboundLocalError("prev_point"); __PYX_ERR(0, 132, __pyx_L1_error) } + __pyx_t_7 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_prev_point, __pyx_v_point); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 132, __pyx_L1_error) + __pyx_v_length = (__pyx_v_length + __pyx_t_7); + + /* "ezdxf/acc/bezier4p.pyx":131 + * + * for point in self.approximate(segments): + * if start_flag: # <<<<<<<<<<<<<< + * length += v3_dist(prev_point, point) + * else: + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bezier4p.pyx":134 + * length += v3_dist(prev_point, point) + * else: + * start_flag = 1 # <<<<<<<<<<<<<< + * prev_point = point + * return length + */ + /*else*/ { + __pyx_v_start_flag = 1; + } + __pyx_L5:; + + /* "ezdxf/acc/bezier4p.pyx":135 + * else: + * start_flag = 1 + * prev_point = point # <<<<<<<<<<<<<< + * return length + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_point); + __Pyx_XDECREF_SET(__pyx_v_prev_point, __pyx_v_point); + + /* "ezdxf/acc/bezier4p.pyx":130 + * cdef Vec3 prev_point, point + * + * for point in self.approximate(segments): # <<<<<<<<<<<<<< + * if start_flag: + * length += v3_dist(prev_point, point) + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":136 + * start_flag = 1 + * prev_point = point + * return length # <<<<<<<<<<<<<< + * + * def reverse(self) -> Bezier4P: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_length); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":125 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.approximated_length", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_prev_point); + __Pyx_XDECREF((PyObject *)__pyx_v_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":138 + * return length + * + * def reverse(self) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse = {"reverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("reverse (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("reverse", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "reverse", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14reverse(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_14reverse(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("reverse", 1); + + /* "ezdxf/acc/bezier4p.pyx":139 + * + * def reverse(self) -> Bezier4P: + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) # <<<<<<<<<<<<<< + * + * def transform(self, Matrix44 m) -> Bezier4P: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self->end_point))) __PYX_ERR(0, 139, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp2); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_self->cp2))) __PYX_ERR(0, 139, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->cp1); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, ((PyObject *)__pyx_v_self->cp1))) __PYX_ERR(0, 139, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_self->start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 3, ((PyObject *)__pyx_v_self->start_point))) __PYX_ERR(0, 139, __pyx_L1_error); + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":138 + * return length + * + * def reverse(self) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.reverse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":141 + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P(tuple(m.transform_vertices(self.control_points))) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform = {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_m,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 141, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform") < 0)) __PYX_ERR(0, 141, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_m = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 141, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, 1, "m", 0))) __PYX_ERR(0, 141, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_16transform(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self), __pyx_v_m); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_16transform(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform", 1); + + /* "ezdxf/acc/bezier4p.pyx":142 + * + * def transform(self, Matrix44 m) -> Bezier4P: + * return Bezier4P(tuple(m.transform_vertices(self.control_points))) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_m), __pyx_n_s_transform_vertices); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_control_points); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P), __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":141 + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P(tuple(m.transform_vertices(self.control_points))) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.Bezier4P.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":43 + * cdef: + * FastCubicCurve curve # pyright: ignore + * readonly Vec3 start_point # <<<<<<<<<<<<<< + * Vec3 cp1 + * Vec3 cp2 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self->start_point); + __pyx_r = ((PyObject *)__pyx_v_self->start_point); + goto __pyx_L0; + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":46 + * Vec3 cp1 + * Vec3 cp2 + * readonly Vec3 end_point # <<<<<<<<<<<<<< + * + * def __cinit__(self, defpoints: Sequence[UVec]): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point___get__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point___get__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self->end_point); + __pyx_r = ((PyObject *)__pyx_v_self->end_point); + goto __pyx_L0; + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":152 + * cdef int _recursion_error + * + * def __cinit__(self, Bezier4P curve, double distance): # <<<<<<<<<<<<<< + * self.curve = curve.curve + * self.distance = distance + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_curve = 0; + double __pyx_v_distance; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_curve,&__pyx_n_s_distance,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_curve)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 152, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_distance)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 152, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, 1); __PYX_ERR(0, 152, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 152, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + } + __pyx_v_curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)values[0]); + __pyx_v_distance = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 152, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 152, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_curve), __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, 1, "curve", 0))) __PYX_ERR(0, 152, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_self), __pyx_v_curve, __pyx_v_distance); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *__pyx_v_curve, double __pyx_v_distance) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/bezier4p.pyx":153 + * + * def __cinit__(self, Bezier4P curve, double distance): + * self.curve = curve.curve # <<<<<<<<<<<<<< + * self.distance = distance + * self.points = [curve.start_point] + */ + __pyx_t_1 = ((PyObject *)__pyx_v_curve->curve); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_self->curve); + __Pyx_DECREF((PyObject *)__pyx_v_self->curve); + __pyx_v_self->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":154 + * def __cinit__(self, Bezier4P curve, double distance): + * self.curve = curve.curve + * self.distance = distance # <<<<<<<<<<<<<< + * self.points = [curve.start_point] + * self._recursion_level = 0 + */ + __pyx_v_self->distance = __pyx_v_distance; + + /* "ezdxf/acc/bezier4p.pyx":155 + * self.curve = curve.curve + * self.distance = distance + * self.points = [curve.start_point] # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_curve->start_point); + __Pyx_GIVEREF((PyObject *)__pyx_v_curve->start_point); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_curve->start_point))) __PYX_ERR(0, 155, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v_self->points); + __Pyx_DECREF(__pyx_v_self->points); + __pyx_v_self->points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":156 + * self.distance = distance + * self.points = [curve.start_point] + * self._recursion_level = 0 # <<<<<<<<<<<<<< + * self._recursion_error = 0 + * + */ + __pyx_v_self->_recursion_level = 0; + + /* "ezdxf/acc/bezier4p.pyx":157 + * self.points = [curve.start_point] + * self._recursion_level = 0 + * self._recursion_error = 0 # <<<<<<<<<<<<<< + * + * cdef has_recursion_error(self): + */ + __pyx_v_self->_recursion_error = 0; + + /* "ezdxf/acc/bezier4p.pyx":152 + * cdef int _recursion_error + * + * def __cinit__(self, Bezier4P curve, double distance): # <<<<<<<<<<<<<< + * self.curve = curve.curve + * self.distance = distance + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":159 + * self._recursion_error = 0 + * + * cdef has_recursion_error(self): # <<<<<<<<<<<<<< + * return self._recursion_error + * + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_has_recursion_error(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("has_recursion_error", 1); + + /* "ezdxf/acc/bezier4p.pyx":160 + * + * cdef has_recursion_error(self): + * return self._recursion_error # <<<<<<<<<<<<<< + * + * cdef reset_recursion_check(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->_recursion_error); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":159 + * self._recursion_error = 0 + * + * cdef has_recursion_error(self): # <<<<<<<<<<<<<< + * return self._recursion_error + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.has_recursion_error", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":162 + * return self._recursion_error + * + * cdef reset_recursion_check(self): # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_reset_recursion_check(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("reset_recursion_check", 1); + + /* "ezdxf/acc/bezier4p.pyx":163 + * + * cdef reset_recursion_check(self): + * self._recursion_level = 0 # <<<<<<<<<<<<<< + * self._recursion_error = 0 + * + */ + __pyx_v_self->_recursion_level = 0; + + /* "ezdxf/acc/bezier4p.pyx":164 + * cdef reset_recursion_check(self): + * self._recursion_level = 0 + * self._recursion_error = 0 # <<<<<<<<<<<<<< + * + * cdef flatten( + */ + __pyx_v_self->_recursion_error = 0; + + /* "ezdxf/acc/bezier4p.pyx":162 + * return self._recursion_error + * + * cdef reset_recursion_check(self): # <<<<<<<<<<<<<< + * self._recursion_level = 0 + * self._recursion_error = 0 + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":166 + * self._recursion_error = 0 + * + * cdef flatten( # <<<<<<<<<<<<<< + * self, + * Vec3 start_point, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_flatten(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_start_point, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_end_point, double __pyx_v_start_t, double __pyx_v_end_t) { + double __pyx_v_mid_t; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_mid_point = 0; + double __pyx_v_d; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("flatten", 1); + + /* "ezdxf/acc/bezier4p.pyx":175 + * # Keep in sync with CPython implementation: ezdxf/math/_bezier4p.py + * # Test suite: 630a + * if self._recursion_level > RECURSION_LIMIT: # <<<<<<<<<<<<<< + * self._recursion_error = 1 + * return + */ + __pyx_t_1 = (__pyx_v_self->_recursion_level > __pyx_v_5ezdxf_3acc_8bezier4p_RECURSION_LIMIT); + if (__pyx_t_1) { + + /* "ezdxf/acc/bezier4p.pyx":176 + * # Test suite: 630a + * if self._recursion_level > RECURSION_LIMIT: + * self._recursion_error = 1 # <<<<<<<<<<<<<< + * return + * self._recursion_level += 1 + */ + __pyx_v_self->_recursion_error = 1; + + /* "ezdxf/acc/bezier4p.pyx":177 + * if self._recursion_level > RECURSION_LIMIT: + * self._recursion_error = 1 + * return # <<<<<<<<<<<<<< + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":175 + * # Keep in sync with CPython implementation: ezdxf/math/_bezier4p.py + * # Test suite: 630a + * if self._recursion_level > RECURSION_LIMIT: # <<<<<<<<<<<<<< + * self._recursion_error = 1 + * return + */ + } + + /* "ezdxf/acc/bezier4p.pyx":178 + * self._recursion_error = 1 + * return + * self._recursion_level += 1 # <<<<<<<<<<<<<< + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) + */ + __pyx_v_self->_recursion_level = (__pyx_v_self->_recursion_level + 1); + + /* "ezdxf/acc/bezier4p.pyx":179 + * return + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 # <<<<<<<<<<<<<< + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + */ + __pyx_v_mid_t = ((__pyx_v_start_t + __pyx_v_end_t) * 0.5); + + /* "ezdxf/acc/bezier4p.pyx":180 + * self._recursion_level += 1 + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) # <<<<<<<<<<<<<< + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: + */ + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self->curve->__pyx_vtab)->point(__pyx_v_self->curve, __pyx_v_mid_t)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_mid_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":181 + * cdef double mid_t = (start_t + end_t) * 0.5 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) # <<<<<<<<<<<<<< + * if d < self.distance: + * self.points.append(end_point) + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_lerp(__pyx_v_start_point, __pyx_v_end_point, 0.5)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_mid_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_d = __pyx_t_3; + + /* "ezdxf/acc/bezier4p.pyx":182 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: # <<<<<<<<<<<<<< + * self.points.append(end_point) + * else: + */ + __pyx_t_1 = (__pyx_v_d < __pyx_v_self->distance); + if (__pyx_t_1) { + + /* "ezdxf/acc/bezier4p.pyx":183 + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: + * self.points.append(end_point) # <<<<<<<<<<<<<< + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) + */ + if (unlikely(__pyx_v_self->points == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append"); + __PYX_ERR(0, 183, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_Append(__pyx_v_self->points, ((PyObject *)__pyx_v_end_point)); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(0, 183, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":182 + * cdef Vec3 mid_point = self.curve.point(mid_t) + * cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + * if d < self.distance: # <<<<<<<<<<<<<< + * self.points.append(end_point) + * else: + */ + goto __pyx_L4; + } + + /* "ezdxf/acc/bezier4p.pyx":185 + * self.points.append(end_point) + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) # <<<<<<<<<<<<<< + * self.flatten(mid_point, end_point, mid_t, end_t) + * self._recursion_level -= 1 + */ + /*else*/ { + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_self->__pyx_vtab)->flatten(__pyx_v_self, __pyx_v_start_point, __pyx_v_mid_point, __pyx_v_start_t, __pyx_v_mid_t); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":186 + * else: + * self.flatten(start_point, mid_point, start_t, mid_t) + * self.flatten(mid_point, end_point, mid_t, end_t) # <<<<<<<<<<<<<< + * self._recursion_level -= 1 + * + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_self->__pyx_vtab)->flatten(__pyx_v_self, __pyx_v_mid_point, __pyx_v_end_point, __pyx_v_mid_t, __pyx_v_end_t); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_L4:; + + /* "ezdxf/acc/bezier4p.pyx":187 + * self.flatten(start_point, mid_point, start_t, mid_t) + * self.flatten(mid_point, end_point, mid_t, end_t) + * self._recursion_level -= 1 # <<<<<<<<<<<<<< + * + * cdef double DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 + */ + __pyx_v_self->_recursion_level = (__pyx_v_self->_recursion_level - 1); + + /* "ezdxf/acc/bezier4p.pyx":166 + * self._recursion_error = 0 + * + * cdef flatten( # <<<<<<<<<<<<<< + * self, + * Vec3 start_point, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.flatten", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mid_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_2__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_4__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_11_Flattening_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p._Flattening.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_2generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bezier4p.pyx":193 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + * @cython.cdivision(True) # <<<<<<<<<<<<<< + * def cubic_bezier_arc_parameters( + * double start_angle, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_1cubic_bezier_arc_parameters(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_1cubic_bezier_arc_parameters = {"cubic_bezier_arc_parameters", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_1cubic_bezier_arc_parameters, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_1cubic_bezier_arc_parameters(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_start_angle; + double __pyx_v_end_angle; + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_arc_parameters (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_start_angle,&__pyx_n_s_end_angle,&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_start_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 193, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_end_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 193, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("cubic_bezier_arc_parameters", 0, 2, 3, 1); __PYX_ERR(0, 193, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 193, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "cubic_bezier_arc_parameters") < 0)) __PYX_ERR(0, 193, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_start_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_start_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error) + __pyx_v_end_angle = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_end_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 196, __pyx_L3_error) + if (values[2]) { + __pyx_v_segments = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 197, __pyx_L3_error) + } else { + __pyx_v_segments = ((int)((int)1)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("cubic_bezier_arc_parameters", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 193, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_arc_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_cubic_bezier_arc_parameters(__pyx_self, __pyx_v_start_angle, __pyx_v_end_angle, __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_cubic_bezier_arc_parameters(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start_angle, double __pyx_v_end_angle, int __pyx_v_segments) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cubic_bezier_arc_parameters", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 193, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_start_angle = __pyx_v_start_angle; + __pyx_cur_scope->__pyx_v_end_angle = __pyx_v_end_angle; + __pyx_cur_scope->__pyx_v_segments = __pyx_v_segments; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8bezier4p_2generator, __pyx_codeobj__6, (PyObject *) __pyx_cur_scope, __pyx_n_s_cubic_bezier_arc_parameters, __pyx_n_s_cubic_bezier_arc_parameters, __pyx_n_s_ezdxf_acc_bezier4p); if (unlikely(!gen)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_arc_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_2generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_arc_parameters", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L9_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 193, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":199 + * int segments = 1, + * ) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError('Invalid argument segments (>= 1).') + * cdef double delta_angle = end_angle - start_angle + */ + __pyx_t_1 = (__pyx_cur_scope->__pyx_v_segments < 1); + if (unlikely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier4p.pyx":200 + * ) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + * if segments < 1: + * raise ValueError('Invalid argument segments (>= 1).') # <<<<<<<<<<<<<< + * cdef double delta_angle = end_angle - start_angle + * cdef int arc_count + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 200, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":199 + * int segments = 1, + * ) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + * if segments < 1: # <<<<<<<<<<<<<< + * raise ValueError('Invalid argument segments (>= 1).') + * cdef double delta_angle = end_angle - start_angle + */ + } + + /* "ezdxf/acc/bezier4p.pyx":201 + * if segments < 1: + * raise ValueError('Invalid argument segments (>= 1).') + * cdef double delta_angle = end_angle - start_angle # <<<<<<<<<<<<<< + * cdef int arc_count + * if delta_angle > 0: + */ + __pyx_cur_scope->__pyx_v_delta_angle = (__pyx_cur_scope->__pyx_v_end_angle - __pyx_cur_scope->__pyx_v_start_angle); + + /* "ezdxf/acc/bezier4p.pyx":203 + * cdef double delta_angle = end_angle - start_angle + * cdef int arc_count + * if delta_angle > 0: # <<<<<<<<<<<<<< + * arc_count = ceil(delta_angle / M_PI * 2.0) + * if segments > arc_count: + */ + __pyx_t_1 = (__pyx_cur_scope->__pyx_v_delta_angle > 0.0); + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/bezier4p.pyx":204 + * cdef int arc_count + * if delta_angle > 0: + * arc_count = ceil(delta_angle / M_PI * 2.0) # <<<<<<<<<<<<<< + * if segments > arc_count: + * arc_count = segments + */ + __pyx_cur_scope->__pyx_v_arc_count = ((int)ceil(((__pyx_cur_scope->__pyx_v_delta_angle / ((double)M_PI)) * 2.0))); + + /* "ezdxf/acc/bezier4p.pyx":205 + * if delta_angle > 0: + * arc_count = ceil(delta_angle / M_PI * 2.0) + * if segments > arc_count: # <<<<<<<<<<<<<< + * arc_count = segments + * else: + */ + __pyx_t_1 = (__pyx_cur_scope->__pyx_v_segments > __pyx_cur_scope->__pyx_v_arc_count); + if (__pyx_t_1) { + + /* "ezdxf/acc/bezier4p.pyx":206 + * arc_count = ceil(delta_angle / M_PI * 2.0) + * if segments > arc_count: + * arc_count = segments # <<<<<<<<<<<<<< + * else: + * raise ValueError('Delta angle from start- to end angle has to be > 0.') + */ + __pyx_cur_scope->__pyx_v_arc_count = __pyx_cur_scope->__pyx_v_segments; + + /* "ezdxf/acc/bezier4p.pyx":205 + * if delta_angle > 0: + * arc_count = ceil(delta_angle / M_PI * 2.0) + * if segments > arc_count: # <<<<<<<<<<<<<< + * arc_count = segments + * else: + */ + } + + /* "ezdxf/acc/bezier4p.pyx":203 + * cdef double delta_angle = end_angle - start_angle + * cdef int arc_count + * if delta_angle > 0: # <<<<<<<<<<<<<< + * arc_count = ceil(delta_angle / M_PI * 2.0) + * if segments > arc_count: + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bezier4p.pyx":208 + * arc_count = segments + * else: + * raise ValueError('Delta angle from start- to end angle has to be > 0.') # <<<<<<<<<<<<<< + * + * cdef double segment_angle = delta_angle / arc_count + */ + /*else*/ { + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 208, __pyx_L1_error) + } + __pyx_L5:; + + /* "ezdxf/acc/bezier4p.pyx":210 + * raise ValueError('Delta angle from start- to end angle has to be > 0.') + * + * cdef double segment_angle = delta_angle / arc_count # <<<<<<<<<<<<<< + * cdef double tangent_length = TANGENT_FACTOR * tan(segment_angle / 4.0) + * cdef double angle = start_angle + */ + __pyx_cur_scope->__pyx_v_segment_angle = (__pyx_cur_scope->__pyx_v_delta_angle / ((double)__pyx_cur_scope->__pyx_v_arc_count)); + + /* "ezdxf/acc/bezier4p.pyx":211 + * + * cdef double segment_angle = delta_angle / arc_count + * cdef double tangent_length = TANGENT_FACTOR * tan(segment_angle / 4.0) # <<<<<<<<<<<<<< + * cdef double angle = start_angle + * cdef Vec3 start_point, end_point, cp1, cp2 + */ + __pyx_cur_scope->__pyx_v_tangent_length = (__pyx_v_5ezdxf_3acc_8bezier4p_TANGENT_FACTOR * tan((__pyx_cur_scope->__pyx_v_segment_angle / 4.0))); + + /* "ezdxf/acc/bezier4p.pyx":212 + * cdef double segment_angle = delta_angle / arc_count + * cdef double tangent_length = TANGENT_FACTOR * tan(segment_angle / 4.0) + * cdef double angle = start_angle # <<<<<<<<<<<<<< + * cdef Vec3 start_point, end_point, cp1, cp2 + * end_point = v3_from_angle(angle, 1.0) + */ + __pyx_cur_scope->__pyx_v_angle = __pyx_cur_scope->__pyx_v_start_angle; + + /* "ezdxf/acc/bezier4p.pyx":214 + * cdef double angle = start_angle + * cdef Vec3 start_point, end_point, cp1, cp2 + * end_point = v3_from_angle(angle, 1.0) # <<<<<<<<<<<<<< + * + * for _ in range(arc_count): + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_from_angle(__pyx_cur_scope->__pyx_v_angle, 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_2); + __pyx_cur_scope->__pyx_v_end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":216 + * end_point = v3_from_angle(angle, 1.0) + * + * for _ in range(arc_count): # <<<<<<<<<<<<<< + * start_point = end_point + * angle += segment_angle + */ + __pyx_t_3 = __pyx_cur_scope->__pyx_v_arc_count; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_cur_scope->__pyx_v__ = __pyx_t_5; + + /* "ezdxf/acc/bezier4p.pyx":217 + * + * for _ in range(arc_count): + * start_point = end_point # <<<<<<<<<<<<<< + * angle += segment_angle + * end_point = v3_from_angle(angle, 1.0) + */ + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_end_point); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_start_point); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_start_point, __pyx_cur_scope->__pyx_v_end_point); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_end_point); + + /* "ezdxf/acc/bezier4p.pyx":218 + * for _ in range(arc_count): + * start_point = end_point + * angle += segment_angle # <<<<<<<<<<<<<< + * end_point = v3_from_angle(angle, 1.0) + * cp1 = Vec3() + */ + __pyx_cur_scope->__pyx_v_angle = (__pyx_cur_scope->__pyx_v_angle + __pyx_cur_scope->__pyx_v_segment_angle); + + /* "ezdxf/acc/bezier4p.pyx":219 + * start_point = end_point + * angle += segment_angle + * end_point = v3_from_angle(angle, 1.0) # <<<<<<<<<<<<<< + * cp1 = Vec3() + * cp1.x = start_point.x - start_point.y * tangent_length + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_from_angle(__pyx_cur_scope->__pyx_v_angle, 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GOTREF((PyObject *)__pyx_cur_scope->__pyx_v_end_point); + __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_end_point, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __Pyx_GIVEREF(__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":220 + * angle += segment_angle + * end_point = v3_from_angle(angle, 1.0) + * cp1 = Vec3() # <<<<<<<<<<<<<< + * cp1.x = start_point.x - start_point.y * tangent_length + * cp1.y = start_point.y + start_point.x * tangent_length + */ + __pyx_t_2 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 220, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_cp1); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_cp1, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __Pyx_GIVEREF(__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":221 + * end_point = v3_from_angle(angle, 1.0) + * cp1 = Vec3() + * cp1.x = start_point.x - start_point.y * tangent_length # <<<<<<<<<<<<<< + * cp1.y = start_point.y + start_point.x * tangent_length + * cp2 = Vec3() + */ + __pyx_cur_scope->__pyx_v_cp1->x = (__pyx_cur_scope->__pyx_v_start_point->x - (__pyx_cur_scope->__pyx_v_start_point->y * __pyx_cur_scope->__pyx_v_tangent_length)); + + /* "ezdxf/acc/bezier4p.pyx":222 + * cp1 = Vec3() + * cp1.x = start_point.x - start_point.y * tangent_length + * cp1.y = start_point.y + start_point.x * tangent_length # <<<<<<<<<<<<<< + * cp2 = Vec3() + * cp2.x = end_point.x + end_point.y * tangent_length + */ + __pyx_cur_scope->__pyx_v_cp1->y = (__pyx_cur_scope->__pyx_v_start_point->y + (__pyx_cur_scope->__pyx_v_start_point->x * __pyx_cur_scope->__pyx_v_tangent_length)); + + /* "ezdxf/acc/bezier4p.pyx":223 + * cp1.x = start_point.x - start_point.y * tangent_length + * cp1.y = start_point.y + start_point.x * tangent_length + * cp2 = Vec3() # <<<<<<<<<<<<<< + * cp2.x = end_point.x + end_point.y * tangent_length + * cp2.y = end_point.y - end_point.x * tangent_length + */ + __pyx_t_2 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_cp2); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_cp2, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __Pyx_GIVEREF(__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":224 + * cp1.y = start_point.y + start_point.x * tangent_length + * cp2 = Vec3() + * cp2.x = end_point.x + end_point.y * tangent_length # <<<<<<<<<<<<<< + * cp2.y = end_point.y - end_point.x * tangent_length + * yield start_point, cp1, cp2, end_point + */ + __pyx_cur_scope->__pyx_v_cp2->x = (__pyx_cur_scope->__pyx_v_end_point->x + (__pyx_cur_scope->__pyx_v_end_point->y * __pyx_cur_scope->__pyx_v_tangent_length)); + + /* "ezdxf/acc/bezier4p.pyx":225 + * cp2 = Vec3() + * cp2.x = end_point.x + end_point.y * tangent_length + * cp2.y = end_point.y - end_point.x * tangent_length # <<<<<<<<<<<<<< + * yield start_point, cp1, cp2, end_point + * + */ + __pyx_cur_scope->__pyx_v_cp2->y = (__pyx_cur_scope->__pyx_v_end_point->y - (__pyx_cur_scope->__pyx_v_end_point->x * __pyx_cur_scope->__pyx_v_tangent_length)); + + /* "ezdxf/acc/bezier4p.pyx":226 + * cp2.x = end_point.x + end_point.y * tangent_length + * cp2.y = end_point.y - end_point.x * tangent_length + * yield start_point, cp1, cp2, end_point # <<<<<<<<<<<<<< + * + * def cubic_bezier_from_arc( + */ + __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_start_point); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_start_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_cur_scope->__pyx_v_start_point))) __PYX_ERR(0, 226, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_cp1); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_cp1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_cur_scope->__pyx_v_cp1))) __PYX_ERR(0, 226, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_cp2); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_cp2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 2, ((PyObject *)__pyx_cur_scope->__pyx_v_cp2))) __PYX_ERR(0, 226, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_end_point); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_end_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 3, ((PyObject *)__pyx_cur_scope->__pyx_v_end_point))) __PYX_ERR(0, 226, __pyx_L1_error); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + __pyx_cur_scope->__pyx_t_0 = __pyx_t_3; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_4; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_5; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L9_resume_from_yield:; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_0; + __pyx_t_4 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_5 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 226, __pyx_L1_error) + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/bezier4p.pyx":193 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + * @cython.cdivision(True) # <<<<<<<<<<<<<< + * def cubic_bezier_arc_parameters( + * double start_angle, + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("cubic_bezier_arc_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_5generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_4cubic_bezier_from_arc(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_4cubic_bezier_from_arc = {"cubic_bezier_from_arc", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_4cubic_bezier_from_arc, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_4cubic_bezier_from_arc(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_center = 0; + double __pyx_v_radius; + double __pyx_v_start_angle; + double __pyx_v_end_angle; + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[5] = {0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_from_arc (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_center,&__pyx_n_s_radius,&__pyx_n_s_start_angle,&__pyx_n_s_end_angle,&__pyx_n_s_segments,0}; + + /* "ezdxf/acc/bezier4p.pyx":229 + * + * def cubic_bezier_from_arc( + * center = (0, 0), # <<<<<<<<<<<<<< + * double radius = 1.0, + * double start_angle = 0.0, + */ + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)((PyObject*)__pyx_tuple__9))); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_center); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 228, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_radius); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 228, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_start_angle); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 228, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_end_angle); + if (value) { values[3] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 228, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[4] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 228, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "cubic_bezier_from_arc") < 0)) __PYX_ERR(0, 228, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_center = values[0]; + if (values[1]) { + __pyx_v_radius = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_radius == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 230, __pyx_L3_error) + } else { + __pyx_v_radius = ((double)((double)1.0)); + } + if (values[2]) { + __pyx_v_start_angle = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_start_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 231, __pyx_L3_error) + } else { + __pyx_v_start_angle = ((double)((double)0.0)); + } + if (values[3]) { + __pyx_v_end_angle = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_end_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 232, __pyx_L3_error) + } else { + __pyx_v_end_angle = ((double)((double)360.0)); + } + if (values[4]) { + __pyx_v_segments = __Pyx_PyInt_As_int(values[4]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 233, __pyx_L3_error) + } else { + __pyx_v_segments = ((int)((int)1)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("cubic_bezier_from_arc", 0, 0, 5, __pyx_nargs); __PYX_ERR(0, 228, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_from_arc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_3cubic_bezier_from_arc(__pyx_self, __pyx_v_center, __pyx_v_radius, __pyx_v_start_angle, __pyx_v_end_angle, __pyx_v_segments); + + /* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_3cubic_bezier_from_arc(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_center, double __pyx_v_radius, double __pyx_v_start_angle, double __pyx_v_end_angle, int __pyx_v_segments) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cubic_bezier_from_arc", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 228, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_center = __pyx_v_center; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_center); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_center); + __pyx_cur_scope->__pyx_v_radius = __pyx_v_radius; + __pyx_cur_scope->__pyx_v_start_angle = __pyx_v_start_angle; + __pyx_cur_scope->__pyx_v_end_angle = __pyx_v_end_angle; + __pyx_cur_scope->__pyx_v_segments = __pyx_v_segments; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8bezier4p_5generator1, __pyx_codeobj__10, (PyObject *) __pyx_cur_scope, __pyx_n_s_cubic_bezier_from_arc, __pyx_n_s_cubic_bezier_from_arc, __pyx_n_s_ezdxf_acc_bezier4p); if (unlikely(!gen)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_from_arc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_5generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + double __pyx_t_7; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + Py_ssize_t __pyx_t_10; + PyObject *(*__pyx_t_11)(PyObject *); + int __pyx_t_12; + int __pyx_t_13; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_from_arc", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L11_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 228, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":235 + * int segments = 1 + * ) -> Iterable[Bezier4P]: + * cdef Vec3 center_ = Vec3(center) # <<<<<<<<<<<<<< + * cdef Vec3 tmp + * cdef list res + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_center); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 235, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_center_ = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":239 + * cdef list res + * cdef int i + * cdef double angle_span = arc_angle_span_deg(start_angle, end_angle) # <<<<<<<<<<<<<< + * if abs(angle_span) < 1e-9: + * return + */ + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_arc_angle_span_deg); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_start_angle); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_end_angle); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_t_3, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_7 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_7 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_cur_scope->__pyx_v_angle_span = __pyx_t_7; + + /* "ezdxf/acc/bezier4p.pyx":240 + * cdef int i + * cdef double angle_span = arc_angle_span_deg(start_angle, end_angle) + * if abs(angle_span) < 1e-9: # <<<<<<<<<<<<<< + * return + * + */ + __pyx_t_8 = (fabs(__pyx_cur_scope->__pyx_v_angle_span) < 1e-9); + if (__pyx_t_8) { + + /* "ezdxf/acc/bezier4p.pyx":241 + * cdef double angle_span = arc_angle_span_deg(start_angle, end_angle) + * if abs(angle_span) < 1e-9: + * return # <<<<<<<<<<<<<< + * + * cdef double s = start_angle + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = NULL; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":240 + * cdef int i + * cdef double angle_span = arc_angle_span_deg(start_angle, end_angle) + * if abs(angle_span) < 1e-9: # <<<<<<<<<<<<<< + * return + * + */ + } + + /* "ezdxf/acc/bezier4p.pyx":243 + * return + * + * cdef double s = start_angle # <<<<<<<<<<<<<< + * start_angle = (s * DEG2RAD) % M_TAU + * end_angle = (s + angle_span) * DEG2RAD + */ + __pyx_cur_scope->__pyx_v_s = __pyx_cur_scope->__pyx_v_start_angle; + + /* "ezdxf/acc/bezier4p.pyx":244 + * + * cdef double s = start_angle + * start_angle = (s * DEG2RAD) % M_TAU # <<<<<<<<<<<<<< + * end_angle = (s + angle_span) * DEG2RAD + * while start_angle > end_angle: + */ + __pyx_t_7 = (__pyx_cur_scope->__pyx_v_s * __pyx_v_5ezdxf_3acc_8bezier4p_DEG2RAD); + if (unlikely(M_TAU == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); + __PYX_ERR(0, 244, __pyx_L1_error) + } + __pyx_cur_scope->__pyx_v_start_angle = __Pyx_mod_double(__pyx_t_7, M_TAU); + + /* "ezdxf/acc/bezier4p.pyx":245 + * cdef double s = start_angle + * start_angle = (s * DEG2RAD) % M_TAU + * end_angle = (s + angle_span) * DEG2RAD # <<<<<<<<<<<<<< + * while start_angle > end_angle: + * end_angle += M_TAU + */ + __pyx_cur_scope->__pyx_v_end_angle = ((__pyx_cur_scope->__pyx_v_s + __pyx_cur_scope->__pyx_v_angle_span) * __pyx_v_5ezdxf_3acc_8bezier4p_DEG2RAD); + + /* "ezdxf/acc/bezier4p.pyx":246 + * start_angle = (s * DEG2RAD) % M_TAU + * end_angle = (s + angle_span) * DEG2RAD + * while start_angle > end_angle: # <<<<<<<<<<<<<< + * end_angle += M_TAU + * + */ + while (1) { + __pyx_t_8 = (__pyx_cur_scope->__pyx_v_start_angle > __pyx_cur_scope->__pyx_v_end_angle); + if (!__pyx_t_8) break; + + /* "ezdxf/acc/bezier4p.pyx":247 + * end_angle = (s + angle_span) * DEG2RAD + * while start_angle > end_angle: + * end_angle += M_TAU # <<<<<<<<<<<<<< + * + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + */ + __pyx_cur_scope->__pyx_v_end_angle = (__pyx_cur_scope->__pyx_v_end_angle + M_TAU); + } + + /* "ezdxf/acc/bezier4p.pyx":249 + * end_angle += M_TAU + * + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): # <<<<<<<<<<<<<< + * res = [] + * for i in range(4): + */ + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_cubic_bezier_arc_parameters); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_start_angle); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_end_angle); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_cur_scope->__pyx_v_segments); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_9 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[4] = {__pyx_t_9, __pyx_t_4, __pyx_t_3, __pyx_t_5}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_6, 3+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { + __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); + __pyx_t_10 = 0; + __pyx_t_11 = NULL; + } else { + __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_11 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 249, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + for (;;) { + if (likely(!__pyx_t_11)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 249, __pyx_L1_error) + #endif + if (__pyx_t_10 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely((0 < 0))) __PYX_ERR(0, 249, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 249, __pyx_L1_error) + #endif + if (__pyx_t_10 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely((0 < 0))) __PYX_ERR(0, 249, __pyx_L1_error) + #else + __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + #endif + } + } else { + __pyx_t_1 = __pyx_t_11(__pyx_t_2); + if (unlikely(!__pyx_t_1)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 249, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_1); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_control_points); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_control_points, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":250 + * + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + * res = [] # <<<<<<<<<<<<<< + * for i in range(4): + * tmp = control_points[i] + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 250, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_res, ((PyObject*)__pyx_t_1)); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":251 + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + * res = [] + * for i in range(4): # <<<<<<<<<<<<<< + * tmp = control_points[i] + * res.append(v3_add(center_, v3_mul(tmp, radius))) + */ + for (__pyx_t_12 = 0; __pyx_t_12 < 4; __pyx_t_12+=1) { + __pyx_cur_scope->__pyx_v_i = __pyx_t_12; + + /* "ezdxf/acc/bezier4p.pyx":252 + * res = [] + * for i in range(4): + * tmp = control_points[i] # <<<<<<<<<<<<<< + * res.append(v3_add(center_, v3_mul(tmp, radius))) + * yield Bezier4P(res) + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_control_points, __pyx_cur_scope->__pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 252, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_tmp); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_tmp, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5)); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":253 + * for i in range(4): + * tmp = control_points[i] + * res.append(v3_add(center_, v3_mul(tmp, radius))) # <<<<<<<<<<<<<< + * yield Bezier4P(res) + * + */ + __pyx_t_5 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_cur_scope->__pyx_v_tmp, __pyx_cur_scope->__pyx_v_radius)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(__pyx_cur_scope->__pyx_v_center_, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_13 = __Pyx_PyList_Append(__pyx_cur_scope->__pyx_v_res, __pyx_t_1); if (unlikely(__pyx_t_13 == ((int)-1))) __PYX_ERR(0, 253, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + + /* "ezdxf/acc/bezier4p.pyx":254 + * tmp = control_points[i] + * res.append(v3_add(center_, v3_mul(tmp, radius))) + * yield Bezier4P(res) # <<<<<<<<<<<<<< + * + * def cubic_bezier_from_ellipse( + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P), __pyx_cur_scope->__pyx_v_res); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 254, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_t_2); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_10; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_11; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L11_resume_from_yield:; + __pyx_t_2 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_2); + __pyx_t_10 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_11 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 254, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":249 + * end_angle += M_TAU + * + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): # <<<<<<<<<<<<<< + * res = [] + * for i in range(4): + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("cubic_bezier_from_arc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_8generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bezier4p.pyx":256 + * yield Bezier4P(res) + * + * def cubic_bezier_from_ellipse( # <<<<<<<<<<<<<< + * ellipse: ConstructionEllipse, + * int segments = 1 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_7cubic_bezier_from_ellipse(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_7cubic_bezier_from_ellipse = {"cubic_bezier_from_ellipse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_7cubic_bezier_from_ellipse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_7cubic_bezier_from_ellipse(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ellipse = 0; + int __pyx_v_segments; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_from_ellipse (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ellipse,&__pyx_n_s_segments,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ellipse)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 256, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_segments); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 256, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "cubic_bezier_from_ellipse") < 0)) __PYX_ERR(0, 256, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ellipse = values[0]; + if (values[1]) { + __pyx_v_segments = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_segments == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 258, __pyx_L3_error) + } else { + __pyx_v_segments = ((int)((int)1)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("cubic_bezier_from_ellipse", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 256, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_from_ellipse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_6cubic_bezier_from_ellipse(__pyx_self, __pyx_v_ellipse, __pyx_v_segments); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_6cubic_bezier_from_ellipse(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_ellipse, int __pyx_v_segments) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cubic_bezier_from_ellipse", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 256, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_ellipse = __pyx_v_ellipse; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_ellipse); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_ellipse); + __pyx_cur_scope->__pyx_v_segments = __pyx_v_segments; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8bezier4p_8generator2, __pyx_codeobj__11, (PyObject *) __pyx_cur_scope, __pyx_n_s_cubic_bezier_from_ellipse, __pyx_n_s_cubic_bezier_from_ellipse, __pyx_n_s_ezdxf_acc_bezier4p); if (unlikely(!gen)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p.cubic_bezier_from_ellipse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8bezier4p_8generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + unsigned int __pyx_t_10; + Py_ssize_t __pyx_t_11; + PyObject *(*__pyx_t_12)(PyObject *); + long __pyx_t_13; + int __pyx_t_14; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubic_bezier_from_ellipse", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L11_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 256, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":260 + * int segments = 1 + * ) -> Iterator[Bezier4P]: + * cdef double param_span = ellipse.param_span # <<<<<<<<<<<<<< + * if abs(param_span) < 1e-9: + * return + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_ellipse, __pyx_n_s_param_span); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 260, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 260, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_cur_scope->__pyx_v_param_span = __pyx_t_2; + + /* "ezdxf/acc/bezier4p.pyx":261 + * ) -> Iterator[Bezier4P]: + * cdef double param_span = ellipse.param_span + * if abs(param_span) < 1e-9: # <<<<<<<<<<<<<< + * return + * + */ + __pyx_t_3 = (fabs(__pyx_cur_scope->__pyx_v_param_span) < 1e-9); + if (__pyx_t_3) { + + /* "ezdxf/acc/bezier4p.pyx":262 + * cdef double param_span = ellipse.param_span + * if abs(param_span) < 1e-9: + * return # <<<<<<<<<<<<<< + * + * cdef double start_angle = normalize_rad_angle(ellipse.start_param) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = NULL; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":261 + * ) -> Iterator[Bezier4P]: + * cdef double param_span = ellipse.param_span + * if abs(param_span) < 1e-9: # <<<<<<<<<<<<<< + * return + * + */ + } + + /* "ezdxf/acc/bezier4p.pyx":264 + * return + * + * cdef double start_angle = normalize_rad_angle(ellipse.start_param) # <<<<<<<<<<<<<< + * cdef double end_angle = start_angle + param_span + * + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_ellipse, __pyx_n_s_start_param); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 264, __pyx_L1_error) + __pyx_cur_scope->__pyx_v_start_angle = __pyx_t_4; + + /* "ezdxf/acc/bezier4p.pyx":265 + * + * cdef double start_angle = normalize_rad_angle(ellipse.start_param) + * cdef double end_angle = start_angle + param_span # <<<<<<<<<<<<<< + * + * while start_angle > end_angle: + */ + __pyx_cur_scope->__pyx_v_end_angle = (__pyx_cur_scope->__pyx_v_start_angle + __pyx_cur_scope->__pyx_v_param_span); + + /* "ezdxf/acc/bezier4p.pyx":267 + * cdef double end_angle = start_angle + param_span + * + * while start_angle > end_angle: # <<<<<<<<<<<<<< + * end_angle += M_TAU + * + */ + while (1) { + __pyx_t_3 = (__pyx_cur_scope->__pyx_v_start_angle > __pyx_cur_scope->__pyx_v_end_angle); + if (!__pyx_t_3) break; + + /* "ezdxf/acc/bezier4p.pyx":268 + * + * while start_angle > end_angle: + * end_angle += M_TAU # <<<<<<<<<<<<<< + * + * cdef Vec3 center = Vec3(ellipse.center) + */ + __pyx_cur_scope->__pyx_v_end_angle = (__pyx_cur_scope->__pyx_v_end_angle + M_TAU); + } + + /* "ezdxf/acc/bezier4p.pyx":270 + * end_angle += M_TAU + * + * cdef Vec3 center = Vec3(ellipse.center) # <<<<<<<<<<<<<< + * cdef Vec3 x_axis = Vec3(ellipse.major_axis) + * cdef Vec3 y_axis = Vec3(ellipse.minor_axis) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_ellipse, __pyx_n_s_center); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_5); + __pyx_cur_scope->__pyx_v_center = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":271 + * + * cdef Vec3 center = Vec3(ellipse.center) + * cdef Vec3 x_axis = Vec3(ellipse.major_axis) # <<<<<<<<<<<<<< + * cdef Vec3 y_axis = Vec3(ellipse.minor_axis) + * cdef Vec3 cp + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_ellipse, __pyx_n_s_major_axis); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_x_axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":272 + * cdef Vec3 center = Vec3(ellipse.center) + * cdef Vec3 x_axis = Vec3(ellipse.major_axis) + * cdef Vec3 y_axis = Vec3(ellipse.minor_axis) # <<<<<<<<<<<<<< + * cdef Vec3 cp + * cdef Vec3 c_res + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_ellipse, __pyx_n_s_minor_axis); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GIVEREF(__pyx_t_5); + __pyx_cur_scope->__pyx_v_y_axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":276 + * cdef Vec3 c_res + * cdef list res + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): # <<<<<<<<<<<<<< + * res = list() + * for i in range(4): + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_cubic_bezier_arc_parameters); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_start_angle); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_end_angle); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyInt_From_int(__pyx_cur_scope->__pyx_v_segments); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = NULL; + __pyx_t_10 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_10 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[4] = {__pyx_t_9, __pyx_t_6, __pyx_t_7, __pyx_t_8}; + __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_10, 3+__pyx_t_10); + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + if (likely(PyList_CheckExact(__pyx_t_5)) || PyTuple_CheckExact(__pyx_t_5)) { + __pyx_t_1 = __pyx_t_5; __Pyx_INCREF(__pyx_t_1); + __pyx_t_11 = 0; + __pyx_t_12 = NULL; + } else { + __pyx_t_11 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_12 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 276, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + for (;;) { + if (likely(!__pyx_t_12)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 276, __pyx_L1_error) + #endif + if (__pyx_t_11 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_11); __Pyx_INCREF(__pyx_t_5); __pyx_t_11++; if (unlikely((0 < 0))) __PYX_ERR(0, 276, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_11); __pyx_t_11++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 276, __pyx_L1_error) + #endif + if (__pyx_t_11 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_11); __Pyx_INCREF(__pyx_t_5); __pyx_t_11++; if (unlikely((0 < 0))) __PYX_ERR(0, 276, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_11); __pyx_t_11++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } + } else { + __pyx_t_5 = __pyx_t_12(__pyx_t_1); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 276, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_5); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_control_points); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_control_points, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":277 + * cdef list res + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + * res = list() # <<<<<<<<<<<<<< + * for i in range(4): + * cp = control_points[i] + */ + __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_res, ((PyObject*)__pyx_t_5)); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":278 + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + * res = list() + * for i in range(4): # <<<<<<<<<<<<<< + * cp = control_points[i] + * c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) + */ + for (__pyx_t_13 = 0; __pyx_t_13 < 4; __pyx_t_13+=1) { + __pyx_cur_scope->__pyx_v_i = __pyx_t_13; + + /* "ezdxf/acc/bezier4p.pyx":279 + * res = list() + * for i in range(4): + * cp = control_points[i] # <<<<<<<<<<<<<< + * c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) + * res.append(c_res) + */ + __pyx_t_5 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_control_points, __pyx_cur_scope->__pyx_v_i, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 279, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_8 = __pyx_t_5; + __Pyx_INCREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_cp); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_cp, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_8)); + __Pyx_GIVEREF(__pyx_t_8); + __pyx_t_8 = 0; + + /* "ezdxf/acc/bezier4p.pyx":280 + * for i in range(4): + * cp = control_points[i] + * c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) # <<<<<<<<<<<<<< + * res.append(c_res) + * yield Bezier4P(res) + */ + __pyx_t_8 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_cur_scope->__pyx_v_x_axis, __pyx_cur_scope->__pyx_v_cp->x)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_5 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_cur_scope->__pyx_v_y_axis, __pyx_cur_scope->__pyx_v_cp->y)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = ((PyObject *)__pyx_f_5ezdxf_3acc_8bezier4p_v3_add_3(__pyx_cur_scope->__pyx_v_center, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_8), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5))); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_c_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_c_res, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_7)); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "ezdxf/acc/bezier4p.pyx":281 + * cp = control_points[i] + * c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) + * res.append(c_res) # <<<<<<<<<<<<<< + * yield Bezier4P(res) + * + */ + __pyx_t_14 = __Pyx_PyList_Append(__pyx_cur_scope->__pyx_v_res, ((PyObject *)__pyx_cur_scope->__pyx_v_c_res)); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 281, __pyx_L1_error) + } + + /* "ezdxf/acc/bezier4p.pyx":282 + * c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) + * res.append(c_res) + * yield Bezier4P(res) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_7 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P), __pyx_cur_scope->__pyx_v_res); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_11; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_12; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L11_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_11 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_12 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 282, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":276 + * cdef Vec3 c_res + * cdef list res + * for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): # <<<<<<<<<<<<<< + * res = list() + * for i in range(4): + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/bezier4p.pyx":256 + * yield Bezier4P(res) + * + * def cubic_bezier_from_ellipse( # <<<<<<<<<<<<<< + * ellipse: ConstructionEllipse, + * int segments = 1 + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("cubic_bezier_from_ellipse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":285 + * + * + * cdef Vec3 v3_add_3(Vec3 a, Vec3 b, Vec3 c): # <<<<<<<<<<<<<< + * cdef Vec3 result = Vec3() + * + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_v3_add_3(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_c) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_result = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_add_3", 1); + + /* "ezdxf/acc/bezier4p.pyx":286 + * + * cdef Vec3 v3_add_3(Vec3 a, Vec3 b, Vec3 c): + * cdef Vec3 result = Vec3() # <<<<<<<<<<<<<< + * + * result.x = a.x + b.x + c.x + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":288 + * cdef Vec3 result = Vec3() + * + * result.x = a.x + b.x + c.x # <<<<<<<<<<<<<< + * result.y = a.y + b.y + c.y + * result.z = a.z + b.z + c.z + */ + __pyx_v_result->x = ((__pyx_v_a->x + __pyx_v_b->x) + __pyx_v_c->x); + + /* "ezdxf/acc/bezier4p.pyx":289 + * + * result.x = a.x + b.x + c.x + * result.y = a.y + b.y + c.y # <<<<<<<<<<<<<< + * result.z = a.z + b.z + c.z + * + */ + __pyx_v_result->y = ((__pyx_v_a->y + __pyx_v_b->y) + __pyx_v_c->y); + + /* "ezdxf/acc/bezier4p.pyx":290 + * result.x = a.x + b.x + c.x + * result.y = a.y + b.y + c.y + * result.z = a.z + b.z + c.z # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->z = ((__pyx_v_a->z + __pyx_v_b->z) + __pyx_v_c->z); + + /* "ezdxf/acc/bezier4p.pyx":292 + * result.z = a.z + b.z + c.z + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":285 + * + * + * cdef Vec3 v3_add_3(Vec3 a, Vec3 b, Vec3 c): # <<<<<<<<<<<<<< + * cdef Vec3 result = Vec3() + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.v3_add_3", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":302 + * double[3] p3 + * + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3): # <<<<<<<<<<<<<< + * cdef: + * double x = p0.x + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p3 = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p0,&__pyx_n_s_p1,&__pyx_n_s_p2,&__pyx_n_s_p3,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p0)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 302, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p1)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 302, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 4, 4, 1); __PYX_ERR(0, 302, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p2)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 302, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 4, 4, 2); __PYX_ERR(0, 302, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p3)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 302, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 4, 4, 3); __PYX_ERR(0, 302, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 302, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 4)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + } + __pyx_v_p0 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[0]); + __pyx_v_p1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[1]); + __pyx_v_p2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[2]); + __pyx_v_p3 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[3]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 302, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p0), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p0", 0))) __PYX_ERR(0, 302, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p1), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p1", 0))) __PYX_ERR(0, 302, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p2), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p2", 0))) __PYX_ERR(0, 302, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_p3), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 1, "p3", 0))) __PYX_ERR(0, 302, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve___cinit__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self), __pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve___cinit__(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p0, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p3) { + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + int __pyx_r; + double __pyx_t_1; + + /* "ezdxf/acc/bezier4p.pyx":304 + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3): + * cdef: + * double x = p0.x # <<<<<<<<<<<<<< + * double y = p0.y + * double z = p0.z + */ + __pyx_t_1 = __pyx_v_p0->x; + __pyx_v_x = __pyx_t_1; + + /* "ezdxf/acc/bezier4p.pyx":305 + * cdef: + * double x = p0.x + * double y = p0.y # <<<<<<<<<<<<<< + * double z = p0.z + * + */ + __pyx_t_1 = __pyx_v_p0->y; + __pyx_v_y = __pyx_t_1; + + /* "ezdxf/acc/bezier4p.pyx":306 + * double x = p0.x + * double y = p0.y + * double z = p0.z # <<<<<<<<<<<<<< + * + * self.offset[0] = x + */ + __pyx_t_1 = __pyx_v_p0->z; + __pyx_v_z = __pyx_t_1; + + /* "ezdxf/acc/bezier4p.pyx":308 + * double z = p0.z + * + * self.offset[0] = x # <<<<<<<<<<<<<< + * self.offset[1] = y + * self.offset[2] = z + */ + (__pyx_v_self->offset[0]) = __pyx_v_x; + + /* "ezdxf/acc/bezier4p.pyx":309 + * + * self.offset[0] = x + * self.offset[1] = y # <<<<<<<<<<<<<< + * self.offset[2] = z + * + */ + (__pyx_v_self->offset[1]) = __pyx_v_y; + + /* "ezdxf/acc/bezier4p.pyx":310 + * self.offset[0] = x + * self.offset[1] = y + * self.offset[2] = z # <<<<<<<<<<<<<< + * + * # 1st control point (p0) is always (0, 0, 0) + */ + (__pyx_v_self->offset[2]) = __pyx_v_z; + + /* "ezdxf/acc/bezier4p.pyx":313 + * + * # 1st control point (p0) is always (0, 0, 0) + * self.p1[0] = p1.x - x # <<<<<<<<<<<<<< + * self.p1[1] = p1.y - y + * self.p1[2] = p1.z - z + */ + (__pyx_v_self->p1[0]) = (__pyx_v_p1->x - __pyx_v_x); + + /* "ezdxf/acc/bezier4p.pyx":314 + * # 1st control point (p0) is always (0, 0, 0) + * self.p1[0] = p1.x - x + * self.p1[1] = p1.y - y # <<<<<<<<<<<<<< + * self.p1[2] = p1.z - z + * + */ + (__pyx_v_self->p1[1]) = (__pyx_v_p1->y - __pyx_v_y); + + /* "ezdxf/acc/bezier4p.pyx":315 + * self.p1[0] = p1.x - x + * self.p1[1] = p1.y - y + * self.p1[2] = p1.z - z # <<<<<<<<<<<<<< + * + * self.p2[0] = p2.x - x + */ + (__pyx_v_self->p1[2]) = (__pyx_v_p1->z - __pyx_v_z); + + /* "ezdxf/acc/bezier4p.pyx":317 + * self.p1[2] = p1.z - z + * + * self.p2[0] = p2.x - x # <<<<<<<<<<<<<< + * self.p2[1] = p2.y - y + * self.p2[2] = p2.z - z + */ + (__pyx_v_self->p2[0]) = (__pyx_v_p2->x - __pyx_v_x); + + /* "ezdxf/acc/bezier4p.pyx":318 + * + * self.p2[0] = p2.x - x + * self.p2[1] = p2.y - y # <<<<<<<<<<<<<< + * self.p2[2] = p2.z - z + * + */ + (__pyx_v_self->p2[1]) = (__pyx_v_p2->y - __pyx_v_y); + + /* "ezdxf/acc/bezier4p.pyx":319 + * self.p2[0] = p2.x - x + * self.p2[1] = p2.y - y + * self.p2[2] = p2.z - z # <<<<<<<<<<<<<< + * + * self.p3[0] = p3.x - x + */ + (__pyx_v_self->p2[2]) = (__pyx_v_p2->z - __pyx_v_z); + + /* "ezdxf/acc/bezier4p.pyx":321 + * self.p2[2] = p2.z - z + * + * self.p3[0] = p3.x - x # <<<<<<<<<<<<<< + * self.p3[1] = p3.y - y + * self.p3[2] = p3.z - z + */ + (__pyx_v_self->p3[0]) = (__pyx_v_p3->x - __pyx_v_x); + + /* "ezdxf/acc/bezier4p.pyx":322 + * + * self.p3[0] = p3.x - x + * self.p3[1] = p3.y - y # <<<<<<<<<<<<<< + * self.p3[2] = p3.z - z + * + */ + (__pyx_v_self->p3[1]) = (__pyx_v_p3->y - __pyx_v_y); + + /* "ezdxf/acc/bezier4p.pyx":323 + * self.p3[0] = p3.x - x + * self.p3[1] = p3.y - y + * self.p3[2] = p3.z - z # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_self->p3[2]) = (__pyx_v_p3->z - __pyx_v_z); + + /* "ezdxf/acc/bezier4p.pyx":302 + * double[3] p3 + * + * def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3): # <<<<<<<<<<<<<< + * cdef: + * double x = p0.x + */ + + /* function exit code */ + __pyx_r = 0; + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":326 + * + * + * cdef Vec3 point(self, double t): # <<<<<<<<<<<<<< + * # 1st control point (p0) is always (0, 0, 0) + * # => p0 * a is always (0, 0, 0) + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_point(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_result = 0; + double __pyx_v_t2; + double __pyx_v__1_minus_t; + double __pyx_v_b; + double __pyx_v_c; + double __pyx_v_d; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + + /* "ezdxf/acc/bezier4p.pyx":330 + * # => p0 * a is always (0, 0, 0) + * cdef: + * Vec3 result = Vec3() # <<<<<<<<<<<<<< + * double t2 = t * t + * double _1_minus_t = 1.0 - t + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 330, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":331 + * cdef: + * Vec3 result = Vec3() + * double t2 = t * t # <<<<<<<<<<<<<< + * double _1_minus_t = 1.0 - t + * # a = (1 - t) ** 3 + */ + __pyx_v_t2 = (__pyx_v_t * __pyx_v_t); + + /* "ezdxf/acc/bezier4p.pyx":332 + * Vec3 result = Vec3() + * double t2 = t * t + * double _1_minus_t = 1.0 - t # <<<<<<<<<<<<<< + * # a = (1 - t) ** 3 + * double b = 3.0 * _1_minus_t * _1_minus_t * t + */ + __pyx_v__1_minus_t = (1.0 - __pyx_v_t); + + /* "ezdxf/acc/bezier4p.pyx":334 + * double _1_minus_t = 1.0 - t + * # a = (1 - t) ** 3 + * double b = 3.0 * _1_minus_t * _1_minus_t * t # <<<<<<<<<<<<<< + * double c = 3.0 * _1_minus_t * t2 + * double d = t2 * t + */ + __pyx_v_b = (((3.0 * __pyx_v__1_minus_t) * __pyx_v__1_minus_t) * __pyx_v_t); + + /* "ezdxf/acc/bezier4p.pyx":335 + * # a = (1 - t) ** 3 + * double b = 3.0 * _1_minus_t * _1_minus_t * t + * double c = 3.0 * _1_minus_t * t2 # <<<<<<<<<<<<<< + * double d = t2 * t + * + */ + __pyx_v_c = ((3.0 * __pyx_v__1_minus_t) * __pyx_v_t2); + + /* "ezdxf/acc/bezier4p.pyx":336 + * double b = 3.0 * _1_minus_t * _1_minus_t * t + * double c = 3.0 * _1_minus_t * t2 + * double d = t2 * t # <<<<<<<<<<<<<< + * + * iadd_mul(result, self.p1, b) + */ + __pyx_v_d = (__pyx_v_t2 * __pyx_v_t); + + /* "ezdxf/acc/bezier4p.pyx":338 + * double d = t2 * t + * + * iadd_mul(result, self.p1, b) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p2, c) + * iadd_mul(result, self.p3, d) + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p1, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 338, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":339 + * + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p3, d) + * + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p2, __pyx_v_c); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 339, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":340 + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) + * iadd_mul(result, self.p3, d) # <<<<<<<<<<<<<< + * + * # add offset at last - it is maybe very large + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p3, __pyx_v_d); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 340, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":343 + * + * # add offset at last - it is maybe very large + * result.x += self.offset[0] # <<<<<<<<<<<<<< + * result.y += self.offset[1] + * result.z += self.offset[2] + */ + __pyx_v_result->x = (__pyx_v_result->x + (__pyx_v_self->offset[0])); + + /* "ezdxf/acc/bezier4p.pyx":344 + * # add offset at last - it is maybe very large + * result.x += self.offset[0] + * result.y += self.offset[1] # <<<<<<<<<<<<<< + * result.z += self.offset[2] + * + */ + __pyx_v_result->y = (__pyx_v_result->y + (__pyx_v_self->offset[1])); + + /* "ezdxf/acc/bezier4p.pyx":345 + * result.x += self.offset[0] + * result.y += self.offset[1] + * result.z += self.offset[2] # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->z = (__pyx_v_result->z + (__pyx_v_self->offset[2])); + + /* "ezdxf/acc/bezier4p.pyx":347 + * result.z += self.offset[2] + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":326 + * + * + * cdef Vec3 point(self, double t): # <<<<<<<<<<<<<< + * # 1st control point (p0) is always (0, 0, 0) + * # => p0 * a is always (0, 0, 0) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":350 + * + * + * cdef Vec3 tangent(self, double t): # <<<<<<<<<<<<<< + * # tangent vector is independent from offset location! + * cdef: + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_tangent(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, double __pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_result = 0; + double __pyx_v_t2; + double __pyx_v_b; + double __pyx_v_c; + double __pyx_v_d; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tangent", 1); + + /* "ezdxf/acc/bezier4p.pyx":353 + * # tangent vector is independent from offset location! + * cdef: + * Vec3 result = Vec3() # <<<<<<<<<<<<<< + * double t2 = t * t + * # a = -3 * (1 - t) ** 2 + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bezier4p.pyx":354 + * cdef: + * Vec3 result = Vec3() + * double t2 = t * t # <<<<<<<<<<<<<< + * # a = -3 * (1 - t) ** 2 + * double b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) + */ + __pyx_v_t2 = (__pyx_v_t * __pyx_v_t); + + /* "ezdxf/acc/bezier4p.pyx":356 + * double t2 = t * t + * # a = -3 * (1 - t) ** 2 + * double b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) # <<<<<<<<<<<<<< + * double c = 3.0 * t * (2.0 - 3.0 * t) + * double d = 3.0 * t2 + */ + __pyx_v_b = (3.0 * ((1.0 - (4.0 * __pyx_v_t)) + (3.0 * __pyx_v_t2))); + + /* "ezdxf/acc/bezier4p.pyx":357 + * # a = -3 * (1 - t) ** 2 + * double b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) + * double c = 3.0 * t * (2.0 - 3.0 * t) # <<<<<<<<<<<<<< + * double d = 3.0 * t2 + * + */ + __pyx_v_c = ((3.0 * __pyx_v_t) * (2.0 - (3.0 * __pyx_v_t))); + + /* "ezdxf/acc/bezier4p.pyx":358 + * double b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) + * double c = 3.0 * t * (2.0 - 3.0 * t) + * double d = 3.0 * t2 # <<<<<<<<<<<<<< + * + * iadd_mul(result, self.p1, b) + */ + __pyx_v_d = (3.0 * __pyx_v_t2); + + /* "ezdxf/acc/bezier4p.pyx":360 + * double d = 3.0 * t2 + * + * iadd_mul(result, self.p1, b) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p2, c) + * iadd_mul(result, self.p3, d) + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p1, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 360, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":361 + * + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) # <<<<<<<<<<<<<< + * iadd_mul(result, self.p3, d) + * + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p2, __pyx_v_c); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 361, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":362 + * iadd_mul(result, self.p1, b) + * iadd_mul(result, self.p2, c) + * iadd_mul(result, self.p3, d) # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(__pyx_v_result, __pyx_v_self->p3, __pyx_v_d); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 362, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":364 + * iadd_mul(result, self.p3, d) + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bezier4p.pyx":350 + * + * + * cdef Vec3 tangent(self, double t): # <<<<<<<<<<<<<< + * # tangent vector is independent from offset location! + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.tangent", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_2__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_4__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8bezier4p_14FastCubicCurve_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bezier4p.FastCubicCurve.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bezier4p.pyx":367 + * + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): # <<<<<<<<<<<<<< + * a.x += b[0] * c + * a.y += b[1] * c + */ + +static void __pyx_f_5ezdxf_3acc_8bezier4p_iadd_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, double *__pyx_v_b, double __pyx_v_c) { + + /* "ezdxf/acc/bezier4p.pyx":368 + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): + * a.x += b[0] * c # <<<<<<<<<<<<<< + * a.y += b[1] * c + * a.z += b[2] * c + */ + __pyx_v_a->x = (__pyx_v_a->x + ((__pyx_v_b[0]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier4p.pyx":369 + * cdef void iadd_mul(Vec3 a, double[3] b, double c): + * a.x += b[0] * c + * a.y += b[1] * c # <<<<<<<<<<<<<< + * a.z += b[2] * c + * + */ + __pyx_v_a->y = (__pyx_v_a->y + ((__pyx_v_b[1]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier4p.pyx":370 + * a.x += b[0] * c + * a.y += b[1] * c + * a.z += b[2] * c # <<<<<<<<<<<<<< + * + */ + __pyx_v_a->z = (__pyx_v_a->z + ((__pyx_v_b[2]) * __pyx_v_c)); + + /* "ezdxf/acc/bezier4p.pyx":367 + * + * + * cdef void iadd_mul(Vec3 a, double[3] b, double c): # <<<<<<<<<<<<<< + * a.x += b[0] * c + * a.y += b[1] * c + */ + + /* function exit code */ +} + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p_Bezier4P(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)o); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)Py_None); Py_INCREF(Py_None); + p->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + p->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + p->cp2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + p->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_Bezier4P(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_Bezier4P) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->curve); + Py_CLEAR(p->start_point); + Py_CLEAR(p->cp1); + Py_CLEAR(p->cp2); + Py_CLEAR(p->end_point); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier4p_Bezier4P(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)o; + if (p->curve) { + e = (*v)(((PyObject *)p->curve), a); if (e) return e; + } + if (p->start_point) { + e = (*v)(((PyObject *)p->start_point), a); if (e) return e; + } + if (p->cp1) { + e = (*v)(((PyObject *)p->cp1), a); if (e) return e; + } + if (p->cp2) { + e = (*v)(((PyObject *)p->cp2), a); if (e) return e; + } + if (p->end_point) { + e = (*v)(((PyObject *)p->end_point), a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8bezier4p_Bezier4P(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P *)o; + tmp = ((PyObject*)p->curve); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->start_point); + p->start_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->cp1); + p->cp1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->cp2); + p->cp2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->end_point); + p->end_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_control_points(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_14control_points_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_start_point(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11start_point_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_end_point(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9end_point_1__get__(o); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier4p_Bezier4P[] = { + {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"point", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_5point, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"tangent", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"approximate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"flattening", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"approximated_length", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"reverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_8bezier4p_Bezier4P[] = { + {(char *)"control_points", __pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_control_points, 0, (char *)0, 0}, + {(char *)"start_point", __pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_start_point, 0, (char *)0, 0}, + {(char *)"end_point", __pyx_getprop_5ezdxf_3acc_8bezier4p_8Bezier4P_end_point, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_Bezier4P}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier4p_Bezier4P}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8bezier4p_Bezier4P}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier4p_Bezier4P}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_8bezier4p_Bezier4P}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p_Bezier4P}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P_spec = { + "ezdxf.acc.bezier4p.Bezier4P", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""Bezier4P", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p_Bezier4P), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p_Bezier4P, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p__Flattening __pyx_vtable_5ezdxf_3acc_8bezier4p__Flattening; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p__Flattening(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_8bezier4p__Flattening; + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)Py_None); Py_INCREF(Py_None); + p->points = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p__Flattening(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p__Flattening) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->curve); + Py_CLEAR(p->points); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier4p__Flattening(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)o; + if (p->curve) { + e = (*v)(((PyObject *)p->curve), a); if (e) return e; + } + if (p->points) { + e = (*v)(p->points, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8bezier4p__Flattening(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *)o; + tmp = ((PyObject*)p->curve); + p->curve = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->points); + p->points = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier4p__Flattening[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p__Flattening_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p__Flattening}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier4p__Flattening}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8bezier4p__Flattening}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier4p__Flattening}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p__Flattening}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p__Flattening_spec = { + "ezdxf.acc.bezier4p._Flattening", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_8bezier4p__Flattening_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p__Flattening = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""_Flattening", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p__Flattening, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier4p__Flattening, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8bezier4p__Flattening, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier4p__Flattening, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p__Flattening, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_5ezdxf_3acc_8bezier4p_FastCubicCurve __pyx_vtable_5ezdxf_3acc_8bezier4p_FastCubicCurve; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p_FastCubicCurve(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_8bezier4p_FastCubicCurve; + if (unlikely(__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_FastCubicCurve(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_FastCubicCurve) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8bezier4p_FastCubicCurve[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_FastCubicCurve}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8bezier4p_FastCubicCurve}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p_FastCubicCurve}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve_spec = { + "ezdxf.acc.bezier4p.FastCubicCurve", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""FastCubicCurve", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p_FastCubicCurve, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8bezier4p_FastCubicCurve, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p_FastCubicCurve, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters[8]; +static int __pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters[--__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_cp1); + Py_CLEAR(p->__pyx_v_cp2); + Py_CLEAR(p->__pyx_v_end_point); + Py_CLEAR(p->__pyx_v_start_point); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters)))) { + __pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters[__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters++] = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters *)o; + if (p->__pyx_v_cp1) { + e = (*v)(((PyObject *)p->__pyx_v_cp1), a); if (e) return e; + } + if (p->__pyx_v_cp2) { + e = (*v)(((PyObject *)p->__pyx_v_cp2), a); if (e) return e; + } + if (p->__pyx_v_end_point) { + e = (*v)(((PyObject *)p->__pyx_v_end_point), a); if (e) return e; + } + if (p->__pyx_v_start_point) { + e = (*v)(((PyObject *)p->__pyx_v_start_point), a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters_spec = { + "ezdxf.acc.bezier4p.__pyx_scope_struct__cubic_bezier_arc_parameters", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""__pyx_scope_struct__cubic_bezier_arc_parameters", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc[8]; +static int __pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc[--__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_center); + Py_CLEAR(p->__pyx_v_center_); + Py_CLEAR(p->__pyx_v_control_points); + Py_CLEAR(p->__pyx_v_res); + Py_CLEAR(p->__pyx_v_tmp); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc)))) { + __pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc[__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc++] = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc *)o; + if (p->__pyx_v_center) { + e = (*v)(p->__pyx_v_center, a); if (e) return e; + } + if (p->__pyx_v_center_) { + e = (*v)(((PyObject *)p->__pyx_v_center_), a); if (e) return e; + } + if (p->__pyx_v_control_points) { + e = (*v)(p->__pyx_v_control_points, a); if (e) return e; + } + if (p->__pyx_v_res) { + e = (*v)(p->__pyx_v_res, a); if (e) return e; + } + if (p->__pyx_v_tmp) { + e = (*v)(((PyObject *)p->__pyx_v_tmp), a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc_spec = { + "ezdxf.acc.bezier4p.__pyx_scope_struct_1_cubic_bezier_from_arc", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""__pyx_scope_struct_1_cubic_bezier_from_arc", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse[8]; +static int __pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse[--__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_c_res); + Py_CLEAR(p->__pyx_v_center); + Py_CLEAR(p->__pyx_v_control_points); + Py_CLEAR(p->__pyx_v_cp); + Py_CLEAR(p->__pyx_v_ellipse); + Py_CLEAR(p->__pyx_v_res); + Py_CLEAR(p->__pyx_v_x_axis); + Py_CLEAR(p->__pyx_v_y_axis); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse)))) { + __pyx_freelist_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse[__pyx_freecount_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse++] = ((struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *p = (struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse *)o; + if (p->__pyx_v_c_res) { + e = (*v)(((PyObject *)p->__pyx_v_c_res), a); if (e) return e; + } + if (p->__pyx_v_center) { + e = (*v)(((PyObject *)p->__pyx_v_center), a); if (e) return e; + } + if (p->__pyx_v_control_points) { + e = (*v)(p->__pyx_v_control_points, a); if (e) return e; + } + if (p->__pyx_v_cp) { + e = (*v)(((PyObject *)p->__pyx_v_cp), a); if (e) return e; + } + if (p->__pyx_v_ellipse) { + e = (*v)(p->__pyx_v_ellipse, a); if (e) return e; + } + if (p->__pyx_v_res) { + e = (*v)(p->__pyx_v_res, a); if (e) return e; + } + if (p->__pyx_v_x_axis) { + e = (*v)(((PyObject *)p->__pyx_v_x_axis), a); if (e) return e; + } + if (p->__pyx_v_y_axis) { + e = (*v)(((PyObject *)p->__pyx_v_y_axis), a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse_spec = { + "ezdxf.acc.bezier4p.__pyx_scope_struct_2_cubic_bezier_from_ellipse", + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bezier4p.""__pyx_scope_struct_2_cubic_bezier_from_ellipse", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_Bezier4P, __pyx_k_Bezier4P, sizeof(__pyx_k_Bezier4P), 0, 0, 1, 1}, + {&__pyx_n_u_Bezier4P, __pyx_k_Bezier4P, sizeof(__pyx_k_Bezier4P), 0, 1, 0, 1}, + {&__pyx_n_s_Bezier4P___reduce, __pyx_k_Bezier4P___reduce, sizeof(__pyx_k_Bezier4P___reduce), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier4P_approximate, __pyx_k_Bezier4P_approximate, sizeof(__pyx_k_Bezier4P_approximate), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier4P_approximated_length, __pyx_k_Bezier4P_approximated_length, sizeof(__pyx_k_Bezier4P_approximated_length), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier4P_flattening, __pyx_k_Bezier4P_flattening, sizeof(__pyx_k_Bezier4P_flattening), 0, 0, 1, 1}, + {&__pyx_kp_u_Bezier4P_flattening_error_check, __pyx_k_Bezier4P_flattening_error_check, sizeof(__pyx_k_Bezier4P_flattening_error_check), 0, 1, 0, 0}, + {&__pyx_n_s_Bezier4P_point, __pyx_k_Bezier4P_point, sizeof(__pyx_k_Bezier4P_point), 0, 0, 1, 1}, + {&__pyx_kp_u_Bezier4P_requires_defpoints_of_t, __pyx_k_Bezier4P_requires_defpoints_of_t, sizeof(__pyx_k_Bezier4P_requires_defpoints_of_t), 0, 1, 0, 0}, + {&__pyx_n_s_Bezier4P_reverse, __pyx_k_Bezier4P_reverse, sizeof(__pyx_k_Bezier4P_reverse), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier4P_tangent, __pyx_k_Bezier4P_tangent, sizeof(__pyx_k_Bezier4P_tangent), 0, 0, 1, 1}, + {&__pyx_n_s_Bezier4P_transform, __pyx_k_Bezier4P_transform, sizeof(__pyx_k_Bezier4P_transform), 0, 0, 1, 1}, + {&__pyx_n_s_ConstructionEllipse, __pyx_k_ConstructionEllipse, sizeof(__pyx_k_ConstructionEllipse), 0, 0, 1, 1}, + {&__pyx_kp_u_Delta_angle_from_start_to_end_an, __pyx_k_Delta_angle_from_start_to_end_an, sizeof(__pyx_k_Delta_angle_from_start_to_end_an), 0, 1, 0, 0}, + {&__pyx_n_s_DeprecationWarning, __pyx_k_DeprecationWarning, sizeof(__pyx_k_DeprecationWarning), 0, 0, 1, 1}, + {&__pyx_n_s_FastCubicCurve, __pyx_k_FastCubicCurve, sizeof(__pyx_k_FastCubicCurve), 0, 0, 1, 1}, + {&__pyx_n_s_FastCubicCurve___reduce_cython, __pyx_k_FastCubicCurve___reduce_cython, sizeof(__pyx_k_FastCubicCurve___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_FastCubicCurve___setstate_cython, __pyx_k_FastCubicCurve___setstate_cython, sizeof(__pyx_k_FastCubicCurve___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening, __pyx_k_Flattening, sizeof(__pyx_k_Flattening), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening___reduce_cython, __pyx_k_Flattening___reduce_cython, sizeof(__pyx_k_Flattening___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Flattening___setstate_cython, __pyx_k_Flattening___setstate_cython, sizeof(__pyx_k_Flattening___setstate_cython), 0, 0, 1, 1}, + {&__pyx_kp_u_Four_control_points_required, __pyx_k_Four_control_points_required, sizeof(__pyx_k_Four_control_points_required), 0, 1, 0, 0}, + {&__pyx_kp_u_Invalid_argument_segments_1, __pyx_k_Invalid_argument_segments_1, sizeof(__pyx_k_Invalid_argument_segments_1), 0, 1, 0, 0}, + {&__pyx_n_s_Iterable, __pyx_k_Iterable, sizeof(__pyx_k_Iterable), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterable_Bezier4P, __pyx_k_Iterable_Bezier4P, sizeof(__pyx_k_Iterable_Bezier4P), 0, 0, 1, 0}, + {&__pyx_n_s_Iterator, __pyx_k_Iterator, sizeof(__pyx_k_Iterator), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterator_Bezier4P, __pyx_k_Iterator_Bezier4P, sizeof(__pyx_k_Iterator_Bezier4P), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve, __pyx_k_Iterator_tuple_Vec3_Vec3_Vec3_Ve, sizeof(__pyx_k_Iterator_tuple_Vec3_Vec3_Vec3_Ve), 0, 0, 1, 0}, + {&__pyx_n_s_RecursionError, __pyx_k_RecursionError, sizeof(__pyx_k_RecursionError), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3, __pyx_k_Vec3, sizeof(__pyx_k_Vec3), 0, 0, 1, 1}, + {&__pyx_kp_u__12, __pyx_k__12, sizeof(__pyx_k__12), 0, 1, 0, 0}, + {&__pyx_n_s__13, __pyx_k__13, sizeof(__pyx_k__13), 0, 0, 1, 1}, + {&__pyx_n_s__32, __pyx_k__32, sizeof(__pyx_k__32), 0, 0, 1, 1}, + {&__pyx_n_s__38, __pyx_k__38, sizeof(__pyx_k__38), 0, 0, 1, 1}, + {&__pyx_n_s_all, __pyx_k_all, sizeof(__pyx_k_all), 0, 0, 1, 1}, + {&__pyx_n_s_angle, __pyx_k_angle, sizeof(__pyx_k_angle), 0, 0, 1, 1}, + {&__pyx_n_s_angle_span, __pyx_k_angle_span, sizeof(__pyx_k_angle_span), 0, 0, 1, 1}, + {&__pyx_n_s_approximate, __pyx_k_approximate, sizeof(__pyx_k_approximate), 0, 0, 1, 1}, + {&__pyx_n_s_approximated_length, __pyx_k_approximated_length, sizeof(__pyx_k_approximated_length), 0, 0, 1, 1}, + {&__pyx_n_s_arc_angle_span_deg, __pyx_k_arc_angle_span_deg, sizeof(__pyx_k_arc_angle_span_deg), 0, 0, 1, 1}, + {&__pyx_n_s_arc_count, __pyx_k_arc_count, sizeof(__pyx_k_arc_count), 0, 0, 1, 1}, + {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_c_res, __pyx_k_c_res, sizeof(__pyx_k_c_res), 0, 0, 1, 1}, + {&__pyx_n_s_center, __pyx_k_center, sizeof(__pyx_k_center), 0, 0, 1, 1}, + {&__pyx_n_s_center_2, __pyx_k_center_2, sizeof(__pyx_k_center_2), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1}, + {&__pyx_n_s_construct, __pyx_k_construct, sizeof(__pyx_k_construct), 0, 0, 1, 1}, + {&__pyx_n_s_control_points, __pyx_k_control_points, sizeof(__pyx_k_control_points), 0, 0, 1, 1}, + {&__pyx_n_s_cp, __pyx_k_cp, sizeof(__pyx_k_cp), 0, 0, 1, 1}, + {&__pyx_n_s_cp1, __pyx_k_cp1, sizeof(__pyx_k_cp1), 0, 0, 1, 1}, + {&__pyx_n_s_cp2, __pyx_k_cp2, sizeof(__pyx_k_cp2), 0, 0, 1, 1}, + {&__pyx_n_s_cubic_bezier_arc_parameters, __pyx_k_cubic_bezier_arc_parameters, sizeof(__pyx_k_cubic_bezier_arc_parameters), 0, 0, 1, 1}, + {&__pyx_n_u_cubic_bezier_arc_parameters, __pyx_k_cubic_bezier_arc_parameters, sizeof(__pyx_k_cubic_bezier_arc_parameters), 0, 1, 0, 1}, + {&__pyx_n_s_cubic_bezier_from_arc, __pyx_k_cubic_bezier_from_arc, sizeof(__pyx_k_cubic_bezier_from_arc), 0, 0, 1, 1}, + {&__pyx_n_u_cubic_bezier_from_arc, __pyx_k_cubic_bezier_from_arc, sizeof(__pyx_k_cubic_bezier_from_arc), 0, 1, 0, 1}, + {&__pyx_n_s_cubic_bezier_from_ellipse, __pyx_k_cubic_bezier_from_ellipse, sizeof(__pyx_k_cubic_bezier_from_ellipse), 0, 0, 1, 1}, + {&__pyx_n_u_cubic_bezier_from_ellipse, __pyx_k_cubic_bezier_from_ellipse, sizeof(__pyx_k_cubic_bezier_from_ellipse), 0, 1, 0, 1}, + {&__pyx_n_s_curve, __pyx_k_curve, sizeof(__pyx_k_curve), 0, 0, 1, 1}, + {&__pyx_n_s_defpoints, __pyx_k_defpoints, sizeof(__pyx_k_defpoints), 0, 0, 1, 1}, + {&__pyx_n_s_delta_angle, __pyx_k_delta_angle, sizeof(__pyx_k_delta_angle), 0, 0, 1, 1}, + {&__pyx_n_s_delta_t, __pyx_k_delta_t, sizeof(__pyx_k_delta_t), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_distance, __pyx_k_distance, sizeof(__pyx_k_distance), 0, 0, 1, 1}, + {&__pyx_n_s_dt, __pyx_k_dt, sizeof(__pyx_k_dt), 0, 0, 1, 1}, + {&__pyx_n_s_ellipse, __pyx_k_ellipse, sizeof(__pyx_k_ellipse), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_end_angle, __pyx_k_end_angle, sizeof(__pyx_k_end_angle), 0, 0, 1, 1}, + {&__pyx_n_s_end_point, __pyx_k_end_point, sizeof(__pyx_k_end_point), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_bezier4p, __pyx_k_ezdxf_acc_bezier4p, sizeof(__pyx_k_ezdxf_acc_bezier4p), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math_ellipse, __pyx_k_ezdxf_math_ellipse, sizeof(__pyx_k_ezdxf_math_ellipse), 0, 0, 1, 1}, + {&__pyx_n_s_f, __pyx_k_f, sizeof(__pyx_k_f), 0, 0, 1, 1}, + {&__pyx_n_s_flattening, __pyx_k_flattening, sizeof(__pyx_k_flattening), 0, 0, 1, 1}, + {&__pyx_n_s_float, __pyx_k_float, sizeof(__pyx_k_float), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_length, __pyx_k_length, sizeof(__pyx_k_length), 0, 0, 1, 1}, + {&__pyx_kp_s_list_Vec3, __pyx_k_list_Vec3, sizeof(__pyx_k_list_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_m, __pyx_k_m, sizeof(__pyx_k_m), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_major_axis, __pyx_k_major_axis, sizeof(__pyx_k_major_axis), 0, 0, 1, 1}, + {&__pyx_n_s_minor_axis, __pyx_k_minor_axis, sizeof(__pyx_k_minor_axis), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_p0, __pyx_k_p0, sizeof(__pyx_k_p0), 0, 0, 1, 1}, + {&__pyx_n_s_p1, __pyx_k_p1, sizeof(__pyx_k_p1), 0, 0, 1, 1}, + {&__pyx_n_s_p2, __pyx_k_p2, sizeof(__pyx_k_p2), 0, 0, 1, 1}, + {&__pyx_n_s_p3, __pyx_k_p3, sizeof(__pyx_k_p3), 0, 0, 1, 1}, + {&__pyx_n_s_param_span, __pyx_k_param_span, sizeof(__pyx_k_param_span), 0, 0, 1, 1}, + {&__pyx_n_s_point, __pyx_k_point, sizeof(__pyx_k_point), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_prev_point, __pyx_k_prev_point, sizeof(__pyx_k_prev_point), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_radius, __pyx_k_radius, sizeof(__pyx_k_radius), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_reverse, __pyx_k_reverse, sizeof(__pyx_k_reverse), 0, 0, 1, 1}, + {&__pyx_n_s_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 0, 1, 1}, + {&__pyx_n_s_segment, __pyx_k_segment, sizeof(__pyx_k_segment), 0, 0, 1, 1}, + {&__pyx_n_s_segment_angle, __pyx_k_segment_angle, sizeof(__pyx_k_segment_angle), 0, 0, 1, 1}, + {&__pyx_n_s_segments, __pyx_k_segments, sizeof(__pyx_k_segments), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_k_src_ezdxf_acc_bezier4p_pyx, sizeof(__pyx_k_src_ezdxf_acc_bezier4p_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start_angle, __pyx_k_start_angle, sizeof(__pyx_k_start_angle), 0, 0, 1, 1}, + {&__pyx_n_s_start_flag, __pyx_k_start_flag, sizeof(__pyx_k_start_flag), 0, 0, 1, 1}, + {&__pyx_n_s_start_param, __pyx_k_start_param, sizeof(__pyx_k_start_param), 0, 0, 1, 1}, + {&__pyx_n_s_start_point, __pyx_k_start_point, sizeof(__pyx_k_start_point), 0, 0, 1, 1}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_t0, __pyx_k_t0, sizeof(__pyx_k_t0), 0, 0, 1, 1}, + {&__pyx_n_s_t1, __pyx_k_t1, sizeof(__pyx_k_t1), 0, 0, 1, 1}, + {&__pyx_kp_u_t_not_in_range_0_to_1, __pyx_k_t_not_in_range_0_to_1, sizeof(__pyx_k_t_not_in_range_0_to_1), 0, 1, 0, 0}, + {&__pyx_n_s_tangent, __pyx_k_tangent, sizeof(__pyx_k_tangent), 0, 0, 1, 1}, + {&__pyx_n_s_tangent_length, __pyx_k_tangent_length, sizeof(__pyx_k_tangent_length), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1}, + {&__pyx_n_s_tmp, __pyx_k_tmp, sizeof(__pyx_k_tmp), 0, 0, 1, 1}, + {&__pyx_n_s_transform, __pyx_k_transform, sizeof(__pyx_k_transform), 0, 0, 1, 1}, + {&__pyx_n_s_transform_vertices, __pyx_k_transform_vertices, sizeof(__pyx_k_transform_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_warn, __pyx_k_warn, sizeof(__pyx_k_warn), 0, 0, 1, 1}, + {&__pyx_n_s_warnings, __pyx_k_warnings, sizeof(__pyx_k_warnings), 0, 0, 1, 1}, + {&__pyx_n_s_x_axis, __pyx_k_x_axis, sizeof(__pyx_k_x_axis), 0, 0, 1, 1}, + {&__pyx_n_s_y_axis, __pyx_k_y_axis, sizeof(__pyx_k_y_axis), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_DeprecationWarning = __Pyx_GetBuiltinName(__pyx_n_s_DeprecationWarning); if (!__pyx_builtin_DeprecationWarning) __PYX_ERR(0, 51, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 67, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 96, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/bezier4p.pyx":50 + * def __cinit__(self, defpoints: Sequence[UVec]): + * if not isinstance(defpoints[0], (Vec2, Vec3)): + * warnings.warn( # <<<<<<<<<<<<<< + * DeprecationWarning, + * "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + */ + __pyx_tuple_ = PyTuple_Pack(2, __pyx_builtin_DeprecationWarning, __pyx_kp_u_Bezier4P_requires_defpoints_of_t); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "ezdxf/acc/bezier4p.pyx":67 + * ) + * else: + * raise ValueError("Four control points required.") # <<<<<<<<<<<<<< + * + * @property + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_Four_control_points_required); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "ezdxf/acc/bezier4p.pyx":80 + * return self.curve.point(t) + * else: + * raise ValueError("t not in range [0 to 1]") # <<<<<<<<<<<<<< + * + * def tangent(self, double t) -> Vec3: + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_t_not_in_range_0_to_1); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 80, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "ezdxf/acc/bezier4p.pyx":117 + * f.flatten(start_point, end_point, t0, t1) + * if f.has_recursion_error(): + * raise RecursionError( # <<<<<<<<<<<<<< + * "Bezier4P flattening error, check for very large coordinates" + * ) + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_Bezier4P_flattening_error_check); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "ezdxf/acc/bezier4p.pyx":200 + * ) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + * if segments < 1: + * raise ValueError('Invalid argument segments (>= 1).') # <<<<<<<<<<<<<< + * cdef double delta_angle = end_angle - start_angle + * cdef int arc_count + */ + __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Invalid_argument_segments_1); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + + /* "ezdxf/acc/bezier4p.pyx":208 + * arc_count = segments + * else: + * raise ValueError('Delta angle from start- to end angle has to be > 0.') # <<<<<<<<<<<<<< + * + * cdef double segment_angle = delta_angle / arc_count + */ + __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Delta_angle_from_start_to_end_an); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "ezdxf/acc/bezier4p.pyx":229 + * + * def cubic_bezier_from_arc( + * center = (0, 0), # <<<<<<<<<<<<<< + * double radius = 1.0, + * double start_angle = 0.0, + */ + __pyx_tuple__9 = PyTuple_Pack(2, __pyx_int_0, __pyx_int_0); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + + /* "ezdxf/acc/bezier4p.pyx":73 + * return self.start_point, self.cp1, self.cp2, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier4P, (self.control_points,) + * + */ + __pyx_tuple__14 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_reduce, 73, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 73, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":76 + * return Bezier4P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + __pyx_tuple__16 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_t); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__16); + __Pyx_GIVEREF(__pyx_tuple__16); + __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_point, 76, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(0, 76, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":82 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + __pyx_codeobj__18 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_tangent, 82, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__18)) __PYX_ERR(0, 82, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":88 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + __pyx_tuple__19 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_segments, __pyx_n_s_delta_t, __pyx_n_s_segment, __pyx_n_s_points); if (unlikely(!__pyx_tuple__19)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__19); + __Pyx_GIVEREF(__pyx_tuple__19); + __pyx_codeobj__20 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_approximate, 88, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(0, 88, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":101 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + __pyx_tuple__21 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_distance, __pyx_n_s_segments, __pyx_n_s_dt, __pyx_n_s_t0, __pyx_n_s_t1, __pyx_n_s_f, __pyx_n_s_start_point, __pyx_n_s_end_point); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__21); + __Pyx_GIVEREF(__pyx_tuple__21); + __pyx_codeobj__22 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__21, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_flattening, 101, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__22)) __PYX_ERR(0, 101, __pyx_L1_error) + __pyx_tuple__23 = PyTuple_Pack(1, __pyx_int_4); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__23); + __Pyx_GIVEREF(__pyx_tuple__23); + + /* "ezdxf/acc/bezier4p.pyx":125 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + __pyx_tuple__24 = PyTuple_Pack(6, __pyx_n_s_self, __pyx_n_s_segments, __pyx_n_s_length, __pyx_n_s_start_flag, __pyx_n_s_prev_point, __pyx_n_s_point); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__24); + __Pyx_GIVEREF(__pyx_tuple__24); + __pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_approximated_length, 125, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) __PYX_ERR(0, 125, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":138 + * return length + * + * def reverse(self) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + */ + __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_reverse, 138, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 138, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":141 + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P(tuple(m.transform_vertices(self.control_points))) + * + */ + __pyx_tuple__27 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_m); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_transform, 141, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(0, 141, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_tuple__30 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_pyx_state); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__30); + __Pyx_GIVEREF(__pyx_tuple__30); + __pyx_codeobj__31 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__30, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__31)) __PYX_ERR(1, 3, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":193 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + * @cython.cdivision(True) # <<<<<<<<<<<<<< + * def cubic_bezier_arc_parameters( + * double start_angle, + */ + __pyx_tuple__33 = PyTuple_Pack(13, __pyx_n_s_start_angle, __pyx_n_s_end_angle, __pyx_n_s_segments, __pyx_n_s_delta_angle, __pyx_n_s_arc_count, __pyx_n_s_segment_angle, __pyx_n_s_tangent_length, __pyx_n_s_angle, __pyx_n_s_start_point, __pyx_n_s_end_point, __pyx_n_s_cp1, __pyx_n_s_cp2, __pyx_n_s__32); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__33); + __Pyx_GIVEREF(__pyx_tuple__33); + __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 13, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_cubic_bezier_arc_parameters, 193, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 193, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ + __pyx_tuple__34 = PyTuple_Pack(12, __pyx_n_s_center, __pyx_n_s_radius, __pyx_n_s_start_angle, __pyx_n_s_end_angle, __pyx_n_s_segments, __pyx_n_s_center_2, __pyx_n_s_tmp, __pyx_n_s_res, __pyx_n_s_i, __pyx_n_s_angle_span, __pyx_n_s_s, __pyx_n_s_control_points); if (unlikely(!__pyx_tuple__34)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__34); + __Pyx_GIVEREF(__pyx_tuple__34); + __pyx_codeobj__10 = (PyObject*)__Pyx_PyCode_New(5, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__34, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_cubic_bezier_from_arc, 228, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__10)) __PYX_ERR(0, 228, __pyx_L1_error) + + /* "ezdxf/acc/bezier4p.pyx":256 + * yield Bezier4P(res) + * + * def cubic_bezier_from_ellipse( # <<<<<<<<<<<<<< + * ellipse: ConstructionEllipse, + * int segments = 1 + */ + __pyx_tuple__35 = PyTuple_Pack(13, __pyx_n_s_ellipse, __pyx_n_s_segments, __pyx_n_s_param_span, __pyx_n_s_start_angle, __pyx_n_s_end_angle, __pyx_n_s_center, __pyx_n_s_x_axis, __pyx_n_s_y_axis, __pyx_n_s_cp, __pyx_n_s_c_res, __pyx_n_s_res, __pyx_n_s_control_points, __pyx_n_s_i); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__35); + __Pyx_GIVEREF(__pyx_tuple__35); + __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 13, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bezier4p_pyx, __pyx_n_s_cubic_bezier_from_ellipse, 256, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 256, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_codeobj__36 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__36)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_codeobj__37 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__30, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__37)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_128 = PyInt_FromLong(128); if (unlikely(!__pyx_int_128)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P)) __PYX_ERR(0, 40, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P = &__pyx_type_5ezdxf_3acc_8bezier4p_Bezier4P; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Bezier4P, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + __pyx_vtabptr_5ezdxf_3acc_8bezier4p__Flattening = &__pyx_vtable_5ezdxf_3acc_8bezier4p__Flattening; + __pyx_vtable_5ezdxf_3acc_8bezier4p__Flattening.has_recursion_error = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *))__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_has_recursion_error; + __pyx_vtable_5ezdxf_3acc_8bezier4p__Flattening.reset_recursion_check = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *))__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_reset_recursion_check; + __pyx_vtable_5ezdxf_3acc_8bezier4p__Flattening.flatten = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier4p__Flattening *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double))__pyx_f_5ezdxf_3acc_8bezier4p_11_Flattening_flatten; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p__Flattening_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening)) __PYX_ERR(0, 145, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p__Flattening_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening = &__pyx_type_5ezdxf_3acc_8bezier4p__Flattening; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening, __pyx_vtabptr_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Flattening, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier4p__Flattening) < 0) __PYX_ERR(0, 145, __pyx_L1_error) + #endif + __pyx_vtabptr_5ezdxf_3acc_8bezier4p_FastCubicCurve = &__pyx_vtable_5ezdxf_3acc_8bezier4p_FastCubicCurve; + __pyx_vtable_5ezdxf_3acc_8bezier4p_FastCubicCurve.point = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *, double))__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_point; + __pyx_vtable_5ezdxf_3acc_8bezier4p_FastCubicCurve.tangent = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8bezier4p_FastCubicCurve *, double))__pyx_f_5ezdxf_3acc_8bezier4p_14FastCubicCurve_tangent; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve)) __PYX_ERR(0, 295, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve = &__pyx_type_5ezdxf_3acc_8bezier4p_FastCubicCurve; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve, __pyx_vtabptr_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_FastCubicCurve, (PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_8bezier4p_FastCubicCurve) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters)) __PYX_ERR(0, 193, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters) < 0) __PYX_ERR(0, 193, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters = &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters) < 0) __PYX_ERR(0, 193, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct__cubic_bezier_arc_parameters->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc)) __PYX_ERR(0, 228, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc) < 0) __PYX_ERR(0, 228, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc = &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc) < 0) __PYX_ERR(0, 228, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_1_cubic_bezier_from_arc->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse)) __PYX_ERR(0, 256, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse_spec, __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse) < 0) __PYX_ERR(0, 256, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse = &__pyx_type_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse) < 0) __PYX_ERR(0, 256, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8bezier4p___pyx_scope_struct_2_cubic_bezier_from_ellipse->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.matrix44"); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.matrix44", "Matrix44", sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) __PYX_ERR(3, 6, __pyx_L1_error) + __pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44 = (struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44*)__Pyx_GetVtable(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); if (unlikely(!__pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44)) __PYX_ERR(3, 6, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "normalize_rad_angle", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle, "double (double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_add", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_mul", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_dist", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_dist, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_from_angle", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_from_angle, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_lerp", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_lerp, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_bezier4p(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_bezier4p}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "bezier4p", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initbezier4p(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initbezier4p(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_bezier4p(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_bezier4p(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_bezier4p(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'bezier4p' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("bezier4p", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "bezier4p" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_bezier4p(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__bezier4p) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.bezier4p")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.bezier4p", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/bezier4p.pyx":4 + * # Copyright (c) 2020-2024 Manfred Moitzi + * # License: MIT License + * from typing import TYPE_CHECKING, Sequence, Iterable, Iterator # <<<<<<<<<<<<<< + * import cython + * import warnings + */ + __pyx_t_2 = PyList_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterable); + __Pyx_GIVEREF(__pyx_n_s_Iterable); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_Iterable)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterator); + __Pyx_GIVEREF(__pyx_n_s_Iterator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_n_s_Iterator)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterable); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterable, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterator); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterator, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier4p.pyx":6 + * from typing import TYPE_CHECKING, Sequence, Iterable, Iterator + * import cython + * import warnings # <<<<<<<<<<<<<< + * from .vector cimport ( + * Vec3, + */ + __pyx_t_3 = __Pyx_ImportDottedModule(__pyx_n_s_warnings, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_warnings, __pyx_t_3) < 0) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier4p.pyx":20 + * from .matrix44 cimport Matrix44 + * from libc.math cimport ceil, tan, M_PI + * from .construct import arc_angle_span_deg # <<<<<<<<<<<<<< + * + * if TYPE_CHECKING: + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_arc_angle_span_deg); + __Pyx_GIVEREF(__pyx_n_s_arc_angle_span_deg); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_arc_angle_span_deg)) __PYX_ERR(0, 20, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_construct, __pyx_t_3, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_arc_angle_span_deg); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_arc_angle_span_deg, __pyx_t_3) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":22 + * from .construct import arc_angle_span_deg + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * from ezdxf.math.ellipse import ConstructionEllipse + */ + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 22, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__pyx_t_4) { + + /* "ezdxf/acc/bezier4p.pyx":23 + * + * if TYPE_CHECKING: + * from ezdxf.math import UVec # <<<<<<<<<<<<<< + * from ezdxf.math.ellipse import ConstructionEllipse + * + */ + __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_UVec)) __PYX_ERR(0, 23, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_UVec); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_2) < 0) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier4p.pyx":24 + * if TYPE_CHECKING: + * from ezdxf.math import UVec + * from ezdxf.math.ellipse import ConstructionEllipse # <<<<<<<<<<<<<< + * + * __all__ = [ + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_ConstructionEllipse); + __Pyx_GIVEREF(__pyx_n_s_ConstructionEllipse); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_ConstructionEllipse)) __PYX_ERR(0, 24, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_ezdxf_math_ellipse, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_ConstructionEllipse); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_ConstructionEllipse, __pyx_t_3) < 0) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":22 + * from .construct import arc_angle_span_deg + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * from ezdxf.math.ellipse import ConstructionEllipse + */ + } + + /* "ezdxf/acc/bezier4p.pyx":26 + * from ezdxf.math.ellipse import ConstructionEllipse + * + * __all__ = [ # <<<<<<<<<<<<<< + * 'Bezier4P', 'cubic_bezier_arc_parameters', + * 'cubic_bezier_from_arc', 'cubic_bezier_from_ellipse', + */ + __pyx_t_2 = PyList_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_u_Bezier4P); + __Pyx_GIVEREF(__pyx_n_u_Bezier4P); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_u_Bezier4P)) __PYX_ERR(0, 26, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_u_cubic_bezier_arc_parameters); + __Pyx_GIVEREF(__pyx_n_u_cubic_bezier_arc_parameters); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_u_cubic_bezier_arc_parameters)) __PYX_ERR(0, 26, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_u_cubic_bezier_from_arc); + __Pyx_GIVEREF(__pyx_n_u_cubic_bezier_from_arc); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_u_cubic_bezier_from_arc)) __PYX_ERR(0, 26, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_u_cubic_bezier_from_ellipse); + __Pyx_GIVEREF(__pyx_n_u_cubic_bezier_from_ellipse); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_n_u_cubic_bezier_from_ellipse)) __PYX_ERR(0, 26, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_all, __pyx_t_2) < 0) __PYX_ERR(0, 26, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":36 + * const double M_TAU + * + * cdef double DEG2RAD = M_PI / 180.0 # <<<<<<<<<<<<<< + * cdef double RECURSION_LIMIT = 1000 + * + */ + __pyx_v_5ezdxf_3acc_8bezier4p_DEG2RAD = (((double)M_PI) / 180.0); + + /* "ezdxf/acc/bezier4p.pyx":37 + * + * cdef double DEG2RAD = M_PI / 180.0 + * cdef double RECURSION_LIMIT = 1000 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_5ezdxf_3acc_8bezier4p_RECURSION_LIMIT = 1000.0; + + /* "ezdxf/acc/bezier4p.pyx":73 + * return self.start_point, self.cp1, self.cp2, self.end_point + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Bezier4P, (self.control_points,) + * + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_3__reduce__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P___reduce, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_reduce, __pyx_t_2) < 0) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":76 + * return Bezier4P, (self.control_points,) + * + * def point(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.point(t) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 76, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_5point, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_point, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_point, __pyx_t_3) < 0) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":82 + * raise ValueError("t not in range [0 to 1]") + * + * def tangent(self, double t) -> Vec3: # <<<<<<<<<<<<<< + * if 0.0 <= t <= 1.0: + * return self.curve.tangent(t) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 82, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_7tangent, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_tangent, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__18)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_tangent, __pyx_t_2) < 0) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":88 + * raise ValueError("t not in range [0 to 1]") + * + * def approximate(self, int segments) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double delta_t + * cdef int segment + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_list_Vec3) < 0) __PYX_ERR(0, 88, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_9approximate, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_approximate, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__20)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_approximate, __pyx_t_3) < 0) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":101 + * return points + * + * def flattening(self, double distance, int segments = 4) -> list[Vec3]: # <<<<<<<<<<<<<< + * cdef double dt = 1.0 / segments + * cdef double t0 = 0.0, t1 + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_list_Vec3) < 0) __PYX_ERR(0, 101, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_11flattening, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_flattening, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__22)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__23); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_flattening, __pyx_t_2) < 0) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":125 + * return f.points + * + * def approximated_length(self, segments: int = 128) -> float: # <<<<<<<<<<<<<< + * cdef double length = 0.0 + * cdef bint start_flag = 0 + */ + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_128)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_128))) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_128); + __pyx_k__5 = ((PyObject*)__pyx_int_128); + __Pyx_GIVEREF(__pyx_int_128); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_128)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_128))) __PYX_ERR(0, 125, __pyx_L1_error) + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_int_128); + __Pyx_GIVEREF(__pyx_int_128); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_int_128)) __PYX_ERR(0, 125, __pyx_L1_error); + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_segments, __pyx_n_s_int) < 0) __PYX_ERR(0, 125, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 125, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_13approximated_length, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_approximated_length, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__25)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_approximated_length, __pyx_t_5) < 0) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":138 + * return length + * + * def reverse(self) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Bezier4P) < 0) __PYX_ERR(0, 138, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_15reverse, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_reverse, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_reverse, __pyx_t_3) < 0) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "ezdxf/acc/bezier4p.pyx":141 + * return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + * + * def transform(self, Matrix44 m) -> Bezier4P: # <<<<<<<<<<<<<< + * return Bezier4P(tuple(m.transform_vertices(self.control_points))) + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Bezier4P) < 0) __PYX_ERR(0, 141, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_8Bezier4P_17transform, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Bezier4P_transform, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__28)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P, __pyx_n_s_transform, __pyx_t_5) < 0) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8bezier4p_Bezier4P); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_11_Flattening_3__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Flattening___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__29)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_5) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_11_Flattening_5__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Flattening___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__31)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_5) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/bezier4p.pyx":189 + * self._recursion_level -= 1 + * + * cdef double DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 # <<<<<<<<<<<<<< + * cdef double OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + */ + __pyx_v_5ezdxf_3acc_8bezier4p_DEFAULT_TANGENT_FACTOR = (4.0 / 3.0); + + /* "ezdxf/acc/bezier4p.pyx":190 + * + * cdef double DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 + * cdef double OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935 # <<<<<<<<<<<<<< + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + */ + __pyx_v_5ezdxf_3acc_8bezier4p_OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935; + + /* "ezdxf/acc/bezier4p.pyx":191 + * cdef double DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 + * cdef double OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR # <<<<<<<<<<<<<< + * + * @cython.cdivision(True) + */ + __pyx_v_5ezdxf_3acc_8bezier4p_TANGENT_FACTOR = __pyx_v_5ezdxf_3acc_8bezier4p_DEFAULT_TANGENT_FACTOR; + + /* "ezdxf/acc/bezier4p.pyx":197 + * double start_angle, + * double end_angle, + * int segments = 1, # <<<<<<<<<<<<<< + * ) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + * if segments < 1: + */ + __pyx_t_5 = __Pyx_PyInt_From_int(((int)1)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 197, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "ezdxf/acc/bezier4p.pyx":193 + * cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + * + * @cython.cdivision(True) # <<<<<<<<<<<<<< + * def cubic_bezier_arc_parameters( + * double start_angle, + */ + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_5)) __PYX_ERR(0, 193, __pyx_L1_error); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_Iterator_tuple_Vec3_Vec3_Vec3_Ve) < 0) __PYX_ERR(0, 193, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_1cubic_bezier_arc_parameters, 0, __pyx_n_s_cubic_bezier_arc_parameters, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__6)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_cubic_bezier_arc_parameters, __pyx_t_2) < 0) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bezier4p.pyx":230 + * def cubic_bezier_from_arc( + * center = (0, 0), + * double radius = 1.0, # <<<<<<<<<<<<<< + * double start_angle = 0.0, + * double end_angle = 360.0, + */ + __pyx_t_2 = PyFloat_FromDouble(((double)1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 230, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "ezdxf/acc/bezier4p.pyx":231 + * center = (0, 0), + * double radius = 1.0, + * double start_angle = 0.0, # <<<<<<<<<<<<<< + * double end_angle = 360.0, + * int segments = 1 + */ + __pyx_t_5 = PyFloat_FromDouble(((double)0.0)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 231, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "ezdxf/acc/bezier4p.pyx":232 + * double radius = 1.0, + * double start_angle = 0.0, + * double end_angle = 360.0, # <<<<<<<<<<<<<< + * int segments = 1 + * ) -> Iterable[Bezier4P]: + */ + __pyx_t_3 = PyFloat_FromDouble(((double)360.0)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "ezdxf/acc/bezier4p.pyx":233 + * double start_angle = 0.0, + * double end_angle = 360.0, + * int segments = 1 # <<<<<<<<<<<<<< + * ) -> Iterable[Bezier4P]: + * cdef Vec3 center_ = Vec3(center) + */ + __pyx_t_6 = __Pyx_PyInt_From_int(((int)1)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 233, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "ezdxf/acc/bezier4p.pyx":228 + * yield start_point, cp1, cp2, end_point + * + * def cubic_bezier_from_arc( # <<<<<<<<<<<<<< + * center = (0, 0), + * double radius = 1.0, + */ + __pyx_t_7 = PyTuple_New(5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(((PyObject*)__pyx_tuple__9)); + __Pyx_GIVEREF(((PyObject*)__pyx_tuple__9)); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject*)__pyx_tuple__9))) __PYX_ERR(0, 228, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_2)) __PYX_ERR(0, 228, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 2, __pyx_t_5)) __PYX_ERR(0, 228, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 3, __pyx_t_3)) __PYX_ERR(0, 228, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 4, __pyx_t_6)) __PYX_ERR(0, 228, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_5 = 0; + __pyx_t_3 = 0; + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_return, __pyx_kp_s_Iterable_Bezier4P) < 0) __PYX_ERR(0, 228, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_4cubic_bezier_from_arc, 0, __pyx_n_s_cubic_bezier_from_arc, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__10)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_cubic_bezier_from_arc, __pyx_t_3) < 0) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bezier4p.pyx":258 + * def cubic_bezier_from_ellipse( + * ellipse: ConstructionEllipse, + * int segments = 1 # <<<<<<<<<<<<<< + * ) -> Iterator[Bezier4P]: + * cdef double param_span = ellipse.param_span + */ + __pyx_t_3 = __Pyx_PyInt_From_int(((int)1)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 258, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "ezdxf/acc/bezier4p.pyx":256 + * yield Bezier4P(res) + * + * def cubic_bezier_from_ellipse( # <<<<<<<<<<<<<< + * ellipse: ConstructionEllipse, + * int segments = 1 + */ + __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3)) __PYX_ERR(0, 256, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_ellipse, __pyx_n_s_ConstructionEllipse) < 0) __PYX_ERR(0, 256, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Iterator_Bezier4P) < 0) __PYX_ERR(0, 256, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_7cubic_bezier_from_ellipse, 0, __pyx_n_s_cubic_bezier_from_ellipse, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_7, __pyx_t_6); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_cubic_bezier_from_ellipse, __pyx_t_7) < 0) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_14FastCubicCurve_3__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_FastCubicCurve___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__36)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_7) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8bezier4p_14FastCubicCurve_5__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_FastCubicCurve___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bezier4p, __pyx_d, ((PyObject *)__pyx_codeobj__37)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_7) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/bezier4p.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2020-2024 Manfred Moitzi + * # License: MIT License + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_7) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.bezier4p", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.bezier4p"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc; + __Pyx_PyThreadState_declare + #ifdef __Pyx_StopAsyncIteration_USED + int is_async_stopiteration = 0; + #endif + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + cur_exc = PyErr_Occurred(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + #ifdef __Pyx_StopAsyncIteration_USED + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else + #endif + return; + } + __Pyx_PyThreadState_assign + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + PyErr_SetString(PyExc_RuntimeError, + #ifdef __Pyx_StopAsyncIteration_USED + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + #endif + "generator raised StopIteration"); +} + +/* ModFloat[double] */ +static CYTHON_INLINE double __Pyx_mod_double(double a, double b) { + double r = fmod(a, b); + r += ((r != 0) & ((r < 0) ^ (b < 0))) * b; + return r; +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__12); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* ImportDottedModule */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { + PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; + if (unlikely(PyErr_Occurred())) { + PyErr_Clear(); + } + if (likely(PyTuple_GET_SIZE(parts_tuple) == count)) { + partial_name = name; + } else { + slice = PySequence_GetSlice(parts_tuple, 0, count); + if (unlikely(!slice)) + goto bad; + sep = PyUnicode_FromStringAndSize(".", 1); + if (unlikely(!sep)) + goto bad; + partial_name = PyUnicode_Join(sep, slice); + } + PyErr_Format( +#if PY_MAJOR_VERSION < 3 + PyExc_ImportError, + "No module named '%s'", PyString_AS_STRING(partial_name)); +#else +#if PY_VERSION_HEX >= 0x030600B1 + PyExc_ModuleNotFoundError, +#else + PyExc_ImportError, +#endif + "No module named '%U'", partial_name); +#endif +bad: + Py_XDECREF(sep); + Py_XDECREF(slice); + Py_XDECREF(partial_name); + return NULL; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { + PyObject *imported_module; +#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + return NULL; + imported_module = __Pyx_PyDict_GetItemStr(modules, name); + Py_XINCREF(imported_module); +#else + imported_module = PyImport_GetModule(name); +#endif + return imported_module; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { + Py_ssize_t i, nparts; + nparts = PyTuple_GET_SIZE(parts_tuple); + for (i=1; i < nparts && module; i++) { + PyObject *part, *submodule; +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + part = PyTuple_GET_ITEM(parts_tuple, i); +#else + part = PySequence_ITEM(parts_tuple, i); +#endif + submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); +#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(part); +#endif + Py_DECREF(module); + module = submodule; + } + if (unlikely(!module)) { + return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); + } + return module; +} +#endif +static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if PY_MAJOR_VERSION < 3 + PyObject *module, *from_list, *star = __pyx_n_s__13; + CYTHON_UNUSED_VAR(parts_tuple); + from_list = PyList_New(1); + if (unlikely(!from_list)) + return NULL; + Py_INCREF(star); + PyList_SET_ITEM(from_list, 0, star); + module = __Pyx_Import(name, from_list, 0); + Py_DECREF(from_list); + return module; +#else + PyObject *imported_module; + PyObject *module = __Pyx_Import(name, NULL, 0); + if (!parts_tuple || unlikely(!module)) + return module; + imported_module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(imported_module)) { + Py_DECREF(module); + return imported_module; + } + PyErr_Clear(); + return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); +#endif +} +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1 + PyObject *module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(module)) { + PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_n_s_spec); + if (likely(spec)) { + PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_n_s_initializing); + if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { + Py_DECREF(spec); + spec = NULL; + } + Py_XDECREF(unsafe); + } + if (likely(!spec)) { + PyErr_Clear(); + return module; + } + Py_DECREF(spec); + Py_DECREF(module); + } else if (PyErr_Occurred()) { + PyErr_Clear(); + } +#endif + return __Pyx__ImportDottedModule(name, parts_tuple); +} + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__38); + } + return name; +} +#endif + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; iexc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* PyObjectCall2Args */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 */ +#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2 + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_GetMethod; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* CoroutineBase */ +#include +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } +#if PY_VERSION_HEX >= 0x030300A0 + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); + } +#endif + else if (unlikely(PyTuple_Check(ev))) { + if (PyTuple_GET_SIZE(ev) >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#else + value = PySequence_ITEM(ev, 0); +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if PY_VERSION_HEX >= 0x030300A0 + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); +#else + { + PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args); + Py_DECREF(ev); + if (likely(args)) { + value = PySequence_GetItem(args, 0); + Py_DECREF(args); + } + if (unlikely(!value)) { + __Pyx_ErrRestore(NULL, NULL, NULL); + Py_INCREF(Py_None); + value = Py_None; + } + } +#endif + *pvalue = value; + return 0; +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +#define __Pyx_Coroutine_NotStartedError(gen) (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_NotStartedError(PyObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(gen)) { + msg = "can't send non-None value to a just-started coroutine"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a just-started async generator"; + #endif + } else { + msg = "can't send non-None value to a just-started generator"; + } + PyErr_SetString(PyExc_TypeError, msg); +} +#define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing) (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(!self->is_running); + if (unlikely(self->resume_label == 0)) { + if (unlikely(value && value != Py_None)) { + return __Pyx_Coroutine_NotStartedError((PyObject*)self); + } + } + if (unlikely(self->resume_label == -1)) { + return __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + self->is_running = 1; + retval = self->body(self, tstate, value); + self->is_running = 0; +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + return retval; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_MethodReturn(PyObject* gen, PyObject *retval) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (unlikely(!retval)) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (!__Pyx_PyErr_Occurred()) { + PyObject *exc = PyExc_StopIteration; + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + exc = __Pyx_PyExc_StopAsyncIteration; + #endif + __Pyx_PyErr_SetNone(exc); + } + } + return retval; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) { + PyObject *ret; + PyObject *val = NULL; + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + ret = __Pyx_Coroutine_SendEx(gen, val, 0); + Py_XDECREF(val); + return ret; +} +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03050000 && defined(PyCoro_CheckExact) && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + { + if (value == Py_None) + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + else + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value); + } + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + retval = __Pyx_Coroutine_FinishDelegation(gen); + } else { + retval = __Pyx_Coroutine_SendEx(gen, value, 0); + } + return __Pyx_Coroutine_MethodReturn(self, retval); +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + PyObject *retval = NULL; + int err = 0; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + retval = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf, NULL); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + } else + #endif + { + PyObject *meth; + gen->is_running = 1; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) + err = -1; + } + gen->is_running = 0; + } + Py_XDECREF(retval); + return err; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + return __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_SendEx(gen, Py_None, 0); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + return __Pyx_Coroutine_Close(self); +} +static PyObject *__Pyx_Coroutine_Close(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *retval, *raised_exception; + PyObject *yf = gen->yieldfrom; + int err = 0; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = __Pyx_Coroutine_SendEx(gen, NULL, 1); + if (unlikely(retval)) { + const char *msg; + Py_DECREF(retval); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { +#if PY_VERSION_HEX < 0x03060000 + msg = "async generator ignored GeneratorExit - might require Python 3.6+ finalisation (PEP 525)"; +#else + msg = "async generator ignored GeneratorExit"; +#endif + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + return NULL; + } + raised_exception = PyErr_Occurred(); + if (likely(!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration))) { + if (raised_exception) PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); + goto throw_here; + } + gen->is_running = 1; + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + gen->is_running = 0; + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + gen->is_running = 0; + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + gen->is_running = 0; + Py_DECREF(yf); + if (!ret) { + ret = __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_MethodReturn(self, ret); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + Py_CLEAR(gen->yieldfrom); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if PY_VERSION_HEX >= 0x030400a1 && CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + Py_TYPE(gen)->tp_del(self); + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } +#if !CYTHON_USE_TP_FINALIZE + assert(self->ob_refcnt == 0); + __Pyx_SET_REFCNT(self, 1); +#endif + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); +#if PY_MAJOR_VERSION >= 3 || defined(PyErr_WarnFormat) + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); +#else + {PyObject *msg; + char *cmsg; + #if CYTHON_COMPILING_IN_PYPY + msg = NULL; + cmsg = (char*) "coroutine was never awaited"; + #else + char *cname; + PyObject *qualname; + qualname = gen->gi_qualname; + cname = PyString_AS_STRING(qualname); + msg = PyString_FromFormat("coroutine '%.50s' was never awaited", cname); + if (unlikely(!msg)) { + PyErr_Clear(); + cmsg = (char*) "coroutine was never awaited"; + } else { + cmsg = PyString_AS_STRING(msg); + } + #endif + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, cmsg, 1) < 0)) + PyErr_WriteUnraisable(self); + Py_XDECREF(msg);} +#endif + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *res = __Pyx_Coroutine_Close(self); + if (unlikely(!res)) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +#if !CYTHON_USE_TP_FINALIZE + assert(Py_REFCNT(self) > 0); + if (likely(--self->ob_refcnt == 0)) { + return; + } + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReference(self); + __Pyx_SET_REFCNT(self, refcnt); + } +#if CYTHON_COMPILING_IN_CPYTHON + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + _Py_DEC_REFTOTAL; +#endif +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif +#endif +} +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) +{ + PyObject *frame = self->gi_frame; + CYTHON_UNUSED_VAR(context); + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (unlikely(!frame)) + return NULL; + self->gi_frame = frame; + } + Py_INCREF(frame); + return frame; +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif + gen->gi_weakreflist = NULL; + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} + +/* PatchModuleWithCoroutine */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + int result; + PyObject *globals, *result_obj; + globals = PyDict_New(); if (unlikely(!globals)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_coroutine_type", + #ifdef __Pyx_Coroutine_USED + (PyObject*)__pyx_CoroutineType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_generator_type", + #ifdef __Pyx_Generator_USED + (PyObject*)__pyx_GeneratorType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore; + result_obj = PyRun_String(py_code, Py_file_input, globals, globals); + if (unlikely(!result_obj)) goto ignore; + Py_DECREF(result_obj); + Py_DECREF(globals); + return module; +ignore: + Py_XDECREF(globals); + PyErr_WriteUnraisable(module); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) { + Py_DECREF(module); + module = NULL; + } +#else + py_code++; +#endif + return module; +} + +/* PatchGeneratorABC */ +#ifndef CYTHON_REGISTER_ABCS +#define CYTHON_REGISTER_ABCS 1 +#endif +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) +static PyObject* __Pyx_patch_abc_module(PyObject *module); +static PyObject* __Pyx_patch_abc_module(PyObject *module) { + module = __Pyx_Coroutine_patch_module( + module, "" +"if _cython_generator_type is not None:\n" +" try: Generator = _module.Generator\n" +" except AttributeError: pass\n" +" else: Generator.register(_cython_generator_type)\n" +"if _cython_coroutine_type is not None:\n" +" try: Coroutine = _module.Coroutine\n" +" except AttributeError: pass\n" +" else: Coroutine.register(_cython_coroutine_type)\n" + ); + return module; +} +#endif +static int __Pyx_patch_abc(void) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + static int abc_patched = 0; + if (CYTHON_REGISTER_ABCS && !abc_patched) { + PyObject *module; + module = PyImport_ImportModule((PY_MAJOR_VERSION >= 3) ? "collections.abc" : "collections"); + if (unlikely(!module)) { + PyErr_WriteUnraisable(NULL); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, + ((PY_MAJOR_VERSION >= 3) ? + "Cython module failed to register with collections.abc module" : + "Cython module failed to register with collections module"), 1) < 0)) { + return -1; + } + } else { + module = __Pyx_patch_abc_module(module); + abc_patched = 1; + if (unlikely(!module)) + return -1; + Py_DECREF(module); + } + module = PyImport_ImportModule("backports_abc"); + if (module) { + module = __Pyx_patch_abc_module(module); + Py_XDECREF(module); + } + if (!module) { + PyErr_Clear(); + } + } +#else + if ((0)) __Pyx_Coroutine_patch_module(NULL, NULL); +#endif + return 0; +} + +/* Generator */ +static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL}, + {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, + {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + (char*) PyDoc_STR("name of the generator"), 0}, + {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + (char*) PyDoc_STR("qualified name of the generator"), 0}, + {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + (char*) PyDoc_STR("Frame of the generator"), 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + __pyx_GeneratorType_slots +}; +#else +static PyTypeObject __pyx_GeneratorType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + (destructor) __Pyx_Coroutine_dealloc, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + 0, + (traverseproc) __Pyx_Coroutine_traverse, + 0, + 0, + offsetof(__pyx_CoroutineObject, gi_weakreflist), + 0, + (iternextfunc) __Pyx_Generator_Next, + __pyx_Generator_methods, + __pyx_Generator_memberlist, + __pyx_Generator_getsets, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if CYTHON_USE_TP_FINALIZE + 0, +#else + __Pyx_Coroutine_del, +#endif + 0, +#if CYTHON_USE_TP_FINALIZE + __Pyx_Coroutine_del, +#elif PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; + __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif + if (unlikely(!__pyx_GeneratorType)) { + return -1; + } + return 0; +} + +/* CheckBinaryVersion */ +static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ +#ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.cpython-312-darwin.so new file mode 100755 index 0000000..cb7bd6c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.pyx new file mode 100644 index 0000000..c4a6395 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bezier4p.pyx @@ -0,0 +1,371 @@ +# cython: language_level=3 +# Copyright (c) 2020-2024 Manfred Moitzi +# License: MIT License +from typing import TYPE_CHECKING, Sequence, Iterable, Iterator +import cython +import warnings +from .vector cimport ( + Vec3, + Vec2, + isclose, + v3_add, + v3_mul, + v3_dist, + v3_lerp, + v3_from_angle, + normalize_rad_angle, +) +from .matrix44 cimport Matrix44 +from libc.math cimport ceil, tan, M_PI +from .construct import arc_angle_span_deg + +if TYPE_CHECKING: + from ezdxf.math import UVec + from ezdxf.math.ellipse import ConstructionEllipse + +__all__ = [ + 'Bezier4P', 'cubic_bezier_arc_parameters', + 'cubic_bezier_from_arc', 'cubic_bezier_from_ellipse', +] + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + const double M_TAU + +cdef double DEG2RAD = M_PI / 180.0 +cdef double RECURSION_LIMIT = 1000 + + +cdef class Bezier4P: + cdef: + FastCubicCurve curve # pyright: ignore + readonly Vec3 start_point + Vec3 cp1 + Vec3 cp2 + readonly Vec3 end_point + + def __cinit__(self, defpoints: Sequence[UVec]): + if not isinstance(defpoints[0], (Vec2, Vec3)): + warnings.warn( + DeprecationWarning, + "Bezier4P requires defpoints of type Vec2 or Vec3 in the future", + ) + if len(defpoints) == 4: + self.start_point = Vec3(defpoints[0]) + self.cp1 = Vec3(defpoints[1]) + self.cp2 = Vec3(defpoints[2]) + self.end_point = Vec3(defpoints[3]) + + self.curve = FastCubicCurve( + self.start_point, + self.cp1, + self.cp2, + self.end_point + ) + else: + raise ValueError("Four control points required.") + + @property + def control_points(self) -> tuple[Vec3, Vec3, Vec3, Vec3]: + return self.start_point, self.cp1, self.cp2, self.end_point + + def __reduce__(self): + return Bezier4P, (self.control_points,) + + def point(self, double t) -> Vec3: + if 0.0 <= t <= 1.0: + return self.curve.point(t) + else: + raise ValueError("t not in range [0 to 1]") + + def tangent(self, double t) -> Vec3: + if 0.0 <= t <= 1.0: + return self.curve.tangent(t) + else: + raise ValueError("t not in range [0 to 1]") + + def approximate(self, int segments) -> list[Vec3]: + cdef double delta_t + cdef int segment + cdef list points = [self.start_point] + + if segments < 1: + raise ValueError(segments) + delta_t = 1.0 / segments + for segment in range(1, segments): + points.append(self.curve.point(delta_t * segment)) + points.append(self.end_point) + return points + + def flattening(self, double distance, int segments = 4) -> list[Vec3]: + cdef double dt = 1.0 / segments + cdef double t0 = 0.0, t1 + cdef _Flattening f = _Flattening(self, distance) + cdef Vec3 start_point = self.start_point + cdef Vec3 end_point + while t0 < 1.0: + t1 = t0 + dt + if isclose(t1, 1.0, REL_TOL, ABS_TOL): + end_point = self.end_point + t1 = 1.0 + else: + end_point = self.curve.point(t1) + f.reset_recursion_check() + f.flatten(start_point, end_point, t0, t1) + if f.has_recursion_error(): + raise RecursionError( + "Bezier4P flattening error, check for very large coordinates" + ) + t0 = t1 + start_point = end_point + + return f.points + + def approximated_length(self, segments: int = 128) -> float: + cdef double length = 0.0 + cdef bint start_flag = 0 + cdef Vec3 prev_point, point + + for point in self.approximate(segments): + if start_flag: + length += v3_dist(prev_point, point) + else: + start_flag = 1 + prev_point = point + return length + + def reverse(self) -> Bezier4P: + return Bezier4P((self.end_point, self.cp2, self.cp1, self.start_point)) + + def transform(self, Matrix44 m) -> Bezier4P: + return Bezier4P(tuple(m.transform_vertices(self.control_points))) + + +cdef class _Flattening: + cdef FastCubicCurve curve # pyright: ignore + cdef double distance + cdef list points + cdef int _recursion_level + cdef int _recursion_error + + def __cinit__(self, Bezier4P curve, double distance): + self.curve = curve.curve + self.distance = distance + self.points = [curve.start_point] + self._recursion_level = 0 + self._recursion_error = 0 + + cdef has_recursion_error(self): + return self._recursion_error + + cdef reset_recursion_check(self): + self._recursion_level = 0 + self._recursion_error = 0 + + cdef flatten( + self, + Vec3 start_point, + Vec3 end_point, + double start_t, + double end_t + ): + # Keep in sync with CPython implementation: ezdxf/math/_bezier4p.py + # Test suite: 630a + if self._recursion_level > RECURSION_LIMIT: + self._recursion_error = 1 + return + self._recursion_level += 1 + cdef double mid_t = (start_t + end_t) * 0.5 + cdef Vec3 mid_point = self.curve.point(mid_t) + cdef double d = v3_dist(mid_point, v3_lerp(start_point, end_point, 0.5)) + if d < self.distance: + self.points.append(end_point) + else: + self.flatten(start_point, mid_point, start_t, mid_t) + self.flatten(mid_point, end_point, mid_t, end_t) + self._recursion_level -= 1 + +cdef double DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 +cdef double OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935 +cdef double TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + +@cython.cdivision(True) +def cubic_bezier_arc_parameters( + double start_angle, + double end_angle, + int segments = 1, +) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + if segments < 1: + raise ValueError('Invalid argument segments (>= 1).') + cdef double delta_angle = end_angle - start_angle + cdef int arc_count + if delta_angle > 0: + arc_count = ceil(delta_angle / M_PI * 2.0) + if segments > arc_count: + arc_count = segments + else: + raise ValueError('Delta angle from start- to end angle has to be > 0.') + + cdef double segment_angle = delta_angle / arc_count + cdef double tangent_length = TANGENT_FACTOR * tan(segment_angle / 4.0) + cdef double angle = start_angle + cdef Vec3 start_point, end_point, cp1, cp2 + end_point = v3_from_angle(angle, 1.0) + + for _ in range(arc_count): + start_point = end_point + angle += segment_angle + end_point = v3_from_angle(angle, 1.0) + cp1 = Vec3() + cp1.x = start_point.x - start_point.y * tangent_length + cp1.y = start_point.y + start_point.x * tangent_length + cp2 = Vec3() + cp2.x = end_point.x + end_point.y * tangent_length + cp2.y = end_point.y - end_point.x * tangent_length + yield start_point, cp1, cp2, end_point + +def cubic_bezier_from_arc( + center = (0, 0), + double radius = 1.0, + double start_angle = 0.0, + double end_angle = 360.0, + int segments = 1 +) -> Iterable[Bezier4P]: + cdef Vec3 center_ = Vec3(center) + cdef Vec3 tmp + cdef list res + cdef int i + cdef double angle_span = arc_angle_span_deg(start_angle, end_angle) + if abs(angle_span) < 1e-9: + return + + cdef double s = start_angle + start_angle = (s * DEG2RAD) % M_TAU + end_angle = (s + angle_span) * DEG2RAD + while start_angle > end_angle: + end_angle += M_TAU + + for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + res = [] + for i in range(4): + tmp = control_points[i] + res.append(v3_add(center_, v3_mul(tmp, radius))) + yield Bezier4P(res) + +def cubic_bezier_from_ellipse( + ellipse: ConstructionEllipse, + int segments = 1 +) -> Iterator[Bezier4P]: + cdef double param_span = ellipse.param_span + if abs(param_span) < 1e-9: + return + + cdef double start_angle = normalize_rad_angle(ellipse.start_param) + cdef double end_angle = start_angle + param_span + + while start_angle > end_angle: + end_angle += M_TAU + + cdef Vec3 center = Vec3(ellipse.center) + cdef Vec3 x_axis = Vec3(ellipse.major_axis) + cdef Vec3 y_axis = Vec3(ellipse.minor_axis) + cdef Vec3 cp + cdef Vec3 c_res + cdef list res + for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + res = list() + for i in range(4): + cp = control_points[i] + c_res = v3_add_3(center, v3_mul(x_axis, cp.x), v3_mul(y_axis, cp.y)) + res.append(c_res) + yield Bezier4P(res) + + +cdef Vec3 v3_add_3(Vec3 a, Vec3 b, Vec3 c): + cdef Vec3 result = Vec3() + + result.x = a.x + b.x + c.x + result.y = a.y + b.y + c.y + result.z = a.z + b.z + c.z + + return result + + +cdef class FastCubicCurve: + cdef: + double[3] offset + double[3] p1 + double[3] p2 + double[3] p3 + + def __cinit__(self, Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3): + cdef: + double x = p0.x + double y = p0.y + double z = p0.z + + self.offset[0] = x + self.offset[1] = y + self.offset[2] = z + + # 1st control point (p0) is always (0, 0, 0) + self.p1[0] = p1.x - x + self.p1[1] = p1.y - y + self.p1[2] = p1.z - z + + self.p2[0] = p2.x - x + self.p2[1] = p2.y - y + self.p2[2] = p2.z - z + + self.p3[0] = p3.x - x + self.p3[1] = p3.y - y + self.p3[2] = p3.z - z + + + cdef Vec3 point(self, double t): + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + cdef: + Vec3 result = Vec3() + double t2 = t * t + double _1_minus_t = 1.0 - t + # a = (1 - t) ** 3 + double b = 3.0 * _1_minus_t * _1_minus_t * t + double c = 3.0 * _1_minus_t * t2 + double d = t2 * t + + iadd_mul(result, self.p1, b) + iadd_mul(result, self.p2, c) + iadd_mul(result, self.p3, d) + + # add offset at last - it is maybe very large + result.x += self.offset[0] + result.y += self.offset[1] + result.z += self.offset[2] + + return result + + + cdef Vec3 tangent(self, double t): + # tangent vector is independent from offset location! + cdef: + Vec3 result = Vec3() + double t2 = t * t + # a = -3 * (1 - t) ** 2 + double b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) + double c = 3.0 * t * (2.0 - 3.0 * t) + double d = 3.0 * t2 + + iadd_mul(result, self.p1, b) + iadd_mul(result, self.p2, c) + iadd_mul(result, self.p3, d) + + return result + + +cdef void iadd_mul(Vec3 a, double[3] b, double c): + a.x += b[0] * c + a.y += b[1] * c + a.z += b[2] * c + diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.c new file mode 100644 index 0000000..091376e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.c @@ -0,0 +1,19393 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.bspline", + "sources": [ + "src/ezdxf/acc/bspline.pyx" + ] + }, + "module_name": "ezdxf.acc.bspline" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__bspline +#define __PYX_HAVE_API__ezdxf__acc__bspline +/* Early includes */ +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/bspline.pyx", + "", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_7bspline_Basis; +struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator; +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr; +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr; +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points; +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives; +struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives; +struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative; + +/* "ezdxf/acc/bspline.pyx":200 + * return NULL_LIST * len(nbasis) + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): # <<<<<<<<<<<<<< + * # pyright: reportUndefinedVariable=false + * # pyright flags Cython multi-arrays incorrect: + */ +struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives { + int __pyx_n; + int n; +}; + +/* "ezdxf/acc/bspline.pyx":339 + * yield self.point(u) + * + * cpdef list derivative(self, double u, int n = 1): # <<<<<<<<<<<<<< + * """ Return point and derivatives up to n <= degree for parameter u. """ + * # Source: The NURBS Book: Algorithm A3.2 + */ +struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative { + int __pyx_n; + int n; +}; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "ezdxf/acc/bspline.pyx":54 + * a[i] = value + * + * cdef class Basis: # <<<<<<<<<<<<<< + * """ Immutable Basis function class. """ + * # public: + */ +struct __pyx_obj_5ezdxf_3acc_7bspline_Basis { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *__pyx_vtab; + int order; + int count; + double max_t; + PyObject *weights_; + double *_knots; + int knot_count; +}; + + +/* "ezdxf/acc/bspline.pyx":303 + * return result + * + * cdef class Evaluator: # <<<<<<<<<<<<<< + * """ B-spline curve point and curve derivative evaluator. """ + * cdef Basis _basis + */ +struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator *__pyx_vtab; + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *_basis; + PyObject *_control_points; +}; + + +/* "ezdxf/acc/bspline.pyx":78 + * self.count = count + * self.knot_count = self.order + self.count + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() # <<<<<<<<<<<<<< + * + * cdef Py_ssize_t i = len(self.weights_) + */ +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr { + PyObject_HEAD + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_x; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/bspline.pyx":102 + * @property + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) # <<<<<<<<<<<<<< + * + * @property + */ +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr { + PyObject_HEAD + double *__pyx_genexpr_arg_0; + int __pyx_genexpr_arg_1; + double __pyx_v_x; + double *__pyx_t_0; + double *__pyx_t_1; + double *__pyx_t_2; +}; + + +/* "ezdxf/acc/bspline.pyx":334 + * return v3_sum + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self; + PyObject *__pyx_v_t; + double __pyx_v_u; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/bspline.pyx":397 + * return CK + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ +struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives { + PyObject_HEAD + int __pyx_v_n; + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self; + PyObject *__pyx_v_t; + double __pyx_v_u; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + + +/* "ezdxf/acc/bspline.pyx":54 + * a[i] = value + * + * cdef class Basis: # <<<<<<<<<<<<<< + * """ Immutable Basis function class. """ + * # public: + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis { + PyObject *(*basis_vector)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, double, int __pyx_skip_dispatch); + int (*find_span)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, double, int __pyx_skip_dispatch); + PyObject *(*basis_funcs)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, int, double, int __pyx_skip_dispatch); + PyObject *(*span_weighting)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, PyObject *, int, int __pyx_skip_dispatch); + PyObject *(*basis_funcs_derivatives)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, int, double, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives *__pyx_optional_args); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *__pyx_vtabptr_5ezdxf_3acc_7bspline_Basis; + + +/* "ezdxf/acc/bspline.pyx":303 + * return result + * + * cdef class Evaluator: # <<<<<<<<<<<<<< + * """ B-spline curve point and curve derivative evaluator. """ + * cdef Basis _basis + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*point)(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *, double, int __pyx_skip_dispatch); + PyObject *(*derivative)(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *, double, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative *__pyx_optional_args); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator *__pyx_vtabptr_5ezdxf_3acc_7bspline_Evaluator; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* DivInt[long].proto */ +static CYTHON_INLINE long __Pyx_div_long(long, long); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* pybytes_as_double.proto */ +static double __Pyx_SlowPyString_AsDouble(PyObject *obj); +static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length); +static CYTHON_INLINE double __Pyx_PyBytes_AsDouble(PyObject *obj) { + char* as_c_string; + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + as_c_string = PyBytes_AS_STRING(obj); + size = PyBytes_GET_SIZE(obj); +#else + if (PyBytes_AsStringAndSize(obj, &as_c_string, &size) < 0) { + return (double)-1; + } +#endif + return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); +} +static CYTHON_INLINE double __Pyx_PyByteArray_AsDouble(PyObject *obj) { + char* as_c_string; + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + as_c_string = PyByteArray_AS_STRING(obj); + size = PyByteArray_GET_SIZE(obj); +#else + as_c_string = PyByteArray_AsString(obj); + if (as_c_string == NULL) { + return (double)-1; + } + size = PyByteArray_Size(obj); +#endif + return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); +} + +/* pyunicode_as_double.proto */ +#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS +static const char* __Pyx__PyUnicode_AsDouble_Copy(const void* data, const int kind, char* buffer, Py_ssize_t start, Py_ssize_t end) { + int last_was_punctuation; + Py_ssize_t i; + last_was_punctuation = 1; + for (i=start; i <= end; i++) { + Py_UCS4 chr = PyUnicode_READ(kind, data, i); + int is_punctuation = (chr == '_') | (chr == '.'); + *buffer = (char)chr; + buffer += (chr != '_'); + if (unlikely(chr > 127)) goto parse_failure; + if (unlikely(last_was_punctuation & is_punctuation)) goto parse_failure; + last_was_punctuation = is_punctuation; + } + if (unlikely(last_was_punctuation)) goto parse_failure; + *buffer = '\0'; + return buffer; +parse_failure: + return NULL; +} +static double __Pyx__PyUnicode_AsDouble_inf_nan(const void* data, int kind, Py_ssize_t start, Py_ssize_t length) { + int matches = 1; + Py_UCS4 chr; + Py_UCS4 sign = PyUnicode_READ(kind, data, start); + int is_signed = (sign == '-') | (sign == '+'); + start += is_signed; + length -= is_signed; + switch (PyUnicode_READ(kind, data, start)) { + #ifdef Py_NAN + case 'n': + case 'N': + if (unlikely(length != 3)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+1); + matches &= (chr == 'a') | (chr == 'A'); + chr = PyUnicode_READ(kind, data, start+2); + matches &= (chr == 'n') | (chr == 'N'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_NAN : Py_NAN; + #endif + case 'i': + case 'I': + if (unlikely(length < 3)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+1); + matches &= (chr == 'n') | (chr == 'N'); + chr = PyUnicode_READ(kind, data, start+2); + matches &= (chr == 'f') | (chr == 'F'); + if (likely(length == 3 && matches)) + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + if (unlikely(length != 8)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+3); + matches &= (chr == 'i') | (chr == 'I'); + chr = PyUnicode_READ(kind, data, start+4); + matches &= (chr == 'n') | (chr == 'N'); + chr = PyUnicode_READ(kind, data, start+5); + matches &= (chr == 'i') | (chr == 'I'); + chr = PyUnicode_READ(kind, data, start+6); + matches &= (chr == 't') | (chr == 'T'); + chr = PyUnicode_READ(kind, data, start+7); + matches &= (chr == 'y') | (chr == 'Y'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + break; + default: + goto parse_failure; + } + return 0.0; +parse_failure: + return -1.0; +} +static double __Pyx_PyUnicode_AsDouble_WithSpaces(PyObject *obj) { + double value; + const char *last; + char *end; + Py_ssize_t start, length = PyUnicode_GET_LENGTH(obj); + const int kind = PyUnicode_KIND(obj); + const void* data = PyUnicode_DATA(obj); + start = 0; + while (Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, start))) + start++; + while (start < length - 1 && Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, length - 1))) + length--; + length -= start; + if (unlikely(length <= 0)) goto fallback; + value = __Pyx__PyUnicode_AsDouble_inf_nan(data, kind, start, length); + if (unlikely(value == -1.0)) goto fallback; + if (value != 0.0) return value; + if (length < 40) { + char number[40]; + last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); + if (unlikely(!last)) goto fallback; + value = PyOS_string_to_double(number, &end, NULL); + } else { + char *number = (char*) PyMem_Malloc((length + 1) * sizeof(char)); + if (unlikely(!number)) goto fallback; + last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); + if (unlikely(!last)) { + PyMem_Free(number); + goto fallback; + } + value = PyOS_string_to_double(number, &end, NULL); + PyMem_Free(number); + } + if (likely(end == last) || (value == (double)-1 && PyErr_Occurred())) { + return value; + } +fallback: + return __Pyx_SlowPyString_AsDouble(obj); +} +#endif +static CYTHON_INLINE double __Pyx_PyUnicode_AsDouble(PyObject *obj) { +#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS + if (unlikely(__Pyx_PyUnicode_READY(obj) == -1)) + return (double)-1; + if (likely(PyUnicode_IS_ASCII(obj))) { + const char *s; + Py_ssize_t length; + s = PyUnicode_AsUTF8AndSize(obj, &length); + return __Pyx__PyBytes_AsDouble(obj, s, length); + } + return __Pyx_PyUnicode_AsDouble_WithSpaces(obj); +#else + return __Pyx_SlowPyString_AsDouble(obj); +#endif +} + +/* pynumber_float.proto */ +static CYTHON_INLINE PyObject* __Pyx__PyNumber_Float(PyObject* obj); +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : __Pyx__PyNumber_Float(x)) + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* ListCompAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len)) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) +#endif + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* ListExtend.proto */ +static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 + PyObject* none = _PyList_Extend((PyListObject*)L, v); + if (unlikely(!none)) + return -1; + Py_DECREF(none); + return 0; +#else + return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); +#endif +} + +/* SliceTupleAndList.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); +#else +#define __Pyx_PyList_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) +#define __Pyx_PyTuple_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) +#endif + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* IterFinish.proto */ +static CYTHON_INLINE int __Pyx_IterFinish(void); + +/* UnpackItemEndCheck.proto */ +static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* PyIntCompare.proto */ +static CYTHON_INLINE int __Pyx_PyInt_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyObjectCall2Args.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* CoroutineBase.proto */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; + PyObject *gi_weakreflist; + PyObject *classobj; + PyObject *yieldfrom; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static PyObject *__Pyx_Coroutine_Close(PyObject *self); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); + +/* PatchModuleWithCoroutine.proto */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code); + +/* PatchGeneratorABC.proto */ +static int __Pyx_patch_abc(void); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_vector(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_t, int __pyx_skip_dispatch); /* proto*/ +static int __pyx_f_5ezdxf_3acc_7bspline_5Basis_find_span(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_skip_dispatch); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_span_weighting(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_nbasis, int __pyx_v_span, int __pyx_skip_dispatch); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives *__pyx_optional_args); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_point(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_derivative(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative *__pyx_optional_args); /* proto*/ + +/* Module declarations from "cython" */ + +/* Module declarations from "cpython.mem" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static int (*__pyx_f_5ezdxf_3acc_6vector_isclose)(double, double, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_sub)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_mul)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ + +/* Module declarations from "ezdxf.acc.bspline" */ +static double __pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[19]; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_5ezdxf_3acc_7bspline_NULLVEC = 0; +static double __pyx_f_5ezdxf_3acc_7bspline_binomial_coefficient(int, int); /*proto*/ +static int __pyx_f_5ezdxf_3acc_7bspline_bisect_right(double *, double, int, int); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_reset_double_array(double *, int, double); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.bspline" +extern int __pyx_module_is_main_ezdxf__acc__bspline; +int __pyx_module_is_main_ezdxf__acc__bspline = 0; + +/* Implementation of "ezdxf.acc.bspline" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_sum; +static PyObject *__pyx_builtin_zip; +static PyObject *__pyx_builtin_TypeError; +/* #### Code section: string_decls ### */ +static const char __pyx_k_n[] = "n"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k_u[] = "u"; +static const char __pyx_k__7[] = "."; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k__30[] = "?"; +static const char __pyx_k_all[] = "__all__"; +static const char __pyx_k_sum[] = "sum"; +static const char __pyx_k_zip[] = "zip"; +static const char __pyx_k_args[] = "args"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_send[] = "send"; +static const char __pyx_k_span[] = "span"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_Basis[] = "Basis"; +static const char __pyx_k_basis[] = "basis"; +static const char __pyx_k_close[] = "close"; +static const char __pyx_k_count[] = "count"; +static const char __pyx_k_knots[] = "knots"; +static const char __pyx_k_order[] = "order"; +static const char __pyx_k_point[] = "point"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_throw[] = "throw"; +static const char __pyx_k_tuple[] = "tuple"; +static const char __pyx_k_degree[] = "degree"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_nbasis[] = "nbasis"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_genexpr[] = "genexpr"; +static const char __pyx_k_weights[] = "weights"; +static const char __pyx_k_Iterable[] = "Iterable"; +static const char __pyx_k_Iterator[] = "Iterator"; +static const char __pyx_k_ONE_LIST[] = "ONE_LIST"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_Evaluator[] = "Evaluator"; +static const char __pyx_k_NULL_LIST[] = "NULL_LIST"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_find_span[] = "find_span"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_derivative[] = "derivative"; +static const char __pyx_k_list_float[] = "list[float]"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_basis_funcs[] = "basis_funcs"; +static const char __pyx_k_derivatives[] = "derivatives"; +static const char __pyx_k_is_rational[] = "is_rational"; +static const char __pyx_k_basis_vector[] = "basis_vector"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_Iterator_Vec3[] = "Iterator[Vec3]"; +static const char __pyx_k_invalid_count[] = "invalid count"; +static const char __pyx_k_invalid_order[] = "invalid order"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_Iterable_float[] = "Iterable[float]"; +static const char __pyx_k_control_points[] = "control_points"; +static const char __pyx_k_span_weighting[] = "span_weighting"; +static const char __pyx_k_Basis_find_span[] = "Basis.find_span"; +static const char __pyx_k_Evaluator_point[] = "Evaluator.point"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_Evaluator_points[] = "Evaluator.points"; +static const char __pyx_k_Basis_basis_funcs[] = "Basis.basis_funcs"; +static const char __pyx_k_ezdxf_acc_bspline[] = "ezdxf.acc.bspline"; +static const char __pyx_k_Basis_basis_vector[] = "Basis.basis_vector"; +static const char __pyx_k_Iterator_list_Vec3[] = "Iterator[list[Vec3]]"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_invalid_knot_count[] = "invalid knot count"; +static const char __pyx_k_Basis_span_weighting[] = "Basis.span_weighting"; +static const char __pyx_k_Evaluator_derivative[] = "Evaluator.derivative"; +static const char __pyx_k_invalid_weight_count[] = "invalid weight count"; +static const char __pyx_k_Basis___reduce_cython[] = "Basis.__reduce_cython__"; +static const char __pyx_k_Evaluator_derivatives[] = "Evaluator.derivatives"; +static const char __pyx_k_cinit___locals_genexpr[] = "__cinit__..genexpr"; +static const char __pyx_k_Basis___setstate_cython[] = "Basis.__setstate_cython__"; +static const char __pyx_k_basis_funcs_derivatives[] = "basis_funcs_derivatives"; +static const char __pyx_k_Evaluator___reduce_cython[] = "Evaluator.__reduce_cython__"; +static const char __pyx_k_src_ezdxf_acc_bspline_pyx[] = "src/ezdxf/acc/bspline.pyx"; +static const char __pyx_k_Evaluator___setstate_cython[] = "Evaluator.__setstate_cython__"; +static const char __pyx_k_Basis___get___locals_genexpr[] = "Basis.__get__..genexpr"; +static const char __pyx_k_Basis_basis_funcs_derivatives[] = "Basis.basis_funcs_derivatives"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +/* #### Code section: decls ### */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_9__cinit___genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static int __pyx_pf_5ezdxf_3acc_7bspline_5Basis___cinit__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_knots, int __pyx_v_order, int __pyx_v_count, PyObject *__pyx_v_weights); /* proto */ +static void __pyx_pf_5ezdxf_3acc_7bspline_5Basis_2__dealloc__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_6degree___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___genexpr(CYTHON_UNUSED PyObject *__pyx_self, double *__pyx_genexpr_arg_0, int __pyx_genexpr_arg_1); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_7weights___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_11is_rational___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_4basis_vector(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_t); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_6find_span(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_u); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_8basis_funcs(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_10span_weighting(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_nbasis, int __pyx_v_span); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_12basis_funcs_derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_v_n); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5order___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5count___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5max_t___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_14__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_16__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator___cinit__(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_basis, PyObject *__pyx_v_control_points); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_2point(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_4points(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, PyObject *__pyx_v_t); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_7derivative(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_v_n); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_9derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, PyObject *__pyx_v_t, int __pyx_v_n); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline_Basis(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline_Evaluator(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_7bspline_Basis; + PyObject *__pyx_type_5ezdxf_3acc_7bspline_Evaluator; + PyObject *__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr; + PyObject *__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points; + PyObject *__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline_Basis; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives; + PyObject *__pyx_n_s_Basis; + PyObject *__pyx_n_u_Basis; + PyObject *__pyx_n_s_Basis___get___locals_genexpr; + PyObject *__pyx_n_s_Basis___reduce_cython; + PyObject *__pyx_n_s_Basis___setstate_cython; + PyObject *__pyx_n_s_Basis_basis_funcs; + PyObject *__pyx_n_s_Basis_basis_funcs_derivatives; + PyObject *__pyx_n_s_Basis_basis_vector; + PyObject *__pyx_n_s_Basis_find_span; + PyObject *__pyx_n_s_Basis_span_weighting; + PyObject *__pyx_n_s_Evaluator; + PyObject *__pyx_n_u_Evaluator; + PyObject *__pyx_n_s_Evaluator___reduce_cython; + PyObject *__pyx_n_s_Evaluator___setstate_cython; + PyObject *__pyx_n_s_Evaluator_derivative; + PyObject *__pyx_n_s_Evaluator_derivatives; + PyObject *__pyx_n_s_Evaluator_point; + PyObject *__pyx_n_s_Evaluator_points; + PyObject *__pyx_n_s_Iterable; + PyObject *__pyx_kp_s_Iterable_float; + PyObject *__pyx_n_s_Iterator; + PyObject *__pyx_kp_s_Iterator_Vec3; + PyObject *__pyx_kp_s_Iterator_list_Vec3; + PyObject *__pyx_n_s_NULL_LIST; + PyObject *__pyx_n_s_ONE_LIST; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s__30; + PyObject *__pyx_kp_u__7; + PyObject *__pyx_n_s_all; + PyObject *__pyx_n_s_args; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_basis; + PyObject *__pyx_n_s_basis_funcs; + PyObject *__pyx_n_s_basis_funcs_derivatives; + PyObject *__pyx_n_s_basis_vector; + PyObject *__pyx_n_s_cinit___locals_genexpr; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_close; + PyObject *__pyx_n_s_control_points; + PyObject *__pyx_n_s_count; + PyObject *__pyx_n_s_degree; + PyObject *__pyx_n_s_derivative; + PyObject *__pyx_n_s_derivatives; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_ezdxf_acc_bspline; + PyObject *__pyx_n_s_find_span; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_genexpr; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_n_s_import; + PyObject *__pyx_kp_u_invalid_count; + PyObject *__pyx_kp_u_invalid_knot_count; + PyObject *__pyx_kp_u_invalid_order; + PyObject *__pyx_kp_u_invalid_weight_count; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_n_s_is_rational; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_knots; + PyObject *__pyx_kp_s_list_float; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_n; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_nbasis; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_order; + PyObject *__pyx_n_s_point; + PyObject *__pyx_n_s_points; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_send; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_span; + PyObject *__pyx_n_s_span_weighting; + PyObject *__pyx_kp_s_src_ezdxf_acc_bspline_pyx; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_sum; + PyObject *__pyx_n_s_t; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_throw; + PyObject *__pyx_n_s_tuple; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_u; + PyObject *__pyx_n_s_weights; + PyObject *__pyx_n_s_zip; + PyObject *__pyx_float_0_0; + PyObject *__pyx_float_1_0; + PyObject *__pyx_int_0; + PyObject *__pyx_int_1; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__2; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__8; + PyObject *__pyx_tuple__10; + PyObject *__pyx_tuple__12; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__16; + PyObject *__pyx_tuple__18; + PyObject *__pyx_tuple__19; + PyObject *__pyx_tuple__21; + PyObject *__pyx_tuple__24; + PyObject *__pyx_tuple__25; + PyObject *__pyx_tuple__27; + PyObject *__pyx_codeobj__5; + PyObject *__pyx_codeobj__6; + PyObject *__pyx_codeobj__9; + PyObject *__pyx_codeobj__11; + PyObject *__pyx_codeobj__13; + PyObject *__pyx_codeobj__15; + PyObject *__pyx_codeobj__17; + PyObject *__pyx_codeobj__20; + PyObject *__pyx_codeobj__22; + PyObject *__pyx_codeobj__23; + PyObject *__pyx_codeobj__26; + PyObject *__pyx_codeobj__28; + PyObject *__pyx_codeobj__29; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline_Basis); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline_Evaluator); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis); + Py_CLEAR(clear_module_state->__pyx_n_u_Basis); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis___get___locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis_basis_funcs); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis_basis_funcs_derivatives); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis_basis_vector); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis_find_span); + Py_CLEAR(clear_module_state->__pyx_n_s_Basis_span_weighting); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator); + Py_CLEAR(clear_module_state->__pyx_n_u_Evaluator); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator_derivative); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator_derivatives); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator_point); + Py_CLEAR(clear_module_state->__pyx_n_s_Evaluator_points); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterable); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_float); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterator); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Vec3); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_list_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_NULL_LIST); + Py_CLEAR(clear_module_state->__pyx_n_s_ONE_LIST); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s__30); + Py_CLEAR(clear_module_state->__pyx_kp_u__7); + Py_CLEAR(clear_module_state->__pyx_n_s_all); + Py_CLEAR(clear_module_state->__pyx_n_s_args); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_basis); + Py_CLEAR(clear_module_state->__pyx_n_s_basis_funcs); + Py_CLEAR(clear_module_state->__pyx_n_s_basis_funcs_derivatives); + Py_CLEAR(clear_module_state->__pyx_n_s_basis_vector); + Py_CLEAR(clear_module_state->__pyx_n_s_cinit___locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_close); + Py_CLEAR(clear_module_state->__pyx_n_s_control_points); + Py_CLEAR(clear_module_state->__pyx_n_s_count); + Py_CLEAR(clear_module_state->__pyx_n_s_degree); + Py_CLEAR(clear_module_state->__pyx_n_s_derivative); + Py_CLEAR(clear_module_state->__pyx_n_s_derivatives); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_bspline); + Py_CLEAR(clear_module_state->__pyx_n_s_find_span); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_count); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_knot_count); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_order); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_weight_count); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_n_s_is_rational); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_knots); + Py_CLEAR(clear_module_state->__pyx_kp_s_list_float); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_n); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_nbasis); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_order); + Py_CLEAR(clear_module_state->__pyx_n_s_point); + Py_CLEAR(clear_module_state->__pyx_n_s_points); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_send); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_span); + Py_CLEAR(clear_module_state->__pyx_n_s_span_weighting); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_bspline_pyx); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_sum); + Py_CLEAR(clear_module_state->__pyx_n_s_t); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_throw); + Py_CLEAR(clear_module_state->__pyx_n_s_tuple); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_u); + Py_CLEAR(clear_module_state->__pyx_n_s_weights); + Py_CLEAR(clear_module_state->__pyx_n_s_zip); + Py_CLEAR(clear_module_state->__pyx_float_0_0); + Py_CLEAR(clear_module_state->__pyx_float_1_0); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_1); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__2); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__8); + Py_CLEAR(clear_module_state->__pyx_tuple__10); + Py_CLEAR(clear_module_state->__pyx_tuple__12); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__16); + Py_CLEAR(clear_module_state->__pyx_tuple__18); + Py_CLEAR(clear_module_state->__pyx_tuple__19); + Py_CLEAR(clear_module_state->__pyx_tuple__21); + Py_CLEAR(clear_module_state->__pyx_tuple__24); + Py_CLEAR(clear_module_state->__pyx_tuple__25); + Py_CLEAR(clear_module_state->__pyx_tuple__27); + Py_CLEAR(clear_module_state->__pyx_codeobj__5); + Py_CLEAR(clear_module_state->__pyx_codeobj__6); + Py_CLEAR(clear_module_state->__pyx_codeobj__9); + Py_CLEAR(clear_module_state->__pyx_codeobj__11); + Py_CLEAR(clear_module_state->__pyx_codeobj__13); + Py_CLEAR(clear_module_state->__pyx_codeobj__15); + Py_CLEAR(clear_module_state->__pyx_codeobj__17); + Py_CLEAR(clear_module_state->__pyx_codeobj__20); + Py_CLEAR(clear_module_state->__pyx_codeobj__22); + Py_CLEAR(clear_module_state->__pyx_codeobj__23); + Py_CLEAR(clear_module_state->__pyx_codeobj__26); + Py_CLEAR(clear_module_state->__pyx_codeobj__28); + Py_CLEAR(clear_module_state->__pyx_codeobj__29); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline_Basis); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline_Evaluator); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis); + Py_VISIT(traverse_module_state->__pyx_n_u_Basis); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis___get___locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis_basis_funcs); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis_basis_funcs_derivatives); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis_basis_vector); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis_find_span); + Py_VISIT(traverse_module_state->__pyx_n_s_Basis_span_weighting); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator); + Py_VISIT(traverse_module_state->__pyx_n_u_Evaluator); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator_derivative); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator_derivatives); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator_point); + Py_VISIT(traverse_module_state->__pyx_n_s_Evaluator_points); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterable); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_float); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterator); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Vec3); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_list_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_NULL_LIST); + Py_VISIT(traverse_module_state->__pyx_n_s_ONE_LIST); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s__30); + Py_VISIT(traverse_module_state->__pyx_kp_u__7); + Py_VISIT(traverse_module_state->__pyx_n_s_all); + Py_VISIT(traverse_module_state->__pyx_n_s_args); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_basis); + Py_VISIT(traverse_module_state->__pyx_n_s_basis_funcs); + Py_VISIT(traverse_module_state->__pyx_n_s_basis_funcs_derivatives); + Py_VISIT(traverse_module_state->__pyx_n_s_basis_vector); + Py_VISIT(traverse_module_state->__pyx_n_s_cinit___locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_close); + Py_VISIT(traverse_module_state->__pyx_n_s_control_points); + Py_VISIT(traverse_module_state->__pyx_n_s_count); + Py_VISIT(traverse_module_state->__pyx_n_s_degree); + Py_VISIT(traverse_module_state->__pyx_n_s_derivative); + Py_VISIT(traverse_module_state->__pyx_n_s_derivatives); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_bspline); + Py_VISIT(traverse_module_state->__pyx_n_s_find_span); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_count); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_knot_count); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_order); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_weight_count); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_n_s_is_rational); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_knots); + Py_VISIT(traverse_module_state->__pyx_kp_s_list_float); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_n); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_nbasis); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_order); + Py_VISIT(traverse_module_state->__pyx_n_s_point); + Py_VISIT(traverse_module_state->__pyx_n_s_points); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_send); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_span); + Py_VISIT(traverse_module_state->__pyx_n_s_span_weighting); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_bspline_pyx); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_sum); + Py_VISIT(traverse_module_state->__pyx_n_s_t); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_throw); + Py_VISIT(traverse_module_state->__pyx_n_s_tuple); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_u); + Py_VISIT(traverse_module_state->__pyx_n_s_weights); + Py_VISIT(traverse_module_state->__pyx_n_s_zip); + Py_VISIT(traverse_module_state->__pyx_float_0_0); + Py_VISIT(traverse_module_state->__pyx_float_1_0); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_1); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__2); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__8); + Py_VISIT(traverse_module_state->__pyx_tuple__10); + Py_VISIT(traverse_module_state->__pyx_tuple__12); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__16); + Py_VISIT(traverse_module_state->__pyx_tuple__18); + Py_VISIT(traverse_module_state->__pyx_tuple__19); + Py_VISIT(traverse_module_state->__pyx_tuple__21); + Py_VISIT(traverse_module_state->__pyx_tuple__24); + Py_VISIT(traverse_module_state->__pyx_tuple__25); + Py_VISIT(traverse_module_state->__pyx_tuple__27); + Py_VISIT(traverse_module_state->__pyx_codeobj__5); + Py_VISIT(traverse_module_state->__pyx_codeobj__6); + Py_VISIT(traverse_module_state->__pyx_codeobj__9); + Py_VISIT(traverse_module_state->__pyx_codeobj__11); + Py_VISIT(traverse_module_state->__pyx_codeobj__13); + Py_VISIT(traverse_module_state->__pyx_codeobj__15); + Py_VISIT(traverse_module_state->__pyx_codeobj__17); + Py_VISIT(traverse_module_state->__pyx_codeobj__20); + Py_VISIT(traverse_module_state->__pyx_codeobj__22); + Py_VISIT(traverse_module_state->__pyx_codeobj__23); + Py_VISIT(traverse_module_state->__pyx_codeobj__26); + Py_VISIT(traverse_module_state->__pyx_codeobj__28); + Py_VISIT(traverse_module_state->__pyx_codeobj__29); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_7bspline_Basis __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline_Basis +#define __pyx_type_5ezdxf_3acc_7bspline_Evaluator __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline_Evaluator +#define __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr +#define __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr +#define __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points +#define __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives __pyx_mstate_global->__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives +#endif +#define __pyx_ptype_5ezdxf_3acc_7bspline_Basis __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline_Basis +#define __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator +#define __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr +#define __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr +#define __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points +#define __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives +#define __pyx_n_s_Basis __pyx_mstate_global->__pyx_n_s_Basis +#define __pyx_n_u_Basis __pyx_mstate_global->__pyx_n_u_Basis +#define __pyx_n_s_Basis___get___locals_genexpr __pyx_mstate_global->__pyx_n_s_Basis___get___locals_genexpr +#define __pyx_n_s_Basis___reduce_cython __pyx_mstate_global->__pyx_n_s_Basis___reduce_cython +#define __pyx_n_s_Basis___setstate_cython __pyx_mstate_global->__pyx_n_s_Basis___setstate_cython +#define __pyx_n_s_Basis_basis_funcs __pyx_mstate_global->__pyx_n_s_Basis_basis_funcs +#define __pyx_n_s_Basis_basis_funcs_derivatives __pyx_mstate_global->__pyx_n_s_Basis_basis_funcs_derivatives +#define __pyx_n_s_Basis_basis_vector __pyx_mstate_global->__pyx_n_s_Basis_basis_vector +#define __pyx_n_s_Basis_find_span __pyx_mstate_global->__pyx_n_s_Basis_find_span +#define __pyx_n_s_Basis_span_weighting __pyx_mstate_global->__pyx_n_s_Basis_span_weighting +#define __pyx_n_s_Evaluator __pyx_mstate_global->__pyx_n_s_Evaluator +#define __pyx_n_u_Evaluator __pyx_mstate_global->__pyx_n_u_Evaluator +#define __pyx_n_s_Evaluator___reduce_cython __pyx_mstate_global->__pyx_n_s_Evaluator___reduce_cython +#define __pyx_n_s_Evaluator___setstate_cython __pyx_mstate_global->__pyx_n_s_Evaluator___setstate_cython +#define __pyx_n_s_Evaluator_derivative __pyx_mstate_global->__pyx_n_s_Evaluator_derivative +#define __pyx_n_s_Evaluator_derivatives __pyx_mstate_global->__pyx_n_s_Evaluator_derivatives +#define __pyx_n_s_Evaluator_point __pyx_mstate_global->__pyx_n_s_Evaluator_point +#define __pyx_n_s_Evaluator_points __pyx_mstate_global->__pyx_n_s_Evaluator_points +#define __pyx_n_s_Iterable __pyx_mstate_global->__pyx_n_s_Iterable +#define __pyx_kp_s_Iterable_float __pyx_mstate_global->__pyx_kp_s_Iterable_float +#define __pyx_n_s_Iterator __pyx_mstate_global->__pyx_n_s_Iterator +#define __pyx_kp_s_Iterator_Vec3 __pyx_mstate_global->__pyx_kp_s_Iterator_Vec3 +#define __pyx_kp_s_Iterator_list_Vec3 __pyx_mstate_global->__pyx_kp_s_Iterator_list_Vec3 +#define __pyx_n_s_NULL_LIST __pyx_mstate_global->__pyx_n_s_NULL_LIST +#define __pyx_n_s_ONE_LIST __pyx_mstate_global->__pyx_n_s_ONE_LIST +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s__30 __pyx_mstate_global->__pyx_n_s__30 +#define __pyx_kp_u__7 __pyx_mstate_global->__pyx_kp_u__7 +#define __pyx_n_s_all __pyx_mstate_global->__pyx_n_s_all +#define __pyx_n_s_args __pyx_mstate_global->__pyx_n_s_args +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_basis __pyx_mstate_global->__pyx_n_s_basis +#define __pyx_n_s_basis_funcs __pyx_mstate_global->__pyx_n_s_basis_funcs +#define __pyx_n_s_basis_funcs_derivatives __pyx_mstate_global->__pyx_n_s_basis_funcs_derivatives +#define __pyx_n_s_basis_vector __pyx_mstate_global->__pyx_n_s_basis_vector +#define __pyx_n_s_cinit___locals_genexpr __pyx_mstate_global->__pyx_n_s_cinit___locals_genexpr +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_close __pyx_mstate_global->__pyx_n_s_close +#define __pyx_n_s_control_points __pyx_mstate_global->__pyx_n_s_control_points +#define __pyx_n_s_count __pyx_mstate_global->__pyx_n_s_count +#define __pyx_n_s_degree __pyx_mstate_global->__pyx_n_s_degree +#define __pyx_n_s_derivative __pyx_mstate_global->__pyx_n_s_derivative +#define __pyx_n_s_derivatives __pyx_mstate_global->__pyx_n_s_derivatives +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_ezdxf_acc_bspline __pyx_mstate_global->__pyx_n_s_ezdxf_acc_bspline +#define __pyx_n_s_find_span __pyx_mstate_global->__pyx_n_s_find_span +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_genexpr __pyx_mstate_global->__pyx_n_s_genexpr +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_kp_u_invalid_count __pyx_mstate_global->__pyx_kp_u_invalid_count +#define __pyx_kp_u_invalid_knot_count __pyx_mstate_global->__pyx_kp_u_invalid_knot_count +#define __pyx_kp_u_invalid_order __pyx_mstate_global->__pyx_kp_u_invalid_order +#define __pyx_kp_u_invalid_weight_count __pyx_mstate_global->__pyx_kp_u_invalid_weight_count +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_n_s_is_rational __pyx_mstate_global->__pyx_n_s_is_rational +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_knots __pyx_mstate_global->__pyx_n_s_knots +#define __pyx_kp_s_list_float __pyx_mstate_global->__pyx_kp_s_list_float +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_n __pyx_mstate_global->__pyx_n_s_n +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_nbasis __pyx_mstate_global->__pyx_n_s_nbasis +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_order __pyx_mstate_global->__pyx_n_s_order +#define __pyx_n_s_point __pyx_mstate_global->__pyx_n_s_point +#define __pyx_n_s_points __pyx_mstate_global->__pyx_n_s_points +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_send __pyx_mstate_global->__pyx_n_s_send +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_span __pyx_mstate_global->__pyx_n_s_span +#define __pyx_n_s_span_weighting __pyx_mstate_global->__pyx_n_s_span_weighting +#define __pyx_kp_s_src_ezdxf_acc_bspline_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_bspline_pyx +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_sum __pyx_mstate_global->__pyx_n_s_sum +#define __pyx_n_s_t __pyx_mstate_global->__pyx_n_s_t +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_throw __pyx_mstate_global->__pyx_n_s_throw +#define __pyx_n_s_tuple __pyx_mstate_global->__pyx_n_s_tuple +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_u __pyx_mstate_global->__pyx_n_s_u +#define __pyx_n_s_weights __pyx_mstate_global->__pyx_n_s_weights +#define __pyx_n_s_zip __pyx_mstate_global->__pyx_n_s_zip +#define __pyx_float_0_0 __pyx_mstate_global->__pyx_float_0_0 +#define __pyx_float_1_0 __pyx_mstate_global->__pyx_float_1_0 +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_1 __pyx_mstate_global->__pyx_int_1 +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__2 __pyx_mstate_global->__pyx_tuple__2 +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8 +#define __pyx_tuple__10 __pyx_mstate_global->__pyx_tuple__10 +#define __pyx_tuple__12 __pyx_mstate_global->__pyx_tuple__12 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__16 __pyx_mstate_global->__pyx_tuple__16 +#define __pyx_tuple__18 __pyx_mstate_global->__pyx_tuple__18 +#define __pyx_tuple__19 __pyx_mstate_global->__pyx_tuple__19 +#define __pyx_tuple__21 __pyx_mstate_global->__pyx_tuple__21 +#define __pyx_tuple__24 __pyx_mstate_global->__pyx_tuple__24 +#define __pyx_tuple__25 __pyx_mstate_global->__pyx_tuple__25 +#define __pyx_tuple__27 __pyx_mstate_global->__pyx_tuple__27 +#define __pyx_codeobj__5 __pyx_mstate_global->__pyx_codeobj__5 +#define __pyx_codeobj__6 __pyx_mstate_global->__pyx_codeobj__6 +#define __pyx_codeobj__9 __pyx_mstate_global->__pyx_codeobj__9 +#define __pyx_codeobj__11 __pyx_mstate_global->__pyx_codeobj__11 +#define __pyx_codeobj__13 __pyx_mstate_global->__pyx_codeobj__13 +#define __pyx_codeobj__15 __pyx_mstate_global->__pyx_codeobj__15 +#define __pyx_codeobj__17 __pyx_mstate_global->__pyx_codeobj__17 +#define __pyx_codeobj__20 __pyx_mstate_global->__pyx_codeobj__20 +#define __pyx_codeobj__22 __pyx_mstate_global->__pyx_codeobj__22 +#define __pyx_codeobj__23 __pyx_mstate_global->__pyx_codeobj__23 +#define __pyx_codeobj__26 __pyx_mstate_global->__pyx_codeobj__26 +#define __pyx_codeobj__28 __pyx_mstate_global->__pyx_codeobj__28 +#define __pyx_codeobj__29 __pyx_mstate_global->__pyx_codeobj__29 +/* #### Code section: module_code ### */ + +/* "ezdxf/acc/bspline.pyx":29 + * + * @cython.cdivision(True) + * cdef double binomial_coefficient(int k, int i): # <<<<<<<<<<<<<< + * cdef double k_fact = FACTORIAL[k] + * cdef double i_fact = FACTORIAL[i] + */ + +static double __pyx_f_5ezdxf_3acc_7bspline_binomial_coefficient(int __pyx_v_k, int __pyx_v_i) { + double __pyx_v_k_fact; + double __pyx_v_i_fact; + double __pyx_v_k_i_fact; + double __pyx_r; + int __pyx_t_1; + + /* "ezdxf/acc/bspline.pyx":30 + * @cython.cdivision(True) + * cdef double binomial_coefficient(int k, int i): + * cdef double k_fact = FACTORIAL[k] # <<<<<<<<<<<<<< + * cdef double i_fact = FACTORIAL[i] + * cdef double k_i_fact + */ + __pyx_v_k_fact = (__pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[__pyx_v_k]); + + /* "ezdxf/acc/bspline.pyx":31 + * cdef double binomial_coefficient(int k, int i): + * cdef double k_fact = FACTORIAL[k] + * cdef double i_fact = FACTORIAL[i] # <<<<<<<<<<<<<< + * cdef double k_i_fact + * if i > k: + */ + __pyx_v_i_fact = (__pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[__pyx_v_i]); + + /* "ezdxf/acc/bspline.pyx":33 + * cdef double i_fact = FACTORIAL[i] + * cdef double k_i_fact + * if i > k: # <<<<<<<<<<<<<< + * return 0.0 + * k_i_fact = FACTORIAL[k - i] + */ + __pyx_t_1 = (__pyx_v_i > __pyx_v_k); + if (__pyx_t_1) { + + /* "ezdxf/acc/bspline.pyx":34 + * cdef double k_i_fact + * if i > k: + * return 0.0 # <<<<<<<<<<<<<< + * k_i_fact = FACTORIAL[k - i] + * return k_fact / (k_i_fact * i_fact) + */ + __pyx_r = 0.0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":33 + * cdef double i_fact = FACTORIAL[i] + * cdef double k_i_fact + * if i > k: # <<<<<<<<<<<<<< + * return 0.0 + * k_i_fact = FACTORIAL[k - i] + */ + } + + /* "ezdxf/acc/bspline.pyx":35 + * if i > k: + * return 0.0 + * k_i_fact = FACTORIAL[k - i] # <<<<<<<<<<<<<< + * return k_fact / (k_i_fact * i_fact) + * + */ + __pyx_v_k_i_fact = (__pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[(__pyx_v_k - __pyx_v_i)]); + + /* "ezdxf/acc/bspline.pyx":36 + * return 0.0 + * k_i_fact = FACTORIAL[k - i] + * return k_fact / (k_i_fact * i_fact) # <<<<<<<<<<<<<< + * + * @cython.boundscheck(False) + */ + __pyx_r = (__pyx_v_k_fact / (__pyx_v_k_i_fact * __pyx_v_i_fact)); + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":29 + * + * @cython.cdivision(True) + * cdef double binomial_coefficient(int k, int i): # <<<<<<<<<<<<<< + * cdef double k_fact = FACTORIAL[k] + * cdef double i_fact = FACTORIAL[i] + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":39 + * + * @cython.boundscheck(False) + * cdef int bisect_right(double *a, double x, int lo, int hi): # <<<<<<<<<<<<<< + * cdef int mid + * while lo < hi: + */ + +static int __pyx_f_5ezdxf_3acc_7bspline_bisect_right(double *__pyx_v_a, double __pyx_v_x, int __pyx_v_lo, int __pyx_v_hi) { + int __pyx_v_mid; + int __pyx_r; + int __pyx_t_1; + + /* "ezdxf/acc/bspline.pyx":41 + * cdef int bisect_right(double *a, double x, int lo, int hi): + * cdef int mid + * while lo < hi: # <<<<<<<<<<<<<< + * mid = (lo + hi) // 2 + * if x < a[mid]: + */ + while (1) { + __pyx_t_1 = (__pyx_v_lo < __pyx_v_hi); + if (!__pyx_t_1) break; + + /* "ezdxf/acc/bspline.pyx":42 + * cdef int mid + * while lo < hi: + * mid = (lo + hi) // 2 # <<<<<<<<<<<<<< + * if x < a[mid]: + * hi = mid + */ + __pyx_v_mid = __Pyx_div_long((__pyx_v_lo + __pyx_v_hi), 2); + + /* "ezdxf/acc/bspline.pyx":43 + * while lo < hi: + * mid = (lo + hi) // 2 + * if x < a[mid]: # <<<<<<<<<<<<<< + * hi = mid + * else: + */ + __pyx_t_1 = (__pyx_v_x < (__pyx_v_a[__pyx_v_mid])); + if (__pyx_t_1) { + + /* "ezdxf/acc/bspline.pyx":44 + * mid = (lo + hi) // 2 + * if x < a[mid]: + * hi = mid # <<<<<<<<<<<<<< + * else: + * lo = mid + 1 + */ + __pyx_v_hi = __pyx_v_mid; + + /* "ezdxf/acc/bspline.pyx":43 + * while lo < hi: + * mid = (lo + hi) // 2 + * if x < a[mid]: # <<<<<<<<<<<<<< + * hi = mid + * else: + */ + goto __pyx_L5; + } + + /* "ezdxf/acc/bspline.pyx":46 + * hi = mid + * else: + * lo = mid + 1 # <<<<<<<<<<<<<< + * return lo + * + */ + /*else*/ { + __pyx_v_lo = (__pyx_v_mid + 1); + } + __pyx_L5:; + } + + /* "ezdxf/acc/bspline.pyx":47 + * else: + * lo = mid + 1 + * return lo # <<<<<<<<<<<<<< + * + * cdef reset_double_array(double *a, int count, double value): + */ + __pyx_r = __pyx_v_lo; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":39 + * + * @cython.boundscheck(False) + * cdef int bisect_right(double *a, double x, int lo, int hi): # <<<<<<<<<<<<<< + * cdef int mid + * while lo < hi: + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":49 + * return lo + * + * cdef reset_double_array(double *a, int count, double value): # <<<<<<<<<<<<<< + * cdef int i + * for i in range(count): + */ + +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_reset_double_array(double *__pyx_v_a, int __pyx_v_count, double __pyx_v_value) { + int __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + __Pyx_RefNannySetupContext("reset_double_array", 1); + + /* "ezdxf/acc/bspline.pyx":51 + * cdef reset_double_array(double *a, int count, double value): + * cdef int i + * for i in range(count): # <<<<<<<<<<<<<< + * a[i] = value + * + */ + __pyx_t_1 = __pyx_v_count; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "ezdxf/acc/bspline.pyx":52 + * cdef int i + * for i in range(count): + * a[i] = value # <<<<<<<<<<<<<< + * + * cdef class Basis: + */ + (__pyx_v_a[__pyx_v_i]) = __pyx_v_value; + } + + /* "ezdxf/acc/bspline.pyx":49 + * return lo + * + * cdef reset_double_array(double *a, int count, double value): # <<<<<<<<<<<<<< + * cdef int i + * for i in range(count): + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":65 + * cdef int knot_count + * + * def __cinit__( # <<<<<<<<<<<<<< + * self, knots: Iterable[float], + * int order, + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_7bspline_5Basis_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_7bspline_5Basis_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_knots = 0; + int __pyx_v_order; + int __pyx_v_count; + PyObject *__pyx_v_weights = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_knots,&__pyx_n_s_order,&__pyx_n_s_count,&__pyx_n_s_weights,0}; + + /* "ezdxf/acc/bspline.pyx":69 + * int order, + * int count, + * weights: Sequence[float] = None # <<<<<<<<<<<<<< + * ): + * if order < 2 or order >= MAX_SPLINE_ORDER: + */ + values[3] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)Py_None)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_knots)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_order)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 4, 1); __PYX_ERR(0, 65, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_count)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 4, 2); __PYX_ERR(0, 65, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_weights); + if (value) { values[3] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 65, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 65, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_knots = values[0]; + __pyx_v_order = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_order == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 67, __pyx_L3_error) + __pyx_v_count = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_count == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L3_error) + __pyx_v_weights = values[3]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 4, __pyx_nargs); __PYX_ERR(0, 65, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis___cinit__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_knots, __pyx_v_order, __pyx_v_count, __pyx_v_weights); + + /* "ezdxf/acc/bspline.pyx":65 + * cdef int knot_count + * + * def __cinit__( # <<<<<<<<<<<<<< + * self, knots: Iterable[float], + * int order, + */ + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_9__cinit___2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bspline.pyx":78 + * self.count = count + * self.knot_count = self.order + self.count + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() # <<<<<<<<<<<<<< + * + * cdef Py_ssize_t i = len(self.weights_) + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_9__cinit___genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 78, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_7bspline_5Basis_9__cinit___2generator2, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_cinit___locals_genexpr, __pyx_n_s_ezdxf_acc_bspline); if (unlikely(!gen)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__cinit__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_9__cinit___2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 78, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 78, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 78, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 78, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 78, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 78, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 78, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 78, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_x); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_x, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyNumber_Float(__pyx_cur_scope->__pyx_v_x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 78, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":65 + * cdef int knot_count + * + * def __cinit__( # <<<<<<<<<<<<<< + * self, knots: Iterable[float], + * int order, + */ + +static int __pyx_pf_5ezdxf_3acc_7bspline_5Basis___cinit__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_knots, int __pyx_v_order, int __pyx_v_count, PyObject *__pyx_v_weights) { + Py_ssize_t __pyx_v_i; + PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_9__cinit___2generator2 = 0; + PyObject *__pyx_8genexpr1__pyx_v_x = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + Py_ssize_t __pyx_t_6; + PyObject *(*__pyx_t_7)(PyObject *); + int __pyx_t_8; + int __pyx_t_9; + double __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + __Pyx_INCREF(__pyx_v_knots); + + /* "ezdxf/acc/bspline.pyx":71 + * weights: Sequence[float] = None + * ): + * if order < 2 or order >= MAX_SPLINE_ORDER: # <<<<<<<<<<<<<< + * raise ValueError('invalid order') + * self.order = order + */ + __pyx_t_2 = (__pyx_v_order < 2); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_order >= MAX_SPLINE_ORDER); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (unlikely(__pyx_t_1)) { + + /* "ezdxf/acc/bspline.pyx":72 + * ): + * if order < 2 or order >= MAX_SPLINE_ORDER: + * raise ValueError('invalid order') # <<<<<<<<<<<<<< + * self.order = order + * if count < 2: + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 72, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":71 + * weights: Sequence[float] = None + * ): + * if order < 2 or order >= MAX_SPLINE_ORDER: # <<<<<<<<<<<<<< + * raise ValueError('invalid order') + * self.order = order + */ + } + + /* "ezdxf/acc/bspline.pyx":73 + * if order < 2 or order >= MAX_SPLINE_ORDER: + * raise ValueError('invalid order') + * self.order = order # <<<<<<<<<<<<<< + * if count < 2: + * raise ValueError('invalid count') + */ + __pyx_v_self->order = __pyx_v_order; + + /* "ezdxf/acc/bspline.pyx":74 + * raise ValueError('invalid order') + * self.order = order + * if count < 2: # <<<<<<<<<<<<<< + * raise ValueError('invalid count') + * self.count = count + */ + __pyx_t_1 = (__pyx_v_count < 2); + if (unlikely(__pyx_t_1)) { + + /* "ezdxf/acc/bspline.pyx":75 + * self.order = order + * if count < 2: + * raise ValueError('invalid count') # <<<<<<<<<<<<<< + * self.count = count + * self.knot_count = self.order + self.count + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 75, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":74 + * raise ValueError('invalid order') + * self.order = order + * if count < 2: # <<<<<<<<<<<<<< + * raise ValueError('invalid count') + * self.count = count + */ + } + + /* "ezdxf/acc/bspline.pyx":76 + * if count < 2: + * raise ValueError('invalid count') + * self.count = count # <<<<<<<<<<<<<< + * self.knot_count = self.order + self.count + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() + */ + __pyx_v_self->count = __pyx_v_count; + + /* "ezdxf/acc/bspline.pyx":77 + * raise ValueError('invalid count') + * self.count = count + * self.knot_count = self.order + self.count # <<<<<<<<<<<<<< + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() + * + */ + __pyx_v_self->knot_count = (__pyx_v_self->order + __pyx_v_self->count); + + /* "ezdxf/acc/bspline.pyx":78 + * self.count = count + * self.knot_count = self.order + self.count + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() # <<<<<<<<<<<<<< + * + * cdef Py_ssize_t i = len(self.weights_) + */ + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_weights); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 78, __pyx_L1_error) + if (__pyx_t_1) { + __pyx_t_4 = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_9__cinit___genexpr(NULL, __pyx_v_weights); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PySequence_Tuple(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = __pyx_t_5; + __pyx_t_5 = 0; + } else { + __pyx_t_5 = __Pyx_PyObject_CallNoArg(((PyObject *)(&PyTuple_Type))); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __pyx_t_5; + __pyx_t_5 = 0; + } + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_GOTREF(__pyx_v_self->weights_); + __Pyx_DECREF(__pyx_v_self->weights_); + __pyx_v_self->weights_ = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":80 + * self.weights_ = tuple(float(x) for x in weights) if weights else tuple() + * + * cdef Py_ssize_t i = len(self.weights_) # <<<<<<<<<<<<<< + * if i != 0 and i != self.count: + * raise ValueError('invalid weight count') + */ + __pyx_t_3 = __pyx_v_self->weights_; + __Pyx_INCREF(__pyx_t_3); + if (unlikely(__pyx_t_3 == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(0, 80, __pyx_L1_error) + } + __pyx_t_6 = __Pyx_PyTuple_GET_SIZE(__pyx_t_3); if (unlikely(__pyx_t_6 == ((Py_ssize_t)-1))) __PYX_ERR(0, 80, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_i = __pyx_t_6; + + /* "ezdxf/acc/bspline.pyx":81 + * + * cdef Py_ssize_t i = len(self.weights_) + * if i != 0 and i != self.count: # <<<<<<<<<<<<<< + * raise ValueError('invalid weight count') + * + */ + __pyx_t_2 = (__pyx_v_i != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L8_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_i != __pyx_v_self->count); + __pyx_t_1 = __pyx_t_2; + __pyx_L8_bool_binop_done:; + if (unlikely(__pyx_t_1)) { + + /* "ezdxf/acc/bspline.pyx":82 + * cdef Py_ssize_t i = len(self.weights_) + * if i != 0 and i != self.count: + * raise ValueError('invalid weight count') # <<<<<<<<<<<<<< + * + * knots = [float(x) for x in knots] + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 82, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":81 + * + * cdef Py_ssize_t i = len(self.weights_) + * if i != 0 and i != self.count: # <<<<<<<<<<<<<< + * raise ValueError('invalid weight count') + * + */ + } + + /* "ezdxf/acc/bspline.pyx":84 + * raise ValueError('invalid weight count') + * + * knots = [float(x) for x in knots] # <<<<<<<<<<<<<< + * if len(knots) != self.knot_count: + * raise ValueError('invalid knot count') + */ + { /* enter inner scope */ + __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_GOTREF(__pyx_t_3); + if (likely(PyList_CheckExact(__pyx_v_knots)) || PyTuple_CheckExact(__pyx_v_knots)) { + __pyx_t_5 = __pyx_v_knots; __Pyx_INCREF(__pyx_t_5); + __pyx_t_6 = 0; + __pyx_t_7 = NULL; + } else { + __pyx_t_6 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_v_knots); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 84, __pyx_L12_error) + } + for (;;) { + if (likely(!__pyx_t_7)) { + if (likely(PyList_CheckExact(__pyx_t_5))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 84, __pyx_L12_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_4); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(0, 84, __pyx_L12_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 84, __pyx_L12_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_4); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(0, 84, __pyx_L12_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_7(__pyx_t_5); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 84, __pyx_L12_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_8genexpr1__pyx_v_x, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyNumber_Float(__pyx_8genexpr1__pyx_v_x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_3, (PyObject*)__pyx_t_4))) __PYX_ERR(0, 84, __pyx_L12_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_x); __pyx_8genexpr1__pyx_v_x = 0; + goto __pyx_L16_exit_scope; + __pyx_L12_error:; + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_x); __pyx_8genexpr1__pyx_v_x = 0; + goto __pyx_L1_error; + __pyx_L16_exit_scope:; + } /* exit inner scope */ + __Pyx_DECREF_SET(__pyx_v_knots, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":85 + * + * knots = [float(x) for x in knots] + * if len(knots) != self.knot_count: # <<<<<<<<<<<<<< + * raise ValueError('invalid knot count') + * + */ + __pyx_t_6 = PyObject_Length(__pyx_v_knots); if (unlikely(__pyx_t_6 == ((Py_ssize_t)-1))) __PYX_ERR(0, 85, __pyx_L1_error) + __pyx_t_1 = (__pyx_t_6 != __pyx_v_self->knot_count); + if (unlikely(__pyx_t_1)) { + + /* "ezdxf/acc/bspline.pyx":86 + * knots = [float(x) for x in knots] + * if len(knots) != self.knot_count: + * raise ValueError('invalid knot count') # <<<<<<<<<<<<<< + * + * self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 86, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":85 + * + * knots = [float(x) for x in knots] + * if len(knots) != self.knot_count: # <<<<<<<<<<<<<< + * raise ValueError('invalid knot count') + * + */ + } + + /* "ezdxf/acc/bspline.pyx":88 + * raise ValueError('invalid knot count') + * + * self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) # <<<<<<<<<<<<<< + * for i in range(self.knot_count): + * self._knots[i] = knots[i] + */ + __pyx_v_self->_knots = ((double *)PyMem_Malloc((__pyx_v_self->knot_count * (sizeof(double))))); + + /* "ezdxf/acc/bspline.pyx":89 + * + * self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) + * for i in range(self.knot_count): # <<<<<<<<<<<<<< + * self._knots[i] = knots[i] + * self.max_t = self._knots[self.knot_count - 1] + */ + __pyx_t_8 = __pyx_v_self->knot_count; + __pyx_t_9 = __pyx_t_8; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_9; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "ezdxf/acc/bspline.pyx":90 + * self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) + * for i in range(self.knot_count): + * self._knots[i] = knots[i] # <<<<<<<<<<<<<< + * self.max_t = self._knots[self.knot_count - 1] + * + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_knots, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_10 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_10 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_self->_knots[__pyx_v_i]) = __pyx_t_10; + } + + /* "ezdxf/acc/bspline.pyx":91 + * for i in range(self.knot_count): + * self._knots[i] = knots[i] + * self.max_t = self._knots[self.knot_count - 1] # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_v_self->max_t = (__pyx_v_self->_knots[(__pyx_v_self->knot_count - 1)]); + + /* "ezdxf/acc/bspline.pyx":65 + * cdef int knot_count + * + * def __cinit__( # <<<<<<<<<<<<<< + * self, knots: Iterable[float], + * int order, + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_7bspline_5Basis_9__cinit___2generator2); + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_x); + __Pyx_XDECREF(__pyx_v_knots); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":93 + * self.max_t = self._knots[self.knot_count - 1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * PyMem_Free(self._knots) + * + */ + +/* Python wrapper */ +static void __pyx_pw_5ezdxf_3acc_7bspline_5Basis_3__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_5ezdxf_3acc_7bspline_5Basis_3__dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_pf_5ezdxf_3acc_7bspline_5Basis_2__dealloc__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_5ezdxf_3acc_7bspline_5Basis_2__dealloc__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + + /* "ezdxf/acc/bspline.pyx":94 + * + * def __dealloc__(self): + * PyMem_Free(self._knots) # <<<<<<<<<<<<<< + * + * @property + */ + PyMem_Free(__pyx_v_self->_knots); + + /* "ezdxf/acc/bspline.pyx":93 + * self.max_t = self._knots[self.knot_count - 1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * PyMem_Free(self._knots) + * + */ + + /* function exit code */ +} + +/* "ezdxf/acc/bspline.pyx":96 + * PyMem_Free(self._knots) + * + * @property # <<<<<<<<<<<<<< + * def degree(self) -> int: + * return self.order - 1 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_6degree_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_6degree_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_6degree___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_6degree___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bspline.pyx":98 + * @property + * def degree(self) -> int: + * return self.order - 1 # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_long((__pyx_v_self->order - 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":96 + * PyMem_Free(self._knots) + * + * @property # <<<<<<<<<<<<<< + * def degree(self) -> int: + * return self.order - 1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.degree.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":100 + * return self.order - 1 + * + * @property # <<<<<<<<<<<<<< + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5knots_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5knots_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bspline.pyx":102 + * @property + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) # <<<<<<<<<<<<<< + * + * @property + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___genexpr(CYTHON_UNUSED PyObject *__pyx_self, double *__pyx_genexpr_arg_0, int __pyx_genexpr_arg_1) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 102, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __pyx_cur_scope->__pyx_genexpr_arg_1 = __pyx_genexpr_arg_1; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___2generator3, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_Basis___get___locals_genexpr, __pyx_n_s_ezdxf_acc_bspline); if (unlikely(!gen)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.knots.__get__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + double *__pyx_t_1; + double *__pyx_t_2; + double *__pyx_t_3; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 102, __pyx_L1_error) + __pyx_t_2 = (__pyx_cur_scope->__pyx_genexpr_arg_0 + __pyx_cur_scope->__pyx_genexpr_arg_1); + for (__pyx_t_3 = __pyx_cur_scope->__pyx_genexpr_arg_0; __pyx_t_3 < __pyx_t_2; __pyx_t_3++) { + __pyx_t_1 = __pyx_t_3; + __pyx_cur_scope->__pyx_v_x = (__pyx_t_1[0]); + __pyx_t_4 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 102, __pyx_L1_error) + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":100 + * return self.order - 1 + * + * @property # <<<<<<<<<<<<<< + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_gb_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___2generator3 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bspline.pyx":102 + * @property + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___genexpr(NULL, __pyx_v_self->_knots, __pyx_v_self->knot_count); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":100 + * return self.order - 1 + * + * @property # <<<<<<<<<<<<<< + * def knots(self) -> tuple[float, ...]: + * return tuple(x for x in self._knots[:self.knot_count]) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.knots.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_7bspline_5Basis_5knots_7__get___2generator3); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":104 + * return tuple(x for x in self._knots[:self.knot_count]) + * + * @property # <<<<<<<<<<<<<< + * def weights(self) -> tuple[float, ...]: + * return self.weights_ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7weights_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7weights_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_7weights___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_7weights___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bspline.pyx":106 + * @property + * def weights(self) -> tuple[float, ...]: + * return self.weights_ # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->weights_); + __pyx_r = __pyx_v_self->weights_; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":104 + * return tuple(x for x in self._knots[:self.knot_count]) + * + * @property # <<<<<<<<<<<<<< + * def weights(self) -> tuple[float, ...]: + * return self.weights_ + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":108 + * return self.weights_ + * + * @property # <<<<<<<<<<<<<< + * def is_rational(self) -> bool: + * """ Returns ``True`` if curve is a rational B-spline. (has weights) """ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11is_rational_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11is_rational_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_11is_rational___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_11is_rational___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/bspline.pyx":111 + * def is_rational(self) -> bool: + * """ Returns ``True`` if curve is a rational B-spline. (has weights) """ + * return bool(self.weights_) # <<<<<<<<<<<<<< + * + * cpdef list basis_vector(self, double t): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = (__pyx_v_self->weights_ != Py_None)&&(PyTuple_GET_SIZE(__pyx_v_self->weights_) != 0); + __pyx_t_2 = __Pyx_PyBool_FromLong((!(!__pyx_t_1))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":108 + * return self.weights_ + * + * @property # <<<<<<<<<<<<<< + * def is_rational(self) -> bool: + * """ Returns ``True`` if curve is a rational B-spline. (has weights) """ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.is_rational.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":113 + * return bool(self.weights_) + * + * cpdef list basis_vector(self, double t): # <<<<<<<<<<<<<< + * """ Returns the expanded basis vector. """ + * + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5basis_vector(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_vector(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_t, int __pyx_skip_dispatch) { + int __pyx_v_span; + int __pyx_v_p; + int __pyx_v_front; + int __pyx_v_back; + PyObject *__pyx_v_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_t_7; + int __pyx_t_8; + int __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_vector", 1); + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_basis_vector); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_5Basis_5basis_vector)) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 113, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":116 + * """ Returns the expanded basis vector. """ + * + * cdef int span = self.find_span(t) # <<<<<<<<<<<<<< + * cdef int p = self.order - 1 + * cdef int front = span - p + */ + __pyx_t_7 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self->__pyx_vtab)->find_span(__pyx_v_self, __pyx_v_t, 0); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 116, __pyx_L1_error) + __pyx_v_span = __pyx_t_7; + + /* "ezdxf/acc/bspline.pyx":117 + * + * cdef int span = self.find_span(t) + * cdef int p = self.order - 1 # <<<<<<<<<<<<<< + * cdef int front = span - p + * cdef int back = self.count - span - 1 + */ + __pyx_v_p = (__pyx_v_self->order - 1); + + /* "ezdxf/acc/bspline.pyx":118 + * cdef int span = self.find_span(t) + * cdef int p = self.order - 1 + * cdef int front = span - p # <<<<<<<<<<<<<< + * cdef int back = self.count - span - 1 + * cdef list result + */ + __pyx_v_front = (__pyx_v_span - __pyx_v_p); + + /* "ezdxf/acc/bspline.pyx":119 + * cdef int p = self.order - 1 + * cdef int front = span - p + * cdef int back = self.count - span - 1 # <<<<<<<<<<<<<< + * cdef list result + * if front > 0: + */ + __pyx_v_back = ((__pyx_v_self->count - __pyx_v_span) - 1); + + /* "ezdxf/acc/bspline.pyx":121 + * cdef int back = self.count - span - 1 + * cdef list result + * if front > 0: # <<<<<<<<<<<<<< + * result = NULL_LIST * front + * result.extend(self.basis_funcs(span, t)) + */ + __pyx_t_8 = (__pyx_v_front > 0); + if (__pyx_t_8) { + + /* "ezdxf/acc/bspline.pyx":122 + * cdef list result + * if front > 0: + * result = NULL_LIST * front # <<<<<<<<<<<<<< + * result.extend(self.basis_funcs(span, t)) + * else: + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_NULL_LIST); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_front); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (!(likely(PyList_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_4))) __PYX_ERR(0, 122, __pyx_L1_error) + __pyx_v_result = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/bspline.pyx":123 + * if front > 0: + * result = NULL_LIST * front + * result.extend(self.basis_funcs(span, t)) # <<<<<<<<<<<<<< + * else: + * result = self.basis_funcs(span, t) + */ + if (unlikely(__pyx_v_result == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "extend"); + __PYX_ERR(0, 123, __pyx_L1_error) + } + __pyx_t_4 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self->__pyx_vtab)->basis_funcs(__pyx_v_self, __pyx_v_span, __pyx_v_t, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = __Pyx_PyList_Extend(__pyx_v_result, __pyx_t_4); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/bspline.pyx":121 + * cdef int back = self.count - span - 1 + * cdef list result + * if front > 0: # <<<<<<<<<<<<<< + * result = NULL_LIST * front + * result.extend(self.basis_funcs(span, t)) + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/bspline.pyx":125 + * result.extend(self.basis_funcs(span, t)) + * else: + * result = self.basis_funcs(span, t) # <<<<<<<<<<<<<< + * if back > 0: + * result.extend(NULL_LIST * back) + */ + /*else*/ { + __pyx_t_4 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self->__pyx_vtab)->basis_funcs(__pyx_v_self, __pyx_v_span, __pyx_v_t, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 125, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_v_result = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + } + __pyx_L3:; + + /* "ezdxf/acc/bspline.pyx":126 + * else: + * result = self.basis_funcs(span, t) + * if back > 0: # <<<<<<<<<<<<<< + * result.extend(NULL_LIST * back) + * return result + */ + __pyx_t_8 = (__pyx_v_back > 0); + if (__pyx_t_8) { + + /* "ezdxf/acc/bspline.pyx":127 + * result = self.basis_funcs(span, t) + * if back > 0: + * result.extend(NULL_LIST * back) # <<<<<<<<<<<<<< + * return result + * + */ + if (unlikely(__pyx_v_result == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "extend"); + __PYX_ERR(0, 127, __pyx_L1_error) + } + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NULL_LIST); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_back); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyNumber_Multiply(__pyx_t_4, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyList_Extend(__pyx_v_result, __pyx_t_1); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":126 + * else: + * result = self.basis_funcs(span, t) + * if back > 0: # <<<<<<<<<<<<<< + * result.extend(NULL_LIST * back) + * return result + */ + } + + /* "ezdxf/acc/bspline.pyx":128 + * if back > 0: + * result.extend(NULL_LIST * back) + * return result # <<<<<<<<<<<<<< + * + * cpdef int find_span(self, double u): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":113 + * return bool(self.weights_) + * + * cpdef list basis_vector(self, double t): # <<<<<<<<<<<<<< + * """ Returns the expanded basis vector. """ + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_vector", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5basis_vector(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_7bspline_5Basis_4basis_vector, " Returns the expanded basis vector. "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_5basis_vector = {"basis_vector", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5basis_vector, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_7bspline_5Basis_4basis_vector}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5basis_vector(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_t; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("basis_vector (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 113, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "basis_vector") < 0)) __PYX_ERR(0, 113, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_t == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 113, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("basis_vector", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 113, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_vector", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_4basis_vector(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_4basis_vector(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_t) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_vector", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_vector(__pyx_v_self, __pyx_v_t, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_vector", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":130 + * return result + * + * cpdef int find_span(self, double u): # <<<<<<<<<<<<<< + * """ Determine the knot span index. """ + * # Linear search is more reliable than binary search of the Algorithm A2.1 + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7find_span(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static int __pyx_f_5ezdxf_3acc_7bspline_5Basis_find_span(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch) { + double *__pyx_v_knots; + int __pyx_v_count; + int __pyx_v_p; + int __pyx_v_span; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_t_7; + double *__pyx_t_8; + int __pyx_t_9; + int __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("find_span", 1); + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_find_span); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_5Basis_7find_span)) { + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_u); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __pyx_t_7 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_7 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_7; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":134 + * # Linear search is more reliable than binary search of the Algorithm A2.1 + * # from The NURBS Book by Piegl & Tiller. + * cdef double *knots = self._knots # <<<<<<<<<<<<<< + * cdef int count = self.count # text book: n+1 + * cdef int p = self.order - 1 + */ + __pyx_t_8 = __pyx_v_self->_knots; + __pyx_v_knots = __pyx_t_8; + + /* "ezdxf/acc/bspline.pyx":135 + * # from The NURBS Book by Piegl & Tiller. + * cdef double *knots = self._knots + * cdef int count = self.count # text book: n+1 # <<<<<<<<<<<<<< + * cdef int p = self.order - 1 + * cdef int span + */ + __pyx_t_7 = __pyx_v_self->count; + __pyx_v_count = __pyx_t_7; + + /* "ezdxf/acc/bspline.pyx":136 + * cdef double *knots = self._knots + * cdef int count = self.count # text book: n+1 + * cdef int p = self.order - 1 # <<<<<<<<<<<<<< + * cdef int span + * if u >= knots[count]: # special case + */ + __pyx_v_p = (__pyx_v_self->order - 1); + + /* "ezdxf/acc/bspline.pyx":138 + * cdef int p = self.order - 1 + * cdef int span + * if u >= knots[count]: # special case # <<<<<<<<<<<<<< + * return count - 1 + * + */ + __pyx_t_9 = (__pyx_v_u >= (__pyx_v_knots[__pyx_v_count])); + if (__pyx_t_9) { + + /* "ezdxf/acc/bspline.pyx":139 + * cdef int span + * if u >= knots[count]: # special case + * return count - 1 # <<<<<<<<<<<<<< + * + * # common clamped spline: + */ + __pyx_r = (__pyx_v_count - 1); + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":138 + * cdef int p = self.order - 1 + * cdef int span + * if u >= knots[count]: # special case # <<<<<<<<<<<<<< + * return count - 1 + * + */ + } + + /* "ezdxf/acc/bspline.pyx":142 + * + * # common clamped spline: + * if knots[p] == 0.0: # use binary search # <<<<<<<<<<<<<< + * # This is fast and works most of the time, + * # but Test 621 : test_weired_closed_spline() + */ + __pyx_t_9 = ((__pyx_v_knots[__pyx_v_p]) == 0.0); + if (__pyx_t_9) { + + /* "ezdxf/acc/bspline.pyx":147 + * # goes into an infinity loop, because of + * # a weird knot configuration. + * return bisect_right(knots, u, p, count) - 1 # <<<<<<<<<<<<<< + * else: # use linear search + * span = 0 + */ + __pyx_t_7 = __pyx_f_5ezdxf_3acc_7bspline_bisect_right(__pyx_v_knots, __pyx_v_u, __pyx_v_p, __pyx_v_count); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 147, __pyx_L1_error) + __pyx_r = (__pyx_t_7 - 1); + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":142 + * + * # common clamped spline: + * if knots[p] == 0.0: # use binary search # <<<<<<<<<<<<<< + * # This is fast and works most of the time, + * # but Test 621 : test_weired_closed_spline() + */ + } + + /* "ezdxf/acc/bspline.pyx":149 + * return bisect_right(knots, u, p, count) - 1 + * else: # use linear search + * span = 0 # <<<<<<<<<<<<<< + * while knots[span] <= u and span < count: + * span += 1 + */ + /*else*/ { + __pyx_v_span = 0; + + /* "ezdxf/acc/bspline.pyx":150 + * else: # use linear search + * span = 0 + * while knots[span] <= u and span < count: # <<<<<<<<<<<<<< + * span += 1 + * return span - 1 + */ + while (1) { + __pyx_t_10 = ((__pyx_v_knots[__pyx_v_span]) <= __pyx_v_u); + if (__pyx_t_10) { + } else { + __pyx_t_9 = __pyx_t_10; + goto __pyx_L7_bool_binop_done; + } + __pyx_t_10 = (__pyx_v_span < __pyx_v_count); + __pyx_t_9 = __pyx_t_10; + __pyx_L7_bool_binop_done:; + if (!__pyx_t_9) break; + + /* "ezdxf/acc/bspline.pyx":151 + * span = 0 + * while knots[span] <= u and span < count: + * span += 1 # <<<<<<<<<<<<<< + * return span - 1 + * + */ + __pyx_v_span = (__pyx_v_span + 1); + } + + /* "ezdxf/acc/bspline.pyx":152 + * while knots[span] <= u and span < count: + * span += 1 + * return span - 1 # <<<<<<<<<<<<<< + * + * cpdef list basis_funcs(self, int span, double u): + */ + __pyx_r = (__pyx_v_span - 1); + goto __pyx_L0; + } + + /* "ezdxf/acc/bspline.pyx":130 + * return result + * + * cpdef int find_span(self, double u): # <<<<<<<<<<<<<< + * """ Determine the knot span index. """ + * # Linear search is more reliable than binary search of the Algorithm A2.1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.find_span", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7find_span(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_7bspline_5Basis_6find_span, " Determine the knot span index. "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_7find_span = {"find_span", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7find_span, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_7bspline_5Basis_6find_span}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_7find_span(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_u; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("find_span (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_u,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_u)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 130, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "find_span") < 0)) __PYX_ERR(0, 130, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_u = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_u == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 130, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("find_span", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 130, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.find_span", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_6find_span(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_u); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_6find_span(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, double __pyx_v_u) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("find_span", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_5Basis_find_span(__pyx_v_self, __pyx_v_u, 1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 130, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.find_span", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":154 + * return span - 1 + * + * cpdef list basis_funcs(self, int span, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_9basis_funcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_skip_dispatch) { + int __pyx_v_order; + double *__pyx_v_knots; + double __pyx_v_N[MAX_SPLINE_ORDER]; + double __pyx_v_left[MAX_SPLINE_ORDER]; + double __pyx_v_right[MAX_SPLINE_ORDER]; + PyObject *__pyx_v_result = 0; + int __pyx_v_j; + int __pyx_v_r; + int __pyx_v_i1; + double __pyx_v_temp; + double __pyx_v_saved; + double __pyx_v_temp_r; + double __pyx_v_temp_l; + double __pyx_8genexpr3__pyx_v_x; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + unsigned int __pyx_t_7; + int __pyx_t_8; + double *__pyx_t_9; + int __pyx_t_10; + int __pyx_t_11; + int __pyx_t_12; + int __pyx_t_13; + int __pyx_t_14; + int __pyx_t_15; + double __pyx_t_16; + double *__pyx_t_17; + double *__pyx_t_18; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_funcs", 1); + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_basis_funcs); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_5Basis_9basis_funcs)) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_span); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_u); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_5 = __pyx_t_1; __pyx_t_6 = NULL; + __pyx_t_7 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_7 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_6, __pyx_t_3, __pyx_t_4}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_7, 2+__pyx_t_7); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 154, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":156 + * cpdef list basis_funcs(self, int span, double u): + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order # <<<<<<<<<<<<<< + * cdef double *knots = self._knots + * cdef double[MAX_SPLINE_ORDER] N, left, right + */ + __pyx_t_8 = __pyx_v_self->order; + __pyx_v_order = __pyx_t_8; + + /* "ezdxf/acc/bspline.pyx":157 + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order + * cdef double *knots = self._knots # <<<<<<<<<<<<<< + * cdef double[MAX_SPLINE_ORDER] N, left, right + * cdef list result + */ + __pyx_t_9 = __pyx_v_self->_knots; + __pyx_v_knots = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":160 + * cdef double[MAX_SPLINE_ORDER] N, left, right + * cdef list result + * reset_double_array(N, order, 0.0) # <<<<<<<<<<<<<< + * reset_double_array(left, order, 0.0) + * reset_double_array(right, order, 0.0) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(__pyx_v_N, __pyx_v_order, 0.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":161 + * cdef list result + * reset_double_array(N, order, 0.0) + * reset_double_array(left, order, 0.0) # <<<<<<<<<<<<<< + * reset_double_array(right, order, 0.0) + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(__pyx_v_left, __pyx_v_order, 0.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":162 + * reset_double_array(N, order, 0.0) + * reset_double_array(left, order, 0.0) + * reset_double_array(right, order, 0.0) # <<<<<<<<<<<<<< + * + * cdef int j, r, i1 + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(__pyx_v_right, __pyx_v_order, 0.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 162, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":166 + * cdef int j, r, i1 + * cdef double temp, saved, temp_r, temp_l + * N[0] = 1.0 # <<<<<<<<<<<<<< + * for j in range(1, order): + * i1 = span + 1 - j + */ + (__pyx_v_N[0]) = 1.0; + + /* "ezdxf/acc/bspline.pyx":167 + * cdef double temp, saved, temp_r, temp_l + * N[0] = 1.0 + * for j in range(1, order): # <<<<<<<<<<<<<< + * i1 = span + 1 - j + * if i1 < 0: + */ + __pyx_t_8 = __pyx_v_order; + __pyx_t_10 = __pyx_t_8; + for (__pyx_t_11 = 1; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) { + __pyx_v_j = __pyx_t_11; + + /* "ezdxf/acc/bspline.pyx":168 + * N[0] = 1.0 + * for j in range(1, order): + * i1 = span + 1 - j # <<<<<<<<<<<<<< + * if i1 < 0: + * i1 = 0 + */ + __pyx_v_i1 = ((__pyx_v_span + 1) - __pyx_v_j); + + /* "ezdxf/acc/bspline.pyx":169 + * for j in range(1, order): + * i1 = span + 1 - j + * if i1 < 0: # <<<<<<<<<<<<<< + * i1 = 0 + * left[j] = u - knots[i1] + */ + __pyx_t_12 = (__pyx_v_i1 < 0); + if (__pyx_t_12) { + + /* "ezdxf/acc/bspline.pyx":170 + * i1 = span + 1 - j + * if i1 < 0: + * i1 = 0 # <<<<<<<<<<<<<< + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u + */ + __pyx_v_i1 = 0; + + /* "ezdxf/acc/bspline.pyx":169 + * for j in range(1, order): + * i1 = span + 1 - j + * if i1 < 0: # <<<<<<<<<<<<<< + * i1 = 0 + * left[j] = u - knots[i1] + */ + } + + /* "ezdxf/acc/bspline.pyx":171 + * if i1 < 0: + * i1 = 0 + * left[j] = u - knots[i1] # <<<<<<<<<<<<<< + * right[j] = knots[span + j] - u + * saved = 0.0 + */ + (__pyx_v_left[__pyx_v_j]) = (__pyx_v_u - (__pyx_v_knots[__pyx_v_i1])); + + /* "ezdxf/acc/bspline.pyx":172 + * i1 = 0 + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u # <<<<<<<<<<<<<< + * saved = 0.0 + * for r in range(j): + */ + (__pyx_v_right[__pyx_v_j]) = ((__pyx_v_knots[(__pyx_v_span + __pyx_v_j)]) - __pyx_v_u); + + /* "ezdxf/acc/bspline.pyx":173 + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u + * saved = 0.0 # <<<<<<<<<<<<<< + * for r in range(j): + * temp_r = right[r + 1] + */ + __pyx_v_saved = 0.0; + + /* "ezdxf/acc/bspline.pyx":174 + * right[j] = knots[span + j] - u + * saved = 0.0 + * for r in range(j): # <<<<<<<<<<<<<< + * temp_r = right[r + 1] + * temp_l = left[j - r] + */ + __pyx_t_13 = __pyx_v_j; + __pyx_t_14 = __pyx_t_13; + for (__pyx_t_15 = 0; __pyx_t_15 < __pyx_t_14; __pyx_t_15+=1) { + __pyx_v_r = __pyx_t_15; + + /* "ezdxf/acc/bspline.pyx":175 + * saved = 0.0 + * for r in range(j): + * temp_r = right[r + 1] # <<<<<<<<<<<<<< + * temp_l = left[j - r] + * temp = N[r] / (temp_r + temp_l) + */ + __pyx_v_temp_r = (__pyx_v_right[(__pyx_v_r + 1)]); + + /* "ezdxf/acc/bspline.pyx":176 + * for r in range(j): + * temp_r = right[r + 1] + * temp_l = left[j - r] # <<<<<<<<<<<<<< + * temp = N[r] / (temp_r + temp_l) + * N[r] = saved + temp_r * temp + */ + __pyx_v_temp_l = (__pyx_v_left[(__pyx_v_j - __pyx_v_r)]); + + /* "ezdxf/acc/bspline.pyx":177 + * temp_r = right[r + 1] + * temp_l = left[j - r] + * temp = N[r] / (temp_r + temp_l) # <<<<<<<<<<<<<< + * N[r] = saved + temp_r * temp + * saved = temp_l * temp + */ + __pyx_t_16 = (__pyx_v_temp_r + __pyx_v_temp_l); + if (unlikely(__pyx_t_16 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 177, __pyx_L1_error) + } + __pyx_v_temp = ((__pyx_v_N[__pyx_v_r]) / __pyx_t_16); + + /* "ezdxf/acc/bspline.pyx":178 + * temp_l = left[j - r] + * temp = N[r] / (temp_r + temp_l) + * N[r] = saved + temp_r * temp # <<<<<<<<<<<<<< + * saved = temp_l * temp + * N[j] = saved + */ + (__pyx_v_N[__pyx_v_r]) = (__pyx_v_saved + (__pyx_v_temp_r * __pyx_v_temp)); + + /* "ezdxf/acc/bspline.pyx":179 + * temp = N[r] / (temp_r + temp_l) + * N[r] = saved + temp_r * temp + * saved = temp_l * temp # <<<<<<<<<<<<<< + * N[j] = saved + * result = [x for x in N[:order]] + */ + __pyx_v_saved = (__pyx_v_temp_l * __pyx_v_temp); + } + + /* "ezdxf/acc/bspline.pyx":180 + * N[r] = saved + temp_r * temp + * saved = temp_l * temp + * N[j] = saved # <<<<<<<<<<<<<< + * result = [x for x in N[:order]] + * if self.is_rational: + */ + (__pyx_v_N[__pyx_v_j]) = __pyx_v_saved; + } + + /* "ezdxf/acc/bspline.pyx":181 + * saved = temp_l * temp + * N[j] = saved + * result = [x for x in N[:order]] # <<<<<<<<<<<<<< + * if self.is_rational: + * return self.span_weighting(result, span) + */ + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_17 = (__pyx_v_N + __pyx_v_order); + for (__pyx_t_18 = __pyx_v_N; __pyx_t_18 < __pyx_t_17; __pyx_t_18++) { + __pyx_t_9 = __pyx_t_18; + __pyx_8genexpr3__pyx_v_x = (__pyx_t_9[0]); + __pyx_t_2 = PyFloat_FromDouble(__pyx_8genexpr3__pyx_v_x); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_2))) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + } /* exit inner scope */ + __pyx_v_result = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":182 + * N[j] = saved + * result = [x for x in N[:order]] + * if self.is_rational: # <<<<<<<<<<<<<< + * return self.span_weighting(result, span) + * else: + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_is_rational); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_12 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_12 < 0))) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_12) { + + /* "ezdxf/acc/bspline.pyx":183 + * result = [x for x in N[:order]] + * if self.is_rational: + * return self.span_weighting(result, span) # <<<<<<<<<<<<<< + * else: + * return result + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self->__pyx_vtab)->span_weighting(__pyx_v_self, __pyx_v_result, __pyx_v_span, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":182 + * N[j] = saved + * result = [x for x in N[:order]] + * if self.is_rational: # <<<<<<<<<<<<<< + * return self.span_weighting(result, span) + * else: + */ + } + + /* "ezdxf/acc/bspline.pyx":185 + * return self.span_weighting(result, span) + * else: + * return result # <<<<<<<<<<<<<< + * + * cpdef list span_weighting(self, nbasis: list[float], int span): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + } + + /* "ezdxf/acc/bspline.pyx":154 + * return span - 1 + * + * cpdef list basis_funcs(self, int span, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_9basis_funcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_9basis_funcs = {"basis_funcs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_9basis_funcs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_9basis_funcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_span; + double __pyx_v_u; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("basis_funcs (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_span,&__pyx_n_s_u,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_span)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 154, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_u)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 154, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("basis_funcs", 1, 2, 2, 1); __PYX_ERR(0, 154, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "basis_funcs") < 0)) __PYX_ERR(0, 154, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_span = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_span == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 154, __pyx_L3_error) + __pyx_v_u = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_u == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 154, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("basis_funcs", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 154, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_8basis_funcs(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_span, __pyx_v_u); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_8basis_funcs(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_funcs", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs(__pyx_v_self, __pyx_v_span, __pyx_v_u, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":187 + * return result + * + * cpdef list span_weighting(self, nbasis: list[float], int span): # <<<<<<<<<<<<<< + * cdef list products = [ + * nb * w for nb, w in zip( + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11span_weighting(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_span_weighting(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_nbasis, int __pyx_v_span, int __pyx_skip_dispatch) { + PyObject *__pyx_v_products = 0; + PyObject *__pyx_v_s = NULL; + PyObject *__pyx_8genexpr4__pyx_v_nb = NULL; + PyObject *__pyx_8genexpr4__pyx_v_w = NULL; + PyObject *__pyx_8genexpr5__pyx_v_p = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + Py_ssize_t __pyx_t_7; + PyObject *(*__pyx_t_8)(PyObject *); + PyObject *__pyx_t_9 = NULL; + PyObject *(*__pyx_t_10)(PyObject *); + int __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("span_weighting", 1); + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_span_weighting); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_5Basis_11span_weighting)) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_span); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_v_nbasis, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 187, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":188 + * + * cpdef list span_weighting(self, nbasis: list[float], int span): + * cdef list products = [ # <<<<<<<<<<<<<< + * nb * w for nb, w in zip( + * nbasis, + */ + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "ezdxf/acc/bspline.pyx":191 + * nb * w for nb, w in zip( + * nbasis, + * self.weights_[span - self.order + 1: span + 1] # <<<<<<<<<<<<<< + * ) + * ] + */ + if (unlikely(__pyx_v_self->weights_ == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 191, __pyx_L5_error) + } + __pyx_t_2 = __Pyx_PyTuple_GetSlice(__pyx_v_self->weights_, ((__pyx_v_span - __pyx_v_self->order) + 1), (__pyx_v_span + 1)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 191, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "ezdxf/acc/bspline.pyx":189 + * cpdef list span_weighting(self, nbasis: list[float], int span): + * cdef list products = [ + * nb * w for nb, w in zip( # <<<<<<<<<<<<<< + * nbasis, + * self.weights_[span - self.order + 1: span + 1] + */ + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_nbasis); + __Pyx_GIVEREF(__pyx_v_nbasis); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_nbasis)) __PYX_ERR(0, 189, __pyx_L5_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_2)) __PYX_ERR(0, 189, __pyx_L5_error); + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_zip, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { + __pyx_t_4 = __pyx_t_2; __Pyx_INCREF(__pyx_t_4); + __pyx_t_7 = 0; + __pyx_t_8 = NULL; + } else { + __pyx_t_7 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 189, __pyx_L5_error) + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + for (;;) { + if (likely(!__pyx_t_8)) { + if (likely(PyList_CheckExact(__pyx_t_4))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 189, __pyx_L5_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 189, __pyx_L5_error) + #else + __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 189, __pyx_L5_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 189, __pyx_L5_error) + #else + __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } + } else { + __pyx_t_2 = __pyx_t_8(__pyx_t_4); + if (unlikely(!__pyx_t_2)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 189, __pyx_L5_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_2); + } + if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) { + PyObject* sequence = __pyx_t_2; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 189, __pyx_L5_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_3 = PyList_GET_ITEM(sequence, 0); + __pyx_t_5 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_5); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_9 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_10 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_9); + index = 0; __pyx_t_3 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_3)) goto __pyx_L8_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_5 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_5)) goto __pyx_L8_unpacking_failed; + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_10(__pyx_t_9), 2) < 0) __PYX_ERR(0, 189, __pyx_L5_error) + __pyx_t_10 = NULL; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L9_unpacking_done; + __pyx_L8_unpacking_failed:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_10 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 189, __pyx_L5_error) + __pyx_L9_unpacking_done:; + } + __Pyx_XDECREF_SET(__pyx_8genexpr4__pyx_v_nb, __pyx_t_3); + __pyx_t_3 = 0; + __Pyx_XDECREF_SET(__pyx_8genexpr4__pyx_v_w, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_2 = PyNumber_Multiply(__pyx_8genexpr4__pyx_v_nb, __pyx_8genexpr4__pyx_v_w); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 189, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_2))) __PYX_ERR(0, 188, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_nb); __pyx_8genexpr4__pyx_v_nb = 0; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_w); __pyx_8genexpr4__pyx_v_w = 0; + goto __pyx_L11_exit_scope; + __pyx_L5_error:; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_nb); __pyx_8genexpr4__pyx_v_nb = 0; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_w); __pyx_8genexpr4__pyx_v_w = 0; + goto __pyx_L1_error; + __pyx_L11_exit_scope:; + } /* exit inner scope */ + __pyx_v_products = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":194 + * ) + * ] + * s = sum(products) # <<<<<<<<<<<<<< + * if s != 0: + * return [p / s for p in products] + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_sum, __pyx_v_products); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 194, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_s = __pyx_t_1; + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":195 + * ] + * s = sum(products) + * if s != 0: # <<<<<<<<<<<<<< + * return [p / s for p in products] + * else: + */ + __pyx_t_11 = (__Pyx_PyInt_BoolNeObjC(__pyx_v_s, __pyx_int_0, 0, 0)); if (unlikely((__pyx_t_11 < 0))) __PYX_ERR(0, 195, __pyx_L1_error) + if (__pyx_t_11) { + + /* "ezdxf/acc/bspline.pyx":196 + * s = sum(products) + * if s != 0: + * return [p / s for p in products] # <<<<<<<<<<<<<< + * else: + * return NULL_LIST * len(nbasis) + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 196, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __pyx_v_products; __Pyx_INCREF(__pyx_t_4); + __pyx_t_7 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 196, __pyx_L15_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely((0 < 0))) __PYX_ERR(0, 196, __pyx_L15_error) + #else + __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 196, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + __Pyx_XDECREF_SET(__pyx_8genexpr5__pyx_v_p, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyNumber_Divide(__pyx_8genexpr5__pyx_v_p, __pyx_v_s); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 196, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_2); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_2))) __PYX_ERR(0, 196, __pyx_L15_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_p); __pyx_8genexpr5__pyx_v_p = 0; + goto __pyx_L19_exit_scope; + __pyx_L15_error:; + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_p); __pyx_8genexpr5__pyx_v_p = 0; + goto __pyx_L1_error; + __pyx_L19_exit_scope:; + } /* exit inner scope */ + __pyx_r = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":195 + * ] + * s = sum(products) + * if s != 0: # <<<<<<<<<<<<<< + * return [p / s for p in products] + * else: + */ + } + + /* "ezdxf/acc/bspline.pyx":198 + * return [p / s for p in products] + * else: + * return NULL_LIST * len(nbasis) # <<<<<<<<<<<<<< + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_NULL_LIST); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyList_GET_SIZE(__pyx_v_nbasis); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 198, __pyx_L1_error) + __pyx_t_4 = PyInt_FromSsize_t(__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 198, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "ezdxf/acc/bspline.pyx":187 + * return result + * + * cpdef list span_weighting(self, nbasis: list[float], int span): # <<<<<<<<<<<<<< + * cdef list products = [ + * nb * w for nb, w in zip( + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.span_weighting", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_products); + __Pyx_XDECREF(__pyx_v_s); + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_nb); + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_w); + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_p); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11span_weighting(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_11span_weighting = {"span_weighting", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11span_weighting, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_11span_weighting(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_nbasis = 0; + int __pyx_v_span; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("span_weighting (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_nbasis,&__pyx_n_s_span,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_nbasis)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_span)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("span_weighting", 1, 2, 2, 1); __PYX_ERR(0, 187, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "span_weighting") < 0)) __PYX_ERR(0, 187, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_nbasis = ((PyObject*)values[0]); + __pyx_v_span = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_span == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("span_weighting", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 187, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.span_weighting", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_nbasis), (&PyList_Type), 0, "nbasis", 1))) __PYX_ERR(0, 187, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_10span_weighting(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_nbasis, __pyx_v_span); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_10span_weighting(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, PyObject *__pyx_v_nbasis, int __pyx_v_span) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("span_weighting", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_5Basis_span_weighting(__pyx_v_self, __pyx_v_nbasis, __pyx_v_span, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.span_weighting", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":200 + * return NULL_LIST * len(nbasis) + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): # <<<<<<<<<<<<<< + * # pyright: reportUndefinedVariable=false + * # pyright flags Cython multi-arrays incorrect: + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives *__pyx_optional_args) { + int __pyx_v_n = ((int)1); + int __pyx_v_order; + int __pyx_v_p; + double *__pyx_v_knots; + double __pyx_v_left[MAX_SPLINE_ORDER]; + double __pyx_v_right[MAX_SPLINE_ORDER]; + double __pyx_v_ndu[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER]; + int __pyx_v_j; + int __pyx_v_r; + int __pyx_v_i1; + double __pyx_v_temp; + double __pyx_v_saved; + double __pyx_v_tmp_r; + double __pyx_v_tmp_l; + double __pyx_v_derivatives[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER]; + double __pyx_v_a[2][MAX_SPLINE_ORDER]; + int __pyx_v_s1; + int __pyx_v_s2; + int __pyx_v_k; + int __pyx_v_rk; + int __pyx_v_pk; + int __pyx_v_j1; + int __pyx_v_j2; + int __pyx_v_t; + double __pyx_v_d; + double __pyx_v_rr; + PyObject *__pyx_v_result = 0; + PyObject *__pyx_v_row = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + unsigned int __pyx_t_8; + int __pyx_t_9; + int __pyx_t_10; + double *__pyx_t_11; + int __pyx_t_12; + int __pyx_t_13; + int __pyx_t_14; + int __pyx_t_15; + int __pyx_t_16; + double __pyx_t_17; + long __pyx_t_18; + long __pyx_t_19; + long __pyx_t_20; + long __pyx_t_21; + double __pyx_t_22; + int __pyx_t_23; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_funcs_derivatives", 1); + if (__pyx_optional_args) { + if (__pyx_optional_args->__pyx_n > 0) { + __pyx_v_n = __pyx_optional_args->n; + } + } + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_basis_funcs_derivatives); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives)) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_span); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_u); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_6 = __pyx_t_1; __pyx_t_7 = NULL; + __pyx_t_8 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_8 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[4] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+1-__pyx_t_8, 3+__pyx_t_8); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 200, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":206 + * # https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#c-arrays + * # Source: The NURBS Book: Algorithm A2.3 + * cdef int order = self.order # <<<<<<<<<<<<<< + * cdef int p = order - 1 + * if n > p: + */ + __pyx_t_9 = __pyx_v_self->order; + __pyx_v_order = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":207 + * # Source: The NURBS Book: Algorithm A2.3 + * cdef int order = self.order + * cdef int p = order - 1 # <<<<<<<<<<<<<< + * if n > p: + * n = p + */ + __pyx_v_p = (__pyx_v_order - 1); + + /* "ezdxf/acc/bspline.pyx":208 + * cdef int order = self.order + * cdef int p = order - 1 + * if n > p: # <<<<<<<<<<<<<< + * n = p + * cdef double *knots = self._knots + */ + __pyx_t_10 = (__pyx_v_n > __pyx_v_p); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":209 + * cdef int p = order - 1 + * if n > p: + * n = p # <<<<<<<<<<<<<< + * cdef double *knots = self._knots + * cdef double[MAX_SPLINE_ORDER] left, right + */ + __pyx_v_n = __pyx_v_p; + + /* "ezdxf/acc/bspline.pyx":208 + * cdef int order = self.order + * cdef int p = order - 1 + * if n > p: # <<<<<<<<<<<<<< + * n = p + * cdef double *knots = self._knots + */ + } + + /* "ezdxf/acc/bspline.pyx":210 + * if n > p: + * n = p + * cdef double *knots = self._knots # <<<<<<<<<<<<<< + * cdef double[MAX_SPLINE_ORDER] left, right + * reset_double_array(left, order, 1.0) + */ + __pyx_t_11 = __pyx_v_self->_knots; + __pyx_v_knots = __pyx_t_11; + + /* "ezdxf/acc/bspline.pyx":212 + * cdef double *knots = self._knots + * cdef double[MAX_SPLINE_ORDER] left, right + * reset_double_array(left, order, 1.0) # <<<<<<<<<<<<<< + * reset_double_array(right, order, 1.0) + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(__pyx_v_left, __pyx_v_order, 1.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":213 + * cdef double[MAX_SPLINE_ORDER] left, right + * reset_double_array(left, order, 1.0) + * reset_double_array(right, order, 1.0) # <<<<<<<<<<<<<< + * + * cdef double[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER] ndu # pyright: ignore + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(__pyx_v_right, __pyx_v_order, 1.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 213, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":216 + * + * cdef double[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER] ndu # pyright: ignore + * reset_double_array( ndu, MAX_SPLINE_ORDER*MAX_SPLINE_ORDER, 1.0) # <<<<<<<<<<<<<< + * + * cdef int j, r, i1 + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(((double *)__pyx_v_ndu), (MAX_SPLINE_ORDER * MAX_SPLINE_ORDER), 1.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 216, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":220 + * cdef int j, r, i1 + * cdef double temp, saved, tmp_r, tmp_l + * for j in range(1, order): # <<<<<<<<<<<<<< + * i1 = span + 1 - j + * if i1 < 0: + */ + __pyx_t_9 = __pyx_v_order; + __pyx_t_12 = __pyx_t_9; + for (__pyx_t_13 = 1; __pyx_t_13 < __pyx_t_12; __pyx_t_13+=1) { + __pyx_v_j = __pyx_t_13; + + /* "ezdxf/acc/bspline.pyx":221 + * cdef double temp, saved, tmp_r, tmp_l + * for j in range(1, order): + * i1 = span + 1 - j # <<<<<<<<<<<<<< + * if i1 < 0: + * i1 = 0 + */ + __pyx_v_i1 = ((__pyx_v_span + 1) - __pyx_v_j); + + /* "ezdxf/acc/bspline.pyx":222 + * for j in range(1, order): + * i1 = span + 1 - j + * if i1 < 0: # <<<<<<<<<<<<<< + * i1 = 0 + * left[j] = u - knots[i1] + */ + __pyx_t_10 = (__pyx_v_i1 < 0); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":223 + * i1 = span + 1 - j + * if i1 < 0: + * i1 = 0 # <<<<<<<<<<<<<< + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u + */ + __pyx_v_i1 = 0; + + /* "ezdxf/acc/bspline.pyx":222 + * for j in range(1, order): + * i1 = span + 1 - j + * if i1 < 0: # <<<<<<<<<<<<<< + * i1 = 0 + * left[j] = u - knots[i1] + */ + } + + /* "ezdxf/acc/bspline.pyx":224 + * if i1 < 0: + * i1 = 0 + * left[j] = u - knots[i1] # <<<<<<<<<<<<<< + * right[j] = knots[span + j] - u + * saved = 0.0 + */ + (__pyx_v_left[__pyx_v_j]) = (__pyx_v_u - (__pyx_v_knots[__pyx_v_i1])); + + /* "ezdxf/acc/bspline.pyx":225 + * i1 = 0 + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u # <<<<<<<<<<<<<< + * saved = 0.0 + * for r in range(j): + */ + (__pyx_v_right[__pyx_v_j]) = ((__pyx_v_knots[(__pyx_v_span + __pyx_v_j)]) - __pyx_v_u); + + /* "ezdxf/acc/bspline.pyx":226 + * left[j] = u - knots[i1] + * right[j] = knots[span + j] - u + * saved = 0.0 # <<<<<<<<<<<<<< + * for r in range(j): + * # lower triangle + */ + __pyx_v_saved = 0.0; + + /* "ezdxf/acc/bspline.pyx":227 + * right[j] = knots[span + j] - u + * saved = 0.0 + * for r in range(j): # <<<<<<<<<<<<<< + * # lower triangle + * tmp_r = right[r + 1] + */ + __pyx_t_14 = __pyx_v_j; + __pyx_t_15 = __pyx_t_14; + for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) { + __pyx_v_r = __pyx_t_16; + + /* "ezdxf/acc/bspline.pyx":229 + * for r in range(j): + * # lower triangle + * tmp_r = right[r + 1] # <<<<<<<<<<<<<< + * tmp_l = left[j - r] + * ndu[j][r] = tmp_r + tmp_l + */ + __pyx_v_tmp_r = (__pyx_v_right[(__pyx_v_r + 1)]); + + /* "ezdxf/acc/bspline.pyx":230 + * # lower triangle + * tmp_r = right[r + 1] + * tmp_l = left[j - r] # <<<<<<<<<<<<<< + * ndu[j][r] = tmp_r + tmp_l + * temp = ndu[r][j - 1] / ndu[j][r] + */ + __pyx_v_tmp_l = (__pyx_v_left[(__pyx_v_j - __pyx_v_r)]); + + /* "ezdxf/acc/bspline.pyx":231 + * tmp_r = right[r + 1] + * tmp_l = left[j - r] + * ndu[j][r] = tmp_r + tmp_l # <<<<<<<<<<<<<< + * temp = ndu[r][j - 1] / ndu[j][r] + * # upper triangle + */ + ((__pyx_v_ndu[__pyx_v_j])[__pyx_v_r]) = (__pyx_v_tmp_r + __pyx_v_tmp_l); + + /* "ezdxf/acc/bspline.pyx":232 + * tmp_l = left[j - r] + * ndu[j][r] = tmp_r + tmp_l + * temp = ndu[r][j - 1] / ndu[j][r] # <<<<<<<<<<<<<< + * # upper triangle + * ndu[r][j] = saved + (tmp_r * temp) + */ + __pyx_t_17 = ((__pyx_v_ndu[__pyx_v_r])[(__pyx_v_j - 1)]); + if (unlikely(((__pyx_v_ndu[__pyx_v_j])[__pyx_v_r]) == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 232, __pyx_L1_error) + } + __pyx_v_temp = (__pyx_t_17 / ((__pyx_v_ndu[__pyx_v_j])[__pyx_v_r])); + + /* "ezdxf/acc/bspline.pyx":234 + * temp = ndu[r][j - 1] / ndu[j][r] + * # upper triangle + * ndu[r][j] = saved + (tmp_r * temp) # <<<<<<<<<<<<<< + * saved = tmp_l * temp + * ndu[j][j] = saved + */ + ((__pyx_v_ndu[__pyx_v_r])[__pyx_v_j]) = (__pyx_v_saved + (__pyx_v_tmp_r * __pyx_v_temp)); + + /* "ezdxf/acc/bspline.pyx":235 + * # upper triangle + * ndu[r][j] = saved + (tmp_r * temp) + * saved = tmp_l * temp # <<<<<<<<<<<<<< + * ndu[j][j] = saved + * + */ + __pyx_v_saved = (__pyx_v_tmp_l * __pyx_v_temp); + } + + /* "ezdxf/acc/bspline.pyx":236 + * ndu[r][j] = saved + (tmp_r * temp) + * saved = tmp_l * temp + * ndu[j][j] = saved # <<<<<<<<<<<<<< + * + * # load the basis_vector functions + */ + ((__pyx_v_ndu[__pyx_v_j])[__pyx_v_j]) = __pyx_v_saved; + } + + /* "ezdxf/acc/bspline.pyx":240 + * # load the basis_vector functions + * cdef double[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER] derivatives # pyright: ignore + * reset_double_array( # <<<<<<<<<<<<<< + * derivatives, MAX_SPLINE_ORDER*MAX_SPLINE_ORDER, 0.0 + * ) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(((double *)__pyx_v_derivatives), (MAX_SPLINE_ORDER * MAX_SPLINE_ORDER), 0.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 240, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":243 + * derivatives, MAX_SPLINE_ORDER*MAX_SPLINE_ORDER, 0.0 + * ) + * for j in range(order): # <<<<<<<<<<<<<< + * derivatives[0][j] = ndu[j][p] + * + */ + __pyx_t_9 = __pyx_v_order; + __pyx_t_12 = __pyx_t_9; + for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_12; __pyx_t_13+=1) { + __pyx_v_j = __pyx_t_13; + + /* "ezdxf/acc/bspline.pyx":244 + * ) + * for j in range(order): + * derivatives[0][j] = ndu[j][p] # <<<<<<<<<<<<<< + * + * # loop over function index + */ + ((__pyx_v_derivatives[0])[__pyx_v_j]) = ((__pyx_v_ndu[__pyx_v_j])[__pyx_v_p]); + } + + /* "ezdxf/acc/bspline.pyx":248 + * # loop over function index + * cdef double[2][MAX_SPLINE_ORDER] a # pyright: ignore + * reset_double_array( a, 2*MAX_SPLINE_ORDER, 1.0) # <<<<<<<<<<<<<< + * + * cdef int s1, s2, k, rk, pk, j1, j2, t + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_7bspline_reset_double_array(((double *)__pyx_v_a), (2 * MAX_SPLINE_ORDER), 1.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":252 + * cdef int s1, s2, k, rk, pk, j1, j2, t + * cdef double d + * for r in range(order): # <<<<<<<<<<<<<< + * s1 = 0 + * s2 = 1 + */ + __pyx_t_9 = __pyx_v_order; + __pyx_t_12 = __pyx_t_9; + for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_12; __pyx_t_13+=1) { + __pyx_v_r = __pyx_t_13; + + /* "ezdxf/acc/bspline.pyx":253 + * cdef double d + * for r in range(order): + * s1 = 0 # <<<<<<<<<<<<<< + * s2 = 1 + * # alternate rows in array a + */ + __pyx_v_s1 = 0; + + /* "ezdxf/acc/bspline.pyx":254 + * for r in range(order): + * s1 = 0 + * s2 = 1 # <<<<<<<<<<<<<< + * # alternate rows in array a + * a[0][0] = 1.0 + */ + __pyx_v_s2 = 1; + + /* "ezdxf/acc/bspline.pyx":256 + * s2 = 1 + * # alternate rows in array a + * a[0][0] = 1.0 # <<<<<<<<<<<<<< + * + * # loop to compute kth derivative + */ + ((__pyx_v_a[0])[0]) = 1.0; + + /* "ezdxf/acc/bspline.pyx":259 + * + * # loop to compute kth derivative + * for k in range(1, n + 1): # <<<<<<<<<<<<<< + * d = 0.0 + * rk = r - k + */ + __pyx_t_18 = (__pyx_v_n + 1); + __pyx_t_19 = __pyx_t_18; + for (__pyx_t_14 = 1; __pyx_t_14 < __pyx_t_19; __pyx_t_14+=1) { + __pyx_v_k = __pyx_t_14; + + /* "ezdxf/acc/bspline.pyx":260 + * # loop to compute kth derivative + * for k in range(1, n + 1): + * d = 0.0 # <<<<<<<<<<<<<< + * rk = r - k + * pk = p - k + */ + __pyx_v_d = 0.0; + + /* "ezdxf/acc/bspline.pyx":261 + * for k in range(1, n + 1): + * d = 0.0 + * rk = r - k # <<<<<<<<<<<<<< + * pk = p - k + * if r >= k: + */ + __pyx_v_rk = (__pyx_v_r - __pyx_v_k); + + /* "ezdxf/acc/bspline.pyx":262 + * d = 0.0 + * rk = r - k + * pk = p - k # <<<<<<<<<<<<<< + * if r >= k: + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + */ + __pyx_v_pk = (__pyx_v_p - __pyx_v_k); + + /* "ezdxf/acc/bspline.pyx":263 + * rk = r - k + * pk = p - k + * if r >= k: # <<<<<<<<<<<<<< + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + * d = a[s2][0] * ndu[rk][pk] + */ + __pyx_t_10 = (__pyx_v_r >= __pyx_v_k); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":264 + * pk = p - k + * if r >= k: + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] # <<<<<<<<<<<<<< + * d = a[s2][0] * ndu[rk][pk] + * if rk >= -1: + */ + __pyx_t_17 = ((__pyx_v_ndu[(__pyx_v_pk + 1)])[__pyx_v_rk]); + if (unlikely(__pyx_t_17 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 264, __pyx_L1_error) + } + ((__pyx_v_a[__pyx_v_s2])[0]) = (((__pyx_v_a[__pyx_v_s1])[0]) / __pyx_t_17); + + /* "ezdxf/acc/bspline.pyx":265 + * if r >= k: + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + * d = a[s2][0] * ndu[rk][pk] # <<<<<<<<<<<<<< + * if rk >= -1: + * j1 = 1 + */ + __pyx_v_d = (((__pyx_v_a[__pyx_v_s2])[0]) * ((__pyx_v_ndu[__pyx_v_rk])[__pyx_v_pk])); + + /* "ezdxf/acc/bspline.pyx":263 + * rk = r - k + * pk = p - k + * if r >= k: # <<<<<<<<<<<<<< + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + * d = a[s2][0] * ndu[rk][pk] + */ + } + + /* "ezdxf/acc/bspline.pyx":266 + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + * d = a[s2][0] * ndu[rk][pk] + * if rk >= -1: # <<<<<<<<<<<<<< + * j1 = 1 + * else: + */ + __pyx_t_10 = (__pyx_v_rk >= -1L); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":267 + * d = a[s2][0] * ndu[rk][pk] + * if rk >= -1: + * j1 = 1 # <<<<<<<<<<<<<< + * else: + * j1 = -rk + */ + __pyx_v_j1 = 1; + + /* "ezdxf/acc/bspline.pyx":266 + * a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + * d = a[s2][0] * ndu[rk][pk] + * if rk >= -1: # <<<<<<<<<<<<<< + * j1 = 1 + * else: + */ + goto __pyx_L16; + } + + /* "ezdxf/acc/bspline.pyx":269 + * j1 = 1 + * else: + * j1 = -rk # <<<<<<<<<<<<<< + * if (r - 1) <= pk: + * j2 = k - 1 + */ + /*else*/ { + __pyx_v_j1 = (-__pyx_v_rk); + } + __pyx_L16:; + + /* "ezdxf/acc/bspline.pyx":270 + * else: + * j1 = -rk + * if (r - 1) <= pk: # <<<<<<<<<<<<<< + * j2 = k - 1 + * else: + */ + __pyx_t_10 = ((__pyx_v_r - 1) <= __pyx_v_pk); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":271 + * j1 = -rk + * if (r - 1) <= pk: + * j2 = k - 1 # <<<<<<<<<<<<<< + * else: + * j2 = p - r + */ + __pyx_v_j2 = (__pyx_v_k - 1); + + /* "ezdxf/acc/bspline.pyx":270 + * else: + * j1 = -rk + * if (r - 1) <= pk: # <<<<<<<<<<<<<< + * j2 = k - 1 + * else: + */ + goto __pyx_L17; + } + + /* "ezdxf/acc/bspline.pyx":273 + * j2 = k - 1 + * else: + * j2 = p - r # <<<<<<<<<<<<<< + * for j in range(j1, j2 + 1): + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + */ + /*else*/ { + __pyx_v_j2 = (__pyx_v_p - __pyx_v_r); + } + __pyx_L17:; + + /* "ezdxf/acc/bspline.pyx":274 + * else: + * j2 = p - r + * for j in range(j1, j2 + 1): # <<<<<<<<<<<<<< + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + * d += (a[s2][j] * ndu[rk + j][pk]) + */ + __pyx_t_20 = (__pyx_v_j2 + 1); + __pyx_t_21 = __pyx_t_20; + for (__pyx_t_15 = __pyx_v_j1; __pyx_t_15 < __pyx_t_21; __pyx_t_15+=1) { + __pyx_v_j = __pyx_t_15; + + /* "ezdxf/acc/bspline.pyx":275 + * j2 = p - r + * for j in range(j1, j2 + 1): + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] # <<<<<<<<<<<<<< + * d += (a[s2][j] * ndu[rk + j][pk]) + * if r <= pk: + */ + __pyx_t_17 = (((__pyx_v_a[__pyx_v_s1])[__pyx_v_j]) - ((__pyx_v_a[__pyx_v_s1])[(__pyx_v_j - 1)])); + __pyx_t_22 = ((__pyx_v_ndu[(__pyx_v_pk + 1)])[(__pyx_v_rk + __pyx_v_j)]); + if (unlikely(__pyx_t_22 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 275, __pyx_L1_error) + } + ((__pyx_v_a[__pyx_v_s2])[__pyx_v_j]) = (__pyx_t_17 / __pyx_t_22); + + /* "ezdxf/acc/bspline.pyx":276 + * for j in range(j1, j2 + 1): + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + * d += (a[s2][j] * ndu[rk + j][pk]) # <<<<<<<<<<<<<< + * if r <= pk: + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + */ + __pyx_v_d = (__pyx_v_d + (((__pyx_v_a[__pyx_v_s2])[__pyx_v_j]) * ((__pyx_v_ndu[(__pyx_v_rk + __pyx_v_j)])[__pyx_v_pk]))); + } + + /* "ezdxf/acc/bspline.pyx":277 + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + * d += (a[s2][j] * ndu[rk + j][pk]) + * if r <= pk: # <<<<<<<<<<<<<< + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + * d += (a[s2][k] * ndu[r][pk]) + */ + __pyx_t_10 = (__pyx_v_r <= __pyx_v_pk); + if (__pyx_t_10) { + + /* "ezdxf/acc/bspline.pyx":278 + * d += (a[s2][j] * ndu[rk + j][pk]) + * if r <= pk: + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] # <<<<<<<<<<<<<< + * d += (a[s2][k] * ndu[r][pk]) + * derivatives[k][r] = d + */ + __pyx_t_22 = (-((__pyx_v_a[__pyx_v_s1])[(__pyx_v_k - 1)])); + __pyx_t_17 = ((__pyx_v_ndu[(__pyx_v_pk + 1)])[__pyx_v_r]); + if (unlikely(__pyx_t_17 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 278, __pyx_L1_error) + } + ((__pyx_v_a[__pyx_v_s2])[__pyx_v_k]) = (__pyx_t_22 / __pyx_t_17); + + /* "ezdxf/acc/bspline.pyx":279 + * if r <= pk: + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + * d += (a[s2][k] * ndu[r][pk]) # <<<<<<<<<<<<<< + * derivatives[k][r] = d + * + */ + __pyx_v_d = (__pyx_v_d + (((__pyx_v_a[__pyx_v_s2])[__pyx_v_k]) * ((__pyx_v_ndu[__pyx_v_r])[__pyx_v_pk]))); + + /* "ezdxf/acc/bspline.pyx":277 + * a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + * d += (a[s2][j] * ndu[rk + j][pk]) + * if r <= pk: # <<<<<<<<<<<<<< + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + * d += (a[s2][k] * ndu[r][pk]) + */ + } + + /* "ezdxf/acc/bspline.pyx":280 + * a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + * d += (a[s2][k] * ndu[r][pk]) + * derivatives[k][r] = d # <<<<<<<<<<<<<< + * + * # Switch rows + */ + ((__pyx_v_derivatives[__pyx_v_k])[__pyx_v_r]) = __pyx_v_d; + + /* "ezdxf/acc/bspline.pyx":283 + * + * # Switch rows + * t = s1 # <<<<<<<<<<<<<< + * s1 = s2 + * s2 = t + */ + __pyx_v_t = __pyx_v_s1; + + /* "ezdxf/acc/bspline.pyx":284 + * # Switch rows + * t = s1 + * s1 = s2 # <<<<<<<<<<<<<< + * s2 = t + * + */ + __pyx_v_s1 = __pyx_v_s2; + + /* "ezdxf/acc/bspline.pyx":285 + * t = s1 + * s1 = s2 + * s2 = t # <<<<<<<<<<<<<< + * + * # Multiply through by the correct factors + */ + __pyx_v_s2 = __pyx_v_t; + } + } + + /* "ezdxf/acc/bspline.pyx":288 + * + * # Multiply through by the correct factors + * cdef double rr = p # <<<<<<<<<<<<<< + * for k in range(1, n + 1): + * for j in range(order): + */ + __pyx_v_rr = __pyx_v_p; + + /* "ezdxf/acc/bspline.pyx":289 + * # Multiply through by the correct factors + * cdef double rr = p + * for k in range(1, n + 1): # <<<<<<<<<<<<<< + * for j in range(order): + * derivatives[k][j] *= rr + */ + __pyx_t_18 = (__pyx_v_n + 1); + __pyx_t_19 = __pyx_t_18; + for (__pyx_t_9 = 1; __pyx_t_9 < __pyx_t_19; __pyx_t_9+=1) { + __pyx_v_k = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":290 + * cdef double rr = p + * for k in range(1, n + 1): + * for j in range(order): # <<<<<<<<<<<<<< + * derivatives[k][j] *= rr + * rr *= (p - k) + */ + __pyx_t_12 = __pyx_v_order; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_v_j = __pyx_t_14; + + /* "ezdxf/acc/bspline.pyx":291 + * for k in range(1, n + 1): + * for j in range(order): + * derivatives[k][j] *= rr # <<<<<<<<<<<<<< + * rr *= (p - k) + * + */ + __pyx_t_15 = __pyx_v_k; + __pyx_t_16 = __pyx_v_j; + ((__pyx_v_derivatives[__pyx_t_15])[__pyx_t_16]) = (((__pyx_v_derivatives[__pyx_t_15])[__pyx_t_16]) * __pyx_v_rr); + } + + /* "ezdxf/acc/bspline.pyx":292 + * for j in range(order): + * derivatives[k][j] *= rr + * rr *= (p - k) # <<<<<<<<<<<<<< + * + * # return result as Python lists + */ + __pyx_v_rr = (__pyx_v_rr * (__pyx_v_p - __pyx_v_k)); + } + + /* "ezdxf/acc/bspline.pyx":295 + * + * # return result as Python lists + * cdef list result = [], row # <<<<<<<<<<<<<< + * for k in range(0, n + 1): + * row = [] + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_result = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":296 + * # return result as Python lists + * cdef list result = [], row + * for k in range(0, n + 1): # <<<<<<<<<<<<<< + * row = [] + * result.append(row) + */ + __pyx_t_18 = (__pyx_v_n + 1); + __pyx_t_19 = __pyx_t_18; + for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_19; __pyx_t_9+=1) { + __pyx_v_k = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":297 + * cdef list result = [], row + * for k in range(0, n + 1): + * row = [] # <<<<<<<<<<<<<< + * result.append(row) + * for j in range(order): + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 297, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_row, ((PyObject*)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":298 + * for k in range(0, n + 1): + * row = [] + * result.append(row) # <<<<<<<<<<<<<< + * for j in range(order): + * row.append(derivatives[k][j]) + */ + __pyx_t_23 = __Pyx_PyList_Append(__pyx_v_result, __pyx_v_row); if (unlikely(__pyx_t_23 == ((int)-1))) __PYX_ERR(0, 298, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":299 + * row = [] + * result.append(row) + * for j in range(order): # <<<<<<<<<<<<<< + * row.append(derivatives[k][j]) + * return result + */ + __pyx_t_12 = __pyx_v_order; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_v_j = __pyx_t_14; + + /* "ezdxf/acc/bspline.pyx":300 + * result.append(row) + * for j in range(order): + * row.append(derivatives[k][j]) # <<<<<<<<<<<<<< + * return result + * + */ + __pyx_t_1 = PyFloat_FromDouble(((__pyx_v_derivatives[__pyx_v_k])[__pyx_v_j])); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 300, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_23 = __Pyx_PyList_Append(__pyx_v_row, __pyx_t_1); if (unlikely(__pyx_t_23 == ((int)-1))) __PYX_ERR(0, 300, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + } + + /* "ezdxf/acc/bspline.pyx":301 + * for j in range(order): + * row.append(derivatives[k][j]) + * return result # <<<<<<<<<<<<<< + * + * cdef class Evaluator: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":200 + * return NULL_LIST * len(nbasis) + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): # <<<<<<<<<<<<<< + * # pyright: reportUndefinedVariable=false + * # pyright flags Cython multi-arrays incorrect: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs_derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_v_row); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives = {"basis_funcs_derivatives", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_span; + double __pyx_v_u; + int __pyx_v_n; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("basis_funcs_derivatives (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_span,&__pyx_n_s_u,&__pyx_n_s_n,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_span)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_u)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("basis_funcs_derivatives", 0, 2, 3, 1); __PYX_ERR(0, 200, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_n); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "basis_funcs_derivatives") < 0)) __PYX_ERR(0, 200, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_span = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_span == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + __pyx_v_u = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_u == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + if (values[2]) { + __pyx_v_n = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 200, __pyx_L3_error) + } else { + __pyx_v_n = ((int)1); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("basis_funcs_derivatives", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 200, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs_derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_12basis_funcs_derivatives(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v_span, __pyx_v_u, __pyx_v_n); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_12basis_funcs_derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, int __pyx_v_span, double __pyx_v_u, int __pyx_v_n) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("basis_funcs_derivatives", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_2.__pyx_n = 1; + __pyx_t_2.n = __pyx_v_n; + __pyx_t_1 = __pyx_vtabptr_5ezdxf_3acc_7bspline_Basis->basis_funcs_derivatives(__pyx_v_self, __pyx_v_span, __pyx_v_u, 1, &__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.basis_funcs_derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":57 + * """ Immutable Basis function class. """ + * # public: + * cdef readonly int order # <<<<<<<<<<<<<< + * cdef readonly int count + * cdef readonly double max_t + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5order_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5order_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_5order___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5order___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->order); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.order.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":58 + * # public: + * cdef readonly int order + * cdef readonly int count # <<<<<<<<<<<<<< + * cdef readonly double max_t + * cdef tuple weights_ # public attribute for Cython Evaluator + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5count_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5count_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_5count___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5count___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->count); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.count.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":59 + * cdef readonly int order + * cdef readonly int count + * cdef readonly double max_t # <<<<<<<<<<<<<< + * cdef tuple weights_ # public attribute for Cython Evaluator + * # private: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5max_t_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_5max_t_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_5max_t___get__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_5max_t___get__(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->max_t); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.max_t.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_14__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_14__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_5Basis_16__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_5Basis_16__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Basis.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":308 + * cdef tuple _control_points + * + * def __cinit__(self, basis: Basis, control_points: Sequence[Vec3]): # <<<<<<<<<<<<<< + * self._basis = basis + * self._control_points = Vec3.tuple(control_points) + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_basis = 0; + PyObject *__pyx_v_control_points = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_basis,&__pyx_n_s_control_points,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_basis)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 308, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_control_points)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 308, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, 1); __PYX_ERR(0, 308, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(0, 308, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + } + __pyx_v_basis = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)values[0]); + __pyx_v_control_points = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 308, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_basis), __pyx_ptype_5ezdxf_3acc_7bspline_Basis, 0, "basis", 0))) __PYX_ERR(0, 308, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator___cinit__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v_basis, __pyx_v_control_points); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator___cinit__(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_basis, PyObject *__pyx_v_control_points) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/bspline.pyx":309 + * + * def __cinit__(self, basis: Basis, control_points: Sequence[Vec3]): + * self._basis = basis # <<<<<<<<<<<<<< + * self._control_points = Vec3.tuple(control_points) + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_basis); + __Pyx_GIVEREF((PyObject *)__pyx_v_basis); + __Pyx_GOTREF((PyObject *)__pyx_v_self->_basis); + __Pyx_DECREF((PyObject *)__pyx_v_self->_basis); + __pyx_v_self->_basis = __pyx_v_basis; + + /* "ezdxf/acc/bspline.pyx":310 + * def __cinit__(self, basis: Basis, control_points: Sequence[Vec3]): + * self._basis = basis + * self._control_points = Vec3.tuple(control_points) # <<<<<<<<<<<<<< + * + * cpdef Vec3 point(self, double u): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_n_s_tuple); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_control_points}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(PyTuple_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None) || __Pyx_RaiseUnexpectedTypeError("tuple", __pyx_t_1))) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v_self->_control_points); + __Pyx_DECREF(__pyx_v_self->_control_points); + __pyx_v_self->_control_points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":308 + * cdef tuple _control_points + * + * def __cinit__(self, basis: Basis, control_points: Sequence[Vec3]): # <<<<<<<<<<<<<< + * self._basis = basis + * self._control_points = Vec3.tuple(control_points) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":312 + * self._control_points = Vec3.tuple(control_points) + * + * cpdef Vec3 point(self, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_3point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_point(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_basis = 0; + int __pyx_v_p; + int __pyx_v_span; + PyObject *__pyx_v_N = 0; + int __pyx_v_i; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_cpoint = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v3_sum = 0; + PyObject *__pyx_v_control_points = 0; + double __pyx_v_factor; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_t_7; + double __pyx_t_8; + int __pyx_t_9; + long __pyx_t_10; + long __pyx_t_11; + int __pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_point); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_3point)) { + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_u); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 312, __pyx_L1_error) + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":314 + * cpdef Vec3 point(self, double u): + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis # <<<<<<<<<<<<<< + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + * u = basis.max_t + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->_basis); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_basis = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":315 + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * u = basis.max_t + * cdef: + */ + __pyx_t_7 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_u, __pyx_v_basis->max_t, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 315, __pyx_L1_error) + if (__pyx_t_7) { + + /* "ezdxf/acc/bspline.pyx":316 + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + * u = basis.max_t # <<<<<<<<<<<<<< + * cdef: + * int p = basis.order - 1 + */ + __pyx_t_8 = __pyx_v_basis->max_t; + __pyx_v_u = __pyx_t_8; + + /* "ezdxf/acc/bspline.pyx":315 + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * u = basis.max_t + * cdef: + */ + } + + /* "ezdxf/acc/bspline.pyx":318 + * u = basis.max_t + * cdef: + * int p = basis.order - 1 # <<<<<<<<<<<<<< + * int span = basis.find_span(u) + * list N = basis.basis_funcs(span, u) + */ + __pyx_v_p = (__pyx_v_basis->order - 1); + + /* "ezdxf/acc/bspline.pyx":319 + * cdef: + * int p = basis.order - 1 + * int span = basis.find_span(u) # <<<<<<<<<<<<<< + * list N = basis.basis_funcs(span, u) + * int i + */ + __pyx_t_9 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_basis->__pyx_vtab)->find_span(__pyx_v_basis, __pyx_v_u, 0); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 319, __pyx_L1_error) + __pyx_v_span = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":320 + * int p = basis.order - 1 + * int span = basis.find_span(u) + * list N = basis.basis_funcs(span, u) # <<<<<<<<<<<<<< + * int i + * Vec3 cpoint, v3_sum = Vec3() + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_basis->__pyx_vtab)->basis_funcs(__pyx_v_basis, __pyx_v_span, __pyx_v_u, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 320, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_N = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":322 + * list N = basis.basis_funcs(span, u) + * int i + * Vec3 cpoint, v3_sum = Vec3() # <<<<<<<<<<<<<< + * tuple control_points = self._control_points + * double factor + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 322, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v3_sum = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":323 + * int i + * Vec3 cpoint, v3_sum = Vec3() + * tuple control_points = self._control_points # <<<<<<<<<<<<<< + * double factor + * + */ + __pyx_t_1 = __pyx_v_self->_control_points; + __Pyx_INCREF(__pyx_t_1); + __pyx_v_control_points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":326 + * double factor + * + * for i in range(p + 1): # <<<<<<<<<<<<<< + * factor = N[i] + * cpoint = control_points[span - p + i] + */ + __pyx_t_10 = (__pyx_v_p + 1); + __pyx_t_11 = __pyx_t_10; + for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_11; __pyx_t_9+=1) { + __pyx_v_i = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":327 + * + * for i in range(p + 1): + * factor = N[i] # <<<<<<<<<<<<<< + * cpoint = control_points[span - p + i] + * v3_sum.x += cpoint.x * factor + */ + if (unlikely(__pyx_v_N == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 327, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_N, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 327, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_8 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_8 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 327, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_factor = ((double)__pyx_t_8); + + /* "ezdxf/acc/bspline.pyx":328 + * for i in range(p + 1): + * factor = N[i] + * cpoint = control_points[span - p + i] # <<<<<<<<<<<<<< + * v3_sum.x += cpoint.x * factor + * v3_sum.y += cpoint.y * factor + */ + if (unlikely(__pyx_v_control_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 328, __pyx_L1_error) + } + __pyx_t_12 = ((__pyx_v_span - __pyx_v_p) + __pyx_v_i); + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_control_points, __pyx_t_12, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF_SET(__pyx_v_cpoint, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __pyx_t_2 = 0; + + /* "ezdxf/acc/bspline.pyx":329 + * factor = N[i] + * cpoint = control_points[span - p + i] + * v3_sum.x += cpoint.x * factor # <<<<<<<<<<<<<< + * v3_sum.y += cpoint.y * factor + * v3_sum.z += cpoint.z * factor + */ + __pyx_v_v3_sum->x = (__pyx_v_v3_sum->x + (__pyx_v_cpoint->x * __pyx_v_factor)); + + /* "ezdxf/acc/bspline.pyx":330 + * cpoint = control_points[span - p + i] + * v3_sum.x += cpoint.x * factor + * v3_sum.y += cpoint.y * factor # <<<<<<<<<<<<<< + * v3_sum.z += cpoint.z * factor + * return v3_sum + */ + __pyx_v_v3_sum->y = (__pyx_v_v3_sum->y + (__pyx_v_cpoint->y * __pyx_v_factor)); + + /* "ezdxf/acc/bspline.pyx":331 + * v3_sum.x += cpoint.x * factor + * v3_sum.y += cpoint.y * factor + * v3_sum.z += cpoint.z * factor # <<<<<<<<<<<<<< + * return v3_sum + * + */ + __pyx_v_v3_sum->z = (__pyx_v_v3_sum->z + (__pyx_v_cpoint->z * __pyx_v_factor)); + } + + /* "ezdxf/acc/bspline.pyx":332 + * v3_sum.y += cpoint.y * factor + * v3_sum.z += cpoint.z * factor + * return v3_sum # <<<<<<<<<<<<<< + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_v3_sum); + __pyx_r = __pyx_v_v3_sum; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":312 + * self._control_points = Vec3.tuple(control_points) + * + * cpdef Vec3 point(self, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_basis); + __Pyx_XDECREF(__pyx_v_N); + __Pyx_XDECREF((PyObject *)__pyx_v_cpoint); + __Pyx_XDECREF((PyObject *)__pyx_v_v3_sum); + __Pyx_XDECREF(__pyx_v_control_points); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_3point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_3point = {"point", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_3point, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_3point(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_u; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("point (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_u,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_u)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 312, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "point") < 0)) __PYX_ERR(0, 312, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_u = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_u == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 312, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("point", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 312, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_2point(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v_u); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_2point(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("point", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_point(__pyx_v_self, __pyx_v_u, 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.point", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_6generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bspline.pyx":334 + * return v3_sum + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_5points(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_5points = {"points", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_5points, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_5points(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_t = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("points (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 334, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "points") < 0)) __PYX_ERR(0, 334, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_t = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("points", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 334, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_4points(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v_t); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_4points(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, PyObject *__pyx_v_t) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("points", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 334, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_t = __pyx_v_t; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_t); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_t); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_6generator, __pyx_codeobj__5, (PyObject *) __pyx_cur_scope, __pyx_n_s_points, __pyx_n_s_Evaluator_points, __pyx_n_s_ezdxf_acc_bspline); if (unlikely(!gen)) __PYX_ERR(0, 334, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_6generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + double __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("points", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 334, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":336 + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: + * cdef double u + * for u in t: # <<<<<<<<<<<<<< + * yield self.point(u) + * + */ + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_t)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_t)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_v_t; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_t); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 336, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 336, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 336, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 336, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 336, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 336, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 336, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 336, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 336, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __pyx_t_5 = __pyx_PyFloat_AsDouble(__pyx_t_4); if (unlikely((__pyx_t_5 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 336, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_cur_scope->__pyx_v_u = __pyx_t_5; + + /* "ezdxf/acc/bspline.pyx":337 + * cdef double u + * for u in t: + * yield self.point(u) # <<<<<<<<<<<<<< + * + * cpdef list derivative(self, double u, int n = 1): + */ + __pyx_t_4 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator *)__pyx_cur_scope->__pyx_v_self->__pyx_vtab)->point(__pyx_cur_scope->__pyx_v_self, __pyx_cur_scope->__pyx_v_u, 0)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 337, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 337, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":336 + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: + * cdef double u + * for u in t: # <<<<<<<<<<<<<< + * yield self.point(u) + * + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/bspline.pyx":334 + * return v3_sum + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/bspline.pyx":339 + * yield self.point(u) + * + * cpdef list derivative(self, double u, int n = 1): # <<<<<<<<<<<<<< + * """ Return point and derivatives up to n <= degree for parameter u. """ + * # Source: The NURBS Book: Algorithm A3.2 + */ + +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_8derivative(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_derivative(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative *__pyx_optional_args) { + int __pyx_v_n = ((int)1); + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *__pyx_v_basis = 0; + PyObject *__pyx_v_CK = 0; + PyObject *__pyx_v_CKw = 0; + PyObject *__pyx_v_wders = 0; + PyObject *__pyx_v_control_points = 0; + PyObject *__pyx_v_weights = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_cpoint = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v3_sum = 0; + double __pyx_v_wder; + double __pyx_v_bas_func_weight; + double __pyx_v_bas_func; + int __pyx_v_k; + int __pyx_v_j; + int __pyx_v_i; + int __pyx_v_p; + int __pyx_v_span; + PyObject *__pyx_v_basis_funcs_ders = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + unsigned int __pyx_t_7; + int __pyx_t_8; + double __pyx_t_9; + int __pyx_t_10; + struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives __pyx_t_11; + long __pyx_t_12; + long __pyx_t_13; + long __pyx_t_14; + long __pyx_t_15; + int __pyx_t_16; + int __pyx_t_17; + int __pyx_t_18; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("derivative", 1); + if (__pyx_optional_args) { + if (__pyx_optional_args->__pyx_n > 0) { + __pyx_v_n = __pyx_optional_args->n; + } + } + /* Check if called by wrapper */ + if (unlikely(__pyx_skip_dispatch)) ; + /* Check if overridden in Python */ + else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) { + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) { + PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + #endif + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_derivative); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_8derivative)) { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_u); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_5 = __pyx_t_1; __pyx_t_6 = NULL; + __pyx_t_7 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_7 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_6, __pyx_t_3, __pyx_t_4}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_7, 2+__pyx_t_7); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + if (!(likely(PyList_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_2))) __PYX_ERR(0, 339, __pyx_L1_error) + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + } + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self)); + __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self)); + if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) { + __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT; + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS + } + #endif + } + + /* "ezdxf/acc/bspline.pyx":343 + * # Source: The NURBS Book: Algorithm A3.2 + * + * cdef Basis basis = self._basis # <<<<<<<<<<<<<< + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + * u = basis.max_t + */ + __pyx_t_1 = ((PyObject *)__pyx_v_self->_basis); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_basis = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":344 + * + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * u = basis.max_t + * cdef: + */ + __pyx_t_8 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_u, __pyx_v_basis->max_t, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 344, __pyx_L1_error) + if (__pyx_t_8) { + + /* "ezdxf/acc/bspline.pyx":345 + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + * u = basis.max_t # <<<<<<<<<<<<<< + * cdef: + * list CK = [], CKw = [], wders = [] + */ + __pyx_t_9 = __pyx_v_basis->max_t; + __pyx_v_u = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":344 + * + * cdef Basis basis = self._basis + * if isclose(u, basis.max_t, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * u = basis.max_t + * cdef: + */ + } + + /* "ezdxf/acc/bspline.pyx":347 + * u = basis.max_t + * cdef: + * list CK = [], CKw = [], wders = [] # <<<<<<<<<<<<<< + * tuple control_points = self._control_points + * tuple weights + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_CK = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_CKw = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_wders = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":348 + * cdef: + * list CK = [], CKw = [], wders = [] + * tuple control_points = self._control_points # <<<<<<<<<<<<<< + * tuple weights + * Vec3 cpoint, v3_sum + */ + __pyx_t_1 = __pyx_v_self->_control_points; + __Pyx_INCREF(__pyx_t_1); + __pyx_v_control_points = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":352 + * Vec3 cpoint, v3_sum + * double wder, bas_func_weight, bas_func + * int k, j, i, p = basis.degree # <<<<<<<<<<<<<< + * int span = basis.find_span(u) + * list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_basis), __pyx_n_s_degree); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 352, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_10 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_10 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 352, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_p = __pyx_t_10; + + /* "ezdxf/acc/bspline.pyx":353 + * double wder, bas_func_weight, bas_func + * int k, j, i, p = basis.degree + * int span = basis.find_span(u) # <<<<<<<<<<<<<< + * list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + * + */ + __pyx_t_10 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_basis->__pyx_vtab)->find_span(__pyx_v_basis, __pyx_v_u, 0); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 353, __pyx_L1_error) + __pyx_v_span = __pyx_t_10; + + /* "ezdxf/acc/bspline.pyx":354 + * int k, j, i, p = basis.degree + * int span = basis.find_span(u) + * list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) # <<<<<<<<<<<<<< + * + * if basis.is_rational: + */ + __pyx_t_11.__pyx_n = 1; + __pyx_t_11.n = __pyx_v_n; + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis *)__pyx_v_basis->__pyx_vtab)->basis_funcs_derivatives(__pyx_v_basis, __pyx_v_span, __pyx_v_u, 0, &__pyx_t_11); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 354, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_basis_funcs_ders = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":356 + * list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + * + * if basis.is_rational: # <<<<<<<<<<<<<< + * # Homogeneous point representation required: + * # (x*w, y*w, z*w, w) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_basis), __pyx_n_s_is_rational); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 356, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_8 < 0))) __PYX_ERR(0, 356, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_8) { + + /* "ezdxf/acc/bspline.pyx":359 + * # Homogeneous point representation required: + * # (x*w, y*w, z*w, w) + * weights = basis.weights_ # <<<<<<<<<<<<<< + * for k in range(n + 1): + * v3_sum = Vec3() + */ + __pyx_t_1 = __pyx_v_basis->weights_; + __Pyx_INCREF(__pyx_t_1); + __pyx_v_weights = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":360 + * # (x*w, y*w, z*w, w) + * weights = basis.weights_ + * for k in range(n + 1): # <<<<<<<<<<<<<< + * v3_sum = Vec3() + * wder = 0.0 + */ + __pyx_t_12 = (__pyx_v_n + 1); + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_13; __pyx_t_10+=1) { + __pyx_v_k = __pyx_t_10; + + /* "ezdxf/acc/bspline.pyx":361 + * weights = basis.weights_ + * for k in range(n + 1): + * v3_sum = Vec3() # <<<<<<<<<<<<<< + * wder = 0.0 + * for j in range(p + 1): + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 361, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_v3_sum, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":362 + * for k in range(n + 1): + * v3_sum = Vec3() + * wder = 0.0 # <<<<<<<<<<<<<< + * for j in range(p + 1): + * i = span - p + j + */ + __pyx_v_wder = 0.0; + + /* "ezdxf/acc/bspline.pyx":363 + * v3_sum = Vec3() + * wder = 0.0 + * for j in range(p + 1): # <<<<<<<<<<<<<< + * i = span - p + j + * bas_func_weight = basis_funcs_ders[k][j] * weights[i] + */ + __pyx_t_14 = (__pyx_v_p + 1); + __pyx_t_15 = __pyx_t_14; + for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) { + __pyx_v_j = __pyx_t_16; + + /* "ezdxf/acc/bspline.pyx":364 + * wder = 0.0 + * for j in range(p + 1): + * i = span - p + j # <<<<<<<<<<<<<< + * bas_func_weight = basis_funcs_ders[k][j] * weights[i] + * # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + */ + __pyx_v_i = ((__pyx_v_span - __pyx_v_p) + __pyx_v_j); + + /* "ezdxf/acc/bspline.pyx":365 + * for j in range(p + 1): + * i = span - p + j + * bas_func_weight = basis_funcs_ders[k][j] * weights[i] # <<<<<<<<<<<<<< + * # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + * cpoint = control_points[i] + */ + if (unlikely(__pyx_v_basis_funcs_ders == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 365, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_basis_funcs_ders, __pyx_v_k, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 365, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, __pyx_v_j, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 365, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_v_weights == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 365, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_weights, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 365, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = PyNumber_Multiply(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 365, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 365, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_bas_func_weight = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":367 + * bas_func_weight = basis_funcs_ders[k][j] * weights[i] + * # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + * cpoint = control_points[i] # <<<<<<<<<<<<<< + * v3_sum.x += cpoint.x * bas_func_weight + * v3_sum.y += cpoint.y * bas_func_weight + */ + if (unlikely(__pyx_v_control_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 367, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_GetItemInt_Tuple(__pyx_v_control_points, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 367, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __pyx_t_5; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF_SET(__pyx_v_cpoint, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":368 + * # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + * cpoint = control_points[i] + * v3_sum.x += cpoint.x * bas_func_weight # <<<<<<<<<<<<<< + * v3_sum.y += cpoint.y * bas_func_weight + * v3_sum.z += cpoint.z * bas_func_weight + */ + __pyx_v_v3_sum->x = (__pyx_v_v3_sum->x + (__pyx_v_cpoint->x * __pyx_v_bas_func_weight)); + + /* "ezdxf/acc/bspline.pyx":369 + * cpoint = control_points[i] + * v3_sum.x += cpoint.x * bas_func_weight + * v3_sum.y += cpoint.y * bas_func_weight # <<<<<<<<<<<<<< + * v3_sum.z += cpoint.z * bas_func_weight + * wder += bas_func_weight + */ + __pyx_v_v3_sum->y = (__pyx_v_v3_sum->y + (__pyx_v_cpoint->y * __pyx_v_bas_func_weight)); + + /* "ezdxf/acc/bspline.pyx":370 + * v3_sum.x += cpoint.x * bas_func_weight + * v3_sum.y += cpoint.y * bas_func_weight + * v3_sum.z += cpoint.z * bas_func_weight # <<<<<<<<<<<<<< + * wder += bas_func_weight + * CKw.append(v3_sum) + */ + __pyx_v_v3_sum->z = (__pyx_v_v3_sum->z + (__pyx_v_cpoint->z * __pyx_v_bas_func_weight)); + + /* "ezdxf/acc/bspline.pyx":371 + * v3_sum.y += cpoint.y * bas_func_weight + * v3_sum.z += cpoint.z * bas_func_weight + * wder += bas_func_weight # <<<<<<<<<<<<<< + * CKw.append(v3_sum) + * wders.append(wder) + */ + __pyx_v_wder = (__pyx_v_wder + __pyx_v_bas_func_weight); + } + + /* "ezdxf/acc/bspline.pyx":372 + * v3_sum.z += cpoint.z * bas_func_weight + * wder += bas_func_weight + * CKw.append(v3_sum) # <<<<<<<<<<<<<< + * wders.append(wder) + * + */ + __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_CKw, ((PyObject *)__pyx_v_v3_sum)); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 372, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":373 + * wder += bas_func_weight + * CKw.append(v3_sum) + * wders.append(wder) # <<<<<<<<<<<<<< + * + * # Source: The NURBS Book: Algorithm A4.2 + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_wder); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 373, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_wders, __pyx_t_1); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 373, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + + /* "ezdxf/acc/bspline.pyx":376 + * + * # Source: The NURBS Book: Algorithm A4.2 + * for k in range(n + 1): # <<<<<<<<<<<<<< + * v3_sum = CKw[k] + * for j in range(1, k + 1): + */ + __pyx_t_12 = (__pyx_v_n + 1); + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_13; __pyx_t_10+=1) { + __pyx_v_k = __pyx_t_10; + + /* "ezdxf/acc/bspline.pyx":377 + * # Source: The NURBS Book: Algorithm A4.2 + * for k in range(n + 1): + * v3_sum = CKw[k] # <<<<<<<<<<<<<< + * for j in range(1, k + 1): + * bas_func_weight = binomial_coefficient(k, j) * wders[j] + */ + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_CKw, __pyx_v_k, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 377, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 377, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_v3_sum, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/bspline.pyx":378 + * for k in range(n + 1): + * v3_sum = CKw[k] + * for j in range(1, k + 1): # <<<<<<<<<<<<<< + * bas_func_weight = binomial_coefficient(k, j) * wders[j] + * v3_sum = v3_sub( + */ + __pyx_t_14 = (__pyx_v_k + 1); + __pyx_t_15 = __pyx_t_14; + for (__pyx_t_16 = 1; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) { + __pyx_v_j = __pyx_t_16; + + /* "ezdxf/acc/bspline.pyx":379 + * v3_sum = CKw[k] + * for j in range(1, k + 1): + * bas_func_weight = binomial_coefficient(k, j) * wders[j] # <<<<<<<<<<<<<< + * v3_sum = v3_sub( + * v3_sum, + */ + __pyx_t_9 = __pyx_f_5ezdxf_3acc_7bspline_binomial_coefficient(__pyx_v_k, __pyx_v_j); if (unlikely(__pyx_t_9 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 379, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_GetItemInt_List(__pyx_v_wders, __pyx_v_j, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_bas_func_weight = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":382 + * v3_sum = v3_sub( + * v3_sum, + * v3_mul(CK[k - j], bas_func_weight) # <<<<<<<<<<<<<< + * ) + * CK.append(v3_sum / wders[0]) + */ + __pyx_t_18 = (__pyx_v_k - __pyx_v_j); + __pyx_t_2 = __Pyx_GetItemInt_List(__pyx_v_CK, __pyx_t_18, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 382, __pyx_L1_error) + __pyx_t_5 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2), __pyx_v_bas_func_weight)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bspline.pyx":380 + * for j in range(1, k + 1): + * bas_func_weight = binomial_coefficient(k, j) * wders[j] + * v3_sum = v3_sub( # <<<<<<<<<<<<<< + * v3_sum, + * v3_mul(CK[k - j], bas_func_weight) + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_v_v3_sum, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 380, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF_SET(__pyx_v_v3_sum, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __pyx_t_2 = 0; + } + + /* "ezdxf/acc/bspline.pyx":384 + * v3_mul(CK[k - j], bas_func_weight) + * ) + * CK.append(v3_sum / wders[0]) # <<<<<<<<<<<<<< + * else: + * for k in range(n + 1): + */ + __pyx_t_2 = __Pyx_GetItemInt_List(__pyx_v_wders, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 384, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyNumber_Divide(((PyObject *)__pyx_v_v3_sum), __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 384, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_CK, __pyx_t_5); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 384, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + + /* "ezdxf/acc/bspline.pyx":356 + * list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + * + * if basis.is_rational: # <<<<<<<<<<<<<< + * # Homogeneous point representation required: + * # (x*w, y*w, z*w, w) + */ + goto __pyx_L4; + } + + /* "ezdxf/acc/bspline.pyx":386 + * CK.append(v3_sum / wders[0]) + * else: + * for k in range(n + 1): # <<<<<<<<<<<<<< + * v3_sum = Vec3() + * for j in range(p + 1): + */ + /*else*/ { + __pyx_t_12 = (__pyx_v_n + 1); + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_13; __pyx_t_10+=1) { + __pyx_v_k = __pyx_t_10; + + /* "ezdxf/acc/bspline.pyx":387 + * else: + * for k in range(n + 1): + * v3_sum = Vec3() # <<<<<<<<<<<<<< + * for j in range(p + 1): + * bas_func = basis_funcs_ders[k][j] + */ + __pyx_t_5 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_v_v3_sum, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bspline.pyx":388 + * for k in range(n + 1): + * v3_sum = Vec3() + * for j in range(p + 1): # <<<<<<<<<<<<<< + * bas_func = basis_funcs_ders[k][j] + * cpoint = control_points[span - p + j] + */ + __pyx_t_14 = (__pyx_v_p + 1); + __pyx_t_15 = __pyx_t_14; + for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) { + __pyx_v_j = __pyx_t_16; + + /* "ezdxf/acc/bspline.pyx":389 + * v3_sum = Vec3() + * for j in range(p + 1): + * bas_func = basis_funcs_ders[k][j] # <<<<<<<<<<<<<< + * cpoint = control_points[span - p + j] + * v3_sum.x += cpoint.x * bas_func + */ + if (unlikely(__pyx_v_basis_funcs_ders == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 389, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_GetItemInt_List(__pyx_v_basis_funcs_ders, __pyx_v_k, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 389, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_5, __pyx_v_j, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 389, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_9 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_9 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 389, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_bas_func = __pyx_t_9; + + /* "ezdxf/acc/bspline.pyx":390 + * for j in range(p + 1): + * bas_func = basis_funcs_ders[k][j] + * cpoint = control_points[span - p + j] # <<<<<<<<<<<<<< + * v3_sum.x += cpoint.x * bas_func + * v3_sum.y += cpoint.y * bas_func + */ + if (unlikely(__pyx_v_control_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 390, __pyx_L1_error) + } + __pyx_t_18 = ((__pyx_v_span - __pyx_v_p) + __pyx_v_j); + __pyx_t_2 = __Pyx_GetItemInt_Tuple(__pyx_v_control_points, __pyx_t_18, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 390, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF_SET(__pyx_v_cpoint, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/bspline.pyx":391 + * bas_func = basis_funcs_ders[k][j] + * cpoint = control_points[span - p + j] + * v3_sum.x += cpoint.x * bas_func # <<<<<<<<<<<<<< + * v3_sum.y += cpoint.y * bas_func + * v3_sum.z += cpoint.z * bas_func + */ + __pyx_v_v3_sum->x = (__pyx_v_v3_sum->x + (__pyx_v_cpoint->x * __pyx_v_bas_func)); + + /* "ezdxf/acc/bspline.pyx":392 + * cpoint = control_points[span - p + j] + * v3_sum.x += cpoint.x * bas_func + * v3_sum.y += cpoint.y * bas_func # <<<<<<<<<<<<<< + * v3_sum.z += cpoint.z * bas_func + * CK.append(v3_sum) + */ + __pyx_v_v3_sum->y = (__pyx_v_v3_sum->y + (__pyx_v_cpoint->y * __pyx_v_bas_func)); + + /* "ezdxf/acc/bspline.pyx":393 + * v3_sum.x += cpoint.x * bas_func + * v3_sum.y += cpoint.y * bas_func + * v3_sum.z += cpoint.z * bas_func # <<<<<<<<<<<<<< + * CK.append(v3_sum) + * return CK + */ + __pyx_v_v3_sum->z = (__pyx_v_v3_sum->z + (__pyx_v_cpoint->z * __pyx_v_bas_func)); + } + + /* "ezdxf/acc/bspline.pyx":394 + * v3_sum.y += cpoint.y * bas_func + * v3_sum.z += cpoint.z * bas_func + * CK.append(v3_sum) # <<<<<<<<<<<<<< + * return CK + * + */ + __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_CK, ((PyObject *)__pyx_v_v3_sum)); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 394, __pyx_L1_error) + } + } + __pyx_L4:; + + /* "ezdxf/acc/bspline.pyx":395 + * v3_sum.z += cpoint.z * bas_func + * CK.append(v3_sum) + * return CK # <<<<<<<<<<<<<< + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_CK); + __pyx_r = __pyx_v_CK; + goto __pyx_L0; + + /* "ezdxf/acc/bspline.pyx":339 + * yield self.point(u) + * + * cpdef list derivative(self, double u, int n = 1): # <<<<<<<<<<<<<< + * """ Return point and derivatives up to n <= degree for parameter u. """ + * # Source: The NURBS Book: Algorithm A3.2 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.derivative", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_basis); + __Pyx_XDECREF(__pyx_v_CK); + __Pyx_XDECREF(__pyx_v_CKw); + __Pyx_XDECREF(__pyx_v_wders); + __Pyx_XDECREF(__pyx_v_control_points); + __Pyx_XDECREF(__pyx_v_weights); + __Pyx_XDECREF((PyObject *)__pyx_v_cpoint); + __Pyx_XDECREF((PyObject *)__pyx_v_v3_sum); + __Pyx_XDECREF(__pyx_v_basis_funcs_ders); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_8derivative(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_7bspline_9Evaluator_7derivative, " Return point and derivatives up to n <= degree for parameter u. "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_8derivative = {"derivative", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_8derivative, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_7bspline_9Evaluator_7derivative}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_8derivative(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_u; + int __pyx_v_n; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("derivative (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_u,&__pyx_n_s_n,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_u)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 339, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_n); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 339, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "derivative") < 0)) __PYX_ERR(0, 339, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_u = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_u == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 339, __pyx_L3_error) + if (values[1]) { + __pyx_v_n = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 339, __pyx_L3_error) + } else { + __pyx_v_n = ((int)1); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("derivative", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 339, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.derivative", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_7derivative(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v_u, __pyx_v_n); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_7derivative(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, double __pyx_v_u, int __pyx_v_n) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("derivative", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_2.__pyx_n = 1; + __pyx_t_2.n = __pyx_v_n; + __pyx_t_1 = __pyx_vtabptr_5ezdxf_3acc_7bspline_Evaluator->derivative(__pyx_v_self, __pyx_v_u, 1, &__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.derivative", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_11generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/bspline.pyx":397 + * return CK + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_10derivatives(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_10derivatives = {"derivatives", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_10derivatives, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_10derivatives(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_t = 0; + int __pyx_v_n; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("derivatives (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t,&__pyx_n_s_n,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 397, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_n); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 397, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "derivatives") < 0)) __PYX_ERR(0, 397, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_t = values[0]; + if (values[1]) { + __pyx_v_n = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 397, __pyx_L3_error) + } else { + __pyx_v_n = ((int)1); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("derivatives", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 397, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_9derivatives(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v_t, __pyx_v_n); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_9derivatives(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, PyObject *__pyx_v_t, int __pyx_v_n) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("derivatives", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 397, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_t = __pyx_v_t; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_t); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_t); + __pyx_cur_scope->__pyx_v_n = __pyx_v_n; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_11generator1, __pyx_codeobj__6, (PyObject *) __pyx_cur_scope, __pyx_n_s_derivatives, __pyx_n_s_Evaluator_derivatives, __pyx_n_s_ezdxf_acc_bspline); if (unlikely(!gen)) __PYX_ERR(0, 397, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_7bspline_9Evaluator_11generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + double __pyx_t_5; + struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("derivatives", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 397, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":399 + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: + * cdef double u + * for u in t: # <<<<<<<<<<<<<< + * yield self.derivative(u, n) + */ + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_t)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_t)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_v_t; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_t); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 399, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 399, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 399, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 399, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 399, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 399, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 399, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 399, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 399, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __pyx_t_5 = __pyx_PyFloat_AsDouble(__pyx_t_4); if (unlikely((__pyx_t_5 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 399, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_cur_scope->__pyx_v_u = __pyx_t_5; + + /* "ezdxf/acc/bspline.pyx":400 + * cdef double u + * for u in t: + * yield self.derivative(u, n) # <<<<<<<<<<<<<< + */ + __pyx_t_6.__pyx_n = 1; + __pyx_t_6.n = __pyx_cur_scope->__pyx_v_n; + __pyx_t_4 = ((struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator *)__pyx_cur_scope->__pyx_v_self->__pyx_vtab)->derivative(__pyx_cur_scope->__pyx_v_self, __pyx_cur_scope->__pyx_v_u, 0, &__pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 400, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 400, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":399 + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: + * cdef double u + * for u in t: # <<<<<<<<<<<<<< + * yield self.derivative(u, n) + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/bspline.pyx":397 + * return CK + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("derivatives", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_12__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_14__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_7bspline_9Evaluator_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.bspline.Evaluator.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Basis __pyx_vtable_5ezdxf_3acc_7bspline_Basis; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline_Basis(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_7bspline_Basis; + p->weights_ = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_7bspline_5Basis_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Basis(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Basis) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_5ezdxf_3acc_7bspline_5Basis_3__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->weights_); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_7bspline_Basis(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)o; + if (p->weights_) { + e = (*v)(p->weights_, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_7bspline_Basis(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)o; + tmp = ((PyObject*)p->weights_); + p->weights_ = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_degree(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_6degree_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_knots(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_5knots_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_weights(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_7weights_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_is_rational(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_11is_rational_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_order(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_5order_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_count(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_5count_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_7bspline_5Basis_max_t(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_7bspline_5Basis_5max_t_1__get__(o); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_7bspline_Basis[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_7bspline_Basis[] = { + {(char *)"degree", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_degree, 0, (char *)0, 0}, + {(char *)"knots", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_knots, 0, (char *)0, 0}, + {(char *)"weights", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_weights, 0, (char *)0, 0}, + {(char *)"is_rational", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_is_rational, 0, (char *)PyDoc_STR(" Returns ``True`` if curve is a rational B-spline. (has weights) "), 0}, + {(char *)"order", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_order, 0, (char *)0, 0}, + {(char *)"count", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_count, 0, (char *)0, 0}, + {(char *)"max_t", __pyx_getprop_5ezdxf_3acc_7bspline_5Basis_max_t, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline_Basis_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline_Basis}, + {Py_tp_doc, (void *)PyDoc_STR(" Immutable Basis function class. ")}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_7bspline_Basis}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_7bspline_Basis}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_7bspline_Basis}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_7bspline_Basis}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline_Basis}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline_Basis_spec = { + "ezdxf.acc.bspline.Basis", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_7bspline_Basis_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline_Basis = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""Basis", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Basis, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + PyDoc_STR(" Immutable Basis function class. "), /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_7bspline_Basis, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_7bspline_Basis, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_7bspline_Basis, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_7bspline_Basis, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline_Basis, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_5ezdxf_3acc_7bspline_Evaluator __pyx_vtable_5ezdxf_3acc_7bspline_Evaluator; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline_Evaluator(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_7bspline_Evaluator; + p->_basis = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)Py_None); Py_INCREF(Py_None); + p->_control_points = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Evaluator(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Evaluator) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->_basis); + Py_CLEAR(p->_control_points); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_7bspline_Evaluator(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)o; + if (p->_basis) { + e = (*v)(((PyObject *)p->_basis), a); if (e) return e; + } + if (p->_control_points) { + e = (*v)(p->_control_points, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_7bspline_Evaluator(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *p = (struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *)o; + tmp = ((PyObject*)p->_basis); + p->_basis = ((struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->_control_points); + p->_control_points = ((PyObject*)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_7bspline_Evaluator[] = { + {"points", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_5points, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"derivatives", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_10derivatives, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline_Evaluator_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline_Evaluator}, + {Py_tp_doc, (void *)PyDoc_STR(" B-spline curve point and curve derivative evaluator. ")}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_7bspline_Evaluator}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_7bspline_Evaluator}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_7bspline_Evaluator}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline_Evaluator}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline_Evaluator_spec = { + "ezdxf.acc.bspline.Evaluator", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_7bspline_Evaluator_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline_Evaluator = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""Evaluator", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline_Evaluator, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + PyDoc_STR(" B-spline curve point and curve derivative evaluator. "), /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_7bspline_Evaluator, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_7bspline_Evaluator, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_7bspline_Evaluator, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline_Evaluator, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr[--__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_x); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr)))) { + __pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr[__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr *)o; + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + } + if (p->__pyx_v_x) { + e = (*v)(p->__pyx_v_x, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr_spec = { + "ezdxf.acc.bspline.__pyx_scope_struct__genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""__pyx_scope_struct__genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr[--__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr)); + (void) PyObject_INIT(o, t); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr[__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr_spec = { + "ezdxf.acc.bspline.__pyx_scope_struct_1_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""__pyx_scope_struct_1_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points[8]; +static int __pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points[--__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_v_t); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points)))) { + __pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points[__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points++] = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_v_t) { + e = (*v)(p->__pyx_v_t, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points_spec = { + "ezdxf.acc.bspline.__pyx_scope_struct_2_points", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""__pyx_scope_struct_2_points", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives[8]; +static int __pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives[--__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_v_t); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives)))) { + __pyx_freelist_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives[__pyx_freecount_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives++] = ((struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *p = (struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_v_t) { + e = (*v)(p->__pyx_v_t, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives_spec = { + "ezdxf.acc.bspline.__pyx_scope_struct_3_derivatives", + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.bspline.""__pyx_scope_struct_3_derivatives", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_Basis, __pyx_k_Basis, sizeof(__pyx_k_Basis), 0, 0, 1, 1}, + {&__pyx_n_u_Basis, __pyx_k_Basis, sizeof(__pyx_k_Basis), 0, 1, 0, 1}, + {&__pyx_n_s_Basis___get___locals_genexpr, __pyx_k_Basis___get___locals_genexpr, sizeof(__pyx_k_Basis___get___locals_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_Basis___reduce_cython, __pyx_k_Basis___reduce_cython, sizeof(__pyx_k_Basis___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Basis___setstate_cython, __pyx_k_Basis___setstate_cython, sizeof(__pyx_k_Basis___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Basis_basis_funcs, __pyx_k_Basis_basis_funcs, sizeof(__pyx_k_Basis_basis_funcs), 0, 0, 1, 1}, + {&__pyx_n_s_Basis_basis_funcs_derivatives, __pyx_k_Basis_basis_funcs_derivatives, sizeof(__pyx_k_Basis_basis_funcs_derivatives), 0, 0, 1, 1}, + {&__pyx_n_s_Basis_basis_vector, __pyx_k_Basis_basis_vector, sizeof(__pyx_k_Basis_basis_vector), 0, 0, 1, 1}, + {&__pyx_n_s_Basis_find_span, __pyx_k_Basis_find_span, sizeof(__pyx_k_Basis_find_span), 0, 0, 1, 1}, + {&__pyx_n_s_Basis_span_weighting, __pyx_k_Basis_span_weighting, sizeof(__pyx_k_Basis_span_weighting), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator, __pyx_k_Evaluator, sizeof(__pyx_k_Evaluator), 0, 0, 1, 1}, + {&__pyx_n_u_Evaluator, __pyx_k_Evaluator, sizeof(__pyx_k_Evaluator), 0, 1, 0, 1}, + {&__pyx_n_s_Evaluator___reduce_cython, __pyx_k_Evaluator___reduce_cython, sizeof(__pyx_k_Evaluator___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator___setstate_cython, __pyx_k_Evaluator___setstate_cython, sizeof(__pyx_k_Evaluator___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator_derivative, __pyx_k_Evaluator_derivative, sizeof(__pyx_k_Evaluator_derivative), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator_derivatives, __pyx_k_Evaluator_derivatives, sizeof(__pyx_k_Evaluator_derivatives), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator_point, __pyx_k_Evaluator_point, sizeof(__pyx_k_Evaluator_point), 0, 0, 1, 1}, + {&__pyx_n_s_Evaluator_points, __pyx_k_Evaluator_points, sizeof(__pyx_k_Evaluator_points), 0, 0, 1, 1}, + {&__pyx_n_s_Iterable, __pyx_k_Iterable, sizeof(__pyx_k_Iterable), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterable_float, __pyx_k_Iterable_float, sizeof(__pyx_k_Iterable_float), 0, 0, 1, 0}, + {&__pyx_n_s_Iterator, __pyx_k_Iterator, sizeof(__pyx_k_Iterator), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterator_Vec3, __pyx_k_Iterator_Vec3, sizeof(__pyx_k_Iterator_Vec3), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterator_list_Vec3, __pyx_k_Iterator_list_Vec3, sizeof(__pyx_k_Iterator_list_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_NULL_LIST, __pyx_k_NULL_LIST, sizeof(__pyx_k_NULL_LIST), 0, 0, 1, 1}, + {&__pyx_n_s_ONE_LIST, __pyx_k_ONE_LIST, sizeof(__pyx_k_ONE_LIST), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s__30, __pyx_k__30, sizeof(__pyx_k__30), 0, 0, 1, 1}, + {&__pyx_kp_u__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 1, 0, 0}, + {&__pyx_n_s_all, __pyx_k_all, sizeof(__pyx_k_all), 0, 0, 1, 1}, + {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_basis, __pyx_k_basis, sizeof(__pyx_k_basis), 0, 0, 1, 1}, + {&__pyx_n_s_basis_funcs, __pyx_k_basis_funcs, sizeof(__pyx_k_basis_funcs), 0, 0, 1, 1}, + {&__pyx_n_s_basis_funcs_derivatives, __pyx_k_basis_funcs_derivatives, sizeof(__pyx_k_basis_funcs_derivatives), 0, 0, 1, 1}, + {&__pyx_n_s_basis_vector, __pyx_k_basis_vector, sizeof(__pyx_k_basis_vector), 0, 0, 1, 1}, + {&__pyx_n_s_cinit___locals_genexpr, __pyx_k_cinit___locals_genexpr, sizeof(__pyx_k_cinit___locals_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1}, + {&__pyx_n_s_control_points, __pyx_k_control_points, sizeof(__pyx_k_control_points), 0, 0, 1, 1}, + {&__pyx_n_s_count, __pyx_k_count, sizeof(__pyx_k_count), 0, 0, 1, 1}, + {&__pyx_n_s_degree, __pyx_k_degree, sizeof(__pyx_k_degree), 0, 0, 1, 1}, + {&__pyx_n_s_derivative, __pyx_k_derivative, sizeof(__pyx_k_derivative), 0, 0, 1, 1}, + {&__pyx_n_s_derivatives, __pyx_k_derivatives, sizeof(__pyx_k_derivatives), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_ezdxf_acc_bspline, __pyx_k_ezdxf_acc_bspline, sizeof(__pyx_k_ezdxf_acc_bspline), 0, 0, 1, 1}, + {&__pyx_n_s_find_span, __pyx_k_find_span, sizeof(__pyx_k_find_span), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_genexpr, __pyx_k_genexpr, sizeof(__pyx_k_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_kp_u_invalid_count, __pyx_k_invalid_count, sizeof(__pyx_k_invalid_count), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_knot_count, __pyx_k_invalid_knot_count, sizeof(__pyx_k_invalid_knot_count), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_order, __pyx_k_invalid_order, sizeof(__pyx_k_invalid_order), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_weight_count, __pyx_k_invalid_weight_count, sizeof(__pyx_k_invalid_weight_count), 0, 1, 0, 0}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_n_s_is_rational, __pyx_k_is_rational, sizeof(__pyx_k_is_rational), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_knots, __pyx_k_knots, sizeof(__pyx_k_knots), 0, 0, 1, 1}, + {&__pyx_kp_s_list_float, __pyx_k_list_float, sizeof(__pyx_k_list_float), 0, 0, 1, 0}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_n, __pyx_k_n, sizeof(__pyx_k_n), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_nbasis, __pyx_k_nbasis, sizeof(__pyx_k_nbasis), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_order, __pyx_k_order, sizeof(__pyx_k_order), 0, 0, 1, 1}, + {&__pyx_n_s_point, __pyx_k_point, sizeof(__pyx_k_point), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_span, __pyx_k_span, sizeof(__pyx_k_span), 0, 0, 1, 1}, + {&__pyx_n_s_span_weighting, __pyx_k_span_weighting, sizeof(__pyx_k_span_weighting), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_k_src_ezdxf_acc_bspline_pyx, sizeof(__pyx_k_src_ezdxf_acc_bspline_pyx), 0, 0, 1, 0}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_sum, __pyx_k_sum, sizeof(__pyx_k_sum), 0, 0, 1, 1}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1}, + {&__pyx_n_s_tuple, __pyx_k_tuple, sizeof(__pyx_k_tuple), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_u, __pyx_k_u, sizeof(__pyx_k_u), 0, 0, 1, 1}, + {&__pyx_n_s_weights, __pyx_k_weights, sizeof(__pyx_k_weights), 0, 0, 1, 1}, + {&__pyx_n_s_zip, __pyx_k_zip, sizeof(__pyx_k_zip), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 51, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 72, __pyx_L1_error) + __pyx_builtin_sum = __Pyx_GetBuiltinName(__pyx_n_s_sum); if (!__pyx_builtin_sum) __PYX_ERR(0, 194, __pyx_L1_error) + __pyx_builtin_zip = __Pyx_GetBuiltinName(__pyx_n_s_zip); if (!__pyx_builtin_zip) __PYX_ERR(0, 189, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/bspline.pyx":72 + * ): + * if order < 2 or order >= MAX_SPLINE_ORDER: + * raise ValueError('invalid order') # <<<<<<<<<<<<<< + * self.order = order + * if count < 2: + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_invalid_order); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "ezdxf/acc/bspline.pyx":75 + * self.order = order + * if count < 2: + * raise ValueError('invalid count') # <<<<<<<<<<<<<< + * self.count = count + * self.knot_count = self.order + self.count + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_invalid_count); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "ezdxf/acc/bspline.pyx":82 + * cdef Py_ssize_t i = len(self.weights_) + * if i != 0 and i != self.count: + * raise ValueError('invalid weight count') # <<<<<<<<<<<<<< + * + * knots = [float(x) for x in knots] + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_invalid_weight_count); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "ezdxf/acc/bspline.pyx":86 + * knots = [float(x) for x in knots] + * if len(knots) != self.knot_count: + * raise ValueError('invalid knot count') # <<<<<<<<<<<<<< + * + * self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_invalid_knot_count); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "ezdxf/acc/bspline.pyx":113 + * return bool(self.weights_) + * + * cpdef list basis_vector(self, double t): # <<<<<<<<<<<<<< + * """ Returns the expanded basis vector. """ + * + */ + __pyx_tuple__8 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_t); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_basis_vector, 113, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 113, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":130 + * return result + * + * cpdef int find_span(self, double u): # <<<<<<<<<<<<<< + * """ Determine the knot span index. """ + * # Linear search is more reliable than binary search of the Algorithm A2.1 + */ + __pyx_tuple__10 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_u); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_find_span, 130, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 130, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":154 + * return span - 1 + * + * cpdef list basis_funcs(self, int span, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order + */ + __pyx_tuple__12 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_span, __pyx_n_s_u); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_basis_funcs, 154, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 154, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":187 + * return result + * + * cpdef list span_weighting(self, nbasis: list[float], int span): # <<<<<<<<<<<<<< + * cdef list products = [ + * nb * w for nb, w in zip( + */ + __pyx_tuple__14 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_nbasis, __pyx_n_s_span); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_span_weighting, 187, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 187, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":200 + * return NULL_LIST * len(nbasis) + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): # <<<<<<<<<<<<<< + * # pyright: reportUndefinedVariable=false + * # pyright flags Cython multi-arrays incorrect: + */ + __pyx_tuple__16 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_span, __pyx_n_s_u, __pyx_n_s_n); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__16); + __Pyx_GIVEREF(__pyx_tuple__16); + __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_basis_funcs_derivatives, 200, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(0, 200, __pyx_L1_error) + __pyx_tuple__18 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_tuple__19 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__19)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__19); + __Pyx_GIVEREF(__pyx_tuple__19); + __pyx_codeobj__20 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_tuple__21 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_pyx_state); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__21); + __Pyx_GIVEREF(__pyx_tuple__21); + __pyx_codeobj__22 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__21, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__22)) __PYX_ERR(1, 3, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":312 + * self._control_points = Vec3.tuple(control_points) + * + * cpdef Vec3 point(self, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + */ + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_point, 312, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 312, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":334 + * return v3_sum + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + __pyx_tuple__24 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_t, __pyx_n_s_u); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(0, 334, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__24); + __Pyx_GIVEREF(__pyx_tuple__24); + __pyx_codeobj__5 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_points, 334, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__5)) __PYX_ERR(0, 334, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":339 + * yield self.point(u) + * + * cpdef list derivative(self, double u, int n = 1): # <<<<<<<<<<<<<< + * """ Return point and derivatives up to n <= degree for parameter u. """ + * # Source: The NURBS Book: Algorithm A3.2 + */ + __pyx_tuple__25 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_u, __pyx_n_s_n); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__25); + __Pyx_GIVEREF(__pyx_tuple__25); + __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_derivative, 339, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 339, __pyx_L1_error) + + /* "ezdxf/acc/bspline.pyx":397 + * return CK + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + __pyx_tuple__27 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_t, __pyx_n_s_n, __pyx_n_s_u); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 397, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_bspline_pyx, __pyx_n_s_derivatives, 397, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 397, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__21, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_float_0_0 = PyFloat_FromDouble(0.0); if (unlikely(!__pyx_float_0_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_1_0 = PyFloat_FromDouble(1.0); if (unlikely(!__pyx_float_1_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __pyx_v_5ezdxf_3acc_7bspline_NULLVEC = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)Py_None); Py_INCREF(Py_None); + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_vtabptr_5ezdxf_3acc_7bspline_Basis = &__pyx_vtable_5ezdxf_3acc_7bspline_Basis; + __pyx_vtable_5ezdxf_3acc_7bspline_Basis.basis_vector = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, double, int __pyx_skip_dispatch))__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_vector; + __pyx_vtable_5ezdxf_3acc_7bspline_Basis.find_span = (int (*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, double, int __pyx_skip_dispatch))__pyx_f_5ezdxf_3acc_7bspline_5Basis_find_span; + __pyx_vtable_5ezdxf_3acc_7bspline_Basis.basis_funcs = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, int, double, int __pyx_skip_dispatch))__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs; + __pyx_vtable_5ezdxf_3acc_7bspline_Basis.span_weighting = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, PyObject *, int, int __pyx_skip_dispatch))__pyx_f_5ezdxf_3acc_7bspline_5Basis_span_weighting; + __pyx_vtable_5ezdxf_3acc_7bspline_Basis.basis_funcs_derivatives = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Basis *, int, double, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives *__pyx_optional_args))__pyx_f_5ezdxf_3acc_7bspline_5Basis_basis_funcs_derivatives; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline_Basis = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline_Basis_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline_Basis)) __PYX_ERR(0, 54, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline_Basis_spec, __pyx_ptype_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline_Basis = &__pyx_type_5ezdxf_3acc_7bspline_Basis; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline_Basis->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline_Basis->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline_Basis->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline_Basis->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_vtabptr_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Basis, (PyObject *) __pyx_ptype_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_7bspline_Basis) < 0) __PYX_ERR(0, 54, __pyx_L1_error) + #endif + __pyx_vtabptr_5ezdxf_3acc_7bspline_Evaluator = &__pyx_vtable_5ezdxf_3acc_7bspline_Evaluator; + __pyx_vtable_5ezdxf_3acc_7bspline_Evaluator.point = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *, double, int __pyx_skip_dispatch))__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_point; + __pyx_vtable_5ezdxf_3acc_7bspline_Evaluator.derivative = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_7bspline_Evaluator *, double, int __pyx_skip_dispatch, struct __pyx_opt_args_5ezdxf_3acc_7bspline_9Evaluator_derivative *__pyx_optional_args))__pyx_f_5ezdxf_3acc_7bspline_9Evaluator_derivative; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline_Evaluator_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator)) __PYX_ERR(0, 303, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline_Evaluator_spec, __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator = &__pyx_type_5ezdxf_3acc_7bspline_Evaluator; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator, __pyx_vtabptr_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Evaluator, (PyObject *) __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_7bspline_Evaluator) < 0) __PYX_ERR(0, 303, __pyx_L1_error) + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr)) __PYX_ERR(0, 78, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr_spec, __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr) < 0) __PYX_ERR(0, 78, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr = &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr) < 0) __PYX_ERR(0, 78, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct__genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr)) __PYX_ERR(0, 102, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr_spec, __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr) < 0) __PYX_ERR(0, 102, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr = &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr) < 0) __PYX_ERR(0, 102, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_1_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points)) __PYX_ERR(0, 334, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points_spec, __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points) < 0) __PYX_ERR(0, 334, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points = &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points) < 0) __PYX_ERR(0, 334, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_2_points->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives)) __PYX_ERR(0, 397, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives_spec, __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives) < 0) __PYX_ERR(0, 397, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives = &__pyx_type_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives) < 0) __PYX_ERR(0, 397, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_7bspline___pyx_scope_struct_3_derivatives->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_sub", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_sub, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_mul", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_bspline(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_bspline}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "bspline", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initbspline(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initbspline(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_bspline(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_bspline(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_bspline(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + static double __pyx_t_4[19]; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'bspline' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("bspline", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "bspline" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_bspline(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__bspline) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.bspline")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.bspline", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/bspline.pyx":4 + * # Copyright (c) 2021-2024, Manfred Moitzi + * # License: MIT License + * from typing import Iterable, Sequence, Iterator # <<<<<<<<<<<<<< + * import cython + * from cpython.mem cimport PyMem_Malloc, PyMem_Free + */ + __pyx_t_2 = PyList_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_Iterable); + __Pyx_GIVEREF(__pyx_n_s_Iterable); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_Iterable)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterator); + __Pyx_GIVEREF(__pyx_n_s_Iterator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_Iterator)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterable); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterable, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterator); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterator, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":9 + * from .vector cimport Vec3, isclose, v3_mul, v3_sub + * + * __all__ = ['Basis', 'Evaluator'] # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_3 = PyList_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_u_Basis); + __Pyx_GIVEREF(__pyx_n_u_Basis); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_u_Basis)) __PYX_ERR(0, 9, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_u_Evaluator); + __Pyx_GIVEREF(__pyx_n_u_Evaluator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_u_Evaluator)) __PYX_ERR(0, 9, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_all, __pyx_t_3) < 0) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":17 + * + * # factorial from 0 to 18 + * cdef double[19] FACTORIAL = [ # <<<<<<<<<<<<<< + * 1., 1., 2., 6., 24., 120., 720., 5040., 40320., 362880., 3628800., + * 39916800., 479001600., 6227020800., 87178291200., 1307674368000., + */ + __pyx_t_4[0] = 1.; + __pyx_t_4[1] = 1.; + __pyx_t_4[2] = 2.; + __pyx_t_4[3] = 6.; + __pyx_t_4[4] = 24.; + __pyx_t_4[5] = 120.; + __pyx_t_4[6] = 720.; + __pyx_t_4[7] = 5040.; + __pyx_t_4[8] = 40320.; + __pyx_t_4[9] = 362880.; + __pyx_t_4[10] = 3628800.; + __pyx_t_4[11] = 39916800.; + __pyx_t_4[12] = 479001600.; + __pyx_t_4[13] = 6227020800.; + __pyx_t_4[14] = 87178291200.; + __pyx_t_4[15] = 1307674368000.; + __pyx_t_4[16] = 20922789888000.; + __pyx_t_4[17] = 355687428096000.; + __pyx_t_4[18] = 6402373705728000.; + memcpy(&(__pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[0]), __pyx_t_4, sizeof(__pyx_v_5ezdxf_3acc_7bspline_FACTORIAL[0]) * (19)); + + /* "ezdxf/acc/bspline.pyx":23 + * ] + * + * NULL_LIST = [0.0] # <<<<<<<<<<<<<< + * ONE_LIST = [1.0] + * + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_float_0_0)) __PYX_ERR(0, 23, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_NULL_LIST, __pyx_t_3) < 0) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":24 + * + * NULL_LIST = [0.0] + * ONE_LIST = [1.0] # <<<<<<<<<<<<<< + * + * cdef Vec3 NULLVEC = Vec3() + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_float_1_0); + __Pyx_GIVEREF(__pyx_float_1_0); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_float_1_0)) __PYX_ERR(0, 24, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_ONE_LIST, __pyx_t_3) < 0) __PYX_ERR(0, 24, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":26 + * ONE_LIST = [1.0] + * + * cdef Vec3 NULLVEC = Vec3() # <<<<<<<<<<<<<< + * + * @cython.cdivision(True) + */ + __pyx_t_3 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_XGOTREF((PyObject *)__pyx_v_5ezdxf_3acc_7bspline_NULLVEC); + __Pyx_DECREF_SET(__pyx_v_5ezdxf_3acc_7bspline_NULLVEC, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3)); + __Pyx_GIVEREF(__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/bspline.pyx":113 + * return bool(self.weights_) + * + * cpdef list basis_vector(self, double t): # <<<<<<<<<<<<<< + * """ Returns the expanded basis vector. """ + * + */ + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_5basis_vector, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis_basis_vector, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_n_s_basis_vector, __pyx_t_3) < 0) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + + /* "ezdxf/acc/bspline.pyx":130 + * return result + * + * cpdef int find_span(self, double u): # <<<<<<<<<<<<<< + * """ Determine the knot span index. """ + * # Linear search is more reliable than binary search of the Algorithm A2.1 + */ + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_7find_span, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis_find_span, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_n_s_find_span, __pyx_t_3) < 0) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + + /* "ezdxf/acc/bspline.pyx":154 + * return span - 1 + * + * cpdef list basis_funcs(self, int span, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A2.2 + * cdef int order = self.order + */ + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_9basis_funcs, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis_basis_funcs, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_n_s_basis_funcs, __pyx_t_3) < 0) __PYX_ERR(0, 154, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + + /* "ezdxf/acc/bspline.pyx":187 + * return result + * + * cpdef list span_weighting(self, nbasis: list[float], int span): # <<<<<<<<<<<<<< + * cdef list products = [ + * nb * w for nb, w in zip( + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_nbasis, __pyx_kp_s_list_float) < 0) __PYX_ERR(0, 187, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_11span_weighting, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis_span_weighting, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_n_s_span_weighting, __pyx_t_2) < 0) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + + /* "ezdxf/acc/bspline.pyx":200 + * return NULL_LIST * len(nbasis) + * + * cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): # <<<<<<<<<<<<<< + * # pyright: reportUndefinedVariable=false + * # pyright flags Cython multi-arrays incorrect: + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_13basis_funcs_derivatives, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis_basis_funcs_derivatives, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__18); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Basis, __pyx_n_s_basis_funcs_derivatives, __pyx_t_2) < 0) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Basis); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_15__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__20)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_5Basis_17__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Basis___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__22)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_2) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bspline.pyx":312 + * self._control_points = Vec3.tuple(control_points) + * + * cpdef Vec3 point(self, double u): # <<<<<<<<<<<<<< + * # Source: The NURBS Book: Algorithm A3.1 + * cdef Basis basis = self._basis + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_3point, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator_point, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator, __pyx_n_s_point, __pyx_t_2) < 0) __PYX_ERR(0, 312, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + + /* "ezdxf/acc/bspline.pyx":334 + * return v3_sum + * + * def points(self, t: Iterable[float]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 334, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_t, __pyx_kp_s_Iterable_float) < 0) __PYX_ERR(0, 334, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec3) < 0) __PYX_ERR(0, 334, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_5points, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator_points, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__5)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 334, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator, __pyx_n_s_points, __pyx_t_3) < 0) __PYX_ERR(0, 334, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + + /* "ezdxf/acc/bspline.pyx":339 + * yield self.point(u) + * + * cpdef list derivative(self, double u, int n = 1): # <<<<<<<<<<<<<< + * """ Return point and derivatives up to n <= degree for parameter u. """ + * # Source: The NURBS Book: Algorithm A3.2 + */ + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_8derivative, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator_derivative, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__18); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator, __pyx_n_s_derivative, __pyx_t_3) < 0) __PYX_ERR(0, 339, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + + /* "ezdxf/acc/bspline.pyx":397 + * return CK + * + * def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: # <<<<<<<<<<<<<< + * cdef double u + * for u in t: + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 397, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_t, __pyx_kp_s_Iterable_float) < 0) __PYX_ERR(0, 397, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Iterator_list_Vec3) < 0) __PYX_ERR(0, 397, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_10derivatives, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator_derivatives, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__6)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 397, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__18); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator, __pyx_n_s_derivatives, __pyx_t_2) < 0) __PYX_ERR(0, 397, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_7bspline_Evaluator); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_13__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__28)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_7bspline_9Evaluator_15__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Evaluator___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_bspline, __pyx_d, ((PyObject *)__pyx_codeobj__29)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_2) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/bspline.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2021-2024, Manfred Moitzi + * # License: MIT License + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.bspline", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.bspline"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* DivInt[long] */ +static CYTHON_INLINE long __Pyx_div_long(long a, long b) { + long q = a / b; + long r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* pybytes_as_double */ +static double __Pyx_SlowPyString_AsDouble(PyObject *obj) { + PyObject *float_value; +#if PY_MAJOR_VERSION >= 3 + float_value = PyFloat_FromString(obj); +#else + float_value = PyFloat_FromString(obj, 0); +#endif + if (likely(float_value)) { +#if CYTHON_ASSUME_SAFE_MACROS + double value = PyFloat_AS_DOUBLE(float_value); +#else + double value = PyFloat_AsDouble(float_value); +#endif + Py_DECREF(float_value); + return value; + } + return (double)-1; +} +static const char* __Pyx__PyBytes_AsDouble_Copy(const char* start, char* buffer, Py_ssize_t length) { + int last_was_punctuation = 1; + Py_ssize_t i; + for (i=0; i < length; i++) { + char chr = start[i]; + int is_punctuation = (chr == '_') | (chr == '.') | (chr == 'e') | (chr == 'E'); + *buffer = chr; + buffer += (chr != '_'); + if (unlikely(last_was_punctuation & is_punctuation)) goto parse_failure; + last_was_punctuation = is_punctuation; + } + if (unlikely(last_was_punctuation)) goto parse_failure; + *buffer = '\0'; + return buffer; +parse_failure: + return NULL; +} +static double __Pyx__PyBytes_AsDouble_inf_nan(const char* start, Py_ssize_t length) { + int matches = 1; + char sign = start[0]; + int is_signed = (sign == '+') | (sign == '-'); + start += is_signed; + length -= is_signed; + switch (start[0]) { + #ifdef Py_NAN + case 'n': + case 'N': + if (unlikely(length != 3)) goto parse_failure; + matches &= (start[1] == 'a' || start[1] == 'A'); + matches &= (start[2] == 'n' || start[2] == 'N'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_NAN : Py_NAN; + #endif + case 'i': + case 'I': + if (unlikely(length < 3)) goto parse_failure; + matches &= (start[1] == 'n' || start[1] == 'N'); + matches &= (start[2] == 'f' || start[2] == 'F'); + if (likely(length == 3 && matches)) + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + if (unlikely(length != 8)) goto parse_failure; + matches &= (start[3] == 'i' || start[3] == 'I'); + matches &= (start[4] == 'n' || start[4] == 'N'); + matches &= (start[5] == 'i' || start[5] == 'I'); + matches &= (start[6] == 't' || start[6] == 'T'); + matches &= (start[7] == 'y' || start[7] == 'Y'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + break; + default: + goto parse_failure; + } + return 0.0; +parse_failure: + return -1.0; +} +static CYTHON_INLINE int __Pyx__PyBytes_AsDouble_IsSpace(char ch) { + return (ch == 0x20) | !((ch < 0x9) | (ch > 0xd)); +} +CYTHON_UNUSED static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length) { + double value; + Py_ssize_t i, digits; + const char *last = start + length; + char *end; + while (__Pyx__PyBytes_AsDouble_IsSpace(*start)) + start++; + while (start < last - 1 && __Pyx__PyBytes_AsDouble_IsSpace(last[-1])) + last--; + length = last - start; + if (unlikely(length <= 0)) goto fallback; + value = __Pyx__PyBytes_AsDouble_inf_nan(start, length); + if (unlikely(value == -1.0)) goto fallback; + if (value != 0.0) return value; + digits = 0; + for (i=0; i < length; digits += start[i++] != '_'); + if (likely(digits == length)) { + value = PyOS_string_to_double(start, &end, NULL); + } else if (digits < 40) { + char number[40]; + last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); + if (unlikely(!last)) goto fallback; + value = PyOS_string_to_double(number, &end, NULL); + } else { + char *number = (char*) PyMem_Malloc((digits + 1) * sizeof(char)); + if (unlikely(!number)) goto fallback; + last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); + if (unlikely(!last)) { + PyMem_Free(number); + goto fallback; + } + value = PyOS_string_to_double(number, &end, NULL); + PyMem_Free(number); + } + if (likely(end == last) || (value == (double)-1 && PyErr_Occurred())) { + return value; + } +fallback: + return __Pyx_SlowPyString_AsDouble(obj); +} + +/* pynumber_float */ +static CYTHON_INLINE PyObject* __Pyx__PyNumber_Float(PyObject* obj) { + double val; + if (PyLong_CheckExact(obj)) { +#if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(obj))) { + val = (double) __Pyx_PyLong_CompactValue(obj); + goto no_error; + } +#endif + val = PyLong_AsDouble(obj); + } else if (PyUnicode_CheckExact(obj)) { + val = __Pyx_PyUnicode_AsDouble(obj); + } else if (PyBytes_CheckExact(obj)) { + val = __Pyx_PyBytes_AsDouble(obj); + } else if (PyByteArray_CheckExact(obj)) { + val = __Pyx_PyByteArray_AsDouble(obj); + } else { + return PyNumber_Float(obj); + } + if (unlikely(val == -1 && PyErr_Occurred())) { + return NULL; + } +#if CYTHON_USE_PYLONG_INTERNALS +no_error: +#endif + return PyFloat_FromDouble(val); +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc; + __Pyx_PyThreadState_declare + #ifdef __Pyx_StopAsyncIteration_USED + int is_async_stopiteration = 0; + #endif + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + cur_exc = PyErr_Occurred(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + #ifdef __Pyx_StopAsyncIteration_USED + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else + #endif + return; + } + __Pyx_PyThreadState_assign + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + PyErr_SetString(PyExc_RuntimeError, + #ifdef __Pyx_StopAsyncIteration_USED + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + #endif + "generator raised StopIteration"); +} + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* SliceTupleAndList */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_crop_slice(Py_ssize_t* _start, Py_ssize_t* _stop, Py_ssize_t* _length) { + Py_ssize_t start = *_start, stop = *_stop, length = *_length; + if (start < 0) { + start += length; + if (start < 0) + start = 0; + } + if (stop < 0) + stop += length; + else if (stop > length) + stop = length; + *_length = stop - start; + *_start = start; + *_stop = stop; +} +static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice( + PyObject* src, Py_ssize_t start, Py_ssize_t stop) { + Py_ssize_t length = PyList_GET_SIZE(src); + __Pyx_crop_slice(&start, &stop, &length); + if (length <= 0) { + return PyList_New(0); + } + return __Pyx_PyList_FromArray(((PyListObject*)src)->ob_item + start, length); +} +static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice( + PyObject* src, Py_ssize_t start, Py_ssize_t stop) { + Py_ssize_t length = PyTuple_GET_SIZE(src); + __Pyx_crop_slice(&start, &stop, &length); + return __Pyx_PyTuple_FromArray(((PyTupleObject*)src)->ob_item + start, length); +} +#endif + +/* RaiseTooManyValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* IterFinish */ +static CYTHON_INLINE int __Pyx_IterFinish(void) { + PyObject* exc_type; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + exc_type = __Pyx_PyErr_CurrentExceptionType(); + if (unlikely(exc_type)) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) + return -1; + __Pyx_PyErr_Clear(); + return 0; + } + return 0; +} + +/* UnpackItemEndCheck */ +static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { + if (unlikely(retval)) { + Py_DECREF(retval); + __Pyx_RaiseTooManyValuesError(expected); + return -1; + } + return __Pyx_IterFinish(); +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyIntCompare */ +static CYTHON_INLINE int __Pyx_PyInt_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace) { + CYTHON_MAYBE_UNUSED_VAR(intval); + CYTHON_UNUSED_VAR(inplace); + if (op1 == op2) { + return 0; + } + #if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(op1))) { + const long b = intval; + long a = PyInt_AS_LONG(op1); + return (a != b); + } + #endif + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + int unequal; + unsigned long uintval; + Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); + const digit* digits = __Pyx_PyLong_Digits(op1); + if (intval == 0) { + return (__Pyx_PyLong_IsZero(op1) != 1); + } else if (intval < 0) { + if (__Pyx_PyLong_IsNonNeg(op1)) + return 1; + intval = -intval; + } else { + if (__Pyx_PyLong_IsNeg(op1)) + return 1; + } + uintval = (unsigned long) intval; +#if PyLong_SHIFT * 4 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 4)) { + unequal = (size != 5) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[4] != ((uintval >> (4 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 3 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 3)) { + unequal = (size != 4) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 2 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 2)) { + unequal = (size != 3) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 1 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 1)) { + unequal = (size != 2) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif + unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); + return (unequal != 0); + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; +#if CYTHON_COMPILING_IN_LIMITED_API + double a = __pyx_PyFloat_AsDouble(op1); +#else + double a = PyFloat_AS_DOUBLE(op1); +#endif + return ((double)a != (double)b); + } + return __Pyx_PyObject_IsTrueAndDecref( + PyObject_RichCompare(op1, op2, Py_NE)); +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__7); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__30); + } + return name; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; iexc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* PyObjectCall2Args */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 */ +#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2 + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_GetMethod; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* CoroutineBase */ +#include +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } +#if PY_VERSION_HEX >= 0x030300A0 + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); + } +#endif + else if (unlikely(PyTuple_Check(ev))) { + if (PyTuple_GET_SIZE(ev) >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#else + value = PySequence_ITEM(ev, 0); +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if PY_VERSION_HEX >= 0x030300A0 + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); +#else + { + PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args); + Py_DECREF(ev); + if (likely(args)) { + value = PySequence_GetItem(args, 0); + Py_DECREF(args); + } + if (unlikely(!value)) { + __Pyx_ErrRestore(NULL, NULL, NULL); + Py_INCREF(Py_None); + value = Py_None; + } + } +#endif + *pvalue = value; + return 0; +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +#define __Pyx_Coroutine_NotStartedError(gen) (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_NotStartedError(PyObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(gen)) { + msg = "can't send non-None value to a just-started coroutine"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a just-started async generator"; + #endif + } else { + msg = "can't send non-None value to a just-started generator"; + } + PyErr_SetString(PyExc_TypeError, msg); +} +#define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing) (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(!self->is_running); + if (unlikely(self->resume_label == 0)) { + if (unlikely(value && value != Py_None)) { + return __Pyx_Coroutine_NotStartedError((PyObject*)self); + } + } + if (unlikely(self->resume_label == -1)) { + return __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + self->is_running = 1; + retval = self->body(self, tstate, value); + self->is_running = 0; +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + return retval; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_MethodReturn(PyObject* gen, PyObject *retval) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (unlikely(!retval)) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (!__Pyx_PyErr_Occurred()) { + PyObject *exc = PyExc_StopIteration; + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + exc = __Pyx_PyExc_StopAsyncIteration; + #endif + __Pyx_PyErr_SetNone(exc); + } + } + return retval; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) { + PyObject *ret; + PyObject *val = NULL; + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + ret = __Pyx_Coroutine_SendEx(gen, val, 0); + Py_XDECREF(val); + return ret; +} +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03050000 && defined(PyCoro_CheckExact) && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + { + if (value == Py_None) + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + else + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value); + } + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + retval = __Pyx_Coroutine_FinishDelegation(gen); + } else { + retval = __Pyx_Coroutine_SendEx(gen, value, 0); + } + return __Pyx_Coroutine_MethodReturn(self, retval); +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + PyObject *retval = NULL; + int err = 0; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + retval = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf, NULL); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + } else + #endif + { + PyObject *meth; + gen->is_running = 1; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) + err = -1; + } + gen->is_running = 0; + } + Py_XDECREF(retval); + return err; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + return __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_SendEx(gen, Py_None, 0); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + return __Pyx_Coroutine_Close(self); +} +static PyObject *__Pyx_Coroutine_Close(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *retval, *raised_exception; + PyObject *yf = gen->yieldfrom; + int err = 0; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = __Pyx_Coroutine_SendEx(gen, NULL, 1); + if (unlikely(retval)) { + const char *msg; + Py_DECREF(retval); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { +#if PY_VERSION_HEX < 0x03060000 + msg = "async generator ignored GeneratorExit - might require Python 3.6+ finalisation (PEP 525)"; +#else + msg = "async generator ignored GeneratorExit"; +#endif + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + return NULL; + } + raised_exception = PyErr_Occurred(); + if (likely(!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration))) { + if (raised_exception) PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); + goto throw_here; + } + gen->is_running = 1; + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + gen->is_running = 0; + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + gen->is_running = 0; + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + gen->is_running = 0; + Py_DECREF(yf); + if (!ret) { + ret = __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_MethodReturn(self, ret); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + Py_CLEAR(gen->yieldfrom); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if PY_VERSION_HEX >= 0x030400a1 && CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + Py_TYPE(gen)->tp_del(self); + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } +#if !CYTHON_USE_TP_FINALIZE + assert(self->ob_refcnt == 0); + __Pyx_SET_REFCNT(self, 1); +#endif + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); +#if PY_MAJOR_VERSION >= 3 || defined(PyErr_WarnFormat) + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); +#else + {PyObject *msg; + char *cmsg; + #if CYTHON_COMPILING_IN_PYPY + msg = NULL; + cmsg = (char*) "coroutine was never awaited"; + #else + char *cname; + PyObject *qualname; + qualname = gen->gi_qualname; + cname = PyString_AS_STRING(qualname); + msg = PyString_FromFormat("coroutine '%.50s' was never awaited", cname); + if (unlikely(!msg)) { + PyErr_Clear(); + cmsg = (char*) "coroutine was never awaited"; + } else { + cmsg = PyString_AS_STRING(msg); + } + #endif + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, cmsg, 1) < 0)) + PyErr_WriteUnraisable(self); + Py_XDECREF(msg);} +#endif + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *res = __Pyx_Coroutine_Close(self); + if (unlikely(!res)) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +#if !CYTHON_USE_TP_FINALIZE + assert(Py_REFCNT(self) > 0); + if (likely(--self->ob_refcnt == 0)) { + return; + } + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReference(self); + __Pyx_SET_REFCNT(self, refcnt); + } +#if CYTHON_COMPILING_IN_CPYTHON + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + _Py_DEC_REFTOTAL; +#endif +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif +#endif +} +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) +{ + PyObject *frame = self->gi_frame; + CYTHON_UNUSED_VAR(context); + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (unlikely(!frame)) + return NULL; + self->gi_frame = frame; + } + Py_INCREF(frame); + return frame; +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif + gen->gi_weakreflist = NULL; + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} + +/* PatchModuleWithCoroutine */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + int result; + PyObject *globals, *result_obj; + globals = PyDict_New(); if (unlikely(!globals)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_coroutine_type", + #ifdef __Pyx_Coroutine_USED + (PyObject*)__pyx_CoroutineType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_generator_type", + #ifdef __Pyx_Generator_USED + (PyObject*)__pyx_GeneratorType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore; + result_obj = PyRun_String(py_code, Py_file_input, globals, globals); + if (unlikely(!result_obj)) goto ignore; + Py_DECREF(result_obj); + Py_DECREF(globals); + return module; +ignore: + Py_XDECREF(globals); + PyErr_WriteUnraisable(module); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) { + Py_DECREF(module); + module = NULL; + } +#else + py_code++; +#endif + return module; +} + +/* PatchGeneratorABC */ +#ifndef CYTHON_REGISTER_ABCS +#define CYTHON_REGISTER_ABCS 1 +#endif +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) +static PyObject* __Pyx_patch_abc_module(PyObject *module); +static PyObject* __Pyx_patch_abc_module(PyObject *module) { + module = __Pyx_Coroutine_patch_module( + module, "" +"if _cython_generator_type is not None:\n" +" try: Generator = _module.Generator\n" +" except AttributeError: pass\n" +" else: Generator.register(_cython_generator_type)\n" +"if _cython_coroutine_type is not None:\n" +" try: Coroutine = _module.Coroutine\n" +" except AttributeError: pass\n" +" else: Coroutine.register(_cython_coroutine_type)\n" + ); + return module; +} +#endif +static int __Pyx_patch_abc(void) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + static int abc_patched = 0; + if (CYTHON_REGISTER_ABCS && !abc_patched) { + PyObject *module; + module = PyImport_ImportModule((PY_MAJOR_VERSION >= 3) ? "collections.abc" : "collections"); + if (unlikely(!module)) { + PyErr_WriteUnraisable(NULL); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, + ((PY_MAJOR_VERSION >= 3) ? + "Cython module failed to register with collections.abc module" : + "Cython module failed to register with collections module"), 1) < 0)) { + return -1; + } + } else { + module = __Pyx_patch_abc_module(module); + abc_patched = 1; + if (unlikely(!module)) + return -1; + Py_DECREF(module); + } + module = PyImport_ImportModule("backports_abc"); + if (module) { + module = __Pyx_patch_abc_module(module); + Py_XDECREF(module); + } + if (!module) { + PyErr_Clear(); + } + } +#else + if ((0)) __Pyx_Coroutine_patch_module(NULL, NULL); +#endif + return 0; +} + +/* Generator */ +static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL}, + {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, + {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + (char*) PyDoc_STR("name of the generator"), 0}, + {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + (char*) PyDoc_STR("qualified name of the generator"), 0}, + {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + (char*) PyDoc_STR("Frame of the generator"), 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + __pyx_GeneratorType_slots +}; +#else +static PyTypeObject __pyx_GeneratorType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + (destructor) __Pyx_Coroutine_dealloc, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + 0, + (traverseproc) __Pyx_Coroutine_traverse, + 0, + 0, + offsetof(__pyx_CoroutineObject, gi_weakreflist), + 0, + (iternextfunc) __Pyx_Generator_Next, + __pyx_Generator_methods, + __pyx_Generator_memberlist, + __pyx_Generator_getsets, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if CYTHON_USE_TP_FINALIZE + 0, +#else + __Pyx_Coroutine_del, +#endif + 0, +#if CYTHON_USE_TP_FINALIZE + __Pyx_Coroutine_del, +#elif PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; + __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif + if (unlikely(!__pyx_GeneratorType)) { + return -1; + } + return 0; +} + +/* CheckBinaryVersion */ +static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ +#ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.cpython-312-darwin.so new file mode 100755 index 0000000..00fa26b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.pyx new file mode 100644 index 0000000..31f7230 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/bspline.pyx @@ -0,0 +1,400 @@ +# cython: language_level=3 +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +from typing import Iterable, Sequence, Iterator +import cython +from cpython.mem cimport PyMem_Malloc, PyMem_Free +from .vector cimport Vec3, isclose, v3_mul, v3_sub + +__all__ = ['Basis', 'Evaluator'] + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + const int MAX_SPLINE_ORDER + +# factorial from 0 to 18 +cdef double[19] FACTORIAL = [ + 1., 1., 2., 6., 24., 120., 720., 5040., 40320., 362880., 3628800., + 39916800., 479001600., 6227020800., 87178291200., 1307674368000., + 20922789888000., 355687428096000., 6402373705728000. +] + +NULL_LIST = [0.0] +ONE_LIST = [1.0] + +cdef Vec3 NULLVEC = Vec3() + +@cython.cdivision(True) +cdef double binomial_coefficient(int k, int i): + cdef double k_fact = FACTORIAL[k] + cdef double i_fact = FACTORIAL[i] + cdef double k_i_fact + if i > k: + return 0.0 + k_i_fact = FACTORIAL[k - i] + return k_fact / (k_i_fact * i_fact) + +@cython.boundscheck(False) +cdef int bisect_right(double *a, double x, int lo, int hi): + cdef int mid + while lo < hi: + mid = (lo + hi) // 2 + if x < a[mid]: + hi = mid + else: + lo = mid + 1 + return lo + +cdef reset_double_array(double *a, int count, double value): + cdef int i + for i in range(count): + a[i] = value + +cdef class Basis: + """ Immutable Basis function class. """ + # public: + cdef readonly int order + cdef readonly int count + cdef readonly double max_t + cdef tuple weights_ # public attribute for Cython Evaluator + # private: + cdef double *_knots + cdef int knot_count + + def __cinit__( + self, knots: Iterable[float], + int order, + int count, + weights: Sequence[float] = None + ): + if order < 2 or order >= MAX_SPLINE_ORDER: + raise ValueError('invalid order') + self.order = order + if count < 2: + raise ValueError('invalid count') + self.count = count + self.knot_count = self.order + self.count + self.weights_ = tuple(float(x) for x in weights) if weights else tuple() + + cdef Py_ssize_t i = len(self.weights_) + if i != 0 and i != self.count: + raise ValueError('invalid weight count') + + knots = [float(x) for x in knots] + if len(knots) != self.knot_count: + raise ValueError('invalid knot count') + + self._knots = PyMem_Malloc(self.knot_count * sizeof(double)) + for i in range(self.knot_count): + self._knots[i] = knots[i] + self.max_t = self._knots[self.knot_count - 1] + + def __dealloc__(self): + PyMem_Free(self._knots) + + @property + def degree(self) -> int: + return self.order - 1 + + @property + def knots(self) -> tuple[float, ...]: + return tuple(x for x in self._knots[:self.knot_count]) + + @property + def weights(self) -> tuple[float, ...]: + return self.weights_ + + @property + def is_rational(self) -> bool: + """ Returns ``True`` if curve is a rational B-spline. (has weights) """ + return bool(self.weights_) + + cpdef list basis_vector(self, double t): + """ Returns the expanded basis vector. """ + + cdef int span = self.find_span(t) + cdef int p = self.order - 1 + cdef int front = span - p + cdef int back = self.count - span - 1 + cdef list result + if front > 0: + result = NULL_LIST * front + result.extend(self.basis_funcs(span, t)) + else: + result = self.basis_funcs(span, t) + if back > 0: + result.extend(NULL_LIST * back) + return result + + cpdef int find_span(self, double u): + """ Determine the knot span index. """ + # Linear search is more reliable than binary search of the Algorithm A2.1 + # from The NURBS Book by Piegl & Tiller. + cdef double *knots = self._knots + cdef int count = self.count # text book: n+1 + cdef int p = self.order - 1 + cdef int span + if u >= knots[count]: # special case + return count - 1 + + # common clamped spline: + if knots[p] == 0.0: # use binary search + # This is fast and works most of the time, + # but Test 621 : test_weired_closed_spline() + # goes into an infinity loop, because of + # a weird knot configuration. + return bisect_right(knots, u, p, count) - 1 + else: # use linear search + span = 0 + while knots[span] <= u and span < count: + span += 1 + return span - 1 + + cpdef list basis_funcs(self, int span, double u): + # Source: The NURBS Book: Algorithm A2.2 + cdef int order = self.order + cdef double *knots = self._knots + cdef double[MAX_SPLINE_ORDER] N, left, right + cdef list result + reset_double_array(N, order, 0.0) + reset_double_array(left, order, 0.0) + reset_double_array(right, order, 0.0) + + cdef int j, r, i1 + cdef double temp, saved, temp_r, temp_l + N[0] = 1.0 + for j in range(1, order): + i1 = span + 1 - j + if i1 < 0: + i1 = 0 + left[j] = u - knots[i1] + right[j] = knots[span + j] - u + saved = 0.0 + for r in range(j): + temp_r = right[r + 1] + temp_l = left[j - r] + temp = N[r] / (temp_r + temp_l) + N[r] = saved + temp_r * temp + saved = temp_l * temp + N[j] = saved + result = [x for x in N[:order]] + if self.is_rational: + return self.span_weighting(result, span) + else: + return result + + cpdef list span_weighting(self, nbasis: list[float], int span): + cdef list products = [ + nb * w for nb, w in zip( + nbasis, + self.weights_[span - self.order + 1: span + 1] + ) + ] + s = sum(products) + if s != 0: + return [p / s for p in products] + else: + return NULL_LIST * len(nbasis) + + cpdef list basis_funcs_derivatives(self, int span, double u, int n = 1): + # pyright: reportUndefinedVariable=false + # pyright flags Cython multi-arrays incorrect: + # cdef double[4][4] a # this is a valid array definition in Cython! + # https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#c-arrays + # Source: The NURBS Book: Algorithm A2.3 + cdef int order = self.order + cdef int p = order - 1 + if n > p: + n = p + cdef double *knots = self._knots + cdef double[MAX_SPLINE_ORDER] left, right + reset_double_array(left, order, 1.0) + reset_double_array(right, order, 1.0) + + cdef double[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER] ndu # pyright: ignore + reset_double_array( ndu, MAX_SPLINE_ORDER*MAX_SPLINE_ORDER, 1.0) + + cdef int j, r, i1 + cdef double temp, saved, tmp_r, tmp_l + for j in range(1, order): + i1 = span + 1 - j + if i1 < 0: + i1 = 0 + left[j] = u - knots[i1] + right[j] = knots[span + j] - u + saved = 0.0 + for r in range(j): + # lower triangle + tmp_r = right[r + 1] + tmp_l = left[j - r] + ndu[j][r] = tmp_r + tmp_l + temp = ndu[r][j - 1] / ndu[j][r] + # upper triangle + ndu[r][j] = saved + (tmp_r * temp) + saved = tmp_l * temp + ndu[j][j] = saved + + # load the basis_vector functions + cdef double[MAX_SPLINE_ORDER][MAX_SPLINE_ORDER] derivatives # pyright: ignore + reset_double_array( + derivatives, MAX_SPLINE_ORDER*MAX_SPLINE_ORDER, 0.0 + ) + for j in range(order): + derivatives[0][j] = ndu[j][p] + + # loop over function index + cdef double[2][MAX_SPLINE_ORDER] a # pyright: ignore + reset_double_array( a, 2*MAX_SPLINE_ORDER, 1.0) + + cdef int s1, s2, k, rk, pk, j1, j2, t + cdef double d + for r in range(order): + s1 = 0 + s2 = 1 + # alternate rows in array a + a[0][0] = 1.0 + + # loop to compute kth derivative + for k in range(1, n + 1): + d = 0.0 + rk = r - k + pk = p - k + if r >= k: + a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + d = a[s2][0] * ndu[rk][pk] + if rk >= -1: + j1 = 1 + else: + j1 = -rk + if (r - 1) <= pk: + j2 = k - 1 + else: + j2 = p - r + for j in range(j1, j2 + 1): + a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + d += (a[s2][j] * ndu[rk + j][pk]) + if r <= pk: + a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + d += (a[s2][k] * ndu[r][pk]) + derivatives[k][r] = d + + # Switch rows + t = s1 + s1 = s2 + s2 = t + + # Multiply through by the correct factors + cdef double rr = p + for k in range(1, n + 1): + for j in range(order): + derivatives[k][j] *= rr + rr *= (p - k) + + # return result as Python lists + cdef list result = [], row + for k in range(0, n + 1): + row = [] + result.append(row) + for j in range(order): + row.append(derivatives[k][j]) + return result + +cdef class Evaluator: + """ B-spline curve point and curve derivative evaluator. """ + cdef Basis _basis + cdef tuple _control_points + + def __cinit__(self, basis: Basis, control_points: Sequence[Vec3]): + self._basis = basis + self._control_points = Vec3.tuple(control_points) + + cpdef Vec3 point(self, double u): + # Source: The NURBS Book: Algorithm A3.1 + cdef Basis basis = self._basis + if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + u = basis.max_t + cdef: + int p = basis.order - 1 + int span = basis.find_span(u) + list N = basis.basis_funcs(span, u) + int i + Vec3 cpoint, v3_sum = Vec3() + tuple control_points = self._control_points + double factor + + for i in range(p + 1): + factor = N[i] + cpoint = control_points[span - p + i] + v3_sum.x += cpoint.x * factor + v3_sum.y += cpoint.y * factor + v3_sum.z += cpoint.z * factor + return v3_sum + + def points(self, t: Iterable[float]) -> Iterator[Vec3]: + cdef double u + for u in t: + yield self.point(u) + + cpdef list derivative(self, double u, int n = 1): + """ Return point and derivatives up to n <= degree for parameter u. """ + # Source: The NURBS Book: Algorithm A3.2 + + cdef Basis basis = self._basis + if isclose(u, basis.max_t, REL_TOL, ABS_TOL): + u = basis.max_t + cdef: + list CK = [], CKw = [], wders = [] + tuple control_points = self._control_points + tuple weights + Vec3 cpoint, v3_sum + double wder, bas_func_weight, bas_func + int k, j, i, p = basis.degree + int span = basis.find_span(u) + list basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + + if basis.is_rational: + # Homogeneous point representation required: + # (x*w, y*w, z*w, w) + weights = basis.weights_ + for k in range(n + 1): + v3_sum = Vec3() + wder = 0.0 + for j in range(p + 1): + i = span - p + j + bas_func_weight = basis_funcs_ders[k][j] * weights[i] + # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + cpoint = control_points[i] + v3_sum.x += cpoint.x * bas_func_weight + v3_sum.y += cpoint.y * bas_func_weight + v3_sum.z += cpoint.z * bas_func_weight + wder += bas_func_weight + CKw.append(v3_sum) + wders.append(wder) + + # Source: The NURBS Book: Algorithm A4.2 + for k in range(n + 1): + v3_sum = CKw[k] + for j in range(1, k + 1): + bas_func_weight = binomial_coefficient(k, j) * wders[j] + v3_sum = v3_sub( + v3_sum, + v3_mul(CK[k - j], bas_func_weight) + ) + CK.append(v3_sum / wders[0]) + else: + for k in range(n + 1): + v3_sum = Vec3() + for j in range(p + 1): + bas_func = basis_funcs_ders[k][j] + cpoint = control_points[span - p + j] + v3_sum.x += cpoint.x * bas_func + v3_sum.y += cpoint.y * bas_func + v3_sum.z += cpoint.z * bas_func + CK.append(v3_sum) + return CK + + def derivatives(self, t: Iterable[float], int n = 1) -> Iterator[list[Vec3]]: + cdef double u + for u in t: + yield self.derivative(u, n) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/constants.h b/.venv/lib/python3.12/site-packages/ezdxf/acc/constants.h new file mode 100644 index 0000000..145f7ee --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/constants.h @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Manfred Moitzi +// License: MIT License +// global constants +#define ABS_TOL 1e-12 +#define REL_TOL 1e-9 +#define M_TAU 6.283185307179586 +// AutoCAD limits the degree of SPLINE to 11 or order = 12 +#define MAX_SPLINE_ORDER 12 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.c new file mode 100644 index 0000000..526aa6e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.c @@ -0,0 +1,11803 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.construct", + "sources": [ + "src/ezdxf/acc/construct.pyx" + ] + }, + "module_name": "ezdxf.acc.construct" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__construct +#define __PYX_HAVE_API__ezdxf__acc__construct +/* Early includes */ +#include +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/construct.pyx", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_ctuple_double__and_double; +typedef struct __pyx_ctuple_double__and_double __pyx_ctuple_double__and_double; +struct __pyx_defaults; +typedef struct __pyx_defaults __pyx_defaults; +struct __pyx_defaults1; +typedef struct __pyx_defaults1 __pyx_defaults1; +struct __pyx_defaults2; +typedef struct __pyx_defaults2 __pyx_defaults2; + +/* "ezdxf/acc/construct.pyx":296 + * + * + * def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform GPS (long/lat) to World Mercator. + * + */ +struct __pyx_ctuple_double__and_double { + double f0; + double f1; +}; +struct __pyx_defaults { + double __pyx_arg_abs_tol; +}; +struct __pyx_defaults1 { + double __pyx_arg_abs_tol; +}; +struct __pyx_defaults2 { + double __pyx_arg_abs_tol; +}; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* ListCompAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len)) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* ModFloat[double].proto */ +static CYTHON_INLINE double __Pyx_mod_double(double, double); + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ + +/* Module declarations from "libc.math" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static int (*__pyx_f_5ezdxf_3acc_6vector_isclose)(double, double, double, double); /*proto*/ +static int (*__pyx_f_5ezdxf_3acc_6vector_v2_isclose)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_add)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_sub)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_mul)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_cross)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static double (*__pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_normalize)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static int (*__pyx_f_5ezdxf_3acc_6vector_v3_isclose)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); /*proto*/ + +/* Module declarations from "cython" */ + +/* Module declarations from "ezdxf.acc.construct" */ +static double __pyx_v_5ezdxf_3acc_9construct_RAD_ABS_TOL; +static double __pyx_v_5ezdxf_3acc_9construct_DEG_ABS_TOL; +static double __pyx_v_5ezdxf_3acc_9construct_TOLERANCE; +static double __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS; +static double __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MINOR_AXIS; +static double __pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC; +static double __pyx_v_5ezdxf_3acc_9construct_RADIANS; +static double __pyx_v_5ezdxf_3acc_9construct_DEGREES; +static double __pyx_f_5ezdxf_3acc_9construct__determinant(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.construct" +extern int __pyx_module_is_main_ezdxf__acc__construct; +int __pyx_module_is_main_ezdxf__acc__construct = 0; + +/* Implementation of "ezdxf.acc.construct" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +/* #### Code section: string_decls ### */ +static const char __pyx_k_a[] = "a"; +static const char __pyx_k_b[] = "b"; +static const char __pyx_k_c[] = "c"; +static const char __pyx_k_d[] = "d"; +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_s[] = "s"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k_v[] = "v"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k__2[] = "."; +static const char __pyx_k_c1[] = "c1"; +static const char __pyx_k_c2[] = "c2"; +static const char __pyx_k_d1[] = "d1"; +static const char __pyx_k_d2[] = "d2"; +static const char __pyx_k_o1[] = "o1"; +static const char __pyx_k_o2[] = "o2"; +static const char __pyx_k_p1[] = "p1"; +static const char __pyx_k_p2[] = "p2"; +static const char __pyx_k_s1[] = "s1"; +static const char __pyx_k_s2[] = "s2"; +static const char __pyx_k_uc[] = "uc"; +static const char __pyx_k_us[] = "us"; +static const char __pyx_k_x1[] = "x1"; +static const char __pyx_k_x2[] = "x2"; +static const char __pyx_k_y1[] = "y1"; +static const char __pyx_k_y2[] = "y2"; +static const char __pyx_k__18[] = "?"; +static const char __pyx_k_c1x[] = "c1x"; +static const char __pyx_k_c1y[] = "c1y"; +static const char __pyx_k_c2x[] = "c2x"; +static const char __pyx_k_c2y[] = "c2y"; +static const char __pyx_k_den[] = "den"; +static const char __pyx_k_end[] = "end"; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_lwr[] = "lwr"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_s1x[] = "s1x"; +static const char __pyx_k_s1y[] = "s1y"; +static const char __pyx_k_s2x[] = "s2x"; +static const char __pyx_k_s2y[] = "s2y"; +static const char __pyx_k_tol[] = "tol"; +static const char __pyx_k_upr[] = "upr"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_Vec2[] = "Vec2"; +static const char __pyx_k_bool[] = "bool"; +static const char __pyx_k_det1[] = "det1"; +static const char __pyx_k_det2[] = "det2"; +static const char __pyx_k_last[] = "last"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_ray1[] = "ray1"; +static const char __pyx_k_ray2[] = "ray2"; +static const char __pyx_k_size[] = "size"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_d1xd2[] = "d1xd2"; +static const char __pyx_k_float[] = "float"; +static const char __pyx_k_index[] = "index"; +static const char __pyx_k_line1[] = "line1"; +static const char __pyx_k_line2[] = "line2"; +static const char __pyx_k_o2_o1[] = "o2_o1"; +static const char __pyx_k_point[] = "point"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_start[] = "start"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_inside[] = "inside"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_abs_tol[] = "abs_tol"; +static const char __pyx_k_polygon[] = "polygon"; +static const char __pyx_k_virtual[] = "virtual"; +static const char __pyx_k_Iterable[] = "Iterable"; +static const char __pyx_k_Optional[] = "Optional"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_latitude[] = "latitude"; +static const char __pyx_k_vertices[] = "vertices"; +static const char __pyx_k_e_sin_lat[] = "e_sin_lat"; +static const char __pyx_k_list_Vec2[] = "list[Vec2]"; +static const char __pyx_k_longitude[] = "longitude"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_vertices_2[] = "_vertices"; +static const char __pyx_k_denominator[] = "denominator"; +static const char __pyx_k_eccentric_2[] = "eccentric_2"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_Iterable_UVec[] = "Iterable[UVec]"; +static const char __pyx_k_Optional_Vec2[] = "Optional[Vec2]"; +static const char __pyx_k_Sequence_Vec2[] = "Sequence[Vec2]"; +static const char __pyx_k_Sequence_Vec3[] = "Sequence[Vec3]"; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_latitude_prev[] = "latitude_prev"; +static const char __pyx_k_tuple_Vec3_Vec3[] = "tuple[Vec3, Vec3]"; +static const char __pyx_k_tuple_float_float[] = "tuple[float, float]"; +static const char __pyx_k_arc_angle_span_deg[] = "arc_angle_span_deg"; +static const char __pyx_k_arc_angle_span_rad[] = "arc_angle_span_rad"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ezdxf_acc_construct[] = "ezdxf.acc.construct"; +static const char __pyx_k_gps_to_world_mercator[] = "gps_to_world_mercator"; +static const char __pyx_k_world_mercator_to_gps[] = "world_mercator_to_gps"; +static const char __pyx_k_is_point_in_polygon_2d[] = "is_point_in_polygon_2d"; +static const char __pyx_k_intersection_ray_ray_3d[] = "intersection_ray_ray_3d"; +static const char __pyx_k_has_clockwise_orientation[] = "has_clockwise_orientation"; +static const char __pyx_k_intersection_line_line_2d[] = "intersection_line_line_2d"; +static const char __pyx_k_src_ezdxf_acc_construct_pyx[] = "src/ezdxf/acc/construct.pyx"; +static const char __pyx_k_At_least_3_vertices_required[] = "At least 3 vertices required."; +/* #### Code section: decls ### */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_has_clockwise_orientation(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_vertices); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_16__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_9construct_2intersection_line_line_2d(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_line1, PyObject *__pyx_v_line2, int __pyx_v_virtual, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_18__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_4intersection_ray_ray_3d(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_ray1, PyObject *__pyx_v_ray2, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_6arc_angle_span_deg(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start, double __pyx_v_end); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_8arc_angle_span_rad(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start, double __pyx_v_end); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_20__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_10is_point_in_polygon_2d(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_point, PyObject *__pyx_v_polygon, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_12gps_to_world_mercator(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_longitude, double __pyx_v_latitude); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_14world_mercator_to_gps(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_x, double __pyx_v_y, double __pyx_v_tol); /* proto */ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyObject *__pyx_kp_u_At_least_3_vertices_required; + PyObject *__pyx_n_s_Iterable; + PyObject *__pyx_kp_s_Iterable_UVec; + PyObject *__pyx_n_s_Optional; + PyObject *__pyx_kp_s_Optional_Vec2; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_kp_s_Sequence_Vec2; + PyObject *__pyx_kp_s_Sequence_Vec3; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s_Vec2; + PyObject *__pyx_n_s__18; + PyObject *__pyx_kp_u__2; + PyObject *__pyx_n_s_a; + PyObject *__pyx_n_s_abs_tol; + PyObject *__pyx_n_s_arc_angle_span_deg; + PyObject *__pyx_n_s_arc_angle_span_rad; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_b; + PyObject *__pyx_n_s_bool; + PyObject *__pyx_n_s_c; + PyObject *__pyx_n_s_c1; + PyObject *__pyx_n_s_c1x; + PyObject *__pyx_n_s_c1y; + PyObject *__pyx_n_s_c2; + PyObject *__pyx_n_s_c2x; + PyObject *__pyx_n_s_c2y; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_d; + PyObject *__pyx_n_s_d1; + PyObject *__pyx_n_s_d1xd2; + PyObject *__pyx_n_s_d2; + PyObject *__pyx_n_s_den; + PyObject *__pyx_n_s_denominator; + PyObject *__pyx_n_s_det1; + PyObject *__pyx_n_s_det2; + PyObject *__pyx_n_s_e_sin_lat; + PyObject *__pyx_n_s_eccentric_2; + PyObject *__pyx_n_s_end; + PyObject *__pyx_n_s_ezdxf_acc_construct; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_n_s_float; + PyObject *__pyx_n_s_gps_to_world_mercator; + PyObject *__pyx_n_s_has_clockwise_orientation; + PyObject *__pyx_n_s_i; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_index; + PyObject *__pyx_n_s_inside; + PyObject *__pyx_n_s_int; + PyObject *__pyx_n_s_intersection_line_line_2d; + PyObject *__pyx_n_s_intersection_ray_ray_3d; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_n_s_is_point_in_polygon_2d; + PyObject *__pyx_n_s_last; + PyObject *__pyx_n_s_latitude; + PyObject *__pyx_n_s_latitude_prev; + PyObject *__pyx_n_s_line1; + PyObject *__pyx_n_s_line2; + PyObject *__pyx_kp_s_list_Vec2; + PyObject *__pyx_n_s_longitude; + PyObject *__pyx_n_s_lwr; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_o1; + PyObject *__pyx_n_s_o2; + PyObject *__pyx_n_s_o2_o1; + PyObject *__pyx_n_s_p1; + PyObject *__pyx_n_s_p2; + PyObject *__pyx_n_s_point; + PyObject *__pyx_n_s_polygon; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_ray1; + PyObject *__pyx_n_s_ray2; + PyObject *__pyx_n_s_res; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_s; + PyObject *__pyx_n_s_s1; + PyObject *__pyx_n_s_s1x; + PyObject *__pyx_n_s_s1y; + PyObject *__pyx_n_s_s2; + PyObject *__pyx_n_s_s2x; + PyObject *__pyx_n_s_s2y; + PyObject *__pyx_n_s_size; + PyObject *__pyx_kp_s_src_ezdxf_acc_construct_pyx; + PyObject *__pyx_n_s_start; + PyObject *__pyx_n_s_t; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_tol; + PyObject *__pyx_kp_s_tuple_Vec3_Vec3; + PyObject *__pyx_kp_s_tuple_float_float; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_uc; + PyObject *__pyx_n_s_upr; + PyObject *__pyx_n_s_us; + PyObject *__pyx_n_s_v; + PyObject *__pyx_n_s_vertices; + PyObject *__pyx_n_s_vertices_2; + PyObject *__pyx_n_s_virtual; + PyObject *__pyx_n_s_world_mercator_to_gps; + PyObject *__pyx_n_s_x; + PyObject *__pyx_n_s_x1; + PyObject *__pyx_n_s_x2; + PyObject *__pyx_n_s_y; + PyObject *__pyx_n_s_y1; + PyObject *__pyx_n_s_y2; + PyObject *__pyx_float_0_0; + PyObject *__pyx_float_360_0; + PyObject *__pyx_int_0; + PyObject *__pyx_int_1; + PyObject *__pyx_int_neg_1; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__5; + PyObject *__pyx_tuple__7; + PyObject *__pyx_tuple__9; + PyObject *__pyx_tuple__12; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__16; + PyObject *__pyx_codeobj__4; + PyObject *__pyx_codeobj__6; + PyObject *__pyx_codeobj__8; + PyObject *__pyx_codeobj__10; + PyObject *__pyx_codeobj__11; + PyObject *__pyx_codeobj__13; + PyObject *__pyx_codeobj__15; + PyObject *__pyx_codeobj__17; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_kp_u_At_least_3_vertices_required); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterable); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_Optional); + Py_CLEAR(clear_module_state->__pyx_kp_s_Optional_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_kp_s_Sequence_Vec2); + Py_CLEAR(clear_module_state->__pyx_kp_s_Sequence_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_s__18); + Py_CLEAR(clear_module_state->__pyx_kp_u__2); + Py_CLEAR(clear_module_state->__pyx_n_s_a); + Py_CLEAR(clear_module_state->__pyx_n_s_abs_tol); + Py_CLEAR(clear_module_state->__pyx_n_s_arc_angle_span_deg); + Py_CLEAR(clear_module_state->__pyx_n_s_arc_angle_span_rad); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_b); + Py_CLEAR(clear_module_state->__pyx_n_s_bool); + Py_CLEAR(clear_module_state->__pyx_n_s_c); + Py_CLEAR(clear_module_state->__pyx_n_s_c1); + Py_CLEAR(clear_module_state->__pyx_n_s_c1x); + Py_CLEAR(clear_module_state->__pyx_n_s_c1y); + Py_CLEAR(clear_module_state->__pyx_n_s_c2); + Py_CLEAR(clear_module_state->__pyx_n_s_c2x); + Py_CLEAR(clear_module_state->__pyx_n_s_c2y); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_d); + Py_CLEAR(clear_module_state->__pyx_n_s_d1); + Py_CLEAR(clear_module_state->__pyx_n_s_d1xd2); + Py_CLEAR(clear_module_state->__pyx_n_s_d2); + Py_CLEAR(clear_module_state->__pyx_n_s_den); + Py_CLEAR(clear_module_state->__pyx_n_s_denominator); + Py_CLEAR(clear_module_state->__pyx_n_s_det1); + Py_CLEAR(clear_module_state->__pyx_n_s_det2); + Py_CLEAR(clear_module_state->__pyx_n_s_e_sin_lat); + Py_CLEAR(clear_module_state->__pyx_n_s_eccentric_2); + Py_CLEAR(clear_module_state->__pyx_n_s_end); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_construct); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_n_s_float); + Py_CLEAR(clear_module_state->__pyx_n_s_gps_to_world_mercator); + Py_CLEAR(clear_module_state->__pyx_n_s_has_clockwise_orientation); + Py_CLEAR(clear_module_state->__pyx_n_s_i); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_index); + Py_CLEAR(clear_module_state->__pyx_n_s_inside); + Py_CLEAR(clear_module_state->__pyx_n_s_int); + Py_CLEAR(clear_module_state->__pyx_n_s_intersection_line_line_2d); + Py_CLEAR(clear_module_state->__pyx_n_s_intersection_ray_ray_3d); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_n_s_is_point_in_polygon_2d); + Py_CLEAR(clear_module_state->__pyx_n_s_last); + Py_CLEAR(clear_module_state->__pyx_n_s_latitude); + Py_CLEAR(clear_module_state->__pyx_n_s_latitude_prev); + Py_CLEAR(clear_module_state->__pyx_n_s_line1); + Py_CLEAR(clear_module_state->__pyx_n_s_line2); + Py_CLEAR(clear_module_state->__pyx_kp_s_list_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_s_longitude); + Py_CLEAR(clear_module_state->__pyx_n_s_lwr); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_o1); + Py_CLEAR(clear_module_state->__pyx_n_s_o2); + Py_CLEAR(clear_module_state->__pyx_n_s_o2_o1); + Py_CLEAR(clear_module_state->__pyx_n_s_p1); + Py_CLEAR(clear_module_state->__pyx_n_s_p2); + Py_CLEAR(clear_module_state->__pyx_n_s_point); + Py_CLEAR(clear_module_state->__pyx_n_s_polygon); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_ray1); + Py_CLEAR(clear_module_state->__pyx_n_s_ray2); + Py_CLEAR(clear_module_state->__pyx_n_s_res); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_s); + Py_CLEAR(clear_module_state->__pyx_n_s_s1); + Py_CLEAR(clear_module_state->__pyx_n_s_s1x); + Py_CLEAR(clear_module_state->__pyx_n_s_s1y); + Py_CLEAR(clear_module_state->__pyx_n_s_s2); + Py_CLEAR(clear_module_state->__pyx_n_s_s2x); + Py_CLEAR(clear_module_state->__pyx_n_s_s2y); + Py_CLEAR(clear_module_state->__pyx_n_s_size); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_construct_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start); + Py_CLEAR(clear_module_state->__pyx_n_s_t); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_tol); + Py_CLEAR(clear_module_state->__pyx_kp_s_tuple_Vec3_Vec3); + Py_CLEAR(clear_module_state->__pyx_kp_s_tuple_float_float); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_uc); + Py_CLEAR(clear_module_state->__pyx_n_s_upr); + Py_CLEAR(clear_module_state->__pyx_n_s_us); + Py_CLEAR(clear_module_state->__pyx_n_s_v); + Py_CLEAR(clear_module_state->__pyx_n_s_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_vertices_2); + Py_CLEAR(clear_module_state->__pyx_n_s_virtual); + Py_CLEAR(clear_module_state->__pyx_n_s_world_mercator_to_gps); + Py_CLEAR(clear_module_state->__pyx_n_s_x); + Py_CLEAR(clear_module_state->__pyx_n_s_x1); + Py_CLEAR(clear_module_state->__pyx_n_s_x2); + Py_CLEAR(clear_module_state->__pyx_n_s_y); + Py_CLEAR(clear_module_state->__pyx_n_s_y1); + Py_CLEAR(clear_module_state->__pyx_n_s_y2); + Py_CLEAR(clear_module_state->__pyx_float_0_0); + Py_CLEAR(clear_module_state->__pyx_float_360_0); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_1); + Py_CLEAR(clear_module_state->__pyx_int_neg_1); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__5); + Py_CLEAR(clear_module_state->__pyx_tuple__7); + Py_CLEAR(clear_module_state->__pyx_tuple__9); + Py_CLEAR(clear_module_state->__pyx_tuple__12); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__16); + Py_CLEAR(clear_module_state->__pyx_codeobj__4); + Py_CLEAR(clear_module_state->__pyx_codeobj__6); + Py_CLEAR(clear_module_state->__pyx_codeobj__8); + Py_CLEAR(clear_module_state->__pyx_codeobj__10); + Py_CLEAR(clear_module_state->__pyx_codeobj__11); + Py_CLEAR(clear_module_state->__pyx_codeobj__13); + Py_CLEAR(clear_module_state->__pyx_codeobj__15); + Py_CLEAR(clear_module_state->__pyx_codeobj__17); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_kp_u_At_least_3_vertices_required); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterable); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_Optional); + Py_VISIT(traverse_module_state->__pyx_kp_s_Optional_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_kp_s_Sequence_Vec2); + Py_VISIT(traverse_module_state->__pyx_kp_s_Sequence_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_s__18); + Py_VISIT(traverse_module_state->__pyx_kp_u__2); + Py_VISIT(traverse_module_state->__pyx_n_s_a); + Py_VISIT(traverse_module_state->__pyx_n_s_abs_tol); + Py_VISIT(traverse_module_state->__pyx_n_s_arc_angle_span_deg); + Py_VISIT(traverse_module_state->__pyx_n_s_arc_angle_span_rad); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_b); + Py_VISIT(traverse_module_state->__pyx_n_s_bool); + Py_VISIT(traverse_module_state->__pyx_n_s_c); + Py_VISIT(traverse_module_state->__pyx_n_s_c1); + Py_VISIT(traverse_module_state->__pyx_n_s_c1x); + Py_VISIT(traverse_module_state->__pyx_n_s_c1y); + Py_VISIT(traverse_module_state->__pyx_n_s_c2); + Py_VISIT(traverse_module_state->__pyx_n_s_c2x); + Py_VISIT(traverse_module_state->__pyx_n_s_c2y); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_d); + Py_VISIT(traverse_module_state->__pyx_n_s_d1); + Py_VISIT(traverse_module_state->__pyx_n_s_d1xd2); + Py_VISIT(traverse_module_state->__pyx_n_s_d2); + Py_VISIT(traverse_module_state->__pyx_n_s_den); + Py_VISIT(traverse_module_state->__pyx_n_s_denominator); + Py_VISIT(traverse_module_state->__pyx_n_s_det1); + Py_VISIT(traverse_module_state->__pyx_n_s_det2); + Py_VISIT(traverse_module_state->__pyx_n_s_e_sin_lat); + Py_VISIT(traverse_module_state->__pyx_n_s_eccentric_2); + Py_VISIT(traverse_module_state->__pyx_n_s_end); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_construct); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_n_s_float); + Py_VISIT(traverse_module_state->__pyx_n_s_gps_to_world_mercator); + Py_VISIT(traverse_module_state->__pyx_n_s_has_clockwise_orientation); + Py_VISIT(traverse_module_state->__pyx_n_s_i); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_index); + Py_VISIT(traverse_module_state->__pyx_n_s_inside); + Py_VISIT(traverse_module_state->__pyx_n_s_int); + Py_VISIT(traverse_module_state->__pyx_n_s_intersection_line_line_2d); + Py_VISIT(traverse_module_state->__pyx_n_s_intersection_ray_ray_3d); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_n_s_is_point_in_polygon_2d); + Py_VISIT(traverse_module_state->__pyx_n_s_last); + Py_VISIT(traverse_module_state->__pyx_n_s_latitude); + Py_VISIT(traverse_module_state->__pyx_n_s_latitude_prev); + Py_VISIT(traverse_module_state->__pyx_n_s_line1); + Py_VISIT(traverse_module_state->__pyx_n_s_line2); + Py_VISIT(traverse_module_state->__pyx_kp_s_list_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_s_longitude); + Py_VISIT(traverse_module_state->__pyx_n_s_lwr); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_o1); + Py_VISIT(traverse_module_state->__pyx_n_s_o2); + Py_VISIT(traverse_module_state->__pyx_n_s_o2_o1); + Py_VISIT(traverse_module_state->__pyx_n_s_p1); + Py_VISIT(traverse_module_state->__pyx_n_s_p2); + Py_VISIT(traverse_module_state->__pyx_n_s_point); + Py_VISIT(traverse_module_state->__pyx_n_s_polygon); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_ray1); + Py_VISIT(traverse_module_state->__pyx_n_s_ray2); + Py_VISIT(traverse_module_state->__pyx_n_s_res); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_s); + Py_VISIT(traverse_module_state->__pyx_n_s_s1); + Py_VISIT(traverse_module_state->__pyx_n_s_s1x); + Py_VISIT(traverse_module_state->__pyx_n_s_s1y); + Py_VISIT(traverse_module_state->__pyx_n_s_s2); + Py_VISIT(traverse_module_state->__pyx_n_s_s2x); + Py_VISIT(traverse_module_state->__pyx_n_s_s2y); + Py_VISIT(traverse_module_state->__pyx_n_s_size); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_construct_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start); + Py_VISIT(traverse_module_state->__pyx_n_s_t); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_tol); + Py_VISIT(traverse_module_state->__pyx_kp_s_tuple_Vec3_Vec3); + Py_VISIT(traverse_module_state->__pyx_kp_s_tuple_float_float); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_uc); + Py_VISIT(traverse_module_state->__pyx_n_s_upr); + Py_VISIT(traverse_module_state->__pyx_n_s_us); + Py_VISIT(traverse_module_state->__pyx_n_s_v); + Py_VISIT(traverse_module_state->__pyx_n_s_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_vertices_2); + Py_VISIT(traverse_module_state->__pyx_n_s_virtual); + Py_VISIT(traverse_module_state->__pyx_n_s_world_mercator_to_gps); + Py_VISIT(traverse_module_state->__pyx_n_s_x); + Py_VISIT(traverse_module_state->__pyx_n_s_x1); + Py_VISIT(traverse_module_state->__pyx_n_s_x2); + Py_VISIT(traverse_module_state->__pyx_n_s_y); + Py_VISIT(traverse_module_state->__pyx_n_s_y1); + Py_VISIT(traverse_module_state->__pyx_n_s_y2); + Py_VISIT(traverse_module_state->__pyx_float_0_0); + Py_VISIT(traverse_module_state->__pyx_float_360_0); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_1); + Py_VISIT(traverse_module_state->__pyx_int_neg_1); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__5); + Py_VISIT(traverse_module_state->__pyx_tuple__7); + Py_VISIT(traverse_module_state->__pyx_tuple__9); + Py_VISIT(traverse_module_state->__pyx_tuple__12); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__16); + Py_VISIT(traverse_module_state->__pyx_codeobj__4); + Py_VISIT(traverse_module_state->__pyx_codeobj__6); + Py_VISIT(traverse_module_state->__pyx_codeobj__8); + Py_VISIT(traverse_module_state->__pyx_codeobj__10); + Py_VISIT(traverse_module_state->__pyx_codeobj__11); + Py_VISIT(traverse_module_state->__pyx_codeobj__13); + Py_VISIT(traverse_module_state->__pyx_codeobj__15); + Py_VISIT(traverse_module_state->__pyx_codeobj__17); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_kp_u_At_least_3_vertices_required __pyx_mstate_global->__pyx_kp_u_At_least_3_vertices_required +#define __pyx_n_s_Iterable __pyx_mstate_global->__pyx_n_s_Iterable +#define __pyx_kp_s_Iterable_UVec __pyx_mstate_global->__pyx_kp_s_Iterable_UVec +#define __pyx_n_s_Optional __pyx_mstate_global->__pyx_n_s_Optional +#define __pyx_kp_s_Optional_Vec2 __pyx_mstate_global->__pyx_kp_s_Optional_Vec2 +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_kp_s_Sequence_Vec2 __pyx_mstate_global->__pyx_kp_s_Sequence_Vec2 +#define __pyx_kp_s_Sequence_Vec3 __pyx_mstate_global->__pyx_kp_s_Sequence_Vec3 +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s_Vec2 __pyx_mstate_global->__pyx_n_s_Vec2 +#define __pyx_n_s__18 __pyx_mstate_global->__pyx_n_s__18 +#define __pyx_kp_u__2 __pyx_mstate_global->__pyx_kp_u__2 +#define __pyx_n_s_a __pyx_mstate_global->__pyx_n_s_a +#define __pyx_n_s_abs_tol __pyx_mstate_global->__pyx_n_s_abs_tol +#define __pyx_n_s_arc_angle_span_deg __pyx_mstate_global->__pyx_n_s_arc_angle_span_deg +#define __pyx_n_s_arc_angle_span_rad __pyx_mstate_global->__pyx_n_s_arc_angle_span_rad +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_b __pyx_mstate_global->__pyx_n_s_b +#define __pyx_n_s_bool __pyx_mstate_global->__pyx_n_s_bool +#define __pyx_n_s_c __pyx_mstate_global->__pyx_n_s_c +#define __pyx_n_s_c1 __pyx_mstate_global->__pyx_n_s_c1 +#define __pyx_n_s_c1x __pyx_mstate_global->__pyx_n_s_c1x +#define __pyx_n_s_c1y __pyx_mstate_global->__pyx_n_s_c1y +#define __pyx_n_s_c2 __pyx_mstate_global->__pyx_n_s_c2 +#define __pyx_n_s_c2x __pyx_mstate_global->__pyx_n_s_c2x +#define __pyx_n_s_c2y __pyx_mstate_global->__pyx_n_s_c2y +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_d __pyx_mstate_global->__pyx_n_s_d +#define __pyx_n_s_d1 __pyx_mstate_global->__pyx_n_s_d1 +#define __pyx_n_s_d1xd2 __pyx_mstate_global->__pyx_n_s_d1xd2 +#define __pyx_n_s_d2 __pyx_mstate_global->__pyx_n_s_d2 +#define __pyx_n_s_den __pyx_mstate_global->__pyx_n_s_den +#define __pyx_n_s_denominator __pyx_mstate_global->__pyx_n_s_denominator +#define __pyx_n_s_det1 __pyx_mstate_global->__pyx_n_s_det1 +#define __pyx_n_s_det2 __pyx_mstate_global->__pyx_n_s_det2 +#define __pyx_n_s_e_sin_lat __pyx_mstate_global->__pyx_n_s_e_sin_lat +#define __pyx_n_s_eccentric_2 __pyx_mstate_global->__pyx_n_s_eccentric_2 +#define __pyx_n_s_end __pyx_mstate_global->__pyx_n_s_end +#define __pyx_n_s_ezdxf_acc_construct __pyx_mstate_global->__pyx_n_s_ezdxf_acc_construct +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_n_s_float __pyx_mstate_global->__pyx_n_s_float +#define __pyx_n_s_gps_to_world_mercator __pyx_mstate_global->__pyx_n_s_gps_to_world_mercator +#define __pyx_n_s_has_clockwise_orientation __pyx_mstate_global->__pyx_n_s_has_clockwise_orientation +#define __pyx_n_s_i __pyx_mstate_global->__pyx_n_s_i +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_index __pyx_mstate_global->__pyx_n_s_index +#define __pyx_n_s_inside __pyx_mstate_global->__pyx_n_s_inside +#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int +#define __pyx_n_s_intersection_line_line_2d __pyx_mstate_global->__pyx_n_s_intersection_line_line_2d +#define __pyx_n_s_intersection_ray_ray_3d __pyx_mstate_global->__pyx_n_s_intersection_ray_ray_3d +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_n_s_is_point_in_polygon_2d __pyx_mstate_global->__pyx_n_s_is_point_in_polygon_2d +#define __pyx_n_s_last __pyx_mstate_global->__pyx_n_s_last +#define __pyx_n_s_latitude __pyx_mstate_global->__pyx_n_s_latitude +#define __pyx_n_s_latitude_prev __pyx_mstate_global->__pyx_n_s_latitude_prev +#define __pyx_n_s_line1 __pyx_mstate_global->__pyx_n_s_line1 +#define __pyx_n_s_line2 __pyx_mstate_global->__pyx_n_s_line2 +#define __pyx_kp_s_list_Vec2 __pyx_mstate_global->__pyx_kp_s_list_Vec2 +#define __pyx_n_s_longitude __pyx_mstate_global->__pyx_n_s_longitude +#define __pyx_n_s_lwr __pyx_mstate_global->__pyx_n_s_lwr +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_o1 __pyx_mstate_global->__pyx_n_s_o1 +#define __pyx_n_s_o2 __pyx_mstate_global->__pyx_n_s_o2 +#define __pyx_n_s_o2_o1 __pyx_mstate_global->__pyx_n_s_o2_o1 +#define __pyx_n_s_p1 __pyx_mstate_global->__pyx_n_s_p1 +#define __pyx_n_s_p2 __pyx_mstate_global->__pyx_n_s_p2 +#define __pyx_n_s_point __pyx_mstate_global->__pyx_n_s_point +#define __pyx_n_s_polygon __pyx_mstate_global->__pyx_n_s_polygon +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_ray1 __pyx_mstate_global->__pyx_n_s_ray1 +#define __pyx_n_s_ray2 __pyx_mstate_global->__pyx_n_s_ray2 +#define __pyx_n_s_res __pyx_mstate_global->__pyx_n_s_res +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_s __pyx_mstate_global->__pyx_n_s_s +#define __pyx_n_s_s1 __pyx_mstate_global->__pyx_n_s_s1 +#define __pyx_n_s_s1x __pyx_mstate_global->__pyx_n_s_s1x +#define __pyx_n_s_s1y __pyx_mstate_global->__pyx_n_s_s1y +#define __pyx_n_s_s2 __pyx_mstate_global->__pyx_n_s_s2 +#define __pyx_n_s_s2x __pyx_mstate_global->__pyx_n_s_s2x +#define __pyx_n_s_s2y __pyx_mstate_global->__pyx_n_s_s2y +#define __pyx_n_s_size __pyx_mstate_global->__pyx_n_s_size +#define __pyx_kp_s_src_ezdxf_acc_construct_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_construct_pyx +#define __pyx_n_s_start __pyx_mstate_global->__pyx_n_s_start +#define __pyx_n_s_t __pyx_mstate_global->__pyx_n_s_t +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_tol __pyx_mstate_global->__pyx_n_s_tol +#define __pyx_kp_s_tuple_Vec3_Vec3 __pyx_mstate_global->__pyx_kp_s_tuple_Vec3_Vec3 +#define __pyx_kp_s_tuple_float_float __pyx_mstate_global->__pyx_kp_s_tuple_float_float +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_uc __pyx_mstate_global->__pyx_n_s_uc +#define __pyx_n_s_upr __pyx_mstate_global->__pyx_n_s_upr +#define __pyx_n_s_us __pyx_mstate_global->__pyx_n_s_us +#define __pyx_n_s_v __pyx_mstate_global->__pyx_n_s_v +#define __pyx_n_s_vertices __pyx_mstate_global->__pyx_n_s_vertices +#define __pyx_n_s_vertices_2 __pyx_mstate_global->__pyx_n_s_vertices_2 +#define __pyx_n_s_virtual __pyx_mstate_global->__pyx_n_s_virtual +#define __pyx_n_s_world_mercator_to_gps __pyx_mstate_global->__pyx_n_s_world_mercator_to_gps +#define __pyx_n_s_x __pyx_mstate_global->__pyx_n_s_x +#define __pyx_n_s_x1 __pyx_mstate_global->__pyx_n_s_x1 +#define __pyx_n_s_x2 __pyx_mstate_global->__pyx_n_s_x2 +#define __pyx_n_s_y __pyx_mstate_global->__pyx_n_s_y +#define __pyx_n_s_y1 __pyx_mstate_global->__pyx_n_s_y1 +#define __pyx_n_s_y2 __pyx_mstate_global->__pyx_n_s_y2 +#define __pyx_float_0_0 __pyx_mstate_global->__pyx_float_0_0 +#define __pyx_float_360_0 __pyx_mstate_global->__pyx_float_360_0 +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_1 __pyx_mstate_global->__pyx_int_1 +#define __pyx_int_neg_1 __pyx_mstate_global->__pyx_int_neg_1 +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__5 __pyx_mstate_global->__pyx_tuple__5 +#define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7 +#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9 +#define __pyx_tuple__12 __pyx_mstate_global->__pyx_tuple__12 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__16 __pyx_mstate_global->__pyx_tuple__16 +#define __pyx_codeobj__4 __pyx_mstate_global->__pyx_codeobj__4 +#define __pyx_codeobj__6 __pyx_mstate_global->__pyx_codeobj__6 +#define __pyx_codeobj__8 __pyx_mstate_global->__pyx_codeobj__8 +#define __pyx_codeobj__10 __pyx_mstate_global->__pyx_codeobj__10 +#define __pyx_codeobj__11 __pyx_mstate_global->__pyx_codeobj__11 +#define __pyx_codeobj__13 __pyx_mstate_global->__pyx_codeobj__13 +#define __pyx_codeobj__15 __pyx_mstate_global->__pyx_codeobj__15 +#define __pyx_codeobj__17 __pyx_mstate_global->__pyx_codeobj__17 +/* #### Code section: module_code ### */ + +/* "ezdxf/acc/construct.pyx":34 + * cdef double TOLERANCE = 1e-10 + * + * def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_1has_clockwise_orientation(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_has_clockwise_orientation, " Returns True if 2D `vertices` have clockwise orientation. Ignores\n z-axis of all vertices.\n\n Args:\n vertices: iterable of :class:`Vec2` compatible objects\n\n Raises:\n ValueError: less than 3 vertices\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_1has_clockwise_orientation = {"has_clockwise_orientation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_1has_clockwise_orientation, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_has_clockwise_orientation}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_1has_clockwise_orientation(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vertices = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("has_clockwise_orientation (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vertices,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vertices)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 34, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "has_clockwise_orientation") < 0)) __PYX_ERR(0, 34, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_vertices = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("has_clockwise_orientation", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 34, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.has_clockwise_orientation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_has_clockwise_orientation(__pyx_self, __pyx_v_vertices); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_has_clockwise_orientation(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_vertices) { + PyObject *__pyx_v__vertices = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_p1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_p2 = 0; + double __pyx_v_s; + Py_ssize_t __pyx_v_index; + PyObject *__pyx_7genexpr__pyx_v_v = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + int __pyx_t_7; + int __pyx_t_8; + Py_ssize_t __pyx_t_9; + Py_ssize_t __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("has_clockwise_orientation", 1); + + /* "ezdxf/acc/construct.pyx":45 + * + * """ + * cdef list _vertices = [Vec2(v) for v in vertices] # <<<<<<<<<<<<<< + * if len(_vertices) < 3: + * raise ValueError('At least 3 vertices required.') + */ + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(PyList_CheckExact(__pyx_v_vertices)) || PyTuple_CheckExact(__pyx_v_vertices)) { + __pyx_t_2 = __pyx_v_vertices; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_vertices); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 45, __pyx_L5_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 45, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 45, __pyx_L5_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 45, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 45, __pyx_L5_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 45, __pyx_L5_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_5); + } + __Pyx_XDECREF_SET(__pyx_7genexpr__pyx_v_v, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_7genexpr__pyx_v_v); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_5); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(0, 45, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_v); __pyx_7genexpr__pyx_v_v = 0; + goto __pyx_L9_exit_scope; + __pyx_L5_error:; + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_v); __pyx_7genexpr__pyx_v_v = 0; + goto __pyx_L1_error; + __pyx_L9_exit_scope:; + } /* exit inner scope */ + __pyx_v__vertices = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":46 + * """ + * cdef list _vertices = [Vec2(v) for v in vertices] + * if len(_vertices) < 3: # <<<<<<<<<<<<<< + * raise ValueError('At least 3 vertices required.') + * + */ + __pyx_t_3 = __Pyx_PyList_GET_SIZE(__pyx_v__vertices); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(0, 46, __pyx_L1_error) + __pyx_t_6 = (__pyx_t_3 < 3); + if (unlikely(__pyx_t_6)) { + + /* "ezdxf/acc/construct.pyx":47 + * cdef list _vertices = [Vec2(v) for v in vertices] + * if len(_vertices) < 3: + * raise ValueError('At least 3 vertices required.') # <<<<<<<<<<<<<< + * + * cdef Vec2 p1 = _vertices[0] + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 47, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":46 + * """ + * cdef list _vertices = [Vec2(v) for v in vertices] + * if len(_vertices) < 3: # <<<<<<<<<<<<<< + * raise ValueError('At least 3 vertices required.') + * + */ + } + + /* "ezdxf/acc/construct.pyx":49 + * raise ValueError('At least 3 vertices required.') + * + * cdef Vec2 p1 = _vertices[0] # <<<<<<<<<<<<<< + * cdef Vec2 p2 = _vertices[-1] + * cdef double s = 0.0 + */ + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v__vertices, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_p1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":50 + * + * cdef Vec2 p1 = _vertices[0] + * cdef Vec2 p2 = _vertices[-1] # <<<<<<<<<<<<<< + * cdef double s = 0.0 + * cdef Py_ssize_t index + */ + __pyx_t_2 = __Pyx_GetItemInt_List(__pyx_v__vertices, -1L, long, 1, __Pyx_PyInt_From_long, 1, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_p2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":51 + * cdef Vec2 p1 = _vertices[0] + * cdef Vec2 p2 = _vertices[-1] + * cdef double s = 0.0 # <<<<<<<<<<<<<< + * cdef Py_ssize_t index + * + */ + __pyx_v_s = 0.0; + + /* "ezdxf/acc/construct.pyx":55 + * + * # Using the same tolerance as the Python implementation: + * if not v2_isclose(p1, p2, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * _vertices.append(p1) + * + */ + __pyx_t_6 = __pyx_f_5ezdxf_3acc_6vector_v2_isclose(__pyx_v_p1, __pyx_v_p2, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 55, __pyx_L1_error) + __pyx_t_7 = (!__pyx_t_6); + if (__pyx_t_7) { + + /* "ezdxf/acc/construct.pyx":56 + * # Using the same tolerance as the Python implementation: + * if not v2_isclose(p1, p2, REL_TOL, ABS_TOL): + * _vertices.append(p1) # <<<<<<<<<<<<<< + * + * for index in range(1, len(_vertices)): + */ + __pyx_t_8 = __Pyx_PyList_Append(__pyx_v__vertices, ((PyObject *)__pyx_v_p1)); if (unlikely(__pyx_t_8 == ((int)-1))) __PYX_ERR(0, 56, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":55 + * + * # Using the same tolerance as the Python implementation: + * if not v2_isclose(p1, p2, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * _vertices.append(p1) + * + */ + } + + /* "ezdxf/acc/construct.pyx":58 + * _vertices.append(p1) + * + * for index in range(1, len(_vertices)): # <<<<<<<<<<<<<< + * p2 = _vertices[index] + * s += (p2.x - p1.x) * (p2.y + p1.y) + */ + __pyx_t_3 = __Pyx_PyList_GET_SIZE(__pyx_v__vertices); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(0, 58, __pyx_L1_error) + __pyx_t_9 = __pyx_t_3; + for (__pyx_t_10 = 1; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) { + __pyx_v_index = __pyx_t_10; + + /* "ezdxf/acc/construct.pyx":59 + * + * for index in range(1, len(_vertices)): + * p2 = _vertices[index] # <<<<<<<<<<<<<< + * s += (p2.x - p1.x) * (p2.y + p1.y) + * p1 = p2 + */ + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v__vertices, __pyx_v_index, Py_ssize_t, 1, PyInt_FromSsize_t, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_p2, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2)); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":60 + * for index in range(1, len(_vertices)): + * p2 = _vertices[index] + * s += (p2.x - p1.x) * (p2.y + p1.y) # <<<<<<<<<<<<<< + * p1 = p2 + * return s > 0.0 + */ + __pyx_v_s = (__pyx_v_s + ((__pyx_v_p2->x - __pyx_v_p1->x) * (__pyx_v_p2->y + __pyx_v_p1->y))); + + /* "ezdxf/acc/construct.pyx":61 + * p2 = _vertices[index] + * s += (p2.x - p1.x) * (p2.y + p1.y) + * p1 = p2 # <<<<<<<<<<<<<< + * return s > 0.0 + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_p2); + __Pyx_DECREF_SET(__pyx_v_p1, __pyx_v_p2); + } + + /* "ezdxf/acc/construct.pyx":62 + * s += (p2.x - p1.x) * (p2.y + p1.y) + * p1 = p2 + * return s > 0.0 # <<<<<<<<<<<<<< + * + * def intersection_line_line_2d( + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyBool_FromLong((__pyx_v_s > 0.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":34 + * cdef double TOLERANCE = 1e-10 + * + * def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.construct.has_clockwise_orientation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v__vertices); + __Pyx_XDECREF((PyObject *)__pyx_v_p1); + __Pyx_XDECREF((PyObject *)__pyx_v_p2); + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_v); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":64 + * return s > 0.0 + * + * def intersection_line_line_2d( # <<<<<<<<<<<<<< + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_16__defaults__(CYTHON_UNUSED PyObject *__pyx_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__defaults__", 1); + __Pyx_XDECREF(__pyx_r); + + /* "ezdxf/acc/construct.pyx":67 + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + * bint virtual=True, # <<<<<<<<<<<<<< + * double abs_tol=TOLERANCE) -> Optional[Vec2]: + * """ + */ + __pyx_t_1 = __Pyx_PyBool_FromLong(((int)1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "ezdxf/acc/construct.pyx":64 + * return s > 0.0 + * + * def intersection_line_line_2d( # <<<<<<<<<<<<<< + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + */ + __pyx_t_2 = PyFloat_FromDouble(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_abs_tol); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3)) __PYX_ERR(0, 64, __pyx_L1_error); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, Py_None)) __PYX_ERR(0, 64, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.construct.__defaults__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_9construct_3intersection_line_line_2d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_2intersection_line_line_2d, "\n Compute the intersection of two lines in the xy-plane.\n\n Args:\n line1: start- and end point of first line to test\n e.g. ((x1, y1), (x2, y2)).\n line2: start- and end point of second line to test\n e.g. ((x3, y3), (x4, y4)).\n virtual: ``True`` returns any intersection point, ``False`` returns\n only real intersection points.\n abs_tol: tolerance for intersection test.\n\n Returns:\n ``None`` if there is no intersection point (parallel lines) or\n intersection point as :class:`Vec2`\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_3intersection_line_line_2d = {"intersection_line_line_2d", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_3intersection_line_line_2d, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_2intersection_line_line_2d}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_9construct_3intersection_line_line_2d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_line1 = 0; + PyObject *__pyx_v_line2 = 0; + int __pyx_v_virtual; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("intersection_line_line_2d (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_line1,&__pyx_n_s_line2,&__pyx_n_s_virtual,&__pyx_n_s_abs_tol,0}; + __pyx_defaults *__pyx_dynamic_args = __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_line1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 64, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_line2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 64, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("intersection_line_line_2d", 0, 2, 4, 1); __PYX_ERR(0, 64, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_virtual); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 64, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_abs_tol); + if (value) { values[3] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 64, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "intersection_line_line_2d") < 0)) __PYX_ERR(0, 64, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_line1 = values[0]; + __pyx_v_line2 = values[1]; + if (values[2]) { + __pyx_v_virtual = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_virtual == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 67, __pyx_L3_error) + } else { + __pyx_v_virtual = ((int)((int)1)); + } + if (values[3]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_dynamic_args->__pyx_arg_abs_tol; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("intersection_line_line_2d", 0, 2, 4, __pyx_nargs); __PYX_ERR(0, 64, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.intersection_line_line_2d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_2intersection_line_line_2d(__pyx_self, __pyx_v_line1, __pyx_v_line2, __pyx_v_virtual, __pyx_v_abs_tol); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_9construct_2intersection_line_line_2d(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_line1, PyObject *__pyx_v_line2, int __pyx_v_virtual, double __pyx_v_abs_tol) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_s1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_s2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_c1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_c2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + double __pyx_v_s1x; + double __pyx_v_s1y; + double __pyx_v_s2x; + double __pyx_v_s2y; + double __pyx_v_c1x; + double __pyx_v_c1y; + double __pyx_v_c2x; + double __pyx_v_c2y; + double __pyx_v_den; + double __pyx_v_us; + double __pyx_v_uc; + double __pyx_v_lwr; + double __pyx_v_upr; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("intersection_line_line_2d", 1); + + /* "ezdxf/acc/construct.pyx":90 + * cdef Vec2 s1, s2, c1, c2, res + * cdef double s1x, s1y, s2x, s2y, c1x, c1y, c2x, c2y, den, us, uc + * cdef double lwr = 0.0, upr = 1.0 # <<<<<<<<<<<<<< + * + * s1 = line1[0] + */ + __pyx_v_lwr = 0.0; + __pyx_v_upr = 1.0; + + /* "ezdxf/acc/construct.pyx":92 + * cdef double lwr = 0.0, upr = 1.0 + * + * s1 = line1[0] # <<<<<<<<<<<<<< + * s2 = line1[1] + * c1 = line2[0] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_line1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_v_s1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":93 + * + * s1 = line1[0] + * s2 = line1[1] # <<<<<<<<<<<<<< + * c1 = line2[0] + * c2 = line2[1] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_line1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 93, __pyx_L1_error) + __pyx_v_s2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":94 + * s1 = line1[0] + * s2 = line1[1] + * c1 = line2[0] # <<<<<<<<<<<<<< + * c2 = line2[1] + * + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_line2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 94, __pyx_L1_error) + __pyx_v_c1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":95 + * s2 = line1[1] + * c1 = line2[0] + * c2 = line2[1] # <<<<<<<<<<<<<< + * + * s1x = s1.x + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_line2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 95, __pyx_L1_error) + __pyx_v_c2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":97 + * c2 = line2[1] + * + * s1x = s1.x # <<<<<<<<<<<<<< + * s1y = s1.y + * s2x = s2.x + */ + __pyx_t_2 = __pyx_v_s1->x; + __pyx_v_s1x = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":98 + * + * s1x = s1.x + * s1y = s1.y # <<<<<<<<<<<<<< + * s2x = s2.x + * s2y = s2.y + */ + __pyx_t_2 = __pyx_v_s1->y; + __pyx_v_s1y = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":99 + * s1x = s1.x + * s1y = s1.y + * s2x = s2.x # <<<<<<<<<<<<<< + * s2y = s2.y + * c1x = c1.x + */ + __pyx_t_2 = __pyx_v_s2->x; + __pyx_v_s2x = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":100 + * s1y = s1.y + * s2x = s2.x + * s2y = s2.y # <<<<<<<<<<<<<< + * c1x = c1.x + * c1y = c1.y + */ + __pyx_t_2 = __pyx_v_s2->y; + __pyx_v_s2y = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":101 + * s2x = s2.x + * s2y = s2.y + * c1x = c1.x # <<<<<<<<<<<<<< + * c1y = c1.y + * c2x = c2.x + */ + __pyx_t_2 = __pyx_v_c1->x; + __pyx_v_c1x = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":102 + * s2y = s2.y + * c1x = c1.x + * c1y = c1.y # <<<<<<<<<<<<<< + * c2x = c2.x + * c2y = c2.y + */ + __pyx_t_2 = __pyx_v_c1->y; + __pyx_v_c1y = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":103 + * c1x = c1.x + * c1y = c1.y + * c2x = c2.x # <<<<<<<<<<<<<< + * c2y = c2.y + * + */ + __pyx_t_2 = __pyx_v_c2->x; + __pyx_v_c2x = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":104 + * c1y = c1.y + * c2x = c2.x + * c2y = c2.y # <<<<<<<<<<<<<< + * + * den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) + */ + __pyx_t_2 = __pyx_v_c2->y; + __pyx_v_c2y = __pyx_t_2; + + /* "ezdxf/acc/construct.pyx":106 + * c2y = c2.y + * + * den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) # <<<<<<<<<<<<<< + * + * if fabs(den) <= abs_tol: + */ + __pyx_v_den = (((__pyx_v_c2y - __pyx_v_c1y) * (__pyx_v_s2x - __pyx_v_s1x)) - ((__pyx_v_c2x - __pyx_v_c1x) * (__pyx_v_s2y - __pyx_v_s1y))); + + /* "ezdxf/acc/construct.pyx":108 + * den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) + * + * if fabs(den) <= abs_tol: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_3 = (fabs(__pyx_v_den) <= __pyx_v_abs_tol); + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":109 + * + * if fabs(den) <= abs_tol: + * return None # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)Py_None); __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":108 + * den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) + * + * if fabs(den) <= abs_tol: # <<<<<<<<<<<<<< + * return None + * + */ + } + + /* "ezdxf/acc/construct.pyx":114 + * # den near zero is checked by if-statement above: + * with cython.cdivision(True): + * us = ((c2x - c1x) * (s1y - c1y) - (c2y - c1y) * (s1x - c1x)) / den # <<<<<<<<<<<<<< + * + * res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + */ + __pyx_v_us = ((((__pyx_v_c2x - __pyx_v_c1x) * (__pyx_v_s1y - __pyx_v_c1y)) - ((__pyx_v_c2y - __pyx_v_c1y) * (__pyx_v_s1x - __pyx_v_c1x))) / __pyx_v_den); + + /* "ezdxf/acc/construct.pyx":116 + * us = ((c2x - c1x) * (s1y - c1y) - (c2y - c1y) * (s1x - c1x)) / den + * + * res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) # <<<<<<<<<<<<<< + * if virtual: + * return res + */ + __pyx_t_1 = PyFloat_FromDouble((__pyx_v_s1x + (__pyx_v_us * (__pyx_v_s2x - __pyx_v_s1x)))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_s1y + (__pyx_v_us * (__pyx_v_s2y - __pyx_v_s1y)))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/construct.pyx":117 + * + * res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + * if virtual: # <<<<<<<<<<<<<< + * return res + * + */ + if (__pyx_v_virtual) { + + /* "ezdxf/acc/construct.pyx":118 + * res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + * if virtual: + * return res # <<<<<<<<<<<<<< + * + * # 0 = intersection point is the start point of the line + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":117 + * + * res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + * if virtual: # <<<<<<<<<<<<<< + * return res + * + */ + } + + /* "ezdxf/acc/construct.pyx":123 + * # 1 = intersection point is the end point of the line + * # otherwise: linear interpolation + * if lwr <= us <= upr: # intersection point is on the subject line # <<<<<<<<<<<<<< + * with cython.cdivision(True): + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + */ + __pyx_t_3 = (__pyx_v_lwr <= __pyx_v_us); + if (__pyx_t_3) { + __pyx_t_3 = (__pyx_v_us <= __pyx_v_upr); + } + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":125 + * if lwr <= us <= upr: # intersection point is on the subject line + * with cython.cdivision(True): + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den # <<<<<<<<<<<<<< + * if lwr <= uc <= upr: # intersection point is on the clipping line + * return res + */ + __pyx_v_uc = ((((__pyx_v_s2x - __pyx_v_s1x) * (__pyx_v_s1y - __pyx_v_c1y)) - ((__pyx_v_s2y - __pyx_v_s1y) * (__pyx_v_s1x - __pyx_v_c1x))) / __pyx_v_den); + + /* "ezdxf/acc/construct.pyx":126 + * with cython.cdivision(True): + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + * if lwr <= uc <= upr: # intersection point is on the clipping line # <<<<<<<<<<<<<< + * return res + * return None + */ + __pyx_t_3 = (__pyx_v_lwr <= __pyx_v_uc); + if (__pyx_t_3) { + __pyx_t_3 = (__pyx_v_uc <= __pyx_v_upr); + } + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":127 + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + * if lwr <= uc <= upr: # intersection point is on the clipping line + * return res # <<<<<<<<<<<<<< + * return None + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":126 + * with cython.cdivision(True): + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + * if lwr <= uc <= upr: # intersection point is on the clipping line # <<<<<<<<<<<<<< + * return res + * return None + */ + } + + /* "ezdxf/acc/construct.pyx":123 + * # 1 = intersection point is the end point of the line + * # otherwise: linear interpolation + * if lwr <= us <= upr: # intersection point is on the subject line # <<<<<<<<<<<<<< + * with cython.cdivision(True): + * uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + */ + } + + /* "ezdxf/acc/construct.pyx":128 + * if lwr <= uc <= upr: # intersection point is on the clipping line + * return res + * return None # <<<<<<<<<<<<<< + * + * cdef double _determinant(Vec3 v1, Vec3 v2, Vec3 v3): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)Py_None); __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":64 + * return s > 0.0 + * + * def intersection_line_line_2d( # <<<<<<<<<<<<<< + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.construct.intersection_line_line_2d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_s1); + __Pyx_XDECREF((PyObject *)__pyx_v_s2); + __Pyx_XDECREF((PyObject *)__pyx_v_c1); + __Pyx_XDECREF((PyObject *)__pyx_v_c2); + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":130 + * return None + * + * cdef double _determinant(Vec3 v1, Vec3 v2, Vec3 v3): # <<<<<<<<<<<<<< + * return v1.x * v2.y * v3.z + v1.y * v2.z * v3.x + \ + * v1.z * v2.x * v3.y - v1.z * v2.y * v3.x - \ + */ + +static double __pyx_f_5ezdxf_3acc_9construct__determinant(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v1, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v2, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v3) { + double __pyx_r; + + /* "ezdxf/acc/construct.pyx":133 + * return v1.x * v2.y * v3.z + v1.y * v2.z * v3.x + \ + * v1.z * v2.x * v3.y - v1.z * v2.y * v3.x - \ + * v1.x * v2.z * v3.y - v1.y * v2.x * v3.z # <<<<<<<<<<<<<< + * + * def intersection_ray_ray_3d( + */ + __pyx_r = (((((((__pyx_v_v1->x * __pyx_v_v2->y) * __pyx_v_v3->z) + ((__pyx_v_v1->y * __pyx_v_v2->z) * __pyx_v_v3->x)) + ((__pyx_v_v1->z * __pyx_v_v2->x) * __pyx_v_v3->y)) - ((__pyx_v_v1->z * __pyx_v_v2->y) * __pyx_v_v3->x)) - ((__pyx_v_v1->x * __pyx_v_v2->z) * __pyx_v_v3->y)) - ((__pyx_v_v1->y * __pyx_v_v2->x) * __pyx_v_v3->z)); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":130 + * return None + * + * cdef double _determinant(Vec3 v1, Vec3 v2, Vec3 v3): # <<<<<<<<<<<<<< + * return v1.x * v2.y * v3.z + v1.y * v2.z * v3.x + \ + * v1.z * v2.x * v3.y - v1.z * v2.y * v3.x - \ + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":135 + * v1.x * v2.z * v3.y - v1.y * v2.x * v3.z + * + * def intersection_ray_ray_3d( # <<<<<<<<<<<<<< + * ray1: tuple[Vec3, Vec3], + * ray2: tuple[Vec3, Vec3], + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_18__defaults__(CYTHON_UNUSED PyObject *__pyx_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__defaults__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self)->__pyx_arg_abs_tol); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 135, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, Py_None)) __PYX_ERR(0, 135, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.construct.__defaults__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_5intersection_ray_ray_3d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_4intersection_ray_ray_3d, "\n Calculate intersection of two 3D rays, returns a 0-tuple for parallel rays,\n a 1-tuple for intersecting rays and a 2-tuple for not intersecting and not\n parallel rays with points of closest approach on each ray.\n\n Args:\n ray1: first ray as tuple of two points as Vec3() objects\n ray2: second ray as tuple of two points as Vec3() objects\n abs_tol: absolute tolerance for comparisons\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_5intersection_ray_ray_3d = {"intersection_ray_ray_3d", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_5intersection_ray_ray_3d, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_4intersection_ray_ray_3d}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_5intersection_ray_ray_3d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ray1 = 0; + PyObject *__pyx_v_ray2 = 0; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("intersection_ray_ray_3d (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ray1,&__pyx_n_s_ray2,&__pyx_n_s_abs_tol,0}; + __pyx_defaults1 *__pyx_dynamic_args = __Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_self); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ray1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ray2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("intersection_ray_ray_3d", 0, 2, 3, 1); __PYX_ERR(0, 135, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_abs_tol); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "intersection_ray_ray_3d") < 0)) __PYX_ERR(0, 135, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ray1 = ((PyObject*)values[0]); + __pyx_v_ray2 = ((PyObject*)values[1]); + if (values[2]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_dynamic_args->__pyx_arg_abs_tol; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("intersection_ray_ray_3d", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 135, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.intersection_ray_ray_3d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ray1), (&PyTuple_Type), 0, "ray1", 1))) __PYX_ERR(0, 136, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ray2), (&PyTuple_Type), 0, "ray2", 1))) __PYX_ERR(0, 137, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_4intersection_ray_ray_3d(__pyx_self, __pyx_v_ray1, __pyx_v_ray2, __pyx_v_abs_tol); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_4intersection_ray_ray_3d(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_ray1, PyObject *__pyx_v_ray2, double __pyx_v_abs_tol) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o2_o1 = 0; + double __pyx_v_det1; + double __pyx_v_det2; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_p2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_d1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_d2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_d1xd2 = 0; + double __pyx_v_denominator; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("intersection_ray_ray_3d", 1); + + /* "ezdxf/acc/construct.pyx":155 + * Vec3 o2_o1 + * double det1, det2 + * Vec3 o1 = Vec3(ray1[0]) # <<<<<<<<<<<<<< + * Vec3 p1 = Vec3(ray1[1]) + * Vec3 o2 = Vec3(ray2[0]) + */ + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_ray1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_o1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":156 + * double det1, det2 + * Vec3 o1 = Vec3(ray1[0]) + * Vec3 p1 = Vec3(ray1[1]) # <<<<<<<<<<<<<< + * Vec3 o2 = Vec3(ray2[0]) + * Vec3 p2 = Vec3(ray2[1]) + */ + __pyx_t_2 = __Pyx_GetItemInt_Tuple(__pyx_v_ray1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_p1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":157 + * Vec3 o1 = Vec3(ray1[0]) + * Vec3 p1 = Vec3(ray1[1]) + * Vec3 o2 = Vec3(ray2[0]) # <<<<<<<<<<<<<< + * Vec3 p2 = Vec3(ray2[1]) + * Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) + */ + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_ray2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_o2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":158 + * Vec3 p1 = Vec3(ray1[1]) + * Vec3 o2 = Vec3(ray2[0]) + * Vec3 p2 = Vec3(ray2[1]) # <<<<<<<<<<<<<< + * Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) + * Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) + */ + __pyx_t_2 = __Pyx_GetItemInt_Tuple(__pyx_v_ray2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_p2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":159 + * Vec3 o2 = Vec3(ray2[0]) + * Vec3 p2 = Vec3(ray2[1]) + * Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) # <<<<<<<<<<<<<< + * Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) + * Vec3 d1xd2 = v3_cross(d1, d2) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_v_p1, __pyx_v_o1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_d1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":160 + * Vec3 p2 = Vec3(ray2[1]) + * Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) + * Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) # <<<<<<<<<<<<<< + * Vec3 d1xd2 = v3_cross(d1, d2) + * double denominator = v3_magnitude_sqr(d1xd2) + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_v_p2, __pyx_v_o2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2), 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_d2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":161 + * Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) + * Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) + * Vec3 d1xd2 = v3_cross(d1, d2) # <<<<<<<<<<<<<< + * double denominator = v3_magnitude_sqr(d1xd2) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_cross(__pyx_v_d1, __pyx_v_d2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_d1xd2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":162 + * Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) + * Vec3 d1xd2 = v3_cross(d1, d2) + * double denominator = v3_magnitude_sqr(d1xd2) # <<<<<<<<<<<<<< + * + * if denominator <= abs_tol: + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr(__pyx_v_d1xd2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 162, __pyx_L1_error) + __pyx_v_denominator = __pyx_t_3; + + /* "ezdxf/acc/construct.pyx":164 + * double denominator = v3_magnitude_sqr(d1xd2) + * + * if denominator <= abs_tol: # <<<<<<<<<<<<<< + * # ray1 is parallel to ray2 + * return tuple() + */ + __pyx_t_4 = (__pyx_v_denominator <= __pyx_v_abs_tol); + if (__pyx_t_4) { + + /* "ezdxf/acc/construct.pyx":166 + * if denominator <= abs_tol: + * # ray1 is parallel to ray2 + * return tuple() # <<<<<<<<<<<<<< + * else: + * o2_o1 = v3_sub(o2, o1) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)(&PyTuple_Type))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":164 + * double denominator = v3_magnitude_sqr(d1xd2) + * + * if denominator <= abs_tol: # <<<<<<<<<<<<<< + * # ray1 is parallel to ray2 + * return tuple() + */ + } + + /* "ezdxf/acc/construct.pyx":168 + * return tuple() + * else: + * o2_o1 = v3_sub(o2, o1) # <<<<<<<<<<<<<< + * det1 = _determinant(o2_o1, d2, d1xd2) + * det2 = _determinant(o2_o1, d1, d1xd2) + */ + /*else*/ { + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_v_o2, __pyx_v_o1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 168, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o2_o1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":169 + * else: + * o2_o1 = v3_sub(o2, o1) + * det1 = _determinant(o2_o1, d2, d1xd2) # <<<<<<<<<<<<<< + * det2 = _determinant(o2_o1, d1, d1xd2) + * with cython.cdivision(True): # denominator check is already done + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_9construct__determinant(__pyx_v_o2_o1, __pyx_v_d2, __pyx_v_d1xd2); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 169, __pyx_L1_error) + __pyx_v_det1 = __pyx_t_3; + + /* "ezdxf/acc/construct.pyx":170 + * o2_o1 = v3_sub(o2, o1) + * det1 = _determinant(o2_o1, d2, d1xd2) + * det2 = _determinant(o2_o1, d1, d1xd2) # <<<<<<<<<<<<<< + * with cython.cdivision(True): # denominator check is already done + * p1 = v3_add(o1, v3_mul(d1, (det1 / denominator))) + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_9construct__determinant(__pyx_v_o2_o1, __pyx_v_d1, __pyx_v_d1xd2); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 170, __pyx_L1_error) + __pyx_v_det2 = __pyx_t_3; + + /* "ezdxf/acc/construct.pyx":172 + * det2 = _determinant(o2_o1, d1, d1xd2) + * with cython.cdivision(True): # denominator check is already done + * p1 = v3_add(o1, v3_mul(d1, (det1 / denominator))) # <<<<<<<<<<<<<< + * p2 = v3_add(o2, v3_mul(d2, (det2 / denominator))) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_v_d1, (__pyx_v_det1 / __pyx_v_denominator))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(__pyx_v_o1, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_p1, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); + __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":173 + * with cython.cdivision(True): # denominator check is already done + * p1 = v3_add(o1, v3_mul(d1, (det1 / denominator))) + * p2 = v3_add(o2, v3_mul(d2, (det2 / denominator))) # <<<<<<<<<<<<<< + * + * if v3_isclose(p1, p2, abs_tol, abs_tol): + */ + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_v_d2, (__pyx_v_det2 / __pyx_v_denominator))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(__pyx_v_o2, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF_SET(__pyx_v_p2, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/construct.pyx":175 + * p2 = v3_add(o2, v3_mul(d2, (det2 / denominator))) + * + * if v3_isclose(p1, p2, abs_tol, abs_tol): # <<<<<<<<<<<<<< + * # ray1 and ray2 have an intersection point + * return p1, + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_v_p1, __pyx_v_p2, __pyx_v_abs_tol, __pyx_v_abs_tol); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 175, __pyx_L1_error) + if (__pyx_t_4) { + + /* "ezdxf/acc/construct.pyx":177 + * if v3_isclose(p1, p2, abs_tol, abs_tol): + * # ray1 and ray2 have an intersection point + * return p1, # <<<<<<<<<<<<<< + * else: + * # ray1 and ray2 do not have an intersection point, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_p1); + __Pyx_GIVEREF((PyObject *)__pyx_v_p1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_p1))) __PYX_ERR(0, 177, __pyx_L1_error); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":175 + * p2 = v3_add(o2, v3_mul(d2, (det2 / denominator))) + * + * if v3_isclose(p1, p2, abs_tol, abs_tol): # <<<<<<<<<<<<<< + * # ray1 and ray2 have an intersection point + * return p1, + */ + } + + /* "ezdxf/acc/construct.pyx":181 + * # ray1 and ray2 do not have an intersection point, + * # p1 and p2 are the points of closest approach on each ray + * return p1, p2 # <<<<<<<<<<<<<< + * + * def arc_angle_span_deg(double start, double end) -> float: + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_v_p1); + __Pyx_GIVEREF((PyObject *)__pyx_v_p1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_p1))) __PYX_ERR(0, 181, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_v_p2); + __Pyx_GIVEREF((PyObject *)__pyx_v_p2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_p2))) __PYX_ERR(0, 181, __pyx_L1_error); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + } + } + + /* "ezdxf/acc/construct.pyx":135 + * v1.x * v2.z * v3.y - v1.y * v2.x * v3.z + * + * def intersection_ray_ray_3d( # <<<<<<<<<<<<<< + * ray1: tuple[Vec3, Vec3], + * ray2: tuple[Vec3, Vec3], + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.construct.intersection_ray_ray_3d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o2_o1); + __Pyx_XDECREF((PyObject *)__pyx_v_o1); + __Pyx_XDECREF((PyObject *)__pyx_v_p1); + __Pyx_XDECREF((PyObject *)__pyx_v_o2); + __Pyx_XDECREF((PyObject *)__pyx_v_p2); + __Pyx_XDECREF((PyObject *)__pyx_v_d1); + __Pyx_XDECREF((PyObject *)__pyx_v_d2); + __Pyx_XDECREF((PyObject *)__pyx_v_d1xd2); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":183 + * return p1, p2 + * + * def arc_angle_span_deg(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): + * return 0.0 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_7arc_angle_span_deg(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_7arc_angle_span_deg = {"arc_angle_span_deg", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_7arc_angle_span_deg, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_7arc_angle_span_deg(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_start; + double __pyx_v_end; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("arc_angle_span_deg (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_start,&__pyx_n_s_end,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_start)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_end)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("arc_angle_span_deg", 1, 2, 2, 1); __PYX_ERR(0, 183, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "arc_angle_span_deg") < 0)) __PYX_ERR(0, 183, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_start = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_start == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L3_error) + __pyx_v_end = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_end == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("arc_angle_span_deg", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 183, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.arc_angle_span_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_6arc_angle_span_deg(__pyx_self, __pyx_v_start, __pyx_v_end); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_6arc_angle_span_deg(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start, double __pyx_v_end) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("arc_angle_span_deg", 1); + + /* "ezdxf/acc/construct.pyx":184 + * + * def arc_angle_span_deg(double start, double end) -> float: + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * return 0.0 + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_start, __pyx_v_end, REL_TOL, __pyx_v_5ezdxf_3acc_9construct_DEG_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 184, __pyx_L1_error) + if (__pyx_t_1) { + + /* "ezdxf/acc/construct.pyx":185 + * def arc_angle_span_deg(double start, double end) -> float: + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): + * return 0.0 # <<<<<<<<<<<<<< + * + * start %= 360.0 + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_float_0_0); + __pyx_r = __pyx_float_0_0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":184 + * + * def arc_angle_span_deg(double start, double end) -> float: + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * return 0.0 + * + */ + } + + /* "ezdxf/acc/construct.pyx":187 + * return 0.0 + * + * start %= 360.0 # <<<<<<<<<<<<<< + * if isclose(start, end % 360.0, REL_TOL, DEG_ABS_TOL): + * return 360.0 + */ + __pyx_v_start = __Pyx_mod_double(__pyx_v_start, 360.0); + + /* "ezdxf/acc/construct.pyx":188 + * + * start %= 360.0 + * if isclose(start, end % 360.0, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * return 360.0 + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_start, __Pyx_mod_double(__pyx_v_end, 360.0), REL_TOL, __pyx_v_5ezdxf_3acc_9construct_DEG_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L1_error) + if (__pyx_t_1) { + + /* "ezdxf/acc/construct.pyx":189 + * start %= 360.0 + * if isclose(start, end % 360.0, REL_TOL, DEG_ABS_TOL): + * return 360.0 # <<<<<<<<<<<<<< + * + * if not isclose(end, 360.0, REL_TOL, DEG_ABS_TOL): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_float_360_0); + __pyx_r = __pyx_float_360_0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":188 + * + * start %= 360.0 + * if isclose(start, end % 360.0, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * return 360.0 + * + */ + } + + /* "ezdxf/acc/construct.pyx":191 + * return 360.0 + * + * if not isclose(end, 360.0, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * end %= 360.0 + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_end, 360.0, REL_TOL, __pyx_v_5ezdxf_3acc_9construct_DEG_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 191, __pyx_L1_error) + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":192 + * + * if not isclose(end, 360.0, REL_TOL, DEG_ABS_TOL): + * end %= 360.0 # <<<<<<<<<<<<<< + * + * if end < start: + */ + __pyx_v_end = __Pyx_mod_double(__pyx_v_end, 360.0); + + /* "ezdxf/acc/construct.pyx":191 + * return 360.0 + * + * if not isclose(end, 360.0, REL_TOL, DEG_ABS_TOL): # <<<<<<<<<<<<<< + * end %= 360.0 + * + */ + } + + /* "ezdxf/acc/construct.pyx":194 + * end %= 360.0 + * + * if end < start: # <<<<<<<<<<<<<< + * end += 360.0 + * return end - start + */ + __pyx_t_2 = (__pyx_v_end < __pyx_v_start); + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":195 + * + * if end < start: + * end += 360.0 # <<<<<<<<<<<<<< + * return end - start + * + */ + __pyx_v_end = (__pyx_v_end + 360.0); + + /* "ezdxf/acc/construct.pyx":194 + * end %= 360.0 + * + * if end < start: # <<<<<<<<<<<<<< + * end += 360.0 + * return end - start + */ + } + + /* "ezdxf/acc/construct.pyx":196 + * if end < start: + * end += 360.0 + * return end - start # <<<<<<<<<<<<<< + * + * def arc_angle_span_rad(double start, double end) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_end - __pyx_v_start)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":183 + * return p1, p2 + * + * def arc_angle_span_deg(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): + * return 0.0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.construct.arc_angle_span_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":198 + * return end - start + * + * def arc_angle_span_rad(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): + * return 0.0 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_9arc_angle_span_rad(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_9arc_angle_span_rad = {"arc_angle_span_rad", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_9arc_angle_span_rad, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_9arc_angle_span_rad(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_start; + double __pyx_v_end; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("arc_angle_span_rad (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_start,&__pyx_n_s_end,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_start)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 198, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_end)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 198, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("arc_angle_span_rad", 1, 2, 2, 1); __PYX_ERR(0, 198, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "arc_angle_span_rad") < 0)) __PYX_ERR(0, 198, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_start = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_start == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 198, __pyx_L3_error) + __pyx_v_end = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_end == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 198, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("arc_angle_span_rad", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 198, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.arc_angle_span_rad", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_8arc_angle_span_rad(__pyx_self, __pyx_v_start, __pyx_v_end); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_8arc_angle_span_rad(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_start, double __pyx_v_end) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("arc_angle_span_rad", 1); + + /* "ezdxf/acc/construct.pyx":199 + * + * def arc_angle_span_rad(double start, double end) -> float: + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * return 0.0 + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_start, __pyx_v_end, REL_TOL, __pyx_v_5ezdxf_3acc_9construct_RAD_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 199, __pyx_L1_error) + if (__pyx_t_1) { + + /* "ezdxf/acc/construct.pyx":200 + * def arc_angle_span_rad(double start, double end) -> float: + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): + * return 0.0 # <<<<<<<<<<<<<< + * + * start %= M_TAU + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_float_0_0); + __pyx_r = __pyx_float_0_0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":199 + * + * def arc_angle_span_rad(double start, double end) -> float: + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * return 0.0 + * + */ + } + + /* "ezdxf/acc/construct.pyx":202 + * return 0.0 + * + * start %= M_TAU # <<<<<<<<<<<<<< + * if isclose(start, end % M_TAU, REL_TOL, RAD_ABS_TOL): + * return M_TAU + */ + if (unlikely(M_TAU == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); + __PYX_ERR(0, 202, __pyx_L1_error) + } + __pyx_v_start = __Pyx_mod_double(__pyx_v_start, M_TAU); + + /* "ezdxf/acc/construct.pyx":203 + * + * start %= M_TAU + * if isclose(start, end % M_TAU, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * return M_TAU + * + */ + if (unlikely(M_TAU == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); + __PYX_ERR(0, 203, __pyx_L1_error) + } + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_start, __Pyx_mod_double(__pyx_v_end, M_TAU), REL_TOL, __pyx_v_5ezdxf_3acc_9construct_RAD_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 203, __pyx_L1_error) + if (__pyx_t_1) { + + /* "ezdxf/acc/construct.pyx":204 + * start %= M_TAU + * if isclose(start, end % M_TAU, REL_TOL, RAD_ABS_TOL): + * return M_TAU # <<<<<<<<<<<<<< + * + * if not isclose(end, M_TAU, REL_TOL, RAD_ABS_TOL): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble(M_TAU); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":203 + * + * start %= M_TAU + * if isclose(start, end % M_TAU, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * return M_TAU + * + */ + } + + /* "ezdxf/acc/construct.pyx":206 + * return M_TAU + * + * if not isclose(end, M_TAU, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * end %= M_TAU + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_end, M_TAU, REL_TOL, __pyx_v_5ezdxf_3acc_9construct_RAD_ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 206, __pyx_L1_error) + __pyx_t_3 = (!__pyx_t_1); + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":207 + * + * if not isclose(end, M_TAU, REL_TOL, RAD_ABS_TOL): + * end %= M_TAU # <<<<<<<<<<<<<< + * + * if end < start: + */ + if (unlikely(M_TAU == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); + __PYX_ERR(0, 207, __pyx_L1_error) + } + __pyx_v_end = __Pyx_mod_double(__pyx_v_end, M_TAU); + + /* "ezdxf/acc/construct.pyx":206 + * return M_TAU + * + * if not isclose(end, M_TAU, REL_TOL, RAD_ABS_TOL): # <<<<<<<<<<<<<< + * end %= M_TAU + * + */ + } + + /* "ezdxf/acc/construct.pyx":209 + * end %= M_TAU + * + * if end < start: # <<<<<<<<<<<<<< + * end += M_TAU + * return end - start + */ + __pyx_t_3 = (__pyx_v_end < __pyx_v_start); + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":210 + * + * if end < start: + * end += M_TAU # <<<<<<<<<<<<<< + * return end - start + * + */ + __pyx_v_end = (__pyx_v_end + M_TAU); + + /* "ezdxf/acc/construct.pyx":209 + * end %= M_TAU + * + * if end < start: # <<<<<<<<<<<<<< + * end += M_TAU + * return end - start + */ + } + + /* "ezdxf/acc/construct.pyx":211 + * if end < start: + * end += M_TAU + * return end - start # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble((__pyx_v_end - __pyx_v_start)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 211, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":198 + * return end - start + * + * def arc_angle_span_rad(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): + * return 0.0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.construct.arc_angle_span_rad", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":214 + * + * + * def is_point_in_polygon_2d( # <<<<<<<<<<<<<< + * point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE + * ) -> int: + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_20__defaults__(CYTHON_UNUSED PyObject *__pyx_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__defaults__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__Pyx_CyFunction_Defaults(__pyx_defaults2, __pyx_self)->__pyx_arg_abs_tol); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, Py_None)) __PYX_ERR(0, 214, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.construct.__defaults__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_11is_point_in_polygon_2d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_10is_point_in_polygon_2d, "\n Test if `point` is inside `polygon`. Returns +1 for inside, 0 for on the \n boundary and -1 for outside.\n\n Supports convex and concave polygons with clockwise or counter-clockwise oriented\n polygon vertices. Does not raise an exception for degenerated polygons.\n\n\n Args:\n point: 2D point to test as :class:`Vec2`\n polygon: list of 2D points as :class:`Vec2`\n abs_tol: tolerance for distance check\n\n Returns:\n +1 for inside, 0 for on the boundary, -1 for outside\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_11is_point_in_polygon_2d = {"is_point_in_polygon_2d", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_11is_point_in_polygon_2d, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_10is_point_in_polygon_2d}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_11is_point_in_polygon_2d(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_point = 0; + PyObject *__pyx_v_polygon = 0; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_point_in_polygon_2d (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_point,&__pyx_n_s_polygon,&__pyx_n_s_abs_tol,0}; + __pyx_defaults2 *__pyx_dynamic_args = __Pyx_CyFunction_Defaults(__pyx_defaults2, __pyx_self); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_point)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_polygon)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("is_point_in_polygon_2d", 0, 2, 3, 1); __PYX_ERR(0, 214, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_abs_tol); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "is_point_in_polygon_2d") < 0)) __PYX_ERR(0, 214, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_point = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)values[0]); + __pyx_v_polygon = ((PyObject*)values[1]); + if (values[2]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 215, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_dynamic_args->__pyx_arg_abs_tol; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("is_point_in_polygon_2d", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 214, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.is_point_in_polygon_2d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_point), __pyx_ptype_5ezdxf_3acc_6vector_Vec2, 0, "point", 0))) __PYX_ERR(0, 215, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_polygon), (&PyList_Type), 0, "polygon", 1))) __PYX_ERR(0, 215, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_10is_point_in_polygon_2d(__pyx_self, __pyx_v_point, __pyx_v_polygon, __pyx_v_abs_tol); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_10is_point_in_polygon_2d(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_point, PyObject *__pyx_v_polygon, double __pyx_v_abs_tol) { + double __pyx_v_a; + double __pyx_v_b; + double __pyx_v_c; + double __pyx_v_d; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_x1; + double __pyx_v_y1; + double __pyx_v_x2; + double __pyx_v_y2; + PyObject *__pyx_v_vertices = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_p1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_p2 = 0; + int __pyx_v_size; + int __pyx_v_last; + int __pyx_v_i; + int __pyx_v_inside; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + double __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + int __pyx_t_8; + __pyx_ctuple_double__and_double __pyx_t_9; + __pyx_ctuple_double__and_double __pyx_t_10; + double __pyx_t_11; + int __pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_point_in_polygon_2d", 1); + + /* "ezdxf/acc/construct.pyx":239 + * # version! + * cdef double a, b, c, d, x, y, x1, y1, x2, y2 + * cdef list vertices = polygon # <<<<<<<<<<<<<< + * cdef Vec2 p1, p2 + * cdef int size, last, i + */ + __Pyx_INCREF(__pyx_v_polygon); + __pyx_v_vertices = __pyx_v_polygon; + + /* "ezdxf/acc/construct.pyx":242 + * cdef Vec2 p1, p2 + * cdef int size, last, i + * cdef bint inside = 0 # <<<<<<<<<<<<<< + * + * size = len(vertices) + */ + __pyx_v_inside = 0; + + /* "ezdxf/acc/construct.pyx":244 + * cdef bint inside = 0 + * + * size = len(vertices) # <<<<<<<<<<<<<< + * if size < 3: # empty polygon + * return -1 + */ + __pyx_t_1 = __Pyx_PyList_GET_SIZE(__pyx_v_vertices); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 244, __pyx_L1_error) + __pyx_v_size = __pyx_t_1; + + /* "ezdxf/acc/construct.pyx":245 + * + * size = len(vertices) + * if size < 3: # empty polygon # <<<<<<<<<<<<<< + * return -1 + * last = size - 1 + */ + __pyx_t_2 = (__pyx_v_size < 3); + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":246 + * size = len(vertices) + * if size < 3: # empty polygon + * return -1 # <<<<<<<<<<<<<< + * last = size - 1 + * p1 = vertices[0] + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_neg_1)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_neg_1))) __PYX_ERR(0, 246, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_neg_1); + __pyx_r = ((PyObject*)__pyx_int_neg_1); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":245 + * + * size = len(vertices) + * if size < 3: # empty polygon # <<<<<<<<<<<<<< + * return -1 + * last = size - 1 + */ + } + + /* "ezdxf/acc/construct.pyx":247 + * if size < 3: # empty polygon + * return -1 + * last = size - 1 # <<<<<<<<<<<<<< + * p1 = vertices[0] + * p2 = vertices[last] + */ + __pyx_v_last = (__pyx_v_size - 1); + + /* "ezdxf/acc/construct.pyx":248 + * return -1 + * last = size - 1 + * p1 = vertices[0] # <<<<<<<<<<<<<< + * p2 = vertices[last] + * + */ + __pyx_t_3 = __Pyx_GetItemInt_List(__pyx_v_vertices, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_p1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/construct.pyx":249 + * last = size - 1 + * p1 = vertices[0] + * p2 = vertices[last] # <<<<<<<<<<<<<< + * + * if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon + */ + __pyx_t_4 = __Pyx_GetItemInt_List(__pyx_v_vertices, __pyx_v_last, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_p2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":251 + * p2 = vertices[last] + * + * if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon # <<<<<<<<<<<<<< + * size -= 1 + * last -= 1 + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_isclose(__pyx_v_p1, __pyx_v_p2, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 251, __pyx_L1_error) + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":252 + * + * if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon + * size -= 1 # <<<<<<<<<<<<<< + * last -= 1 + * if size < 3: + */ + __pyx_v_size = (__pyx_v_size - 1); + + /* "ezdxf/acc/construct.pyx":253 + * if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon + * size -= 1 + * last -= 1 # <<<<<<<<<<<<<< + * if size < 3: + * return -1 + */ + __pyx_v_last = (__pyx_v_last - 1); + + /* "ezdxf/acc/construct.pyx":251 + * p2 = vertices[last] + * + * if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon # <<<<<<<<<<<<<< + * size -= 1 + * last -= 1 + */ + } + + /* "ezdxf/acc/construct.pyx":254 + * size -= 1 + * last -= 1 + * if size < 3: # <<<<<<<<<<<<<< + * return -1 + * + */ + __pyx_t_2 = (__pyx_v_size < 3); + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":255 + * last -= 1 + * if size < 3: + * return -1 # <<<<<<<<<<<<<< + * + * x = point.x + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_neg_1)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_neg_1))) __PYX_ERR(0, 255, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_neg_1); + __pyx_r = ((PyObject*)__pyx_int_neg_1); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":254 + * size -= 1 + * last -= 1 + * if size < 3: # <<<<<<<<<<<<<< + * return -1 + * + */ + } + + /* "ezdxf/acc/construct.pyx":257 + * return -1 + * + * x = point.x # <<<<<<<<<<<<<< + * y = point.y + * p1 = vertices[last] + */ + __pyx_t_5 = __pyx_v_point->x; + __pyx_v_x = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":258 + * + * x = point.x + * y = point.y # <<<<<<<<<<<<<< + * p1 = vertices[last] + * x1 = p1.x + */ + __pyx_t_5 = __pyx_v_point->y; + __pyx_v_y = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":259 + * x = point.x + * y = point.y + * p1 = vertices[last] # <<<<<<<<<<<<<< + * x1 = p1.x + * y1 = p1.y + */ + __pyx_t_3 = __Pyx_GetItemInt_List(__pyx_v_vertices, __pyx_v_last, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_p1, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/construct.pyx":260 + * y = point.y + * p1 = vertices[last] + * x1 = p1.x # <<<<<<<<<<<<<< + * y1 = p1.y + * + */ + __pyx_t_5 = __pyx_v_p1->x; + __pyx_v_x1 = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":261 + * p1 = vertices[last] + * x1 = p1.x + * y1 = p1.y # <<<<<<<<<<<<<< + * + * for i in range(size): + */ + __pyx_t_5 = __pyx_v_p1->y; + __pyx_v_y1 = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":263 + * y1 = p1.y + * + * for i in range(size): # <<<<<<<<<<<<<< + * p2 = vertices[i] + * x2 = p2.x + */ + __pyx_t_6 = __pyx_v_size; + __pyx_t_7 = __pyx_t_6; + for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) { + __pyx_v_i = __pyx_t_8; + + /* "ezdxf/acc/construct.pyx":264 + * + * for i in range(size): + * p2 = vertices[i] # <<<<<<<<<<<<<< + * x2 = p2.x + * y2 = p2.y + */ + __pyx_t_4 = __Pyx_GetItemInt_List(__pyx_v_vertices, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_p2, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":265 + * for i in range(size): + * p2 = vertices[i] + * x2 = p2.x # <<<<<<<<<<<<<< + * y2 = p2.y + * + */ + __pyx_t_5 = __pyx_v_p2->x; + __pyx_v_x2 = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":266 + * p2 = vertices[i] + * x2 = p2.x + * y2 = p2.y # <<<<<<<<<<<<<< + * + * # is point on polygon boundary line: + */ + __pyx_t_5 = __pyx_v_p2->y; + __pyx_v_y2 = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":270 + * # is point on polygon boundary line: + * # is point in x-range of line + * a, b = (x2, x1) if x2 < x1 else (x1, x2) # <<<<<<<<<<<<<< + * if a <= x <= b: + * # is point in y-range of line + */ + __pyx_t_2 = (__pyx_v_x2 < __pyx_v_x1); + if (__pyx_t_2) { + __pyx_t_10.f0 = __pyx_v_x2; + __pyx_t_10.f1 = __pyx_v_x1; + __pyx_t_9 = __pyx_t_10; + } else { + __pyx_t_10.f0 = __pyx_v_x1; + __pyx_t_10.f1 = __pyx_v_x2; + __pyx_t_9 = __pyx_t_10; + } + __pyx_t_5 = __pyx_t_9.f0; + __pyx_t_11 = __pyx_t_9.f1; + __pyx_v_a = __pyx_t_5; + __pyx_v_b = __pyx_t_11; + + /* "ezdxf/acc/construct.pyx":271 + * # is point in x-range of line + * a, b = (x2, x1) if x2 < x1 else (x1, x2) + * if a <= x <= b: # <<<<<<<<<<<<<< + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) + */ + __pyx_t_2 = (__pyx_v_a <= __pyx_v_x); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_x <= __pyx_v_b); + } + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":273 + * if a <= x <= b: + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) # <<<<<<<<<<<<<< + * if (c <= y <= d) and fabs( + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + */ + __pyx_t_2 = (__pyx_v_y2 < __pyx_v_y1); + if (__pyx_t_2) { + __pyx_t_10.f0 = __pyx_v_y2; + __pyx_t_10.f1 = __pyx_v_y1; + __pyx_t_9 = __pyx_t_10; + } else { + __pyx_t_10.f0 = __pyx_v_y1; + __pyx_t_10.f1 = __pyx_v_y2; + __pyx_t_9 = __pyx_t_10; + } + __pyx_t_11 = __pyx_t_9.f0; + __pyx_t_5 = __pyx_t_9.f1; + __pyx_v_c = __pyx_t_11; + __pyx_v_d = __pyx_t_5; + + /* "ezdxf/acc/construct.pyx":274 + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) + * if (c <= y <= d) and fabs( # <<<<<<<<<<<<<< + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + * ) <= abs_tol: + */ + __pyx_t_12 = (__pyx_v_c <= __pyx_v_y); + if (__pyx_t_12) { + __pyx_t_12 = (__pyx_v_y <= __pyx_v_d); + } + if (__pyx_t_12) { + } else { + __pyx_t_2 = __pyx_t_12; + goto __pyx_L10_bool_binop_done; + } + + /* "ezdxf/acc/construct.pyx":276 + * if (c <= y <= d) and fabs( + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + * ) <= abs_tol: # <<<<<<<<<<<<<< + * return 0 # on boundary line + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( + */ + __pyx_t_12 = (fabs(((((__pyx_v_y2 - __pyx_v_y1) * __pyx_v_x) - ((__pyx_v_x2 - __pyx_v_x1) * __pyx_v_y)) + ((__pyx_v_x2 * __pyx_v_y1) - (__pyx_v_y2 * __pyx_v_x1)))) <= __pyx_v_abs_tol); + __pyx_t_2 = __pyx_t_12; + __pyx_L10_bool_binop_done:; + + /* "ezdxf/acc/construct.pyx":274 + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) + * if (c <= y <= d) and fabs( # <<<<<<<<<<<<<< + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + * ) <= abs_tol: + */ + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":277 + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + * ) <= abs_tol: + * return 0 # on boundary line # <<<<<<<<<<<<<< + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_0)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_0))) __PYX_ERR(0, 277, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_0); + __pyx_r = ((PyObject*)__pyx_int_0); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":274 + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) + * if (c <= y <= d) and fabs( # <<<<<<<<<<<<<< + * (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + * ) <= abs_tol: + */ + } + + /* "ezdxf/acc/construct.pyx":271 + * # is point in x-range of line + * a, b = (x2, x1) if x2 < x1 else (x1, x2) + * if a <= x <= b: # <<<<<<<<<<<<<< + * # is point in y-range of line + * c, d = (y2, y1) if y2 < y1 else (y1, y2) + */ + } + + /* "ezdxf/acc/construct.pyx":278 + * ) <= abs_tol: + * return 0 # on boundary line + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( # <<<<<<<<<<<<<< + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + * ): + */ + __pyx_t_12 = (__pyx_v_y1 <= __pyx_v_y); + if (__pyx_t_12) { + __pyx_t_12 = (__pyx_v_y < __pyx_v_y2); + } + if (!__pyx_t_12) { + } else { + goto __pyx_L14_next_and; + } + __pyx_t_12 = (__pyx_v_y2 <= __pyx_v_y); + if (__pyx_t_12) { + __pyx_t_12 = (__pyx_v_y < __pyx_v_y1); + } + if (__pyx_t_12) { + } else { + __pyx_t_2 = __pyx_t_12; + goto __pyx_L13_bool_binop_done; + } + __pyx_L14_next_and:; + + /* "ezdxf/acc/construct.pyx":279 + * return 0 # on boundary line + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 # <<<<<<<<<<<<<< + * ): + * inside = not inside + */ + __pyx_t_5 = ((__pyx_v_x2 - __pyx_v_x1) * (__pyx_v_y - __pyx_v_y1)); + __pyx_t_11 = (__pyx_v_y2 - __pyx_v_y1); + if (unlikely(__pyx_t_11 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 279, __pyx_L1_error) + } + __pyx_t_12 = (__pyx_v_x < ((__pyx_t_5 / __pyx_t_11) + __pyx_v_x1)); + __pyx_t_2 = __pyx_t_12; + __pyx_L13_bool_binop_done:; + + /* "ezdxf/acc/construct.pyx":278 + * ) <= abs_tol: + * return 0 # on boundary line + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( # <<<<<<<<<<<<<< + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + * ): + */ + if (__pyx_t_2) { + + /* "ezdxf/acc/construct.pyx":281 + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + * ): + * inside = not inside # <<<<<<<<<<<<<< + * x1 = x2 + * y1 = y2 + */ + __pyx_v_inside = (!__pyx_v_inside); + + /* "ezdxf/acc/construct.pyx":278 + * ) <= abs_tol: + * return 0 # on boundary line + * if ((y1 <= y < y2) or (y2 <= y < y1)) and ( # <<<<<<<<<<<<<< + * x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + * ): + */ + } + + /* "ezdxf/acc/construct.pyx":282 + * ): + * inside = not inside + * x1 = x2 # <<<<<<<<<<<<<< + * y1 = y2 + * if inside: + */ + __pyx_v_x1 = __pyx_v_x2; + + /* "ezdxf/acc/construct.pyx":283 + * inside = not inside + * x1 = x2 + * y1 = y2 # <<<<<<<<<<<<<< + * if inside: + * return 1 # inside polygon + */ + __pyx_v_y1 = __pyx_v_y2; + } + + /* "ezdxf/acc/construct.pyx":284 + * x1 = x2 + * y1 = y2 + * if inside: # <<<<<<<<<<<<<< + * return 1 # inside polygon + * else: + */ + if (__pyx_v_inside) { + + /* "ezdxf/acc/construct.pyx":285 + * y1 = y2 + * if inside: + * return 1 # inside polygon # <<<<<<<<<<<<<< + * else: + * return -1 # outside polygon + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_1)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_1))) __PYX_ERR(0, 285, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_1); + __pyx_r = ((PyObject*)__pyx_int_1); + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":284 + * x1 = x2 + * y1 = y2 + * if inside: # <<<<<<<<<<<<<< + * return 1 # inside polygon + * else: + */ + } + + /* "ezdxf/acc/construct.pyx":287 + * return 1 # inside polygon + * else: + * return -1 # outside polygon # <<<<<<<<<<<<<< + * + * cdef double WGS84_SEMI_MAJOR_AXIS = 6378137 + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_int_neg_1)) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_int_neg_1))) __PYX_ERR(0, 287, __pyx_L1_error) + __Pyx_INCREF(__pyx_int_neg_1); + __pyx_r = ((PyObject*)__pyx_int_neg_1); + goto __pyx_L0; + } + + /* "ezdxf/acc/construct.pyx":214 + * + * + * def is_point_in_polygon_2d( # <<<<<<<<<<<<<< + * point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE + * ) -> int: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.construct.is_point_in_polygon_2d", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_vertices); + __Pyx_XDECREF((PyObject *)__pyx_v_p1); + __Pyx_XDECREF((PyObject *)__pyx_v_p2); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":296 + * + * + * def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform GPS (long/lat) to World Mercator. + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_13gps_to_world_mercator(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_12gps_to_world_mercator, "Transform GPS (long/lat) to World Mercator.\n \n Transform WGS84 `EPSG:4326 `_ location given as\n latitude and longitude in decimal degrees as used by GPS into World Mercator\n cartesian 2D coordinates in meters `EPSG:3395 `_.\n\n Args:\n longitude: represents the longitude value (East-West) in decimal degrees \n latitude: represents the latitude value (North-South) in decimal degrees.\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_13gps_to_world_mercator = {"gps_to_world_mercator", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_13gps_to_world_mercator, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_12gps_to_world_mercator}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_13gps_to_world_mercator(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_longitude; + double __pyx_v_latitude; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("gps_to_world_mercator (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_longitude,&__pyx_n_s_latitude,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_longitude)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_latitude)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("gps_to_world_mercator", 1, 2, 2, 1); __PYX_ERR(0, 296, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "gps_to_world_mercator") < 0)) __PYX_ERR(0, 296, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_longitude = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_longitude == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + __pyx_v_latitude = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_latitude == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("gps_to_world_mercator", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 296, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.gps_to_world_mercator", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_12gps_to_world_mercator(__pyx_self, __pyx_v_longitude, __pyx_v_latitude); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_12gps_to_world_mercator(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_longitude, double __pyx_v_latitude) { + double __pyx_v_e_sin_lat; + double __pyx_v_c; + double __pyx_v_y; + double __pyx_v_x; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + double __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("gps_to_world_mercator", 1); + + /* "ezdxf/acc/construct.pyx":313 + * # EPSG:3395 - World Mercator + * # Source: https://gis.stackexchange.com/questions/259121/transformation-functions-for-epsg3395-projection-vs-epsg3857 + * longitude = longitude * RADIANS # east # <<<<<<<<<<<<<< + * latitude = latitude * RADIANS # north + * cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC + */ + __pyx_v_longitude = (__pyx_v_longitude * __pyx_v_5ezdxf_3acc_9construct_RADIANS); + + /* "ezdxf/acc/construct.pyx":314 + * # Source: https://gis.stackexchange.com/questions/259121/transformation-functions-for-epsg3395-projection-vs-epsg3857 + * longitude = longitude * RADIANS # east + * latitude = latitude * RADIANS # north # <<<<<<<<<<<<<< + * cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC + * cdef double c = pow( + */ + __pyx_v_latitude = (__pyx_v_latitude * __pyx_v_5ezdxf_3acc_9construct_RADIANS); + + /* "ezdxf/acc/construct.pyx":315 + * longitude = longitude * RADIANS # east + * latitude = latitude * RADIANS # north + * cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC # <<<<<<<<<<<<<< + * cdef double c = pow( + * (1.0 - e_sin_lat) / (1.0 + e_sin_lat), WGS84_ELLIPSOID_ECCENTRIC / 2.0 + */ + __pyx_v_e_sin_lat = (sin(__pyx_v_latitude) * __pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC); + + /* "ezdxf/acc/construct.pyx":317 + * cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC + * cdef double c = pow( + * (1.0 - e_sin_lat) / (1.0 + e_sin_lat), WGS84_ELLIPSOID_ECCENTRIC / 2.0 # <<<<<<<<<<<<<< + * ) # 7-7 p.44 + * y = WGS84_SEMI_MAJOR_AXIS * log(tan(M_PI_4 + latitude / 2.0) * c) # 7-7 p.44 + */ + __pyx_t_1 = (1.0 - __pyx_v_e_sin_lat); + __pyx_t_2 = (1.0 + __pyx_v_e_sin_lat); + if (unlikely(__pyx_t_2 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 317, __pyx_L1_error) + } + + /* "ezdxf/acc/construct.pyx":316 + * latitude = latitude * RADIANS # north + * cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC + * cdef double c = pow( # <<<<<<<<<<<<<< + * (1.0 - e_sin_lat) / (1.0 + e_sin_lat), WGS84_ELLIPSOID_ECCENTRIC / 2.0 + * ) # 7-7 p.44 + */ + __pyx_v_c = pow((__pyx_t_1 / __pyx_t_2), (__pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC / 2.0)); + + /* "ezdxf/acc/construct.pyx":319 + * (1.0 - e_sin_lat) / (1.0 + e_sin_lat), WGS84_ELLIPSOID_ECCENTRIC / 2.0 + * ) # 7-7 p.44 + * y = WGS84_SEMI_MAJOR_AXIS * log(tan(M_PI_4 + latitude / 2.0) * c) # 7-7 p.44 # <<<<<<<<<<<<<< + * x = WGS84_SEMI_MAJOR_AXIS * longitude + * return x, y + */ + __pyx_v_y = (__pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS * log((tan((M_PI_4 + (__pyx_v_latitude / 2.0))) * __pyx_v_c))); + + /* "ezdxf/acc/construct.pyx":320 + * ) # 7-7 p.44 + * y = WGS84_SEMI_MAJOR_AXIS * log(tan(M_PI_4 + latitude / 2.0) * c) # 7-7 p.44 + * x = WGS84_SEMI_MAJOR_AXIS * longitude # <<<<<<<<<<<<<< + * return x, y + * + */ + __pyx_v_x = (__pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS * __pyx_v_longitude); + + /* "ezdxf/acc/construct.pyx":321 + * y = WGS84_SEMI_MAJOR_AXIS * log(tan(M_PI_4 + latitude / 2.0) * c) # 7-7 p.44 + * x = WGS84_SEMI_MAJOR_AXIS * longitude + * return x, y # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_x); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 321, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_y); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 321, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 321, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3)) __PYX_ERR(0, 321, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4)) __PYX_ERR(0, 321, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":296 + * + * + * def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform GPS (long/lat) to World Mercator. + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.construct.gps_to_world_mercator", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/construct.pyx":324 + * + * + * def world_mercator_to_gps(double x, double y, double tol = 1e-6) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform World Mercator to GPS. + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_15world_mercator_to_gps(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_9construct_14world_mercator_to_gps, "Transform World Mercator to GPS.\n\n Transform WGS84 World Mercator `EPSG:3395 `_\n location given as cartesian 2D coordinates x, y in meters into WGS84 decimal\n degrees as longitude and latitude `EPSG:4326 `_ as\n used by GPS.\n\n Args:\n x: coordinate WGS84 World Mercator\n y: coordinate WGS84 World Mercator\n tol: accuracy for latitude calculation\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9construct_15world_mercator_to_gps = {"world_mercator_to_gps", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9construct_15world_mercator_to_gps, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_9construct_14world_mercator_to_gps}; +static PyObject *__pyx_pw_5ezdxf_3acc_9construct_15world_mercator_to_gps(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("world_mercator_to_gps (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_tol,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_x)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_y)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("world_mercator_to_gps", 0, 2, 3, 1); __PYX_ERR(0, 324, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_tol); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "world_mercator_to_gps") < 0)) __PYX_ERR(0, 324, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_x = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_x == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + __pyx_v_y = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_y == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + if (values[2]) { + __pyx_v_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 324, __pyx_L3_error) + } else { + __pyx_v_tol = ((double)((double)1e-6)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("world_mercator_to_gps", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 324, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.construct.world_mercator_to_gps", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9construct_14world_mercator_to_gps(__pyx_self, __pyx_v_x, __pyx_v_y, __pyx_v_tol); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9construct_14world_mercator_to_gps(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_x, double __pyx_v_y, double __pyx_v_tol) { + double __pyx_v_eccentric_2; + double __pyx_v_t; + double __pyx_v_e_sin_lat; + double __pyx_v_latitude; + double __pyx_v_latitude_prev; + double __pyx_v_longitude; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + double __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("world_mercator_to_gps", 1); + + /* "ezdxf/acc/construct.pyx":344 + * # Source: Map Projections - A Working Manual + * # https://pubs.usgs.gov/pp/1395/report.pdf + * cdef double eccentric_2 = WGS84_ELLIPSOID_ECCENTRIC / 2.0 # <<<<<<<<<<<<<< + * cdef double t = pow(M_E, (-y / WGS84_SEMI_MAJOR_AXIS)) # 7-10 p.44 + * cdef double e_sin_lat, latitude, latitude_prev + */ + __pyx_v_eccentric_2 = (__pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC / 2.0); + + /* "ezdxf/acc/construct.pyx":345 + * # https://pubs.usgs.gov/pp/1395/report.pdf + * cdef double eccentric_2 = WGS84_ELLIPSOID_ECCENTRIC / 2.0 + * cdef double t = pow(M_E, (-y / WGS84_SEMI_MAJOR_AXIS)) # 7-10 p.44 # <<<<<<<<<<<<<< + * cdef double e_sin_lat, latitude, latitude_prev + * + */ + __pyx_t_1 = (-__pyx_v_y); + if (unlikely(__pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 345, __pyx_L1_error) + } + __pyx_v_t = pow(M_E, (__pyx_t_1 / __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS)); + + /* "ezdxf/acc/construct.pyx":348 + * cdef double e_sin_lat, latitude, latitude_prev + * + * latitude_prev = M_PI_2 - 2.0 * atan(t) # 7-11 p.45 # <<<<<<<<<<<<<< + * while True: + * e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC + */ + __pyx_v_latitude_prev = (M_PI_2 - (2.0 * atan(__pyx_v_t))); + + /* "ezdxf/acc/construct.pyx":349 + * + * latitude_prev = M_PI_2 - 2.0 * atan(t) # 7-11 p.45 + * while True: # <<<<<<<<<<<<<< + * e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC + * latitude = M_PI_2 - 2.0 * atan( + */ + while (1) { + + /* "ezdxf/acc/construct.pyx":350 + * latitude_prev = M_PI_2 - 2.0 * atan(t) # 7-11 p.45 + * while True: + * e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC # <<<<<<<<<<<<<< + * latitude = M_PI_2 - 2.0 * atan( + * t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) + */ + __pyx_v_e_sin_lat = (sin(__pyx_v_latitude_prev) * __pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC); + + /* "ezdxf/acc/construct.pyx":352 + * e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC + * latitude = M_PI_2 - 2.0 * atan( + * t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) # <<<<<<<<<<<<<< + * ) # 7-9 p.44 + * if fabs(latitude - latitude_prev) < tol: + */ + __pyx_t_1 = (1.0 - __pyx_v_e_sin_lat); + __pyx_t_2 = (1.0 + __pyx_v_e_sin_lat); + if (unlikely(__pyx_t_2 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 352, __pyx_L1_error) + } + + /* "ezdxf/acc/construct.pyx":351 + * while True: + * e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC + * latitude = M_PI_2 - 2.0 * atan( # <<<<<<<<<<<<<< + * t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) + * ) # 7-9 p.44 + */ + __pyx_v_latitude = (M_PI_2 - (2.0 * atan((__pyx_v_t * pow((__pyx_t_1 / __pyx_t_2), __pyx_v_eccentric_2))))); + + /* "ezdxf/acc/construct.pyx":354 + * t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) + * ) # 7-9 p.44 + * if fabs(latitude - latitude_prev) < tol: # <<<<<<<<<<<<<< + * break + * latitude_prev = latitude + */ + __pyx_t_3 = (fabs((__pyx_v_latitude - __pyx_v_latitude_prev)) < __pyx_v_tol); + if (__pyx_t_3) { + + /* "ezdxf/acc/construct.pyx":355 + * ) # 7-9 p.44 + * if fabs(latitude - latitude_prev) < tol: + * break # <<<<<<<<<<<<<< + * latitude_prev = latitude + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/construct.pyx":354 + * t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) + * ) # 7-9 p.44 + * if fabs(latitude - latitude_prev) < tol: # <<<<<<<<<<<<<< + * break + * latitude_prev = latitude + */ + } + + /* "ezdxf/acc/construct.pyx":356 + * if fabs(latitude - latitude_prev) < tol: + * break + * latitude_prev = latitude # <<<<<<<<<<<<<< + * + * longitude = x / WGS84_SEMI_MAJOR_AXIS # 7-12 p.45 + */ + __pyx_v_latitude_prev = __pyx_v_latitude; + } + __pyx_L4_break:; + + /* "ezdxf/acc/construct.pyx":358 + * latitude_prev = latitude + * + * longitude = x / WGS84_SEMI_MAJOR_AXIS # 7-12 p.45 # <<<<<<<<<<<<<< + * return longitude * DEGREES, latitude * DEGREES + */ + if (unlikely(__pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 358, __pyx_L1_error) + } + __pyx_v_longitude = (__pyx_v_x / __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS); + + /* "ezdxf/acc/construct.pyx":359 + * + * longitude = x / WGS84_SEMI_MAJOR_AXIS # 7-12 p.45 + * return longitude * DEGREES, latitude * DEGREES # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_longitude * __pyx_v_5ezdxf_3acc_9construct_DEGREES)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 359, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyFloat_FromDouble((__pyx_v_latitude * __pyx_v_5ezdxf_3acc_9construct_DEGREES)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 359, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 359, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4)) __PYX_ERR(0, 359, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_5)) __PYX_ERR(0, 359, __pyx_L1_error); + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/construct.pyx":324 + * + * + * def world_mercator_to_gps(double x, double y, double tol = 1e-6) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform World Mercator to GPS. + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.construct.world_mercator_to_gps", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_u_At_least_3_vertices_required, __pyx_k_At_least_3_vertices_required, sizeof(__pyx_k_At_least_3_vertices_required), 0, 1, 0, 0}, + {&__pyx_n_s_Iterable, __pyx_k_Iterable, sizeof(__pyx_k_Iterable), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterable_UVec, __pyx_k_Iterable_UVec, sizeof(__pyx_k_Iterable_UVec), 0, 0, 1, 0}, + {&__pyx_n_s_Optional, __pyx_k_Optional, sizeof(__pyx_k_Optional), 0, 0, 1, 1}, + {&__pyx_kp_s_Optional_Vec2, __pyx_k_Optional_Vec2, sizeof(__pyx_k_Optional_Vec2), 0, 0, 1, 0}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_kp_s_Sequence_Vec2, __pyx_k_Sequence_Vec2, sizeof(__pyx_k_Sequence_Vec2), 0, 0, 1, 0}, + {&__pyx_kp_s_Sequence_Vec3, __pyx_k_Sequence_Vec3, sizeof(__pyx_k_Sequence_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2, __pyx_k_Vec2, sizeof(__pyx_k_Vec2), 0, 0, 1, 1}, + {&__pyx_n_s__18, __pyx_k__18, sizeof(__pyx_k__18), 0, 0, 1, 1}, + {&__pyx_kp_u__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0, 0}, + {&__pyx_n_s_a, __pyx_k_a, sizeof(__pyx_k_a), 0, 0, 1, 1}, + {&__pyx_n_s_abs_tol, __pyx_k_abs_tol, sizeof(__pyx_k_abs_tol), 0, 0, 1, 1}, + {&__pyx_n_s_arc_angle_span_deg, __pyx_k_arc_angle_span_deg, sizeof(__pyx_k_arc_angle_span_deg), 0, 0, 1, 1}, + {&__pyx_n_s_arc_angle_span_rad, __pyx_k_arc_angle_span_rad, sizeof(__pyx_k_arc_angle_span_rad), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_b, __pyx_k_b, sizeof(__pyx_k_b), 0, 0, 1, 1}, + {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1}, + {&__pyx_n_s_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 0, 1, 1}, + {&__pyx_n_s_c1, __pyx_k_c1, sizeof(__pyx_k_c1), 0, 0, 1, 1}, + {&__pyx_n_s_c1x, __pyx_k_c1x, sizeof(__pyx_k_c1x), 0, 0, 1, 1}, + {&__pyx_n_s_c1y, __pyx_k_c1y, sizeof(__pyx_k_c1y), 0, 0, 1, 1}, + {&__pyx_n_s_c2, __pyx_k_c2, sizeof(__pyx_k_c2), 0, 0, 1, 1}, + {&__pyx_n_s_c2x, __pyx_k_c2x, sizeof(__pyx_k_c2x), 0, 0, 1, 1}, + {&__pyx_n_s_c2y, __pyx_k_c2y, sizeof(__pyx_k_c2y), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_d, __pyx_k_d, sizeof(__pyx_k_d), 0, 0, 1, 1}, + {&__pyx_n_s_d1, __pyx_k_d1, sizeof(__pyx_k_d1), 0, 0, 1, 1}, + {&__pyx_n_s_d1xd2, __pyx_k_d1xd2, sizeof(__pyx_k_d1xd2), 0, 0, 1, 1}, + {&__pyx_n_s_d2, __pyx_k_d2, sizeof(__pyx_k_d2), 0, 0, 1, 1}, + {&__pyx_n_s_den, __pyx_k_den, sizeof(__pyx_k_den), 0, 0, 1, 1}, + {&__pyx_n_s_denominator, __pyx_k_denominator, sizeof(__pyx_k_denominator), 0, 0, 1, 1}, + {&__pyx_n_s_det1, __pyx_k_det1, sizeof(__pyx_k_det1), 0, 0, 1, 1}, + {&__pyx_n_s_det2, __pyx_k_det2, sizeof(__pyx_k_det2), 0, 0, 1, 1}, + {&__pyx_n_s_e_sin_lat, __pyx_k_e_sin_lat, sizeof(__pyx_k_e_sin_lat), 0, 0, 1, 1}, + {&__pyx_n_s_eccentric_2, __pyx_k_eccentric_2, sizeof(__pyx_k_eccentric_2), 0, 0, 1, 1}, + {&__pyx_n_s_end, __pyx_k_end, sizeof(__pyx_k_end), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_construct, __pyx_k_ezdxf_acc_construct, sizeof(__pyx_k_ezdxf_acc_construct), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_n_s_float, __pyx_k_float, sizeof(__pyx_k_float), 0, 0, 1, 1}, + {&__pyx_n_s_gps_to_world_mercator, __pyx_k_gps_to_world_mercator, sizeof(__pyx_k_gps_to_world_mercator), 0, 0, 1, 1}, + {&__pyx_n_s_has_clockwise_orientation, __pyx_k_has_clockwise_orientation, sizeof(__pyx_k_has_clockwise_orientation), 0, 0, 1, 1}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_index, __pyx_k_index, sizeof(__pyx_k_index), 0, 0, 1, 1}, + {&__pyx_n_s_inside, __pyx_k_inside, sizeof(__pyx_k_inside), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_n_s_intersection_line_line_2d, __pyx_k_intersection_line_line_2d, sizeof(__pyx_k_intersection_line_line_2d), 0, 0, 1, 1}, + {&__pyx_n_s_intersection_ray_ray_3d, __pyx_k_intersection_ray_ray_3d, sizeof(__pyx_k_intersection_ray_ray_3d), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_n_s_is_point_in_polygon_2d, __pyx_k_is_point_in_polygon_2d, sizeof(__pyx_k_is_point_in_polygon_2d), 0, 0, 1, 1}, + {&__pyx_n_s_last, __pyx_k_last, sizeof(__pyx_k_last), 0, 0, 1, 1}, + {&__pyx_n_s_latitude, __pyx_k_latitude, sizeof(__pyx_k_latitude), 0, 0, 1, 1}, + {&__pyx_n_s_latitude_prev, __pyx_k_latitude_prev, sizeof(__pyx_k_latitude_prev), 0, 0, 1, 1}, + {&__pyx_n_s_line1, __pyx_k_line1, sizeof(__pyx_k_line1), 0, 0, 1, 1}, + {&__pyx_n_s_line2, __pyx_k_line2, sizeof(__pyx_k_line2), 0, 0, 1, 1}, + {&__pyx_kp_s_list_Vec2, __pyx_k_list_Vec2, sizeof(__pyx_k_list_Vec2), 0, 0, 1, 0}, + {&__pyx_n_s_longitude, __pyx_k_longitude, sizeof(__pyx_k_longitude), 0, 0, 1, 1}, + {&__pyx_n_s_lwr, __pyx_k_lwr, sizeof(__pyx_k_lwr), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_o1, __pyx_k_o1, sizeof(__pyx_k_o1), 0, 0, 1, 1}, + {&__pyx_n_s_o2, __pyx_k_o2, sizeof(__pyx_k_o2), 0, 0, 1, 1}, + {&__pyx_n_s_o2_o1, __pyx_k_o2_o1, sizeof(__pyx_k_o2_o1), 0, 0, 1, 1}, + {&__pyx_n_s_p1, __pyx_k_p1, sizeof(__pyx_k_p1), 0, 0, 1, 1}, + {&__pyx_n_s_p2, __pyx_k_p2, sizeof(__pyx_k_p2), 0, 0, 1, 1}, + {&__pyx_n_s_point, __pyx_k_point, sizeof(__pyx_k_point), 0, 0, 1, 1}, + {&__pyx_n_s_polygon, __pyx_k_polygon, sizeof(__pyx_k_polygon), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_ray1, __pyx_k_ray1, sizeof(__pyx_k_ray1), 0, 0, 1, 1}, + {&__pyx_n_s_ray2, __pyx_k_ray2, sizeof(__pyx_k_ray2), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 0, 1, 1}, + {&__pyx_n_s_s1, __pyx_k_s1, sizeof(__pyx_k_s1), 0, 0, 1, 1}, + {&__pyx_n_s_s1x, __pyx_k_s1x, sizeof(__pyx_k_s1x), 0, 0, 1, 1}, + {&__pyx_n_s_s1y, __pyx_k_s1y, sizeof(__pyx_k_s1y), 0, 0, 1, 1}, + {&__pyx_n_s_s2, __pyx_k_s2, sizeof(__pyx_k_s2), 0, 0, 1, 1}, + {&__pyx_n_s_s2x, __pyx_k_s2x, sizeof(__pyx_k_s2x), 0, 0, 1, 1}, + {&__pyx_n_s_s2y, __pyx_k_s2y, sizeof(__pyx_k_s2y), 0, 0, 1, 1}, + {&__pyx_n_s_size, __pyx_k_size, sizeof(__pyx_k_size), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_k_src_ezdxf_acc_construct_pyx, sizeof(__pyx_k_src_ezdxf_acc_construct_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_tol, __pyx_k_tol, sizeof(__pyx_k_tol), 0, 0, 1, 1}, + {&__pyx_kp_s_tuple_Vec3_Vec3, __pyx_k_tuple_Vec3_Vec3, sizeof(__pyx_k_tuple_Vec3_Vec3), 0, 0, 1, 0}, + {&__pyx_kp_s_tuple_float_float, __pyx_k_tuple_float_float, sizeof(__pyx_k_tuple_float_float), 0, 0, 1, 0}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_uc, __pyx_k_uc, sizeof(__pyx_k_uc), 0, 0, 1, 1}, + {&__pyx_n_s_upr, __pyx_k_upr, sizeof(__pyx_k_upr), 0, 0, 1, 1}, + {&__pyx_n_s_us, __pyx_k_us, sizeof(__pyx_k_us), 0, 0, 1, 1}, + {&__pyx_n_s_v, __pyx_k_v, sizeof(__pyx_k_v), 0, 0, 1, 1}, + {&__pyx_n_s_vertices, __pyx_k_vertices, sizeof(__pyx_k_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_vertices_2, __pyx_k_vertices_2, sizeof(__pyx_k_vertices_2), 0, 0, 1, 1}, + {&__pyx_n_s_virtual, __pyx_k_virtual, sizeof(__pyx_k_virtual), 0, 0, 1, 1}, + {&__pyx_n_s_world_mercator_to_gps, __pyx_k_world_mercator_to_gps, sizeof(__pyx_k_world_mercator_to_gps), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_x1, __pyx_k_x1, sizeof(__pyx_k_x1), 0, 0, 1, 1}, + {&__pyx_n_s_x2, __pyx_k_x2, sizeof(__pyx_k_x2), 0, 0, 1, 1}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {&__pyx_n_s_y1, __pyx_k_y1, sizeof(__pyx_k_y1), 0, 0, 1, 1}, + {&__pyx_n_s_y2, __pyx_k_y2, sizeof(__pyx_k_y2), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 47, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 58, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/construct.pyx":47 + * cdef list _vertices = [Vec2(v) for v in vertices] + * if len(_vertices) < 3: + * raise ValueError('At least 3 vertices required.') # <<<<<<<<<<<<<< + * + * cdef Vec2 p1 = _vertices[0] + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_At_least_3_vertices_required); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "ezdxf/acc/construct.pyx":34 + * cdef double TOLERANCE = 1e-10 + * + * def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + __pyx_tuple__3 = PyTuple_Pack(7, __pyx_n_s_vertices, __pyx_n_s_vertices_2, __pyx_n_s_p1, __pyx_n_s_p2, __pyx_n_s_s, __pyx_n_s_index, __pyx_n_s_v); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_has_clockwise_orientation, 34, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 34, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":64 + * return s > 0.0 + * + * def intersection_line_line_2d( # <<<<<<<<<<<<<< + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + */ + __pyx_tuple__5 = PyTuple_Pack(22, __pyx_n_s_line1, __pyx_n_s_line2, __pyx_n_s_virtual, __pyx_n_s_abs_tol, __pyx_n_s_s1, __pyx_n_s_s2, __pyx_n_s_c1, __pyx_n_s_c2, __pyx_n_s_res, __pyx_n_s_s1x, __pyx_n_s_s1y, __pyx_n_s_s2x, __pyx_n_s_s2y, __pyx_n_s_c1x, __pyx_n_s_c1y, __pyx_n_s_c2x, __pyx_n_s_c2y, __pyx_n_s_den, __pyx_n_s_us, __pyx_n_s_uc, __pyx_n_s_lwr, __pyx_n_s_upr); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__5); + __Pyx_GIVEREF(__pyx_tuple__5); + __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 22, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_intersection_line_line_2d, 64, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 64, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":135 + * v1.x * v2.z * v3.y - v1.y * v2.x * v3.z + * + * def intersection_ray_ray_3d( # <<<<<<<<<<<<<< + * ray1: tuple[Vec3, Vec3], + * ray2: tuple[Vec3, Vec3], + */ + __pyx_tuple__7 = PyTuple_Pack(14, __pyx_n_s_ray1, __pyx_n_s_ray2, __pyx_n_s_abs_tol, __pyx_n_s_o2_o1, __pyx_n_s_det1, __pyx_n_s_det2, __pyx_n_s_o1, __pyx_n_s_p1, __pyx_n_s_o2, __pyx_n_s_p2, __pyx_n_s_d1, __pyx_n_s_d2, __pyx_n_s_d1xd2, __pyx_n_s_denominator); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + __pyx_codeobj__8 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__7, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_intersection_ray_ray_3d, 135, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__8)) __PYX_ERR(0, 135, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":183 + * return p1, p2 + * + * def arc_angle_span_deg(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): + * return 0.0 + */ + __pyx_tuple__9 = PyTuple_Pack(2, __pyx_n_s_start, __pyx_n_s_end); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + __pyx_codeobj__10 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__9, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_arc_angle_span_deg, 183, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__10)) __PYX_ERR(0, 183, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":198 + * return end - start + * + * def arc_angle_span_rad(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): + * return 0.0 + */ + __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__9, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_arc_angle_span_rad, 198, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 198, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":214 + * + * + * def is_point_in_polygon_2d( # <<<<<<<<<<<<<< + * point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE + * ) -> int: + */ + __pyx_tuple__12 = PyTuple_Pack(20, __pyx_n_s_point, __pyx_n_s_polygon, __pyx_n_s_abs_tol, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_c, __pyx_n_s_d, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_x1, __pyx_n_s_y1, __pyx_n_s_x2, __pyx_n_s_y2, __pyx_n_s_vertices, __pyx_n_s_p1, __pyx_n_s_p2, __pyx_n_s_size, __pyx_n_s_last, __pyx_n_s_i, __pyx_n_s_inside); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 20, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_is_point_in_polygon_2d, 214, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 214, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":296 + * + * + * def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform GPS (long/lat) to World Mercator. + * + */ + __pyx_tuple__14 = PyTuple_Pack(6, __pyx_n_s_longitude, __pyx_n_s_latitude, __pyx_n_s_e_sin_lat, __pyx_n_s_c, __pyx_n_s_y, __pyx_n_s_x); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_gps_to_world_mercator, 296, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 296, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":324 + * + * + * def world_mercator_to_gps(double x, double y, double tol = 1e-6) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform World Mercator to GPS. + * + */ + __pyx_tuple__16 = PyTuple_Pack(9, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_tol, __pyx_n_s_eccentric_2, __pyx_n_s_t, __pyx_n_s_e_sin_lat, __pyx_n_s_latitude, __pyx_n_s_latitude_prev, __pyx_n_s_longitude); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__16); + __Pyx_GIVEREF(__pyx_tuple__16); + __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_construct_pyx, __pyx_n_s_world_mercator_to_gps, 324, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_float_0_0 = PyFloat_FromDouble(0.0); if (unlikely(!__pyx_float_0_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_360_0 = PyFloat_FromDouble(360.0); if (unlikely(!__pyx_float_360_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(1, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v2_isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v2_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_add", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_sub", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_sub, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_mul", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_cross", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_cross, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_magnitude_sqr", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_normalize", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_normalize, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_construct(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_construct}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "construct", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initconstruct(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initconstruct(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_construct(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_construct(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_construct(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'construct' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("construct", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "construct" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_construct(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__construct) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.construct")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.construct", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + (void)__Pyx_modinit_type_init_code(); + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/construct.pyx":4 + * # Copyright (c) 2020-2024, Manfred Moitzi + * # License: MIT License + * from typing import Iterable, TYPE_CHECKING, Sequence, Optional # <<<<<<<<<<<<<< + * from libc.math cimport fabs, M_PI, M_PI_2, M_PI_4, M_E, sin, tan, pow, atan, log + * from .vector cimport ( + */ + __pyx_t_2 = PyList_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_Iterable); + __Pyx_GIVEREF(__pyx_n_s_Iterable); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_Iterable)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Optional); + __Pyx_GIVEREF(__pyx_n_s_Optional); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_n_s_Optional)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterable); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterable, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Optional); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Optional, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":22 + * import cython + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 22, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "ezdxf/acc/construct.pyx":23 + * + * if TYPE_CHECKING: + * from ezdxf.math import UVec # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_UVec)) __PYX_ERR(0, 23, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_UVec); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_3) < 0) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":22 + * import cython + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + } + + /* "ezdxf/acc/construct.pyx":30 + * const double M_TAU + * + * cdef double RAD_ABS_TOL = 1e-15 # <<<<<<<<<<<<<< + * cdef double DEG_ABS_TOL = 1e-13 + * cdef double TOLERANCE = 1e-10 + */ + __pyx_v_5ezdxf_3acc_9construct_RAD_ABS_TOL = 1e-15; + + /* "ezdxf/acc/construct.pyx":31 + * + * cdef double RAD_ABS_TOL = 1e-15 + * cdef double DEG_ABS_TOL = 1e-13 # <<<<<<<<<<<<<< + * cdef double TOLERANCE = 1e-10 + * + */ + __pyx_v_5ezdxf_3acc_9construct_DEG_ABS_TOL = 1e-13; + + /* "ezdxf/acc/construct.pyx":32 + * cdef double RAD_ABS_TOL = 1e-15 + * cdef double DEG_ABS_TOL = 1e-13 + * cdef double TOLERANCE = 1e-10 # <<<<<<<<<<<<<< + * + * def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: + */ + __pyx_v_5ezdxf_3acc_9construct_TOLERANCE = 1e-10; + + /* "ezdxf/acc/construct.pyx":34 + * cdef double TOLERANCE = 1e-10 + * + * def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_vertices, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 34, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 34, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_1has_clockwise_orientation, 0, __pyx_n_s_has_clockwise_orientation, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__4)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_has_clockwise_orientation, __pyx_t_3) < 0) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":64 + * return s > 0.0 + * + * def intersection_line_line_2d( # <<<<<<<<<<<<<< + * line1: Sequence[Vec2], + * line2: Sequence[Vec2], + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_line1, __pyx_kp_s_Sequence_Vec2) < 0) __PYX_ERR(0, 64, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_line2, __pyx_kp_s_Sequence_Vec2) < 0) __PYX_ERR(0, 64, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Optional_Vec2) < 0) __PYX_ERR(0, 64, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_3intersection_line_line_2d, 0, __pyx_n_s_intersection_line_line_2d, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__6)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (!__Pyx_CyFunction_InitDefaults(__pyx_t_2, sizeof(__pyx_defaults), 0)) __PYX_ERR(0, 64, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":68 + * line2: Sequence[Vec2], + * bint virtual=True, + * double abs_tol=TOLERANCE) -> Optional[Vec2]: # <<<<<<<<<<<<<< + * """ + * Compute the intersection of two lines in the xy-plane. + */ + __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_t_2)->__pyx_arg_abs_tol = __pyx_v_5ezdxf_3acc_9construct_TOLERANCE; + __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_2, __pyx_pf_5ezdxf_3acc_9construct_16__defaults__); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_intersection_line_line_2d, __pyx_t_2) < 0) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":135 + * v1.x * v2.z * v3.y - v1.y * v2.x * v3.z + * + * def intersection_ray_ray_3d( # <<<<<<<<<<<<<< + * ray1: tuple[Vec3, Vec3], + * ray2: tuple[Vec3, Vec3], + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_ray1, __pyx_kp_s_tuple_Vec3_Vec3) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_ray2, __pyx_kp_s_tuple_Vec3_Vec3) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_Sequence_Vec3) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_5intersection_ray_ray_3d, 0, __pyx_n_s_intersection_ray_ray_3d, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__8)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (!__Pyx_CyFunction_InitDefaults(__pyx_t_3, sizeof(__pyx_defaults1), 0)) __PYX_ERR(0, 135, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":138 + * ray1: tuple[Vec3, Vec3], + * ray2: tuple[Vec3, Vec3], + * double abs_tol=TOLERANCE # <<<<<<<<<<<<<< + * ) -> Sequence[Vec3]: + * """ + */ + __Pyx_CyFunction_Defaults(__pyx_defaults1, __pyx_t_3)->__pyx_arg_abs_tol = __pyx_v_5ezdxf_3acc_9construct_TOLERANCE; + __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_3, __pyx_pf_5ezdxf_3acc_9construct_18__defaults__); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_intersection_ray_ray_3d, __pyx_t_3) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":183 + * return p1, p2 + * + * def arc_angle_span_deg(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, DEG_ABS_TOL): + * return 0.0 + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 183, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_7arc_angle_span_deg, 0, __pyx_n_s_arc_angle_span_deg, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__10)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_arc_angle_span_deg, __pyx_t_2) < 0) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":198 + * return end - start + * + * def arc_angle_span_rad(double start, double end) -> float: # <<<<<<<<<<<<<< + * if isclose(start, end, REL_TOL, RAD_ABS_TOL): + * return 0.0 + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 198, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_9arc_angle_span_rad, 0, __pyx_n_s_arc_angle_span_rad, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_arc_angle_span_rad, __pyx_t_3) < 0) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":214 + * + * + * def is_point_in_polygon_2d( # <<<<<<<<<<<<<< + * point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE + * ) -> int: + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_point, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 214, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_polygon, __pyx_kp_s_list_Vec2) < 0) __PYX_ERR(0, 214, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_int) < 0) __PYX_ERR(0, 214, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_11is_point_in_polygon_2d, 0, __pyx_n_s_is_point_in_polygon_2d, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (!__Pyx_CyFunction_InitDefaults(__pyx_t_2, sizeof(__pyx_defaults2), 0)) __PYX_ERR(0, 214, __pyx_L1_error) + + /* "ezdxf/acc/construct.pyx":215 + * + * def is_point_in_polygon_2d( + * point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE # <<<<<<<<<<<<<< + * ) -> int: + * """ + */ + __Pyx_CyFunction_Defaults(__pyx_defaults2, __pyx_t_2)->__pyx_arg_abs_tol = __pyx_v_5ezdxf_3acc_9construct_TOLERANCE; + __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_2, __pyx_pf_5ezdxf_3acc_9construct_20__defaults__); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_is_point_in_polygon_2d, __pyx_t_2) < 0) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/construct.pyx":289 + * return -1 # outside polygon + * + * cdef double WGS84_SEMI_MAJOR_AXIS = 6378137 # <<<<<<<<<<<<<< + * cdef double WGS84_SEMI_MINOR_AXIS = 6356752.3142 + * cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 + */ + __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MAJOR_AXIS = 6378137.0; + + /* "ezdxf/acc/construct.pyx":290 + * + * cdef double WGS84_SEMI_MAJOR_AXIS = 6378137 + * cdef double WGS84_SEMI_MINOR_AXIS = 6356752.3142 # <<<<<<<<<<<<<< + * cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 + * cdef double RADIANS = M_PI / 180.0 + */ + __pyx_v_5ezdxf_3acc_9construct_WGS84_SEMI_MINOR_AXIS = 6356752.3142; + + /* "ezdxf/acc/construct.pyx":291 + * cdef double WGS84_SEMI_MAJOR_AXIS = 6378137 + * cdef double WGS84_SEMI_MINOR_AXIS = 6356752.3142 + * cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 # <<<<<<<<<<<<<< + * cdef double RADIANS = M_PI / 180.0 + * cdef double DEGREES = 180.0 / M_PI + */ + __pyx_v_5ezdxf_3acc_9construct_WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624; + + /* "ezdxf/acc/construct.pyx":292 + * cdef double WGS84_SEMI_MINOR_AXIS = 6356752.3142 + * cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 + * cdef double RADIANS = M_PI / 180.0 # <<<<<<<<<<<<<< + * cdef double DEGREES = 180.0 / M_PI + * + */ + __pyx_v_5ezdxf_3acc_9construct_RADIANS = (((double)M_PI) / 180.0); + + /* "ezdxf/acc/construct.pyx":293 + * cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 + * cdef double RADIANS = M_PI / 180.0 + * cdef double DEGREES = 180.0 / M_PI # <<<<<<<<<<<<<< + * + * + */ + if (unlikely(M_PI == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 293, __pyx_L1_error) + } + __pyx_v_5ezdxf_3acc_9construct_DEGREES = (180.0 / ((double)M_PI)); + + /* "ezdxf/acc/construct.pyx":296 + * + * + * def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform GPS (long/lat) to World Mercator. + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_kp_s_tuple_float_float) < 0) __PYX_ERR(0, 296, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_13gps_to_world_mercator, 0, __pyx_n_s_gps_to_world_mercator, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_gps_to_world_mercator, __pyx_t_3) < 0) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/construct.pyx":324 + * + * + * def world_mercator_to_gps(double x, double y, double tol = 1e-6) -> tuple[float, float]: # <<<<<<<<<<<<<< + * """Transform World Mercator to GPS. + * + */ + __pyx_t_3 = PyFloat_FromDouble(((double)1e-6)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3)) __PYX_ERR(0, 324, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_tuple_float_float) < 0) __PYX_ERR(0, 324, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9construct_15world_mercator_to_gps, 0, __pyx_n_s_world_mercator_to_gps, NULL, __pyx_n_s_ezdxf_acc_construct, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_world_mercator_to_gps, __pyx_t_5) < 0) __PYX_ERR(0, 324, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/construct.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2020-2024, Manfred Moitzi + * # License: MIT License + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_5) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.construct", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.construct"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* ModFloat[double] */ +static CYTHON_INLINE double __Pyx_mod_double(double a, double b) { + double r = fmod(a, b); + r += ((r != 0) & ((r < 0) ^ (b < 0))) * b; + return r; +} + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__2); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__18); + } + return name; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ +#ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.cpython-312-darwin.so new file mode 100755 index 0000000..8d22bce Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.pyx new file mode 100644 index 0000000..f63a807 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/construct.pyx @@ -0,0 +1,359 @@ +# cython: language_level=3 +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from typing import Iterable, TYPE_CHECKING, Sequence, Optional +from libc.math cimport fabs, M_PI, M_PI_2, M_PI_4, M_E, sin, tan, pow, atan, log +from .vector cimport ( + isclose, + Vec2, + v2_isclose, + Vec3, + v3_sub, + v3_add, + v3_mul, + v3_normalize, + v3_cross, + v3_magnitude_sqr, + v3_isclose, +) + +import cython + +if TYPE_CHECKING: + from ezdxf.math import UVec + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + const double M_TAU + +cdef double RAD_ABS_TOL = 1e-15 +cdef double DEG_ABS_TOL = 1e-13 +cdef double TOLERANCE = 1e-10 + +def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: + """ Returns True if 2D `vertices` have clockwise orientation. Ignores + z-axis of all vertices. + + Args: + vertices: iterable of :class:`Vec2` compatible objects + + Raises: + ValueError: less than 3 vertices + + """ + cdef list _vertices = [Vec2(v) for v in vertices] + if len(_vertices) < 3: + raise ValueError('At least 3 vertices required.') + + cdef Vec2 p1 = _vertices[0] + cdef Vec2 p2 = _vertices[-1] + cdef double s = 0.0 + cdef Py_ssize_t index + + # Using the same tolerance as the Python implementation: + if not v2_isclose(p1, p2, REL_TOL, ABS_TOL): + _vertices.append(p1) + + for index in range(1, len(_vertices)): + p2 = _vertices[index] + s += (p2.x - p1.x) * (p2.y + p1.y) + p1 = p2 + return s > 0.0 + +def intersection_line_line_2d( + line1: Sequence[Vec2], + line2: Sequence[Vec2], + bint virtual=True, + double abs_tol=TOLERANCE) -> Optional[Vec2]: + """ + Compute the intersection of two lines in the xy-plane. + + Args: + line1: start- and end point of first line to test + e.g. ((x1, y1), (x2, y2)). + line2: start- and end point of second line to test + e.g. ((x3, y3), (x4, y4)). + virtual: ``True`` returns any intersection point, ``False`` returns + only real intersection points. + abs_tol: tolerance for intersection test. + + Returns: + ``None`` if there is no intersection point (parallel lines) or + intersection point as :class:`Vec2` + + """ + # Algorithm based on: http://paulbourke.net/geometry/pointlineplane/ + # chapter: Intersection point of two line segments in 2 dimensions + cdef Vec2 s1, s2, c1, c2, res + cdef double s1x, s1y, s2x, s2y, c1x, c1y, c2x, c2y, den, us, uc + cdef double lwr = 0.0, upr = 1.0 + + s1 = line1[0] + s2 = line1[1] + c1 = line2[0] + c2 = line2[1] + + s1x = s1.x + s1y = s1.y + s2x = s2.x + s2y = s2.y + c1x = c1.x + c1y = c1.y + c2x = c2.x + c2y = c2.y + + den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) + + if fabs(den) <= abs_tol: + return None + + + # den near zero is checked by if-statement above: + with cython.cdivision(True): + us = ((c2x - c1x) * (s1y - c1y) - (c2y - c1y) * (s1x - c1x)) / den + + res = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + if virtual: + return res + + # 0 = intersection point is the start point of the line + # 1 = intersection point is the end point of the line + # otherwise: linear interpolation + if lwr <= us <= upr: # intersection point is on the subject line + with cython.cdivision(True): + uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + if lwr <= uc <= upr: # intersection point is on the clipping line + return res + return None + +cdef double _determinant(Vec3 v1, Vec3 v2, Vec3 v3): + return v1.x * v2.y * v3.z + v1.y * v2.z * v3.x + \ + v1.z * v2.x * v3.y - v1.z * v2.y * v3.x - \ + v1.x * v2.z * v3.y - v1.y * v2.x * v3.z + +def intersection_ray_ray_3d( + ray1: tuple[Vec3, Vec3], + ray2: tuple[Vec3, Vec3], + double abs_tol=TOLERANCE + ) -> Sequence[Vec3]: + """ + Calculate intersection of two 3D rays, returns a 0-tuple for parallel rays, + a 1-tuple for intersecting rays and a 2-tuple for not intersecting and not + parallel rays with points of closest approach on each ray. + + Args: + ray1: first ray as tuple of two points as Vec3() objects + ray2: second ray as tuple of two points as Vec3() objects + abs_tol: absolute tolerance for comparisons + + """ + # source: http://www.realtimerendering.com/intersections.html#I304 + cdef: + Vec3 o2_o1 + double det1, det2 + Vec3 o1 = Vec3(ray1[0]) + Vec3 p1 = Vec3(ray1[1]) + Vec3 o2 = Vec3(ray2[0]) + Vec3 p2 = Vec3(ray2[1]) + Vec3 d1 = v3_normalize(v3_sub(p1, o1), 1.0) + Vec3 d2 = v3_normalize(v3_sub(p2, o2), 1.0) + Vec3 d1xd2 = v3_cross(d1, d2) + double denominator = v3_magnitude_sqr(d1xd2) + + if denominator <= abs_tol: + # ray1 is parallel to ray2 + return tuple() + else: + o2_o1 = v3_sub(o2, o1) + det1 = _determinant(o2_o1, d2, d1xd2) + det2 = _determinant(o2_o1, d1, d1xd2) + with cython.cdivision(True): # denominator check is already done + p1 = v3_add(o1, v3_mul(d1, (det1 / denominator))) + p2 = v3_add(o2, v3_mul(d2, (det2 / denominator))) + + if v3_isclose(p1, p2, abs_tol, abs_tol): + # ray1 and ray2 have an intersection point + return p1, + else: + # ray1 and ray2 do not have an intersection point, + # p1 and p2 are the points of closest approach on each ray + return p1, p2 + +def arc_angle_span_deg(double start, double end) -> float: + if isclose(start, end, REL_TOL, DEG_ABS_TOL): + return 0.0 + + start %= 360.0 + if isclose(start, end % 360.0, REL_TOL, DEG_ABS_TOL): + return 360.0 + + if not isclose(end, 360.0, REL_TOL, DEG_ABS_TOL): + end %= 360.0 + + if end < start: + end += 360.0 + return end - start + +def arc_angle_span_rad(double start, double end) -> float: + if isclose(start, end, REL_TOL, RAD_ABS_TOL): + return 0.0 + + start %= M_TAU + if isclose(start, end % M_TAU, REL_TOL, RAD_ABS_TOL): + return M_TAU + + if not isclose(end, M_TAU, REL_TOL, RAD_ABS_TOL): + end %= M_TAU + + if end < start: + end += M_TAU + return end - start + + +def is_point_in_polygon_2d( + point: Vec2, polygon: list[Vec2], double abs_tol=TOLERANCE +) -> int: + """ + Test if `point` is inside `polygon`. Returns +1 for inside, 0 for on the + boundary and -1 for outside. + + Supports convex and concave polygons with clockwise or counter-clockwise oriented + polygon vertices. Does not raise an exception for degenerated polygons. + + + Args: + point: 2D point to test as :class:`Vec2` + polygon: list of 2D points as :class:`Vec2` + abs_tol: tolerance for distance check + + Returns: + +1 for inside, 0 for on the boundary, -1 for outside + + """ + # Source: http://www.faqs.org/faqs/graphics/algorithms-faq/ + # Subject 2.03: How do I find if a point lies within a polygon? + # Numpy version was just 10x faster, this version is 23x faster than the Python + # version! + cdef double a, b, c, d, x, y, x1, y1, x2, y2 + cdef list vertices = polygon + cdef Vec2 p1, p2 + cdef int size, last, i + cdef bint inside = 0 + + size = len(vertices) + if size < 3: # empty polygon + return -1 + last = size - 1 + p1 = vertices[0] + p2 = vertices[last] + + if v2_isclose(p1, p2, REL_TOL, ABS_TOL): # open polygon + size -= 1 + last -= 1 + if size < 3: + return -1 + + x = point.x + y = point.y + p1 = vertices[last] + x1 = p1.x + y1 = p1.y + + for i in range(size): + p2 = vertices[i] + x2 = p2.x + y2 = p2.y + + # is point on polygon boundary line: + # is point in x-range of line + a, b = (x2, x1) if x2 < x1 else (x1, x2) + if a <= x <= b: + # is point in y-range of line + c, d = (y2, y1) if y2 < y1 else (y1, y2) + if (c <= y <= d) and fabs( + (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + ) <= abs_tol: + return 0 # on boundary line + if ((y1 <= y < y2) or (y2 <= y < y1)) and ( + x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + ): + inside = not inside + x1 = x2 + y1 = y2 + if inside: + return 1 # inside polygon + else: + return -1 # outside polygon + +cdef double WGS84_SEMI_MAJOR_AXIS = 6378137 +cdef double WGS84_SEMI_MINOR_AXIS = 6356752.3142 +cdef double WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 +cdef double RADIANS = M_PI / 180.0 +cdef double DEGREES = 180.0 / M_PI + + +def gps_to_world_mercator(double longitude, double latitude) -> tuple[float, float]: + """Transform GPS (long/lat) to World Mercator. + + Transform WGS84 `EPSG:4326 `_ location given as + latitude and longitude in decimal degrees as used by GPS into World Mercator + cartesian 2D coordinates in meters `EPSG:3395 `_. + + Args: + longitude: represents the longitude value (East-West) in decimal degrees + latitude: represents the latitude value (North-South) in decimal degrees. + + """ + # From: https://epsg.io/4326 + # EPSG:4326 WGS84 - World Geodetic System 1984, used in GPS + # To: https://epsg.io/3395 + # EPSG:3395 - World Mercator + # Source: https://gis.stackexchange.com/questions/259121/transformation-functions-for-epsg3395-projection-vs-epsg3857 + longitude = longitude * RADIANS # east + latitude = latitude * RADIANS # north + cdef double e_sin_lat = sin(latitude) * WGS84_ELLIPSOID_ECCENTRIC + cdef double c = pow( + (1.0 - e_sin_lat) / (1.0 + e_sin_lat), WGS84_ELLIPSOID_ECCENTRIC / 2.0 + ) # 7-7 p.44 + y = WGS84_SEMI_MAJOR_AXIS * log(tan(M_PI_4 + latitude / 2.0) * c) # 7-7 p.44 + x = WGS84_SEMI_MAJOR_AXIS * longitude + return x, y + + +def world_mercator_to_gps(double x, double y, double tol = 1e-6) -> tuple[float, float]: + """Transform World Mercator to GPS. + + Transform WGS84 World Mercator `EPSG:3395 `_ + location given as cartesian 2D coordinates x, y in meters into WGS84 decimal + degrees as longitude and latitude `EPSG:4326 `_ as + used by GPS. + + Args: + x: coordinate WGS84 World Mercator + y: coordinate WGS84 World Mercator + tol: accuracy for latitude calculation + + """ + # From: https://epsg.io/3395 + # EPSG:3395 - World Mercator + # To: https://epsg.io/4326 + # EPSG:4326 WGS84 - World Geodetic System 1984, used in GPS + # Source: Map Projections - A Working Manual + # https://pubs.usgs.gov/pp/1395/report.pdf + cdef double eccentric_2 = WGS84_ELLIPSOID_ECCENTRIC / 2.0 + cdef double t = pow(M_E, (-y / WGS84_SEMI_MAJOR_AXIS)) # 7-10 p.44 + cdef double e_sin_lat, latitude, latitude_prev + + latitude_prev = M_PI_2 - 2.0 * atan(t) # 7-11 p.45 + while True: + e_sin_lat = sin(latitude_prev) * WGS84_ELLIPSOID_ECCENTRIC + latitude = M_PI_2 - 2.0 * atan( + t * pow(((1.0 - e_sin_lat) / (1.0 + e_sin_lat)), eccentric_2) + ) # 7-9 p.44 + if fabs(latitude - latitude_prev) < tol: + break + latitude_prev = latitude + + longitude = x / WGS84_SEMI_MAJOR_AXIS # 7-12 p.45 + return longitude * DEGREES, latitude * DEGREES \ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.c new file mode 100644 index 0000000..483862d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.c @@ -0,0 +1,11553 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.linetypes", + "sources": [ + "src/ezdxf/acc/linetypes.pyx" + ] + }, + "module_name": "ezdxf.acc.linetypes" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__linetypes +#define __PYX_HAVE_API__ezdxf__acc__linetypes +/* Early includes */ +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/linetypes.pyx", + "", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer; +struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "ezdxf/acc/linetypes.pyx":20 + * + * + * cdef class _LineTypeRenderer: # <<<<<<<<<<<<<< + * cdef double *dashes + * cdef int dash_count + */ +struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_vtab; + double *dashes; + int dash_count; + int is_solid; + int is_dash; + int current_dash; + double current_dash_length; +}; + + +/* "ezdxf/acc/linetypes.pyx":50 + * PyMem_Free(self.dashes) + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: # <<<<<<<<<<<<<< + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) + */ +struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment { + PyObject_HEAD + double __pyx_v_dash_length; + PyObject *__pyx_v_dashes; + PyObject *__pyx_v_end; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_segment_dir; + double __pyx_v_segment_length; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_segment_vec; + struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self; + PyObject *__pyx_v_start; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v3_end; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v3_start; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; +}; + + + +/* "ezdxf/acc/linetypes.pyx":20 + * + * + * cdef class _LineTypeRenderer: # <<<<<<<<<<<<<< + * cdef double *dashes + * cdef int dash_count + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer { + PyObject *(*_render_dashes)(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *, double, PyObject *); + PyObject *(*_cycle_dashes)(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_vtabptr_5ezdxf_3acc_9linetypes__LineTypeRenderer; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyObjectCall2Args.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* CoroutineBase.proto */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; + PyObject *gi_weakreflist; + PyObject *classobj; + PyObject *yieldfrom; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static PyObject *__Pyx_Coroutine_Close(PyObject *self); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); + +/* PatchModuleWithCoroutine.proto */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code); + +/* PatchGeneratorABC.proto */ +static int __Pyx_patch_abc(void); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__render_dashes(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, double __pyx_v_length, PyObject *__pyx_v_dashes); /* proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__cycle_dashes(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self); /* proto*/ + +/* Module declarations from "cython" */ + +/* Module declarations from "cpython.mem" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_add)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_sub)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_mul)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static double (*__pyx_f_5ezdxf_3acc_6vector_v3_magnitude)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static int (*__pyx_f_5ezdxf_3acc_6vector_v3_isclose)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); /*proto*/ + +/* Module declarations from "ezdxf.acc.linetypes" */ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.linetypes" +extern int __pyx_module_is_main_ezdxf__acc__linetypes; +int __pyx_module_is_main_ezdxf__acc__linetypes = 0; + +/* Implementation of "ezdxf.acc.linetypes" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_TypeError; +/* #### Code section: string_decls ### */ +static const char __pyx_k__2[] = "."; +static const char __pyx_k__8[] = "?"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_all[] = "__all__"; +static const char __pyx_k_end[] = "end"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_args[] = "args"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_send[] = "send"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_close[] = "close"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_start[] = "start"; +static const char __pyx_k_throw[] = "throw"; +static const char __pyx_k_dashes[] = "dashes"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_v3_end[] = "v3_end"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_Iterator[] = "Iterator"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_v3_start[] = "v3_start"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_LineSegment[] = "LineSegment"; +static const char __pyx_k_dash_length[] = "dash_length"; +static const char __pyx_k_segment_dir[] = "segment_dir"; +static const char __pyx_k_segment_vec[] = "segment_vec"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_line_segment[] = "line_segment"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_class_getitem[] = "__class_getitem__"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_segment_length[] = "segment_length"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_LineTypeRenderer[] = "_LineTypeRenderer"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ezdxf_acc_linetypes[] = "ezdxf.acc.linetypes"; +static const char __pyx_k_Iterator_LineSegment[] = "Iterator[LineSegment]"; +static const char __pyx_k_src_ezdxf_acc_linetypes_pyx[] = "src/ezdxf/acc/linetypes.pyx"; +static const char __pyx_k_LineTypeRenderer_line_segment[] = "_LineTypeRenderer.line_segment"; +static const char __pyx_k_LineTypeRenderer___reduce_cytho[] = "_LineTypeRenderer.__reduce_cython__"; +static const char __pyx_k_LineTypeRenderer___setstate_cyt[] = "_LineTypeRenderer.__setstate_cython__"; +static const char __pyx_k_self_dashes_cannot_be_converted[] = "self.dashes cannot be converted to a Python object for pickling"; +/* #### Code section: decls ### */ +static int __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer___init__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, PyObject *__pyx_v_dashes); /* proto */ +static void __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_2__dealloc__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_4line_segment(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, PyObject *__pyx_v_start, PyObject *__pyx_v_end); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid___get__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_7__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_9__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_9linetypes__LineTypeRenderer(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer; + PyObject *__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment; + PyObject *__pyx_n_s_Iterator; + PyObject *__pyx_kp_s_Iterator_LineSegment; + PyObject *__pyx_n_s_LineSegment; + PyObject *__pyx_n_s_LineTypeRenderer; + PyObject *__pyx_n_u_LineTypeRenderer; + PyObject *__pyx_n_s_LineTypeRenderer___reduce_cytho; + PyObject *__pyx_n_s_LineTypeRenderer___setstate_cyt; + PyObject *__pyx_n_s_LineTypeRenderer_line_segment; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_kp_u__2; + PyObject *__pyx_n_s__8; + PyObject *__pyx_n_s_all; + PyObject *__pyx_n_s_args; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_class_getitem; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_close; + PyObject *__pyx_n_s_dash_length; + PyObject *__pyx_n_s_dashes; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_end; + PyObject *__pyx_n_s_ezdxf_acc_linetypes; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_line_segment; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_segment_dir; + PyObject *__pyx_n_s_segment_length; + PyObject *__pyx_n_s_segment_vec; + PyObject *__pyx_n_s_self; + PyObject *__pyx_kp_s_self_dashes_cannot_be_converted; + PyObject *__pyx_n_s_send; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_kp_s_src_ezdxf_acc_linetypes_pyx; + PyObject *__pyx_n_s_start; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_throw; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_v3_end; + PyObject *__pyx_n_s_v3_start; + PyObject *__pyx_codeobj_; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__6; + PyObject *__pyx_codeobj__5; + PyObject *__pyx_codeobj__7; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterator); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_LineSegment); + Py_CLEAR(clear_module_state->__pyx_n_s_LineSegment); + Py_CLEAR(clear_module_state->__pyx_n_s_LineTypeRenderer); + Py_CLEAR(clear_module_state->__pyx_n_u_LineTypeRenderer); + Py_CLEAR(clear_module_state->__pyx_n_s_LineTypeRenderer___reduce_cytho); + Py_CLEAR(clear_module_state->__pyx_n_s_LineTypeRenderer___setstate_cyt); + Py_CLEAR(clear_module_state->__pyx_n_s_LineTypeRenderer_line_segment); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_kp_u__2); + Py_CLEAR(clear_module_state->__pyx_n_s__8); + Py_CLEAR(clear_module_state->__pyx_n_s_all); + Py_CLEAR(clear_module_state->__pyx_n_s_args); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_class_getitem); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_close); + Py_CLEAR(clear_module_state->__pyx_n_s_dash_length); + Py_CLEAR(clear_module_state->__pyx_n_s_dashes); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_end); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_linetypes); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_line_segment); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_segment_dir); + Py_CLEAR(clear_module_state->__pyx_n_s_segment_length); + Py_CLEAR(clear_module_state->__pyx_n_s_segment_vec); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_kp_s_self_dashes_cannot_be_converted); + Py_CLEAR(clear_module_state->__pyx_n_s_send); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_linetypes_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_throw); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_v3_end); + Py_CLEAR(clear_module_state->__pyx_n_s_v3_start); + Py_CLEAR(clear_module_state->__pyx_codeobj_); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__6); + Py_CLEAR(clear_module_state->__pyx_codeobj__5); + Py_CLEAR(clear_module_state->__pyx_codeobj__7); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterator); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_LineSegment); + Py_VISIT(traverse_module_state->__pyx_n_s_LineSegment); + Py_VISIT(traverse_module_state->__pyx_n_s_LineTypeRenderer); + Py_VISIT(traverse_module_state->__pyx_n_u_LineTypeRenderer); + Py_VISIT(traverse_module_state->__pyx_n_s_LineTypeRenderer___reduce_cytho); + Py_VISIT(traverse_module_state->__pyx_n_s_LineTypeRenderer___setstate_cyt); + Py_VISIT(traverse_module_state->__pyx_n_s_LineTypeRenderer_line_segment); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_kp_u__2); + Py_VISIT(traverse_module_state->__pyx_n_s__8); + Py_VISIT(traverse_module_state->__pyx_n_s_all); + Py_VISIT(traverse_module_state->__pyx_n_s_args); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_class_getitem); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_close); + Py_VISIT(traverse_module_state->__pyx_n_s_dash_length); + Py_VISIT(traverse_module_state->__pyx_n_s_dashes); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_end); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_linetypes); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_line_segment); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_segment_dir); + Py_VISIT(traverse_module_state->__pyx_n_s_segment_length); + Py_VISIT(traverse_module_state->__pyx_n_s_segment_vec); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_kp_s_self_dashes_cannot_be_converted); + Py_VISIT(traverse_module_state->__pyx_n_s_send); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_linetypes_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_throw); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_v3_end); + Py_VISIT(traverse_module_state->__pyx_n_s_v3_start); + Py_VISIT(traverse_module_state->__pyx_codeobj_); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__6); + Py_VISIT(traverse_module_state->__pyx_codeobj__5); + Py_VISIT(traverse_module_state->__pyx_codeobj__7); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer __pyx_mstate_global->__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer +#define __pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment __pyx_mstate_global->__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment +#endif +#define __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer +#define __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment +#define __pyx_n_s_Iterator __pyx_mstate_global->__pyx_n_s_Iterator +#define __pyx_kp_s_Iterator_LineSegment __pyx_mstate_global->__pyx_kp_s_Iterator_LineSegment +#define __pyx_n_s_LineSegment __pyx_mstate_global->__pyx_n_s_LineSegment +#define __pyx_n_s_LineTypeRenderer __pyx_mstate_global->__pyx_n_s_LineTypeRenderer +#define __pyx_n_u_LineTypeRenderer __pyx_mstate_global->__pyx_n_u_LineTypeRenderer +#define __pyx_n_s_LineTypeRenderer___reduce_cytho __pyx_mstate_global->__pyx_n_s_LineTypeRenderer___reduce_cytho +#define __pyx_n_s_LineTypeRenderer___setstate_cyt __pyx_mstate_global->__pyx_n_s_LineTypeRenderer___setstate_cyt +#define __pyx_n_s_LineTypeRenderer_line_segment __pyx_mstate_global->__pyx_n_s_LineTypeRenderer_line_segment +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_kp_u__2 __pyx_mstate_global->__pyx_kp_u__2 +#define __pyx_n_s__8 __pyx_mstate_global->__pyx_n_s__8 +#define __pyx_n_s_all __pyx_mstate_global->__pyx_n_s_all +#define __pyx_n_s_args __pyx_mstate_global->__pyx_n_s_args +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_class_getitem __pyx_mstate_global->__pyx_n_s_class_getitem +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_close __pyx_mstate_global->__pyx_n_s_close +#define __pyx_n_s_dash_length __pyx_mstate_global->__pyx_n_s_dash_length +#define __pyx_n_s_dashes __pyx_mstate_global->__pyx_n_s_dashes +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_end __pyx_mstate_global->__pyx_n_s_end +#define __pyx_n_s_ezdxf_acc_linetypes __pyx_mstate_global->__pyx_n_s_ezdxf_acc_linetypes +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_line_segment __pyx_mstate_global->__pyx_n_s_line_segment +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_segment_dir __pyx_mstate_global->__pyx_n_s_segment_dir +#define __pyx_n_s_segment_length __pyx_mstate_global->__pyx_n_s_segment_length +#define __pyx_n_s_segment_vec __pyx_mstate_global->__pyx_n_s_segment_vec +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_kp_s_self_dashes_cannot_be_converted __pyx_mstate_global->__pyx_kp_s_self_dashes_cannot_be_converted +#define __pyx_n_s_send __pyx_mstate_global->__pyx_n_s_send +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_kp_s_src_ezdxf_acc_linetypes_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_linetypes_pyx +#define __pyx_n_s_start __pyx_mstate_global->__pyx_n_s_start +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_throw __pyx_mstate_global->__pyx_n_s_throw +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_v3_end __pyx_mstate_global->__pyx_n_s_v3_end +#define __pyx_n_s_v3_start __pyx_mstate_global->__pyx_n_s_v3_start +#define __pyx_codeobj_ __pyx_mstate_global->__pyx_codeobj_ +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__6 __pyx_mstate_global->__pyx_tuple__6 +#define __pyx_codeobj__5 __pyx_mstate_global->__pyx_codeobj__5 +#define __pyx_codeobj__7 __pyx_mstate_global->__pyx_codeobj__7 +/* #### Code section: module_code ### */ + +/* "ezdxf/acc/linetypes.pyx":28 + * cdef double current_dash_length + * + * def __init__(self, dashes: Sequence[float]): # <<<<<<<<<<<<<< + * cdef list _dashes = list(dashes) + * cdef int i + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_dashes = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_dashes,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dashes)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 28, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__init__") < 0)) __PYX_ERR(0, 28, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + } + __pyx_v_dashes = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 28, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer___init__(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self), __pyx_v_dashes); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer___init__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, PyObject *__pyx_v_dashes) { + PyObject *__pyx_v__dashes = 0; + int __pyx_v_i; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + double __pyx_t_6; + int __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 1); + + /* "ezdxf/acc/linetypes.pyx":29 + * + * def __init__(self, dashes: Sequence[float]): + * cdef list _dashes = list(dashes) # <<<<<<<<<<<<<< + * cdef int i + * + */ + __pyx_t_1 = PySequence_List(__pyx_v_dashes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__dashes = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":32 + * cdef int i + * + * self.dash_count = len(_dashes) # <<<<<<<<<<<<<< + * self.dashes = PyMem_Malloc(self.dash_count * sizeof(double)) + * for i in range(self.dash_count): + */ + __pyx_t_2 = __Pyx_PyList_GET_SIZE(__pyx_v__dashes); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 32, __pyx_L1_error) + __pyx_v_self->dash_count = __pyx_t_2; + + /* "ezdxf/acc/linetypes.pyx":33 + * + * self.dash_count = len(_dashes) + * self.dashes = PyMem_Malloc(self.dash_count * sizeof(double)) # <<<<<<<<<<<<<< + * for i in range(self.dash_count): + * self.dashes[i] = _dashes[i] + */ + __pyx_v_self->dashes = ((double *)PyMem_Malloc((__pyx_v_self->dash_count * (sizeof(double))))); + + /* "ezdxf/acc/linetypes.pyx":34 + * self.dash_count = len(_dashes) + * self.dashes = PyMem_Malloc(self.dash_count * sizeof(double)) + * for i in range(self.dash_count): # <<<<<<<<<<<<<< + * self.dashes[i] = _dashes[i] + * + */ + __pyx_t_3 = __pyx_v_self->dash_count; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "ezdxf/acc/linetypes.pyx":35 + * self.dashes = PyMem_Malloc(self.dash_count * sizeof(double)) + * for i in range(self.dash_count): + * self.dashes[i] = _dashes[i] # <<<<<<<<<<<<<< + * + * self.is_solid = True + */ + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v__dashes, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + (__pyx_v_self->dashes[__pyx_v_i]) = __pyx_t_6; + } + + /* "ezdxf/acc/linetypes.pyx":37 + * self.dashes[i] = _dashes[i] + * + * self.is_solid = True # <<<<<<<<<<<<<< + * self.is_dash = False + * self.current_dash = 0 + */ + __pyx_v_self->is_solid = 1; + + /* "ezdxf/acc/linetypes.pyx":38 + * + * self.is_solid = True + * self.is_dash = False # <<<<<<<<<<<<<< + * self.current_dash = 0 + * self.current_dash_length = 0.0 + */ + __pyx_v_self->is_dash = 0; + + /* "ezdxf/acc/linetypes.pyx":39 + * self.is_solid = True + * self.is_dash = False + * self.current_dash = 0 # <<<<<<<<<<<<<< + * self.current_dash_length = 0.0 + * + */ + __pyx_v_self->current_dash = 0; + + /* "ezdxf/acc/linetypes.pyx":40 + * self.is_dash = False + * self.current_dash = 0 + * self.current_dash_length = 0.0 # <<<<<<<<<<<<<< + * + * if self.dash_count > 1: + */ + __pyx_v_self->current_dash_length = 0.0; + + /* "ezdxf/acc/linetypes.pyx":42 + * self.current_dash_length = 0.0 + * + * if self.dash_count > 1: # <<<<<<<<<<<<<< + * self.is_solid = False + * self.current_dash_length = self.dashes[0] + */ + __pyx_t_7 = (__pyx_v_self->dash_count > 1); + if (__pyx_t_7) { + + /* "ezdxf/acc/linetypes.pyx":43 + * + * if self.dash_count > 1: + * self.is_solid = False # <<<<<<<<<<<<<< + * self.current_dash_length = self.dashes[0] + * self.is_dash = True + */ + __pyx_v_self->is_solid = 0; + + /* "ezdxf/acc/linetypes.pyx":44 + * if self.dash_count > 1: + * self.is_solid = False + * self.current_dash_length = self.dashes[0] # <<<<<<<<<<<<<< + * self.is_dash = True + * + */ + __pyx_v_self->current_dash_length = (__pyx_v_self->dashes[0]); + + /* "ezdxf/acc/linetypes.pyx":45 + * self.is_solid = False + * self.current_dash_length = self.dashes[0] + * self.is_dash = True # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_v_self->is_dash = 1; + + /* "ezdxf/acc/linetypes.pyx":42 + * self.current_dash_length = 0.0 + * + * if self.dash_count > 1: # <<<<<<<<<<<<<< + * self.is_solid = False + * self.current_dash_length = self.dashes[0] + */ + } + + /* "ezdxf/acc/linetypes.pyx":28 + * cdef double current_dash_length + * + * def __init__(self, dashes: Sequence[float]): # <<<<<<<<<<<<<< + * cdef list _dashes = list(dashes) + * cdef int i + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v__dashes); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/linetypes.pyx":47 + * self.is_dash = True + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * PyMem_Free(self.dashes) + * + */ + +/* Python wrapper */ +static void __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_3__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_3__dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_2__dealloc__(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_2__dealloc__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self) { + + /* "ezdxf/acc/linetypes.pyx":48 + * + * def __dealloc__(self): + * PyMem_Free(self.dashes) # <<<<<<<<<<<<<< + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: + */ + PyMem_Free(__pyx_v_self->dashes); + + /* "ezdxf/acc/linetypes.pyx":47 + * self.is_dash = True + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * PyMem_Free(self.dashes) + * + */ + + /* function exit code */ +} +static PyObject *__pyx_gb_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_6generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/linetypes.pyx":50 + * PyMem_Free(self.dashes) + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: # <<<<<<<<<<<<<< + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment = {"line_segment", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_start = 0; + PyObject *__pyx_v_end = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("line_segment (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_start,&__pyx_n_s_end,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_start)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 50, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_end)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 50, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("line_segment", 1, 2, 2, 1); __PYX_ERR(0, 50, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "line_segment") < 0)) __PYX_ERR(0, 50, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_start = values[0]; + __pyx_v_end = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("line_segment", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 50, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.line_segment", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_4line_segment(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self), __pyx_v_start, __pyx_v_end); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_4line_segment(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, PyObject *__pyx_v_start, PyObject *__pyx_v_end) { + struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("line_segment", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)__pyx_tp_new_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment(__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 50, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_start = __pyx_v_start; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_start); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_start); + __pyx_cur_scope->__pyx_v_end = __pyx_v_end; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_end); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_end); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_6generator, __pyx_codeobj_, (PyObject *) __pyx_cur_scope, __pyx_n_s_line_segment, __pyx_n_s_LineTypeRenderer_line_segment, __pyx_n_s_ezdxf_acc_linetypes); if (unlikely(!gen)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.line_segment", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_6generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + double __pyx_t_4; + Py_ssize_t __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("line_segment", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L7_resume_from_yield; + case 2: goto __pyx_L11_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 50, __pyx_L1_error) + + /* "ezdxf/acc/linetypes.pyx":51 + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: + * cdef Vec3 v3_start = Vec3(start) # <<<<<<<<<<<<<< + * cdef Vec3 v3_end = Vec3(end) + * cdef Vec3 segment_vec, segment_dir + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_start); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_v3_start = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":52 + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) # <<<<<<<<<<<<<< + * cdef Vec3 segment_vec, segment_dir + * cdef double segment_length, dash_length + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_end); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 52, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_v3_end = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":55 + * cdef Vec3 segment_vec, segment_dir + * cdef double segment_length, dash_length + * cdef list dashes = [] # <<<<<<<<<<<<<< + * + * if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_dashes = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":57 + * cdef list dashes = [] + * + * if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * yield v3_start, v3_end + * return + */ + if (!__pyx_cur_scope->__pyx_v_self->is_solid) { + } else { + __pyx_t_2 = __pyx_cur_scope->__pyx_v_self->is_solid; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_cur_scope->__pyx_v_v3_start, __pyx_cur_scope->__pyx_v_v3_end, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 57, __pyx_L1_error) + __pyx_t_2 = __pyx_t_3; + __pyx_L5_bool_binop_done:; + if (__pyx_t_2) { + + /* "ezdxf/acc/linetypes.pyx":58 + * + * if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): + * yield v3_start, v3_end # <<<<<<<<<<<<<< + * return + * + */ + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_start); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_start); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_cur_scope->__pyx_v_v3_start))) __PYX_ERR(0, 58, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_cur_scope->__pyx_v_v3_end))) __PYX_ERR(0, 58, __pyx_L1_error); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L7_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 58, __pyx_L1_error) + + /* "ezdxf/acc/linetypes.pyx":59 + * if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): + * yield v3_start, v3_end + * return # <<<<<<<<<<<<<< + * + * segment_vec = v3_sub(v3_end, v3_start) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = NULL; + goto __pyx_L0; + + /* "ezdxf/acc/linetypes.pyx":57 + * cdef list dashes = [] + * + * if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): # <<<<<<<<<<<<<< + * yield v3_start, v3_end + * return + */ + } + + /* "ezdxf/acc/linetypes.pyx":61 + * return + * + * segment_vec = v3_sub(v3_end, v3_start) # <<<<<<<<<<<<<< + * segment_length = v3_magnitude(segment_vec) + * with cython.cdivision: + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_cur_scope->__pyx_v_v3_end, __pyx_cur_scope->__pyx_v_v3_start)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_segment_vec = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":62 + * + * segment_vec = v3_sub(v3_end, v3_start) + * segment_length = v3_magnitude(segment_vec) # <<<<<<<<<<<<<< + * with cython.cdivision: + * segment_dir = v3_mul(segment_vec, 1.0 / segment_length) # normalize + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(__pyx_cur_scope->__pyx_v_segment_vec); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 62, __pyx_L1_error) + __pyx_cur_scope->__pyx_v_segment_length = __pyx_t_4; + + /* "ezdxf/acc/linetypes.pyx":64 + * segment_length = v3_magnitude(segment_vec) + * with cython.cdivision: + * segment_dir = v3_mul(segment_vec, 1.0 / segment_length) # normalize # <<<<<<<<<<<<<< + * + * self._render_dashes(segment_length, dashes) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_cur_scope->__pyx_v_segment_vec, (1.0 / __pyx_cur_scope->__pyx_v_segment_length))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_segment_dir = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":66 + * segment_dir = v3_mul(segment_vec, 1.0 / segment_length) # normalize + * + * self._render_dashes(segment_length, dashes) # <<<<<<<<<<<<<< + * for dash_length in dashes: + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_cur_scope->__pyx_v_self->__pyx_vtab)->_render_dashes(__pyx_cur_scope->__pyx_v_self, __pyx_cur_scope->__pyx_v_segment_length, __pyx_cur_scope->__pyx_v_dashes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/linetypes.pyx":67 + * + * self._render_dashes(segment_length, dashes) + * for dash_length in dashes: # <<<<<<<<<<<<<< + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + * if dash_length > 0: + */ + __pyx_t_1 = __pyx_cur_scope->__pyx_v_dashes; __Pyx_INCREF(__pyx_t_1); + __pyx_t_5 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 67, __pyx_L1_error) + #endif + if (__pyx_t_5 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_6 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_6); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 67, __pyx_L1_error) + #else + __pyx_t_6 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + #endif + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_6); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_cur_scope->__pyx_v_dash_length = __pyx_t_4; + + /* "ezdxf/acc/linetypes.pyx":68 + * self._render_dashes(segment_length, dashes) + * for dash_length in dashes: + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) # <<<<<<<<<<<<<< + * if dash_length > 0: + * yield v3_start, v3_end + */ + __pyx_t_6 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_cur_scope->__pyx_v_segment_dir, fabs(__pyx_cur_scope->__pyx_v_dash_length))); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(__pyx_cur_scope->__pyx_v_v3_start, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_6))); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_v3_end, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_7)); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "ezdxf/acc/linetypes.pyx":69 + * for dash_length in dashes: + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + * if dash_length > 0: # <<<<<<<<<<<<<< + * yield v3_start, v3_end + * v3_start = v3_end + */ + __pyx_t_2 = (__pyx_cur_scope->__pyx_v_dash_length > 0.0); + if (__pyx_t_2) { + + /* "ezdxf/acc/linetypes.pyx":70 + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + * if dash_length > 0: + * yield v3_start, v3_end # <<<<<<<<<<<<<< + * v3_start = v3_end + * + */ + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_start); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_start); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_cur_scope->__pyx_v_v3_start))) __PYX_ERR(0, 70, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_cur_scope->__pyx_v_v3_end))) __PYX_ERR(0, 70, __pyx_L1_error); + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_5; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 2; + return __pyx_r; + __pyx_L11_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_5 = __pyx_cur_scope->__pyx_t_1; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 70, __pyx_L1_error) + + /* "ezdxf/acc/linetypes.pyx":69 + * for dash_length in dashes: + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + * if dash_length > 0: # <<<<<<<<<<<<<< + * yield v3_start, v3_end + * v3_start = v3_end + */ + } + + /* "ezdxf/acc/linetypes.pyx":71 + * if dash_length > 0: + * yield v3_start, v3_end + * v3_start = v3_end # <<<<<<<<<<<<<< + * + * cdef _render_dashes(self, double length, list dashes): + */ + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + __Pyx_GOTREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_start); + __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_v3_start, __pyx_cur_scope->__pyx_v_v3_end); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_v3_end); + + /* "ezdxf/acc/linetypes.pyx":67 + * + * self._render_dashes(segment_length, dashes) + * for dash_length in dashes: # <<<<<<<<<<<<<< + * v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + * if dash_length > 0: + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/linetypes.pyx":50 + * PyMem_Free(self.dashes) + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: # <<<<<<<<<<<<<< + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("line_segment", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/linetypes.pyx":73 + * v3_start = v3_end + * + * cdef _render_dashes(self, double length, list dashes): # <<<<<<<<<<<<<< + * if length <= self.current_dash_length: + * self.current_dash_length -= length + */ + +static PyObject *__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__render_dashes(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, double __pyx_v_length, PyObject *__pyx_v_dashes) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_render_dashes", 1); + + /* "ezdxf/acc/linetypes.pyx":74 + * + * cdef _render_dashes(self, double length, list dashes): + * if length <= self.current_dash_length: # <<<<<<<<<<<<<< + * self.current_dash_length -= length + * dashes.append(length if self.is_dash else -length) + */ + __pyx_t_1 = (__pyx_v_length <= __pyx_v_self->current_dash_length); + if (__pyx_t_1) { + + /* "ezdxf/acc/linetypes.pyx":75 + * cdef _render_dashes(self, double length, list dashes): + * if length <= self.current_dash_length: + * self.current_dash_length -= length # <<<<<<<<<<<<<< + * dashes.append(length if self.is_dash else -length) + * if self.current_dash_length < ABS_TOL: + */ + __pyx_v_self->current_dash_length = (__pyx_v_self->current_dash_length - __pyx_v_length); + + /* "ezdxf/acc/linetypes.pyx":76 + * if length <= self.current_dash_length: + * self.current_dash_length -= length + * dashes.append(length if self.is_dash else -length) # <<<<<<<<<<<<<< + * if self.current_dash_length < ABS_TOL: + * self._cycle_dashes() + */ + if (unlikely(__pyx_v_dashes == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append"); + __PYX_ERR(0, 76, __pyx_L1_error) + } + if (__pyx_v_self->is_dash) { + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_length); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __pyx_t_3; + __pyx_t_3 = 0; + } else { + __pyx_t_3 = PyFloat_FromDouble((-__pyx_v_length)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __pyx_t_3; + __pyx_t_3 = 0; + } + __pyx_t_4 = __Pyx_PyList_Append(__pyx_v_dashes, __pyx_t_2); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":77 + * self.current_dash_length -= length + * dashes.append(length if self.is_dash else -length) + * if self.current_dash_length < ABS_TOL: # <<<<<<<<<<<<<< + * self._cycle_dashes() + * else: + */ + __pyx_t_1 = (__pyx_v_self->current_dash_length < ABS_TOL); + if (__pyx_t_1) { + + /* "ezdxf/acc/linetypes.pyx":78 + * dashes.append(length if self.is_dash else -length) + * if self.current_dash_length < ABS_TOL: + * self._cycle_dashes() # <<<<<<<<<<<<<< + * else: + * # Avoid deep recursions! + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self->__pyx_vtab)->_cycle_dashes(__pyx_v_self); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":77 + * self.current_dash_length -= length + * dashes.append(length if self.is_dash else -length) + * if self.current_dash_length < ABS_TOL: # <<<<<<<<<<<<<< + * self._cycle_dashes() + * else: + */ + } + + /* "ezdxf/acc/linetypes.pyx":74 + * + * cdef _render_dashes(self, double length, list dashes): + * if length <= self.current_dash_length: # <<<<<<<<<<<<<< + * self.current_dash_length -= length + * dashes.append(length if self.is_dash else -length) + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/linetypes.pyx":81 + * else: + * # Avoid deep recursions! + * while length > self.current_dash_length: # <<<<<<<<<<<<<< + * length -= self.current_dash_length + * self._render_dashes(self.current_dash_length, dashes) + */ + /*else*/ { + while (1) { + __pyx_t_1 = (__pyx_v_length > __pyx_v_self->current_dash_length); + if (!__pyx_t_1) break; + + /* "ezdxf/acc/linetypes.pyx":82 + * # Avoid deep recursions! + * while length > self.current_dash_length: + * length -= self.current_dash_length # <<<<<<<<<<<<<< + * self._render_dashes(self.current_dash_length, dashes) + * if length > 0.0: + */ + __pyx_v_length = (__pyx_v_length - __pyx_v_self->current_dash_length); + + /* "ezdxf/acc/linetypes.pyx":83 + * while length > self.current_dash_length: + * length -= self.current_dash_length + * self._render_dashes(self.current_dash_length, dashes) # <<<<<<<<<<<<<< + * if length > 0.0: + * self._render_dashes(length, dashes) + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self->__pyx_vtab)->_render_dashes(__pyx_v_self, __pyx_v_self->current_dash_length, __pyx_v_dashes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + + /* "ezdxf/acc/linetypes.pyx":84 + * length -= self.current_dash_length + * self._render_dashes(self.current_dash_length, dashes) + * if length > 0.0: # <<<<<<<<<<<<<< + * self._render_dashes(length, dashes) + * + */ + __pyx_t_1 = (__pyx_v_length > 0.0); + if (__pyx_t_1) { + + /* "ezdxf/acc/linetypes.pyx":85 + * self._render_dashes(self.current_dash_length, dashes) + * if length > 0.0: + * self._render_dashes(length, dashes) # <<<<<<<<<<<<<< + * + * cdef _cycle_dashes(self): + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self->__pyx_vtab)->_render_dashes(__pyx_v_self, __pyx_v_length, __pyx_v_dashes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 85, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":84 + * length -= self.current_dash_length + * self._render_dashes(self.current_dash_length, dashes) + * if length > 0.0: # <<<<<<<<<<<<<< + * self._render_dashes(length, dashes) + * + */ + } + } + __pyx_L3:; + + /* "ezdxf/acc/linetypes.pyx":73 + * v3_start = v3_end + * + * cdef _render_dashes(self, double length, list dashes): # <<<<<<<<<<<<<< + * if length <= self.current_dash_length: + * self.current_dash_length -= length + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer._render_dashes", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/linetypes.pyx":87 + * self._render_dashes(length, dashes) + * + * cdef _cycle_dashes(self): # <<<<<<<<<<<<<< + * with cython.cdivision: + * self.current_dash = (self.current_dash + 1) % self.dash_count + */ + +static PyObject *__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__cycle_dashes(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_cycle_dashes", 1); + + /* "ezdxf/acc/linetypes.pyx":89 + * cdef _cycle_dashes(self): + * with cython.cdivision: + * self.current_dash = (self.current_dash + 1) % self.dash_count # <<<<<<<<<<<<<< + * self.current_dash_length = self.dashes[self.current_dash] + * self.is_dash = not self.is_dash + */ + __pyx_v_self->current_dash = ((__pyx_v_self->current_dash + 1) % __pyx_v_self->dash_count); + + /* "ezdxf/acc/linetypes.pyx":90 + * with cython.cdivision: + * self.current_dash = (self.current_dash + 1) % self.dash_count + * self.current_dash_length = self.dashes[self.current_dash] # <<<<<<<<<<<<<< + * self.is_dash = not self.is_dash + */ + __pyx_v_self->current_dash_length = (__pyx_v_self->dashes[__pyx_v_self->current_dash]); + + /* "ezdxf/acc/linetypes.pyx":91 + * self.current_dash = (self.current_dash + 1) % self.dash_count + * self.current_dash_length = self.dashes[self.current_dash] + * self.is_dash = not self.is_dash # <<<<<<<<<<<<<< + */ + __pyx_v_self->is_dash = (!__pyx_v_self->is_dash); + + /* "ezdxf/acc/linetypes.pyx":87 + * self._render_dashes(length, dashes) + * + * cdef _cycle_dashes(self): # <<<<<<<<<<<<<< + * with cython.cdivision: + * self.current_dash = (self.current_dash + 1) % self.dash_count + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/linetypes.pyx":23 + * cdef double *dashes + * cdef int dash_count + * cdef readonly bint is_solid # <<<<<<<<<<<<<< + * cdef bint is_dash + * cdef int current_dash + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid___get__(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid___get__(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_v_self->is_solid); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.is_solid.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_7__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_7__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_self_dashes_cannot_be_converted, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_9__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_9__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_self_dashes_cannot_be_converted, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.linetypes._LineTypeRenderer.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static struct __pyx_vtabstruct_5ezdxf_3acc_9linetypes__LineTypeRenderer __pyx_vtable_5ezdxf_3acc_9linetypes__LineTypeRenderer; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_9linetypes__LineTypeRenderer(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_9linetypes__LineTypeRenderer; + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_9linetypes__LineTypeRenderer(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_9linetypes__LineTypeRenderer) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_3__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_is_solid(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8is_solid_1__get__(o); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_9linetypes__LineTypeRenderer[] = { + {"line_segment", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_9linetypes__LineTypeRenderer[] = { + {(char *)"is_solid", __pyx_getprop_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_is_solid, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_9linetypes__LineTypeRenderer}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_9linetypes__LineTypeRenderer}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_9linetypes__LineTypeRenderer}, + {Py_tp_init, (void *)__pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_1__init__}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_9linetypes__LineTypeRenderer}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer_spec = { + "ezdxf.acc.linetypes._LineTypeRenderer", + sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.linetypes.""_LineTypeRenderer", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_9linetypes__LineTypeRenderer, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_9linetypes__LineTypeRenderer, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_9linetypes__LineTypeRenderer, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + __pyx_pw_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_1__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_9linetypes__LineTypeRenderer, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *__pyx_freelist_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment[8]; +static int __pyx_freecount_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment[--__pyx_freecount_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *p = (struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_dashes); + Py_CLEAR(p->__pyx_v_end); + Py_CLEAR(p->__pyx_v_segment_dir); + Py_CLEAR(p->__pyx_v_segment_vec); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_v_start); + Py_CLEAR(p->__pyx_v_v3_end); + Py_CLEAR(p->__pyx_v_v3_start); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment)))) { + __pyx_freelist_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment[__pyx_freecount_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment++] = ((struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *p = (struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment *)o; + if (p->__pyx_v_dashes) { + e = (*v)(p->__pyx_v_dashes, a); if (e) return e; + } + if (p->__pyx_v_end) { + e = (*v)(p->__pyx_v_end, a); if (e) return e; + } + if (p->__pyx_v_segment_dir) { + e = (*v)(((PyObject *)p->__pyx_v_segment_dir), a); if (e) return e; + } + if (p->__pyx_v_segment_vec) { + e = (*v)(((PyObject *)p->__pyx_v_segment_vec), a); if (e) return e; + } + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_v_start) { + e = (*v)(p->__pyx_v_start, a); if (e) return e; + } + if (p->__pyx_v_v3_end) { + e = (*v)(((PyObject *)p->__pyx_v_v3_end), a); if (e) return e; + } + if (p->__pyx_v_v3_start) { + e = (*v)(((PyObject *)p->__pyx_v_v3_start), a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment_spec = { + "ezdxf.acc.linetypes.__pyx_scope_struct__line_segment", + sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.linetypes.""__pyx_scope_struct__line_segment", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_Iterator, __pyx_k_Iterator, sizeof(__pyx_k_Iterator), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterator_LineSegment, __pyx_k_Iterator_LineSegment, sizeof(__pyx_k_Iterator_LineSegment), 0, 0, 1, 0}, + {&__pyx_n_s_LineSegment, __pyx_k_LineSegment, sizeof(__pyx_k_LineSegment), 0, 0, 1, 1}, + {&__pyx_n_s_LineTypeRenderer, __pyx_k_LineTypeRenderer, sizeof(__pyx_k_LineTypeRenderer), 0, 0, 1, 1}, + {&__pyx_n_u_LineTypeRenderer, __pyx_k_LineTypeRenderer, sizeof(__pyx_k_LineTypeRenderer), 0, 1, 0, 1}, + {&__pyx_n_s_LineTypeRenderer___reduce_cytho, __pyx_k_LineTypeRenderer___reduce_cytho, sizeof(__pyx_k_LineTypeRenderer___reduce_cytho), 0, 0, 1, 1}, + {&__pyx_n_s_LineTypeRenderer___setstate_cyt, __pyx_k_LineTypeRenderer___setstate_cyt, sizeof(__pyx_k_LineTypeRenderer___setstate_cyt), 0, 0, 1, 1}, + {&__pyx_n_s_LineTypeRenderer_line_segment, __pyx_k_LineTypeRenderer_line_segment, sizeof(__pyx_k_LineTypeRenderer_line_segment), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_kp_u__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0, 0}, + {&__pyx_n_s__8, __pyx_k__8, sizeof(__pyx_k__8), 0, 0, 1, 1}, + {&__pyx_n_s_all, __pyx_k_all, sizeof(__pyx_k_all), 0, 0, 1, 1}, + {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_class_getitem, __pyx_k_class_getitem, sizeof(__pyx_k_class_getitem), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1}, + {&__pyx_n_s_dash_length, __pyx_k_dash_length, sizeof(__pyx_k_dash_length), 0, 0, 1, 1}, + {&__pyx_n_s_dashes, __pyx_k_dashes, sizeof(__pyx_k_dashes), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_end, __pyx_k_end, sizeof(__pyx_k_end), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_linetypes, __pyx_k_ezdxf_acc_linetypes, sizeof(__pyx_k_ezdxf_acc_linetypes), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_line_segment, __pyx_k_line_segment, sizeof(__pyx_k_line_segment), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_segment_dir, __pyx_k_segment_dir, sizeof(__pyx_k_segment_dir), 0, 0, 1, 1}, + {&__pyx_n_s_segment_length, __pyx_k_segment_length, sizeof(__pyx_k_segment_length), 0, 0, 1, 1}, + {&__pyx_n_s_segment_vec, __pyx_k_segment_vec, sizeof(__pyx_k_segment_vec), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_kp_s_self_dashes_cannot_be_converted, __pyx_k_self_dashes_cannot_be_converted, sizeof(__pyx_k_self_dashes_cannot_be_converted), 0, 0, 1, 0}, + {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_linetypes_pyx, __pyx_k_src_ezdxf_acc_linetypes_pyx, sizeof(__pyx_k_src_ezdxf_acc_linetypes_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_v3_end, __pyx_k_v3_end, sizeof(__pyx_k_v3_end), 0, 0, 1, 1}, + {&__pyx_n_s_v3_start, __pyx_k_v3_start, sizeof(__pyx_k_v3_start), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 34, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/linetypes.pyx":50 + * PyMem_Free(self.dashes) + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: # <<<<<<<<<<<<<< + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) + */ + __pyx_tuple__3 = PyTuple_Pack(10, __pyx_n_s_self, __pyx_n_s_start, __pyx_n_s_end, __pyx_n_s_v3_start, __pyx_n_s_v3_end, __pyx_n_s_segment_vec, __pyx_n_s_segment_dir, __pyx_n_s_segment_length, __pyx_n_s_dash_length, __pyx_n_s_dashes); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + __pyx_codeobj_ = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_linetypes_pyx, __pyx_n_s_line_segment, 50, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj_)) __PYX_ERR(0, 50, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + __pyx_codeobj__5 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__4, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__5)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + */ + __pyx_tuple__6 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_pyx_state); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__6); + __Pyx_GIVEREF(__pyx_tuple__6); + __pyx_codeobj__7 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__6, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__7)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_vtabptr_5ezdxf_3acc_9linetypes__LineTypeRenderer = &__pyx_vtable_5ezdxf_3acc_9linetypes__LineTypeRenderer; + __pyx_vtable_5ezdxf_3acc_9linetypes__LineTypeRenderer._render_dashes = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *, double, PyObject *))__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__render_dashes; + __pyx_vtable_5ezdxf_3acc_9linetypes__LineTypeRenderer._cycle_dashes = (PyObject *(*)(struct __pyx_obj_5ezdxf_3acc_9linetypes__LineTypeRenderer *))__pyx_f_5ezdxf_3acc_9linetypes_17_LineTypeRenderer__cycle_dashes; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer)) __PYX_ERR(0, 20, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer_spec, __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer = &__pyx_type_5ezdxf_3acc_9linetypes__LineTypeRenderer; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer, __pyx_vtabptr_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_LineTypeRenderer, (PyObject *) __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment)) __PYX_ERR(0, 50, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment_spec, __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment = &__pyx_type_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_9linetypes___pyx_scope_struct__line_segment->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_add", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_sub", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_sub, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_mul", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_magnitude", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_magnitude, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_linetypes(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_linetypes}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "linetypes", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initlinetypes(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initlinetypes(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_linetypes(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_linetypes(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_linetypes(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'linetypes' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("linetypes", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "linetypes" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_linetypes(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__linetypes) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.linetypes")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.linetypes", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/linetypes.pyx":4 + * # Copyright (c) 2022-2024, Manfred Moitzi + * # License: MIT License + * from typing import Iterator, TYPE_CHECKING, Sequence # <<<<<<<<<<<<<< + * import cython + * from cpython.mem cimport PyMem_Malloc, PyMem_Free + */ + __pyx_t_2 = PyList_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_Iterator); + __Pyx_GIVEREF(__pyx_n_s_Iterator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_Iterator)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterator); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterator, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/linetypes.pyx":9 + * from .vector cimport Vec3, v3_isclose, v3_sub, v3_add, v3_mul, v3_magnitude + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 9, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "ezdxf/acc/linetypes.pyx":10 + * + * if TYPE_CHECKING: + * from ezdxf.math import UVec # <<<<<<<<<<<<<< + * + * __all__ = ["_LineTypeRenderer"] + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_UVec)) __PYX_ERR(0, 10, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_UVec); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_3) < 0) __PYX_ERR(0, 10, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":9 + * from .vector cimport Vec3, v3_isclose, v3_sub, v3_add, v3_mul, v3_magnitude + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + } + + /* "ezdxf/acc/linetypes.pyx":12 + * from ezdxf.math import UVec + * + * __all__ = ["_LineTypeRenderer"] # <<<<<<<<<<<<<< + * LineSegment = tuple[Vec3, Vec3] + * + */ + __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_u_LineTypeRenderer); + __Pyx_GIVEREF(__pyx_n_u_LineTypeRenderer); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_u_LineTypeRenderer)) __PYX_ERR(0, 12, __pyx_L1_error); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_all, __pyx_t_2) < 0) __PYX_ERR(0, 12, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":13 + * + * __all__ = ["_LineTypeRenderer"] + * LineSegment = tuple[Vec3, Vec3] # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3))) __PYX_ERR(0, 13, __pyx_L1_error); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3))) __PYX_ERR(0, 13, __pyx_L1_error); + __pyx_t_3 = __Pyx_PyObject_GetItem(((PyObject *)(&PyTuple_Type)), __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_LineSegment, __pyx_t_3) < 0) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/linetypes.pyx":50 + * PyMem_Free(self.dashes) + * + * def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: # <<<<<<<<<<<<<< + * cdef Vec3 v3_start = Vec3(start) + * cdef Vec3 v3_end = Vec3(end) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_start, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_end, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Iterator_LineSegment) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_5line_segment, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_LineTypeRenderer_line_segment, NULL, __pyx_n_s_ezdxf_acc_linetypes, __pyx_d, ((PyObject *)__pyx_codeobj_)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer, __pyx_n_s_line_segment, __pyx_t_2) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_9linetypes__LineTypeRenderer); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_8__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_LineTypeRenderer___reduce_cytho, NULL, __pyx_n_s_ezdxf_acc_linetypes, __pyx_d, ((PyObject *)__pyx_codeobj__5)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "self.dashes cannot be converted to a Python object for pickling" + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_9linetypes_17_LineTypeRenderer_10__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_LineTypeRenderer___setstate_cyt, NULL, __pyx_n_s_ezdxf_acc_linetypes, __pyx_d, ((PyObject *)__pyx_codeobj__7)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_2) < 0) __PYX_ERR(1, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/linetypes.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2022-2024, Manfred Moitzi + * # License: MIT License + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.linetypes", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.linetypes"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc; + __Pyx_PyThreadState_declare + #ifdef __Pyx_StopAsyncIteration_USED + int is_async_stopiteration = 0; + #endif + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + cur_exc = PyErr_Occurred(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + #ifdef __Pyx_StopAsyncIteration_USED + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else + #endif + return; + } + __Pyx_PyThreadState_assign + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + PyErr_SetString(PyExc_RuntimeError, + #ifdef __Pyx_StopAsyncIteration_USED + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + #endif + "generator raised StopIteration"); +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__2); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* ObjectGetItem */ +#if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject *index) { + PyObject *runerr = NULL; + Py_ssize_t key_value; + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + __Pyx_TypeName index_type_name = __Pyx_PyType_GetName(Py_TYPE(index)); + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, + "cannot fit '" __Pyx_FMT_TYPENAME "' into an index-sized integer", index_type_name); + __Pyx_DECREF_TypeName(index_type_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem_Slow(PyObject *obj, PyObject *key) { + __Pyx_TypeName obj_type_name; + if (likely(PyType_Check(obj))) { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(obj, __pyx_n_s_class_getitem); + if (!meth) { + PyErr_Clear(); + } else { + PyObject *result = __Pyx_PyObject_CallOneArg(meth, key); + Py_DECREF(meth); + return result; + } + } + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "'" __Pyx_FMT_TYPENAME "' object is not subscriptable", obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key) { + PyTypeObject *tp = Py_TYPE(obj); + PyMappingMethods *mm = tp->tp_as_mapping; + PySequenceMethods *sm = tp->tp_as_sequence; + if (likely(mm && mm->mp_subscript)) { + return mm->mp_subscript(obj, key); + } + if (likely(sm && sm->sq_item)) { + return __Pyx_PyObject_GetIndex(obj, key); + } + return __Pyx_PyObject_GetItem_Slow(obj, key); +} +#endif + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__8); + } + return name; +} +#endif + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; iexc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* PyObjectCall2Args */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 */ +#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2 + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_GetMethod; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* CoroutineBase */ +#include +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } +#if PY_VERSION_HEX >= 0x030300A0 + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); + } +#endif + else if (unlikely(PyTuple_Check(ev))) { + if (PyTuple_GET_SIZE(ev) >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#else + value = PySequence_ITEM(ev, 0); +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if PY_VERSION_HEX >= 0x030300A0 + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); +#else + { + PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args); + Py_DECREF(ev); + if (likely(args)) { + value = PySequence_GetItem(args, 0); + Py_DECREF(args); + } + if (unlikely(!value)) { + __Pyx_ErrRestore(NULL, NULL, NULL); + Py_INCREF(Py_None); + value = Py_None; + } + } +#endif + *pvalue = value; + return 0; +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +#define __Pyx_Coroutine_NotStartedError(gen) (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_NotStartedError(PyObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(gen)) { + msg = "can't send non-None value to a just-started coroutine"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a just-started async generator"; + #endif + } else { + msg = "can't send non-None value to a just-started generator"; + } + PyErr_SetString(PyExc_TypeError, msg); +} +#define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing) (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(!self->is_running); + if (unlikely(self->resume_label == 0)) { + if (unlikely(value && value != Py_None)) { + return __Pyx_Coroutine_NotStartedError((PyObject*)self); + } + } + if (unlikely(self->resume_label == -1)) { + return __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + self->is_running = 1; + retval = self->body(self, tstate, value); + self->is_running = 0; +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + return retval; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_MethodReturn(PyObject* gen, PyObject *retval) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (unlikely(!retval)) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (!__Pyx_PyErr_Occurred()) { + PyObject *exc = PyExc_StopIteration; + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + exc = __Pyx_PyExc_StopAsyncIteration; + #endif + __Pyx_PyErr_SetNone(exc); + } + } + return retval; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) { + PyObject *ret; + PyObject *val = NULL; + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + ret = __Pyx_Coroutine_SendEx(gen, val, 0); + Py_XDECREF(val); + return ret; +} +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03050000 && defined(PyCoro_CheckExact) && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + { + if (value == Py_None) + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + else + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value); + } + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + retval = __Pyx_Coroutine_FinishDelegation(gen); + } else { + retval = __Pyx_Coroutine_SendEx(gen, value, 0); + } + return __Pyx_Coroutine_MethodReturn(self, retval); +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + PyObject *retval = NULL; + int err = 0; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + retval = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf, NULL); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + } else + #endif + { + PyObject *meth; + gen->is_running = 1; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) + err = -1; + } + gen->is_running = 0; + } + Py_XDECREF(retval); + return err; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + return __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_SendEx(gen, Py_None, 0); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + return __Pyx_Coroutine_Close(self); +} +static PyObject *__Pyx_Coroutine_Close(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *retval, *raised_exception; + PyObject *yf = gen->yieldfrom; + int err = 0; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = __Pyx_Coroutine_SendEx(gen, NULL, 1); + if (unlikely(retval)) { + const char *msg; + Py_DECREF(retval); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { +#if PY_VERSION_HEX < 0x03060000 + msg = "async generator ignored GeneratorExit - might require Python 3.6+ finalisation (PEP 525)"; +#else + msg = "async generator ignored GeneratorExit"; +#endif + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + return NULL; + } + raised_exception = PyErr_Occurred(); + if (likely(!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration))) { + if (raised_exception) PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); + goto throw_here; + } + gen->is_running = 1; + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + gen->is_running = 0; + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + gen->is_running = 0; + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + gen->is_running = 0; + Py_DECREF(yf); + if (!ret) { + ret = __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_MethodReturn(self, ret); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + Py_CLEAR(gen->yieldfrom); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if PY_VERSION_HEX >= 0x030400a1 && CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + Py_TYPE(gen)->tp_del(self); + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } +#if !CYTHON_USE_TP_FINALIZE + assert(self->ob_refcnt == 0); + __Pyx_SET_REFCNT(self, 1); +#endif + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); +#if PY_MAJOR_VERSION >= 3 || defined(PyErr_WarnFormat) + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); +#else + {PyObject *msg; + char *cmsg; + #if CYTHON_COMPILING_IN_PYPY + msg = NULL; + cmsg = (char*) "coroutine was never awaited"; + #else + char *cname; + PyObject *qualname; + qualname = gen->gi_qualname; + cname = PyString_AS_STRING(qualname); + msg = PyString_FromFormat("coroutine '%.50s' was never awaited", cname); + if (unlikely(!msg)) { + PyErr_Clear(); + cmsg = (char*) "coroutine was never awaited"; + } else { + cmsg = PyString_AS_STRING(msg); + } + #endif + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, cmsg, 1) < 0)) + PyErr_WriteUnraisable(self); + Py_XDECREF(msg);} +#endif + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *res = __Pyx_Coroutine_Close(self); + if (unlikely(!res)) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +#if !CYTHON_USE_TP_FINALIZE + assert(Py_REFCNT(self) > 0); + if (likely(--self->ob_refcnt == 0)) { + return; + } + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReference(self); + __Pyx_SET_REFCNT(self, refcnt); + } +#if CYTHON_COMPILING_IN_CPYTHON + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + _Py_DEC_REFTOTAL; +#endif +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif +#endif +} +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) +{ + PyObject *frame = self->gi_frame; + CYTHON_UNUSED_VAR(context); + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (unlikely(!frame)) + return NULL; + self->gi_frame = frame; + } + Py_INCREF(frame); + return frame; +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif + gen->gi_weakreflist = NULL; + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} + +/* PatchModuleWithCoroutine */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + int result; + PyObject *globals, *result_obj; + globals = PyDict_New(); if (unlikely(!globals)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_coroutine_type", + #ifdef __Pyx_Coroutine_USED + (PyObject*)__pyx_CoroutineType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_generator_type", + #ifdef __Pyx_Generator_USED + (PyObject*)__pyx_GeneratorType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore; + result_obj = PyRun_String(py_code, Py_file_input, globals, globals); + if (unlikely(!result_obj)) goto ignore; + Py_DECREF(result_obj); + Py_DECREF(globals); + return module; +ignore: + Py_XDECREF(globals); + PyErr_WriteUnraisable(module); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) { + Py_DECREF(module); + module = NULL; + } +#else + py_code++; +#endif + return module; +} + +/* PatchGeneratorABC */ +#ifndef CYTHON_REGISTER_ABCS +#define CYTHON_REGISTER_ABCS 1 +#endif +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) +static PyObject* __Pyx_patch_abc_module(PyObject *module); +static PyObject* __Pyx_patch_abc_module(PyObject *module) { + module = __Pyx_Coroutine_patch_module( + module, "" +"if _cython_generator_type is not None:\n" +" try: Generator = _module.Generator\n" +" except AttributeError: pass\n" +" else: Generator.register(_cython_generator_type)\n" +"if _cython_coroutine_type is not None:\n" +" try: Coroutine = _module.Coroutine\n" +" except AttributeError: pass\n" +" else: Coroutine.register(_cython_coroutine_type)\n" + ); + return module; +} +#endif +static int __Pyx_patch_abc(void) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + static int abc_patched = 0; + if (CYTHON_REGISTER_ABCS && !abc_patched) { + PyObject *module; + module = PyImport_ImportModule((PY_MAJOR_VERSION >= 3) ? "collections.abc" : "collections"); + if (unlikely(!module)) { + PyErr_WriteUnraisable(NULL); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, + ((PY_MAJOR_VERSION >= 3) ? + "Cython module failed to register with collections.abc module" : + "Cython module failed to register with collections module"), 1) < 0)) { + return -1; + } + } else { + module = __Pyx_patch_abc_module(module); + abc_patched = 1; + if (unlikely(!module)) + return -1; + Py_DECREF(module); + } + module = PyImport_ImportModule("backports_abc"); + if (module) { + module = __Pyx_patch_abc_module(module); + Py_XDECREF(module); + } + if (!module) { + PyErr_Clear(); + } + } +#else + if ((0)) __Pyx_Coroutine_patch_module(NULL, NULL); +#endif + return 0; +} + +/* Generator */ +static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL}, + {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, + {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + (char*) PyDoc_STR("name of the generator"), 0}, + {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + (char*) PyDoc_STR("qualified name of the generator"), 0}, + {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + (char*) PyDoc_STR("Frame of the generator"), 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + __pyx_GeneratorType_slots +}; +#else +static PyTypeObject __pyx_GeneratorType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + (destructor) __Pyx_Coroutine_dealloc, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + 0, + (traverseproc) __Pyx_Coroutine_traverse, + 0, + 0, + offsetof(__pyx_CoroutineObject, gi_weakreflist), + 0, + (iternextfunc) __Pyx_Generator_Next, + __pyx_Generator_methods, + __pyx_Generator_memberlist, + __pyx_Generator_getsets, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if CYTHON_USE_TP_FINALIZE + 0, +#else + __Pyx_Coroutine_del, +#endif + 0, +#if CYTHON_USE_TP_FINALIZE + __Pyx_Coroutine_del, +#elif PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; + __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif + if (unlikely(!__pyx_GeneratorType)) { + return -1; + } + return 0; +} + +/* CheckBinaryVersion */ +static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ +#ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.cpython-312-darwin.so new file mode 100755 index 0000000..9541385 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.pyx new file mode 100644 index 0000000..d0b570e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/linetypes.pyx @@ -0,0 +1,91 @@ +# cython: language_level=3 +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from typing import Iterator, TYPE_CHECKING, Sequence +import cython +from cpython.mem cimport PyMem_Malloc, PyMem_Free +from .vector cimport Vec3, v3_isclose, v3_sub, v3_add, v3_mul, v3_magnitude + +if TYPE_CHECKING: + from ezdxf.math import UVec + +__all__ = ["_LineTypeRenderer"] +LineSegment = tuple[Vec3, Vec3] + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + + +cdef class _LineTypeRenderer: + cdef double *dashes + cdef int dash_count + cdef readonly bint is_solid + cdef bint is_dash + cdef int current_dash + cdef double current_dash_length + + def __init__(self, dashes: Sequence[float]): + cdef list _dashes = list(dashes) + cdef int i + + self.dash_count = len(_dashes) + self.dashes = PyMem_Malloc(self.dash_count * sizeof(double)) + for i in range(self.dash_count): + self.dashes[i] = _dashes[i] + + self.is_solid = True + self.is_dash = False + self.current_dash = 0 + self.current_dash_length = 0.0 + + if self.dash_count > 1: + self.is_solid = False + self.current_dash_length = self.dashes[0] + self.is_dash = True + + def __dealloc__(self): + PyMem_Free(self.dashes) + + def line_segment(self, start: UVec, end: UVec) -> Iterator[LineSegment]: + cdef Vec3 v3_start = Vec3(start) + cdef Vec3 v3_end = Vec3(end) + cdef Vec3 segment_vec, segment_dir + cdef double segment_length, dash_length + cdef list dashes = [] + + if self.is_solid or v3_isclose(v3_start, v3_end, REL_TOL, ABS_TOL): + yield v3_start, v3_end + return + + segment_vec = v3_sub(v3_end, v3_start) + segment_length = v3_magnitude(segment_vec) + with cython.cdivision: + segment_dir = v3_mul(segment_vec, 1.0 / segment_length) # normalize + + self._render_dashes(segment_length, dashes) + for dash_length in dashes: + v3_end = v3_add(v3_start, v3_mul(segment_dir, abs(dash_length))) + if dash_length > 0: + yield v3_start, v3_end + v3_start = v3_end + + cdef _render_dashes(self, double length, list dashes): + if length <= self.current_dash_length: + self.current_dash_length -= length + dashes.append(length if self.is_dash else -length) + if self.current_dash_length < ABS_TOL: + self._cycle_dashes() + else: + # Avoid deep recursions! + while length > self.current_dash_length: + length -= self.current_dash_length + self._render_dashes(self.current_dash_length, dashes) + if length > 0.0: + self._render_dashes(length, dashes) + + cdef _cycle_dashes(self): + with cython.cdivision: + self.current_dash = (self.current_dash + 1) % self.dash_count + self.current_dash_length = self.dashes[self.current_dash] + self.is_dash = not self.is_dash diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.c new file mode 100644 index 0000000..a3649f5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.c @@ -0,0 +1,16206 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [], + "name": "ezdxf.acc.mapbox_earcut", + "sources": [ + "src/ezdxf/acc/mapbox_earcut.pyx" + ] + }, + "module_name": "ezdxf.acc.mapbox_earcut" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__mapbox_earcut +#define __PYX_HAVE_API__ezdxf__acc__mapbox_earcut +/* Early includes */ +#include +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "", + "src/ezdxf/acc/mapbox_earcut.pyx", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node; +struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points; + +/* "ezdxf/acc/mapbox_earcut.pyx":312 + * + * + * cdef Node filter_points(Node start, Node end = None): # <<<<<<<<<<<<<< + * """eliminate colinear or duplicate points""" + * cdef: + */ +struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points { + int __pyx_n; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *end; +}; + +/* "ezdxf/acc/mapbox_earcut.pyx":26 + * + * + * cdef class Node: # <<<<<<<<<<<<<< + * cdef: + * int i + */ +struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_vtab; + int i; + double x; + double y; + int z; + int steiner; + PyObject *point; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *prev; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *next; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *prev_z; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *next_z; +}; + + + +struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node { + int (*equals)(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_vtabptr_5ezdxf_3acc_13mapbox_earcut_Node; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_4Node_equals(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_other); /* proto*/ + +/* Module declarations from "libc.math" */ + +/* Module declarations from "ezdxf.acc.mapbox_earcut" */ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_linked_list(PyObject *, int, int); /*proto*/ +static double __pyx_f_5ezdxf_3acc_13mapbox_earcut_signed_area(PyObject *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_valid_diagonal(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects_polygon(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(double); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_insert_node(int, PyObject *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_holes(PyObject *, int, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_hole(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points *__pyx_optional_args); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, PyObject *, double, double, double, int); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear_hashed(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, double, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_get_leftmost(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(double, double, double, double, double, double, double, double); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_sector_contains_sector(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_index_curve(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, double, double, double); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_z_order(double, double, double, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_sort_linked(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_polygon(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_cure_local_intersections(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, PyObject *); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_ear_cut(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, PyObject *, double, double, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_find_hole_bridge(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_middle_inside(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.mapbox_earcut" +extern int __pyx_module_is_main_ezdxf__acc__mapbox_earcut; +int __pyx_module_is_main_ezdxf__acc__mapbox_earcut = 0; + +/* Implementation of "ezdxf.acc.mapbox_earcut" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_reversed; +static PyObject *__pyx_builtin_range; +/* #### Code section: string_decls ### */ +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k__9[] = "?"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_key[] = "key"; +static const char __pyx_k_Node[] = "Node"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_node[] = "node"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_sort[] = "sort"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_holes[] = "holes"; +static const char __pyx_k_max_x[] = "max_x"; +static const char __pyx_k_max_y[] = "max_y"; +static const char __pyx_k_min_x[] = "min_x"; +static const char __pyx_k_min_y[] = "min_y"; +static const char __pyx_k_point[] = "point"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_earcut[] = "earcut"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_exterior[] = "exterior"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_inv_size[] = "inv_size"; +static const char __pyx_k_node_key[] = "node_key"; +static const char __pyx_k_reversed[] = "reversed"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_triangles[] = "triangles"; +static const char __pyx_k_outer_node[] = "outer_node"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_Node___reduce_cython[] = "Node.__reduce_cython__"; +static const char __pyx_k_Node___setstate_cython[] = "Node.__setstate_cython__"; +static const char __pyx_k_ezdxf_acc_mapbox_earcut[] = "ezdxf.acc.mapbox_earcut"; +static const char __pyx_k_src_ezdxf_acc_mapbox_earcut_pyx[] = "src/ezdxf/acc/mapbox_earcut.pyx"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +/* #### Code section: decls ### */ +static int __pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node___cinit__(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, int __pyx_v_i, PyObject *__pyx_v_point); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_node_key(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_node); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_2earcut(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_exterior, PyObject *__pyx_v_holes); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_13mapbox_earcut_Node(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node; + PyObject *__pyx_n_s_Node; + PyObject *__pyx_n_s_Node___reduce_cython; + PyObject *__pyx_n_s_Node___setstate_cython; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s__9; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_earcut; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_exterior; + PyObject *__pyx_n_s_ezdxf_acc_mapbox_earcut; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_n_s_holes; + PyObject *__pyx_n_s_i; + PyObject *__pyx_n_s_inv_size; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_key; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_max_x; + PyObject *__pyx_n_s_max_y; + PyObject *__pyx_n_s_min_x; + PyObject *__pyx_n_s_min_y; + PyObject *__pyx_n_s_name; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_node; + PyObject *__pyx_n_s_node_key; + PyObject *__pyx_n_s_outer_node; + PyObject *__pyx_n_s_point; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_reversed; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_sort; + PyObject *__pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_triangles; + PyObject *__pyx_n_s_x; + PyObject *__pyx_n_s_y; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__3; + PyObject *__pyx_tuple__5; + PyObject *__pyx_tuple__7; + PyObject *__pyx_codeobj__2; + PyObject *__pyx_codeobj__4; + PyObject *__pyx_codeobj__6; + PyObject *__pyx_codeobj__8; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node); + Py_CLEAR(clear_module_state->__pyx_n_s_Node); + Py_CLEAR(clear_module_state->__pyx_n_s_Node___reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_Node___setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s__9); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_earcut); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_exterior); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_mapbox_earcut); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_n_s_holes); + Py_CLEAR(clear_module_state->__pyx_n_s_i); + Py_CLEAR(clear_module_state->__pyx_n_s_inv_size); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_key); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_max_x); + Py_CLEAR(clear_module_state->__pyx_n_s_max_y); + Py_CLEAR(clear_module_state->__pyx_n_s_min_x); + Py_CLEAR(clear_module_state->__pyx_n_s_min_y); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_node); + Py_CLEAR(clear_module_state->__pyx_n_s_node_key); + Py_CLEAR(clear_module_state->__pyx_n_s_outer_node); + Py_CLEAR(clear_module_state->__pyx_n_s_point); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_reversed); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_sort); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_triangles); + Py_CLEAR(clear_module_state->__pyx_n_s_x); + Py_CLEAR(clear_module_state->__pyx_n_s_y); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__3); + Py_CLEAR(clear_module_state->__pyx_tuple__5); + Py_CLEAR(clear_module_state->__pyx_tuple__7); + Py_CLEAR(clear_module_state->__pyx_codeobj__2); + Py_CLEAR(clear_module_state->__pyx_codeobj__4); + Py_CLEAR(clear_module_state->__pyx_codeobj__6); + Py_CLEAR(clear_module_state->__pyx_codeobj__8); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node); + Py_VISIT(traverse_module_state->__pyx_n_s_Node); + Py_VISIT(traverse_module_state->__pyx_n_s_Node___reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_Node___setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s__9); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_earcut); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_exterior); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_mapbox_earcut); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_n_s_holes); + Py_VISIT(traverse_module_state->__pyx_n_s_i); + Py_VISIT(traverse_module_state->__pyx_n_s_inv_size); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_key); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_max_x); + Py_VISIT(traverse_module_state->__pyx_n_s_max_y); + Py_VISIT(traverse_module_state->__pyx_n_s_min_x); + Py_VISIT(traverse_module_state->__pyx_n_s_min_y); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_node); + Py_VISIT(traverse_module_state->__pyx_n_s_node_key); + Py_VISIT(traverse_module_state->__pyx_n_s_outer_node); + Py_VISIT(traverse_module_state->__pyx_n_s_point); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_reversed); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_sort); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_triangles); + Py_VISIT(traverse_module_state->__pyx_n_s_x); + Py_VISIT(traverse_module_state->__pyx_n_s_y); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__3); + Py_VISIT(traverse_module_state->__pyx_tuple__5); + Py_VISIT(traverse_module_state->__pyx_tuple__7); + Py_VISIT(traverse_module_state->__pyx_codeobj__2); + Py_VISIT(traverse_module_state->__pyx_codeobj__4); + Py_VISIT(traverse_module_state->__pyx_codeobj__6); + Py_VISIT(traverse_module_state->__pyx_codeobj__8); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_13mapbox_earcut_Node __pyx_mstate_global->__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node +#endif +#define __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node +#define __pyx_n_s_Node __pyx_mstate_global->__pyx_n_s_Node +#define __pyx_n_s_Node___reduce_cython __pyx_mstate_global->__pyx_n_s_Node___reduce_cython +#define __pyx_n_s_Node___setstate_cython __pyx_mstate_global->__pyx_n_s_Node___setstate_cython +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s__9 __pyx_mstate_global->__pyx_n_s__9 +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_earcut __pyx_mstate_global->__pyx_n_s_earcut +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_exterior __pyx_mstate_global->__pyx_n_s_exterior +#define __pyx_n_s_ezdxf_acc_mapbox_earcut __pyx_mstate_global->__pyx_n_s_ezdxf_acc_mapbox_earcut +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_n_s_holes __pyx_mstate_global->__pyx_n_s_holes +#define __pyx_n_s_i __pyx_mstate_global->__pyx_n_s_i +#define __pyx_n_s_inv_size __pyx_mstate_global->__pyx_n_s_inv_size +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_key __pyx_mstate_global->__pyx_n_s_key +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_max_x __pyx_mstate_global->__pyx_n_s_max_x +#define __pyx_n_s_max_y __pyx_mstate_global->__pyx_n_s_max_y +#define __pyx_n_s_min_x __pyx_mstate_global->__pyx_n_s_min_x +#define __pyx_n_s_min_y __pyx_mstate_global->__pyx_n_s_min_y +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_node __pyx_mstate_global->__pyx_n_s_node +#define __pyx_n_s_node_key __pyx_mstate_global->__pyx_n_s_node_key +#define __pyx_n_s_outer_node __pyx_mstate_global->__pyx_n_s_outer_node +#define __pyx_n_s_point __pyx_mstate_global->__pyx_n_s_point +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_reversed __pyx_mstate_global->__pyx_n_s_reversed +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_sort __pyx_mstate_global->__pyx_n_s_sort +#define __pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_triangles __pyx_mstate_global->__pyx_n_s_triangles +#define __pyx_n_s_x __pyx_mstate_global->__pyx_n_s_x +#define __pyx_n_s_y __pyx_mstate_global->__pyx_n_s_y +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__3 __pyx_mstate_global->__pyx_tuple__3 +#define __pyx_tuple__5 __pyx_mstate_global->__pyx_tuple__5 +#define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7 +#define __pyx_codeobj__2 __pyx_mstate_global->__pyx_codeobj__2 +#define __pyx_codeobj__4 __pyx_mstate_global->__pyx_codeobj__4 +#define __pyx_codeobj__6 __pyx_mstate_global->__pyx_codeobj__6 +#define __pyx_codeobj__8 __pyx_mstate_global->__pyx_codeobj__8 +/* #### Code section: module_code ### */ + +/* "ezdxf/acc/mapbox_earcut.pyx":39 + * Node next_z + * + * def __cinit__(self, int i, object point): # <<<<<<<<<<<<<< + * self.i = i + * self.point = point + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_v_i; + PyObject *__pyx_v_point = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_i,&__pyx_n_s_point,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_i)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 39, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_point)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 39, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, 1); __PYX_ERR(1, 39, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(1, 39, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + } + __pyx_v_i = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_i == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 39, __pyx_L3_error) + __pyx_v_point = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 2, 2, __pyx_nargs); __PYX_ERR(1, 39, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.Node.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node___cinit__(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_self), __pyx_v_i, __pyx_v_point); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node___cinit__(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, int __pyx_v_i, PyObject *__pyx_v_point) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":40 + * + * def __cinit__(self, int i, object point): + * self.i = i # <<<<<<<<<<<<<< + * self.point = point + * self.x = point.x + */ + __pyx_v_self->i = __pyx_v_i; + + /* "ezdxf/acc/mapbox_earcut.pyx":41 + * def __cinit__(self, int i, object point): + * self.i = i + * self.point = point # <<<<<<<<<<<<<< + * self.x = point.x + * self.y = point.y + */ + __Pyx_INCREF(__pyx_v_point); + __Pyx_GIVEREF(__pyx_v_point); + __Pyx_GOTREF(__pyx_v_self->point); + __Pyx_DECREF(__pyx_v_self->point); + __pyx_v_self->point = __pyx_v_point; + + /* "ezdxf/acc/mapbox_earcut.pyx":42 + * self.i = i + * self.point = point + * self.x = point.x # <<<<<<<<<<<<<< + * self.y = point.y + * self.z = 0 + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_self->x = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":43 + * self.point = point + * self.x = point.x + * self.y = point.y # <<<<<<<<<<<<<< + * self.z = 0 + * self.steiner = False + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 43, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 43, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_self->y = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":44 + * self.x = point.x + * self.y = point.y + * self.z = 0 # <<<<<<<<<<<<<< + * self.steiner = False + * self.prev = None + */ + __pyx_v_self->z = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":45 + * self.y = point.y + * self.z = 0 + * self.steiner = False # <<<<<<<<<<<<<< + * self.prev = None + * self.next = None + */ + __pyx_v_self->steiner = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":46 + * self.z = 0 + * self.steiner = False + * self.prev = None # <<<<<<<<<<<<<< + * self.next = None + * self.prev_z = None + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_self->prev); + __Pyx_DECREF((PyObject *)__pyx_v_self->prev); + __pyx_v_self->prev = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":47 + * self.steiner = False + * self.prev = None + * self.next = None # <<<<<<<<<<<<<< + * self.prev_z = None + * self.next_z = None + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_self->next); + __Pyx_DECREF((PyObject *)__pyx_v_self->next); + __pyx_v_self->next = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":48 + * self.prev = None + * self.next = None + * self.prev_z = None # <<<<<<<<<<<<<< + * self.next_z = None + * + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_self->prev_z); + __Pyx_DECREF((PyObject *)__pyx_v_self->prev_z); + __pyx_v_self->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":49 + * self.next = None + * self.prev_z = None + * self.next_z = None # <<<<<<<<<<<<<< + * + * cdef bint equals(self, Node other): + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_self->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_self->next_z); + __pyx_v_self->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":39 + * Node next_z + * + * def __cinit__(self, int i, object point): # <<<<<<<<<<<<<< + * self.i = i + * self.point = point + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.Node.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":51 + * self.next_z = None + * + * cdef bint equals(self, Node other): # <<<<<<<<<<<<<< + * return self.x == other.x and self.y == other.y + * + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_4Node_equals(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_other) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":52 + * + * cdef bint equals(self, Node other): + * return self.x == other.x and self.y == other.y # <<<<<<<<<<<<<< + * + * def node_key(Node node): + */ + __pyx_t_2 = (__pyx_v_self->x == __pyx_v_other->x); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_self->y == __pyx_v_other->y); + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":51 + * self.next_z = None + * + * cdef bint equals(self, Node other): # <<<<<<<<<<<<<< + * return self.x == other.x and self.y == other.y + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__ = {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_2__reduce_cython__(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(0, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.Node.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__ = {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(0, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.Node.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_4__setstate_cython__(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_4Node_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(0, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.Node.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":54 + * return self.x == other.x and self.y == other.y + * + * def node_key(Node node): # <<<<<<<<<<<<<< + * return node.x, node.y + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_1node_key(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_13mapbox_earcut_1node_key = {"node_key", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_1node_key, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_1node_key(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_node = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("node_key (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_node,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_node)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 54, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "node_key") < 0)) __PYX_ERR(1, 54, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_node = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("node_key", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 54, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.node_key", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_node), __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node, 1, "node", 0))) __PYX_ERR(1, 54, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_13mapbox_earcut_node_key(__pyx_self, __pyx_v_node); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_node_key(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_node) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("node_key", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":55 + * + * def node_key(Node node): + * return node.x, node.y # <<<<<<<<<<<<<< + * + * def earcut(list exterior, list holes): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_node->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_node->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(1, 55, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(1, 55, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":54 + * return self.x == other.x and self.y == other.y + * + * def node_key(Node node): # <<<<<<<<<<<<<< + * return node.x, node.y + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.node_key", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":57 + * return node.x, node.y + * + * def earcut(list exterior, list holes): # <<<<<<<<<<<<<< + * """Implements a modified ear slicing algorithm, optimized by z-order + * curve hashing and extended to handle holes, twisted polygons, degeneracies + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_3earcut(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_13mapbox_earcut_2earcut, "Implements a modified ear slicing algorithm, optimized by z-order\n curve hashing and extended to handle holes, twisted polygons, degeneracies\n and self-intersections in a way that doesn't guarantee correctness of\n triangulation, but attempts to always produce acceptable results for\n practical data.\n\n Source: https://github.com/mapbox/earcut\n\n Args:\n exterior: outer path as list of points as objects which provide a\n `x`- and a `y`-attribute\n holes: list of holes, each hole is list of points, a hole with\n a single points is a Steiner point\n\n Returns:\n Returns a list of triangles, each triangle is a tuple of three points,\n the output points are the same objects as the input points.\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_13mapbox_earcut_3earcut = {"earcut", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_3earcut, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_13mapbox_earcut_2earcut}; +static PyObject *__pyx_pw_5ezdxf_3acc_13mapbox_earcut_3earcut(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_exterior = 0; + PyObject *__pyx_v_holes = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("earcut (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_exterior,&__pyx_n_s_holes,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_exterior)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 57, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_holes)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 57, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("earcut", 1, 2, 2, 1); __PYX_ERR(1, 57, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "earcut") < 0)) __PYX_ERR(1, 57, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_exterior = ((PyObject*)values[0]); + __pyx_v_holes = ((PyObject*)values[1]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("earcut", 1, 2, 2, __pyx_nargs); __PYX_ERR(1, 57, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.earcut", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_exterior), (&PyList_Type), 1, "exterior", 1))) __PYX_ERR(1, 57, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_holes), (&PyList_Type), 1, "holes", 1))) __PYX_ERR(1, 57, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_13mapbox_earcut_2earcut(__pyx_self, __pyx_v_exterior, __pyx_v_holes); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_13mapbox_earcut_2earcut(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_exterior, PyObject *__pyx_v_holes) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_outer_node = 0; + PyObject *__pyx_v_triangles = 0; + double __pyx_v_max_x; + double __pyx_v_max_y; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_min_x; + double __pyx_v_min_y; + double __pyx_v_inv_size; + PyObject *__pyx_v_point = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + Py_ssize_t __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + double __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("earcut", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":79 + * cdef: + * Node outer_node + * list triangles = [] # <<<<<<<<<<<<<< + * double max_x, max_y, x, y + * double min_x = 0.0 + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 79, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_triangles = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":81 + * list triangles = [] + * double max_x, max_y, x, y + * double min_x = 0.0 # <<<<<<<<<<<<<< + * double min_y = 0.0 + * double inv_size = 0.0 + */ + __pyx_v_min_x = 0.0; + + /* "ezdxf/acc/mapbox_earcut.pyx":82 + * double max_x, max_y, x, y + * double min_x = 0.0 + * double min_y = 0.0 # <<<<<<<<<<<<<< + * double inv_size = 0.0 + * + */ + __pyx_v_min_y = 0.0; + + /* "ezdxf/acc/mapbox_earcut.pyx":83 + * double min_x = 0.0 + * double min_y = 0.0 + * double inv_size = 0.0 # <<<<<<<<<<<<<< + * + * if not exterior: + */ + __pyx_v_inv_size = 0.0; + + /* "ezdxf/acc/mapbox_earcut.pyx":85 + * double inv_size = 0.0 + * + * if not exterior: # <<<<<<<<<<<<<< + * return triangles + * + */ + __pyx_t_2 = (__pyx_v_exterior != Py_None)&&(PyList_GET_SIZE(__pyx_v_exterior) != 0); + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":86 + * + * if not exterior: + * return triangles # <<<<<<<<<<<<<< + * + * outer_node = linked_list(exterior, 0, ccw=True) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_triangles); + __pyx_r = __pyx_v_triangles; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":85 + * double inv_size = 0.0 + * + * if not exterior: # <<<<<<<<<<<<<< + * return triangles + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":88 + * return triangles + * + * outer_node = linked_list(exterior, 0, ccw=True) # <<<<<<<<<<<<<< + * if outer_node is None or outer_node.next is outer_node.prev: + * return triangles + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_linked_list(__pyx_v_exterior, 0, 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_outer_node = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":89 + * + * outer_node = linked_list(exterior, 0, ccw=True) + * if outer_node is None or outer_node.next is outer_node.prev: # <<<<<<<<<<<<<< + * return triangles + * + */ + __pyx_t_2 = (((PyObject *)__pyx_v_outer_node) == Py_None); + if (!__pyx_t_2) { + } else { + __pyx_t_3 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_outer_node->next == __pyx_v_outer_node->prev); + __pyx_t_3 = __pyx_t_2; + __pyx_L5_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":90 + * outer_node = linked_list(exterior, 0, ccw=True) + * if outer_node is None or outer_node.next is outer_node.prev: + * return triangles # <<<<<<<<<<<<<< + * + * if holes: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_triangles); + __pyx_r = __pyx_v_triangles; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":89 + * + * outer_node = linked_list(exterior, 0, ccw=True) + * if outer_node is None or outer_node.next is outer_node.prev: # <<<<<<<<<<<<<< + * return triangles + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":92 + * return triangles + * + * if holes: # <<<<<<<<<<<<<< + * outer_node = eliminate_holes(holes, len(exterior), outer_node) + * + */ + __pyx_t_3 = (__pyx_v_holes != Py_None)&&(PyList_GET_SIZE(__pyx_v_holes) != 0); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":93 + * + * if holes: + * outer_node = eliminate_holes(holes, len(exterior), outer_node) # <<<<<<<<<<<<<< + * + * # if the shape is not too simple, we'll use z-order curve hash later + */ + if (unlikely(__pyx_v_exterior == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 93, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_v_exterior); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 93, __pyx_L1_error) + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_holes(__pyx_v_holes, __pyx_t_4, __pyx_v_outer_node)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_outer_node, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":92 + * return triangles + * + * if holes: # <<<<<<<<<<<<<< + * outer_node = eliminate_holes(holes, len(exterior), outer_node) + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":97 + * # if the shape is not too simple, we'll use z-order curve hash later + * # calculate polygon bbox + * if len(exterior) > 80: # <<<<<<<<<<<<<< + * min_x = max_x = exterior[0].x + * min_y = max_y = exterior[0].y + */ + if (unlikely(__pyx_v_exterior == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 97, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_v_exterior); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 97, __pyx_L1_error) + __pyx_t_3 = (__pyx_t_4 > 80); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":98 + * # calculate polygon bbox + * if len(exterior) > 80: + * min_x = max_x = exterior[0].x # <<<<<<<<<<<<<< + * min_y = max_y = exterior[0].y + * for point in exterior: + */ + if (unlikely(__pyx_v_exterior == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 98, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_exterior, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_x); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_min_x = __pyx_t_6; + __pyx_v_max_x = __pyx_t_6; + + /* "ezdxf/acc/mapbox_earcut.pyx":99 + * if len(exterior) > 80: + * min_x = max_x = exterior[0].x + * min_y = max_y = exterior[0].y # <<<<<<<<<<<<<< + * for point in exterior: + * x = point.x + */ + if (unlikely(__pyx_v_exterior == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 99, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_GetItemInt_List(__pyx_v_exterior, 0, long, 1, __Pyx_PyInt_From_long, 1, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 99, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 99, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_1); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 99, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_min_y = __pyx_t_6; + __pyx_v_max_y = __pyx_t_6; + + /* "ezdxf/acc/mapbox_earcut.pyx":100 + * min_x = max_x = exterior[0].x + * min_y = max_y = exterior[0].y + * for point in exterior: # <<<<<<<<<<<<<< + * x = point.x + * y = point.y + */ + if (unlikely(__pyx_v_exterior == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 100, __pyx_L1_error) + } + __pyx_t_1 = __pyx_v_exterior; __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 100, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_5); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(1, 100, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_XDECREF_SET(__pyx_v_point, __pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":101 + * min_y = max_y = exterior[0].y + * for point in exterior: + * x = point.x # <<<<<<<<<<<<<< + * y = point.y + * min_x = fmin(min_x, x) + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_x); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 101, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_x = __pyx_t_6; + + /* "ezdxf/acc/mapbox_earcut.pyx":102 + * for point in exterior: + * x = point.x + * y = point.y # <<<<<<<<<<<<<< + * min_x = fmin(min_x, x) + * min_y = fmin(min_y, y) + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_y); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 102, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_y = __pyx_t_6; + + /* "ezdxf/acc/mapbox_earcut.pyx":103 + * x = point.x + * y = point.y + * min_x = fmin(min_x, x) # <<<<<<<<<<<<<< + * min_y = fmin(min_y, y) + * max_x = fmax(max_x, x) + */ + __pyx_v_min_x = fmin(__pyx_v_min_x, __pyx_v_x); + + /* "ezdxf/acc/mapbox_earcut.pyx":104 + * y = point.y + * min_x = fmin(min_x, x) + * min_y = fmin(min_y, y) # <<<<<<<<<<<<<< + * max_x = fmax(max_x, x) + * max_y = fmax(max_y, y) + */ + __pyx_v_min_y = fmin(__pyx_v_min_y, __pyx_v_y); + + /* "ezdxf/acc/mapbox_earcut.pyx":105 + * min_x = fmin(min_x, x) + * min_y = fmin(min_y, y) + * max_x = fmax(max_x, x) # <<<<<<<<<<<<<< + * max_y = fmax(max_y, y) + * + */ + __pyx_v_max_x = fmax(__pyx_v_max_x, __pyx_v_x); + + /* "ezdxf/acc/mapbox_earcut.pyx":106 + * min_y = fmin(min_y, y) + * max_x = fmax(max_x, x) + * max_y = fmax(max_y, y) # <<<<<<<<<<<<<< + * + * # min_x, min_y and inv_size are later used to transform coords into + */ + __pyx_v_max_y = fmax(__pyx_v_max_y, __pyx_v_y); + + /* "ezdxf/acc/mapbox_earcut.pyx":100 + * min_x = max_x = exterior[0].x + * min_y = max_y = exterior[0].y + * for point in exterior: # <<<<<<<<<<<<<< + * x = point.x + * y = point.y + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":110 + * # min_x, min_y and inv_size are later used to transform coords into + * # integers for z-order calculation + * inv_size = fmax(max_x - min_x, max_y - min_y) # <<<<<<<<<<<<<< + * inv_size = 32767 / inv_size if inv_size != 0 else 0 + * + */ + __pyx_v_inv_size = fmax((__pyx_v_max_x - __pyx_v_min_x), (__pyx_v_max_y - __pyx_v_min_y)); + + /* "ezdxf/acc/mapbox_earcut.pyx":111 + * # integers for z-order calculation + * inv_size = fmax(max_x - min_x, max_y - min_y) + * inv_size = 32767 / inv_size if inv_size != 0 else 0 # <<<<<<<<<<<<<< + * + * earcut_linked(outer_node, triangles, min_x, min_y, inv_size, 0) + */ + __pyx_t_3 = (__pyx_v_inv_size != 0.0); + if (__pyx_t_3) { + if (unlikely(__pyx_v_inv_size == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(1, 111, __pyx_L1_error) + } + __pyx_t_6 = (32767.0 / __pyx_v_inv_size); + } else { + __pyx_t_6 = 0.0; + } + __pyx_v_inv_size = __pyx_t_6; + + /* "ezdxf/acc/mapbox_earcut.pyx":97 + * # if the shape is not too simple, we'll use z-order curve hash later + * # calculate polygon bbox + * if len(exterior) > 80: # <<<<<<<<<<<<<< + * min_x = max_x = exterior[0].x + * min_y = max_y = exterior[0].y + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":113 + * inv_size = 32767 / inv_size if inv_size != 0 else 0 + * + * earcut_linked(outer_node, triangles, min_x, min_y, inv_size, 0) # <<<<<<<<<<<<<< + * return triangles + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(__pyx_v_outer_node, __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":114 + * + * earcut_linked(outer_node, triangles, min_x, min_y, inv_size, 0) + * return triangles # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_triangles); + __pyx_r = __pyx_v_triangles; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":57 + * return node.x, node.y + * + * def earcut(list exterior, list holes): # <<<<<<<<<<<<<< + * """Implements a modified ear slicing algorithm, optimized by z-order + * curve hashing and extended to handle holes, twisted polygons, degeneracies + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.earcut", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_outer_node); + __Pyx_XDECREF(__pyx_v_triangles); + __Pyx_XDECREF(__pyx_v_point); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":117 + * + * + * cdef Node linked_list(list points, int start, bint ccw): # <<<<<<<<<<<<<< + * """Create a circular doubly linked list from polygon points in the specified + * winding order + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_linked_list(PyObject *__pyx_v_points, int __pyx_v_start, int __pyx_v_ccw) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_last = 0; + int __pyx_v_end; + PyObject *__pyx_v_point = NULL; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("linked_list", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":122 + * """ + * cdef: + * Node last = None # <<<<<<<<<<<<<< + * int end + * + */ + __Pyx_INCREF(Py_None); + __pyx_v_last = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":125 + * int end + * + * if ccw is (signed_area(points) < 0): # <<<<<<<<<<<<<< + * for point in points: + * last = insert_node(start, point, last) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_signed_area(__pyx_v_points); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 125, __pyx_L1_error) + __pyx_t_2 = (__pyx_v_ccw == (__pyx_t_1 < 0.0)); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":126 + * + * if ccw is (signed_area(points) < 0): + * for point in points: # <<<<<<<<<<<<<< + * last = insert_node(start, point, last) + * start += 1 + */ + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 126, __pyx_L1_error) + } + __pyx_t_3 = __pyx_v_points; __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 126, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_5); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(1, 126, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_XDECREF_SET(__pyx_v_point, __pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":127 + * if ccw is (signed_area(points) < 0): + * for point in points: + * last = insert_node(start, point, last) # <<<<<<<<<<<<<< + * start += 1 + * else: + */ + __pyx_t_5 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_insert_node(__pyx_v_start, __pyx_v_point, __pyx_v_last)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_last, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":128 + * for point in points: + * last = insert_node(start, point, last) + * start += 1 # <<<<<<<<<<<<<< + * else: + * end = start + len(points) + */ + __pyx_v_start = (__pyx_v_start + 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":126 + * + * if ccw is (signed_area(points) < 0): + * for point in points: # <<<<<<<<<<<<<< + * last = insert_node(start, point, last) + * start += 1 + */ + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":125 + * int end + * + * if ccw is (signed_area(points) < 0): # <<<<<<<<<<<<<< + * for point in points: + * last = insert_node(start, point, last) + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":130 + * start += 1 + * else: + * end = start + len(points) # <<<<<<<<<<<<<< + * for point in reversed(points): + * last = insert_node(end, point, last) + */ + /*else*/ { + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 130, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_v_points); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 130, __pyx_L1_error) + __pyx_v_end = (__pyx_v_start + __pyx_t_4); + + /* "ezdxf/acc/mapbox_earcut.pyx":131 + * else: + * end = start + len(points) + * for point in reversed(points): # <<<<<<<<<<<<<< + * last = insert_node(end, point, last) + * end -= 1 + */ + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 131, __pyx_L1_error) + } + __pyx_t_3 = __pyx_v_points; __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(1, 131, __pyx_L1_error) + #endif + --__pyx_t_4; + for (;;) { + if (__pyx_t_4 < 0) break; + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 131, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_5); __pyx_t_4--; if (unlikely((0 < 0))) __PYX_ERR(1, 131, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4--; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_XDECREF_SET(__pyx_v_point, __pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":132 + * end = start + len(points) + * for point in reversed(points): + * last = insert_node(end, point, last) # <<<<<<<<<<<<<< + * end -= 1 + * + */ + __pyx_t_5 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_insert_node(__pyx_v_end, __pyx_v_point, __pyx_v_last)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 132, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_last, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":133 + * for point in reversed(points): + * last = insert_node(end, point, last) + * end -= 1 # <<<<<<<<<<<<<< + * + * # open polygon: where the 1st vertex is not coincident with the last vertex + */ + __pyx_v_end = (__pyx_v_end - 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":131 + * else: + * end = start + len(points) + * for point in reversed(points): # <<<<<<<<<<<<<< + * last = insert_node(end, point, last) + * end -= 1 + */ + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "ezdxf/acc/mapbox_earcut.pyx":136 + * + * # open polygon: where the 1st vertex is not coincident with the last vertex + * if last and last.equals(last.next): # <<<<<<<<<<<<<< + * remove_node(last) + * last = last.next + */ + __pyx_t_6 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_last)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 136, __pyx_L1_error) + if (__pyx_t_6) { + } else { + __pyx_t_2 = __pyx_t_6; + goto __pyx_L11_bool_binop_done; + } + __pyx_t_3 = ((PyObject *)__pyx_v_last->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_6 = ((struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_last->__pyx_vtab)->equals(__pyx_v_last, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 136, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __pyx_t_6; + __pyx_L11_bool_binop_done:; + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":137 + * # open polygon: where the 1st vertex is not coincident with the last vertex + * if last and last.equals(last.next): + * remove_node(last) # <<<<<<<<<<<<<< + * last = last.next + * return last + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(__pyx_v_last); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":138 + * if last and last.equals(last.next): + * remove_node(last) + * last = last.next # <<<<<<<<<<<<<< + * return last + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_last->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_last, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":136 + * + * # open polygon: where the 1st vertex is not coincident with the last vertex + * if last and last.equals(last.next): # <<<<<<<<<<<<<< + * remove_node(last) + * last = last.next + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":139 + * remove_node(last) + * last = last.next + * return last # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_last); + __pyx_r = __pyx_v_last; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":117 + * + * + * cdef Node linked_list(list points, int start, bint ccw): # <<<<<<<<<<<<<< + * """Create a circular doubly linked list from polygon points in the specified + * winding order + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.linked_list", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_last); + __Pyx_XDECREF(__pyx_v_point); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":142 + * + * + * cdef double signed_area(list points): # <<<<<<<<<<<<<< + * cdef: + * double s = 0.0 + */ + +static double __pyx_f_5ezdxf_3acc_13mapbox_earcut_signed_area(PyObject *__pyx_v_points) { + double __pyx_v_s; + double __pyx_v_point_x; + double __pyx_v_prev_x; + double __pyx_v_point_y; + double __pyx_v_prev_y; + PyObject *__pyx_v_prev = NULL; + PyObject *__pyx_v_point = NULL; + double __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("signed_area", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":144 + * cdef double signed_area(list points): + * cdef: + * double s = 0.0 # <<<<<<<<<<<<<< + * double point_x, prev_x, point_y, prev_y + * if not len(points): + */ + __pyx_v_s = 0.0; + + /* "ezdxf/acc/mapbox_earcut.pyx":146 + * double s = 0.0 + * double point_x, prev_x, point_y, prev_y + * if not len(points): # <<<<<<<<<<<<<< + * return s + * prev = points[-1] + */ + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 146, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyList_GET_SIZE(__pyx_v_points); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(1, 146, __pyx_L1_error) + __pyx_t_2 = (!(__pyx_t_1 != 0)); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":147 + * double point_x, prev_x, point_y, prev_y + * if not len(points): + * return s # <<<<<<<<<<<<<< + * prev = points[-1] + * prev_x = prev.x + */ + __pyx_r = __pyx_v_s; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":146 + * double s = 0.0 + * double point_x, prev_x, point_y, prev_y + * if not len(points): # <<<<<<<<<<<<<< + * return s + * prev = points[-1] + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":148 + * if not len(points): + * return s + * prev = points[-1] # <<<<<<<<<<<<<< + * prev_x = prev.x + * prev_y = prev.y + */ + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 148, __pyx_L1_error) + } + __pyx_t_3 = __Pyx_GetItemInt_List(__pyx_v_points, -1L, long, 1, __Pyx_PyInt_From_long, 1, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 148, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_v_prev = __pyx_t_3; + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":149 + * return s + * prev = points[-1] + * prev_x = prev.x # <<<<<<<<<<<<<< + * prev_y = prev.y + * for point in points: + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_prev, __pyx_n_s_x); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_prev_x = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":150 + * prev = points[-1] + * prev_x = prev.x + * prev_y = prev.y # <<<<<<<<<<<<<< + * for point in points: + * point_x = point.x + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_prev, __pyx_n_s_y); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 150, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_prev_y = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":151 + * prev_x = prev.x + * prev_y = prev.y + * for point in points: # <<<<<<<<<<<<<< + * point_x = point.x + * point_y = point.y + */ + if (unlikely(__pyx_v_points == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 151, __pyx_L1_error) + } + __pyx_t_3 = __pyx_v_points; __Pyx_INCREF(__pyx_t_3); + __pyx_t_1 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 151, __pyx_L1_error) + #endif + if (__pyx_t_1 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_5); __pyx_t_1++; if (unlikely((0 < 0))) __PYX_ERR(1, 151, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __Pyx_XDECREF_SET(__pyx_v_point, __pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":152 + * prev_y = prev.y + * for point in points: + * point_x = point.x # <<<<<<<<<<<<<< + * point_y = point.y + * s += (point_x - prev_x) * (point_y + prev_y) + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_x); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 152, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_point_x = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":153 + * for point in points: + * point_x = point.x + * point_y = point.y # <<<<<<<<<<<<<< + * s += (point_x - prev_x) * (point_y + prev_y) + * prev_x = point_x + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_point, __pyx_n_s_y); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 153, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_point_y = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":154 + * point_x = point.x + * point_y = point.y + * s += (point_x - prev_x) * (point_y + prev_y) # <<<<<<<<<<<<<< + * prev_x = point_x + * prev_y = point_y + */ + __pyx_v_s = (__pyx_v_s + ((__pyx_v_point_x - __pyx_v_prev_x) * (__pyx_v_point_y + __pyx_v_prev_y))); + + /* "ezdxf/acc/mapbox_earcut.pyx":155 + * point_y = point.y + * s += (point_x - prev_x) * (point_y + prev_y) + * prev_x = point_x # <<<<<<<<<<<<<< + * prev_y = point_y + * # s < 0 is counter-clockwise + */ + __pyx_v_prev_x = __pyx_v_point_x; + + /* "ezdxf/acc/mapbox_earcut.pyx":156 + * s += (point_x - prev_x) * (point_y + prev_y) + * prev_x = point_x + * prev_y = point_y # <<<<<<<<<<<<<< + * # s < 0 is counter-clockwise + * # s > 0 is clockwise + */ + __pyx_v_prev_y = __pyx_v_point_y; + + /* "ezdxf/acc/mapbox_earcut.pyx":151 + * prev_x = prev.x + * prev_y = prev.y + * for point in points: # <<<<<<<<<<<<<< + * point_x = point.x + * point_y = point.y + */ + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":159 + * # s < 0 is counter-clockwise + * # s > 0 is clockwise + * return s # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_s; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":142 + * + * + * cdef double signed_area(list points): # <<<<<<<<<<<<<< + * cdef: + * double s = 0.0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.signed_area", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_prev); + __Pyx_XDECREF(__pyx_v_point); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":162 + * + * + * cdef double area(Node p, Node q, Node r): # <<<<<<<<<<<<<< + * """Returns signed area of a triangle""" + * return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) + */ + +static double __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_q, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_r) { + double __pyx_r; + + /* "ezdxf/acc/mapbox_earcut.pyx":164 + * cdef double area(Node p, Node q, Node r): + * """Returns signed area of a triangle""" + * return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = (((__pyx_v_q->y - __pyx_v_p->y) * (__pyx_v_r->x - __pyx_v_q->x)) - ((__pyx_v_q->x - __pyx_v_p->x) * (__pyx_v_r->y - __pyx_v_q->y))); + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":162 + * + * + * cdef double area(Node p, Node q, Node r): # <<<<<<<<<<<<<< + * """Returns signed area of a triangle""" + * return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":167 + * + * + * cdef bint is_valid_diagonal(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a diagonal between two polygon nodes is valid (lies in polygon + * interior) + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_valid_diagonal(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + double __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_valid_diagonal", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":172 + * """ + * return ( + * a.next.i != b.i # <<<<<<<<<<<<<< + * and a.prev.i != b.i + * and not intersects_polygon(a, b) # doesn't intersect other edges + */ + __pyx_t_2 = (__pyx_v_a->next->i != __pyx_v_b->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":173 + * return ( + * a.next.i != b.i + * and a.prev.i != b.i # <<<<<<<<<<<<<< + * and not intersects_polygon(a, b) # doesn't intersect other edges + * and ( + */ + __pyx_t_2 = (__pyx_v_a->prev->i != __pyx_v_b->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":174 + * a.next.i != b.i + * and a.prev.i != b.i + * and not intersects_polygon(a, b) # doesn't intersect other edges # <<<<<<<<<<<<<< + * and ( + * locally_inside(a, b) + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects_polygon(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 174, __pyx_L1_error) + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":176 + * and not intersects_polygon(a, b) # doesn't intersect other edges + * and ( + * locally_inside(a, b) # <<<<<<<<<<<<<< + * and locally_inside(b, a) + * and middle_inside(a, b) + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_3 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 176, __pyx_L1_error) + if (!__pyx_t_3) { + goto __pyx_L7_next_or; + } else { + } + + /* "ezdxf/acc/mapbox_earcut.pyx":177 + * and ( + * locally_inside(a, b) + * and locally_inside(b, a) # <<<<<<<<<<<<<< + * and middle_inside(a, b) + * and ( + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(__pyx_v_b, __pyx_v_a); if (unlikely(__pyx_t_3 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 177, __pyx_L1_error) + if (!__pyx_t_3) { + goto __pyx_L7_next_or; + } else { + } + + /* "ezdxf/acc/mapbox_earcut.pyx":178 + * locally_inside(a, b) + * and locally_inside(b, a) + * and middle_inside(a, b) # <<<<<<<<<<<<<< + * and ( + * area(a.prev, a, b.prev) or area(a, b.prev, b) + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_middle_inside(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_3 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 178, __pyx_L1_error) + if (!__pyx_t_3) { + goto __pyx_L7_next_or; + } else { + } + + /* "ezdxf/acc/mapbox_earcut.pyx":180 + * and middle_inside(a, b) + * and ( + * area(a.prev, a, b.prev) or area(a, b.prev, b) # <<<<<<<<<<<<<< + * ) # does not create opposite-facing sectors + * or a.equals(b) + */ + __pyx_t_4 = ((PyObject *)__pyx_v_a->prev); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_5 = ((PyObject *)__pyx_v_b->prev); + __Pyx_INCREF(__pyx_t_5); + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4), __pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); if (unlikely(__pyx_t_6 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 180, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = (__pyx_t_6 != 0); + if (!__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_5 = ((PyObject *)__pyx_v_b->prev); + __Pyx_INCREF(__pyx_t_5); + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5), __pyx_v_b); if (unlikely(__pyx_t_6 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 180, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = (__pyx_t_6 != 0); + if (!__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L3_bool_binop_done; + } + __pyx_L7_next_or:; + + /* "ezdxf/acc/mapbox_earcut.pyx":182 + * area(a.prev, a, b.prev) or area(a, b.prev, b) + * ) # does not create opposite-facing sectors + * or a.equals(b) # <<<<<<<<<<<<<< + * and area(a.prev, a, a.next) > 0 + * and area(b.prev, b, b.next) > 0 + */ + __pyx_t_3 = ((struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_a->__pyx_vtab)->equals(__pyx_v_a, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 182, __pyx_L1_error) + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":183 + * ) # does not create opposite-facing sectors + * or a.equals(b) + * and area(a.prev, a, a.next) > 0 # <<<<<<<<<<<<<< + * and area(b.prev, b, b.next) > 0 + * ) # special zero-length case + */ + __pyx_t_5 = ((PyObject *)__pyx_v_a->prev); + __Pyx_INCREF(__pyx_t_5); + __pyx_t_4 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5), __pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); if (unlikely(__pyx_t_6 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 183, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = (__pyx_t_6 > 0.0); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":184 + * or a.equals(b) + * and area(a.prev, a, a.next) > 0 + * and area(b.prev, b, b.next) > 0 # <<<<<<<<<<<<<< + * ) # special zero-length case + * ) + */ + __pyx_t_4 = ((PyObject *)__pyx_v_b->prev); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_5 = ((PyObject *)__pyx_v_b->next); + __Pyx_INCREF(__pyx_t_5); + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4), __pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); if (unlikely(__pyx_t_6 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 184, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = (__pyx_t_6 > 0.0); + __pyx_t_1 = __pyx_t_3; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":167 + * + * + * cdef bint is_valid_diagonal(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a diagonal between two polygon nodes is valid (lies in polygon + * interior) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.is_valid_diagonal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":189 + * + * + * cdef bint intersects_polygon(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a polygon diagonal intersects any polygon segments""" + * cdef Node p = a + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects_polygon(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("intersects_polygon", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":191 + * cdef bint intersects_polygon(Node a, Node b): + * """Check if a polygon diagonal intersects any polygon segments""" + * cdef Node p = a # <<<<<<<<<<<<<< + * while True: + * if ( + */ + __Pyx_INCREF((PyObject *)__pyx_v_a); + __pyx_v_p = __pyx_v_a; + + /* "ezdxf/acc/mapbox_earcut.pyx":192 + * """Check if a polygon diagonal intersects any polygon segments""" + * cdef Node p = a + * while True: # <<<<<<<<<<<<<< + * if ( + * p.i != a.i + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":194 + * while True: + * if ( + * p.i != a.i # <<<<<<<<<<<<<< + * and p.next.i != a.i + * and p.i != b.i + */ + __pyx_t_2 = (__pyx_v_p->i != __pyx_v_a->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":195 + * if ( + * p.i != a.i + * and p.next.i != a.i # <<<<<<<<<<<<<< + * and p.i != b.i + * and p.next.i != b.i + */ + __pyx_t_2 = (__pyx_v_p->next->i != __pyx_v_a->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":196 + * p.i != a.i + * and p.next.i != a.i + * and p.i != b.i # <<<<<<<<<<<<<< + * and p.next.i != b.i + * and intersects(p, p.next, a, b) + */ + __pyx_t_2 = (__pyx_v_p->i != __pyx_v_b->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":197 + * and p.next.i != a.i + * and p.i != b.i + * and p.next.i != b.i # <<<<<<<<<<<<<< + * and intersects(p, p.next, a, b) + * ): + */ + __pyx_t_2 = (__pyx_v_p->next->i != __pyx_v_b->i); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":198 + * and p.i != b.i + * and p.next.i != b.i + * and intersects(p, p.next, a, b) # <<<<<<<<<<<<<< + * ): + * return True + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 198, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_1 = __pyx_t_2; + __pyx_L6_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":193 + * cdef Node p = a + * while True: + * if ( # <<<<<<<<<<<<<< + * p.i != a.i + * and p.next.i != a.i + */ + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":200 + * and intersects(p, p.next, a, b) + * ): + * return True # <<<<<<<<<<<<<< + * p = p.next + * if p is a: + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":193 + * cdef Node p = a + * while True: + * if ( # <<<<<<<<<<<<<< + * p.i != a.i + * and p.next.i != a.i + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":201 + * ): + * return True + * p = p.next # <<<<<<<<<<<<<< + * if p is a: + * break + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":202 + * return True + * p = p.next + * if p is a: # <<<<<<<<<<<<<< + * break + * return False + */ + __pyx_t_1 = (__pyx_v_p == __pyx_v_a); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":203 + * p = p.next + * if p is a: + * break # <<<<<<<<<<<<<< + * return False + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":202 + * return True + * p = p.next + * if p is a: # <<<<<<<<<<<<<< + * break + * return False + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":204 + * if p is a: + * break + * return False # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":189 + * + * + * cdef bint intersects_polygon(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a polygon diagonal intersects any polygon segments""" + * cdef Node p = a + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.intersects_polygon", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":207 + * + * + * cdef int sign(double num): # <<<<<<<<<<<<<< + * if num < 0.0: + * return -1 + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(double __pyx_v_num) { + int __pyx_r; + int __pyx_t_1; + + /* "ezdxf/acc/mapbox_earcut.pyx":208 + * + * cdef int sign(double num): + * if num < 0.0: # <<<<<<<<<<<<<< + * return -1 + * if num > 0.0: + */ + __pyx_t_1 = (__pyx_v_num < 0.0); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":209 + * cdef int sign(double num): + * if num < 0.0: + * return -1 # <<<<<<<<<<<<<< + * if num > 0.0: + * return 1 + */ + __pyx_r = -1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":208 + * + * cdef int sign(double num): + * if num < 0.0: # <<<<<<<<<<<<<< + * return -1 + * if num > 0.0: + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":210 + * if num < 0.0: + * return -1 + * if num > 0.0: # <<<<<<<<<<<<<< + * return 1 + * return 0 + */ + __pyx_t_1 = (__pyx_v_num > 0.0); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":211 + * return -1 + * if num > 0.0: + * return 1 # <<<<<<<<<<<<<< + * return 0 + * + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":210 + * if num < 0.0: + * return -1 + * if num > 0.0: # <<<<<<<<<<<<<< + * return 1 + * return 0 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":212 + * if num > 0.0: + * return 1 + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":207 + * + * + * cdef int sign(double num): # <<<<<<<<<<<<<< + * if num < 0.0: + * return -1 + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":215 + * + * + * cdef bint on_segment(p: Node, q: Node, r: Node): # <<<<<<<<<<<<<< + * return fmax(p.x, r.x) >= q.x >= fmin(p.x, r.x) and fmax( + * p.y, r.y + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_q, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_r) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":216 + * + * cdef bint on_segment(p: Node, q: Node, r: Node): + * return fmax(p.x, r.x) >= q.x >= fmin(p.x, r.x) and fmax( # <<<<<<<<<<<<<< + * p.y, r.y + * ) >= q.y >= fmin(p.y, r.y) + */ + __pyx_t_2 = (fmax(__pyx_v_p->x, __pyx_v_r->x) >= __pyx_v_q->x); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_q->x >= fmin(__pyx_v_p->x, __pyx_v_r->x)); + } + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":218 + * return fmax(p.x, r.x) >= q.x >= fmin(p.x, r.x) and fmax( + * p.y, r.y + * ) >= q.y >= fmin(p.y, r.y) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (fmax(__pyx_v_p->y, __pyx_v_r->y) >= __pyx_v_q->y); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_q->y >= fmin(__pyx_v_p->y, __pyx_v_r->y)); + } + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":215 + * + * + * cdef bint on_segment(p: Node, q: Node, r: Node): # <<<<<<<<<<<<<< + * return fmax(p.x, r.x) >= q.x >= fmin(p.x, r.x) and fmax( + * p.y, r.y + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":221 + * + * + * cdef bint intersects(Node p1, Node q1, Node p2, Node q2): # <<<<<<<<<<<<<< + * """check if two segments intersect""" + * cdef: + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p1, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_q1, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p2, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_q2) { + int __pyx_v_o1; + int __pyx_v_o2; + int __pyx_v_o3; + int __pyx_v_o4; + int __pyx_r; + double __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":224 + * """check if two segments intersect""" + * cdef: + * int o1 = sign(area(p1, q1, p2)) # <<<<<<<<<<<<<< + * int o2 = sign(area(p1, q1, q2)) + * int o3 = sign(area(p2, q2, p1)) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_p1, __pyx_v_q1, __pyx_v_p2); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 224, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(__pyx_t_1); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 224, __pyx_L1_error) + __pyx_v_o1 = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":225 + * cdef: + * int o1 = sign(area(p1, q1, p2)) + * int o2 = sign(area(p1, q1, q2)) # <<<<<<<<<<<<<< + * int o3 = sign(area(p2, q2, p1)) + * int o4 = sign(area(p2, q2, q1)) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_p1, __pyx_v_q1, __pyx_v_q2); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 225, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(__pyx_t_1); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 225, __pyx_L1_error) + __pyx_v_o2 = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":226 + * int o1 = sign(area(p1, q1, p2)) + * int o2 = sign(area(p1, q1, q2)) + * int o3 = sign(area(p2, q2, p1)) # <<<<<<<<<<<<<< + * int o4 = sign(area(p2, q2, q1)) + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_p2, __pyx_v_q2, __pyx_v_p1); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 226, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(__pyx_t_1); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 226, __pyx_L1_error) + __pyx_v_o3 = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":227 + * int o2 = sign(area(p1, q1, q2)) + * int o3 = sign(area(p2, q2, p1)) + * int o4 = sign(area(p2, q2, q1)) # <<<<<<<<<<<<<< + * + * if o1 != o2 and o3 != o4: + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_p2, __pyx_v_q2, __pyx_v_q1); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 227, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_sign(__pyx_t_1); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 227, __pyx_L1_error) + __pyx_v_o4 = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":229 + * int o4 = sign(area(p2, q2, q1)) + * + * if o1 != o2 and o3 != o4: # <<<<<<<<<<<<<< + * return True # general case + * + */ + __pyx_t_4 = (__pyx_v_o1 != __pyx_v_o2); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = (__pyx_v_o3 != __pyx_v_o4); + __pyx_t_3 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":230 + * + * if o1 != o2 and o3 != o4: + * return True # general case # <<<<<<<<<<<<<< + * + * if o1 == 0 and on_segment(p1, p2, q1): + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":229 + * int o4 = sign(area(p2, q2, q1)) + * + * if o1 != o2 and o3 != o4: # <<<<<<<<<<<<<< + * return True # general case + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":232 + * return True # general case + * + * if o1 == 0 and on_segment(p1, p2, q1): # <<<<<<<<<<<<<< + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + * if o2 == 0 and on_segment(p1, q2, q1): + */ + __pyx_t_4 = (__pyx_v_o1 == 0); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L7_bool_binop_done; + } + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(__pyx_v_p1, __pyx_v_p2, __pyx_v_q1); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 232, __pyx_L1_error) + __pyx_t_3 = __pyx_t_4; + __pyx_L7_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":233 + * + * if o1 == 0 and on_segment(p1, p2, q1): + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 # <<<<<<<<<<<<<< + * if o2 == 0 and on_segment(p1, q2, q1): + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":232 + * return True # general case + * + * if o1 == 0 and on_segment(p1, p2, q1): # <<<<<<<<<<<<<< + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + * if o2 == 0 and on_segment(p1, q2, q1): + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":234 + * if o1 == 0 and on_segment(p1, p2, q1): + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + * if o2 == 0 and on_segment(p1, q2, q1): # <<<<<<<<<<<<<< + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + * if o3 == 0 and on_segment(p2, p1, q2): + */ + __pyx_t_4 = (__pyx_v_o2 == 0); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L10_bool_binop_done; + } + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(__pyx_v_p1, __pyx_v_q2, __pyx_v_q1); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 234, __pyx_L1_error) + __pyx_t_3 = __pyx_t_4; + __pyx_L10_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":235 + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + * if o2 == 0 and on_segment(p1, q2, q1): + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 # <<<<<<<<<<<<<< + * if o3 == 0 and on_segment(p2, p1, q2): + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":234 + * if o1 == 0 and on_segment(p1, p2, q1): + * return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + * if o2 == 0 and on_segment(p1, q2, q1): # <<<<<<<<<<<<<< + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + * if o3 == 0 and on_segment(p2, p1, q2): + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":236 + * if o2 == 0 and on_segment(p1, q2, q1): + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + * if o3 == 0 and on_segment(p2, p1, q2): # <<<<<<<<<<<<<< + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + * if o4 == 0 and on_segment(p2, q1, q2): + */ + __pyx_t_4 = (__pyx_v_o3 == 0); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L13_bool_binop_done; + } + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(__pyx_v_p2, __pyx_v_p1, __pyx_v_q2); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 236, __pyx_L1_error) + __pyx_t_3 = __pyx_t_4; + __pyx_L13_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":237 + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + * if o3 == 0 and on_segment(p2, p1, q2): + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 # <<<<<<<<<<<<<< + * if o4 == 0 and on_segment(p2, q1, q2): + * return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":236 + * if o2 == 0 and on_segment(p1, q2, q1): + * return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + * if o3 == 0 and on_segment(p2, p1, q2): # <<<<<<<<<<<<<< + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + * if o4 == 0 and on_segment(p2, q1, q2): + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":238 + * if o3 == 0 and on_segment(p2, p1, q2): + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + * if o4 == 0 and on_segment(p2, q1, q2): # <<<<<<<<<<<<<< + * return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + * return False + */ + __pyx_t_4 = (__pyx_v_o4 == 0); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L16_bool_binop_done; + } + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_on_segment(__pyx_v_p2, __pyx_v_q1, __pyx_v_q2); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 238, __pyx_L1_error) + __pyx_t_3 = __pyx_t_4; + __pyx_L16_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":239 + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + * if o4 == 0 and on_segment(p2, q1, q2): + * return True # p2, q2 and q1 are collinear and q1 lies on p2q2 # <<<<<<<<<<<<<< + * return False + * + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":238 + * if o3 == 0 and on_segment(p2, p1, q2): + * return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + * if o4 == 0 and on_segment(p2, q1, q2): # <<<<<<<<<<<<<< + * return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + * return False + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":240 + * if o4 == 0 and on_segment(p2, q1, q2): + * return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + * return False # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":221 + * + * + * cdef bint intersects(Node p1, Node q1, Node p2, Node q2): # <<<<<<<<<<<<<< + * """check if two segments intersect""" + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.intersects", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":243 + * + * + * cdef Node insert_node(int i, point, Node last): # <<<<<<<<<<<<<< + * """create a node and optionally link it with previous one (in a circular + * doubly linked list) + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_insert_node(int __pyx_v_i, PyObject *__pyx_v_point, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_last) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("insert_node", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":247 + * doubly linked list) + * """ + * cdef Node p = Node(i, point) # <<<<<<<<<<<<<< + * + * if last is None: + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 247, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 247, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(1, 247, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_point); + __Pyx_GIVEREF(__pyx_v_point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_point)) __PYX_ERR(1, 247, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node), __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 247, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_p = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":249 + * cdef Node p = Node(i, point) + * + * if last is None: # <<<<<<<<<<<<<< + * p.prev = p + * p.next = p + */ + __pyx_t_3 = (((PyObject *)__pyx_v_last) == Py_None); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":250 + * + * if last is None: + * p.prev = p # <<<<<<<<<<<<<< + * p.next = p + * else: + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_GIVEREF((PyObject *)__pyx_v_p); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev); + __pyx_v_p->prev = __pyx_v_p; + + /* "ezdxf/acc/mapbox_earcut.pyx":251 + * if last is None: + * p.prev = p + * p.next = p # <<<<<<<<<<<<<< + * else: + * p.next = last.next + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_GIVEREF((PyObject *)__pyx_v_p); + __Pyx_GOTREF((PyObject *)__pyx_v_p->next); + __Pyx_DECREF((PyObject *)__pyx_v_p->next); + __pyx_v_p->next = __pyx_v_p; + + /* "ezdxf/acc/mapbox_earcut.pyx":249 + * cdef Node p = Node(i, point) + * + * if last is None: # <<<<<<<<<<<<<< + * p.prev = p + * p.next = p + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":253 + * p.next = p + * else: + * p.next = last.next # <<<<<<<<<<<<<< + * p.prev = last + * last.next.prev = p + */ + /*else*/ { + __pyx_t_1 = ((PyObject *)__pyx_v_last->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_p->next); + __Pyx_DECREF((PyObject *)__pyx_v_p->next); + __pyx_v_p->next = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":254 + * else: + * p.next = last.next + * p.prev = last # <<<<<<<<<<<<<< + * last.next.prev = p + * last.next = p + */ + __Pyx_INCREF((PyObject *)__pyx_v_last); + __Pyx_GIVEREF((PyObject *)__pyx_v_last); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev); + __pyx_v_p->prev = __pyx_v_last; + + /* "ezdxf/acc/mapbox_earcut.pyx":255 + * p.next = last.next + * p.prev = last + * last.next.prev = p # <<<<<<<<<<<<<< + * last.next = p + * return p + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_GIVEREF((PyObject *)__pyx_v_p); + __Pyx_GOTREF((PyObject *)__pyx_v_last->next->prev); + __Pyx_DECREF((PyObject *)__pyx_v_last->next->prev); + __pyx_v_last->next->prev = __pyx_v_p; + + /* "ezdxf/acc/mapbox_earcut.pyx":256 + * p.prev = last + * last.next.prev = p + * last.next = p # <<<<<<<<<<<<<< + * return p + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_GIVEREF((PyObject *)__pyx_v_p); + __Pyx_GOTREF((PyObject *)__pyx_v_last->next); + __Pyx_DECREF((PyObject *)__pyx_v_last->next); + __pyx_v_last->next = __pyx_v_p; + } + __pyx_L3:; + + /* "ezdxf/acc/mapbox_earcut.pyx":257 + * last.next.prev = p + * last.next = p + * return p # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_p); + __pyx_r = __pyx_v_p; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":243 + * + * + * cdef Node insert_node(int i, point, Node last): # <<<<<<<<<<<<<< + * """create a node and optionally link it with previous one (in a circular + * doubly linked list) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.insert_node", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":260 + * + * + * cdef remove_node(Node p): # <<<<<<<<<<<<<< + * p.next.prev = p.prev + * p.prev.next = p.next + */ + +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + __Pyx_RefNannySetupContext("remove_node", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":261 + * + * cdef remove_node(Node p): + * p.next.prev = p.prev # <<<<<<<<<<<<<< + * p.prev.next = p.next + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_p->next->prev); + __Pyx_DECREF((PyObject *)__pyx_v_p->next->prev); + __pyx_v_p->next->prev = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":262 + * cdef remove_node(Node p): + * p.next.prev = p.prev + * p.prev.next = p.next # <<<<<<<<<<<<<< + * + * if p.prev_z is not None: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev->next); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev->next); + __pyx_v_p->prev->next = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":264 + * p.prev.next = p.next + * + * if p.prev_z is not None: # <<<<<<<<<<<<<< + * p.prev_z.next_z = p.next_z + * if p.next_z is not None: + */ + __pyx_t_2 = (((PyObject *)__pyx_v_p->prev_z) != Py_None); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":265 + * + * if p.prev_z is not None: + * p.prev_z.next_z = p.next_z # <<<<<<<<<<<<<< + * if p.next_z is not None: + * p.next_z.prev_z = p.prev_z + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->next_z); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev_z->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev_z->next_z); + __pyx_v_p->prev_z->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":264 + * p.prev.next = p.next + * + * if p.prev_z is not None: # <<<<<<<<<<<<<< + * p.prev_z.next_z = p.next_z + * if p.next_z is not None: + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":266 + * if p.prev_z is not None: + * p.prev_z.next_z = p.next_z + * if p.next_z is not None: # <<<<<<<<<<<<<< + * p.next_z.prev_z = p.prev_z + * + */ + __pyx_t_2 = (((PyObject *)__pyx_v_p->next_z) != Py_None); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":267 + * p.prev_z.next_z = p.next_z + * if p.next_z is not None: + * p.next_z.prev_z = p.prev_z # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev_z); + __Pyx_INCREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF((PyObject *)__pyx_v_p->next_z->prev_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->next_z->prev_z); + __pyx_v_p->next_z->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":266 + * if p.prev_z is not None: + * p.prev_z.next_z = p.next_z + * if p.next_z is not None: # <<<<<<<<<<<<<< + * p.next_z.prev_z = p.prev_z + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":260 + * + * + * cdef remove_node(Node p): # <<<<<<<<<<<<<< + * p.next.prev = p.prev + * p.prev.next = p.next + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":270 + * + * + * cdef Node eliminate_holes(list holes, int start, Node outer_node): # <<<<<<<<<<<<<< + * """link every hole into the outer loop, producing a single-ring polygon + * without holes + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_holes(PyObject *__pyx_v_holes, int __pyx_v_start, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_outer_node) { + PyObject *__pyx_v_queue = 0; + PyObject *__pyx_v_hole = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v__list = NULL; + PyObject *__pyx_v_hole_ = NULL; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("eliminate_holes", 0); + __Pyx_INCREF((PyObject *)__pyx_v_outer_node); + + /* "ezdxf/acc/mapbox_earcut.pyx":275 + * """ + * cdef: + * list queue = [] # <<<<<<<<<<<<<< + * list hole + * for hole in holes: + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_queue = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":277 + * list queue = [] + * list hole + * for hole in holes: # <<<<<<<<<<<<<< + * if len(hole) < 1: # skip empty holes + * continue + */ + if (unlikely(__pyx_v_holes == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 277, __pyx_L1_error) + } + __pyx_t_1 = __pyx_v_holes; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 277, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(1, 277, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + if (!(likely(PyList_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", __pyx_t_3))) __PYX_ERR(1, 277, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_hole, ((PyObject*)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":278 + * list hole + * for hole in holes: + * if len(hole) < 1: # skip empty holes # <<<<<<<<<<<<<< + * continue + * # hole vertices in clockwise order + */ + if (unlikely(__pyx_v_hole == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 278, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_v_hole); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 278, __pyx_L1_error) + __pyx_t_5 = (__pyx_t_4 < 1); + if (__pyx_t_5) { + + /* "ezdxf/acc/mapbox_earcut.pyx":279 + * for hole in holes: + * if len(hole) < 1: # skip empty holes + * continue # <<<<<<<<<<<<<< + * # hole vertices in clockwise order + * _list = linked_list(hole, start, ccw=False) + */ + goto __pyx_L3_continue; + + /* "ezdxf/acc/mapbox_earcut.pyx":278 + * list hole + * for hole in holes: + * if len(hole) < 1: # skip empty holes # <<<<<<<<<<<<<< + * continue + * # hole vertices in clockwise order + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":281 + * continue + * # hole vertices in clockwise order + * _list = linked_list(hole, start, ccw=False) # <<<<<<<<<<<<<< + * if _list is _list.next: + * _list.steiner = True + */ + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_linked_list(__pyx_v_hole, __pyx_v_start, 0)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_XDECREF_SET(__pyx_v__list, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":282 + * # hole vertices in clockwise order + * _list = linked_list(hole, start, ccw=False) + * if _list is _list.next: # <<<<<<<<<<<<<< + * _list.steiner = True + * start += len(hole) + */ + __pyx_t_5 = (__pyx_v__list == __pyx_v__list->next); + if (__pyx_t_5) { + + /* "ezdxf/acc/mapbox_earcut.pyx":283 + * _list = linked_list(hole, start, ccw=False) + * if _list is _list.next: + * _list.steiner = True # <<<<<<<<<<<<<< + * start += len(hole) + * queue.append(get_leftmost(_list)) + */ + __pyx_v__list->steiner = 1; + + /* "ezdxf/acc/mapbox_earcut.pyx":282 + * # hole vertices in clockwise order + * _list = linked_list(hole, start, ccw=False) + * if _list is _list.next: # <<<<<<<<<<<<<< + * _list.steiner = True + * start += len(hole) + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":284 + * if _list is _list.next: + * _list.steiner = True + * start += len(hole) # <<<<<<<<<<<<<< + * queue.append(get_leftmost(_list)) + * queue.sort(key=node_key) + */ + if (unlikely(__pyx_v_hole == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 284, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyList_GET_SIZE(__pyx_v_hole); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 284, __pyx_L1_error) + __pyx_v_start = (__pyx_v_start + __pyx_t_4); + + /* "ezdxf/acc/mapbox_earcut.pyx":285 + * _list.steiner = True + * start += len(hole) + * queue.append(get_leftmost(_list)) # <<<<<<<<<<<<<< + * queue.sort(key=node_key) + * + */ + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_get_leftmost(__pyx_v__list)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 285, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_6 = __Pyx_PyList_Append(__pyx_v_queue, __pyx_t_3); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(1, 285, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":277 + * list queue = [] + * list hole + * for hole in holes: # <<<<<<<<<<<<<< + * if len(hole) < 1: # skip empty holes + * continue + */ + __pyx_L3_continue:; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":286 + * start += len(hole) + * queue.append(get_leftmost(_list)) + * queue.sort(key=node_key) # <<<<<<<<<<<<<< + * + * # process holes from left to right + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_queue, __pyx_n_s_sort); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_node_key); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_key, __pyx_t_7) < 0) __PYX_ERR(1, 286, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_empty_tuple, __pyx_t_3); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":289 + * + * # process holes from left to right + * for hole_ in queue: # <<<<<<<<<<<<<< + * outer_node = eliminate_hole(hole_, outer_node) + * return outer_node + */ + __pyx_t_7 = __pyx_v_queue; __Pyx_INCREF(__pyx_t_7); + __pyx_t_2 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_7); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 289, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyList_GET_ITEM(__pyx_t_7, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(1, 289, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_7, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 289, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_hole_, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":290 + * # process holes from left to right + * for hole_ in queue: + * outer_node = eliminate_hole(hole_, outer_node) # <<<<<<<<<<<<<< + * return outer_node + * + */ + if (!(likely(((__pyx_v_hole_) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_hole_, __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node))))) __PYX_ERR(1, 290, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_hole(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_hole_), __pyx_v_outer_node)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 290, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_outer_node, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":289 + * + * # process holes from left to right + * for hole_ in queue: # <<<<<<<<<<<<<< + * outer_node = eliminate_hole(hole_, outer_node) + * return outer_node + */ + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":291 + * for hole_ in queue: + * outer_node = eliminate_hole(hole_, outer_node) + * return outer_node # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_outer_node); + __pyx_r = __pyx_v_outer_node; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":270 + * + * + * cdef Node eliminate_holes(list holes, int start, Node outer_node): # <<<<<<<<<<<<<< + * """link every hole into the outer loop, producing a single-ring polygon + * without holes + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.eliminate_holes", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_queue); + __Pyx_XDECREF(__pyx_v_hole); + __Pyx_XDECREF((PyObject *)__pyx_v__list); + __Pyx_XDECREF(__pyx_v_hole_); + __Pyx_XDECREF((PyObject *)__pyx_v_outer_node); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":294 + * + * + * cdef Node eliminate_hole(Node hole, Node outer_node): # <<<<<<<<<<<<<< + * """Find a bridge between vertices that connects hole with an outer ring and + * link it + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_eliminate_hole(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_hole, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_outer_node) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_bridge = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_bridge_reverse = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("eliminate_hole", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":299 + * """ + * cdef: + * Node bridge = find_hole_bridge(hole, outer_node) # <<<<<<<<<<<<<< + * Node bridge_reverse + * + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_find_hole_bridge(__pyx_v_hole, __pyx_v_outer_node)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 299, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_bridge = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":302 + * Node bridge_reverse + * + * if bridge is None: # <<<<<<<<<<<<<< + * return outer_node + * + */ + __pyx_t_2 = (((PyObject *)__pyx_v_bridge) == Py_None); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":303 + * + * if bridge is None: + * return outer_node # <<<<<<<<<<<<<< + * + * bridge_reverse = split_polygon(bridge, hole) + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_outer_node); + __pyx_r = __pyx_v_outer_node; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":302 + * Node bridge_reverse + * + * if bridge is None: # <<<<<<<<<<<<<< + * return outer_node + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":305 + * return outer_node + * + * bridge_reverse = split_polygon(bridge, hole) # <<<<<<<<<<<<<< + * + * # filter collinear points around the cuts + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_polygon(__pyx_v_bridge, __pyx_v_hole)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 305, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_bridge_reverse = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":308 + * + * # filter collinear points around the cuts + * filter_points(bridge_reverse, bridge_reverse.next) # <<<<<<<<<<<<<< + * return filter_points(bridge, bridge.next) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_bridge_reverse->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4.__pyx_n = 1; + __pyx_t_4.end = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_bridge_reverse, &__pyx_t_4)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":309 + * # filter collinear points around the cuts + * filter_points(bridge_reverse, bridge_reverse.next) + * return filter_points(bridge, bridge.next) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_3 = ((PyObject *)__pyx_v_bridge->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4.__pyx_n = 1; + __pyx_t_4.end = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_bridge, &__pyx_t_4)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":294 + * + * + * cdef Node eliminate_hole(Node hole, Node outer_node): # <<<<<<<<<<<<<< + * """Find a bridge between vertices that connects hole with an outer ring and + * link it + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.eliminate_hole", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_bridge); + __Pyx_XDECREF((PyObject *)__pyx_v_bridge_reverse); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":312 + * + * + * cdef Node filter_points(Node start, Node end = None): # <<<<<<<<<<<<<< + * """eliminate colinear or duplicate points""" + * cdef: + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_start, struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points *__pyx_optional_args) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_end = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + int __pyx_v_again; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + double __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("filter_points", 0); + if (__pyx_optional_args) { + if (__pyx_optional_args->__pyx_n > 0) { + __pyx_v_end = __pyx_optional_args->end; + } + } + __Pyx_INCREF((PyObject *)__pyx_v_end); + + /* "ezdxf/acc/mapbox_earcut.pyx":318 + * bint again + * + * if start is None: # <<<<<<<<<<<<<< + * return start + * if end is None: + */ + __pyx_t_1 = (((PyObject *)__pyx_v_start) == Py_None); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":319 + * + * if start is None: + * return start # <<<<<<<<<<<<<< + * if end is None: + * end = start + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_r = __pyx_v_start; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":318 + * bint again + * + * if start is None: # <<<<<<<<<<<<<< + * return start + * if end is None: + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":320 + * if start is None: + * return start + * if end is None: # <<<<<<<<<<<<<< + * end = start + * + */ + __pyx_t_1 = (((PyObject *)__pyx_v_end) == Py_None); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":321 + * return start + * if end is None: + * end = start # <<<<<<<<<<<<<< + * + * p = start + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __Pyx_DECREF_SET(__pyx_v_end, __pyx_v_start); + + /* "ezdxf/acc/mapbox_earcut.pyx":320 + * if start is None: + * return start + * if end is None: # <<<<<<<<<<<<<< + * end = start + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":323 + * end = start + * + * p = start # <<<<<<<<<<<<<< + * while True: + * again = False + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_p = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":324 + * + * p = start + * while True: # <<<<<<<<<<<<<< + * again = False + * if not p.steiner and ( + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":325 + * p = start + * while True: + * again = False # <<<<<<<<<<<<<< + * if not p.steiner and ( + * p.equals(p.next) or area(p.prev, p, p.next) == 0 + */ + __pyx_v_again = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":326 + * while True: + * again = False + * if not p.steiner and ( # <<<<<<<<<<<<<< + * p.equals(p.next) or area(p.prev, p, p.next) == 0 + * ): + */ + __pyx_t_2 = (!__pyx_v_p->steiner); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L8_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":327 + * again = False + * if not p.steiner and ( + * p.equals(p.next) or area(p.prev, p, p.next) == 0 # <<<<<<<<<<<<<< + * ): + * remove_node(p) + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_2 = ((struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_p->__pyx_vtab)->equals(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 327, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L8_bool_binop_done; + } + __pyx_t_3 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); if (unlikely(__pyx_t_5 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 327, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_2 = (__pyx_t_5 == 0.0); + __pyx_t_1 = __pyx_t_2; + __pyx_L8_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":326 + * while True: + * again = False + * if not p.steiner and ( # <<<<<<<<<<<<<< + * p.equals(p.next) or area(p.prev, p, p.next) == 0 + * ): + */ + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":329 + * p.equals(p.next) or area(p.prev, p, p.next) == 0 + * ): + * remove_node(p) # <<<<<<<<<<<<<< + * p = end = p.prev + * if p is p.next: + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(__pyx_v_p); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 329, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":330 + * ): + * remove_node(p) + * p = end = p.prev # <<<<<<<<<<<<<< + * if p is p.next: + * break + */ + __pyx_t_4 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_end, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":331 + * remove_node(p) + * p = end = p.prev + * if p is p.next: # <<<<<<<<<<<<<< + * break + * again = True + */ + __pyx_t_1 = (__pyx_v_p == __pyx_v_p->next); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":332 + * p = end = p.prev + * if p is p.next: + * break # <<<<<<<<<<<<<< + * again = True + * else: + */ + goto __pyx_L6_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":331 + * remove_node(p) + * p = end = p.prev + * if p is p.next: # <<<<<<<<<<<<<< + * break + * again = True + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":333 + * if p is p.next: + * break + * again = True # <<<<<<<<<<<<<< + * else: + * p = p.next + */ + __pyx_v_again = 1; + + /* "ezdxf/acc/mapbox_earcut.pyx":326 + * while True: + * again = False + * if not p.steiner and ( # <<<<<<<<<<<<<< + * p.equals(p.next) or area(p.prev, p, p.next) == 0 + * ): + */ + goto __pyx_L7; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":335 + * again = True + * else: + * p = p.next # <<<<<<<<<<<<<< + * if not (again or p is not end): + * break + */ + /*else*/ { + __pyx_t_4 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __pyx_t_4 = 0; + } + __pyx_L7:; + + /* "ezdxf/acc/mapbox_earcut.pyx":336 + * else: + * p = p.next + * if not (again or p is not end): # <<<<<<<<<<<<<< + * break + * return end + */ + if (!__pyx_v_again) { + } else { + __pyx_t_1 = __pyx_v_again; + goto __pyx_L13_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_p != __pyx_v_end); + __pyx_t_1 = __pyx_t_2; + __pyx_L13_bool_binop_done:; + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":337 + * p = p.next + * if not (again or p is not end): + * break # <<<<<<<<<<<<<< + * return end + * + */ + goto __pyx_L6_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":336 + * else: + * p = p.next + * if not (again or p is not end): # <<<<<<<<<<<<<< + * break + * return end + */ + } + } + __pyx_L6_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":338 + * if not (again or p is not end): + * break + * return end # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_end); + __pyx_r = __pyx_v_end; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":312 + * + * + * cdef Node filter_points(Node start, Node end = None): # <<<<<<<<<<<<<< + * """eliminate colinear or duplicate points""" + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.filter_points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_end); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":342 + * + * # main ear slicing loop which triangulates a polygon (given as a linked list) + * cdef earcut_linked( # <<<<<<<<<<<<<< + * Node ear, + * list triangles, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_ear, PyObject *__pyx_v_triangles, double __pyx_v_min_x, double __pyx_v_min_y, double __pyx_v_inv_size, int __pyx_v_pass_) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_stop = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_prev = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_next = 0; + int __pyx_v__is_ear; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("earcut_linked", 0); + __Pyx_INCREF((PyObject *)__pyx_v_ear); + + /* "ezdxf/acc/mapbox_earcut.pyx":354 + * bint _is_ear + * + * if ear is None: # <<<<<<<<<<<<<< + * return + * + */ + __pyx_t_1 = (((PyObject *)__pyx_v_ear) == Py_None); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":355 + * + * if ear is None: + * return # <<<<<<<<<<<<<< + * + * # interlink polygon nodes in z-order + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":354 + * bint _is_ear + * + * if ear is None: # <<<<<<<<<<<<<< + * return + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":358 + * + * # interlink polygon nodes in z-order + * if not pass_ and inv_size: # <<<<<<<<<<<<<< + * index_curve(ear, min_x, min_y, inv_size) + * + */ + __pyx_t_2 = (!(__pyx_v_pass_ != 0)); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_inv_size != 0); + __pyx_t_1 = __pyx_t_2; + __pyx_L5_bool_binop_done:; + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":359 + * # interlink polygon nodes in z-order + * if not pass_ and inv_size: + * index_curve(ear, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * + * stop = ear + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_index_curve(__pyx_v_ear, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 359, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":358 + * + * # interlink polygon nodes in z-order + * if not pass_ and inv_size: # <<<<<<<<<<<<<< + * index_curve(ear, min_x, min_y, inv_size) + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":361 + * index_curve(ear, min_x, min_y, inv_size) + * + * stop = ear # <<<<<<<<<<<<<< + * + * # iterate through ears, slicing them one by one + */ + __Pyx_INCREF((PyObject *)__pyx_v_ear); + __pyx_v_stop = __pyx_v_ear; + + /* "ezdxf/acc/mapbox_earcut.pyx":364 + * + * # iterate through ears, slicing them one by one + * while ear.prev is not ear.next: # <<<<<<<<<<<<<< + * prev = ear.prev + * next = ear.next + */ + while (1) { + __pyx_t_1 = (__pyx_v_ear->prev != __pyx_v_ear->next); + if (!__pyx_t_1) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":365 + * # iterate through ears, slicing them one by one + * while ear.prev is not ear.next: + * prev = ear.prev # <<<<<<<<<<<<<< + * next = ear.next + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_ear->prev); + __Pyx_INCREF(__pyx_t_3); + __Pyx_XDECREF_SET(__pyx_v_prev, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":366 + * while ear.prev is not ear.next: + * prev = ear.prev + * next = ear.next # <<<<<<<<<<<<<< + * + * _is_ear = ( + */ + __pyx_t_3 = ((PyObject *)__pyx_v_ear->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_XDECREF_SET(__pyx_v_next, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":370 + * _is_ear = ( + * is_ear_hashed(ear, min_x, min_y, inv_size) + * if inv_size # <<<<<<<<<<<<<< + * else is_ear(ear) + * ) + */ + __pyx_t_2 = (__pyx_v_inv_size != 0); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":369 + * + * _is_ear = ( + * is_ear_hashed(ear, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * if inv_size + * else is_ear(ear) + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear_hashed(__pyx_v_ear, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 369, __pyx_L1_error) + __pyx_t_1 = __pyx_t_4; + } else { + + /* "ezdxf/acc/mapbox_earcut.pyx":371 + * is_ear_hashed(ear, min_x, min_y, inv_size) + * if inv_size + * else is_ear(ear) # <<<<<<<<<<<<<< + * ) + * if _is_ear: + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear(__pyx_v_ear); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 371, __pyx_L1_error) + __pyx_t_1 = __pyx_t_4; + } + __pyx_v__is_ear = __pyx_t_1; + + /* "ezdxf/acc/mapbox_earcut.pyx":373 + * else is_ear(ear) + * ) + * if _is_ear: # <<<<<<<<<<<<<< + * # cut off the triangle + * triangles.append((prev.point, ear.point, next.point)) + */ + if (__pyx_v__is_ear) { + + /* "ezdxf/acc/mapbox_earcut.pyx":375 + * if _is_ear: + * # cut off the triangle + * triangles.append((prev.point, ear.point, next.point)) # <<<<<<<<<<<<<< + * remove_node(ear) + * + */ + if (unlikely(__pyx_v_triangles == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append"); + __PYX_ERR(1, 375, __pyx_L1_error) + } + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 375, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_prev->point); + __Pyx_GIVEREF(__pyx_v_prev->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_prev->point)) __PYX_ERR(1, 375, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ear->point); + __Pyx_GIVEREF(__pyx_v_ear->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_ear->point)) __PYX_ERR(1, 375, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_next->point); + __Pyx_GIVEREF(__pyx_v_next->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_next->point)) __PYX_ERR(1, 375, __pyx_L1_error); + __pyx_t_5 = __Pyx_PyList_Append(__pyx_v_triangles, __pyx_t_3); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 375, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":376 + * # cut off the triangle + * triangles.append((prev.point, ear.point, next.point)) + * remove_node(ear) # <<<<<<<<<<<<<< + * + * # skipping the next vertex leads to less sliver triangles + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(__pyx_v_ear); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":379 + * + * # skipping the next vertex leads to less sliver triangles + * ear = next.next # <<<<<<<<<<<<<< + * stop = next.next + * continue + */ + __pyx_t_3 = ((PyObject *)__pyx_v_next->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_ear, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":380 + * # skipping the next vertex leads to less sliver triangles + * ear = next.next + * stop = next.next # <<<<<<<<<<<<<< + * continue + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_next->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_stop, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":381 + * ear = next.next + * stop = next.next + * continue # <<<<<<<<<<<<<< + * + * ear = next + */ + goto __pyx_L7_continue; + + /* "ezdxf/acc/mapbox_earcut.pyx":373 + * else is_ear(ear) + * ) + * if _is_ear: # <<<<<<<<<<<<<< + * # cut off the triangle + * triangles.append((prev.point, ear.point, next.point)) + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":383 + * continue + * + * ear = next # <<<<<<<<<<<<<< + * + * # if we looped through the whole remaining polygon and can't find any more ears + */ + __Pyx_INCREF((PyObject *)__pyx_v_next); + __Pyx_DECREF_SET(__pyx_v_ear, __pyx_v_next); + + /* "ezdxf/acc/mapbox_earcut.pyx":386 + * + * # if we looped through the whole remaining polygon and can't find any more ears + * if ear is stop: # <<<<<<<<<<<<<< + * # try filtering points and slicing again + * if not pass_: + */ + __pyx_t_1 = (__pyx_v_ear == __pyx_v_stop); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":388 + * if ear is stop: + * # try filtering points and slicing again + * if not pass_: # <<<<<<<<<<<<<< + * earcut_linked( + * filter_points(ear), + */ + __pyx_t_1 = (!(__pyx_v_pass_ != 0)); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":390 + * if not pass_: + * earcut_linked( + * filter_points(ear), # <<<<<<<<<<<<<< + * triangles, + * min_x, + */ + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_ear, NULL)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 390, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "ezdxf/acc/mapbox_earcut.pyx":389 + * # try filtering points and slicing again + * if not pass_: + * earcut_linked( # <<<<<<<<<<<<<< + * filter_points(ear), + * triangles, + */ + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 389, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":388 + * if ear is stop: + * # try filtering points and slicing again + * if not pass_: # <<<<<<<<<<<<<< + * earcut_linked( + * filter_points(ear), + */ + goto __pyx_L11; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":399 + * + * # if this didn't work, try curing all small self-intersections locally + * elif pass_ == 1: # <<<<<<<<<<<<<< + * ear = cure_local_intersections(filter_points(ear), triangles) + * earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) + */ + __pyx_t_1 = (__pyx_v_pass_ == 1); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":400 + * # if this didn't work, try curing all small self-intersections locally + * elif pass_ == 1: + * ear = cure_local_intersections(filter_points(ear), triangles) # <<<<<<<<<<<<<< + * earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) + * + */ + __pyx_t_6 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_ear, NULL)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 400, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_cure_local_intersections(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6), __pyx_v_triangles)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 400, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF_SET(__pyx_v_ear, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":401 + * elif pass_ == 1: + * ear = cure_local_intersections(filter_points(ear), triangles) + * earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) # <<<<<<<<<<<<<< + * + * # as a last resort, try splitting the remaining polygon into two + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(__pyx_v_ear, __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size, 2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":399 + * + * # if this didn't work, try curing all small self-intersections locally + * elif pass_ == 1: # <<<<<<<<<<<<<< + * ear = cure_local_intersections(filter_points(ear), triangles) + * earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) + */ + goto __pyx_L11; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":404 + * + * # as a last resort, try splitting the remaining polygon into two + * elif pass_ == 2: # <<<<<<<<<<<<<< + * split_ear_cut(ear, triangles, min_x, min_y, inv_size) + * break + */ + __pyx_t_1 = (__pyx_v_pass_ == 2); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":405 + * # as a last resort, try splitting the remaining polygon into two + * elif pass_ == 2: + * split_ear_cut(ear, triangles, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * break + * + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_split_ear_cut(__pyx_v_ear, __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 405, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":404 + * + * # as a last resort, try splitting the remaining polygon into two + * elif pass_ == 2: # <<<<<<<<<<<<<< + * split_ear_cut(ear, triangles, min_x, min_y, inv_size) + * break + */ + } + __pyx_L11:; + + /* "ezdxf/acc/mapbox_earcut.pyx":406 + * elif pass_ == 2: + * split_ear_cut(ear, triangles, min_x, min_y, inv_size) + * break # <<<<<<<<<<<<<< + * + * + */ + goto __pyx_L8_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":386 + * + * # if we looped through the whole remaining polygon and can't find any more ears + * if ear is stop: # <<<<<<<<<<<<<< + * # try filtering points and slicing again + * if not pass_: + */ + } + __pyx_L7_continue:; + } + __pyx_L8_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":342 + * + * # main ear slicing loop which triangulates a polygon (given as a linked list) + * cdef earcut_linked( # <<<<<<<<<<<<<< + * Node ear, + * list triangles, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.earcut_linked", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_stop); + __Pyx_XDECREF((PyObject *)__pyx_v_prev); + __Pyx_XDECREF((PyObject *)__pyx_v_next); + __Pyx_XDECREF((PyObject *)__pyx_v_ear); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":409 + * + * + * cdef bint is_ear(Node ear): # <<<<<<<<<<<<<< + * """check whether a polygon node forms a valid ear with adjacent nodes""" + * cdef: + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_ear) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_c = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + double __pyx_v_x0; + double __pyx_v_x1; + double __pyx_v_y0; + double __pyx_v_y1; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_ear", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":412 + * """check whether a polygon node forms a valid ear with adjacent nodes""" + * cdef: + * Node a = ear.prev # <<<<<<<<<<<<<< + * Node b = ear + * Node c = ear.next + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_a = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":413 + * cdef: + * Node a = ear.prev + * Node b = ear # <<<<<<<<<<<<<< + * Node c = ear.next + * Node p + */ + __Pyx_INCREF((PyObject *)__pyx_v_ear); + __pyx_v_b = __pyx_v_ear; + + /* "ezdxf/acc/mapbox_earcut.pyx":414 + * Node a = ear.prev + * Node b = ear + * Node c = ear.next # <<<<<<<<<<<<<< + * Node p + * double x0, x1, y0, y1 + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_c = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":418 + * double x0, x1, y0, y1 + * + * if area(a, b, c) >= 0: # <<<<<<<<<<<<<< + * return False # reflex, can't be an ear + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, __pyx_v_b, __pyx_v_c); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 418, __pyx_L1_error) + __pyx_t_3 = (__pyx_t_2 >= 0.0); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":419 + * + * if area(a, b, c) >= 0: + * return False # reflex, can't be an ear # <<<<<<<<<<<<<< + * + * # now make sure we don't have other points inside the potential ear + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":418 + * double x0, x1, y0, y1 + * + * if area(a, b, c) >= 0: # <<<<<<<<<<<<<< + * return False # reflex, can't be an ear + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":423 + * # now make sure we don't have other points inside the potential ear + * # triangle bbox + * x0 = fmin(a.x, fmin(b.x, c.x)) # <<<<<<<<<<<<<< + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) + */ + __pyx_v_x0 = fmin(__pyx_v_a->x, fmin(__pyx_v_b->x, __pyx_v_c->x)); + + /* "ezdxf/acc/mapbox_earcut.pyx":424 + * # triangle bbox + * x0 = fmin(a.x, fmin(b.x, c.x)) + * x1 = fmax(a.x, fmax(b.x, c.x)) # <<<<<<<<<<<<<< + * y0 = fmin(a.y, fmin(b.y, c.y)) + * y1 = fmax(a.y, fmax(b.y, c.y)) + */ + __pyx_v_x1 = fmax(__pyx_v_a->x, fmax(__pyx_v_b->x, __pyx_v_c->x)); + + /* "ezdxf/acc/mapbox_earcut.pyx":425 + * x0 = fmin(a.x, fmin(b.x, c.x)) + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) # <<<<<<<<<<<<<< + * y1 = fmax(a.y, fmax(b.y, c.y)) + * p = c.next + */ + __pyx_v_y0 = fmin(__pyx_v_a->y, fmin(__pyx_v_b->y, __pyx_v_c->y)); + + /* "ezdxf/acc/mapbox_earcut.pyx":426 + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) + * y1 = fmax(a.y, fmax(b.y, c.y)) # <<<<<<<<<<<<<< + * p = c.next + * + */ + __pyx_v_y1 = fmax(__pyx_v_a->y, fmax(__pyx_v_b->y, __pyx_v_c->y)); + + /* "ezdxf/acc/mapbox_earcut.pyx":427 + * y0 = fmin(a.y, fmin(b.y, c.y)) + * y1 = fmax(a.y, fmax(b.y, c.y)) + * p = c.next # <<<<<<<<<<<<<< + * + * while p is not a: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_c->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_p = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":429 + * p = c.next + * + * while p is not a: # <<<<<<<<<<<<<< + * if ( + * x0 <= p.x <= x1 + */ + while (1) { + __pyx_t_3 = (__pyx_v_p != __pyx_v_a); + if (!__pyx_t_3) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":431 + * while p is not a: + * if ( + * x0 <= p.x <= x1 # <<<<<<<<<<<<<< + * and y0 <= p.y <= y1 + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + */ + __pyx_t_4 = (__pyx_v_x0 <= __pyx_v_p->x); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_p->x <= __pyx_v_x1); + } + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L7_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":432 + * if ( + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 # <<<<<<<<<<<<<< + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 + */ + __pyx_t_4 = (__pyx_v_y0 <= __pyx_v_p->y); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_p->y <= __pyx_v_y1); + } + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L7_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":433 + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) # <<<<<<<<<<<<<< + * and area(p.prev, p, p.next) >= 0 + * ): + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_v_a->x, __pyx_v_a->y, __pyx_v_b->x, __pyx_v_b->y, __pyx_v_c->x, __pyx_v_c->y, __pyx_v_p->x, __pyx_v_p->y); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 433, __pyx_L1_error) + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L7_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":434 + * and y0 <= p.y <= y1 + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 # <<<<<<<<<<<<<< + * ): + * return False + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_5 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_5); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1), __pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 434, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_4 = (__pyx_t_2 >= 0.0); + __pyx_t_3 = __pyx_t_4; + __pyx_L7_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":430 + * + * while p is not a: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":436 + * and area(p.prev, p, p.next) >= 0 + * ): + * return False # <<<<<<<<<<<<<< + * p = p.next + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":430 + * + * while p is not a: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":437 + * ): + * return False + * p = p.next # <<<<<<<<<<<<<< + * + * return True + */ + __pyx_t_5 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":439 + * p = p.next + * + * return True # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":409 + * + * + * cdef bint is_ear(Node ear): # <<<<<<<<<<<<<< + * """check whether a polygon node forms a valid ear with adjacent nodes""" + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.is_ear", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XDECREF((PyObject *)__pyx_v_c); + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":442 + * + * + * cdef bint is_ear_hashed(Node ear, double min_x, double min_y, double inv_size): # <<<<<<<<<<<<<< + * cdef: + * Node a = ear.prev + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_ear_hashed(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_ear, double __pyx_v_min_x, double __pyx_v_min_y, double __pyx_v_inv_size) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_c = 0; + double __pyx_v_x0; + double __pyx_v_x1; + double __pyx_v_y0; + double __pyx_v_y1; + double __pyx_v_min_z; + double __pyx_v_max_z; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_n = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_ear_hashed", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":444 + * cdef bint is_ear_hashed(Node ear, double min_x, double min_y, double inv_size): + * cdef: + * Node a = ear.prev # <<<<<<<<<<<<<< + * Node b = ear + * Node c = ear.next + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_a = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":445 + * cdef: + * Node a = ear.prev + * Node b = ear # <<<<<<<<<<<<<< + * Node c = ear.next + * double x0, x1, y0, y1, min_z, max_z + */ + __Pyx_INCREF((PyObject *)__pyx_v_ear); + __pyx_v_b = __pyx_v_ear; + + /* "ezdxf/acc/mapbox_earcut.pyx":446 + * Node a = ear.prev + * Node b = ear + * Node c = ear.next # <<<<<<<<<<<<<< + * double x0, x1, y0, y1, min_z, max_z + * Node p, n + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_c = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":450 + * Node p, n + * + * if area(a, b, c) >= 0: # <<<<<<<<<<<<<< + * return False # reflex, can't be an ear + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, __pyx_v_b, __pyx_v_c); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 450, __pyx_L1_error) + __pyx_t_3 = (__pyx_t_2 >= 0.0); + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":451 + * + * if area(a, b, c) >= 0: + * return False # reflex, can't be an ear # <<<<<<<<<<<<<< + * + * # triangle bbox + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":450 + * Node p, n + * + * if area(a, b, c) >= 0: # <<<<<<<<<<<<<< + * return False # reflex, can't be an ear + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":454 + * + * # triangle bbox + * x0 = fmin(a.x, fmin(b.x, c.x)) # <<<<<<<<<<<<<< + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) + */ + __pyx_v_x0 = fmin(__pyx_v_a->x, fmin(__pyx_v_b->x, __pyx_v_c->x)); + + /* "ezdxf/acc/mapbox_earcut.pyx":455 + * # triangle bbox + * x0 = fmin(a.x, fmin(b.x, c.x)) + * x1 = fmax(a.x, fmax(b.x, c.x)) # <<<<<<<<<<<<<< + * y0 = fmin(a.y, fmin(b.y, c.y)) + * y1 = fmax(a.y, fmax(b.y, c.y)) + */ + __pyx_v_x1 = fmax(__pyx_v_a->x, fmax(__pyx_v_b->x, __pyx_v_c->x)); + + /* "ezdxf/acc/mapbox_earcut.pyx":456 + * x0 = fmin(a.x, fmin(b.x, c.x)) + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) # <<<<<<<<<<<<<< + * y1 = fmax(a.y, fmax(b.y, c.y)) + * + */ + __pyx_v_y0 = fmin(__pyx_v_a->y, fmin(__pyx_v_b->y, __pyx_v_c->y)); + + /* "ezdxf/acc/mapbox_earcut.pyx":457 + * x1 = fmax(a.x, fmax(b.x, c.x)) + * y0 = fmin(a.y, fmin(b.y, c.y)) + * y1 = fmax(a.y, fmax(b.y, c.y)) # <<<<<<<<<<<<<< + * + * # z-order range for the current triangle bbox; + */ + __pyx_v_y1 = fmax(__pyx_v_a->y, fmax(__pyx_v_b->y, __pyx_v_c->y)); + + /* "ezdxf/acc/mapbox_earcut.pyx":460 + * + * # z-order range for the current triangle bbox; + * min_z = z_order(x0, y0, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * max_z = z_order(x1, y1, min_x, min_y, inv_size) + * + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_z_order(__pyx_v_x0, __pyx_v_y0, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 460, __pyx_L1_error) + __pyx_v_min_z = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":461 + * # z-order range for the current triangle bbox; + * min_z = z_order(x0, y0, min_x, min_y, inv_size) + * max_z = z_order(x1, y1, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * + * p = ear.prev_z + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_z_order(__pyx_v_x1, __pyx_v_y1, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 461, __pyx_L1_error) + __pyx_v_max_z = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":463 + * max_z = z_order(x1, y1, min_x, min_y, inv_size) + * + * p = ear.prev_z # <<<<<<<<<<<<<< + * n = ear.next_z + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->prev_z); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_p = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":464 + * + * p = ear.prev_z + * n = ear.next_z # <<<<<<<<<<<<<< + * + * # look for points inside the triangle in both directions + */ + __pyx_t_1 = ((PyObject *)__pyx_v_ear->next_z); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_n = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":467 + * + * # look for points inside the triangle in both directions + * while p and p.z >= min_z and n and n.z <= max_z: # <<<<<<<<<<<<<< + * if ( + * x0 <= p.x <= x1 + */ + while (1) { + __pyx_t_5 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_p)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(1, 467, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_5 = (__pyx_v_p->z >= __pyx_v_min_z); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_5 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_n)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(1, 467, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_5 = (__pyx_v_n->z <= __pyx_v_max_z); + __pyx_t_3 = __pyx_t_5; + __pyx_L6_bool_binop_done:; + if (!__pyx_t_3) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":469 + * while p and p.z >= min_z and n and n.z <= max_z: + * if ( + * x0 <= p.x <= x1 # <<<<<<<<<<<<<< + * and y0 <= p.y <= y1 + * and p is not a + */ + __pyx_t_5 = (__pyx_v_x0 <= __pyx_v_p->x); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_p->x <= __pyx_v_x1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L11_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":470 + * if ( + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 # <<<<<<<<<<<<<< + * and p is not a + * and p is not c + */ + __pyx_t_5 = (__pyx_v_y0 <= __pyx_v_p->y); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_p->y <= __pyx_v_y1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L11_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":471 + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + * and p is not a # <<<<<<<<<<<<<< + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + */ + __pyx_t_5 = (__pyx_v_p != __pyx_v_a); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L11_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":472 + * and y0 <= p.y <= y1 + * and p is not a + * and p is not c # <<<<<<<<<<<<<< + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 + */ + __pyx_t_5 = (__pyx_v_p != __pyx_v_c); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L11_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":473 + * and p is not a + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) # <<<<<<<<<<<<<< + * and area(p.prev, p, p.next) >= 0 + * ): + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_v_a->x, __pyx_v_a->y, __pyx_v_b->x, __pyx_v_b->y, __pyx_v_c->x, __pyx_v_c->y, __pyx_v_p->x, __pyx_v_p->y); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 473, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L11_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":474 + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 # <<<<<<<<<<<<<< + * ): + * return False + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_6 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_6); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1), __pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6)); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 474, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_5 = (__pyx_t_2 >= 0.0); + __pyx_t_3 = __pyx_t_5; + __pyx_L11_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":468 + * # look for points inside the triangle in both directions + * while p and p.z >= min_z and n and n.z <= max_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":476 + * and area(p.prev, p, p.next) >= 0 + * ): + * return False # <<<<<<<<<<<<<< + * p = p.prev_z + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":468 + * # look for points inside the triangle in both directions + * while p and p.z >= min_z and n and n.z <= max_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":477 + * ): + * return False + * p = p.prev_z # <<<<<<<<<<<<<< + * + * if ( + */ + __pyx_t_6 = ((PyObject *)__pyx_v_p->prev_z); + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6)); + __pyx_t_6 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":480 + * + * if ( + * x0 <= n.x <= x1 # <<<<<<<<<<<<<< + * and y0 <= n.y <= y1 + * and n is not a + */ + __pyx_t_5 = (__pyx_v_x0 <= __pyx_v_n->x); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_n->x <= __pyx_v_x1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L18_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":481 + * if ( + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 # <<<<<<<<<<<<<< + * and n is not a + * and n is not c + */ + __pyx_t_5 = (__pyx_v_y0 <= __pyx_v_n->y); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_n->y <= __pyx_v_y1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L18_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":482 + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + * and n is not a # <<<<<<<<<<<<<< + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + */ + __pyx_t_5 = (__pyx_v_n != __pyx_v_a); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L18_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":483 + * and y0 <= n.y <= y1 + * and n is not a + * and n is not c # <<<<<<<<<<<<<< + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + * and area(n.prev, n, n.next) >= 0 + */ + __pyx_t_5 = (__pyx_v_n != __pyx_v_c); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L18_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":484 + * and n is not a + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) # <<<<<<<<<<<<<< + * and area(n.prev, n, n.next) >= 0 + * ): + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_v_a->x, __pyx_v_a->y, __pyx_v_b->x, __pyx_v_b->y, __pyx_v_c->x, __pyx_v_c->y, __pyx_v_n->x, __pyx_v_n->y); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 484, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L18_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":485 + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + * and area(n.prev, n, n.next) >= 0 # <<<<<<<<<<<<<< + * ): + * return False + */ + __pyx_t_6 = ((PyObject *)__pyx_v_n->prev); + __Pyx_INCREF(__pyx_t_6); + __pyx_t_1 = ((PyObject *)__pyx_v_n->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6), __pyx_v_n, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 485, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_5 = (__pyx_t_2 >= 0.0); + __pyx_t_3 = __pyx_t_5; + __pyx_L18_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":479 + * p = p.prev_z + * + * if ( # <<<<<<<<<<<<<< + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + */ + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":487 + * and area(n.prev, n, n.next) >= 0 + * ): + * return False # <<<<<<<<<<<<<< + * n = n.next_z + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":479 + * p = p.prev_z + * + * if ( # <<<<<<<<<<<<<< + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":488 + * ): + * return False + * n = n.next_z # <<<<<<<<<<<<<< + * + * # look for remaining points in decreasing z-order + */ + __pyx_t_1 = ((PyObject *)__pyx_v_n->next_z); + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_n, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":491 + * + * # look for remaining points in decreasing z-order + * while p and p.z >= min_z: # <<<<<<<<<<<<<< + * if ( + * x0 <= p.x <= x1 + */ + while (1) { + __pyx_t_5 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_p)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(1, 491, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L26_bool_binop_done; + } + __pyx_t_5 = (__pyx_v_p->z >= __pyx_v_min_z); + __pyx_t_3 = __pyx_t_5; + __pyx_L26_bool_binop_done:; + if (!__pyx_t_3) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":493 + * while p and p.z >= min_z: + * if ( + * x0 <= p.x <= x1 # <<<<<<<<<<<<<< + * and y0 <= p.y <= y1 + * and p is not a + */ + __pyx_t_5 = (__pyx_v_x0 <= __pyx_v_p->x); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_p->x <= __pyx_v_x1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L29_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":494 + * if ( + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 # <<<<<<<<<<<<<< + * and p is not a + * and p is not c + */ + __pyx_t_5 = (__pyx_v_y0 <= __pyx_v_p->y); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_p->y <= __pyx_v_y1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L29_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":495 + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + * and p is not a # <<<<<<<<<<<<<< + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + */ + __pyx_t_5 = (__pyx_v_p != __pyx_v_a); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L29_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":496 + * and y0 <= p.y <= y1 + * and p is not a + * and p is not c # <<<<<<<<<<<<<< + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 + */ + __pyx_t_5 = (__pyx_v_p != __pyx_v_c); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L29_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":497 + * and p is not a + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) # <<<<<<<<<<<<<< + * and area(p.prev, p, p.next) >= 0 + * ): + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_v_a->x, __pyx_v_a->y, __pyx_v_b->x, __pyx_v_b->y, __pyx_v_c->x, __pyx_v_c->y, __pyx_v_p->x, __pyx_v_p->y); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 497, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L29_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":498 + * and p is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + * and area(p.prev, p, p.next) >= 0 # <<<<<<<<<<<<<< + * ): + * return False + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_6 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_6); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1), __pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6)); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 498, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_5 = (__pyx_t_2 >= 0.0); + __pyx_t_3 = __pyx_t_5; + __pyx_L29_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":492 + * # look for remaining points in decreasing z-order + * while p and p.z >= min_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":500 + * and area(p.prev, p, p.next) >= 0 + * ): + * return False # <<<<<<<<<<<<<< + * p = p.prev_z + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":492 + * # look for remaining points in decreasing z-order + * while p and p.z >= min_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= p.x <= x1 + * and y0 <= p.y <= y1 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":501 + * ): + * return False + * p = p.prev_z # <<<<<<<<<<<<<< + * + * # look for remaining points in increasing z-order + */ + __pyx_t_6 = ((PyObject *)__pyx_v_p->prev_z); + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6)); + __pyx_t_6 = 0; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":504 + * + * # look for remaining points in increasing z-order + * while n and n.z <= max_z: # <<<<<<<<<<<<<< + * if ( + * x0 <= n.x <= x1 + */ + while (1) { + __pyx_t_5 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_n)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(1, 504, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L37_bool_binop_done; + } + __pyx_t_5 = (__pyx_v_n->z <= __pyx_v_max_z); + __pyx_t_3 = __pyx_t_5; + __pyx_L37_bool_binop_done:; + if (!__pyx_t_3) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":506 + * while n and n.z <= max_z: + * if ( + * x0 <= n.x <= x1 # <<<<<<<<<<<<<< + * and y0 <= n.y <= y1 + * and n is not a + */ + __pyx_t_5 = (__pyx_v_x0 <= __pyx_v_n->x); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_n->x <= __pyx_v_x1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L40_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":507 + * if ( + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 # <<<<<<<<<<<<<< + * and n is not a + * and n is not c + */ + __pyx_t_5 = (__pyx_v_y0 <= __pyx_v_n->y); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_n->y <= __pyx_v_y1); + } + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L40_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":508 + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + * and n is not a # <<<<<<<<<<<<<< + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + */ + __pyx_t_5 = (__pyx_v_n != __pyx_v_a); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L40_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":509 + * and y0 <= n.y <= y1 + * and n is not a + * and n is not c # <<<<<<<<<<<<<< + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + * and area(n.prev, n, n.next) >= 0 + */ + __pyx_t_5 = (__pyx_v_n != __pyx_v_c); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L40_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":510 + * and n is not a + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) # <<<<<<<<<<<<<< + * and area(n.prev, n, n.next) >= 0 + * ): + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_v_a->x, __pyx_v_a->y, __pyx_v_b->x, __pyx_v_b->y, __pyx_v_c->x, __pyx_v_c->y, __pyx_v_n->x, __pyx_v_n->y); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 510, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L40_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":511 + * and n is not c + * and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + * and area(n.prev, n, n.next) >= 0 # <<<<<<<<<<<<<< + * ): + * return False + */ + __pyx_t_6 = ((PyObject *)__pyx_v_n->prev); + __Pyx_INCREF(__pyx_t_6); + __pyx_t_1 = ((PyObject *)__pyx_v_n->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6), __pyx_v_n, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 511, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_5 = (__pyx_t_2 >= 0.0); + __pyx_t_3 = __pyx_t_5; + __pyx_L40_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":505 + * # look for remaining points in increasing z-order + * while n and n.z <= max_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + */ + if (__pyx_t_3) { + + /* "ezdxf/acc/mapbox_earcut.pyx":513 + * and area(n.prev, n, n.next) >= 0 + * ): + * return False # <<<<<<<<<<<<<< + * n = n.next_z + * return True + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":505 + * # look for remaining points in increasing z-order + * while n and n.z <= max_z: + * if ( # <<<<<<<<<<<<<< + * x0 <= n.x <= x1 + * and y0 <= n.y <= y1 + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":514 + * ): + * return False + * n = n.next_z # <<<<<<<<<<<<<< + * return True + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_n->next_z); + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_n, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":515 + * return False + * n = n.next_z + * return True # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":442 + * + * + * cdef bint is_ear_hashed(Node ear, double min_x, double min_y, double inv_size): # <<<<<<<<<<<<<< + * cdef: + * Node a = ear.prev + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.is_ear_hashed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XDECREF((PyObject *)__pyx_v_c); + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_n); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":518 + * + * + * cdef Node get_leftmost(Node start): # <<<<<<<<<<<<<< + * """Find the leftmost node of a polygon ring""" + * cdef: + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_get_leftmost(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_start) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_leftmost = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + __Pyx_RefNannySetupContext("get_leftmost", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":521 + * """Find the leftmost node of a polygon ring""" + * cdef: + * Node p = start # <<<<<<<<<<<<<< + * Node leftmost = start + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_p = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":522 + * cdef: + * Node p = start + * Node leftmost = start # <<<<<<<<<<<<<< + * + * while True: + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_leftmost = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":524 + * Node leftmost = start + * + * while True: # <<<<<<<<<<<<<< + * if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): + * leftmost = p + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":525 + * + * while True: + * if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): # <<<<<<<<<<<<<< + * leftmost = p + * p = p.next + */ + __pyx_t_2 = (__pyx_v_p->x < __pyx_v_leftmost->x); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_p->x == __pyx_v_leftmost->x); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_p->y < __pyx_v_leftmost->y); + __pyx_t_1 = __pyx_t_2; + __pyx_L6_bool_binop_done:; + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":526 + * while True: + * if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): + * leftmost = p # <<<<<<<<<<<<<< + * p = p.next + * if p is start: + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_DECREF_SET(__pyx_v_leftmost, __pyx_v_p); + + /* "ezdxf/acc/mapbox_earcut.pyx":525 + * + * while True: + * if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): # <<<<<<<<<<<<<< + * leftmost = p + * p = p.next + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":527 + * if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): + * leftmost = p + * p = p.next # <<<<<<<<<<<<<< + * if p is start: + * break + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":528 + * leftmost = p + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * return leftmost + */ + __pyx_t_1 = (__pyx_v_p == __pyx_v_start); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":529 + * p = p.next + * if p is start: + * break # <<<<<<<<<<<<<< + * return leftmost + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":528 + * leftmost = p + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * return leftmost + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":530 + * if p is start: + * break + * return leftmost # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_leftmost); + __pyx_r = __pyx_v_leftmost; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":518 + * + * + * cdef Node get_leftmost(Node start): # <<<<<<<<<<<<<< + * """Find the leftmost node of a polygon ring""" + * cdef: + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_leftmost); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":533 + * + * + * cdef bint point_in_triangle( # <<<<<<<<<<<<<< + * double ax, + * double ay, + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(double __pyx_v_ax, double __pyx_v_ay, double __pyx_v_bx, double __pyx_v_by_, double __pyx_v_cx, double __pyx_v_cy, double __pyx_v_px, double __pyx_v_py) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":545 + * """Check if a point lies within a convex triangle""" + * return ( + * (cx - px) * (ay - py) >= (ax - px) * (cy - py) # <<<<<<<<<<<<<< + * and (ax - px) * (by_ - py) >= (bx - px) * (ay - py) + * and (bx - px) * (cy - py) >= (cx - px) * (by_ - py) + */ + __pyx_t_2 = (((__pyx_v_cx - __pyx_v_px) * (__pyx_v_ay - __pyx_v_py)) >= ((__pyx_v_ax - __pyx_v_px) * (__pyx_v_cy - __pyx_v_py))); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":546 + * return ( + * (cx - px) * (ay - py) >= (ax - px) * (cy - py) + * and (ax - px) * (by_ - py) >= (bx - px) * (ay - py) # <<<<<<<<<<<<<< + * and (bx - px) * (cy - py) >= (cx - px) * (by_ - py) + * ) + */ + __pyx_t_2 = (((__pyx_v_ax - __pyx_v_px) * (__pyx_v_by_ - __pyx_v_py)) >= ((__pyx_v_bx - __pyx_v_px) * (__pyx_v_ay - __pyx_v_py))); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":547 + * (cx - px) * (ay - py) >= (ax - px) * (cy - py) + * and (ax - px) * (by_ - py) >= (bx - px) * (ay - py) + * and (bx - px) * (cy - py) >= (cx - px) * (by_ - py) # <<<<<<<<<<<<<< + * ) + * + */ + __pyx_t_2 = (((__pyx_v_bx - __pyx_v_px) * (__pyx_v_cy - __pyx_v_py)) >= ((__pyx_v_cx - __pyx_v_px) * (__pyx_v_by_ - __pyx_v_py))); + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":533 + * + * + * cdef bint point_in_triangle( # <<<<<<<<<<<<<< + * double ax, + * double ay, + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":551 + * + * + * cdef bint sector_contains_sector(Node m, Node p): # <<<<<<<<<<<<<< + * """Whether sector in vertex m contains sector in vertex p in the same + * coordinates. + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_sector_contains_sector(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_m, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("sector_contains_sector", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":555 + * coordinates. + * """ + * return area(m.prev, m, p.prev) < 0 and area(p.next, m, m.next) < 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = ((PyObject *)__pyx_v_m->prev); + __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_2), __pyx_v_m, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 555, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = (__pyx_t_4 < 0.0); + if (__pyx_t_5) { + } else { + __pyx_t_1 = __pyx_t_5; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_2 = ((PyObject *)__pyx_v_m->next); + __Pyx_INCREF(__pyx_t_2); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_m, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_2)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 555, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = (__pyx_t_4 < 0.0); + __pyx_t_1 = __pyx_t_5; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":551 + * + * + * cdef bint sector_contains_sector(Node m, Node p): # <<<<<<<<<<<<<< + * """Whether sector in vertex m contains sector in vertex p in the same + * coordinates. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.sector_contains_sector", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":558 + * + * + * cdef index_curve(Node start, double min_x, double min_y, double inv_size): # <<<<<<<<<<<<<< + * """Interlink polygon nodes in z-order""" + * cdef Node p = start + */ + +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_index_curve(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_start, double __pyx_v_min_x, double __pyx_v_min_y, double __pyx_v_inv_size) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("index_curve", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":560 + * cdef index_curve(Node start, double min_x, double min_y, double inv_size): + * """Interlink polygon nodes in z-order""" + * cdef Node p = start # <<<<<<<<<<<<<< + * while True: + * if p.z == 0: + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_p = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":561 + * """Interlink polygon nodes in z-order""" + * cdef Node p = start + * while True: # <<<<<<<<<<<<<< + * if p.z == 0: + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":562 + * cdef Node p = start + * while True: + * if p.z == 0: # <<<<<<<<<<<<<< + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + * p.prev_z = p.prev + */ + __pyx_t_1 = (__pyx_v_p->z == 0); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":563 + * while True: + * if p.z == 0: + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) # <<<<<<<<<<<<<< + * p.prev_z = p.prev + * p.next_z = p.next + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_z_order(__pyx_v_p->x, __pyx_v_p->y, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 563, __pyx_L1_error) + __pyx_v_p->z = __pyx_t_2; + + /* "ezdxf/acc/mapbox_earcut.pyx":562 + * cdef Node p = start + * while True: + * if p.z == 0: # <<<<<<<<<<<<<< + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + * p.prev_z = p.prev + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":564 + * if p.z == 0: + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + * p.prev_z = p.prev # <<<<<<<<<<<<<< + * p.next_z = p.next + * p = p.next + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev_z); + __pyx_v_p->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":565 + * p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + * p.prev_z = p.prev + * p.next_z = p.next # <<<<<<<<<<<<<< + * p = p.next + * if p is start: + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_GOTREF((PyObject *)__pyx_v_p->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->next_z); + __pyx_v_p->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":566 + * p.prev_z = p.prev + * p.next_z = p.next + * p = p.next # <<<<<<<<<<<<<< + * if p is start: + * break + */ + __pyx_t_3 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":567 + * p.next_z = p.next + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * + */ + __pyx_t_1 = (__pyx_v_p == __pyx_v_start); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":568 + * p = p.next + * if p is start: + * break # <<<<<<<<<<<<<< + * + * p.prev_z.next_z = None + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":567 + * p.next_z = p.next + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":570 + * break + * + * p.prev_z.next_z = None # <<<<<<<<<<<<<< + * p.prev_z = None + * + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev_z->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev_z->next_z); + __pyx_v_p->prev_z->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":571 + * + * p.prev_z.next_z = None + * p.prev_z = None # <<<<<<<<<<<<<< + * + * sort_linked(p) + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_p->prev_z); + __Pyx_DECREF((PyObject *)__pyx_v_p->prev_z); + __pyx_v_p->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":573 + * p.prev_z = None + * + * sort_linked(p) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_sort_linked(__pyx_v_p)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 573, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":558 + * + * + * cdef index_curve(Node start, double min_x, double min_y, double inv_size): # <<<<<<<<<<<<<< + * """Interlink polygon nodes in z-order""" + * cdef Node p = start + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.index_curve", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":576 + * + * + * cdef int z_order( # <<<<<<<<<<<<<< + * double x0, double y0, double min_x, double min_y, double inv_size + * ): + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_z_order(double __pyx_v_x0, double __pyx_v_y0, double __pyx_v_min_x, double __pyx_v_min_y, double __pyx_v_inv_size) { + int __pyx_v_x; + int __pyx_v_y; + int __pyx_r; + + /* "ezdxf/acc/mapbox_earcut.pyx":584 + * # coords are transformed into non-negative 15-bit integer range + * cdef: + * int x = int((x0 - min_x) * inv_size) # <<<<<<<<<<<<<< + * int y = int ((y0 - min_y) * inv_size) + * + */ + __pyx_v_x = ((int)((__pyx_v_x0 - __pyx_v_min_x) * __pyx_v_inv_size)); + + /* "ezdxf/acc/mapbox_earcut.pyx":585 + * cdef: + * int x = int((x0 - min_x) * inv_size) + * int y = int ((y0 - min_y) * inv_size) # <<<<<<<<<<<<<< + * + * x = (x | (x << 8)) & 0x00FF00FF + */ + __pyx_v_y = ((int)((__pyx_v_y0 - __pyx_v_min_y) * __pyx_v_inv_size)); + + /* "ezdxf/acc/mapbox_earcut.pyx":587 + * int y = int ((y0 - min_y) * inv_size) + * + * x = (x | (x << 8)) & 0x00FF00FF # <<<<<<<<<<<<<< + * x = (x | (x << 4)) & 0x0F0F0F0F + * x = (x | (x << 2)) & 0x33333333 + */ + __pyx_v_x = ((__pyx_v_x | (__pyx_v_x << 8)) & 0x00FF00FF); + + /* "ezdxf/acc/mapbox_earcut.pyx":588 + * + * x = (x | (x << 8)) & 0x00FF00FF + * x = (x | (x << 4)) & 0x0F0F0F0F # <<<<<<<<<<<<<< + * x = (x | (x << 2)) & 0x33333333 + * x = (x | (x << 1)) & 0x55555555 + */ + __pyx_v_x = ((__pyx_v_x | (__pyx_v_x << 4)) & 0x0F0F0F0F); + + /* "ezdxf/acc/mapbox_earcut.pyx":589 + * x = (x | (x << 8)) & 0x00FF00FF + * x = (x | (x << 4)) & 0x0F0F0F0F + * x = (x | (x << 2)) & 0x33333333 # <<<<<<<<<<<<<< + * x = (x | (x << 1)) & 0x55555555 + * + */ + __pyx_v_x = ((__pyx_v_x | (__pyx_v_x << 2)) & 0x33333333); + + /* "ezdxf/acc/mapbox_earcut.pyx":590 + * x = (x | (x << 4)) & 0x0F0F0F0F + * x = (x | (x << 2)) & 0x33333333 + * x = (x | (x << 1)) & 0x55555555 # <<<<<<<<<<<<<< + * + * y = (y | (y << 8)) & 0x00FF00FF + */ + __pyx_v_x = ((__pyx_v_x | (__pyx_v_x << 1)) & 0x55555555); + + /* "ezdxf/acc/mapbox_earcut.pyx":592 + * x = (x | (x << 1)) & 0x55555555 + * + * y = (y | (y << 8)) & 0x00FF00FF # <<<<<<<<<<<<<< + * y = (y | (y << 4)) & 0x0F0F0F0F + * y = (y | (y << 2)) & 0x33333333 + */ + __pyx_v_y = ((__pyx_v_y | (__pyx_v_y << 8)) & 0x00FF00FF); + + /* "ezdxf/acc/mapbox_earcut.pyx":593 + * + * y = (y | (y << 8)) & 0x00FF00FF + * y = (y | (y << 4)) & 0x0F0F0F0F # <<<<<<<<<<<<<< + * y = (y | (y << 2)) & 0x33333333 + * y = (y | (y << 1)) & 0x55555555 + */ + __pyx_v_y = ((__pyx_v_y | (__pyx_v_y << 4)) & 0x0F0F0F0F); + + /* "ezdxf/acc/mapbox_earcut.pyx":594 + * y = (y | (y << 8)) & 0x00FF00FF + * y = (y | (y << 4)) & 0x0F0F0F0F + * y = (y | (y << 2)) & 0x33333333 # <<<<<<<<<<<<<< + * y = (y | (y << 1)) & 0x55555555 + * + */ + __pyx_v_y = ((__pyx_v_y | (__pyx_v_y << 2)) & 0x33333333); + + /* "ezdxf/acc/mapbox_earcut.pyx":595 + * y = (y | (y << 4)) & 0x0F0F0F0F + * y = (y | (y << 2)) & 0x33333333 + * y = (y | (y << 1)) & 0x55555555 # <<<<<<<<<<<<<< + * + * return x | (y << 1) + */ + __pyx_v_y = ((__pyx_v_y | (__pyx_v_y << 1)) & 0x55555555); + + /* "ezdxf/acc/mapbox_earcut.pyx":597 + * y = (y | (y << 1)) & 0x55555555 + * + * return x | (y << 1) # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = (__pyx_v_x | (__pyx_v_y << 1)); + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":576 + * + * + * cdef int z_order( # <<<<<<<<<<<<<< + * double x0, double y0, double min_x, double min_y, double inv_size + * ): + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":602 + * # Simon Tatham's linked list merge sort algorithm + * # http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + * cdef Node sort_linked(Node head): # <<<<<<<<<<<<<< + * cdef: + * int in_size = 1 + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_sort_linked(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_head) { + int __pyx_v_in_size; + int __pyx_v_num_merges; + int __pyx_v_p_size; + int __pyx_v_q_size; + CYTHON_UNUSED int __pyx_v_i; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_tail = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_q = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_e = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + int __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("sort_linked", 0); + __Pyx_INCREF((PyObject *)__pyx_v_head); + + /* "ezdxf/acc/mapbox_earcut.pyx":604 + * cdef Node sort_linked(Node head): + * cdef: + * int in_size = 1 # <<<<<<<<<<<<<< + * int num_merges, p_size, q_size, i + * Node tail, p, q, e + */ + __pyx_v_in_size = 1; + + /* "ezdxf/acc/mapbox_earcut.pyx":608 + * Node tail, p, q, e + * + * while True: # <<<<<<<<<<<<<< + * p = head + * head = None + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":609 + * + * while True: + * p = head # <<<<<<<<<<<<<< + * head = None + * tail = None + */ + __Pyx_INCREF((PyObject *)__pyx_v_head); + __Pyx_XDECREF_SET(__pyx_v_p, __pyx_v_head); + + /* "ezdxf/acc/mapbox_earcut.pyx":610 + * while True: + * p = head + * head = None # <<<<<<<<<<<<<< + * tail = None + * num_merges = 0 + */ + __Pyx_INCREF(Py_None); + __Pyx_DECREF_SET(__pyx_v_head, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None)); + + /* "ezdxf/acc/mapbox_earcut.pyx":611 + * p = head + * head = None + * tail = None # <<<<<<<<<<<<<< + * num_merges = 0 + * while p: + */ + __Pyx_INCREF(Py_None); + __Pyx_XDECREF_SET(__pyx_v_tail, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None)); + + /* "ezdxf/acc/mapbox_earcut.pyx":612 + * head = None + * tail = None + * num_merges = 0 # <<<<<<<<<<<<<< + * while p: + * num_merges += 1 + */ + __pyx_v_num_merges = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":613 + * tail = None + * num_merges = 0 + * while p: # <<<<<<<<<<<<<< + * num_merges += 1 + * q = p + */ + while (1) { + __pyx_t_1 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_p)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 613, __pyx_L1_error) + if (!__pyx_t_1) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":614 + * num_merges = 0 + * while p: + * num_merges += 1 # <<<<<<<<<<<<<< + * q = p + * p_size = 0 + */ + __pyx_v_num_merges = (__pyx_v_num_merges + 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":615 + * while p: + * num_merges += 1 + * q = p # <<<<<<<<<<<<<< + * p_size = 0 + * for i in range(in_size): + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF_SET(__pyx_v_q, __pyx_v_p); + + /* "ezdxf/acc/mapbox_earcut.pyx":616 + * num_merges += 1 + * q = p + * p_size = 0 # <<<<<<<<<<<<<< + * for i in range(in_size): + * p_size += 1 + */ + __pyx_v_p_size = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":617 + * q = p + * p_size = 0 + * for i in range(in_size): # <<<<<<<<<<<<<< + * p_size += 1 + * q = q.next_z + */ + __pyx_t_2 = __pyx_v_in_size; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "ezdxf/acc/mapbox_earcut.pyx":618 + * p_size = 0 + * for i in range(in_size): + * p_size += 1 # <<<<<<<<<<<<<< + * q = q.next_z + * if not q: + */ + __pyx_v_p_size = (__pyx_v_p_size + 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":619 + * for i in range(in_size): + * p_size += 1 + * q = q.next_z # <<<<<<<<<<<<<< + * if not q: + * break + */ + __pyx_t_5 = ((PyObject *)__pyx_v_q->next_z); + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_q, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":620 + * p_size += 1 + * q = q.next_z + * if not q: # <<<<<<<<<<<<<< + * break + * q_size = in_size + */ + __pyx_t_1 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_q)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 620, __pyx_L1_error) + __pyx_t_6 = (!__pyx_t_1); + if (__pyx_t_6) { + + /* "ezdxf/acc/mapbox_earcut.pyx":621 + * q = q.next_z + * if not q: + * break # <<<<<<<<<<<<<< + * q_size = in_size + * while p_size > 0 or (q_size > 0 and q): + */ + goto __pyx_L8_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":620 + * p_size += 1 + * q = q.next_z + * if not q: # <<<<<<<<<<<<<< + * break + * q_size = in_size + */ + } + } + __pyx_L8_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":622 + * if not q: + * break + * q_size = in_size # <<<<<<<<<<<<<< + * while p_size > 0 or (q_size > 0 and q): + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + */ + __pyx_v_q_size = __pyx_v_in_size; + + /* "ezdxf/acc/mapbox_earcut.pyx":623 + * break + * q_size = in_size + * while p_size > 0 or (q_size > 0 and q): # <<<<<<<<<<<<<< + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + * e = p + */ + while (1) { + __pyx_t_1 = (__pyx_v_p_size > 0); + if (!__pyx_t_1) { + } else { + __pyx_t_6 = __pyx_t_1; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_1 = (__pyx_v_q_size > 0); + if (__pyx_t_1) { + } else { + __pyx_t_6 = __pyx_t_1; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_1 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_q)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 623, __pyx_L1_error) + __pyx_t_6 = __pyx_t_1; + __pyx_L12_bool_binop_done:; + if (!__pyx_t_6) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":624 + * q_size = in_size + * while p_size > 0 or (q_size > 0 and q): + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): # <<<<<<<<<<<<<< + * e = p + * p = p.next_z + */ + __pyx_t_1 = (__pyx_v_p_size != 0); + if (__pyx_t_1) { + } else { + __pyx_t_6 = __pyx_t_1; + goto __pyx_L16_bool_binop_done; + } + __pyx_t_1 = (__pyx_v_q_size == 0); + if (!__pyx_t_1) { + } else { + __pyx_t_6 = __pyx_t_1; + goto __pyx_L16_bool_binop_done; + } + __pyx_t_1 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_q)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 624, __pyx_L1_error) + __pyx_t_7 = (!__pyx_t_1); + if (!__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L16_bool_binop_done; + } + __pyx_t_7 = (__pyx_v_p->z <= __pyx_v_q->z); + __pyx_t_6 = __pyx_t_7; + __pyx_L16_bool_binop_done:; + if (__pyx_t_6) { + + /* "ezdxf/acc/mapbox_earcut.pyx":625 + * while p_size > 0 or (q_size > 0 and q): + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + * e = p # <<<<<<<<<<<<<< + * p = p.next_z + * p_size -= 1 + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF_SET(__pyx_v_e, __pyx_v_p); + + /* "ezdxf/acc/mapbox_earcut.pyx":626 + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + * e = p + * p = p.next_z # <<<<<<<<<<<<<< + * p_size -= 1 + * else: + */ + __pyx_t_5 = ((PyObject *)__pyx_v_p->next_z); + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":627 + * e = p + * p = p.next_z + * p_size -= 1 # <<<<<<<<<<<<<< + * else: + * e = q + */ + __pyx_v_p_size = (__pyx_v_p_size - 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":624 + * q_size = in_size + * while p_size > 0 or (q_size > 0 and q): + * if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): # <<<<<<<<<<<<<< + * e = p + * p = p.next_z + */ + goto __pyx_L15; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":629 + * p_size -= 1 + * else: + * e = q # <<<<<<<<<<<<<< + * q = q.next_z + * q_size -= 1 + */ + /*else*/ { + __Pyx_INCREF((PyObject *)__pyx_v_q); + __Pyx_XDECREF_SET(__pyx_v_e, __pyx_v_q); + + /* "ezdxf/acc/mapbox_earcut.pyx":630 + * else: + * e = q + * q = q.next_z # <<<<<<<<<<<<<< + * q_size -= 1 + * + */ + __pyx_t_5 = ((PyObject *)__pyx_v_q->next_z); + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_q, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":631 + * e = q + * q = q.next_z + * q_size -= 1 # <<<<<<<<<<<<<< + * + * if tail: + */ + __pyx_v_q_size = (__pyx_v_q_size - 1); + } + __pyx_L15:; + + /* "ezdxf/acc/mapbox_earcut.pyx":633 + * q_size -= 1 + * + * if tail: # <<<<<<<<<<<<<< + * tail.next_z = e + * else: + */ + __pyx_t_6 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_tail)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 633, __pyx_L1_error) + if (__pyx_t_6) { + + /* "ezdxf/acc/mapbox_earcut.pyx":634 + * + * if tail: + * tail.next_z = e # <<<<<<<<<<<<<< + * else: + * head = e + */ + __Pyx_INCREF((PyObject *)__pyx_v_e); + __Pyx_GIVEREF((PyObject *)__pyx_v_e); + __Pyx_GOTREF((PyObject *)__pyx_v_tail->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_tail->next_z); + __pyx_v_tail->next_z = __pyx_v_e; + + /* "ezdxf/acc/mapbox_earcut.pyx":633 + * q_size -= 1 + * + * if tail: # <<<<<<<<<<<<<< + * tail.next_z = e + * else: + */ + goto __pyx_L20; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":636 + * tail.next_z = e + * else: + * head = e # <<<<<<<<<<<<<< + * e.prev_z = tail + * tail = e + */ + /*else*/ { + __Pyx_INCREF((PyObject *)__pyx_v_e); + __Pyx_DECREF_SET(__pyx_v_head, __pyx_v_e); + } + __pyx_L20:; + + /* "ezdxf/acc/mapbox_earcut.pyx":637 + * else: + * head = e + * e.prev_z = tail # <<<<<<<<<<<<<< + * tail = e + * p = q + */ + __Pyx_INCREF((PyObject *)__pyx_v_tail); + __Pyx_GIVEREF((PyObject *)__pyx_v_tail); + __Pyx_GOTREF((PyObject *)__pyx_v_e->prev_z); + __Pyx_DECREF((PyObject *)__pyx_v_e->prev_z); + __pyx_v_e->prev_z = __pyx_v_tail; + + /* "ezdxf/acc/mapbox_earcut.pyx":638 + * head = e + * e.prev_z = tail + * tail = e # <<<<<<<<<<<<<< + * p = q + * tail.next_z = None + */ + __Pyx_INCREF((PyObject *)__pyx_v_e); + __Pyx_DECREF_SET(__pyx_v_tail, __pyx_v_e); + } + + /* "ezdxf/acc/mapbox_earcut.pyx":639 + * e.prev_z = tail + * tail = e + * p = q # <<<<<<<<<<<<<< + * tail.next_z = None + * in_size *= 2 + */ + __Pyx_INCREF((PyObject *)__pyx_v_q); + __Pyx_DECREF_SET(__pyx_v_p, __pyx_v_q); + } + + /* "ezdxf/acc/mapbox_earcut.pyx":640 + * tail = e + * p = q + * tail.next_z = None # <<<<<<<<<<<<<< + * in_size *= 2 + * if num_merges <= 1: + */ + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_GOTREF((PyObject *)__pyx_v_tail->next_z); + __Pyx_DECREF((PyObject *)__pyx_v_tail->next_z); + __pyx_v_tail->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":641 + * p = q + * tail.next_z = None + * in_size *= 2 # <<<<<<<<<<<<<< + * if num_merges <= 1: + * break + */ + __pyx_v_in_size = (__pyx_v_in_size * 2); + + /* "ezdxf/acc/mapbox_earcut.pyx":642 + * tail.next_z = None + * in_size *= 2 + * if num_merges <= 1: # <<<<<<<<<<<<<< + * break + * return head + */ + __pyx_t_6 = (__pyx_v_num_merges <= 1); + if (__pyx_t_6) { + + /* "ezdxf/acc/mapbox_earcut.pyx":643 + * in_size *= 2 + * if num_merges <= 1: + * break # <<<<<<<<<<<<<< + * return head + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":642 + * tail.next_z = None + * in_size *= 2 + * if num_merges <= 1: # <<<<<<<<<<<<<< + * break + * return head + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":644 + * if num_merges <= 1: + * break + * return head # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_head); + __pyx_r = __pyx_v_head; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":602 + * # Simon Tatham's linked list merge sort algorithm + * # http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + * cdef Node sort_linked(Node head): # <<<<<<<<<<<<<< + * cdef: + * int in_size = 1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.sort_linked", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_tail); + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_q); + __Pyx_XDECREF((PyObject *)__pyx_v_e); + __Pyx_XDECREF((PyObject *)__pyx_v_head); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":647 + * + * + * cdef Node split_polygon(Node a, Node b): # <<<<<<<<<<<<<< + * """Link two polygon vertices with a bridge. + * + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_polygon(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a2 = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b2 = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_an = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_bp = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("split_polygon", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":655 + * """ + * cdef : + * Node a2 = Node(a.i, a.point) # <<<<<<<<<<<<<< + * Node b2 = Node(b.i, b.point) + * Node an = a.next + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_a->i); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(1, 655, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_a->point); + __Pyx_GIVEREF(__pyx_v_a->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_a->point)) __PYX_ERR(1, 655, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node), __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_a2 = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":656 + * cdef : + * Node a2 = Node(a.i, a.point) + * Node b2 = Node(b.i, b.point) # <<<<<<<<<<<<<< + * Node an = a.next + * Node bp = b.prev + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_b->i); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(1, 656, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_b->point); + __Pyx_GIVEREF(__pyx_v_b->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_b->point)) __PYX_ERR(1, 656, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node), __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_b2 = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":657 + * Node a2 = Node(a.i, a.point) + * Node b2 = Node(b.i, b.point) + * Node an = a.next # <<<<<<<<<<<<<< + * Node bp = b.prev + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_an = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":658 + * Node b2 = Node(b.i, b.point) + * Node an = a.next + * Node bp = b.prev # <<<<<<<<<<<<<< + * + * a.next = b + */ + __pyx_t_1 = ((PyObject *)__pyx_v_b->prev); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_bp = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":660 + * Node bp = b.prev + * + * a.next = b # <<<<<<<<<<<<<< + * b.prev = a + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_b); + __Pyx_GIVEREF((PyObject *)__pyx_v_b); + __Pyx_GOTREF((PyObject *)__pyx_v_a->next); + __Pyx_DECREF((PyObject *)__pyx_v_a->next); + __pyx_v_a->next = __pyx_v_b; + + /* "ezdxf/acc/mapbox_earcut.pyx":661 + * + * a.next = b + * b.prev = a # <<<<<<<<<<<<<< + * + * a2.next = an + */ + __Pyx_INCREF((PyObject *)__pyx_v_a); + __Pyx_GIVEREF((PyObject *)__pyx_v_a); + __Pyx_GOTREF((PyObject *)__pyx_v_b->prev); + __Pyx_DECREF((PyObject *)__pyx_v_b->prev); + __pyx_v_b->prev = __pyx_v_a; + + /* "ezdxf/acc/mapbox_earcut.pyx":663 + * b.prev = a + * + * a2.next = an # <<<<<<<<<<<<<< + * an.prev = a2 + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_an); + __Pyx_GIVEREF((PyObject *)__pyx_v_an); + __Pyx_GOTREF((PyObject *)__pyx_v_a2->next); + __Pyx_DECREF((PyObject *)__pyx_v_a2->next); + __pyx_v_a2->next = __pyx_v_an; + + /* "ezdxf/acc/mapbox_earcut.pyx":664 + * + * a2.next = an + * an.prev = a2 # <<<<<<<<<<<<<< + * + * b2.next = a2 + */ + __Pyx_INCREF((PyObject *)__pyx_v_a2); + __Pyx_GIVEREF((PyObject *)__pyx_v_a2); + __Pyx_GOTREF((PyObject *)__pyx_v_an->prev); + __Pyx_DECREF((PyObject *)__pyx_v_an->prev); + __pyx_v_an->prev = __pyx_v_a2; + + /* "ezdxf/acc/mapbox_earcut.pyx":666 + * an.prev = a2 + * + * b2.next = a2 # <<<<<<<<<<<<<< + * a2.prev = b2 + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_a2); + __Pyx_GIVEREF((PyObject *)__pyx_v_a2); + __Pyx_GOTREF((PyObject *)__pyx_v_b2->next); + __Pyx_DECREF((PyObject *)__pyx_v_b2->next); + __pyx_v_b2->next = __pyx_v_a2; + + /* "ezdxf/acc/mapbox_earcut.pyx":667 + * + * b2.next = a2 + * a2.prev = b2 # <<<<<<<<<<<<<< + * + * bp.next = b2 + */ + __Pyx_INCREF((PyObject *)__pyx_v_b2); + __Pyx_GIVEREF((PyObject *)__pyx_v_b2); + __Pyx_GOTREF((PyObject *)__pyx_v_a2->prev); + __Pyx_DECREF((PyObject *)__pyx_v_a2->prev); + __pyx_v_a2->prev = __pyx_v_b2; + + /* "ezdxf/acc/mapbox_earcut.pyx":669 + * a2.prev = b2 + * + * bp.next = b2 # <<<<<<<<<<<<<< + * b2.prev = bp + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_b2); + __Pyx_GIVEREF((PyObject *)__pyx_v_b2); + __Pyx_GOTREF((PyObject *)__pyx_v_bp->next); + __Pyx_DECREF((PyObject *)__pyx_v_bp->next); + __pyx_v_bp->next = __pyx_v_b2; + + /* "ezdxf/acc/mapbox_earcut.pyx":670 + * + * bp.next = b2 + * b2.prev = bp # <<<<<<<<<<<<<< + * + * return b2 + */ + __Pyx_INCREF((PyObject *)__pyx_v_bp); + __Pyx_GIVEREF((PyObject *)__pyx_v_bp); + __Pyx_GOTREF((PyObject *)__pyx_v_b2->prev); + __Pyx_DECREF((PyObject *)__pyx_v_b2->prev); + __pyx_v_b2->prev = __pyx_v_bp; + + /* "ezdxf/acc/mapbox_earcut.pyx":672 + * b2.prev = bp + * + * return b2 # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_b2); + __pyx_r = __pyx_v_b2; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":647 + * + * + * cdef Node split_polygon(Node a, Node b): # <<<<<<<<<<<<<< + * """Link two polygon vertices with a bridge. + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.split_polygon", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a2); + __Pyx_XDECREF((PyObject *)__pyx_v_b2); + __Pyx_XDECREF((PyObject *)__pyx_v_an); + __Pyx_XDECREF((PyObject *)__pyx_v_bp); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":676 + * + * # go through all polygon nodes and cure small local self-intersections + * cdef Node cure_local_intersections(Node start, list triangles): # <<<<<<<<<<<<<< + * cdef: + * Node p = start + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_cure_local_intersections(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_start, PyObject *__pyx_v_triangles) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cure_local_intersections", 0); + __Pyx_INCREF((PyObject *)__pyx_v_start); + + /* "ezdxf/acc/mapbox_earcut.pyx":678 + * cdef Node cure_local_intersections(Node start, list triangles): + * cdef: + * Node p = start # <<<<<<<<<<<<<< + * Node a, b + * while True: + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_p = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":680 + * Node p = start + * Node a, b + * while True: # <<<<<<<<<<<<<< + * a = p.prev + * b = p.next.next + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":681 + * Node a, b + * while True: + * a = p.prev # <<<<<<<<<<<<<< + * b = p.next.next + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->prev); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":682 + * while True: + * a = p.prev + * b = p.next.next # <<<<<<<<<<<<<< + * + * if ( + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->next->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":685 + * + * if ( + * not a.equals(b) # <<<<<<<<<<<<<< + * and intersects(a, p, p.next, b) + * and locally_inside(a, b) + */ + __pyx_t_3 = ((struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_v_a->__pyx_vtab)->equals(__pyx_v_a, __pyx_v_b); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 685, __pyx_L1_error) + __pyx_t_4 = (!__pyx_t_3); + if (__pyx_t_4) { + } else { + __pyx_t_2 = __pyx_t_4; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":686 + * if ( + * not a.equals(b) + * and intersects(a, p, p.next, b) # <<<<<<<<<<<<<< + * and locally_inside(a, b) + * and locally_inside(b, a) + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_intersects(__pyx_v_a, __pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1), __pyx_v_b); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 686, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_4) { + } else { + __pyx_t_2 = __pyx_t_4; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":687 + * not a.equals(b) + * and intersects(a, p, p.next, b) + * and locally_inside(a, b) # <<<<<<<<<<<<<< + * and locally_inside(b, a) + * ): + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 687, __pyx_L1_error) + if (__pyx_t_4) { + } else { + __pyx_t_2 = __pyx_t_4; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":688 + * and intersects(a, p, p.next, b) + * and locally_inside(a, b) + * and locally_inside(b, a) # <<<<<<<<<<<<<< + * ): + * triangles.append((a.point, p.point, b.point)) + */ + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(__pyx_v_b, __pyx_v_a); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 688, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + __pyx_L6_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":684 + * b = p.next.next + * + * if ( # <<<<<<<<<<<<<< + * not a.equals(b) + * and intersects(a, p, p.next, b) + */ + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":690 + * and locally_inside(b, a) + * ): + * triangles.append((a.point, p.point, b.point)) # <<<<<<<<<<<<<< + * # remove two nodes involved + * remove_node(p) + */ + if (unlikely(__pyx_v_triangles == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append"); + __PYX_ERR(1, 690, __pyx_L1_error) + } + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_a->point); + __Pyx_GIVEREF(__pyx_v_a->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_a->point)) __PYX_ERR(1, 690, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_p->point); + __Pyx_GIVEREF(__pyx_v_p->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_p->point)) __PYX_ERR(1, 690, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_b->point); + __Pyx_GIVEREF(__pyx_v_b->point); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_b->point)) __PYX_ERR(1, 690, __pyx_L1_error); + __pyx_t_5 = __Pyx_PyList_Append(__pyx_v_triangles, __pyx_t_1); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 690, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":692 + * triangles.append((a.point, p.point, b.point)) + * # remove two nodes involved + * remove_node(p) # <<<<<<<<<<<<<< + * remove_node(p.next) + * p = start = b + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(__pyx_v_p); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 692, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":693 + * # remove two nodes involved + * remove_node(p) + * remove_node(p.next) # <<<<<<<<<<<<<< + * p = start = b + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_6 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_remove_node(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":694 + * remove_node(p) + * remove_node(p.next) + * p = start = b # <<<<<<<<<<<<<< + * + * p = p.next + */ + __Pyx_INCREF((PyObject *)__pyx_v_b); + __Pyx_DECREF_SET(__pyx_v_p, __pyx_v_b); + __Pyx_INCREF((PyObject *)__pyx_v_b); + __Pyx_DECREF_SET(__pyx_v_start, __pyx_v_b); + + /* "ezdxf/acc/mapbox_earcut.pyx":684 + * b = p.next.next + * + * if ( # <<<<<<<<<<<<<< + * not a.equals(b) + * and intersects(a, p, p.next, b) + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":696 + * p = start = b + * + * p = p.next # <<<<<<<<<<<<<< + * if p is start: + * break + */ + __pyx_t_6 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6)); + __pyx_t_6 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":697 + * + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * return filter_points(p) + */ + __pyx_t_2 = (__pyx_v_p == __pyx_v_start); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":698 + * p = p.next + * if p is start: + * break # <<<<<<<<<<<<<< + * return filter_points(p) + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":697 + * + * p = p.next + * if p is start: # <<<<<<<<<<<<<< + * break + * return filter_points(p) + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":699 + * if p is start: + * break + * return filter_points(p) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_6 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_p, NULL)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 699, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_6); + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":676 + * + * # go through all polygon nodes and cure small local self-intersections + * cdef Node cure_local_intersections(Node start, list triangles): # <<<<<<<<<<<<<< + * cdef: + * Node p = start + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.cure_local_intersections", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XDECREF((PyObject *)__pyx_v_start); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":702 + * + * + * cdef split_ear_cut( # <<<<<<<<<<<<<< + * Node start, + * list triangles, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_ear_cut(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_start, PyObject *__pyx_v_triangles, double __pyx_v_min_x, double __pyx_v_min_y, double __pyx_v_inv_size) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_c = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + struct __pyx_opt_args_5ezdxf_3acc_13mapbox_earcut_filter_points __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("split_ear_cut", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":712 + * # look for a valid diagonal that divides the polygon into two + * cdef: + * Node a = start # <<<<<<<<<<<<<< + * Node b, c + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_start); + __pyx_v_a = __pyx_v_start; + + /* "ezdxf/acc/mapbox_earcut.pyx":715 + * Node b, c + * + * while True: # <<<<<<<<<<<<<< + * b = a.next.next + * while b is not a.prev: + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":716 + * + * while True: + * b = a.next.next # <<<<<<<<<<<<<< + * while b is not a.prev: + * if a.i != b.i and is_valid_diagonal(a, b): + */ + __pyx_t_1 = ((PyObject *)__pyx_v_a->next->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":717 + * while True: + * b = a.next.next + * while b is not a.prev: # <<<<<<<<<<<<<< + * if a.i != b.i and is_valid_diagonal(a, b): + * # split the polygon in two by the diagonal + */ + while (1) { + __pyx_t_2 = (__pyx_v_b != __pyx_v_a->prev); + if (!__pyx_t_2) break; + + /* "ezdxf/acc/mapbox_earcut.pyx":718 + * b = a.next.next + * while b is not a.prev: + * if a.i != b.i and is_valid_diagonal(a, b): # <<<<<<<<<<<<<< + * # split the polygon in two by the diagonal + * c = split_polygon(a, b) + */ + __pyx_t_3 = (__pyx_v_a->i != __pyx_v_b->i); + if (__pyx_t_3) { + } else { + __pyx_t_2 = __pyx_t_3; + goto __pyx_L8_bool_binop_done; + } + __pyx_t_3 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_is_valid_diagonal(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_3 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 718, __pyx_L1_error) + __pyx_t_2 = __pyx_t_3; + __pyx_L8_bool_binop_done:; + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":720 + * if a.i != b.i and is_valid_diagonal(a, b): + * # split the polygon in two by the diagonal + * c = split_polygon(a, b) # <<<<<<<<<<<<<< + * + * # filter colinear points around the cuts + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_split_polygon(__pyx_v_a, __pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 720, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_c = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":723 + * + * # filter colinear points around the cuts + * a = filter_points(a, a.next) # <<<<<<<<<<<<<< + * c = filter_points(c, c.next) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_1); + __pyx_t_5.__pyx_n = 1; + __pyx_t_5.end = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1); + __pyx_t_4 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_a, &__pyx_t_5)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 723, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":724 + * # filter colinear points around the cuts + * a = filter_points(a, a.next) + * c = filter_points(c, c.next) # <<<<<<<<<<<<<< + * + * # run earcut on each half + */ + __pyx_t_4 = ((PyObject *)__pyx_v_c->next); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_5.__pyx_n = 1; + __pyx_t_5.end = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_13mapbox_earcut_filter_points(__pyx_v_c, &__pyx_t_5)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 724, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_c, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":727 + * + * # run earcut on each half + * earcut_linked(a, triangles, min_x, min_y, inv_size, 0) # <<<<<<<<<<<<<< + * earcut_linked(c, triangles, min_x, min_y, inv_size, 0) + * return + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(__pyx_v_a, __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 727, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":728 + * # run earcut on each half + * earcut_linked(a, triangles, min_x, min_y, inv_size, 0) + * earcut_linked(c, triangles, min_x, min_y, inv_size, 0) # <<<<<<<<<<<<<< + * return + * b = b.next + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_earcut_linked(__pyx_v_c, __pyx_v_triangles, __pyx_v_min_x, __pyx_v_min_y, __pyx_v_inv_size, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":729 + * earcut_linked(a, triangles, min_x, min_y, inv_size, 0) + * earcut_linked(c, triangles, min_x, min_y, inv_size, 0) + * return # <<<<<<<<<<<<<< + * b = b.next + * a = a.next + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":718 + * b = a.next.next + * while b is not a.prev: + * if a.i != b.i and is_valid_diagonal(a, b): # <<<<<<<<<<<<<< + * # split the polygon in two by the diagonal + * c = split_polygon(a, b) + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":730 + * earcut_linked(c, triangles, min_x, min_y, inv_size, 0) + * return + * b = b.next # <<<<<<<<<<<<<< + * a = a.next + * if a is start: + */ + __pyx_t_1 = ((PyObject *)__pyx_v_b->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":731 + * return + * b = b.next + * a = a.next # <<<<<<<<<<<<<< + * if a is start: + * break + */ + __pyx_t_1 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":732 + * b = b.next + * a = a.next + * if a is start: # <<<<<<<<<<<<<< + * break + * + */ + __pyx_t_2 = (__pyx_v_a == __pyx_v_start); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":733 + * a = a.next + * if a is start: + * break # <<<<<<<<<<<<<< + * + * + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":732 + * b = b.next + * a = a.next + * if a is start: # <<<<<<<<<<<<<< + * break + * + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":702 + * + * + * cdef split_ear_cut( # <<<<<<<<<<<<<< + * Node start, + * list triangles, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.split_ear_cut", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XDECREF((PyObject *)__pyx_v_c); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":737 + * + * # David Eberly's algorithm for finding a bridge between hole and outer polygon + * cdef Node find_hole_bridge(Node hole, Node outer_node): # <<<<<<<<<<<<<< + * cdef: + * Node p = outer_node + */ + +static struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_f_5ezdxf_3acc_13mapbox_earcut_find_hole_bridge(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_hole, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_outer_node) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_m = 0; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_stop = 0; + double __pyx_v_hx; + double __pyx_v_hy; + double __pyx_v_qx; + double __pyx_v_mx; + double __pyx_v_my; + double __pyx_v_tan_min; + double __pyx_v_tan; + double __pyx_v_x; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + int __pyx_t_2; + double __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("find_hole_bridge", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":739 + * cdef Node find_hole_bridge(Node hole, Node outer_node): + * cdef: + * Node p = outer_node # <<<<<<<<<<<<<< + * Node m = None + * Node stop + */ + __Pyx_INCREF((PyObject *)__pyx_v_outer_node); + __pyx_v_p = __pyx_v_outer_node; + + /* "ezdxf/acc/mapbox_earcut.pyx":740 + * cdef: + * Node p = outer_node + * Node m = None # <<<<<<<<<<<<<< + * Node stop + * double hx = hole.x + */ + __Pyx_INCREF(Py_None); + __pyx_v_m = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); + + /* "ezdxf/acc/mapbox_earcut.pyx":742 + * Node m = None + * Node stop + * double hx = hole.x # <<<<<<<<<<<<<< + * double hy = hole.y + * double qx = -INFINITY + */ + __pyx_t_1 = __pyx_v_hole->x; + __pyx_v_hx = __pyx_t_1; + + /* "ezdxf/acc/mapbox_earcut.pyx":743 + * Node stop + * double hx = hole.x + * double hy = hole.y # <<<<<<<<<<<<<< + * double qx = -INFINITY + * double mx, my, tan_min, tan + */ + __pyx_t_1 = __pyx_v_hole->y; + __pyx_v_hy = __pyx_t_1; + + /* "ezdxf/acc/mapbox_earcut.pyx":744 + * double hx = hole.x + * double hy = hole.y + * double qx = -INFINITY # <<<<<<<<<<<<<< + * double mx, my, tan_min, tan + * + */ + __pyx_v_qx = (-INFINITY); + + /* "ezdxf/acc/mapbox_earcut.pyx":749 + * # find a segment intersected by a ray from the hole's leftmost point to the left; + * # segment's endpoint with lesser x will be potential connection point + * while True: # <<<<<<<<<<<<<< + * if p.y >= hy >= p.next.y != p.y: + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":750 + * # segment's endpoint with lesser x will be potential connection point + * while True: + * if p.y >= hy >= p.next.y != p.y: # <<<<<<<<<<<<<< + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + * if hx >= x > qx: + */ + __pyx_t_2 = (__pyx_v_p->y >= __pyx_v_hy); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_hy >= __pyx_v_p->next->y); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_p->next->y != __pyx_v_p->y); + } + } + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":751 + * while True: + * if p.y >= hy >= p.next.y != p.y: + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) # <<<<<<<<<<<<<< + * if hx >= x > qx: + * qx = x + */ + __pyx_t_1 = ((__pyx_v_hy - __pyx_v_p->y) * (__pyx_v_p->next->x - __pyx_v_p->x)); + __pyx_t_3 = (__pyx_v_p->next->y - __pyx_v_p->y); + if (unlikely(__pyx_t_3 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(1, 751, __pyx_L1_error) + } + __pyx_v_x = (__pyx_v_p->x + (__pyx_t_1 / __pyx_t_3)); + + /* "ezdxf/acc/mapbox_earcut.pyx":752 + * if p.y >= hy >= p.next.y != p.y: + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + * if hx >= x > qx: # <<<<<<<<<<<<<< + * qx = x + * m = p if p.x < p.next.x else p.next + */ + __pyx_t_2 = (__pyx_v_hx >= __pyx_v_x); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_x > __pyx_v_qx); + } + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":753 + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + * if hx >= x > qx: + * qx = x # <<<<<<<<<<<<<< + * m = p if p.x < p.next.x else p.next + * if x == hx: + */ + __pyx_v_qx = __pyx_v_x; + + /* "ezdxf/acc/mapbox_earcut.pyx":754 + * if hx >= x > qx: + * qx = x + * m = p if p.x < p.next.x else p.next # <<<<<<<<<<<<<< + * if x == hx: + * # hole touches outer segment; pick leftmost endpoint + */ + __pyx_t_2 = (__pyx_v_p->x < __pyx_v_p->next->x); + if (__pyx_t_2) { + __Pyx_INCREF((PyObject *)__pyx_v_p); + __pyx_t_4 = ((PyObject *)__pyx_v_p); + } else { + __Pyx_INCREF((PyObject *)__pyx_v_p->next); + __pyx_t_4 = ((PyObject *)__pyx_v_p->next); + } + __Pyx_DECREF_SET(__pyx_v_m, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":755 + * qx = x + * m = p if p.x < p.next.x else p.next + * if x == hx: # <<<<<<<<<<<<<< + * # hole touches outer segment; pick leftmost endpoint + * return m + */ + __pyx_t_2 = (__pyx_v_x == __pyx_v_hx); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":757 + * if x == hx: + * # hole touches outer segment; pick leftmost endpoint + * return m # <<<<<<<<<<<<<< + * p = p.next + * if p is outer_node: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_m); + __pyx_r = __pyx_v_m; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":755 + * qx = x + * m = p if p.x < p.next.x else p.next + * if x == hx: # <<<<<<<<<<<<<< + * # hole touches outer segment; pick leftmost endpoint + * return m + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":752 + * if p.y >= hy >= p.next.y != p.y: + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + * if hx >= x > qx: # <<<<<<<<<<<<<< + * qx = x + * m = p if p.x < p.next.x else p.next + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":750 + * # segment's endpoint with lesser x will be potential connection point + * while True: + * if p.y >= hy >= p.next.y != p.y: # <<<<<<<<<<<<<< + * x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + * if hx >= x > qx: + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":758 + * # hole touches outer segment; pick leftmost endpoint + * return m + * p = p.next # <<<<<<<<<<<<<< + * if p is outer_node: + * break + */ + __pyx_t_4 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":759 + * return m + * p = p.next + * if p is outer_node: # <<<<<<<<<<<<<< + * break + * + */ + __pyx_t_2 = (__pyx_v_p == __pyx_v_outer_node); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":760 + * p = p.next + * if p is outer_node: + * break # <<<<<<<<<<<<<< + * + * if m is None: + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":759 + * return m + * p = p.next + * if p is outer_node: # <<<<<<<<<<<<<< + * break + * + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":762 + * break + * + * if m is None: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_2 = (((PyObject *)__pyx_v_m) == Py_None); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":763 + * + * if m is None: + * return None # <<<<<<<<<<<<<< + * + * # look for points inside the triangle of hole point, segment intersection and endpoint; + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":762 + * break + * + * if m is None: # <<<<<<<<<<<<<< + * return None + * + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":768 + * # if there are no points found, we have a valid connection; + * # otherwise choose the point of the minimum angle with the ray as connection point + * stop = m # <<<<<<<<<<<<<< + * mx = m.x + * my = m.y + */ + __Pyx_INCREF((PyObject *)__pyx_v_m); + __pyx_v_stop = __pyx_v_m; + + /* "ezdxf/acc/mapbox_earcut.pyx":769 + * # otherwise choose the point of the minimum angle with the ray as connection point + * stop = m + * mx = m.x # <<<<<<<<<<<<<< + * my = m.y + * tan_min = INFINITY + */ + __pyx_t_3 = __pyx_v_m->x; + __pyx_v_mx = __pyx_t_3; + + /* "ezdxf/acc/mapbox_earcut.pyx":770 + * stop = m + * mx = m.x + * my = m.y # <<<<<<<<<<<<<< + * tan_min = INFINITY + * p = m + */ + __pyx_t_3 = __pyx_v_m->y; + __pyx_v_my = __pyx_t_3; + + /* "ezdxf/acc/mapbox_earcut.pyx":771 + * mx = m.x + * my = m.y + * tan_min = INFINITY # <<<<<<<<<<<<<< + * p = m + * + */ + __pyx_v_tan_min = INFINITY; + + /* "ezdxf/acc/mapbox_earcut.pyx":772 + * my = m.y + * tan_min = INFINITY + * p = m # <<<<<<<<<<<<<< + * + * while True: + */ + __Pyx_INCREF((PyObject *)__pyx_v_m); + __Pyx_DECREF_SET(__pyx_v_p, __pyx_v_m); + + /* "ezdxf/acc/mapbox_earcut.pyx":774 + * p = m + * + * while True: # <<<<<<<<<<<<<< + * if ( + * hx >= p.x >= mx + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":776 + * while True: + * if ( + * hx >= p.x >= mx # <<<<<<<<<<<<<< + * and hx != p.x + * and point_in_triangle( + */ + __pyx_t_5 = (__pyx_v_hx >= __pyx_v_p->x); + if (__pyx_t_5) { + __pyx_t_5 = (__pyx_v_p->x >= __pyx_v_mx); + } + if (__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L13_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":777 + * if ( + * hx >= p.x >= mx + * and hx != p.x # <<<<<<<<<<<<<< + * and point_in_triangle( + * hx if hy < my else qx, + */ + __pyx_t_5 = (__pyx_v_hx != __pyx_v_p->x); + if (__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L13_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":779 + * and hx != p.x + * and point_in_triangle( + * hx if hy < my else qx, # <<<<<<<<<<<<<< + * hy, + * mx, + */ + __pyx_t_5 = (__pyx_v_hy < __pyx_v_my); + if (__pyx_t_5) { + __pyx_t_3 = __pyx_v_hx; + } else { + __pyx_t_3 = __pyx_v_qx; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":783 + * mx, + * my, + * qx if hy < my else hx, # <<<<<<<<<<<<<< + * hy, + * p.x, + */ + __pyx_t_5 = (__pyx_v_hy < __pyx_v_my); + if (__pyx_t_5) { + __pyx_t_1 = __pyx_v_qx; + } else { + __pyx_t_1 = __pyx_v_hx; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":778 + * hx >= p.x >= mx + * and hx != p.x + * and point_in_triangle( # <<<<<<<<<<<<<< + * hx if hy < my else qx, + * hy, + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_point_in_triangle(__pyx_t_3, __pyx_v_hy, __pyx_v_mx, __pyx_v_my, __pyx_t_1, __pyx_v_hy, __pyx_v_p->x, __pyx_v_p->y); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 778, __pyx_L1_error) + __pyx_t_2 = __pyx_t_5; + __pyx_L13_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":775 + * + * while True: + * if ( # <<<<<<<<<<<<<< + * hx >= p.x >= mx + * and hx != p.x + */ + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":789 + * ) + * ): + * tan = fabs(hy - p.y) / (hx - p.x) # tangential # <<<<<<<<<<<<<< + * if locally_inside(p, hole) and ( + * tan < tan_min + */ + __pyx_t_1 = fabs((__pyx_v_hy - __pyx_v_p->y)); + __pyx_t_3 = (__pyx_v_hx - __pyx_v_p->x); + if (unlikely(__pyx_t_3 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(1, 789, __pyx_L1_error) + } + __pyx_v_tan = (__pyx_t_1 / __pyx_t_3); + + /* "ezdxf/acc/mapbox_earcut.pyx":790 + * ): + * tan = fabs(hy - p.y) / (hx - p.x) # tangential + * if locally_inside(p, hole) and ( # <<<<<<<<<<<<<< + * tan < tan_min + * or ( + */ + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(__pyx_v_p, __pyx_v_hole); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 790, __pyx_L1_error) + if (__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L17_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":791 + * tan = fabs(hy - p.y) / (hx - p.x) # tangential + * if locally_inside(p, hole) and ( + * tan < tan_min # <<<<<<<<<<<<<< + * or ( + * tan == tan_min + */ + __pyx_t_5 = (__pyx_v_tan < __pyx_v_tan_min); + if (!__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L17_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":793 + * tan < tan_min + * or ( + * tan == tan_min # <<<<<<<<<<<<<< + * and ( + * p.x > m.x + */ + __pyx_t_5 = (__pyx_v_tan == __pyx_v_tan_min); + if (__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L17_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":795 + * tan == tan_min + * and ( + * p.x > m.x # <<<<<<<<<<<<<< + * or (p.x == m.x and sector_contains_sector(m, p)) + * ) + */ + __pyx_t_5 = (__pyx_v_p->x > __pyx_v_m->x); + if (!__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L17_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":796 + * and ( + * p.x > m.x + * or (p.x == m.x and sector_contains_sector(m, p)) # <<<<<<<<<<<<<< + * ) + * ) + */ + __pyx_t_5 = (__pyx_v_p->x == __pyx_v_m->x); + if (__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L17_bool_binop_done; + } + __pyx_t_5 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_sector_contains_sector(__pyx_v_m, __pyx_v_p); if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(1, 796, __pyx_L1_error) + __pyx_t_2 = __pyx_t_5; + __pyx_L17_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":790 + * ): + * tan = fabs(hy - p.y) / (hx - p.x) # tangential + * if locally_inside(p, hole) and ( # <<<<<<<<<<<<<< + * tan < tan_min + * or ( + */ + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":800 + * ) + * ): + * m = p # <<<<<<<<<<<<<< + * tan_min = tan + * p = p.next + */ + __Pyx_INCREF((PyObject *)__pyx_v_p); + __Pyx_DECREF_SET(__pyx_v_m, __pyx_v_p); + + /* "ezdxf/acc/mapbox_earcut.pyx":801 + * ): + * m = p + * tan_min = tan # <<<<<<<<<<<<<< + * p = p.next + * if p is stop: + */ + __pyx_v_tan_min = __pyx_v_tan; + + /* "ezdxf/acc/mapbox_earcut.pyx":790 + * ): + * tan = fabs(hy - p.y) / (hx - p.x) # tangential + * if locally_inside(p, hole) and ( # <<<<<<<<<<<<<< + * tan < tan_min + * or ( + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":775 + * + * while True: + * if ( # <<<<<<<<<<<<<< + * hx >= p.x >= mx + * and hx != p.x + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":802 + * m = p + * tan_min = tan + * p = p.next # <<<<<<<<<<<<<< + * if p is stop: + * break + */ + __pyx_t_4 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":803 + * tan_min = tan + * p = p.next + * if p is stop: # <<<<<<<<<<<<<< + * break + * return m + */ + __pyx_t_2 = (__pyx_v_p == __pyx_v_stop); + if (__pyx_t_2) { + + /* "ezdxf/acc/mapbox_earcut.pyx":804 + * p = p.next + * if p is stop: + * break # <<<<<<<<<<<<<< + * return m + * + */ + goto __pyx_L11_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":803 + * tan_min = tan + * p = p.next + * if p is stop: # <<<<<<<<<<<<<< + * break + * return m + */ + } + } + __pyx_L11_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":805 + * if p is stop: + * break + * return m # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_m); + __pyx_r = __pyx_v_m; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":737 + * + * # David Eberly's algorithm for finding a bridge between hole and outer polygon + * cdef Node find_hole_bridge(Node hole, Node outer_node): # <<<<<<<<<<<<<< + * cdef: + * Node p = outer_node + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.find_hole_bridge", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_XDECREF((PyObject *)__pyx_v_m); + __Pyx_XDECREF((PyObject *)__pyx_v_stop); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":808 + * + * + * cdef bint locally_inside(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a polygon diagonal is locally inside the polygon""" + * return ( + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_locally_inside(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("locally_inside", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":812 + * return ( + * area(a, b, a.next) >= 0 and area(a, a.prev, b) >= 0 + * if area(a.prev, a, a.next) < 0 # <<<<<<<<<<<<<< + * else area(a, b, a.prev) < 0 or area(a, a.next, b) < 0 + * ) + */ + __pyx_t_2 = ((PyObject *)__pyx_v_a->prev); + __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_2), __pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 812, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = (__pyx_t_4 < 0.0); + if (__pyx_t_5) { + + /* "ezdxf/acc/mapbox_earcut.pyx":811 + * """Check if a polygon diagonal is locally inside the polygon""" + * return ( + * area(a, b, a.next) >= 0 and area(a, a.prev, b) >= 0 # <<<<<<<<<<<<<< + * if area(a.prev, a, a.next) < 0 + * else area(a, b, a.prev) < 0 or area(a, a.next, b) < 0 + */ + __pyx_t_3 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, __pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 811, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = (__pyx_t_4 >= 0.0); + if (__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_3 = ((PyObject *)__pyx_v_a->prev); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_b); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 811, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = (__pyx_t_4 >= 0.0); + __pyx_t_6 = __pyx_t_7; + __pyx_L3_bool_binop_done:; + __pyx_t_1 = __pyx_t_6; + } else { + + /* "ezdxf/acc/mapbox_earcut.pyx":813 + * area(a, b, a.next) >= 0 and area(a, a.prev, b) >= 0 + * if area(a.prev, a, a.next) < 0 + * else area(a, b, a.prev) < 0 or area(a, a.next, b) < 0 # <<<<<<<<<<<<<< + * ) + * + */ + __pyx_t_3 = ((PyObject *)__pyx_v_a->prev); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, __pyx_v_b, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 813, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = (__pyx_t_4 < 0.0); + if (!__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_3 = ((PyObject *)__pyx_v_a->next); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_13mapbox_earcut_area(__pyx_v_a, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_3), __pyx_v_b); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(1, 813, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = (__pyx_t_4 < 0.0); + __pyx_t_6 = __pyx_t_7; + __pyx_L5_bool_binop_done:; + __pyx_t_1 = __pyx_t_6; + } + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":808 + * + * + * cdef bint locally_inside(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if a polygon diagonal is locally inside the polygon""" + * return ( + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.locally_inside", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/mapbox_earcut.pyx":817 + * + * + * cdef bint middle_inside(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if the middle point of a polygon diagonal is inside the polygon""" + * cdef: + */ + +static int __pyx_f_5ezdxf_3acc_13mapbox_earcut_middle_inside(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *__pyx_v_p = 0; + int __pyx_v_inside; + double __pyx_v_px; + double __pyx_v_py; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + double __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("middle_inside", 1); + + /* "ezdxf/acc/mapbox_earcut.pyx":820 + * """Check if the middle point of a polygon diagonal is inside the polygon""" + * cdef: + * Node p = a # <<<<<<<<<<<<<< + * bint inside = False + * double px = (a.x + b.x) / 2 + */ + __Pyx_INCREF((PyObject *)__pyx_v_a); + __pyx_v_p = __pyx_v_a; + + /* "ezdxf/acc/mapbox_earcut.pyx":821 + * cdef: + * Node p = a + * bint inside = False # <<<<<<<<<<<<<< + * double px = (a.x + b.x) / 2 + * double py = (a.y + b.y) / 2 + */ + __pyx_v_inside = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":822 + * Node p = a + * bint inside = False + * double px = (a.x + b.x) / 2 # <<<<<<<<<<<<<< + * double py = (a.y + b.y) / 2 + * + */ + __pyx_v_px = ((__pyx_v_a->x + __pyx_v_b->x) / 2.0); + + /* "ezdxf/acc/mapbox_earcut.pyx":823 + * bint inside = False + * double px = (a.x + b.x) / 2 + * double py = (a.y + b.y) / 2 # <<<<<<<<<<<<<< + * + * while True: + */ + __pyx_v_py = ((__pyx_v_a->y + __pyx_v_b->y) / 2.0); + + /* "ezdxf/acc/mapbox_earcut.pyx":825 + * double py = (a.y + b.y) / 2 + * + * while True: # <<<<<<<<<<<<<< + * if ( + * ((p.y > py) != (p.next.y > py)) + */ + while (1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":827 + * while True: + * if ( + * ((p.y > py) != (p.next.y > py)) # <<<<<<<<<<<<<< + * and p.next.y != p.y + * and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) + */ + __pyx_t_2 = ((__pyx_v_p->y > __pyx_v_py) != (__pyx_v_p->next->y > __pyx_v_py)); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":828 + * if ( + * ((p.y > py) != (p.next.y > py)) + * and p.next.y != p.y # <<<<<<<<<<<<<< + * and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) + * ): + */ + __pyx_t_2 = (__pyx_v_p->next->y != __pyx_v_p->y); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L6_bool_binop_done; + } + + /* "ezdxf/acc/mapbox_earcut.pyx":829 + * ((p.y > py) != (p.next.y > py)) + * and p.next.y != p.y + * and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) # <<<<<<<<<<<<<< + * ): + * inside = not inside + */ + __pyx_t_3 = ((__pyx_v_p->next->x - __pyx_v_p->x) * (__pyx_v_py - __pyx_v_p->y)); + __pyx_t_4 = (__pyx_v_p->next->y - __pyx_v_p->y); + if (unlikely(__pyx_t_4 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(1, 829, __pyx_L1_error) + } + __pyx_t_2 = (__pyx_v_px < ((__pyx_t_3 / __pyx_t_4) + __pyx_v_p->x)); + __pyx_t_1 = __pyx_t_2; + __pyx_L6_bool_binop_done:; + + /* "ezdxf/acc/mapbox_earcut.pyx":826 + * + * while True: + * if ( # <<<<<<<<<<<<<< + * ((p.y > py) != (p.next.y > py)) + * and p.next.y != p.y + */ + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":831 + * and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) + * ): + * inside = not inside # <<<<<<<<<<<<<< + * p = p.next + * if p is a: + */ + __pyx_v_inside = (!__pyx_v_inside); + + /* "ezdxf/acc/mapbox_earcut.pyx":826 + * + * while True: + * if ( # <<<<<<<<<<<<<< + * ((p.y > py) != (p.next.y > py)) + * and p.next.y != p.y + */ + } + + /* "ezdxf/acc/mapbox_earcut.pyx":832 + * ): + * inside = not inside + * p = p.next # <<<<<<<<<<<<<< + * if p is a: + * break + */ + __pyx_t_5 = ((PyObject *)__pyx_v_p->next); + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_p, ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)__pyx_t_5)); + __pyx_t_5 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":833 + * inside = not inside + * p = p.next + * if p is a: # <<<<<<<<<<<<<< + * break + * return inside + */ + __pyx_t_1 = (__pyx_v_p == __pyx_v_a); + if (__pyx_t_1) { + + /* "ezdxf/acc/mapbox_earcut.pyx":834 + * p = p.next + * if p is a: + * break # <<<<<<<<<<<<<< + * return inside + */ + goto __pyx_L4_break; + + /* "ezdxf/acc/mapbox_earcut.pyx":833 + * inside = not inside + * p = p.next + * if p is a: # <<<<<<<<<<<<<< + * break + * return inside + */ + } + } + __pyx_L4_break:; + + /* "ezdxf/acc/mapbox_earcut.pyx":835 + * if p is a: + * break + * return inside # <<<<<<<<<<<<<< + */ + __pyx_r = __pyx_v_inside; + goto __pyx_L0; + + /* "ezdxf/acc/mapbox_earcut.pyx":817 + * + * + * cdef bint middle_inside(Node a, Node b): # <<<<<<<<<<<<<< + * """Check if the middle point of a polygon diagonal is inside the polygon""" + * cdef: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.mapbox_earcut.middle_inside", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_p); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static struct __pyx_vtabstruct_5ezdxf_3acc_13mapbox_earcut_Node __pyx_vtable_5ezdxf_3acc_13mapbox_earcut_Node; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_13mapbox_earcut_Node(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_13mapbox_earcut_Node; + p->point = Py_None; Py_INCREF(Py_None); + p->prev = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + p->next = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + p->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + p->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_13mapbox_earcut_Node(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *p = (struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_13mapbox_earcut_Node) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->point); + Py_CLEAR(p->prev); + Py_CLEAR(p->next); + Py_CLEAR(p->prev_z); + Py_CLEAR(p->next_z); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_5ezdxf_3acc_13mapbox_earcut_Node(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *p = (struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)o; + if (p->point) { + e = (*v)(p->point, a); if (e) return e; + } + if (p->prev) { + e = (*v)(((PyObject *)p->prev), a); if (e) return e; + } + if (p->next) { + e = (*v)(((PyObject *)p->next), a); if (e) return e; + } + if (p->prev_z) { + e = (*v)(((PyObject *)p->prev_z), a); if (e) return e; + } + if (p->next_z) { + e = (*v)(((PyObject *)p->next_z), a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_13mapbox_earcut_Node(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *p = (struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)o; + tmp = ((PyObject*)p->point); + p->point = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->prev); + p->prev = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->next); + p->next = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->prev_z); + p->prev_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->next_z); + p->next_z = ((struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_13mapbox_earcut_Node[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_13mapbox_earcut_Node_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_13mapbox_earcut_Node}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_13mapbox_earcut_Node}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_13mapbox_earcut_Node}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_13mapbox_earcut_Node}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_13mapbox_earcut_Node}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_13mapbox_earcut_Node_spec = { + "ezdxf.acc.mapbox_earcut.Node", + sizeof(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type_5ezdxf_3acc_13mapbox_earcut_Node_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_13mapbox_earcut_Node = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.mapbox_earcut.""Node", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_13mapbox_earcut_Node, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_13mapbox_earcut_Node, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_13mapbox_earcut_Node, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_13mapbox_earcut_Node, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_13mapbox_earcut_Node, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_Node, __pyx_k_Node, sizeof(__pyx_k_Node), 0, 0, 1, 1}, + {&__pyx_n_s_Node___reduce_cython, __pyx_k_Node___reduce_cython, sizeof(__pyx_k_Node___reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_Node___setstate_cython, __pyx_k_Node___setstate_cython, sizeof(__pyx_k_Node___setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s__9, __pyx_k__9, sizeof(__pyx_k__9), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_earcut, __pyx_k_earcut, sizeof(__pyx_k_earcut), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_exterior, __pyx_k_exterior, sizeof(__pyx_k_exterior), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_mapbox_earcut, __pyx_k_ezdxf_acc_mapbox_earcut, sizeof(__pyx_k_ezdxf_acc_mapbox_earcut), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_holes, __pyx_k_holes, sizeof(__pyx_k_holes), 0, 0, 1, 1}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_inv_size, __pyx_k_inv_size, sizeof(__pyx_k_inv_size), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_key, __pyx_k_key, sizeof(__pyx_k_key), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_max_x, __pyx_k_max_x, sizeof(__pyx_k_max_x), 0, 0, 1, 1}, + {&__pyx_n_s_max_y, __pyx_k_max_y, sizeof(__pyx_k_max_y), 0, 0, 1, 1}, + {&__pyx_n_s_min_x, __pyx_k_min_x, sizeof(__pyx_k_min_x), 0, 0, 1, 1}, + {&__pyx_n_s_min_y, __pyx_k_min_y, sizeof(__pyx_k_min_y), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_node, __pyx_k_node, sizeof(__pyx_k_node), 0, 0, 1, 1}, + {&__pyx_n_s_node_key, __pyx_k_node_key, sizeof(__pyx_k_node_key), 0, 0, 1, 1}, + {&__pyx_n_s_outer_node, __pyx_k_outer_node, sizeof(__pyx_k_outer_node), 0, 0, 1, 1}, + {&__pyx_n_s_point, __pyx_k_point, sizeof(__pyx_k_point), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_reversed, __pyx_k_reversed, sizeof(__pyx_k_reversed), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_sort, __pyx_k_sort, sizeof(__pyx_k_sort), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx, __pyx_k_src_ezdxf_acc_mapbox_earcut_pyx, sizeof(__pyx_k_src_ezdxf_acc_mapbox_earcut_pyx), 0, 0, 1, 0}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_triangles, __pyx_k_triangles, sizeof(__pyx_k_triangles), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) + __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) __PYX_ERR(1, 131, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(1, 617, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_reduce_cython, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) __PYX_ERR(0, 1, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_tuple__3 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_pyx_state); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_setstate_cython, 3, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 3, __pyx_L1_error) + + /* "ezdxf/acc/mapbox_earcut.pyx":54 + * return self.x == other.x and self.y == other.y + * + * def node_key(Node node): # <<<<<<<<<<<<<< + * return node.x, node.y + * + */ + __pyx_tuple__5 = PyTuple_Pack(1, __pyx_n_s_node); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__5); + __Pyx_GIVEREF(__pyx_tuple__5); + __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx, __pyx_n_s_node_key, 54, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(1, 54, __pyx_L1_error) + + /* "ezdxf/acc/mapbox_earcut.pyx":57 + * return node.x, node.y + * + * def earcut(list exterior, list holes): # <<<<<<<<<<<<<< + * """Implements a modified ear slicing algorithm, optimized by z-order + * curve hashing and extended to handle holes, twisted polygons, degeneracies + */ + __pyx_tuple__7 = PyTuple_Pack(12, __pyx_n_s_exterior, __pyx_n_s_holes, __pyx_n_s_outer_node, __pyx_n_s_triangles, __pyx_n_s_max_x, __pyx_n_s_max_y, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_min_x, __pyx_n_s_min_y, __pyx_n_s_inv_size, __pyx_n_s_point); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + __pyx_codeobj__8 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__7, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_mapbox_earcut_pyx, __pyx_n_s_earcut, 57, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__8)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(1, 1, __pyx_L1_error); + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_vtabptr_5ezdxf_3acc_13mapbox_earcut_Node = &__pyx_vtable_5ezdxf_3acc_13mapbox_earcut_Node; + __pyx_vtable_5ezdxf_3acc_13mapbox_earcut_Node.equals = (int (*)(struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *, struct __pyx_obj_5ezdxf_3acc_13mapbox_earcut_Node *))__pyx_f_5ezdxf_3acc_13mapbox_earcut_4Node_equals; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node)) __PYX_ERR(1, 26, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node_spec, __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node = &__pyx_type_5ezdxf_3acc_13mapbox_earcut_Node; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node, __pyx_vtabptr_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Node, (PyObject *) __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_ptype_5ezdxf_3acc_13mapbox_earcut_Node) < 0) __PYX_ERR(1, 26, __pyx_L1_error) + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_mapbox_earcut(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_mapbox_earcut}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "mapbox_earcut", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initmapbox_earcut(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initmapbox_earcut(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_mapbox_earcut(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_mapbox_earcut(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_mapbox_earcut(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'mapbox_earcut' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("mapbox_earcut", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(1, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "mapbox_earcut" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(1, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(1, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(1, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(1, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_mapbox_earcut(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(1, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(1, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(1, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__mapbox_earcut) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(1, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.mapbox_earcut")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.mapbox_earcut", __pyx_m) < 0))) __PYX_ERR(1, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(1, 1, __pyx_L1_error) + (void)__Pyx_modinit_type_import_code(); + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) + #endif + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_13mapbox_earcut_4Node_3__reduce_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Node___reduce_cython, NULL, __pyx_n_s_ezdxf_acc_mapbox_earcut, __pyx_d, ((PyObject *)__pyx_codeobj__2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_reduce_cython, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_13mapbox_earcut_4Node_5__setstate_cython__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Node___setstate_cython, NULL, __pyx_n_s_ezdxf_acc_mapbox_earcut, __pyx_d, ((PyObject *)__pyx_codeobj__4)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_setstate_cython, __pyx_t_2) < 0) __PYX_ERR(0, 3, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":54 + * return self.x == other.x and self.y == other.y + * + * def node_key(Node node): # <<<<<<<<<<<<<< + * return node.x, node.y + * + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_13mapbox_earcut_1node_key, 0, __pyx_n_s_node_key, NULL, __pyx_n_s_ezdxf_acc_mapbox_earcut, __pyx_d, ((PyObject *)__pyx_codeobj__6)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_node_key, __pyx_t_2) < 0) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":57 + * return node.x, node.y + * + * def earcut(list exterior, list holes): # <<<<<<<<<<<<<< + * """Implements a modified ear slicing algorithm, optimized by z-order + * curve hashing and extended to handle holes, twisted polygons, degeneracies + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_13mapbox_earcut_3earcut, 0, __pyx_n_s_earcut, NULL, __pyx_n_s_ezdxf_acc_mapbox_earcut, __pyx_d, ((PyObject *)__pyx_codeobj__8)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_earcut, __pyx_t_2) < 0) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/mapbox_earcut.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Source: https://github.com/mapbox/earcut + * # License: ISC License (MIT compatible) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.mapbox_earcut", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.mapbox_earcut"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__9); + } + return name; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.cpython-312-darwin.so new file mode 100755 index 0000000..db45610 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.pyx new file mode 100644 index 0000000..cf9d338 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/mapbox_earcut.pyx @@ -0,0 +1,835 @@ +# cython: language_level=3 +# Source: https://github.com/mapbox/earcut +# License: ISC License (MIT compatible) +# +# Copyright (c) 2016, Mapbox +# +# Permission to use, copy, modify, and/or distribute this software for any purpose +# with or without fee is hereby granted, provided that the above copyright notice +# and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +# THIS SOFTWARE. +# +# Cython implementation of module ezdxf.math._mapbox_earcut.py +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +# type: ignore +from libc.math cimport fmin, fmax, fabs, INFINITY + + +cdef class Node: + cdef: + int i + double x + double y + int z + bint steiner + object point + Node prev + Node next + Node prev_z + Node next_z + + def __cinit__(self, int i, object point): + self.i = i + self.point = point + self.x = point.x + self.y = point.y + self.z = 0 + self.steiner = False + self.prev = None + self.next = None + self.prev_z = None + self.next_z = None + + cdef bint equals(self, Node other): + return self.x == other.x and self.y == other.y + +def node_key(Node node): + return node.x, node.y + +def earcut(list exterior, list holes): + """Implements a modified ear slicing algorithm, optimized by z-order + curve hashing and extended to handle holes, twisted polygons, degeneracies + and self-intersections in a way that doesn't guarantee correctness of + triangulation, but attempts to always produce acceptable results for + practical data. + + Source: https://github.com/mapbox/earcut + + Args: + exterior: outer path as list of points as objects which provide a + `x`- and a `y`-attribute + holes: list of holes, each hole is list of points, a hole with + a single points is a Steiner point + + Returns: + Returns a list of triangles, each triangle is a tuple of three points, + the output points are the same objects as the input points. + + """ + cdef: + Node outer_node + list triangles = [] + double max_x, max_y, x, y + double min_x = 0.0 + double min_y = 0.0 + double inv_size = 0.0 + + if not exterior: + return triangles + + outer_node = linked_list(exterior, 0, ccw=True) + if outer_node is None or outer_node.next is outer_node.prev: + return triangles + + if holes: + outer_node = eliminate_holes(holes, len(exterior), outer_node) + + # if the shape is not too simple, we'll use z-order curve hash later + # calculate polygon bbox + if len(exterior) > 80: + min_x = max_x = exterior[0].x + min_y = max_y = exterior[0].y + for point in exterior: + x = point.x + y = point.y + min_x = fmin(min_x, x) + min_y = fmin(min_y, y) + max_x = fmax(max_x, x) + max_y = fmax(max_y, y) + + # min_x, min_y and inv_size are later used to transform coords into + # integers for z-order calculation + inv_size = fmax(max_x - min_x, max_y - min_y) + inv_size = 32767 / inv_size if inv_size != 0 else 0 + + earcut_linked(outer_node, triangles, min_x, min_y, inv_size, 0) + return triangles + + +cdef Node linked_list(list points, int start, bint ccw): + """Create a circular doubly linked list from polygon points in the specified + winding order + """ + cdef: + Node last = None + int end + + if ccw is (signed_area(points) < 0): + for point in points: + last = insert_node(start, point, last) + start += 1 + else: + end = start + len(points) + for point in reversed(points): + last = insert_node(end, point, last) + end -= 1 + + # open polygon: where the 1st vertex is not coincident with the last vertex + if last and last.equals(last.next): + remove_node(last) + last = last.next + return last + + +cdef double signed_area(list points): + cdef: + double s = 0.0 + double point_x, prev_x, point_y, prev_y + if not len(points): + return s + prev = points[-1] + prev_x = prev.x + prev_y = prev.y + for point in points: + point_x = point.x + point_y = point.y + s += (point_x - prev_x) * (point_y + prev_y) + prev_x = point_x + prev_y = point_y + # s < 0 is counter-clockwise + # s > 0 is clockwise + return s + + +cdef double area(Node p, Node q, Node r): + """Returns signed area of a triangle""" + return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) + + +cdef bint is_valid_diagonal(Node a, Node b): + """Check if a diagonal between two polygon nodes is valid (lies in polygon + interior) + """ + return ( + a.next.i != b.i + and a.prev.i != b.i + and not intersects_polygon(a, b) # doesn't intersect other edges + and ( + locally_inside(a, b) + and locally_inside(b, a) + and middle_inside(a, b) + and ( + area(a.prev, a, b.prev) or area(a, b.prev, b) + ) # does not create opposite-facing sectors + or a.equals(b) + and area(a.prev, a, a.next) > 0 + and area(b.prev, b, b.next) > 0 + ) # special zero-length case + ) + + +cdef bint intersects_polygon(Node a, Node b): + """Check if a polygon diagonal intersects any polygon segments""" + cdef Node p = a + while True: + if ( + p.i != a.i + and p.next.i != a.i + and p.i != b.i + and p.next.i != b.i + and intersects(p, p.next, a, b) + ): + return True + p = p.next + if p is a: + break + return False + + +cdef int sign(double num): + if num < 0.0: + return -1 + if num > 0.0: + return 1 + return 0 + + +cdef bint on_segment(p: Node, q: Node, r: Node): + return fmax(p.x, r.x) >= q.x >= fmin(p.x, r.x) and fmax( + p.y, r.y + ) >= q.y >= fmin(p.y, r.y) + + +cdef bint intersects(Node p1, Node q1, Node p2, Node q2): + """check if two segments intersect""" + cdef: + int o1 = sign(area(p1, q1, p2)) + int o2 = sign(area(p1, q1, q2)) + int o3 = sign(area(p2, q2, p1)) + int o4 = sign(area(p2, q2, q1)) + + if o1 != o2 and o3 != o4: + return True # general case + + if o1 == 0 and on_segment(p1, p2, q1): + return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + if o2 == 0 and on_segment(p1, q2, q1): + return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + if o3 == 0 and on_segment(p2, p1, q2): + return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + if o4 == 0 and on_segment(p2, q1, q2): + return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + return False + + +cdef Node insert_node(int i, point, Node last): + """create a node and optionally link it with previous one (in a circular + doubly linked list) + """ + cdef Node p = Node(i, point) + + if last is None: + p.prev = p + p.next = p + else: + p.next = last.next + p.prev = last + last.next.prev = p + last.next = p + return p + + +cdef remove_node(Node p): + p.next.prev = p.prev + p.prev.next = p.next + + if p.prev_z is not None: + p.prev_z.next_z = p.next_z + if p.next_z is not None: + p.next_z.prev_z = p.prev_z + + +cdef Node eliminate_holes(list holes, int start, Node outer_node): + """link every hole into the outer loop, producing a single-ring polygon + without holes + """ + cdef: + list queue = [] + list hole + for hole in holes: + if len(hole) < 1: # skip empty holes + continue + # hole vertices in clockwise order + _list = linked_list(hole, start, ccw=False) + if _list is _list.next: + _list.steiner = True + start += len(hole) + queue.append(get_leftmost(_list)) + queue.sort(key=node_key) + + # process holes from left to right + for hole_ in queue: + outer_node = eliminate_hole(hole_, outer_node) + return outer_node + + +cdef Node eliminate_hole(Node hole, Node outer_node): + """Find a bridge between vertices that connects hole with an outer ring and + link it + """ + cdef: + Node bridge = find_hole_bridge(hole, outer_node) + Node bridge_reverse + + if bridge is None: + return outer_node + + bridge_reverse = split_polygon(bridge, hole) + + # filter collinear points around the cuts + filter_points(bridge_reverse, bridge_reverse.next) + return filter_points(bridge, bridge.next) + + +cdef Node filter_points(Node start, Node end = None): + """eliminate colinear or duplicate points""" + cdef: + Node p + bint again + + if start is None: + return start + if end is None: + end = start + + p = start + while True: + again = False + if not p.steiner and ( + p.equals(p.next) or area(p.prev, p, p.next) == 0 + ): + remove_node(p) + p = end = p.prev + if p is p.next: + break + again = True + else: + p = p.next + if not (again or p is not end): + break + return end + + +# main ear slicing loop which triangulates a polygon (given as a linked list) +cdef earcut_linked( + Node ear, + list triangles, + double min_x, + double min_y, + double inv_size, + int pass_, +): + cdef: + Node stop, prev, next + bint _is_ear + + if ear is None: + return + + # interlink polygon nodes in z-order + if not pass_ and inv_size: + index_curve(ear, min_x, min_y, inv_size) + + stop = ear + + # iterate through ears, slicing them one by one + while ear.prev is not ear.next: + prev = ear.prev + next = ear.next + + _is_ear = ( + is_ear_hashed(ear, min_x, min_y, inv_size) + if inv_size + else is_ear(ear) + ) + if _is_ear: + # cut off the triangle + triangles.append((prev.point, ear.point, next.point)) + remove_node(ear) + + # skipping the next vertex leads to less sliver triangles + ear = next.next + stop = next.next + continue + + ear = next + + # if we looped through the whole remaining polygon and can't find any more ears + if ear is stop: + # try filtering points and slicing again + if not pass_: + earcut_linked( + filter_points(ear), + triangles, + min_x, + min_y, + inv_size, + 1, + ) + + # if this didn't work, try curing all small self-intersections locally + elif pass_ == 1: + ear = cure_local_intersections(filter_points(ear), triangles) + earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) + + # as a last resort, try splitting the remaining polygon into two + elif pass_ == 2: + split_ear_cut(ear, triangles, min_x, min_y, inv_size) + break + + +cdef bint is_ear(Node ear): + """check whether a polygon node forms a valid ear with adjacent nodes""" + cdef: + Node a = ear.prev + Node b = ear + Node c = ear.next + Node p + double x0, x1, y0, y1 + + if area(a, b, c) >= 0: + return False # reflex, can't be an ear + + # now make sure we don't have other points inside the potential ear + # triangle bbox + x0 = fmin(a.x, fmin(b.x, c.x)) + x1 = fmax(a.x, fmax(b.x, c.x)) + y0 = fmin(a.y, fmin(b.y, c.y)) + y1 = fmax(a.y, fmax(b.y, c.y)) + p = c.next + + while p is not a: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.next + + return True + + +cdef bint is_ear_hashed(Node ear, double min_x, double min_y, double inv_size): + cdef: + Node a = ear.prev + Node b = ear + Node c = ear.next + double x0, x1, y0, y1, min_z, max_z + Node p, n + + if area(a, b, c) >= 0: + return False # reflex, can't be an ear + + # triangle bbox + x0 = fmin(a.x, fmin(b.x, c.x)) + x1 = fmax(a.x, fmax(b.x, c.x)) + y0 = fmin(a.y, fmin(b.y, c.y)) + y1 = fmax(a.y, fmax(b.y, c.y)) + + # z-order range for the current triangle bbox; + min_z = z_order(x0, y0, min_x, min_y, inv_size) + max_z = z_order(x1, y1, min_x, min_y, inv_size) + + p = ear.prev_z + n = ear.next_z + + # look for points inside the triangle in both directions + while p and p.z >= min_z and n and n.z <= max_z: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and p is not a + and p is not c + and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.prev_z + + if ( + x0 <= n.x <= x1 + and y0 <= n.y <= y1 + and n is not a + and n is not c + and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + and area(n.prev, n, n.next) >= 0 + ): + return False + n = n.next_z + + # look for remaining points in decreasing z-order + while p and p.z >= min_z: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and p is not a + and p is not c + and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.prev_z + + # look for remaining points in increasing z-order + while n and n.z <= max_z: + if ( + x0 <= n.x <= x1 + and y0 <= n.y <= y1 + and n is not a + and n is not c + and point_in_triangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) + and area(n.prev, n, n.next) >= 0 + ): + return False + n = n.next_z + return True + + +cdef Node get_leftmost(Node start): + """Find the leftmost node of a polygon ring""" + cdef: + Node p = start + Node leftmost = start + + while True: + if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): + leftmost = p + p = p.next + if p is start: + break + return leftmost + + +cdef bint point_in_triangle( + double ax, + double ay, + double bx, + double by_, + double cx, + double cy, + double px, + double py, +): + """Check if a point lies within a convex triangle""" + return ( + (cx - px) * (ay - py) >= (ax - px) * (cy - py) + and (ax - px) * (by_ - py) >= (bx - px) * (ay - py) + and (bx - px) * (cy - py) >= (cx - px) * (by_ - py) + ) + + +cdef bint sector_contains_sector(Node m, Node p): + """Whether sector in vertex m contains sector in vertex p in the same + coordinates. + """ + return area(m.prev, m, p.prev) < 0 and area(p.next, m, m.next) < 0 + + +cdef index_curve(Node start, double min_x, double min_y, double inv_size): + """Interlink polygon nodes in z-order""" + cdef Node p = start + while True: + if p.z == 0: + p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + p.prev_z = p.prev + p.next_z = p.next + p = p.next + if p is start: + break + + p.prev_z.next_z = None + p.prev_z = None + + sort_linked(p) + + +cdef int z_order( + double x0, double y0, double min_x, double min_y, double inv_size +): + """Z-order of a point given coords and inverse of the longer side of data + bbox. + """ + # coords are transformed into non-negative 15-bit integer range + cdef: + int x = int((x0 - min_x) * inv_size) + int y = int ((y0 - min_y) * inv_size) + + x = (x | (x << 8)) & 0x00FF00FF + x = (x | (x << 4)) & 0x0F0F0F0F + x = (x | (x << 2)) & 0x33333333 + x = (x | (x << 1)) & 0x55555555 + + y = (y | (y << 8)) & 0x00FF00FF + y = (y | (y << 4)) & 0x0F0F0F0F + y = (y | (y << 2)) & 0x33333333 + y = (y | (y << 1)) & 0x55555555 + + return x | (y << 1) + + +# Simon Tatham's linked list merge sort algorithm +# http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +cdef Node sort_linked(Node head): + cdef: + int in_size = 1 + int num_merges, p_size, q_size, i + Node tail, p, q, e + + while True: + p = head + head = None + tail = None + num_merges = 0 + while p: + num_merges += 1 + q = p + p_size = 0 + for i in range(in_size): + p_size += 1 + q = q.next_z + if not q: + break + q_size = in_size + while p_size > 0 or (q_size > 0 and q): + if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + e = p + p = p.next_z + p_size -= 1 + else: + e = q + q = q.next_z + q_size -= 1 + + if tail: + tail.next_z = e + else: + head = e + e.prev_z = tail + tail = e + p = q + tail.next_z = None + in_size *= 2 + if num_merges <= 1: + break + return head + + +cdef Node split_polygon(Node a, Node b): + """Link two polygon vertices with a bridge. + + If the vertices belong to the same ring, it splits polygon into two. + If one belongs to the outer ring and another to a hole, it merges it into a + single ring. + """ + cdef : + Node a2 = Node(a.i, a.point) + Node b2 = Node(b.i, b.point) + Node an = a.next + Node bp = b.prev + + a.next = b + b.prev = a + + a2.next = an + an.prev = a2 + + b2.next = a2 + a2.prev = b2 + + bp.next = b2 + b2.prev = bp + + return b2 + + +# go through all polygon nodes and cure small local self-intersections +cdef Node cure_local_intersections(Node start, list triangles): + cdef: + Node p = start + Node a, b + while True: + a = p.prev + b = p.next.next + + if ( + not a.equals(b) + and intersects(a, p, p.next, b) + and locally_inside(a, b) + and locally_inside(b, a) + ): + triangles.append((a.point, p.point, b.point)) + # remove two nodes involved + remove_node(p) + remove_node(p.next) + p = start = b + + p = p.next + if p is start: + break + return filter_points(p) + + +cdef split_ear_cut( + Node start, + list triangles, + double min_x, + double min_y, + double inv_size, +): + """Try splitting polygon into two and triangulate them independently""" + # look for a valid diagonal that divides the polygon into two + cdef: + Node a = start + Node b, c + + while True: + b = a.next.next + while b is not a.prev: + if a.i != b.i and is_valid_diagonal(a, b): + # split the polygon in two by the diagonal + c = split_polygon(a, b) + + # filter colinear points around the cuts + a = filter_points(a, a.next) + c = filter_points(c, c.next) + + # run earcut on each half + earcut_linked(a, triangles, min_x, min_y, inv_size, 0) + earcut_linked(c, triangles, min_x, min_y, inv_size, 0) + return + b = b.next + a = a.next + if a is start: + break + + +# David Eberly's algorithm for finding a bridge between hole and outer polygon +cdef Node find_hole_bridge(Node hole, Node outer_node): + cdef: + Node p = outer_node + Node m = None + Node stop + double hx = hole.x + double hy = hole.y + double qx = -INFINITY + double mx, my, tan_min, tan + + # find a segment intersected by a ray from the hole's leftmost point to the left; + # segment's endpoint with lesser x will be potential connection point + while True: + if p.y >= hy >= p.next.y != p.y: + x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + if hx >= x > qx: + qx = x + m = p if p.x < p.next.x else p.next + if x == hx: + # hole touches outer segment; pick leftmost endpoint + return m + p = p.next + if p is outer_node: + break + + if m is None: + return None + + # look for points inside the triangle of hole point, segment intersection and endpoint; + # if there are no points found, we have a valid connection; + # otherwise choose the point of the minimum angle with the ray as connection point + stop = m + mx = m.x + my = m.y + tan_min = INFINITY + p = m + + while True: + if ( + hx >= p.x >= mx + and hx != p.x + and point_in_triangle( + hx if hy < my else qx, + hy, + mx, + my, + qx if hy < my else hx, + hy, + p.x, + p.y, + ) + ): + tan = fabs(hy - p.y) / (hx - p.x) # tangential + if locally_inside(p, hole) and ( + tan < tan_min + or ( + tan == tan_min + and ( + p.x > m.x + or (p.x == m.x and sector_contains_sector(m, p)) + ) + ) + ): + m = p + tan_min = tan + p = p.next + if p is stop: + break + return m + + +cdef bint locally_inside(Node a, Node b): + """Check if a polygon diagonal is locally inside the polygon""" + return ( + area(a, b, a.next) >= 0 and area(a, a.prev, b) >= 0 + if area(a.prev, a, a.next) < 0 + else area(a, b, a.prev) < 0 or area(a, a.next, b) < 0 + ) + + +cdef bint middle_inside(Node a, Node b): + """Check if the middle point of a polygon diagonal is inside the polygon""" + cdef: + Node p = a + bint inside = False + double px = (a.x + b.x) / 2 + double py = (a.y + b.y) / 2 + + while True: + if ( + ((p.y > py) != (p.next.y > py)) + and p.next.y != p.y + and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) + ): + inside = not inside + p = p.next + if p is a: + break + return inside diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.c new file mode 100644 index 0000000..63512ee --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.c @@ -0,0 +1,45728 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.matrix44", + "sources": [ + "src/ezdxf/acc/matrix44.pyx" + ] + }, + "module_name": "ezdxf.acc.matrix44" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__matrix44 +#define __PYX_HAVE_API__ezdxf__acc__matrix44 +/* Early includes */ +#include +#include "constants.h" +#include "pythread.h" +#include +#include +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/matrix44.pyx", + "", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* NoFastGil.proto */ +#define __Pyx_PyGILState_Ensure PyGILState_Ensure +#define __Pyx_PyGILState_Release PyGILState_Release +#define __Pyx_FastGIL_Remember() +#define __Pyx_FastGIL_Forget() +#define __Pyx_FastGilFuncInit() + +/* BufferFormatStructs.proto */ +struct __Pyx_StructField_; +#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0) +typedef struct { + const char* name; + struct __Pyx_StructField_* fields; + size_t size; + size_t arraysize[8]; + int ndim; + char typegroup; + char is_unsigned; + int flags; +} __Pyx_TypeInfo; +typedef struct __Pyx_StructField_ { + __Pyx_TypeInfo* type; + const char* name; + size_t offset; +} __Pyx_StructField; +typedef struct { + __Pyx_StructField* field; + size_t parent_offset; +} __Pyx_BufFmt_StackElem; +typedef struct { + __Pyx_StructField root; + __Pyx_BufFmt_StackElem* head; + size_t fmt_offset; + size_t new_count, enc_count; + size_t struct_alignment; + int is_complex; + char enc_type; + char new_packmode; + char enc_packmode; + char is_valid_array; +} __Pyx_BufFmt_Context; + +/* Atomics.proto */ +#include +#ifndef CYTHON_ATOMICS + #define CYTHON_ATOMICS 1 +#endif +#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS +#define __pyx_atomic_int_type int +#define __pyx_nonatomic_int_type int +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__)) + #include +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ + (defined(_MSC_VER) && _MSC_VER >= 1700))) + #include +#endif +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type atomic_int + #define __pyx_atomic_incr_aligned(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) + #define __pyx_atomic_decr_aligned(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C atomics" + #endif +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ +\ + (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type std::atomic_int + #define __pyx_atomic_incr_aligned(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) + #define __pyx_atomic_decr_aligned(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C++ atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C++ atomics" + #endif +#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ + (__GNUC_MINOR__ > 1 ||\ + (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) + #define __pyx_atomic_incr_aligned(value) __sync_fetch_and_add(value, 1) + #define __pyx_atomic_decr_aligned(value) __sync_fetch_and_sub(value, 1) + #ifdef __PYX_DEBUG_ATOMICS + #warning "Using GNU atomics" + #endif +#elif CYTHON_ATOMICS && defined(_MSC_VER) + #include + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type long + #undef __pyx_nonatomic_int_type + #define __pyx_nonatomic_int_type long + #pragma intrinsic (_InterlockedExchangeAdd) + #define __pyx_atomic_incr_aligned(value) _InterlockedExchangeAdd(value, 1) + #define __pyx_atomic_decr_aligned(value) _InterlockedExchangeAdd(value, -1) + #ifdef __PYX_DEBUG_ATOMICS + #pragma message ("Using MSVC atomics") + #endif +#else + #undef CYTHON_ATOMICS + #define CYTHON_ATOMICS 0 + #ifdef __PYX_DEBUG_ATOMICS + #warning "Not using atomics" + #endif +#endif +#if CYTHON_ATOMICS + #define __pyx_add_acquisition_count(memview)\ + __pyx_atomic_incr_aligned(__pyx_get_slice_count_pointer(memview)) + #define __pyx_sub_acquisition_count(memview)\ + __pyx_atomic_decr_aligned(__pyx_get_slice_count_pointer(memview)) +#else + #define __pyx_add_acquisition_count(memview)\ + __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) + #define __pyx_sub_acquisition_count(memview)\ + __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) +#endif + +/* MemviewSliceStruct.proto */ +struct __pyx_memoryview_obj; +typedef struct { + struct __pyx_memoryview_obj *memview; + char *data; + Py_ssize_t shape[8]; + Py_ssize_t strides[8]; + Py_ssize_t suboffsets[8]; +} __Pyx_memviewslice; +#define __Pyx_MemoryView_Len(m) (m.shape[0]) + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform; +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions; +struct __pyx_array_obj; +struct __pyx_MemviewEnum_obj; +struct __pyx_memoryview_obj; +struct __pyx_memoryviewslice_obj; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "ezdxf/acc/matrix44.pxd":6 + * from .vector cimport Vec3 + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * cdef double m[16] + * cdef Vec3 get_ux(self: Matrix44) + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 { + PyObject_HEAD + struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtab; + double m[16]; +}; + + +/* "ezdxf/acc/matrix44.pyx":76 + * raise IndexError(f'index out of range: {index}') + * + * def __iter__(self): # <<<<<<<<<<<<<< + * cdef int i + * for i in range(16): + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ { + PyObject_HEAD + int __pyx_v_i; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; + int __pyx_t_0; +}; + + +/* "ezdxf/acc/matrix44.pyx":81 + * yield self.m[i] + * + * def __repr__(self) -> str: # <<<<<<<<<<<<<< + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ { + PyObject_HEAD + PyObject *__pyx_v_format_row; +}; + + +/* "ezdxf/acc/matrix44.pyx":83 + * def __repr__(self) -> str: + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) # <<<<<<<<<<<<<< + * + * return "Matrix44(%s)" % \ + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr { + PyObject_HEAD + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_value; +}; + + +/* "ezdxf/acc/matrix44.pyx":86 + * + * return "Matrix44(%s)" % \ + * ", ".join(format_row(row) for row in self.rows()) # <<<<<<<<<<<<<< + * + * def get_2d_transformation(self) -> Tuple[float, ...]: + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *__pyx_outer_scope; + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_row; +}; + + +/* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; +}; + + +/* "ezdxf/acc/matrix44.pyx":147 + * + * def rows(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_row(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *__pyx_outer_scope; + PyObject *__pyx_v_index; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; +}; + + +/* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; +}; + + +/* "ezdxf/acc/matrix44.pyx":150 + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_col(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def copy(self) -> Matrix44: + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *__pyx_outer_scope; + PyObject *__pyx_v_index; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; +}; + + +/* "ezdxf/acc/matrix44.pyx":556 + * ocs_to_wcs = transform_direction + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices { + PyObject_HEAD + double *__pyx_v_m; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; + PyObject *__pyx_v_vector; + PyObject *__pyx_v_vectors; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/matrix44.pyx":572 + * yield res + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: # <<<<<<<<<<<<<< + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform { + PyObject_HEAD + double __pyx_v_m0; + double __pyx_v_m1; + double __pyx_v_m12; + double __pyx_v_m13; + double __pyx_v_m4; + double __pyx_v_m5; + PyObject *__pyx_v_pnt; + PyObject *__pyx_v_points; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; + double __pyx_v_x; + double __pyx_v_y; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ +struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions { + PyObject_HEAD + int __pyx_v__normalize; + double *__pyx_v_m; + PyObject *__pyx_v_normalize; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self; + PyObject *__pyx_v_vector; + PyObject *__pyx_v_vectors; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "View.MemoryView":114 + * @cython.collection_type("sequence") + * @cname("__pyx_array") + * cdef class array: # <<<<<<<<<<<<<< + * + * cdef: + */ +struct __pyx_array_obj { + PyObject_HEAD + struct __pyx_vtabstruct_array *__pyx_vtab; + char *data; + Py_ssize_t len; + char *format; + int ndim; + Py_ssize_t *_shape; + Py_ssize_t *_strides; + Py_ssize_t itemsize; + PyObject *mode; + PyObject *_format; + void (*callback_free_data)(void *); + int free_data; + int dtype_is_object; +}; + + +/* "View.MemoryView":302 + * + * @cname('__pyx_MemviewEnum') + * cdef class Enum(object): # <<<<<<<<<<<<<< + * cdef object name + * def __init__(self, name): + */ +struct __pyx_MemviewEnum_obj { + PyObject_HEAD + PyObject *name; +}; + + +/* "View.MemoryView":337 + * + * @cname('__pyx_memoryview') + * cdef class memoryview: # <<<<<<<<<<<<<< + * + * cdef object obj + */ +struct __pyx_memoryview_obj { + PyObject_HEAD + struct __pyx_vtabstruct_memoryview *__pyx_vtab; + PyObject *obj; + PyObject *_size; + PyObject *_array_interface; + PyThread_type_lock lock; + __pyx_atomic_int_type acquisition_count; + Py_buffer view; + int flags; + int dtype_is_object; + __Pyx_TypeInfo *typeinfo; +}; + + +/* "View.MemoryView":952 + * @cython.collection_type("sequence") + * @cname('__pyx_memoryviewslice') + * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<< + * "Internal class for passing memoryview slices to Python" + * + */ +struct __pyx_memoryviewslice_obj { + struct __pyx_memoryview_obj __pyx_base; + __Pyx_memviewslice from_slice; + PyObject *from_object; + PyObject *(*to_object_func)(char *); + int (*to_dtype_func)(char *, PyObject *); +}; + + + +/* "ezdxf/acc/matrix44.pyx":40 + * raise ValueError("invalid argument count") + * + * cdef class Matrix44: # <<<<<<<<<<<<<< + * def __cinit__(self, *args): + * cdef int nargs = len(args) + */ + +struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_ux)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uy)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*get_uz)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *); +}; +static struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44; + + +/* "View.MemoryView":114 + * @cython.collection_type("sequence") + * @cname("__pyx_array") + * cdef class array: # <<<<<<<<<<<<<< + * + * cdef: + */ + +struct __pyx_vtabstruct_array { + PyObject *(*get_memview)(struct __pyx_array_obj *); +}; +static struct __pyx_vtabstruct_array *__pyx_vtabptr_array; + + +/* "View.MemoryView":337 + * + * @cname('__pyx_memoryview') + * cdef class memoryview: # <<<<<<<<<<<<<< + * + * cdef object obj + */ + +struct __pyx_vtabstruct_memoryview { + char *(*get_item_pointer)(struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*is_slice)(struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*setitem_slice_assignment)(struct __pyx_memoryview_obj *, PyObject *, PyObject *); + PyObject *(*setitem_slice_assign_scalar)(struct __pyx_memoryview_obj *, struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*setitem_indexed)(struct __pyx_memoryview_obj *, PyObject *, PyObject *); + PyObject *(*convert_item_to_object)(struct __pyx_memoryview_obj *, char *); + PyObject *(*assign_item_from_object)(struct __pyx_memoryview_obj *, char *, PyObject *); + PyObject *(*_get_base)(struct __pyx_memoryview_obj *); +}; +static struct __pyx_vtabstruct_memoryview *__pyx_vtabptr_memoryview; + + +/* "View.MemoryView":952 + * @cython.collection_type("sequence") + * @cname('__pyx_memoryviewslice') + * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<< + * "Internal class for passing memoryview slices to Python" + * + */ + +struct __pyx_vtabstruct__memoryviewslice { + struct __pyx_vtabstruct_memoryview __pyx_base; +}; +static struct __pyx_vtabstruct__memoryviewslice *__pyx_vtabptr__memoryviewslice; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* BuildPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char); + +/* CIntToPyUnicode.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char); + +/* CIntToPyUnicode.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char); + +/* JoinPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char); + +/* StrEquals.proto */ +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals +#else +#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals +#endif + +/* PyObjectFormatSimple.proto */ +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#elif PY_MAJOR_VERSION < 3 + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyString_CheckExact(s)) ? PyUnicode_FromEncodedObject(s, NULL, "strict") :\ + PyObject_Format(s, f)) +#elif CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyLong_CheckExact(s)) ? PyLong_Type.tp_repr(s) :\ + likely(PyFloat_CheckExact(s)) ? PyFloat_Type.tp_repr(s) :\ + PyObject_Format(s, f)) +#else + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#endif + +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *); /*proto*/ +/* GetAttr.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* DivInt[Py_ssize_t].proto */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t, Py_ssize_t); + +/* UnaryNegOverflows.proto */ +#define __Pyx_UNARY_NEG_WOULD_OVERFLOW(x)\ + (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) + +/* GetAttr3.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* AssertionsEnabled.proto */ +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define __Pyx_init_assertions_enabled() (0) + #define __pyx_assertions_enabled() (1) +#elif CYTHON_COMPILING_IN_LIMITED_API || (CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030C0000) + static int __pyx_assertions_enabled_flag; + #define __pyx_assertions_enabled() (__pyx_assertions_enabled_flag) + static int __Pyx_init_assertions_enabled(void) { + PyObject *builtins, *debug, *debug_str; + int flag; + builtins = PyEval_GetBuiltins(); + if (!builtins) goto bad; + debug_str = PyUnicode_FromStringAndSize("__debug__", 9); + if (!debug_str) goto bad; + debug = PyObject_GetItem(builtins, debug_str); + Py_DECREF(debug_str); + if (!debug) goto bad; + flag = PyObject_IsTrue(debug); + Py_DECREF(debug); + if (flag == -1) goto bad; + __pyx_assertions_enabled_flag = flag; + return 0; + bad: + __pyx_assertions_enabled_flag = 1; + return -1; + } +#else + #define __Pyx_init_assertions_enabled() (0) + #define __pyx_assertions_enabled() (!Py_OptimizeFlag) +#endif + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* RaiseNoneIterError.proto */ +static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportDottedModule.proto */ +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); +#endif + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +/* ListCompAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len)) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) +#endif + +/* PySequenceMultiply.proto */ +#define __Pyx_PySequence_Multiply_Left(mul, seq) __Pyx_PySequence_Multiply(seq, mul) +static CYTHON_INLINE PyObject* __Pyx_PySequence_Multiply(PyObject *seq, Py_ssize_t mul); + +/* SetItemInt.proto */ +#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) :\ + __Pyx_SetItemInt_Generic(o, to_py_func(i), v))) +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v); +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, + int is_list, int wraparound, int boundscheck); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* DivInt[long].proto */ +static CYTHON_INLINE long __Pyx_div_long(long, long); + +/* PySequenceContains.proto */ +static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { + int result = PySequence_Contains(seq, item); + return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); +} + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* HasAttr.proto */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* PyObject_Unicode.proto */ +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyObject_Unicode(obj)\ + (likely(PyUnicode_CheckExact(obj)) ? __Pyx_NewRef(obj) : PyObject_Str(obj)) +#else +#define __Pyx_PyObject_Unicode(obj)\ + (likely(PyUnicode_CheckExact(obj)) ? __Pyx_NewRef(obj) : PyObject_Unicode(obj)) +#endif + +/* RaiseClosureNameError.proto */ +static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname); + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* GetNameInClass.proto */ +#define __Pyx_GetNameInClass(var, nmspace, name) (var) = __Pyx__GetNameInClass(nmspace, name) +static PyObject *__Pyx__GetNameInClass(PyObject *nmspace, PyObject *name); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +#if PY_MAJOR_VERSION < 3 + static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); + static void __Pyx_ReleaseBuffer(Py_buffer *view); +#else + #define __Pyx_GetBuffer PyObject_GetBuffer + #define __Pyx_ReleaseBuffer PyBuffer_Release +#endif + + +/* BufferStructDeclare.proto */ +typedef struct { + Py_ssize_t shape, strides, suboffsets; +} __Pyx_Buf_DimInfo; +typedef struct { + size_t refcount; + Py_buffer pybuffer; +} __Pyx_Buffer; +typedef struct { + __Pyx_Buffer *rcbuffer; + char *data; + __Pyx_Buf_DimInfo diminfo[8]; +} __Pyx_LocalBuf_ND; + +/* MemviewSliceIsContig.proto */ +static int __pyx_memviewslice_is_contig(const __Pyx_memviewslice mvs, char order, int ndim); + +/* OverlappingSlices.proto */ +static int __pyx_slices_overlap(__Pyx_memviewslice *slice1, + __Pyx_memviewslice *slice2, + int ndim, size_t itemsize); + +/* IsLittleEndian.proto */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void); + +/* BufferFormatCheck.proto */ +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts); +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type); + +/* TypeInfoCompare.proto */ +static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b); + +/* MemviewSliceValidateAndInit.proto */ +static int __Pyx_ValidateAndInit_memviewslice( + int *axes_specs, + int c_or_f_flag, + int buf_flags, + int ndim, + __Pyx_TypeInfo *dtype, + __Pyx_BufFmt_StackElem stack[], + __Pyx_memviewslice *memviewslice, + PyObject *original_obj); + +/* ObjectToMemviewSlice.proto */ +static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(PyObject *, int writable_flag); + +/* MemviewSliceCopyTemplate.proto */ +static __Pyx_memviewslice +__pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, + const char *mode, int ndim, + size_t sizeof_dtype, int contig_flag, + int dtype_is_object); + +/* MemviewSliceInit.proto */ +#define __Pyx_BUF_MAX_NDIMS %(BUF_MAX_NDIMS)d +#define __Pyx_MEMVIEW_DIRECT 1 +#define __Pyx_MEMVIEW_PTR 2 +#define __Pyx_MEMVIEW_FULL 4 +#define __Pyx_MEMVIEW_CONTIG 8 +#define __Pyx_MEMVIEW_STRIDED 16 +#define __Pyx_MEMVIEW_FOLLOW 32 +#define __Pyx_IS_C_CONTIG 1 +#define __Pyx_IS_F_CONTIG 2 +static int __Pyx_init_memviewslice( + struct __pyx_memoryview_obj *memview, + int ndim, + __Pyx_memviewslice *memviewslice, + int memview_is_new_reference); +static CYTHON_INLINE int __pyx_add_acquisition_count_locked( + __pyx_atomic_int_type *acquisition_count, PyThread_type_lock lock); +static CYTHON_INLINE int __pyx_sub_acquisition_count_locked( + __pyx_atomic_int_type *acquisition_count, PyThread_type_lock lock); +#define __pyx_get_slice_count_pointer(memview) (&memview->acquisition_count) +#define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__) +#define __PYX_XCLEAR_MEMVIEW(slice, have_gil) __Pyx_XCLEAR_MEMVIEW(slice, have_gil, __LINE__) +static CYTHON_INLINE void __Pyx_INC_MEMVIEW(__Pyx_memviewslice *, int, int); +static CYTHON_INLINE void __Pyx_XCLEAR_MEMVIEW(__Pyx_memviewslice *, int, int); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE char __Pyx_PyInt_As_char(PyObject *); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* PyObjectCall2Args.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* CoroutineBase.proto */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; + PyObject *gi_weakreflist; + PyObject *classobj; + PyObject *yieldfrom; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static PyObject *__Pyx_Coroutine_Close(PyObject *self); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); + +/* PatchModuleWithCoroutine.proto */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code); + +/* PatchGeneratorABC.proto */ +static int __Pyx_patch_abc(void); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *__pyx_v_self); /* proto*/ +static char *__pyx_memoryview_get_item_pointer(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto*/ +static PyObject *__pyx_memoryview_is_slice(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj); /* proto*/ +static PyObject *__pyx_memoryview_setitem_slice_assignment(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_dst, PyObject *__pyx_v_src); /* proto*/ +static PyObject *__pyx_memoryview_setitem_slice_assign_scalar(struct __pyx_memoryview_obj *__pyx_v_self, struct __pyx_memoryview_obj *__pyx_v_dst, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview_setitem_indexed(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview_convert_item_to_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/ +static PyObject *__pyx_memoryview_assign_item_from_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview__get_base(struct __pyx_memoryview_obj *__pyx_v_self); /* proto*/ +static PyObject *__pyx_memoryviewslice_convert_item_to_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/ +static PyObject *__pyx_memoryviewslice_assign_item_from_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryviewslice__get_base(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_ux(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uy(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uz(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto*/ + +/* Module declarations from "ezdxf.acc.vector" */ +static double (*__pyx_f_5ezdxf_3acc_6vector_v3_dot)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_cross)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*__pyx_f_5ezdxf_3acc_6vector_v3_normalize)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static int (*__pyx_f_5ezdxf_3acc_6vector_v3_isclose)(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); /*proto*/ + +/* Module declarations from "cython.view" */ + +/* Module declarations from "cython.dataclasses" */ + +/* Module declarations from "cython" */ + +/* Module declarations from "libc.math" */ + +/* Module declarations from "ezdxf.acc.matrix44" */ +static double __pyx_v_5ezdxf_3acc_8matrix44_IDENTITY[16]; +static PyObject *__pyx_collections_abc_Sequence = 0; +static PyObject *generic = 0; +static PyObject *strided = 0; +static PyObject *indirect = 0; +static PyObject *contiguous = 0; +static PyObject *indirect_contiguous = 0; +static int __pyx_memoryview_thread_locks_used; +static PyThread_type_lock __pyx_memoryview_thread_locks[8]; +static CYTHON_INLINE PyObject *__pyx_f_5ezdxf_3acc_8matrix44_swap(double *, double *); /*proto*/ +static void __pyx_f_5ezdxf_3acc_8matrix44_set_floats(double *, PyObject *); /*proto*/ +static void __pyx_f_5ezdxf_3acc_8matrix44_transform_2d_array_inplace(double *, __Pyx_memviewslice, Py_ssize_t); /*proto*/ +static void __pyx_f_5ezdxf_3acc_8matrix44_transform_3d_array_inplace(double *, __Pyx_memviewslice, Py_ssize_t); /*proto*/ +static int __pyx_array_allocate_buffer(struct __pyx_array_obj *); /*proto*/ +static struct __pyx_array_obj *__pyx_array_new(PyObject *, Py_ssize_t, char *, char *, char *); /*proto*/ +static PyObject *__pyx_memoryview_new(PyObject *, int, int, __Pyx_TypeInfo *); /*proto*/ +static CYTHON_INLINE int __pyx_memoryview_check(PyObject *); /*proto*/ +static PyObject *_unellipsify(PyObject *, int); /*proto*/ +static int assert_direct_dimensions(Py_ssize_t *, int); /*proto*/ +static struct __pyx_memoryview_obj *__pyx_memview_slice(struct __pyx_memoryview_obj *, PyObject *); /*proto*/ +static int __pyx_memoryview_slice_memviewslice(__Pyx_memviewslice *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int, int); /*proto*/ +static char *__pyx_pybuffer_index(Py_buffer *, char *, Py_ssize_t, Py_ssize_t); /*proto*/ +static int __pyx_memslice_transpose(__Pyx_memviewslice *); /*proto*/ +static PyObject *__pyx_memoryview_fromslice(__Pyx_memviewslice, int, PyObject *(*)(char *), int (*)(char *, PyObject *), int); /*proto*/ +static __Pyx_memviewslice *__pyx_memoryview_get_slice_from_memoryview(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static void __pyx_memoryview_slice_copy(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static PyObject *__pyx_memoryview_copy_object(struct __pyx_memoryview_obj *); /*proto*/ +static PyObject *__pyx_memoryview_copy_object_from_slice(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static Py_ssize_t abs_py_ssize_t(Py_ssize_t); /*proto*/ +static char __pyx_get_best_slice_order(__Pyx_memviewslice *, int); /*proto*/ +static void _copy_strided_to_strided(char *, Py_ssize_t *, char *, Py_ssize_t *, Py_ssize_t *, Py_ssize_t *, int, size_t); /*proto*/ +static void copy_strided_to_strided(__Pyx_memviewslice *, __Pyx_memviewslice *, int, size_t); /*proto*/ +static Py_ssize_t __pyx_memoryview_slice_get_size(__Pyx_memviewslice *, int); /*proto*/ +static Py_ssize_t __pyx_fill_contig_strides_array(Py_ssize_t *, Py_ssize_t *, Py_ssize_t, int, char); /*proto*/ +static void *__pyx_memoryview_copy_data_to_temp(__Pyx_memviewslice *, __Pyx_memviewslice *, char, int); /*proto*/ +static int __pyx_memoryview_err_extents(int, Py_ssize_t, Py_ssize_t); /*proto*/ +static int __pyx_memoryview_err_dim(PyObject *, PyObject *, int); /*proto*/ +static int __pyx_memoryview_err(PyObject *, PyObject *); /*proto*/ +static int __pyx_memoryview_err_no_memory(void); /*proto*/ +static int __pyx_memoryview_copy_contents(__Pyx_memviewslice, __Pyx_memviewslice, int, int, int); /*proto*/ +static void __pyx_memoryview_broadcast_leading(__Pyx_memviewslice *, int, int); /*proto*/ +static void __pyx_memoryview_refcount_copying(__Pyx_memviewslice *, int, int, int); /*proto*/ +static void __pyx_memoryview_refcount_objects_in_slice_with_gil(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/ +static void __pyx_memoryview_refcount_objects_in_slice(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/ +static void __pyx_memoryview_slice_assign_scalar(__Pyx_memviewslice *, int, size_t, void *, int); /*proto*/ +static void __pyx_memoryview__slice_assign_scalar(char *, Py_ssize_t *, Py_ssize_t *, int, size_t, void *); /*proto*/ +static PyObject *__pyx_unpickle_Enum__set_state(struct __pyx_MemviewEnum_obj *, PyObject *); /*proto*/ +/* #### Code section: typeinfo ### */ +static __Pyx_TypeInfo __Pyx_TypeInfo_double = { "double", NULL, sizeof(double), { 0 }, 0, 'R', 0, 0 }; +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.matrix44" +extern int __pyx_module_is_main_ezdxf__acc__matrix44; +int __pyx_module_is_main_ezdxf__acc__matrix44 = 0; + +/* Implementation of "ezdxf.acc.matrix44" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_staticmethod; +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_IndexError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_AssertionError; +static PyObject *__pyx_builtin___import__; +static PyObject *__pyx_builtin_MemoryError; +static PyObject *__pyx_builtin_enumerate; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_Ellipsis; +static PyObject *__pyx_builtin_id; +/* #### Code section: string_decls ### */ +static const char __pyx_k_[] = ": "; +static const char __pyx_k_O[] = "O"; +static const char __pyx_k_c[] = "c"; +static const char __pyx_k_f[] = "f"; +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_m[] = "m"; +static const char __pyx_k_s[] = "(%s)"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k_z[] = "z"; +static const char __pyx_k__2[] = "."; +static const char __pyx_k__3[] = "*"; +static const char __pyx_k__6[] = "'"; +static const char __pyx_k__7[] = ")"; +static const char __pyx_k_cx[] = "cx"; +static const char __pyx_k_cy[] = "cy"; +static const char __pyx_k_cz[] = "cz"; +static const char __pyx_k_dx[] = "dx"; +static const char __pyx_k_dy[] = "dy"; +static const char __pyx_k_dz[] = "dz"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_id[] = "id"; +static const char __pyx_k_m0[] = "m0"; +static const char __pyx_k_m1[] = "m1"; +static const char __pyx_k_m4[] = "m4"; +static const char __pyx_k_m5[] = "m5"; +static const char __pyx_k_np[] = "np"; +static const char __pyx_k_sx[] = "sx"; +static const char __pyx_k_sy[] = "sy"; +static const char __pyx_k_sz[] = "sz"; +static const char __pyx_k_tx[] = "tx"; +static const char __pyx_k_ty[] = "ty"; +static const char __pyx_k_ux[] = "ux"; +static const char __pyx_k_uy[] = "uy"; +static const char __pyx_k_uz[] = "uz"; +static const char __pyx_k__11[] = ", "; +static const char __pyx_k__96[] = "?"; +static const char __pyx_k_abc[] = "abc"; +static const char __pyx_k_and[] = " and "; +static const char __pyx_k_col[] = "col"; +static const char __pyx_k_det[] = "det"; +static const char __pyx_k_far[] = "far"; +static const char __pyx_k_fov[] = "fov"; +static const char __pyx_k_got[] = " (got "; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_m12[] = "m12"; +static const char __pyx_k_m13[] = "m13"; +static const char __pyx_k_m44[] = "m44"; +static const char __pyx_k_mat[] = "mat"; +static const char __pyx_k_new[] = "__new__"; +static const char __pyx_k_obj[] = "obj"; +static const char __pyx_k_pnt[] = "pnt"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_row[] = "row"; +static const char __pyx_k_sys[] = "sys"; +static const char __pyx_k_tan[] = "tan"; +static const char __pyx_k_top[] = "top"; +static const char __pyx_k_ucs[] = "ucs"; +static const char __pyx_k_wcs[] = "wcs"; +static const char __pyx_k_None[] = "None"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_Vec3[] = "Vec3"; +static const char __pyx_k_args[] = "args"; +static const char __pyx_k_axis[] = "axis"; +static const char __pyx_k_base[] = "base"; +static const char __pyx_k_copy[] = "copy"; +static const char __pyx_k_cxsy[] = "cxsy"; +static const char __pyx_k_dict[] = "__dict__"; +static const char __pyx_k_imul[] = "__imul__"; +static const char __pyx_k_iter[] = "__iter__"; +static const char __pyx_k_left[] = "left"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_math[] = "math"; +static const char __pyx_k_mode[] = "mode"; +static const char __pyx_k_name[] = "name"; +static const char __pyx_k_ndim[] = "ndim"; +static const char __pyx_k_near[] = "near"; +static const char __pyx_k_pack[] = "pack"; +static const char __pyx_k_rows[] = "rows"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_send[] = "send"; +static const char __pyx_k_size[] = "size"; +static const char __pyx_k_spec[] = "__spec__"; +static const char __pyx_k_step[] = "step"; +static const char __pyx_k_stop[] = "stop"; +static const char __pyx_k_sxsy[] = "sxsy"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_ux_2[] = "_ux"; +static const char __pyx_k_uy_2[] = "_uy"; +static const char __pyx_k_uz_2[] = "_uz"; +static const char __pyx_k_ASCII[] = "ASCII"; +static const char __pyx_k_Tuple[] = "Tuple"; +static const char __pyx_k_angle[] = "angle"; +static const char __pyx_k_array[] = "array"; +static const char __pyx_k_chain[] = "chain"; +static const char __pyx_k_class[] = "__class__"; +static const char __pyx_k_close[] = "close"; +static const char __pyx_k_cos_a[] = "cos_a"; +static const char __pyx_k_count[] = "count"; +static const char __pyx_k_error[] = "error"; +static const char __pyx_k_flags[] = "flags"; +static const char __pyx_k_float[] = "float"; +static const char __pyx_k_index[] = "index"; +static const char __pyx_k_numpy[] = "numpy"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_right[] = "right"; +static const char __pyx_k_scale[] = "scale"; +static const char __pyx_k_shape[] = "shape"; +static const char __pyx_k_sin_a[] = "sin_a"; +static const char __pyx_k_start[] = "start"; +static const char __pyx_k_throw[] = "throw"; +static const char __pyx_k_X_AXIS[] = "X_AXIS"; +static const char __pyx_k_Y_AXIS[] = "Y_AXIS"; +static const char __pyx_k_Z_AXIS[] = "Z_AXIS"; +static const char __pyx_k_aspect[] = "aspect"; +static const char __pyx_k_axis_2[] = "_axis"; +static const char __pyx_k_bottom[] = "bottom"; +static const char __pyx_k_copy_2[] = "_copy"; +static const char __pyx_k_copy_3[] = "__copy__"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_encode[] = "encode"; +static const char __pyx_k_format[] = "format"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_matrix[] = "matrix"; +static const char __pyx_k_name_2[] = "__name__"; +static const char __pyx_k_ndim_2[] = "_ndim"; +static const char __pyx_k_origin[] = "origin"; +static const char __pyx_k_pickle[] = "pickle"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_struct[] = "struct"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_unpack[] = "unpack"; +static const char __pyx_k_update[] = "update"; +static const char __pyx_k_values[] = "values"; +static const char __pyx_k_vector[] = "vector"; +static const char __pyx_k_vrange[] = "vrange"; +static const char __pyx_k_NULLVEC[] = "NULLVEC"; +static const char __pyx_k_angle_x[] = "angle_x"; +static const char __pyx_k_angle_y[] = "angle_y"; +static const char __pyx_k_angle_z[] = "angle_z"; +static const char __pyx_k_columns[] = "columns"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_fortran[] = "fortran"; +static const char __pyx_k_genexpr[] = "genexpr"; +static const char __pyx_k_get_col[] = "get_col"; +static const char __pyx_k_get_row[] = "get_row"; +static const char __pyx_k_inverse[] = "inverse"; +static const char __pyx_k_memview[] = "memview"; +static const char __pyx_k_set_col[] = "set_col"; +static const char __pyx_k_set_row[] = "set_row"; +static const char __pyx_k_vectors[] = "vectors"; +static const char __pyx_k_Ellipsis[] = "Ellipsis"; +static const char __pyx_k_Iterable[] = "Iterable"; +static const char __pyx_k_Iterator[] = "Iterator"; +static const char __pyx_k_Matrix44[] = "Matrix44"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_itemsize[] = "itemsize"; +static const char __pyx_k_matrices[] = "matrices"; +static const char __pyx_k_origin_2[] = "_origin"; +static const char __pyx_k_pyx_type[] = "__pyx_type"; +static const char __pyx_k_register[] = "register"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_shear_xy[] = "shear_xy"; +static const char __pyx_k_x_rotate[] = "x_rotate"; +static const char __pyx_k_y_rotate[] = "y_rotate"; +static const char __pyx_k_z_rotate[] = "z_rotate"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_enumerate[] = "enumerate"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_itertools[] = "itertools"; +static const char __pyx_k_normalize[] = "normalize"; +static const char __pyx_k_one_m_cos[] = "one_m_cos"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_transform[] = "transform"; +static const char __pyx_k_translate[] = "translate"; +static const char __pyx_k_transpose[] = "transpose"; +static const char __pyx_k_IndexError[] = "IndexError"; +static const char __pyx_k_Matrix44_s[] = "Matrix44(%s)"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_components[] = "components"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_format_row[] = "format_row"; +static const char __pyx_k_np_ndarray[] = "np.ndarray"; +static const char __pyx_k_ocs_to_wcs[] = "ocs_to_wcs"; +static const char __pyx_k_pyx_result[] = "__pyx_result"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_xyz_rotate[] = "xyz_rotate"; +static const char __pyx_k_MemoryError[] = "MemoryError"; +static const char __pyx_k_PickleError[] = "PickleError"; +static const char __pyx_k_Tuple_float[] = "Tuple[float, ...]"; +static const char __pyx_k_axis_rotate[] = "axis_rotate"; +static const char __pyx_k_collections[] = "collections"; +static const char __pyx_k_determinant[] = "determinant"; +static const char __pyx_k_normalize_2[] = "_normalize"; +static const char __pyx_k_Matrix44_ucs[] = "Matrix44.ucs"; +static const char __pyx_k_initializing[] = "_initializing"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_ocs_from_wcs[] = "ocs_from_wcs"; +static const char __pyx_k_pyx_checksum[] = "__pyx_checksum"; +static const char __pyx_k_staticmethod[] = "staticmethod"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_version_info[] = "version_info"; +static const char __pyx_k_Iterable_UVec[] = "Iterable[UVec]"; +static const char __pyx_k_Iterator_Vec2[] = "Iterator[Vec2]"; +static const char __pyx_k_Iterator_Vec3[] = "Iterator[Vec3]"; +static const char __pyx_k_Matrix44_copy[] = "Matrix44.copy"; +static const char __pyx_k_Matrix44_rows[] = "Matrix44.rows"; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_class_getitem[] = "__class_getitem__"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_AssertionError[] = "AssertionError"; +static const char __pyx_k_Matrix44_chain[] = "Matrix44.chain"; +static const char __pyx_k_Matrix44_scale[] = "Matrix44.scale"; +static const char __pyx_k_Sequence_float[] = "Sequence[float]"; +static const char __pyx_k_transformation[] = "transformation"; +static const char __pyx_k_Matrix44___iter[] = "Matrix44.__iter__"; +static const char __pyx_k_View_MemoryView[] = "View.MemoryView"; +static const char __pyx_k_allocate_buffer[] = "allocate_buffer"; +static const char __pyx_k_collections_abc[] = "collections.abc"; +static const char __pyx_k_dtype_is_object[] = "dtype_is_object"; +static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_Matrix44_columns[] = "Matrix44.columns"; +static const char __pyx_k_Matrix44_get_col[] = "Matrix44.get_col"; +static const char __pyx_k_Matrix44_get_row[] = "Matrix44.get_row"; +static const char __pyx_k_Matrix44_inverse[] = "Matrix44.inverse"; +static const char __pyx_k_Matrix44_set_col[] = "Matrix44.set_col"; +static const char __pyx_k_Matrix44_set_row[] = "Matrix44.set_row"; +static const char __pyx_k_Matrix44___reduce[] = "Matrix44.__reduce__"; +static const char __pyx_k_Matrix44_shear_xy[] = "Matrix44.shear_xy"; +static const char __pyx_k_Matrix44_x_rotate[] = "Matrix44.x_rotate"; +static const char __pyx_k_Matrix44_y_rotate[] = "Matrix44.y_rotate"; +static const char __pyx_k_Matrix44_z_rotate[] = "Matrix44.z_rotate"; +static const char __pyx_k_fast_2d_transform[] = "fast_2d_transform"; +static const char __pyx_k_invalid_col_index[] = "invalid col index: "; +static const char __pyx_k_invalid_row_index[] = "invalid row index: "; +static const char __pyx_k_pyx_unpickle_Enum[] = "__pyx_unpickle_Enum"; +static const char __pyx_k_Matrix44_transform[] = "Matrix44.transform"; +static const char __pyx_k_Matrix44_translate[] = "Matrix44.translate"; +static const char __pyx_k_Matrix44_transpose[] = "Matrix44.transpose"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ezdxf_acc_matrix44[] = "ezdxf.acc.matrix44"; +static const char __pyx_k_index_out_of_range[] = "index out of range: "; +static const char __pyx_k_strided_and_direct[] = ""; +static const char __pyx_k_transform_vertices[] = "transform_vertices"; +static const char __pyx_k_Matrix44_xyz_rotate[] = "Matrix44.xyz_rotate"; +static const char __pyx_k_rows_locals_genexpr[] = "rows..genexpr"; +static const char __pyx_k_transform_direction[] = "transform_direction"; +static const char __pyx_k_ucs_vertex_from_wcs[] = "ucs_vertex_from_wcs"; +static const char __pyx_k_Iterator_Tuple_float[] = "Iterator[Tuple[float, ...]]"; +static const char __pyx_k_Matrix44_axis_rotate[] = "Matrix44.axis_rotate"; +static const char __pyx_k_Matrix44_determinant[] = "Matrix44.determinant"; +static const char __pyx_k_strided_and_indirect[] = ""; +static const char __pyx_k_transform_directions[] = "transform_directions"; +static const char __pyx_k_Invalid_shape_in_axis[] = "Invalid shape in axis "; +static const char __pyx_k_contiguous_and_direct[] = ""; +static const char __pyx_k_get_2d_transformation[] = "get_2d_transformation"; +static const char __pyx_k_ndim_has_to_be_2_or_3[] = "ndim has to be 2 or 3"; +static const char __pyx_k_repr___locals_genexpr[] = "__repr__..genexpr"; +static const char __pyx_k_Cannot_index_with_type[] = "Cannot index with type '"; +static const char __pyx_k_MemoryView_of_r_object[] = ""; +static const char __pyx_k_columns_locals_genexpr[] = "columns..genexpr"; +static const char __pyx_k_from_2d_transformation[] = "from_2d_transformation"; +static const char __pyx_k_invalid_argument_count[] = "invalid argument count"; +static const char __pyx_k_perspective_projection[] = "perspective_projection"; +static const char __pyx_k_ucs_direction_from_wcs[] = "ucs_direction_from_wcs"; +static const char __pyx_k_MemoryView_of_r_at_0x_x[] = ""; +static const char __pyx_k_contiguous_and_indirect[] = ""; +static const char __pyx_k_transform_array_inplace[] = "transform_array_inplace"; +static const char __pyx_k_repr___locals_format_row[] = "__repr__..format_row"; +static const char __pyx_k_Dimension_d_is_not_direct[] = "Dimension %d is not direct"; +static const char __pyx_k_Index_out_of_bounds_axis_d[] = "Index out of bounds (axis %d)"; +static const char __pyx_k_Matrix44_fast_2d_transform[] = "Matrix44.fast_2d_transform"; +static const char __pyx_k_perspective_projection_fov[] = "perspective_projection_fov"; +static const char __pyx_k_src_ezdxf_acc_matrix44_pyx[] = "src/ezdxf/acc/matrix44.pyx"; +static const char __pyx_k_Matrix44_transform_vertices[] = "Matrix44.transform_vertices"; +static const char __pyx_k_Step_may_not_be_zero_axis_d[] = "Step may not be zero (axis %d)"; +static const char __pyx_k_itemsize_0_for_cython_array[] = "itemsize <= 0 for cython.array"; +static const char __pyx_k_Matrix44_transform_direction[] = "Matrix44.transform_direction"; +static const char __pyx_k_Matrix44_ucs_vertex_from_wcs[] = "Matrix44.ucs_vertex_from_wcs"; +static const char __pyx_k_Matrix44_transform_directions[] = "Matrix44.transform_directions"; +static const char __pyx_k_unable_to_allocate_array_data[] = "unable to allocate array data."; +static const char __pyx_k_Matrix44_get_2d_transformation[] = "Matrix44.get_2d_transformation"; +static const char __pyx_k_repr___locals_format_row_local[] = "__repr__..format_row..genexpr"; +static const char __pyx_k_strided_and_direct_or_indirect[] = ""; +static const char __pyx_k_First_2_columns_of_a_3x3_matrix[] = "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32"; +static const char __pyx_k_Matrix44_from_2d_transformation[] = "Matrix44.from_2d_transformation"; +static const char __pyx_k_Matrix44_perspective_projection[] = "Matrix44.perspective_projection"; +static const char __pyx_k_Matrix44_ucs_direction_from_wcs[] = "Matrix44.ucs_direction_from_wcs"; +static const char __pyx_k_All_dimensions_preceding_dimensi[] = "All dimensions preceding dimension %d must be indexed and not sliced"; +static const char __pyx_k_Buffer_view_does_not_expose_stri[] = "Buffer view does not expose strides"; +static const char __pyx_k_Can_only_create_a_buffer_that_is[] = "Can only create a buffer that is contiguous in memory."; +static const char __pyx_k_Cannot_assign_to_read_only_memor[] = "Cannot assign to read-only memoryview"; +static const char __pyx_k_Cannot_create_writable_memory_vi[] = "Cannot create writable memory view from read-only memoryview"; +static const char __pyx_k_Cannot_transpose_memoryview_with[] = "Cannot transpose memoryview with indirect dimensions"; +static const char __pyx_k_Empty_shape_tuple_for_cython_arr[] = "Empty shape tuple for cython.array"; +static const char __pyx_k_Incompatible_checksums_0x_x_vs_0[] = "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))"; +static const char __pyx_k_Indirect_dimensions_not_supporte[] = "Indirect dimensions not supported"; +static const char __pyx_k_Invalid_mode_expected_c_or_fortr[] = "Invalid mode, expected 'c' or 'fortran', got "; +static const char __pyx_k_Matrix44_transform_array_inplace[] = "Matrix44.transform_array_inplace"; +static const char __pyx_k_Out_of_bounds_on_buffer_access_a[] = "Out of bounds on buffer access (axis "; +static const char __pyx_k_Unable_to_convert_item_to_object[] = "Unable to convert item to object"; +static const char __pyx_k_got_differing_extents_in_dimensi[] = "got differing extents in dimension "; +static const char __pyx_k_invalid_argument_count_4_row_vec[] = "invalid argument count: 4 row vectors or iterable of 16 numbers"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +static const char __pyx_k_unable_to_allocate_shape_and_str[] = "unable to allocate shape and strides."; +static const char __pyx_k_Matrix44_perspective_projection_2[] = "Matrix44.perspective_projection_fov"; +/* #### Code section: decls ### */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer); /* proto */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(struct __pyx_array_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ +static void __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_5array_7memview___get__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_attr); /* proto */ +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item); /* proto */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value); /* proto */ +static PyObject *__pyx_pf___pyx_array___reduce_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_array_2__setstate_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_MemviewEnum___reduce_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_MemviewEnum_2__setstate_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj, int __pyx_v_flags, int __pyx_v_dtype_is_object); /* proto */ +static void __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(struct __pyx_memoryview_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryview___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryview_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static void __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryviewslice___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryviewslice_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44___cinit__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_args); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4__getitem__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_index); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6__setitem__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_index, double __pyx_v_value); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__iter__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___format_row(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_row); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___2genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_11__repr__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13get_2d_transformation(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_15from_2d_transformation(PyObject *__pyx_v_components); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_17get_row(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_row); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_19set_row(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_row, PyObject *__pyx_v_values); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_21get_col(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_col); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_23set_col(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_col, PyObject *__pyx_v_values); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4rows_genexpr(PyObject *__pyx_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_25rows(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_7columns_genexpr(PyObject *__pyx_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_27columns(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_29copy(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin_2__set__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_v); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2ux___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uy___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uz___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_31scale(double __pyx_v_sx, PyObject *__pyx_v_sy, PyObject *__pyx_v_sz); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_33translate(double __pyx_v_dx, double __pyx_v_dy, double __pyx_v_dz); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_35x_rotate(double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_37y_rotate(double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_39z_rotate(double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_41axis_rotate(PyObject *__pyx_v_axis, double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_43xyz_rotate(double __pyx_v_angle_x, double __pyx_v_angle_y, double __pyx_v_angle_z); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_45shear_xy(double __pyx_v_angle_x, double __pyx_v_angle_y); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_47perspective_projection(double __pyx_v_left, double __pyx_v_right, double __pyx_v_top, double __pyx_v_bottom, double __pyx_v_near, double __pyx_v_far); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_49perspective_projection_fov(double __pyx_v_fov, double __pyx_v_aspect, double __pyx_v_near, double __pyx_v_far); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_51chain(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_matrices); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_53__imul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_55__mul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other); /* proto */ +#if PY_VERSION_HEX >= 0x03050000 +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_57__matmul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other); /* proto */ +#endif +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_59transpose(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_61determinant(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_63inverse(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_65ucs(PyObject *__pyx_v_ux, PyObject *__pyx_v_uy, PyObject *__pyx_v_uz, PyObject *__pyx_v_origin); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_67transform(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vector); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_69transform_direction(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vector, PyObject *__pyx_v_normalize); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_71transform_vertices(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vectors); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_74fast_2d_transform(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_points); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_array, PyObject *__pyx_v_ndim); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_79transform_directions(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vectors, PyObject *__pyx_v_normalize); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_82ucs_vertex_from_wcs(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_wcs); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_84ucs_direction_from_wcs(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_wcs); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44_Matrix44(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_array(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_memoryview(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new__memoryviewslice(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_8matrix44_Matrix44; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform; + PyObject *__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions; + PyObject *__pyx_type___pyx_array; + PyObject *__pyx_type___pyx_MemviewEnum; + PyObject *__pyx_type___pyx_memoryview; + PyObject *__pyx_type___pyx_memoryviewslice; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions; + PyTypeObject *__pyx_array_type; + PyTypeObject *__pyx_MemviewEnum_type; + PyTypeObject *__pyx_memoryview_type; + PyTypeObject *__pyx_memoryviewslice_type; + PyObject *__pyx_kp_u_; + PyObject *__pyx_n_s_ASCII; + PyObject *__pyx_kp_s_All_dimensions_preceding_dimensi; + PyObject *__pyx_n_s_AssertionError; + PyObject *__pyx_kp_s_Buffer_view_does_not_expose_stri; + PyObject *__pyx_kp_s_Can_only_create_a_buffer_that_is; + PyObject *__pyx_kp_s_Cannot_assign_to_read_only_memor; + PyObject *__pyx_kp_s_Cannot_create_writable_memory_vi; + PyObject *__pyx_kp_u_Cannot_index_with_type; + PyObject *__pyx_kp_s_Cannot_transpose_memoryview_with; + PyObject *__pyx_kp_s_Dimension_d_is_not_direct; + PyObject *__pyx_n_s_Ellipsis; + PyObject *__pyx_kp_s_Empty_shape_tuple_for_cython_arr; + PyObject *__pyx_kp_u_First_2_columns_of_a_3x3_matrix; + PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0; + PyObject *__pyx_n_s_IndexError; + PyObject *__pyx_kp_s_Index_out_of_bounds_axis_d; + PyObject *__pyx_kp_s_Indirect_dimensions_not_supporte; + PyObject *__pyx_kp_u_Invalid_mode_expected_c_or_fortr; + PyObject *__pyx_kp_u_Invalid_shape_in_axis; + PyObject *__pyx_n_s_Iterable; + PyObject *__pyx_kp_s_Iterable_UVec; + PyObject *__pyx_n_s_Iterator; + PyObject *__pyx_kp_s_Iterator_Tuple_float; + PyObject *__pyx_kp_s_Iterator_Vec2; + PyObject *__pyx_kp_s_Iterator_Vec3; + PyObject *__pyx_n_s_Matrix44; + PyObject *__pyx_n_s_Matrix44___iter; + PyObject *__pyx_n_s_Matrix44___reduce; + PyObject *__pyx_n_s_Matrix44_axis_rotate; + PyObject *__pyx_n_s_Matrix44_chain; + PyObject *__pyx_n_s_Matrix44_columns; + PyObject *__pyx_n_s_Matrix44_copy; + PyObject *__pyx_n_s_Matrix44_determinant; + PyObject *__pyx_n_s_Matrix44_fast_2d_transform; + PyObject *__pyx_n_s_Matrix44_from_2d_transformation; + PyObject *__pyx_n_s_Matrix44_get_2d_transformation; + PyObject *__pyx_n_s_Matrix44_get_col; + PyObject *__pyx_n_s_Matrix44_get_row; + PyObject *__pyx_n_s_Matrix44_inverse; + PyObject *__pyx_n_s_Matrix44_perspective_projection; + PyObject *__pyx_n_s_Matrix44_perspective_projection_2; + PyObject *__pyx_n_s_Matrix44_rows; + PyObject *__pyx_kp_u_Matrix44_s; + PyObject *__pyx_n_s_Matrix44_scale; + PyObject *__pyx_n_s_Matrix44_set_col; + PyObject *__pyx_n_s_Matrix44_set_row; + PyObject *__pyx_n_s_Matrix44_shear_xy; + PyObject *__pyx_n_s_Matrix44_transform; + PyObject *__pyx_n_s_Matrix44_transform_array_inplace; + PyObject *__pyx_n_s_Matrix44_transform_direction; + PyObject *__pyx_n_s_Matrix44_transform_directions; + PyObject *__pyx_n_s_Matrix44_transform_vertices; + PyObject *__pyx_n_s_Matrix44_translate; + PyObject *__pyx_n_s_Matrix44_transpose; + PyObject *__pyx_n_s_Matrix44_ucs; + PyObject *__pyx_n_s_Matrix44_ucs_direction_from_wcs; + PyObject *__pyx_n_s_Matrix44_ucs_vertex_from_wcs; + PyObject *__pyx_n_s_Matrix44_x_rotate; + PyObject *__pyx_n_s_Matrix44_xyz_rotate; + PyObject *__pyx_n_s_Matrix44_y_rotate; + PyObject *__pyx_n_s_Matrix44_z_rotate; + PyObject *__pyx_n_s_MemoryError; + PyObject *__pyx_kp_s_MemoryView_of_r_at_0x_x; + PyObject *__pyx_kp_s_MemoryView_of_r_object; + PyObject *__pyx_n_s_NULLVEC; + PyObject *__pyx_n_s_None; + PyObject *__pyx_n_b_O; + PyObject *__pyx_kp_u_Out_of_bounds_on_buffer_access_a; + PyObject *__pyx_n_s_PickleError; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_kp_s_Sequence_float; + PyObject *__pyx_kp_s_Step_may_not_be_zero_axis_d; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_n_s_Tuple; + PyObject *__pyx_kp_s_Tuple_float; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_kp_s_Unable_to_convert_item_to_object; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s_Vec3; + PyObject *__pyx_n_s_View_MemoryView; + PyObject *__pyx_n_s_X_AXIS; + PyObject *__pyx_n_s_Y_AXIS; + PyObject *__pyx_n_s_Z_AXIS; + PyObject *__pyx_kp_u__11; + PyObject *__pyx_kp_u__2; + PyObject *__pyx_n_s__3; + PyObject *__pyx_kp_u__6; + PyObject *__pyx_kp_u__7; + PyObject *__pyx_n_s__96; + PyObject *__pyx_n_s_abc; + PyObject *__pyx_n_s_allocate_buffer; + PyObject *__pyx_kp_u_and; + PyObject *__pyx_n_s_angle; + PyObject *__pyx_n_s_angle_x; + PyObject *__pyx_n_s_angle_y; + PyObject *__pyx_n_s_angle_z; + PyObject *__pyx_n_s_args; + PyObject *__pyx_n_s_array; + PyObject *__pyx_n_s_aspect; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_axis; + PyObject *__pyx_n_s_axis_2; + PyObject *__pyx_n_s_axis_rotate; + PyObject *__pyx_n_s_base; + PyObject *__pyx_n_s_bottom; + PyObject *__pyx_n_s_c; + PyObject *__pyx_n_u_c; + PyObject *__pyx_n_s_chain; + PyObject *__pyx_n_s_class; + PyObject *__pyx_n_s_class_getitem; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_close; + PyObject *__pyx_n_s_col; + PyObject *__pyx_n_s_collections; + PyObject *__pyx_kp_s_collections_abc; + PyObject *__pyx_n_s_columns; + PyObject *__pyx_n_s_columns_locals_genexpr; + PyObject *__pyx_n_s_components; + PyObject *__pyx_kp_s_contiguous_and_direct; + PyObject *__pyx_kp_s_contiguous_and_indirect; + PyObject *__pyx_n_s_copy; + PyObject *__pyx_n_s_copy_2; + PyObject *__pyx_n_s_copy_3; + PyObject *__pyx_n_s_cos_a; + PyObject *__pyx_n_s_count; + PyObject *__pyx_n_s_cx; + PyObject *__pyx_n_s_cxsy; + PyObject *__pyx_n_s_cy; + PyObject *__pyx_n_s_cz; + PyObject *__pyx_n_s_det; + PyObject *__pyx_n_s_determinant; + PyObject *__pyx_n_s_dict; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_dtype_is_object; + PyObject *__pyx_n_s_dx; + PyObject *__pyx_n_s_dy; + PyObject *__pyx_n_s_dz; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_encode; + PyObject *__pyx_n_s_enumerate; + PyObject *__pyx_n_s_error; + PyObject *__pyx_n_s_ezdxf_acc_matrix44; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_n_s_f; + PyObject *__pyx_n_s_far; + PyObject *__pyx_n_s_fast_2d_transform; + PyObject *__pyx_n_s_flags; + PyObject *__pyx_n_s_float; + PyObject *__pyx_n_s_format; + PyObject *__pyx_n_s_format_row; + PyObject *__pyx_n_s_fortran; + PyObject *__pyx_n_u_fortran; + PyObject *__pyx_n_s_fov; + PyObject *__pyx_n_s_from_2d_transformation; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_genexpr; + PyObject *__pyx_n_s_get_2d_transformation; + PyObject *__pyx_n_s_get_col; + PyObject *__pyx_n_s_get_row; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_kp_u_got; + PyObject *__pyx_kp_u_got_differing_extents_in_dimensi; + PyObject *__pyx_n_s_i; + PyObject *__pyx_n_s_id; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_imul; + PyObject *__pyx_n_s_index; + PyObject *__pyx_kp_u_index_out_of_range; + PyObject *__pyx_n_s_initializing; + PyObject *__pyx_n_s_int; + PyObject *__pyx_kp_u_invalid_argument_count; + PyObject *__pyx_kp_u_invalid_argument_count_4_row_vec; + PyObject *__pyx_kp_u_invalid_col_index; + PyObject *__pyx_kp_u_invalid_row_index; + PyObject *__pyx_n_s_inverse; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_itemsize; + PyObject *__pyx_kp_s_itemsize_0_for_cython_array; + PyObject *__pyx_n_s_iter; + PyObject *__pyx_n_s_itertools; + PyObject *__pyx_n_s_left; + PyObject *__pyx_n_s_m; + PyObject *__pyx_n_s_m0; + PyObject *__pyx_n_s_m1; + PyObject *__pyx_n_s_m12; + PyObject *__pyx_n_s_m13; + PyObject *__pyx_n_s_m4; + PyObject *__pyx_n_s_m44; + PyObject *__pyx_n_s_m5; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_mat; + PyObject *__pyx_n_s_math; + PyObject *__pyx_n_s_matrices; + PyObject *__pyx_n_s_matrix; + PyObject *__pyx_n_s_memview; + PyObject *__pyx_n_s_mode; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_name_2; + PyObject *__pyx_n_s_ndim; + PyObject *__pyx_n_s_ndim_2; + PyObject *__pyx_kp_u_ndim_has_to_be_2_or_3; + PyObject *__pyx_n_s_near; + PyObject *__pyx_n_s_new; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_normalize; + PyObject *__pyx_n_s_normalize_2; + PyObject *__pyx_n_s_np; + PyObject *__pyx_kp_s_np_ndarray; + PyObject *__pyx_n_s_numpy; + PyObject *__pyx_n_s_obj; + PyObject *__pyx_n_s_ocs_from_wcs; + PyObject *__pyx_n_s_ocs_to_wcs; + PyObject *__pyx_n_s_one_m_cos; + PyObject *__pyx_n_s_origin; + PyObject *__pyx_n_s_origin_2; + PyObject *__pyx_n_s_pack; + PyObject *__pyx_n_s_perspective_projection; + PyObject *__pyx_n_s_perspective_projection_fov; + PyObject *__pyx_n_s_pickle; + PyObject *__pyx_n_s_pnt; + PyObject *__pyx_n_s_points; + PyObject *__pyx_n_s_pyx_PickleError; + PyObject *__pyx_n_s_pyx_checksum; + PyObject *__pyx_n_s_pyx_result; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_type; + PyObject *__pyx_n_s_pyx_unpickle_Enum; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_register; + PyObject *__pyx_n_s_repr___locals_format_row; + PyObject *__pyx_n_s_repr___locals_format_row_local; + PyObject *__pyx_n_s_repr___locals_genexpr; + PyObject *__pyx_n_s_res; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_right; + PyObject *__pyx_n_s_row; + PyObject *__pyx_n_s_rows; + PyObject *__pyx_n_s_rows_locals_genexpr; + PyObject *__pyx_kp_u_s; + PyObject *__pyx_n_s_scale; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_send; + PyObject *__pyx_n_s_set_col; + PyObject *__pyx_n_s_set_row; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_shape; + PyObject *__pyx_n_s_shear_xy; + PyObject *__pyx_n_s_sin_a; + PyObject *__pyx_n_s_size; + PyObject *__pyx_n_s_spec; + PyObject *__pyx_kp_s_src_ezdxf_acc_matrix44_pyx; + PyObject *__pyx_n_s_start; + PyObject *__pyx_n_s_staticmethod; + PyObject *__pyx_n_s_step; + PyObject *__pyx_n_s_stop; + PyObject *__pyx_kp_s_strided_and_direct; + PyObject *__pyx_kp_s_strided_and_direct_or_indirect; + PyObject *__pyx_kp_s_strided_and_indirect; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_struct; + PyObject *__pyx_n_s_sx; + PyObject *__pyx_n_s_sxsy; + PyObject *__pyx_n_s_sy; + PyObject *__pyx_n_s_sys; + PyObject *__pyx_n_s_sz; + PyObject *__pyx_n_s_tan; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_throw; + PyObject *__pyx_n_s_top; + PyObject *__pyx_n_s_transform; + PyObject *__pyx_n_s_transform_array_inplace; + PyObject *__pyx_n_s_transform_direction; + PyObject *__pyx_n_s_transform_directions; + PyObject *__pyx_n_s_transform_vertices; + PyObject *__pyx_n_s_transformation; + PyObject *__pyx_n_s_translate; + PyObject *__pyx_n_s_transpose; + PyObject *__pyx_n_s_tx; + PyObject *__pyx_n_s_ty; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_ucs; + PyObject *__pyx_n_s_ucs_direction_from_wcs; + PyObject *__pyx_n_s_ucs_vertex_from_wcs; + PyObject *__pyx_kp_s_unable_to_allocate_array_data; + PyObject *__pyx_kp_s_unable_to_allocate_shape_and_str; + PyObject *__pyx_n_s_unpack; + PyObject *__pyx_n_s_update; + PyObject *__pyx_n_s_ux; + PyObject *__pyx_n_s_ux_2; + PyObject *__pyx_n_s_uy; + PyObject *__pyx_n_s_uy_2; + PyObject *__pyx_n_s_uz; + PyObject *__pyx_n_s_uz_2; + PyObject *__pyx_n_s_values; + PyObject *__pyx_n_s_vector; + PyObject *__pyx_n_s_vectors; + PyObject *__pyx_n_s_version_info; + PyObject *__pyx_n_s_vrange; + PyObject *__pyx_n_s_wcs; + PyObject *__pyx_n_s_x; + PyObject *__pyx_n_s_x_rotate; + PyObject *__pyx_n_s_xyz_rotate; + PyObject *__pyx_n_s_y; + PyObject *__pyx_n_s_y_rotate; + PyObject *__pyx_n_s_z; + PyObject *__pyx_n_s_z_rotate; + PyObject *__pyx_float_0_0; + PyObject *__pyx_float_1_0; + PyObject *__pyx_int_0; + PyObject *__pyx_int_1; + PyObject *__pyx_int_2; + PyObject *__pyx_int_3; + PyObject *__pyx_int_112105877; + PyObject *__pyx_int_136983863; + PyObject *__pyx_int_184977713; + PyObject *__pyx_int_neg_1; + PyObject *__pyx_k__16; + PyObject *__pyx_k__17; + PyObject *__pyx_k__18; + PyObject *__pyx_k__19; + PyObject *__pyx_slice__5; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__8; + PyObject *__pyx_tuple__9; + PyObject *__pyx_tuple__10; + PyObject *__pyx_tuple__12; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__15; + PyObject *__pyx_tuple__22; + PyObject *__pyx_tuple__24; + PyObject *__pyx_tuple__25; + PyObject *__pyx_tuple__26; + PyObject *__pyx_tuple__27; + PyObject *__pyx_tuple__28; + PyObject *__pyx_tuple__29; + PyObject *__pyx_tuple__30; + PyObject *__pyx_tuple__31; + PyObject *__pyx_tuple__32; + PyObject *__pyx_tuple__33; + PyObject *__pyx_tuple__35; + PyObject *__pyx_tuple__37; + PyObject *__pyx_tuple__39; + PyObject *__pyx_tuple__41; + PyObject *__pyx_tuple__43; + PyObject *__pyx_tuple__45; + PyObject *__pyx_tuple__47; + PyObject *__pyx_tuple__49; + PyObject *__pyx_tuple__52; + PyObject *__pyx_tuple__54; + PyObject *__pyx_tuple__56; + PyObject *__pyx_tuple__57; + PyObject *__pyx_tuple__59; + PyObject *__pyx_tuple__63; + PyObject *__pyx_tuple__65; + PyObject *__pyx_tuple__67; + PyObject *__pyx_tuple__69; + PyObject *__pyx_tuple__70; + PyObject *__pyx_tuple__72; + PyObject *__pyx_tuple__74; + PyObject *__pyx_tuple__78; + PyObject *__pyx_tuple__80; + PyObject *__pyx_tuple__82; + PyObject *__pyx_tuple__84; + PyObject *__pyx_tuple__86; + PyObject *__pyx_tuple__87; + PyObject *__pyx_tuple__88; + PyObject *__pyx_tuple__89; + PyObject *__pyx_tuple__91; + PyObject *__pyx_tuple__92; + PyObject *__pyx_tuple__94; + PyObject *__pyx_codeobj__13; + PyObject *__pyx_codeobj__20; + PyObject *__pyx_codeobj__21; + PyObject *__pyx_codeobj__23; + PyObject *__pyx_codeobj__34; + PyObject *__pyx_codeobj__36; + PyObject *__pyx_codeobj__38; + PyObject *__pyx_codeobj__40; + PyObject *__pyx_codeobj__42; + PyObject *__pyx_codeobj__44; + PyObject *__pyx_codeobj__46; + PyObject *__pyx_codeobj__48; + PyObject *__pyx_codeobj__50; + PyObject *__pyx_codeobj__51; + PyObject *__pyx_codeobj__53; + PyObject *__pyx_codeobj__55; + PyObject *__pyx_codeobj__58; + PyObject *__pyx_codeobj__60; + PyObject *__pyx_codeobj__61; + PyObject *__pyx_codeobj__62; + PyObject *__pyx_codeobj__64; + PyObject *__pyx_codeobj__66; + PyObject *__pyx_codeobj__68; + PyObject *__pyx_codeobj__71; + PyObject *__pyx_codeobj__73; + PyObject *__pyx_codeobj__75; + PyObject *__pyx_codeobj__76; + PyObject *__pyx_codeobj__77; + PyObject *__pyx_codeobj__79; + PyObject *__pyx_codeobj__81; + PyObject *__pyx_codeobj__83; + PyObject *__pyx_codeobj__85; + PyObject *__pyx_codeobj__90; + PyObject *__pyx_codeobj__93; + PyObject *__pyx_codeobj__95; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44_Matrix44); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions); + Py_CLEAR(clear_module_state->__pyx_array_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_array); + Py_CLEAR(clear_module_state->__pyx_MemviewEnum_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_MemviewEnum); + Py_CLEAR(clear_module_state->__pyx_memoryview_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_memoryview); + Py_CLEAR(clear_module_state->__pyx_memoryviewslice_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_memoryviewslice); + Py_CLEAR(clear_module_state->__pyx_kp_u_); + Py_CLEAR(clear_module_state->__pyx_n_s_ASCII); + Py_CLEAR(clear_module_state->__pyx_kp_s_All_dimensions_preceding_dimensi); + Py_CLEAR(clear_module_state->__pyx_n_s_AssertionError); + Py_CLEAR(clear_module_state->__pyx_kp_s_Buffer_view_does_not_expose_stri); + Py_CLEAR(clear_module_state->__pyx_kp_s_Can_only_create_a_buffer_that_is); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_assign_to_read_only_memor); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_create_writable_memory_vi); + Py_CLEAR(clear_module_state->__pyx_kp_u_Cannot_index_with_type); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_transpose_memoryview_with); + Py_CLEAR(clear_module_state->__pyx_kp_s_Dimension_d_is_not_direct); + Py_CLEAR(clear_module_state->__pyx_n_s_Ellipsis); + Py_CLEAR(clear_module_state->__pyx_kp_s_Empty_shape_tuple_for_cython_arr); + Py_CLEAR(clear_module_state->__pyx_kp_u_First_2_columns_of_a_3x3_matrix); + Py_CLEAR(clear_module_state->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0); + Py_CLEAR(clear_module_state->__pyx_n_s_IndexError); + Py_CLEAR(clear_module_state->__pyx_kp_s_Index_out_of_bounds_axis_d); + Py_CLEAR(clear_module_state->__pyx_kp_s_Indirect_dimensions_not_supporte); + Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_mode_expected_c_or_fortr); + Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_shape_in_axis); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterable); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterator); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Tuple_float); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Vec2); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44___iter); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44___reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_axis_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_chain); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_columns); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_copy); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_determinant); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_fast_2d_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_from_2d_transformation); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_get_2d_transformation); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_get_col); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_get_row); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_inverse); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_perspective_projection); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_perspective_projection_2); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_rows); + Py_CLEAR(clear_module_state->__pyx_kp_u_Matrix44_s); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_scale); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_set_col); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_set_row); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_shear_xy); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transform_array_inplace); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transform_direction); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transform_directions); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_translate); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_transpose); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_ucs); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_ucs_direction_from_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_ucs_vertex_from_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_x_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_xyz_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_y_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Matrix44_z_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_MemoryError); + Py_CLEAR(clear_module_state->__pyx_kp_s_MemoryView_of_r_at_0x_x); + Py_CLEAR(clear_module_state->__pyx_kp_s_MemoryView_of_r_object); + Py_CLEAR(clear_module_state->__pyx_n_s_NULLVEC); + Py_CLEAR(clear_module_state->__pyx_n_s_None); + Py_CLEAR(clear_module_state->__pyx_n_b_O); + Py_CLEAR(clear_module_state->__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + Py_CLEAR(clear_module_state->__pyx_n_s_PickleError); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_kp_s_Sequence_float); + Py_CLEAR(clear_module_state->__pyx_kp_s_Step_may_not_be_zero_axis_d); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_n_s_Tuple); + Py_CLEAR(clear_module_state->__pyx_kp_s_Tuple_float); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_kp_s_Unable_to_convert_item_to_object); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_View_MemoryView); + Py_CLEAR(clear_module_state->__pyx_n_s_X_AXIS); + Py_CLEAR(clear_module_state->__pyx_n_s_Y_AXIS); + Py_CLEAR(clear_module_state->__pyx_n_s_Z_AXIS); + Py_CLEAR(clear_module_state->__pyx_kp_u__11); + Py_CLEAR(clear_module_state->__pyx_kp_u__2); + Py_CLEAR(clear_module_state->__pyx_n_s__3); + Py_CLEAR(clear_module_state->__pyx_kp_u__6); + Py_CLEAR(clear_module_state->__pyx_kp_u__7); + Py_CLEAR(clear_module_state->__pyx_n_s__96); + Py_CLEAR(clear_module_state->__pyx_n_s_abc); + Py_CLEAR(clear_module_state->__pyx_n_s_allocate_buffer); + Py_CLEAR(clear_module_state->__pyx_kp_u_and); + Py_CLEAR(clear_module_state->__pyx_n_s_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_x); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_y); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_z); + Py_CLEAR(clear_module_state->__pyx_n_s_args); + Py_CLEAR(clear_module_state->__pyx_n_s_array); + Py_CLEAR(clear_module_state->__pyx_n_s_aspect); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_axis); + Py_CLEAR(clear_module_state->__pyx_n_s_axis_2); + Py_CLEAR(clear_module_state->__pyx_n_s_axis_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_base); + Py_CLEAR(clear_module_state->__pyx_n_s_bottom); + Py_CLEAR(clear_module_state->__pyx_n_s_c); + Py_CLEAR(clear_module_state->__pyx_n_u_c); + Py_CLEAR(clear_module_state->__pyx_n_s_chain); + Py_CLEAR(clear_module_state->__pyx_n_s_class); + Py_CLEAR(clear_module_state->__pyx_n_s_class_getitem); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_close); + Py_CLEAR(clear_module_state->__pyx_n_s_col); + Py_CLEAR(clear_module_state->__pyx_n_s_collections); + Py_CLEAR(clear_module_state->__pyx_kp_s_collections_abc); + Py_CLEAR(clear_module_state->__pyx_n_s_columns); + Py_CLEAR(clear_module_state->__pyx_n_s_columns_locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_components); + Py_CLEAR(clear_module_state->__pyx_kp_s_contiguous_and_direct); + Py_CLEAR(clear_module_state->__pyx_kp_s_contiguous_and_indirect); + Py_CLEAR(clear_module_state->__pyx_n_s_copy); + Py_CLEAR(clear_module_state->__pyx_n_s_copy_2); + Py_CLEAR(clear_module_state->__pyx_n_s_copy_3); + Py_CLEAR(clear_module_state->__pyx_n_s_cos_a); + Py_CLEAR(clear_module_state->__pyx_n_s_count); + Py_CLEAR(clear_module_state->__pyx_n_s_cx); + Py_CLEAR(clear_module_state->__pyx_n_s_cxsy); + Py_CLEAR(clear_module_state->__pyx_n_s_cy); + Py_CLEAR(clear_module_state->__pyx_n_s_cz); + Py_CLEAR(clear_module_state->__pyx_n_s_det); + Py_CLEAR(clear_module_state->__pyx_n_s_determinant); + Py_CLEAR(clear_module_state->__pyx_n_s_dict); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_dtype_is_object); + Py_CLEAR(clear_module_state->__pyx_n_s_dx); + Py_CLEAR(clear_module_state->__pyx_n_s_dy); + Py_CLEAR(clear_module_state->__pyx_n_s_dz); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_encode); + Py_CLEAR(clear_module_state->__pyx_n_s_enumerate); + Py_CLEAR(clear_module_state->__pyx_n_s_error); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_matrix44); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_n_s_f); + Py_CLEAR(clear_module_state->__pyx_n_s_far); + Py_CLEAR(clear_module_state->__pyx_n_s_fast_2d_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_flags); + Py_CLEAR(clear_module_state->__pyx_n_s_float); + Py_CLEAR(clear_module_state->__pyx_n_s_format); + Py_CLEAR(clear_module_state->__pyx_n_s_format_row); + Py_CLEAR(clear_module_state->__pyx_n_s_fortran); + Py_CLEAR(clear_module_state->__pyx_n_u_fortran); + Py_CLEAR(clear_module_state->__pyx_n_s_fov); + Py_CLEAR(clear_module_state->__pyx_n_s_from_2d_transformation); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_get_2d_transformation); + Py_CLEAR(clear_module_state->__pyx_n_s_get_col); + Py_CLEAR(clear_module_state->__pyx_n_s_get_row); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_kp_u_got); + Py_CLEAR(clear_module_state->__pyx_kp_u_got_differing_extents_in_dimensi); + Py_CLEAR(clear_module_state->__pyx_n_s_i); + Py_CLEAR(clear_module_state->__pyx_n_s_id); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_imul); + Py_CLEAR(clear_module_state->__pyx_n_s_index); + Py_CLEAR(clear_module_state->__pyx_kp_u_index_out_of_range); + Py_CLEAR(clear_module_state->__pyx_n_s_initializing); + Py_CLEAR(clear_module_state->__pyx_n_s_int); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_argument_count); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_argument_count_4_row_vec); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_col_index); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_row_index); + Py_CLEAR(clear_module_state->__pyx_n_s_inverse); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_itemsize); + Py_CLEAR(clear_module_state->__pyx_kp_s_itemsize_0_for_cython_array); + Py_CLEAR(clear_module_state->__pyx_n_s_iter); + Py_CLEAR(clear_module_state->__pyx_n_s_itertools); + Py_CLEAR(clear_module_state->__pyx_n_s_left); + Py_CLEAR(clear_module_state->__pyx_n_s_m); + Py_CLEAR(clear_module_state->__pyx_n_s_m0); + Py_CLEAR(clear_module_state->__pyx_n_s_m1); + Py_CLEAR(clear_module_state->__pyx_n_s_m12); + Py_CLEAR(clear_module_state->__pyx_n_s_m13); + Py_CLEAR(clear_module_state->__pyx_n_s_m4); + Py_CLEAR(clear_module_state->__pyx_n_s_m44); + Py_CLEAR(clear_module_state->__pyx_n_s_m5); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_mat); + Py_CLEAR(clear_module_state->__pyx_n_s_math); + Py_CLEAR(clear_module_state->__pyx_n_s_matrices); + Py_CLEAR(clear_module_state->__pyx_n_s_matrix); + Py_CLEAR(clear_module_state->__pyx_n_s_memview); + Py_CLEAR(clear_module_state->__pyx_n_s_mode); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_name_2); + Py_CLEAR(clear_module_state->__pyx_n_s_ndim); + Py_CLEAR(clear_module_state->__pyx_n_s_ndim_2); + Py_CLEAR(clear_module_state->__pyx_kp_u_ndim_has_to_be_2_or_3); + Py_CLEAR(clear_module_state->__pyx_n_s_near); + Py_CLEAR(clear_module_state->__pyx_n_s_new); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_normalize); + Py_CLEAR(clear_module_state->__pyx_n_s_normalize_2); + Py_CLEAR(clear_module_state->__pyx_n_s_np); + Py_CLEAR(clear_module_state->__pyx_kp_s_np_ndarray); + Py_CLEAR(clear_module_state->__pyx_n_s_numpy); + Py_CLEAR(clear_module_state->__pyx_n_s_obj); + Py_CLEAR(clear_module_state->__pyx_n_s_ocs_from_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_ocs_to_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_one_m_cos); + Py_CLEAR(clear_module_state->__pyx_n_s_origin); + Py_CLEAR(clear_module_state->__pyx_n_s_origin_2); + Py_CLEAR(clear_module_state->__pyx_n_s_pack); + Py_CLEAR(clear_module_state->__pyx_n_s_perspective_projection); + Py_CLEAR(clear_module_state->__pyx_n_s_perspective_projection_fov); + Py_CLEAR(clear_module_state->__pyx_n_s_pickle); + Py_CLEAR(clear_module_state->__pyx_n_s_pnt); + Py_CLEAR(clear_module_state->__pyx_n_s_points); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_PickleError); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_checksum); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_result); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_type); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_unpickle_Enum); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_register); + Py_CLEAR(clear_module_state->__pyx_n_s_repr___locals_format_row); + Py_CLEAR(clear_module_state->__pyx_n_s_repr___locals_format_row_local); + Py_CLEAR(clear_module_state->__pyx_n_s_repr___locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_res); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_right); + Py_CLEAR(clear_module_state->__pyx_n_s_row); + Py_CLEAR(clear_module_state->__pyx_n_s_rows); + Py_CLEAR(clear_module_state->__pyx_n_s_rows_locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_kp_u_s); + Py_CLEAR(clear_module_state->__pyx_n_s_scale); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_send); + Py_CLEAR(clear_module_state->__pyx_n_s_set_col); + Py_CLEAR(clear_module_state->__pyx_n_s_set_row); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_shape); + Py_CLEAR(clear_module_state->__pyx_n_s_shear_xy); + Py_CLEAR(clear_module_state->__pyx_n_s_sin_a); + Py_CLEAR(clear_module_state->__pyx_n_s_size); + Py_CLEAR(clear_module_state->__pyx_n_s_spec); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_matrix44_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start); + Py_CLEAR(clear_module_state->__pyx_n_s_staticmethod); + Py_CLEAR(clear_module_state->__pyx_n_s_step); + Py_CLEAR(clear_module_state->__pyx_n_s_stop); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_direct); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_direct_or_indirect); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_indirect); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_struct); + Py_CLEAR(clear_module_state->__pyx_n_s_sx); + Py_CLEAR(clear_module_state->__pyx_n_s_sxsy); + Py_CLEAR(clear_module_state->__pyx_n_s_sy); + Py_CLEAR(clear_module_state->__pyx_n_s_sys); + Py_CLEAR(clear_module_state->__pyx_n_s_sz); + Py_CLEAR(clear_module_state->__pyx_n_s_tan); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_throw); + Py_CLEAR(clear_module_state->__pyx_n_s_top); + Py_CLEAR(clear_module_state->__pyx_n_s_transform); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_array_inplace); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_direction); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_directions); + Py_CLEAR(clear_module_state->__pyx_n_s_transform_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_transformation); + Py_CLEAR(clear_module_state->__pyx_n_s_translate); + Py_CLEAR(clear_module_state->__pyx_n_s_transpose); + Py_CLEAR(clear_module_state->__pyx_n_s_tx); + Py_CLEAR(clear_module_state->__pyx_n_s_ty); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_ucs); + Py_CLEAR(clear_module_state->__pyx_n_s_ucs_direction_from_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_ucs_vertex_from_wcs); + Py_CLEAR(clear_module_state->__pyx_kp_s_unable_to_allocate_array_data); + Py_CLEAR(clear_module_state->__pyx_kp_s_unable_to_allocate_shape_and_str); + Py_CLEAR(clear_module_state->__pyx_n_s_unpack); + Py_CLEAR(clear_module_state->__pyx_n_s_update); + Py_CLEAR(clear_module_state->__pyx_n_s_ux); + Py_CLEAR(clear_module_state->__pyx_n_s_ux_2); + Py_CLEAR(clear_module_state->__pyx_n_s_uy); + Py_CLEAR(clear_module_state->__pyx_n_s_uy_2); + Py_CLEAR(clear_module_state->__pyx_n_s_uz); + Py_CLEAR(clear_module_state->__pyx_n_s_uz_2); + Py_CLEAR(clear_module_state->__pyx_n_s_values); + Py_CLEAR(clear_module_state->__pyx_n_s_vector); + Py_CLEAR(clear_module_state->__pyx_n_s_vectors); + Py_CLEAR(clear_module_state->__pyx_n_s_version_info); + Py_CLEAR(clear_module_state->__pyx_n_s_vrange); + Py_CLEAR(clear_module_state->__pyx_n_s_wcs); + Py_CLEAR(clear_module_state->__pyx_n_s_x); + Py_CLEAR(clear_module_state->__pyx_n_s_x_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_xyz_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_y); + Py_CLEAR(clear_module_state->__pyx_n_s_y_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_z); + Py_CLEAR(clear_module_state->__pyx_n_s_z_rotate); + Py_CLEAR(clear_module_state->__pyx_float_0_0); + Py_CLEAR(clear_module_state->__pyx_float_1_0); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_1); + Py_CLEAR(clear_module_state->__pyx_int_2); + Py_CLEAR(clear_module_state->__pyx_int_3); + Py_CLEAR(clear_module_state->__pyx_int_112105877); + Py_CLEAR(clear_module_state->__pyx_int_136983863); + Py_CLEAR(clear_module_state->__pyx_int_184977713); + Py_CLEAR(clear_module_state->__pyx_int_neg_1); + Py_CLEAR(clear_module_state->__pyx_k__16); + Py_CLEAR(clear_module_state->__pyx_k__17); + Py_CLEAR(clear_module_state->__pyx_k__18); + Py_CLEAR(clear_module_state->__pyx_k__19); + Py_CLEAR(clear_module_state->__pyx_slice__5); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__8); + Py_CLEAR(clear_module_state->__pyx_tuple__9); + Py_CLEAR(clear_module_state->__pyx_tuple__10); + Py_CLEAR(clear_module_state->__pyx_tuple__12); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__15); + Py_CLEAR(clear_module_state->__pyx_tuple__22); + Py_CLEAR(clear_module_state->__pyx_tuple__24); + Py_CLEAR(clear_module_state->__pyx_tuple__25); + Py_CLEAR(clear_module_state->__pyx_tuple__26); + Py_CLEAR(clear_module_state->__pyx_tuple__27); + Py_CLEAR(clear_module_state->__pyx_tuple__28); + Py_CLEAR(clear_module_state->__pyx_tuple__29); + Py_CLEAR(clear_module_state->__pyx_tuple__30); + Py_CLEAR(clear_module_state->__pyx_tuple__31); + Py_CLEAR(clear_module_state->__pyx_tuple__32); + Py_CLEAR(clear_module_state->__pyx_tuple__33); + Py_CLEAR(clear_module_state->__pyx_tuple__35); + Py_CLEAR(clear_module_state->__pyx_tuple__37); + Py_CLEAR(clear_module_state->__pyx_tuple__39); + Py_CLEAR(clear_module_state->__pyx_tuple__41); + Py_CLEAR(clear_module_state->__pyx_tuple__43); + Py_CLEAR(clear_module_state->__pyx_tuple__45); + Py_CLEAR(clear_module_state->__pyx_tuple__47); + Py_CLEAR(clear_module_state->__pyx_tuple__49); + Py_CLEAR(clear_module_state->__pyx_tuple__52); + Py_CLEAR(clear_module_state->__pyx_tuple__54); + Py_CLEAR(clear_module_state->__pyx_tuple__56); + Py_CLEAR(clear_module_state->__pyx_tuple__57); + Py_CLEAR(clear_module_state->__pyx_tuple__59); + Py_CLEAR(clear_module_state->__pyx_tuple__63); + Py_CLEAR(clear_module_state->__pyx_tuple__65); + Py_CLEAR(clear_module_state->__pyx_tuple__67); + Py_CLEAR(clear_module_state->__pyx_tuple__69); + Py_CLEAR(clear_module_state->__pyx_tuple__70); + Py_CLEAR(clear_module_state->__pyx_tuple__72); + Py_CLEAR(clear_module_state->__pyx_tuple__74); + Py_CLEAR(clear_module_state->__pyx_tuple__78); + Py_CLEAR(clear_module_state->__pyx_tuple__80); + Py_CLEAR(clear_module_state->__pyx_tuple__82); + Py_CLEAR(clear_module_state->__pyx_tuple__84); + Py_CLEAR(clear_module_state->__pyx_tuple__86); + Py_CLEAR(clear_module_state->__pyx_tuple__87); + Py_CLEAR(clear_module_state->__pyx_tuple__88); + Py_CLEAR(clear_module_state->__pyx_tuple__89); + Py_CLEAR(clear_module_state->__pyx_tuple__91); + Py_CLEAR(clear_module_state->__pyx_tuple__92); + Py_CLEAR(clear_module_state->__pyx_tuple__94); + Py_CLEAR(clear_module_state->__pyx_codeobj__13); + Py_CLEAR(clear_module_state->__pyx_codeobj__20); + Py_CLEAR(clear_module_state->__pyx_codeobj__21); + Py_CLEAR(clear_module_state->__pyx_codeobj__23); + Py_CLEAR(clear_module_state->__pyx_codeobj__34); + Py_CLEAR(clear_module_state->__pyx_codeobj__36); + Py_CLEAR(clear_module_state->__pyx_codeobj__38); + Py_CLEAR(clear_module_state->__pyx_codeobj__40); + Py_CLEAR(clear_module_state->__pyx_codeobj__42); + Py_CLEAR(clear_module_state->__pyx_codeobj__44); + Py_CLEAR(clear_module_state->__pyx_codeobj__46); + Py_CLEAR(clear_module_state->__pyx_codeobj__48); + Py_CLEAR(clear_module_state->__pyx_codeobj__50); + Py_CLEAR(clear_module_state->__pyx_codeobj__51); + Py_CLEAR(clear_module_state->__pyx_codeobj__53); + Py_CLEAR(clear_module_state->__pyx_codeobj__55); + Py_CLEAR(clear_module_state->__pyx_codeobj__58); + Py_CLEAR(clear_module_state->__pyx_codeobj__60); + Py_CLEAR(clear_module_state->__pyx_codeobj__61); + Py_CLEAR(clear_module_state->__pyx_codeobj__62); + Py_CLEAR(clear_module_state->__pyx_codeobj__64); + Py_CLEAR(clear_module_state->__pyx_codeobj__66); + Py_CLEAR(clear_module_state->__pyx_codeobj__68); + Py_CLEAR(clear_module_state->__pyx_codeobj__71); + Py_CLEAR(clear_module_state->__pyx_codeobj__73); + Py_CLEAR(clear_module_state->__pyx_codeobj__75); + Py_CLEAR(clear_module_state->__pyx_codeobj__76); + Py_CLEAR(clear_module_state->__pyx_codeobj__77); + Py_CLEAR(clear_module_state->__pyx_codeobj__79); + Py_CLEAR(clear_module_state->__pyx_codeobj__81); + Py_CLEAR(clear_module_state->__pyx_codeobj__83); + Py_CLEAR(clear_module_state->__pyx_codeobj__85); + Py_CLEAR(clear_module_state->__pyx_codeobj__90); + Py_CLEAR(clear_module_state->__pyx_codeobj__93); + Py_CLEAR(clear_module_state->__pyx_codeobj__95); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44_Matrix44); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions); + Py_VISIT(traverse_module_state->__pyx_array_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_array); + Py_VISIT(traverse_module_state->__pyx_MemviewEnum_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_MemviewEnum); + Py_VISIT(traverse_module_state->__pyx_memoryview_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_memoryview); + Py_VISIT(traverse_module_state->__pyx_memoryviewslice_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_memoryviewslice); + Py_VISIT(traverse_module_state->__pyx_kp_u_); + Py_VISIT(traverse_module_state->__pyx_n_s_ASCII); + Py_VISIT(traverse_module_state->__pyx_kp_s_All_dimensions_preceding_dimensi); + Py_VISIT(traverse_module_state->__pyx_n_s_AssertionError); + Py_VISIT(traverse_module_state->__pyx_kp_s_Buffer_view_does_not_expose_stri); + Py_VISIT(traverse_module_state->__pyx_kp_s_Can_only_create_a_buffer_that_is); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_assign_to_read_only_memor); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_create_writable_memory_vi); + Py_VISIT(traverse_module_state->__pyx_kp_u_Cannot_index_with_type); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_transpose_memoryview_with); + Py_VISIT(traverse_module_state->__pyx_kp_s_Dimension_d_is_not_direct); + Py_VISIT(traverse_module_state->__pyx_n_s_Ellipsis); + Py_VISIT(traverse_module_state->__pyx_kp_s_Empty_shape_tuple_for_cython_arr); + Py_VISIT(traverse_module_state->__pyx_kp_u_First_2_columns_of_a_3x3_matrix); + Py_VISIT(traverse_module_state->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0); + Py_VISIT(traverse_module_state->__pyx_n_s_IndexError); + Py_VISIT(traverse_module_state->__pyx_kp_s_Index_out_of_bounds_axis_d); + Py_VISIT(traverse_module_state->__pyx_kp_s_Indirect_dimensions_not_supporte); + Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_mode_expected_c_or_fortr); + Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_shape_in_axis); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterable); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterator); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Tuple_float); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Vec2); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44___iter); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44___reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_axis_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_chain); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_columns); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_copy); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_determinant); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_fast_2d_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_from_2d_transformation); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_get_2d_transformation); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_get_col); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_get_row); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_inverse); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_perspective_projection); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_perspective_projection_2); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_rows); + Py_VISIT(traverse_module_state->__pyx_kp_u_Matrix44_s); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_scale); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_set_col); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_set_row); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_shear_xy); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transform_array_inplace); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transform_direction); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transform_directions); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_translate); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_transpose); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_ucs); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_ucs_direction_from_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_ucs_vertex_from_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_x_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_xyz_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_y_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Matrix44_z_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_MemoryError); + Py_VISIT(traverse_module_state->__pyx_kp_s_MemoryView_of_r_at_0x_x); + Py_VISIT(traverse_module_state->__pyx_kp_s_MemoryView_of_r_object); + Py_VISIT(traverse_module_state->__pyx_n_s_NULLVEC); + Py_VISIT(traverse_module_state->__pyx_n_s_None); + Py_VISIT(traverse_module_state->__pyx_n_b_O); + Py_VISIT(traverse_module_state->__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + Py_VISIT(traverse_module_state->__pyx_n_s_PickleError); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_kp_s_Sequence_float); + Py_VISIT(traverse_module_state->__pyx_kp_s_Step_may_not_be_zero_axis_d); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_n_s_Tuple); + Py_VISIT(traverse_module_state->__pyx_kp_s_Tuple_float); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_kp_s_Unable_to_convert_item_to_object); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_View_MemoryView); + Py_VISIT(traverse_module_state->__pyx_n_s_X_AXIS); + Py_VISIT(traverse_module_state->__pyx_n_s_Y_AXIS); + Py_VISIT(traverse_module_state->__pyx_n_s_Z_AXIS); + Py_VISIT(traverse_module_state->__pyx_kp_u__11); + Py_VISIT(traverse_module_state->__pyx_kp_u__2); + Py_VISIT(traverse_module_state->__pyx_n_s__3); + Py_VISIT(traverse_module_state->__pyx_kp_u__6); + Py_VISIT(traverse_module_state->__pyx_kp_u__7); + Py_VISIT(traverse_module_state->__pyx_n_s__96); + Py_VISIT(traverse_module_state->__pyx_n_s_abc); + Py_VISIT(traverse_module_state->__pyx_n_s_allocate_buffer); + Py_VISIT(traverse_module_state->__pyx_kp_u_and); + Py_VISIT(traverse_module_state->__pyx_n_s_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_x); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_y); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_z); + Py_VISIT(traverse_module_state->__pyx_n_s_args); + Py_VISIT(traverse_module_state->__pyx_n_s_array); + Py_VISIT(traverse_module_state->__pyx_n_s_aspect); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_axis); + Py_VISIT(traverse_module_state->__pyx_n_s_axis_2); + Py_VISIT(traverse_module_state->__pyx_n_s_axis_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_base); + Py_VISIT(traverse_module_state->__pyx_n_s_bottom); + Py_VISIT(traverse_module_state->__pyx_n_s_c); + Py_VISIT(traverse_module_state->__pyx_n_u_c); + Py_VISIT(traverse_module_state->__pyx_n_s_chain); + Py_VISIT(traverse_module_state->__pyx_n_s_class); + Py_VISIT(traverse_module_state->__pyx_n_s_class_getitem); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_close); + Py_VISIT(traverse_module_state->__pyx_n_s_col); + Py_VISIT(traverse_module_state->__pyx_n_s_collections); + Py_VISIT(traverse_module_state->__pyx_kp_s_collections_abc); + Py_VISIT(traverse_module_state->__pyx_n_s_columns); + Py_VISIT(traverse_module_state->__pyx_n_s_columns_locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_components); + Py_VISIT(traverse_module_state->__pyx_kp_s_contiguous_and_direct); + Py_VISIT(traverse_module_state->__pyx_kp_s_contiguous_and_indirect); + Py_VISIT(traverse_module_state->__pyx_n_s_copy); + Py_VISIT(traverse_module_state->__pyx_n_s_copy_2); + Py_VISIT(traverse_module_state->__pyx_n_s_copy_3); + Py_VISIT(traverse_module_state->__pyx_n_s_cos_a); + Py_VISIT(traverse_module_state->__pyx_n_s_count); + Py_VISIT(traverse_module_state->__pyx_n_s_cx); + Py_VISIT(traverse_module_state->__pyx_n_s_cxsy); + Py_VISIT(traverse_module_state->__pyx_n_s_cy); + Py_VISIT(traverse_module_state->__pyx_n_s_cz); + Py_VISIT(traverse_module_state->__pyx_n_s_det); + Py_VISIT(traverse_module_state->__pyx_n_s_determinant); + Py_VISIT(traverse_module_state->__pyx_n_s_dict); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_dtype_is_object); + Py_VISIT(traverse_module_state->__pyx_n_s_dx); + Py_VISIT(traverse_module_state->__pyx_n_s_dy); + Py_VISIT(traverse_module_state->__pyx_n_s_dz); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_encode); + Py_VISIT(traverse_module_state->__pyx_n_s_enumerate); + Py_VISIT(traverse_module_state->__pyx_n_s_error); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_matrix44); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_n_s_f); + Py_VISIT(traverse_module_state->__pyx_n_s_far); + Py_VISIT(traverse_module_state->__pyx_n_s_fast_2d_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_flags); + Py_VISIT(traverse_module_state->__pyx_n_s_float); + Py_VISIT(traverse_module_state->__pyx_n_s_format); + Py_VISIT(traverse_module_state->__pyx_n_s_format_row); + Py_VISIT(traverse_module_state->__pyx_n_s_fortran); + Py_VISIT(traverse_module_state->__pyx_n_u_fortran); + Py_VISIT(traverse_module_state->__pyx_n_s_fov); + Py_VISIT(traverse_module_state->__pyx_n_s_from_2d_transformation); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_get_2d_transformation); + Py_VISIT(traverse_module_state->__pyx_n_s_get_col); + Py_VISIT(traverse_module_state->__pyx_n_s_get_row); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_kp_u_got); + Py_VISIT(traverse_module_state->__pyx_kp_u_got_differing_extents_in_dimensi); + Py_VISIT(traverse_module_state->__pyx_n_s_i); + Py_VISIT(traverse_module_state->__pyx_n_s_id); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_imul); + Py_VISIT(traverse_module_state->__pyx_n_s_index); + Py_VISIT(traverse_module_state->__pyx_kp_u_index_out_of_range); + Py_VISIT(traverse_module_state->__pyx_n_s_initializing); + Py_VISIT(traverse_module_state->__pyx_n_s_int); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_argument_count); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_argument_count_4_row_vec); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_col_index); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_row_index); + Py_VISIT(traverse_module_state->__pyx_n_s_inverse); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_itemsize); + Py_VISIT(traverse_module_state->__pyx_kp_s_itemsize_0_for_cython_array); + Py_VISIT(traverse_module_state->__pyx_n_s_iter); + Py_VISIT(traverse_module_state->__pyx_n_s_itertools); + Py_VISIT(traverse_module_state->__pyx_n_s_left); + Py_VISIT(traverse_module_state->__pyx_n_s_m); + Py_VISIT(traverse_module_state->__pyx_n_s_m0); + Py_VISIT(traverse_module_state->__pyx_n_s_m1); + Py_VISIT(traverse_module_state->__pyx_n_s_m12); + Py_VISIT(traverse_module_state->__pyx_n_s_m13); + Py_VISIT(traverse_module_state->__pyx_n_s_m4); + Py_VISIT(traverse_module_state->__pyx_n_s_m44); + Py_VISIT(traverse_module_state->__pyx_n_s_m5); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_mat); + Py_VISIT(traverse_module_state->__pyx_n_s_math); + Py_VISIT(traverse_module_state->__pyx_n_s_matrices); + Py_VISIT(traverse_module_state->__pyx_n_s_matrix); + Py_VISIT(traverse_module_state->__pyx_n_s_memview); + Py_VISIT(traverse_module_state->__pyx_n_s_mode); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_name_2); + Py_VISIT(traverse_module_state->__pyx_n_s_ndim); + Py_VISIT(traverse_module_state->__pyx_n_s_ndim_2); + Py_VISIT(traverse_module_state->__pyx_kp_u_ndim_has_to_be_2_or_3); + Py_VISIT(traverse_module_state->__pyx_n_s_near); + Py_VISIT(traverse_module_state->__pyx_n_s_new); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_normalize); + Py_VISIT(traverse_module_state->__pyx_n_s_normalize_2); + Py_VISIT(traverse_module_state->__pyx_n_s_np); + Py_VISIT(traverse_module_state->__pyx_kp_s_np_ndarray); + Py_VISIT(traverse_module_state->__pyx_n_s_numpy); + Py_VISIT(traverse_module_state->__pyx_n_s_obj); + Py_VISIT(traverse_module_state->__pyx_n_s_ocs_from_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_ocs_to_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_one_m_cos); + Py_VISIT(traverse_module_state->__pyx_n_s_origin); + Py_VISIT(traverse_module_state->__pyx_n_s_origin_2); + Py_VISIT(traverse_module_state->__pyx_n_s_pack); + Py_VISIT(traverse_module_state->__pyx_n_s_perspective_projection); + Py_VISIT(traverse_module_state->__pyx_n_s_perspective_projection_fov); + Py_VISIT(traverse_module_state->__pyx_n_s_pickle); + Py_VISIT(traverse_module_state->__pyx_n_s_pnt); + Py_VISIT(traverse_module_state->__pyx_n_s_points); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_PickleError); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_checksum); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_result); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_type); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_unpickle_Enum); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_register); + Py_VISIT(traverse_module_state->__pyx_n_s_repr___locals_format_row); + Py_VISIT(traverse_module_state->__pyx_n_s_repr___locals_format_row_local); + Py_VISIT(traverse_module_state->__pyx_n_s_repr___locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_res); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_right); + Py_VISIT(traverse_module_state->__pyx_n_s_row); + Py_VISIT(traverse_module_state->__pyx_n_s_rows); + Py_VISIT(traverse_module_state->__pyx_n_s_rows_locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_kp_u_s); + Py_VISIT(traverse_module_state->__pyx_n_s_scale); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_send); + Py_VISIT(traverse_module_state->__pyx_n_s_set_col); + Py_VISIT(traverse_module_state->__pyx_n_s_set_row); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_shape); + Py_VISIT(traverse_module_state->__pyx_n_s_shear_xy); + Py_VISIT(traverse_module_state->__pyx_n_s_sin_a); + Py_VISIT(traverse_module_state->__pyx_n_s_size); + Py_VISIT(traverse_module_state->__pyx_n_s_spec); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_matrix44_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start); + Py_VISIT(traverse_module_state->__pyx_n_s_staticmethod); + Py_VISIT(traverse_module_state->__pyx_n_s_step); + Py_VISIT(traverse_module_state->__pyx_n_s_stop); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_direct); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_direct_or_indirect); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_indirect); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_struct); + Py_VISIT(traverse_module_state->__pyx_n_s_sx); + Py_VISIT(traverse_module_state->__pyx_n_s_sxsy); + Py_VISIT(traverse_module_state->__pyx_n_s_sy); + Py_VISIT(traverse_module_state->__pyx_n_s_sys); + Py_VISIT(traverse_module_state->__pyx_n_s_sz); + Py_VISIT(traverse_module_state->__pyx_n_s_tan); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_throw); + Py_VISIT(traverse_module_state->__pyx_n_s_top); + Py_VISIT(traverse_module_state->__pyx_n_s_transform); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_array_inplace); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_direction); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_directions); + Py_VISIT(traverse_module_state->__pyx_n_s_transform_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_transformation); + Py_VISIT(traverse_module_state->__pyx_n_s_translate); + Py_VISIT(traverse_module_state->__pyx_n_s_transpose); + Py_VISIT(traverse_module_state->__pyx_n_s_tx); + Py_VISIT(traverse_module_state->__pyx_n_s_ty); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_ucs); + Py_VISIT(traverse_module_state->__pyx_n_s_ucs_direction_from_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_ucs_vertex_from_wcs); + Py_VISIT(traverse_module_state->__pyx_kp_s_unable_to_allocate_array_data); + Py_VISIT(traverse_module_state->__pyx_kp_s_unable_to_allocate_shape_and_str); + Py_VISIT(traverse_module_state->__pyx_n_s_unpack); + Py_VISIT(traverse_module_state->__pyx_n_s_update); + Py_VISIT(traverse_module_state->__pyx_n_s_ux); + Py_VISIT(traverse_module_state->__pyx_n_s_ux_2); + Py_VISIT(traverse_module_state->__pyx_n_s_uy); + Py_VISIT(traverse_module_state->__pyx_n_s_uy_2); + Py_VISIT(traverse_module_state->__pyx_n_s_uz); + Py_VISIT(traverse_module_state->__pyx_n_s_uz_2); + Py_VISIT(traverse_module_state->__pyx_n_s_values); + Py_VISIT(traverse_module_state->__pyx_n_s_vector); + Py_VISIT(traverse_module_state->__pyx_n_s_vectors); + Py_VISIT(traverse_module_state->__pyx_n_s_version_info); + Py_VISIT(traverse_module_state->__pyx_n_s_vrange); + Py_VISIT(traverse_module_state->__pyx_n_s_wcs); + Py_VISIT(traverse_module_state->__pyx_n_s_x); + Py_VISIT(traverse_module_state->__pyx_n_s_x_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_xyz_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_y); + Py_VISIT(traverse_module_state->__pyx_n_s_y_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_z); + Py_VISIT(traverse_module_state->__pyx_n_s_z_rotate); + Py_VISIT(traverse_module_state->__pyx_float_0_0); + Py_VISIT(traverse_module_state->__pyx_float_1_0); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_1); + Py_VISIT(traverse_module_state->__pyx_int_2); + Py_VISIT(traverse_module_state->__pyx_int_3); + Py_VISIT(traverse_module_state->__pyx_int_112105877); + Py_VISIT(traverse_module_state->__pyx_int_136983863); + Py_VISIT(traverse_module_state->__pyx_int_184977713); + Py_VISIT(traverse_module_state->__pyx_int_neg_1); + Py_VISIT(traverse_module_state->__pyx_k__16); + Py_VISIT(traverse_module_state->__pyx_k__17); + Py_VISIT(traverse_module_state->__pyx_k__18); + Py_VISIT(traverse_module_state->__pyx_k__19); + Py_VISIT(traverse_module_state->__pyx_slice__5); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__8); + Py_VISIT(traverse_module_state->__pyx_tuple__9); + Py_VISIT(traverse_module_state->__pyx_tuple__10); + Py_VISIT(traverse_module_state->__pyx_tuple__12); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__15); + Py_VISIT(traverse_module_state->__pyx_tuple__22); + Py_VISIT(traverse_module_state->__pyx_tuple__24); + Py_VISIT(traverse_module_state->__pyx_tuple__25); + Py_VISIT(traverse_module_state->__pyx_tuple__26); + Py_VISIT(traverse_module_state->__pyx_tuple__27); + Py_VISIT(traverse_module_state->__pyx_tuple__28); + Py_VISIT(traverse_module_state->__pyx_tuple__29); + Py_VISIT(traverse_module_state->__pyx_tuple__30); + Py_VISIT(traverse_module_state->__pyx_tuple__31); + Py_VISIT(traverse_module_state->__pyx_tuple__32); + Py_VISIT(traverse_module_state->__pyx_tuple__33); + Py_VISIT(traverse_module_state->__pyx_tuple__35); + Py_VISIT(traverse_module_state->__pyx_tuple__37); + Py_VISIT(traverse_module_state->__pyx_tuple__39); + Py_VISIT(traverse_module_state->__pyx_tuple__41); + Py_VISIT(traverse_module_state->__pyx_tuple__43); + Py_VISIT(traverse_module_state->__pyx_tuple__45); + Py_VISIT(traverse_module_state->__pyx_tuple__47); + Py_VISIT(traverse_module_state->__pyx_tuple__49); + Py_VISIT(traverse_module_state->__pyx_tuple__52); + Py_VISIT(traverse_module_state->__pyx_tuple__54); + Py_VISIT(traverse_module_state->__pyx_tuple__56); + Py_VISIT(traverse_module_state->__pyx_tuple__57); + Py_VISIT(traverse_module_state->__pyx_tuple__59); + Py_VISIT(traverse_module_state->__pyx_tuple__63); + Py_VISIT(traverse_module_state->__pyx_tuple__65); + Py_VISIT(traverse_module_state->__pyx_tuple__67); + Py_VISIT(traverse_module_state->__pyx_tuple__69); + Py_VISIT(traverse_module_state->__pyx_tuple__70); + Py_VISIT(traverse_module_state->__pyx_tuple__72); + Py_VISIT(traverse_module_state->__pyx_tuple__74); + Py_VISIT(traverse_module_state->__pyx_tuple__78); + Py_VISIT(traverse_module_state->__pyx_tuple__80); + Py_VISIT(traverse_module_state->__pyx_tuple__82); + Py_VISIT(traverse_module_state->__pyx_tuple__84); + Py_VISIT(traverse_module_state->__pyx_tuple__86); + Py_VISIT(traverse_module_state->__pyx_tuple__87); + Py_VISIT(traverse_module_state->__pyx_tuple__88); + Py_VISIT(traverse_module_state->__pyx_tuple__89); + Py_VISIT(traverse_module_state->__pyx_tuple__91); + Py_VISIT(traverse_module_state->__pyx_tuple__92); + Py_VISIT(traverse_module_state->__pyx_tuple__94); + Py_VISIT(traverse_module_state->__pyx_codeobj__13); + Py_VISIT(traverse_module_state->__pyx_codeobj__20); + Py_VISIT(traverse_module_state->__pyx_codeobj__21); + Py_VISIT(traverse_module_state->__pyx_codeobj__23); + Py_VISIT(traverse_module_state->__pyx_codeobj__34); + Py_VISIT(traverse_module_state->__pyx_codeobj__36); + Py_VISIT(traverse_module_state->__pyx_codeobj__38); + Py_VISIT(traverse_module_state->__pyx_codeobj__40); + Py_VISIT(traverse_module_state->__pyx_codeobj__42); + Py_VISIT(traverse_module_state->__pyx_codeobj__44); + Py_VISIT(traverse_module_state->__pyx_codeobj__46); + Py_VISIT(traverse_module_state->__pyx_codeobj__48); + Py_VISIT(traverse_module_state->__pyx_codeobj__50); + Py_VISIT(traverse_module_state->__pyx_codeobj__51); + Py_VISIT(traverse_module_state->__pyx_codeobj__53); + Py_VISIT(traverse_module_state->__pyx_codeobj__55); + Py_VISIT(traverse_module_state->__pyx_codeobj__58); + Py_VISIT(traverse_module_state->__pyx_codeobj__60); + Py_VISIT(traverse_module_state->__pyx_codeobj__61); + Py_VISIT(traverse_module_state->__pyx_codeobj__62); + Py_VISIT(traverse_module_state->__pyx_codeobj__64); + Py_VISIT(traverse_module_state->__pyx_codeobj__66); + Py_VISIT(traverse_module_state->__pyx_codeobj__68); + Py_VISIT(traverse_module_state->__pyx_codeobj__71); + Py_VISIT(traverse_module_state->__pyx_codeobj__73); + Py_VISIT(traverse_module_state->__pyx_codeobj__75); + Py_VISIT(traverse_module_state->__pyx_codeobj__76); + Py_VISIT(traverse_module_state->__pyx_codeobj__77); + Py_VISIT(traverse_module_state->__pyx_codeobj__79); + Py_VISIT(traverse_module_state->__pyx_codeobj__81); + Py_VISIT(traverse_module_state->__pyx_codeobj__83); + Py_VISIT(traverse_module_state->__pyx_codeobj__85); + Py_VISIT(traverse_module_state->__pyx_codeobj__90); + Py_VISIT(traverse_module_state->__pyx_codeobj__93); + Py_VISIT(traverse_module_state->__pyx_codeobj__95); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_8matrix44_Matrix44 __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44_Matrix44 +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform +#define __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions __pyx_mstate_global->__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions +#define __pyx_type___pyx_array __pyx_mstate_global->__pyx_type___pyx_array +#define __pyx_type___pyx_MemviewEnum __pyx_mstate_global->__pyx_type___pyx_MemviewEnum +#define __pyx_type___pyx_memoryview __pyx_mstate_global->__pyx_type___pyx_memoryview +#define __pyx_type___pyx_memoryviewslice __pyx_mstate_global->__pyx_type___pyx_memoryviewslice +#endif +#define __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform +#define __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions +#define __pyx_array_type __pyx_mstate_global->__pyx_array_type +#define __pyx_MemviewEnum_type __pyx_mstate_global->__pyx_MemviewEnum_type +#define __pyx_memoryview_type __pyx_mstate_global->__pyx_memoryview_type +#define __pyx_memoryviewslice_type __pyx_mstate_global->__pyx_memoryviewslice_type +#define __pyx_kp_u_ __pyx_mstate_global->__pyx_kp_u_ +#define __pyx_n_s_ASCII __pyx_mstate_global->__pyx_n_s_ASCII +#define __pyx_kp_s_All_dimensions_preceding_dimensi __pyx_mstate_global->__pyx_kp_s_All_dimensions_preceding_dimensi +#define __pyx_n_s_AssertionError __pyx_mstate_global->__pyx_n_s_AssertionError +#define __pyx_kp_s_Buffer_view_does_not_expose_stri __pyx_mstate_global->__pyx_kp_s_Buffer_view_does_not_expose_stri +#define __pyx_kp_s_Can_only_create_a_buffer_that_is __pyx_mstate_global->__pyx_kp_s_Can_only_create_a_buffer_that_is +#define __pyx_kp_s_Cannot_assign_to_read_only_memor __pyx_mstate_global->__pyx_kp_s_Cannot_assign_to_read_only_memor +#define __pyx_kp_s_Cannot_create_writable_memory_vi __pyx_mstate_global->__pyx_kp_s_Cannot_create_writable_memory_vi +#define __pyx_kp_u_Cannot_index_with_type __pyx_mstate_global->__pyx_kp_u_Cannot_index_with_type +#define __pyx_kp_s_Cannot_transpose_memoryview_with __pyx_mstate_global->__pyx_kp_s_Cannot_transpose_memoryview_with +#define __pyx_kp_s_Dimension_d_is_not_direct __pyx_mstate_global->__pyx_kp_s_Dimension_d_is_not_direct +#define __pyx_n_s_Ellipsis __pyx_mstate_global->__pyx_n_s_Ellipsis +#define __pyx_kp_s_Empty_shape_tuple_for_cython_arr __pyx_mstate_global->__pyx_kp_s_Empty_shape_tuple_for_cython_arr +#define __pyx_kp_u_First_2_columns_of_a_3x3_matrix __pyx_mstate_global->__pyx_kp_u_First_2_columns_of_a_3x3_matrix +#define __pyx_kp_s_Incompatible_checksums_0x_x_vs_0 __pyx_mstate_global->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0 +#define __pyx_n_s_IndexError __pyx_mstate_global->__pyx_n_s_IndexError +#define __pyx_kp_s_Index_out_of_bounds_axis_d __pyx_mstate_global->__pyx_kp_s_Index_out_of_bounds_axis_d +#define __pyx_kp_s_Indirect_dimensions_not_supporte __pyx_mstate_global->__pyx_kp_s_Indirect_dimensions_not_supporte +#define __pyx_kp_u_Invalid_mode_expected_c_or_fortr __pyx_mstate_global->__pyx_kp_u_Invalid_mode_expected_c_or_fortr +#define __pyx_kp_u_Invalid_shape_in_axis __pyx_mstate_global->__pyx_kp_u_Invalid_shape_in_axis +#define __pyx_n_s_Iterable __pyx_mstate_global->__pyx_n_s_Iterable +#define __pyx_kp_s_Iterable_UVec __pyx_mstate_global->__pyx_kp_s_Iterable_UVec +#define __pyx_n_s_Iterator __pyx_mstate_global->__pyx_n_s_Iterator +#define __pyx_kp_s_Iterator_Tuple_float __pyx_mstate_global->__pyx_kp_s_Iterator_Tuple_float +#define __pyx_kp_s_Iterator_Vec2 __pyx_mstate_global->__pyx_kp_s_Iterator_Vec2 +#define __pyx_kp_s_Iterator_Vec3 __pyx_mstate_global->__pyx_kp_s_Iterator_Vec3 +#define __pyx_n_s_Matrix44 __pyx_mstate_global->__pyx_n_s_Matrix44 +#define __pyx_n_s_Matrix44___iter __pyx_mstate_global->__pyx_n_s_Matrix44___iter +#define __pyx_n_s_Matrix44___reduce __pyx_mstate_global->__pyx_n_s_Matrix44___reduce +#define __pyx_n_s_Matrix44_axis_rotate __pyx_mstate_global->__pyx_n_s_Matrix44_axis_rotate +#define __pyx_n_s_Matrix44_chain __pyx_mstate_global->__pyx_n_s_Matrix44_chain +#define __pyx_n_s_Matrix44_columns __pyx_mstate_global->__pyx_n_s_Matrix44_columns +#define __pyx_n_s_Matrix44_copy __pyx_mstate_global->__pyx_n_s_Matrix44_copy +#define __pyx_n_s_Matrix44_determinant __pyx_mstate_global->__pyx_n_s_Matrix44_determinant +#define __pyx_n_s_Matrix44_fast_2d_transform __pyx_mstate_global->__pyx_n_s_Matrix44_fast_2d_transform +#define __pyx_n_s_Matrix44_from_2d_transformation __pyx_mstate_global->__pyx_n_s_Matrix44_from_2d_transformation +#define __pyx_n_s_Matrix44_get_2d_transformation __pyx_mstate_global->__pyx_n_s_Matrix44_get_2d_transformation +#define __pyx_n_s_Matrix44_get_col __pyx_mstate_global->__pyx_n_s_Matrix44_get_col +#define __pyx_n_s_Matrix44_get_row __pyx_mstate_global->__pyx_n_s_Matrix44_get_row +#define __pyx_n_s_Matrix44_inverse __pyx_mstate_global->__pyx_n_s_Matrix44_inverse +#define __pyx_n_s_Matrix44_perspective_projection __pyx_mstate_global->__pyx_n_s_Matrix44_perspective_projection +#define __pyx_n_s_Matrix44_perspective_projection_2 __pyx_mstate_global->__pyx_n_s_Matrix44_perspective_projection_2 +#define __pyx_n_s_Matrix44_rows __pyx_mstate_global->__pyx_n_s_Matrix44_rows +#define __pyx_kp_u_Matrix44_s __pyx_mstate_global->__pyx_kp_u_Matrix44_s +#define __pyx_n_s_Matrix44_scale __pyx_mstate_global->__pyx_n_s_Matrix44_scale +#define __pyx_n_s_Matrix44_set_col __pyx_mstate_global->__pyx_n_s_Matrix44_set_col +#define __pyx_n_s_Matrix44_set_row __pyx_mstate_global->__pyx_n_s_Matrix44_set_row +#define __pyx_n_s_Matrix44_shear_xy __pyx_mstate_global->__pyx_n_s_Matrix44_shear_xy +#define __pyx_n_s_Matrix44_transform __pyx_mstate_global->__pyx_n_s_Matrix44_transform +#define __pyx_n_s_Matrix44_transform_array_inplace __pyx_mstate_global->__pyx_n_s_Matrix44_transform_array_inplace +#define __pyx_n_s_Matrix44_transform_direction __pyx_mstate_global->__pyx_n_s_Matrix44_transform_direction +#define __pyx_n_s_Matrix44_transform_directions __pyx_mstate_global->__pyx_n_s_Matrix44_transform_directions +#define __pyx_n_s_Matrix44_transform_vertices __pyx_mstate_global->__pyx_n_s_Matrix44_transform_vertices +#define __pyx_n_s_Matrix44_translate __pyx_mstate_global->__pyx_n_s_Matrix44_translate +#define __pyx_n_s_Matrix44_transpose __pyx_mstate_global->__pyx_n_s_Matrix44_transpose +#define __pyx_n_s_Matrix44_ucs __pyx_mstate_global->__pyx_n_s_Matrix44_ucs +#define __pyx_n_s_Matrix44_ucs_direction_from_wcs __pyx_mstate_global->__pyx_n_s_Matrix44_ucs_direction_from_wcs +#define __pyx_n_s_Matrix44_ucs_vertex_from_wcs __pyx_mstate_global->__pyx_n_s_Matrix44_ucs_vertex_from_wcs +#define __pyx_n_s_Matrix44_x_rotate __pyx_mstate_global->__pyx_n_s_Matrix44_x_rotate +#define __pyx_n_s_Matrix44_xyz_rotate __pyx_mstate_global->__pyx_n_s_Matrix44_xyz_rotate +#define __pyx_n_s_Matrix44_y_rotate __pyx_mstate_global->__pyx_n_s_Matrix44_y_rotate +#define __pyx_n_s_Matrix44_z_rotate __pyx_mstate_global->__pyx_n_s_Matrix44_z_rotate +#define __pyx_n_s_MemoryError __pyx_mstate_global->__pyx_n_s_MemoryError +#define __pyx_kp_s_MemoryView_of_r_at_0x_x __pyx_mstate_global->__pyx_kp_s_MemoryView_of_r_at_0x_x +#define __pyx_kp_s_MemoryView_of_r_object __pyx_mstate_global->__pyx_kp_s_MemoryView_of_r_object +#define __pyx_n_s_NULLVEC __pyx_mstate_global->__pyx_n_s_NULLVEC +#define __pyx_n_s_None __pyx_mstate_global->__pyx_n_s_None +#define __pyx_n_b_O __pyx_mstate_global->__pyx_n_b_O +#define __pyx_kp_u_Out_of_bounds_on_buffer_access_a __pyx_mstate_global->__pyx_kp_u_Out_of_bounds_on_buffer_access_a +#define __pyx_n_s_PickleError __pyx_mstate_global->__pyx_n_s_PickleError +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_kp_s_Sequence_float __pyx_mstate_global->__pyx_kp_s_Sequence_float +#define __pyx_kp_s_Step_may_not_be_zero_axis_d __pyx_mstate_global->__pyx_kp_s_Step_may_not_be_zero_axis_d +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_n_s_Tuple __pyx_mstate_global->__pyx_n_s_Tuple +#define __pyx_kp_s_Tuple_float __pyx_mstate_global->__pyx_kp_s_Tuple_float +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_kp_s_Unable_to_convert_item_to_object __pyx_mstate_global->__pyx_kp_s_Unable_to_convert_item_to_object +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s_Vec3 __pyx_mstate_global->__pyx_n_s_Vec3 +#define __pyx_n_s_View_MemoryView __pyx_mstate_global->__pyx_n_s_View_MemoryView +#define __pyx_n_s_X_AXIS __pyx_mstate_global->__pyx_n_s_X_AXIS +#define __pyx_n_s_Y_AXIS __pyx_mstate_global->__pyx_n_s_Y_AXIS +#define __pyx_n_s_Z_AXIS __pyx_mstate_global->__pyx_n_s_Z_AXIS +#define __pyx_kp_u__11 __pyx_mstate_global->__pyx_kp_u__11 +#define __pyx_kp_u__2 __pyx_mstate_global->__pyx_kp_u__2 +#define __pyx_n_s__3 __pyx_mstate_global->__pyx_n_s__3 +#define __pyx_kp_u__6 __pyx_mstate_global->__pyx_kp_u__6 +#define __pyx_kp_u__7 __pyx_mstate_global->__pyx_kp_u__7 +#define __pyx_n_s__96 __pyx_mstate_global->__pyx_n_s__96 +#define __pyx_n_s_abc __pyx_mstate_global->__pyx_n_s_abc +#define __pyx_n_s_allocate_buffer __pyx_mstate_global->__pyx_n_s_allocate_buffer +#define __pyx_kp_u_and __pyx_mstate_global->__pyx_kp_u_and +#define __pyx_n_s_angle __pyx_mstate_global->__pyx_n_s_angle +#define __pyx_n_s_angle_x __pyx_mstate_global->__pyx_n_s_angle_x +#define __pyx_n_s_angle_y __pyx_mstate_global->__pyx_n_s_angle_y +#define __pyx_n_s_angle_z __pyx_mstate_global->__pyx_n_s_angle_z +#define __pyx_n_s_args __pyx_mstate_global->__pyx_n_s_args +#define __pyx_n_s_array __pyx_mstate_global->__pyx_n_s_array +#define __pyx_n_s_aspect __pyx_mstate_global->__pyx_n_s_aspect +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_axis __pyx_mstate_global->__pyx_n_s_axis +#define __pyx_n_s_axis_2 __pyx_mstate_global->__pyx_n_s_axis_2 +#define __pyx_n_s_axis_rotate __pyx_mstate_global->__pyx_n_s_axis_rotate +#define __pyx_n_s_base __pyx_mstate_global->__pyx_n_s_base +#define __pyx_n_s_bottom __pyx_mstate_global->__pyx_n_s_bottom +#define __pyx_n_s_c __pyx_mstate_global->__pyx_n_s_c +#define __pyx_n_u_c __pyx_mstate_global->__pyx_n_u_c +#define __pyx_n_s_chain __pyx_mstate_global->__pyx_n_s_chain +#define __pyx_n_s_class __pyx_mstate_global->__pyx_n_s_class +#define __pyx_n_s_class_getitem __pyx_mstate_global->__pyx_n_s_class_getitem +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_close __pyx_mstate_global->__pyx_n_s_close +#define __pyx_n_s_col __pyx_mstate_global->__pyx_n_s_col +#define __pyx_n_s_collections __pyx_mstate_global->__pyx_n_s_collections +#define __pyx_kp_s_collections_abc __pyx_mstate_global->__pyx_kp_s_collections_abc +#define __pyx_n_s_columns __pyx_mstate_global->__pyx_n_s_columns +#define __pyx_n_s_columns_locals_genexpr __pyx_mstate_global->__pyx_n_s_columns_locals_genexpr +#define __pyx_n_s_components __pyx_mstate_global->__pyx_n_s_components +#define __pyx_kp_s_contiguous_and_direct __pyx_mstate_global->__pyx_kp_s_contiguous_and_direct +#define __pyx_kp_s_contiguous_and_indirect __pyx_mstate_global->__pyx_kp_s_contiguous_and_indirect +#define __pyx_n_s_copy __pyx_mstate_global->__pyx_n_s_copy +#define __pyx_n_s_copy_2 __pyx_mstate_global->__pyx_n_s_copy_2 +#define __pyx_n_s_copy_3 __pyx_mstate_global->__pyx_n_s_copy_3 +#define __pyx_n_s_cos_a __pyx_mstate_global->__pyx_n_s_cos_a +#define __pyx_n_s_count __pyx_mstate_global->__pyx_n_s_count +#define __pyx_n_s_cx __pyx_mstate_global->__pyx_n_s_cx +#define __pyx_n_s_cxsy __pyx_mstate_global->__pyx_n_s_cxsy +#define __pyx_n_s_cy __pyx_mstate_global->__pyx_n_s_cy +#define __pyx_n_s_cz __pyx_mstate_global->__pyx_n_s_cz +#define __pyx_n_s_det __pyx_mstate_global->__pyx_n_s_det +#define __pyx_n_s_determinant __pyx_mstate_global->__pyx_n_s_determinant +#define __pyx_n_s_dict __pyx_mstate_global->__pyx_n_s_dict +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_dtype_is_object __pyx_mstate_global->__pyx_n_s_dtype_is_object +#define __pyx_n_s_dx __pyx_mstate_global->__pyx_n_s_dx +#define __pyx_n_s_dy __pyx_mstate_global->__pyx_n_s_dy +#define __pyx_n_s_dz __pyx_mstate_global->__pyx_n_s_dz +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_encode __pyx_mstate_global->__pyx_n_s_encode +#define __pyx_n_s_enumerate __pyx_mstate_global->__pyx_n_s_enumerate +#define __pyx_n_s_error __pyx_mstate_global->__pyx_n_s_error +#define __pyx_n_s_ezdxf_acc_matrix44 __pyx_mstate_global->__pyx_n_s_ezdxf_acc_matrix44 +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_n_s_f __pyx_mstate_global->__pyx_n_s_f +#define __pyx_n_s_far __pyx_mstate_global->__pyx_n_s_far +#define __pyx_n_s_fast_2d_transform __pyx_mstate_global->__pyx_n_s_fast_2d_transform +#define __pyx_n_s_flags __pyx_mstate_global->__pyx_n_s_flags +#define __pyx_n_s_float __pyx_mstate_global->__pyx_n_s_float +#define __pyx_n_s_format __pyx_mstate_global->__pyx_n_s_format +#define __pyx_n_s_format_row __pyx_mstate_global->__pyx_n_s_format_row +#define __pyx_n_s_fortran __pyx_mstate_global->__pyx_n_s_fortran +#define __pyx_n_u_fortran __pyx_mstate_global->__pyx_n_u_fortran +#define __pyx_n_s_fov __pyx_mstate_global->__pyx_n_s_fov +#define __pyx_n_s_from_2d_transformation __pyx_mstate_global->__pyx_n_s_from_2d_transformation +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_genexpr __pyx_mstate_global->__pyx_n_s_genexpr +#define __pyx_n_s_get_2d_transformation __pyx_mstate_global->__pyx_n_s_get_2d_transformation +#define __pyx_n_s_get_col __pyx_mstate_global->__pyx_n_s_get_col +#define __pyx_n_s_get_row __pyx_mstate_global->__pyx_n_s_get_row +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_kp_u_got __pyx_mstate_global->__pyx_kp_u_got +#define __pyx_kp_u_got_differing_extents_in_dimensi __pyx_mstate_global->__pyx_kp_u_got_differing_extents_in_dimensi +#define __pyx_n_s_i __pyx_mstate_global->__pyx_n_s_i +#define __pyx_n_s_id __pyx_mstate_global->__pyx_n_s_id +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_imul __pyx_mstate_global->__pyx_n_s_imul +#define __pyx_n_s_index __pyx_mstate_global->__pyx_n_s_index +#define __pyx_kp_u_index_out_of_range __pyx_mstate_global->__pyx_kp_u_index_out_of_range +#define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing +#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int +#define __pyx_kp_u_invalid_argument_count __pyx_mstate_global->__pyx_kp_u_invalid_argument_count +#define __pyx_kp_u_invalid_argument_count_4_row_vec __pyx_mstate_global->__pyx_kp_u_invalid_argument_count_4_row_vec +#define __pyx_kp_u_invalid_col_index __pyx_mstate_global->__pyx_kp_u_invalid_col_index +#define __pyx_kp_u_invalid_row_index __pyx_mstate_global->__pyx_kp_u_invalid_row_index +#define __pyx_n_s_inverse __pyx_mstate_global->__pyx_n_s_inverse +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_itemsize __pyx_mstate_global->__pyx_n_s_itemsize +#define __pyx_kp_s_itemsize_0_for_cython_array __pyx_mstate_global->__pyx_kp_s_itemsize_0_for_cython_array +#define __pyx_n_s_iter __pyx_mstate_global->__pyx_n_s_iter +#define __pyx_n_s_itertools __pyx_mstate_global->__pyx_n_s_itertools +#define __pyx_n_s_left __pyx_mstate_global->__pyx_n_s_left +#define __pyx_n_s_m __pyx_mstate_global->__pyx_n_s_m +#define __pyx_n_s_m0 __pyx_mstate_global->__pyx_n_s_m0 +#define __pyx_n_s_m1 __pyx_mstate_global->__pyx_n_s_m1 +#define __pyx_n_s_m12 __pyx_mstate_global->__pyx_n_s_m12 +#define __pyx_n_s_m13 __pyx_mstate_global->__pyx_n_s_m13 +#define __pyx_n_s_m4 __pyx_mstate_global->__pyx_n_s_m4 +#define __pyx_n_s_m44 __pyx_mstate_global->__pyx_n_s_m44 +#define __pyx_n_s_m5 __pyx_mstate_global->__pyx_n_s_m5 +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_mat __pyx_mstate_global->__pyx_n_s_mat +#define __pyx_n_s_math __pyx_mstate_global->__pyx_n_s_math +#define __pyx_n_s_matrices __pyx_mstate_global->__pyx_n_s_matrices +#define __pyx_n_s_matrix __pyx_mstate_global->__pyx_n_s_matrix +#define __pyx_n_s_memview __pyx_mstate_global->__pyx_n_s_memview +#define __pyx_n_s_mode __pyx_mstate_global->__pyx_n_s_mode +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_name_2 __pyx_mstate_global->__pyx_n_s_name_2 +#define __pyx_n_s_ndim __pyx_mstate_global->__pyx_n_s_ndim +#define __pyx_n_s_ndim_2 __pyx_mstate_global->__pyx_n_s_ndim_2 +#define __pyx_kp_u_ndim_has_to_be_2_or_3 __pyx_mstate_global->__pyx_kp_u_ndim_has_to_be_2_or_3 +#define __pyx_n_s_near __pyx_mstate_global->__pyx_n_s_near +#define __pyx_n_s_new __pyx_mstate_global->__pyx_n_s_new +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_normalize __pyx_mstate_global->__pyx_n_s_normalize +#define __pyx_n_s_normalize_2 __pyx_mstate_global->__pyx_n_s_normalize_2 +#define __pyx_n_s_np __pyx_mstate_global->__pyx_n_s_np +#define __pyx_kp_s_np_ndarray __pyx_mstate_global->__pyx_kp_s_np_ndarray +#define __pyx_n_s_numpy __pyx_mstate_global->__pyx_n_s_numpy +#define __pyx_n_s_obj __pyx_mstate_global->__pyx_n_s_obj +#define __pyx_n_s_ocs_from_wcs __pyx_mstate_global->__pyx_n_s_ocs_from_wcs +#define __pyx_n_s_ocs_to_wcs __pyx_mstate_global->__pyx_n_s_ocs_to_wcs +#define __pyx_n_s_one_m_cos __pyx_mstate_global->__pyx_n_s_one_m_cos +#define __pyx_n_s_origin __pyx_mstate_global->__pyx_n_s_origin +#define __pyx_n_s_origin_2 __pyx_mstate_global->__pyx_n_s_origin_2 +#define __pyx_n_s_pack __pyx_mstate_global->__pyx_n_s_pack +#define __pyx_n_s_perspective_projection __pyx_mstate_global->__pyx_n_s_perspective_projection +#define __pyx_n_s_perspective_projection_fov __pyx_mstate_global->__pyx_n_s_perspective_projection_fov +#define __pyx_n_s_pickle __pyx_mstate_global->__pyx_n_s_pickle +#define __pyx_n_s_pnt __pyx_mstate_global->__pyx_n_s_pnt +#define __pyx_n_s_points __pyx_mstate_global->__pyx_n_s_points +#define __pyx_n_s_pyx_PickleError __pyx_mstate_global->__pyx_n_s_pyx_PickleError +#define __pyx_n_s_pyx_checksum __pyx_mstate_global->__pyx_n_s_pyx_checksum +#define __pyx_n_s_pyx_result __pyx_mstate_global->__pyx_n_s_pyx_result +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_type __pyx_mstate_global->__pyx_n_s_pyx_type +#define __pyx_n_s_pyx_unpickle_Enum __pyx_mstate_global->__pyx_n_s_pyx_unpickle_Enum +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_register __pyx_mstate_global->__pyx_n_s_register +#define __pyx_n_s_repr___locals_format_row __pyx_mstate_global->__pyx_n_s_repr___locals_format_row +#define __pyx_n_s_repr___locals_format_row_local __pyx_mstate_global->__pyx_n_s_repr___locals_format_row_local +#define __pyx_n_s_repr___locals_genexpr __pyx_mstate_global->__pyx_n_s_repr___locals_genexpr +#define __pyx_n_s_res __pyx_mstate_global->__pyx_n_s_res +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_right __pyx_mstate_global->__pyx_n_s_right +#define __pyx_n_s_row __pyx_mstate_global->__pyx_n_s_row +#define __pyx_n_s_rows __pyx_mstate_global->__pyx_n_s_rows +#define __pyx_n_s_rows_locals_genexpr __pyx_mstate_global->__pyx_n_s_rows_locals_genexpr +#define __pyx_kp_u_s __pyx_mstate_global->__pyx_kp_u_s +#define __pyx_n_s_scale __pyx_mstate_global->__pyx_n_s_scale +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_send __pyx_mstate_global->__pyx_n_s_send +#define __pyx_n_s_set_col __pyx_mstate_global->__pyx_n_s_set_col +#define __pyx_n_s_set_row __pyx_mstate_global->__pyx_n_s_set_row +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_shape __pyx_mstate_global->__pyx_n_s_shape +#define __pyx_n_s_shear_xy __pyx_mstate_global->__pyx_n_s_shear_xy +#define __pyx_n_s_sin_a __pyx_mstate_global->__pyx_n_s_sin_a +#define __pyx_n_s_size __pyx_mstate_global->__pyx_n_s_size +#define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec +#define __pyx_kp_s_src_ezdxf_acc_matrix44_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_matrix44_pyx +#define __pyx_n_s_start __pyx_mstate_global->__pyx_n_s_start +#define __pyx_n_s_staticmethod __pyx_mstate_global->__pyx_n_s_staticmethod +#define __pyx_n_s_step __pyx_mstate_global->__pyx_n_s_step +#define __pyx_n_s_stop __pyx_mstate_global->__pyx_n_s_stop +#define __pyx_kp_s_strided_and_direct __pyx_mstate_global->__pyx_kp_s_strided_and_direct +#define __pyx_kp_s_strided_and_direct_or_indirect __pyx_mstate_global->__pyx_kp_s_strided_and_direct_or_indirect +#define __pyx_kp_s_strided_and_indirect __pyx_mstate_global->__pyx_kp_s_strided_and_indirect +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_struct __pyx_mstate_global->__pyx_n_s_struct +#define __pyx_n_s_sx __pyx_mstate_global->__pyx_n_s_sx +#define __pyx_n_s_sxsy __pyx_mstate_global->__pyx_n_s_sxsy +#define __pyx_n_s_sy __pyx_mstate_global->__pyx_n_s_sy +#define __pyx_n_s_sys __pyx_mstate_global->__pyx_n_s_sys +#define __pyx_n_s_sz __pyx_mstate_global->__pyx_n_s_sz +#define __pyx_n_s_tan __pyx_mstate_global->__pyx_n_s_tan +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_throw __pyx_mstate_global->__pyx_n_s_throw +#define __pyx_n_s_top __pyx_mstate_global->__pyx_n_s_top +#define __pyx_n_s_transform __pyx_mstate_global->__pyx_n_s_transform +#define __pyx_n_s_transform_array_inplace __pyx_mstate_global->__pyx_n_s_transform_array_inplace +#define __pyx_n_s_transform_direction __pyx_mstate_global->__pyx_n_s_transform_direction +#define __pyx_n_s_transform_directions __pyx_mstate_global->__pyx_n_s_transform_directions +#define __pyx_n_s_transform_vertices __pyx_mstate_global->__pyx_n_s_transform_vertices +#define __pyx_n_s_transformation __pyx_mstate_global->__pyx_n_s_transformation +#define __pyx_n_s_translate __pyx_mstate_global->__pyx_n_s_translate +#define __pyx_n_s_transpose __pyx_mstate_global->__pyx_n_s_transpose +#define __pyx_n_s_tx __pyx_mstate_global->__pyx_n_s_tx +#define __pyx_n_s_ty __pyx_mstate_global->__pyx_n_s_ty +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_ucs __pyx_mstate_global->__pyx_n_s_ucs +#define __pyx_n_s_ucs_direction_from_wcs __pyx_mstate_global->__pyx_n_s_ucs_direction_from_wcs +#define __pyx_n_s_ucs_vertex_from_wcs __pyx_mstate_global->__pyx_n_s_ucs_vertex_from_wcs +#define __pyx_kp_s_unable_to_allocate_array_data __pyx_mstate_global->__pyx_kp_s_unable_to_allocate_array_data +#define __pyx_kp_s_unable_to_allocate_shape_and_str __pyx_mstate_global->__pyx_kp_s_unable_to_allocate_shape_and_str +#define __pyx_n_s_unpack __pyx_mstate_global->__pyx_n_s_unpack +#define __pyx_n_s_update __pyx_mstate_global->__pyx_n_s_update +#define __pyx_n_s_ux __pyx_mstate_global->__pyx_n_s_ux +#define __pyx_n_s_ux_2 __pyx_mstate_global->__pyx_n_s_ux_2 +#define __pyx_n_s_uy __pyx_mstate_global->__pyx_n_s_uy +#define __pyx_n_s_uy_2 __pyx_mstate_global->__pyx_n_s_uy_2 +#define __pyx_n_s_uz __pyx_mstate_global->__pyx_n_s_uz +#define __pyx_n_s_uz_2 __pyx_mstate_global->__pyx_n_s_uz_2 +#define __pyx_n_s_values __pyx_mstate_global->__pyx_n_s_values +#define __pyx_n_s_vector __pyx_mstate_global->__pyx_n_s_vector +#define __pyx_n_s_vectors __pyx_mstate_global->__pyx_n_s_vectors +#define __pyx_n_s_version_info __pyx_mstate_global->__pyx_n_s_version_info +#define __pyx_n_s_vrange __pyx_mstate_global->__pyx_n_s_vrange +#define __pyx_n_s_wcs __pyx_mstate_global->__pyx_n_s_wcs +#define __pyx_n_s_x __pyx_mstate_global->__pyx_n_s_x +#define __pyx_n_s_x_rotate __pyx_mstate_global->__pyx_n_s_x_rotate +#define __pyx_n_s_xyz_rotate __pyx_mstate_global->__pyx_n_s_xyz_rotate +#define __pyx_n_s_y __pyx_mstate_global->__pyx_n_s_y +#define __pyx_n_s_y_rotate __pyx_mstate_global->__pyx_n_s_y_rotate +#define __pyx_n_s_z __pyx_mstate_global->__pyx_n_s_z +#define __pyx_n_s_z_rotate __pyx_mstate_global->__pyx_n_s_z_rotate +#define __pyx_float_0_0 __pyx_mstate_global->__pyx_float_0_0 +#define __pyx_float_1_0 __pyx_mstate_global->__pyx_float_1_0 +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_1 __pyx_mstate_global->__pyx_int_1 +#define __pyx_int_2 __pyx_mstate_global->__pyx_int_2 +#define __pyx_int_3 __pyx_mstate_global->__pyx_int_3 +#define __pyx_int_112105877 __pyx_mstate_global->__pyx_int_112105877 +#define __pyx_int_136983863 __pyx_mstate_global->__pyx_int_136983863 +#define __pyx_int_184977713 __pyx_mstate_global->__pyx_int_184977713 +#define __pyx_int_neg_1 __pyx_mstate_global->__pyx_int_neg_1 +#define __pyx_k__16 __pyx_mstate_global->__pyx_k__16 +#define __pyx_k__17 __pyx_mstate_global->__pyx_k__17 +#define __pyx_k__18 __pyx_mstate_global->__pyx_k__18 +#define __pyx_k__19 __pyx_mstate_global->__pyx_k__19 +#define __pyx_slice__5 __pyx_mstate_global->__pyx_slice__5 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8 +#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9 +#define __pyx_tuple__10 __pyx_mstate_global->__pyx_tuple__10 +#define __pyx_tuple__12 __pyx_mstate_global->__pyx_tuple__12 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__15 __pyx_mstate_global->__pyx_tuple__15 +#define __pyx_tuple__22 __pyx_mstate_global->__pyx_tuple__22 +#define __pyx_tuple__24 __pyx_mstate_global->__pyx_tuple__24 +#define __pyx_tuple__25 __pyx_mstate_global->__pyx_tuple__25 +#define __pyx_tuple__26 __pyx_mstate_global->__pyx_tuple__26 +#define __pyx_tuple__27 __pyx_mstate_global->__pyx_tuple__27 +#define __pyx_tuple__28 __pyx_mstate_global->__pyx_tuple__28 +#define __pyx_tuple__29 __pyx_mstate_global->__pyx_tuple__29 +#define __pyx_tuple__30 __pyx_mstate_global->__pyx_tuple__30 +#define __pyx_tuple__31 __pyx_mstate_global->__pyx_tuple__31 +#define __pyx_tuple__32 __pyx_mstate_global->__pyx_tuple__32 +#define __pyx_tuple__33 __pyx_mstate_global->__pyx_tuple__33 +#define __pyx_tuple__35 __pyx_mstate_global->__pyx_tuple__35 +#define __pyx_tuple__37 __pyx_mstate_global->__pyx_tuple__37 +#define __pyx_tuple__39 __pyx_mstate_global->__pyx_tuple__39 +#define __pyx_tuple__41 __pyx_mstate_global->__pyx_tuple__41 +#define __pyx_tuple__43 __pyx_mstate_global->__pyx_tuple__43 +#define __pyx_tuple__45 __pyx_mstate_global->__pyx_tuple__45 +#define __pyx_tuple__47 __pyx_mstate_global->__pyx_tuple__47 +#define __pyx_tuple__49 __pyx_mstate_global->__pyx_tuple__49 +#define __pyx_tuple__52 __pyx_mstate_global->__pyx_tuple__52 +#define __pyx_tuple__54 __pyx_mstate_global->__pyx_tuple__54 +#define __pyx_tuple__56 __pyx_mstate_global->__pyx_tuple__56 +#define __pyx_tuple__57 __pyx_mstate_global->__pyx_tuple__57 +#define __pyx_tuple__59 __pyx_mstate_global->__pyx_tuple__59 +#define __pyx_tuple__63 __pyx_mstate_global->__pyx_tuple__63 +#define __pyx_tuple__65 __pyx_mstate_global->__pyx_tuple__65 +#define __pyx_tuple__67 __pyx_mstate_global->__pyx_tuple__67 +#define __pyx_tuple__69 __pyx_mstate_global->__pyx_tuple__69 +#define __pyx_tuple__70 __pyx_mstate_global->__pyx_tuple__70 +#define __pyx_tuple__72 __pyx_mstate_global->__pyx_tuple__72 +#define __pyx_tuple__74 __pyx_mstate_global->__pyx_tuple__74 +#define __pyx_tuple__78 __pyx_mstate_global->__pyx_tuple__78 +#define __pyx_tuple__80 __pyx_mstate_global->__pyx_tuple__80 +#define __pyx_tuple__82 __pyx_mstate_global->__pyx_tuple__82 +#define __pyx_tuple__84 __pyx_mstate_global->__pyx_tuple__84 +#define __pyx_tuple__86 __pyx_mstate_global->__pyx_tuple__86 +#define __pyx_tuple__87 __pyx_mstate_global->__pyx_tuple__87 +#define __pyx_tuple__88 __pyx_mstate_global->__pyx_tuple__88 +#define __pyx_tuple__89 __pyx_mstate_global->__pyx_tuple__89 +#define __pyx_tuple__91 __pyx_mstate_global->__pyx_tuple__91 +#define __pyx_tuple__92 __pyx_mstate_global->__pyx_tuple__92 +#define __pyx_tuple__94 __pyx_mstate_global->__pyx_tuple__94 +#define __pyx_codeobj__13 __pyx_mstate_global->__pyx_codeobj__13 +#define __pyx_codeobj__20 __pyx_mstate_global->__pyx_codeobj__20 +#define __pyx_codeobj__21 __pyx_mstate_global->__pyx_codeobj__21 +#define __pyx_codeobj__23 __pyx_mstate_global->__pyx_codeobj__23 +#define __pyx_codeobj__34 __pyx_mstate_global->__pyx_codeobj__34 +#define __pyx_codeobj__36 __pyx_mstate_global->__pyx_codeobj__36 +#define __pyx_codeobj__38 __pyx_mstate_global->__pyx_codeobj__38 +#define __pyx_codeobj__40 __pyx_mstate_global->__pyx_codeobj__40 +#define __pyx_codeobj__42 __pyx_mstate_global->__pyx_codeobj__42 +#define __pyx_codeobj__44 __pyx_mstate_global->__pyx_codeobj__44 +#define __pyx_codeobj__46 __pyx_mstate_global->__pyx_codeobj__46 +#define __pyx_codeobj__48 __pyx_mstate_global->__pyx_codeobj__48 +#define __pyx_codeobj__50 __pyx_mstate_global->__pyx_codeobj__50 +#define __pyx_codeobj__51 __pyx_mstate_global->__pyx_codeobj__51 +#define __pyx_codeobj__53 __pyx_mstate_global->__pyx_codeobj__53 +#define __pyx_codeobj__55 __pyx_mstate_global->__pyx_codeobj__55 +#define __pyx_codeobj__58 __pyx_mstate_global->__pyx_codeobj__58 +#define __pyx_codeobj__60 __pyx_mstate_global->__pyx_codeobj__60 +#define __pyx_codeobj__61 __pyx_mstate_global->__pyx_codeobj__61 +#define __pyx_codeobj__62 __pyx_mstate_global->__pyx_codeobj__62 +#define __pyx_codeobj__64 __pyx_mstate_global->__pyx_codeobj__64 +#define __pyx_codeobj__66 __pyx_mstate_global->__pyx_codeobj__66 +#define __pyx_codeobj__68 __pyx_mstate_global->__pyx_codeobj__68 +#define __pyx_codeobj__71 __pyx_mstate_global->__pyx_codeobj__71 +#define __pyx_codeobj__73 __pyx_mstate_global->__pyx_codeobj__73 +#define __pyx_codeobj__75 __pyx_mstate_global->__pyx_codeobj__75 +#define __pyx_codeobj__76 __pyx_mstate_global->__pyx_codeobj__76 +#define __pyx_codeobj__77 __pyx_mstate_global->__pyx_codeobj__77 +#define __pyx_codeobj__79 __pyx_mstate_global->__pyx_codeobj__79 +#define __pyx_codeobj__81 __pyx_mstate_global->__pyx_codeobj__81 +#define __pyx_codeobj__83 __pyx_mstate_global->__pyx_codeobj__83 +#define __pyx_codeobj__85 __pyx_mstate_global->__pyx_codeobj__85 +#define __pyx_codeobj__90 __pyx_mstate_global->__pyx_codeobj__90 +#define __pyx_codeobj__93 __pyx_mstate_global->__pyx_codeobj__93 +#define __pyx_codeobj__95 __pyx_mstate_global->__pyx_codeobj__95 +/* #### Code section: module_code ### */ + +/* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + +/* Python wrapper */ +static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_shape = 0; + Py_ssize_t __pyx_v_itemsize; + PyObject *__pyx_v_format = 0; + PyObject *__pyx_v_mode = 0; + int __pyx_v_allocate_buffer; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[5] = {0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_shape,&__pyx_n_s_itemsize,&__pyx_n_s_format,&__pyx_n_s_mode,&__pyx_n_s_allocate_buffer,0}; + values[3] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)__pyx_n_s_c)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_shape)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_itemsize)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 1); __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_format)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 2); __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_mode); + if (value) { values[3] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_allocate_buffer); + if (value) { values[4] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(1, 131, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_shape = ((PyObject*)values[0]); + __pyx_v_itemsize = __Pyx_PyIndex_AsSsize_t(values[1]); if (unlikely((__pyx_v_itemsize == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + __pyx_v_format = values[2]; + __pyx_v_mode = values[3]; + if (values[4]) { + __pyx_v_allocate_buffer = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_allocate_buffer == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 132, __pyx_L3_error) + } else { + + /* "View.MemoryView":132 + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, + * mode="c", bint allocate_buffer=True): # <<<<<<<<<<<<<< + * + * cdef int idx + */ + __pyx_v_allocate_buffer = ((int)1); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, __pyx_nargs); __PYX_ERR(1, 131, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.array.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_shape), (&PyTuple_Type), 1, "shape", 1))) __PYX_ERR(1, 131, __pyx_L1_error) + if (unlikely(((PyObject *)__pyx_v_format) == Py_None)) { + PyErr_Format(PyExc_TypeError, "Argument '%.200s' must not be None", "format"); __PYX_ERR(1, 131, __pyx_L1_error) + } + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(((struct __pyx_array_obj *)__pyx_v_self), __pyx_v_shape, __pyx_v_itemsize, __pyx_v_format, __pyx_v_mode, __pyx_v_allocate_buffer); + + /* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer) { + int __pyx_v_idx; + Py_ssize_t __pyx_v_dim; + char __pyx_v_order; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + unsigned int __pyx_t_7; + char *__pyx_t_8; + int __pyx_t_9; + Py_ssize_t __pyx_t_10; + Py_UCS4 __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + __Pyx_INCREF(__pyx_v_format); + + /* "View.MemoryView":137 + * cdef Py_ssize_t dim + * + * self.ndim = len(shape) # <<<<<<<<<<<<<< + * self.itemsize = itemsize + * + */ + if (unlikely(__pyx_v_shape == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 137, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyTuple_GET_SIZE(__pyx_v_shape); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(1, 137, __pyx_L1_error) + __pyx_v_self->ndim = ((int)__pyx_t_1); + + /* "View.MemoryView":138 + * + * self.ndim = len(shape) + * self.itemsize = itemsize # <<<<<<<<<<<<<< + * + * if not self.ndim: + */ + __pyx_v_self->itemsize = __pyx_v_itemsize; + + /* "View.MemoryView":140 + * self.itemsize = itemsize + * + * if not self.ndim: # <<<<<<<<<<<<<< + * raise ValueError, "Empty shape tuple for cython.array" + * + */ + __pyx_t_2 = (!(__pyx_v_self->ndim != 0)); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":141 + * + * if not self.ndim: + * raise ValueError, "Empty shape tuple for cython.array" # <<<<<<<<<<<<<< + * + * if itemsize <= 0: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Empty_shape_tuple_for_cython_arr, 0, 0); + __PYX_ERR(1, 141, __pyx_L1_error) + + /* "View.MemoryView":140 + * self.itemsize = itemsize + * + * if not self.ndim: # <<<<<<<<<<<<<< + * raise ValueError, "Empty shape tuple for cython.array" + * + */ + } + + /* "View.MemoryView":143 + * raise ValueError, "Empty shape tuple for cython.array" + * + * if itemsize <= 0: # <<<<<<<<<<<<<< + * raise ValueError, "itemsize <= 0 for cython.array" + * + */ + __pyx_t_2 = (__pyx_v_itemsize <= 0); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":144 + * + * if itemsize <= 0: + * raise ValueError, "itemsize <= 0 for cython.array" # <<<<<<<<<<<<<< + * + * if not isinstance(format, bytes): + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_itemsize_0_for_cython_array, 0, 0); + __PYX_ERR(1, 144, __pyx_L1_error) + + /* "View.MemoryView":143 + * raise ValueError, "Empty shape tuple for cython.array" + * + * if itemsize <= 0: # <<<<<<<<<<<<<< + * raise ValueError, "itemsize <= 0 for cython.array" + * + */ + } + + /* "View.MemoryView":146 + * raise ValueError, "itemsize <= 0 for cython.array" + * + * if not isinstance(format, bytes): # <<<<<<<<<<<<<< + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + */ + __pyx_t_2 = PyBytes_Check(__pyx_v_format); + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + + /* "View.MemoryView":147 + * + * if not isinstance(format, bytes): + * format = format.encode('ASCII') # <<<<<<<<<<<<<< + * self._format = format # keep a reference to the byte string + * self.format = self._format + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_format, __pyx_n_s_encode); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + __pyx_t_7 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_7 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_n_s_ASCII}; + __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_7, 1+__pyx_t_7); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF_SET(__pyx_v_format, __pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":146 + * raise ValueError, "itemsize <= 0 for cython.array" + * + * if not isinstance(format, bytes): # <<<<<<<<<<<<<< + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + */ + } + + /* "View.MemoryView":148 + * if not isinstance(format, bytes): + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string # <<<<<<<<<<<<<< + * self.format = self._format + * + */ + if (!(likely(PyBytes_CheckExact(__pyx_v_format))||((__pyx_v_format) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_v_format))) __PYX_ERR(1, 148, __pyx_L1_error) + __pyx_t_4 = __pyx_v_format; + __Pyx_INCREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_v_self->_format); + __Pyx_DECREF(__pyx_v_self->_format); + __pyx_v_self->_format = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":149 + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + * self.format = self._format # <<<<<<<<<<<<<< + * + * + */ + if (unlikely(__pyx_v_self->_format == Py_None)) { + PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found"); + __PYX_ERR(1, 149, __pyx_L1_error) + } + __pyx_t_8 = __Pyx_PyBytes_AsWritableString(__pyx_v_self->_format); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(1, 149, __pyx_L1_error) + __pyx_v_self->format = __pyx_t_8; + + /* "View.MemoryView":152 + * + * + * self._shape = PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2) # <<<<<<<<<<<<<< + * self._strides = self._shape + self.ndim + * + */ + __pyx_v_self->_shape = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * __pyx_v_self->ndim) * 2))); + + /* "View.MemoryView":153 + * + * self._shape = PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2) + * self._strides = self._shape + self.ndim # <<<<<<<<<<<<<< + * + * if not self._shape: + */ + __pyx_v_self->_strides = (__pyx_v_self->_shape + __pyx_v_self->ndim); + + /* "View.MemoryView":155 + * self._strides = self._shape + self.ndim + * + * if not self._shape: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate shape and strides." + * + */ + __pyx_t_3 = (!(__pyx_v_self->_shape != 0)); + if (unlikely(__pyx_t_3)) { + + /* "View.MemoryView":156 + * + * if not self._shape: + * raise MemoryError, "unable to allocate shape and strides." # <<<<<<<<<<<<<< + * + * + */ + __Pyx_Raise(__pyx_builtin_MemoryError, __pyx_kp_s_unable_to_allocate_shape_and_str, 0, 0); + __PYX_ERR(1, 156, __pyx_L1_error) + + /* "View.MemoryView":155 + * self._strides = self._shape + self.ndim + * + * if not self._shape: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate shape and strides." + * + */ + } + + /* "View.MemoryView":159 + * + * + * for idx, dim in enumerate(shape): # <<<<<<<<<<<<<< + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + */ + __pyx_t_9 = 0; + __pyx_t_4 = __pyx_v_shape; __Pyx_INCREF(__pyx_t_4); + __pyx_t_1 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 159, __pyx_L1_error) + #endif + if (__pyx_t_1 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_5); __pyx_t_1++; if (unlikely((0 < 0))) __PYX_ERR(1, 159, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_t_5); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 159, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_dim = __pyx_t_10; + __pyx_v_idx = __pyx_t_9; + __pyx_t_9 = (__pyx_t_9 + 1); + + /* "View.MemoryView":160 + * + * for idx, dim in enumerate(shape): + * if dim <= 0: # <<<<<<<<<<<<<< + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim + */ + __pyx_t_3 = (__pyx_v_dim <= 0); + if (unlikely(__pyx_t_3)) { + + /* "View.MemoryView":161 + * for idx, dim in enumerate(shape): + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." # <<<<<<<<<<<<<< + * self._shape[idx] = dim + * + */ + __pyx_t_5 = PyTuple_New(5); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = 0; + __pyx_t_11 = 127; + __Pyx_INCREF(__pyx_kp_u_Invalid_shape_in_axis); + __pyx_t_10 += 22; + __Pyx_GIVEREF(__pyx_kp_u_Invalid_shape_in_axis); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_kp_u_Invalid_shape_in_axis); + __pyx_t_6 = __Pyx_PyUnicode_From_int(__pyx_v_idx, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_10 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_6); + __pyx_t_6 = 0; + __Pyx_INCREF(__pyx_kp_u_); + __pyx_t_10 += 2; + __Pyx_GIVEREF(__pyx_kp_u_); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_kp_u_); + __pyx_t_6 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_10 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_6); + __pyx_t_6 = 0; + __Pyx_INCREF(__pyx_kp_u__2); + __pyx_t_10 += 1; + __Pyx_GIVEREF(__pyx_kp_u__2); + PyTuple_SET_ITEM(__pyx_t_5, 4, __pyx_kp_u__2); + __pyx_t_6 = __Pyx_PyUnicode_Join(__pyx_t_5, 5, __pyx_t_10, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_6, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(1, 161, __pyx_L1_error) + + /* "View.MemoryView":160 + * + * for idx, dim in enumerate(shape): + * if dim <= 0: # <<<<<<<<<<<<<< + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim + */ + } + + /* "View.MemoryView":162 + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim # <<<<<<<<<<<<<< + * + * cdef char order + */ + (__pyx_v_self->_shape[__pyx_v_idx]) = __pyx_v_dim; + + /* "View.MemoryView":159 + * + * + * for idx, dim in enumerate(shape): # <<<<<<<<<<<<<< + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + */ + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "View.MemoryView":165 + * + * cdef char order + * if mode == 'c': # <<<<<<<<<<<<<< + * order = b'C' + * self.mode = u'c' + */ + __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_v_mode, __pyx_n_s_c, Py_EQ)); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(1, 165, __pyx_L1_error) + if (__pyx_t_3) { + + /* "View.MemoryView":166 + * cdef char order + * if mode == 'c': + * order = b'C' # <<<<<<<<<<<<<< + * self.mode = u'c' + * elif mode == 'fortran': + */ + __pyx_v_order = 'C'; + + /* "View.MemoryView":167 + * if mode == 'c': + * order = b'C' + * self.mode = u'c' # <<<<<<<<<<<<<< + * elif mode == 'fortran': + * order = b'F' + */ + __Pyx_INCREF(__pyx_n_u_c); + __Pyx_GIVEREF(__pyx_n_u_c); + __Pyx_GOTREF(__pyx_v_self->mode); + __Pyx_DECREF(__pyx_v_self->mode); + __pyx_v_self->mode = __pyx_n_u_c; + + /* "View.MemoryView":165 + * + * cdef char order + * if mode == 'c': # <<<<<<<<<<<<<< + * order = b'C' + * self.mode = u'c' + */ + goto __pyx_L11; + } + + /* "View.MemoryView":168 + * order = b'C' + * self.mode = u'c' + * elif mode == 'fortran': # <<<<<<<<<<<<<< + * order = b'F' + * self.mode = u'fortran' + */ + __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_v_mode, __pyx_n_s_fortran, Py_EQ)); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(1, 168, __pyx_L1_error) + if (likely(__pyx_t_3)) { + + /* "View.MemoryView":169 + * self.mode = u'c' + * elif mode == 'fortran': + * order = b'F' # <<<<<<<<<<<<<< + * self.mode = u'fortran' + * else: + */ + __pyx_v_order = 'F'; + + /* "View.MemoryView":170 + * elif mode == 'fortran': + * order = b'F' + * self.mode = u'fortran' # <<<<<<<<<<<<<< + * else: + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" + */ + __Pyx_INCREF(__pyx_n_u_fortran); + __Pyx_GIVEREF(__pyx_n_u_fortran); + __Pyx_GOTREF(__pyx_v_self->mode); + __Pyx_DECREF(__pyx_v_self->mode); + __pyx_v_self->mode = __pyx_n_u_fortran; + + /* "View.MemoryView":168 + * order = b'C' + * self.mode = u'c' + * elif mode == 'fortran': # <<<<<<<<<<<<<< + * order = b'F' + * self.mode = u'fortran' + */ + goto __pyx_L11; + } + + /* "View.MemoryView":172 + * self.mode = u'fortran' + * else: + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" # <<<<<<<<<<<<<< + * + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) + */ + /*else*/ { + __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_v_mode, __pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyUnicode_Concat(__pyx_kp_u_Invalid_mode_expected_c_or_fortr, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_6, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(1, 172, __pyx_L1_error) + } + __pyx_L11:; + + /* "View.MemoryView":174 + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" + * + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) # <<<<<<<<<<<<<< + * + * self.free_data = allocate_buffer + */ + __pyx_v_self->len = __pyx_fill_contig_strides_array(__pyx_v_self->_shape, __pyx_v_self->_strides, __pyx_v_itemsize, __pyx_v_self->ndim, __pyx_v_order); + + /* "View.MemoryView":176 + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) + * + * self.free_data = allocate_buffer # <<<<<<<<<<<<<< + * self.dtype_is_object = format == b'O' + * + */ + __pyx_v_self->free_data = __pyx_v_allocate_buffer; + + /* "View.MemoryView":177 + * + * self.free_data = allocate_buffer + * self.dtype_is_object = format == b'O' # <<<<<<<<<<<<<< + * + * if allocate_buffer: + */ + __pyx_t_6 = PyObject_RichCompare(__pyx_v_format, __pyx_n_b_O, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 177, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 177, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_self->dtype_is_object = __pyx_t_3; + + /* "View.MemoryView":179 + * self.dtype_is_object = format == b'O' + * + * if allocate_buffer: # <<<<<<<<<<<<<< + * _allocate_buffer(self) + * + */ + if (__pyx_v_allocate_buffer) { + + /* "View.MemoryView":180 + * + * if allocate_buffer: + * _allocate_buffer(self) # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + __pyx_t_9 = __pyx_array_allocate_buffer(__pyx_v_self); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(1, 180, __pyx_L1_error) + + /* "View.MemoryView":179 + * self.dtype_is_object = format == b'O' + * + * if allocate_buffer: # <<<<<<<<<<<<<< + * _allocate_buffer(self) + * + */ + } + + /* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.array.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_format); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":182 + * _allocate_buffer(self) + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + */ + +/* Python wrapper */ +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(((struct __pyx_array_obj *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(struct __pyx_array_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_v_bufmode; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + char *__pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + Py_ssize_t *__pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + if (unlikely(__pyx_v_info == NULL)) { + PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); + return -1; + } + __Pyx_RefNannySetupContext("__getbuffer__", 0); + __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(__pyx_v_info->obj); + + /* "View.MemoryView":184 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 # <<<<<<<<<<<<<< + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": + */ + __pyx_v_bufmode = -1; + + /* "View.MemoryView":185 + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): # <<<<<<<<<<<<<< + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + __pyx_t_1 = ((__pyx_v_flags & ((PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS) | PyBUF_ANY_CONTIGUOUS)) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":186 + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": # <<<<<<<<<<<<<< + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + */ + __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_self->mode, __pyx_n_u_c, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 186, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":187 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS # <<<<<<<<<<<<<< + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + __pyx_v_bufmode = (PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS); + + /* "View.MemoryView":186 + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": # <<<<<<<<<<<<<< + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + */ + goto __pyx_L4; + } + + /* "View.MemoryView":188 + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": # <<<<<<<<<<<<<< + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + */ + __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_self->mode, __pyx_n_u_fortran, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 188, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":189 + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS # <<<<<<<<<<<<<< + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." + */ + __pyx_v_bufmode = (PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS); + + /* "View.MemoryView":188 + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": # <<<<<<<<<<<<<< + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + */ + } + __pyx_L4:; + + /* "View.MemoryView":190 + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): # <<<<<<<<<<<<<< + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + */ + __pyx_t_1 = (!((__pyx_v_flags & __pyx_v_bufmode) != 0)); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":191 + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." # <<<<<<<<<<<<<< + * info.buf = self.data + * info.len = self.len + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Can_only_create_a_buffer_that_is, 0, 0); + __PYX_ERR(1, 191, __pyx_L1_error) + + /* "View.MemoryView":190 + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): # <<<<<<<<<<<<<< + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + */ + } + + /* "View.MemoryView":185 + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): # <<<<<<<<<<<<<< + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + } + + /* "View.MemoryView":192 + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data # <<<<<<<<<<<<<< + * info.len = self.len + * + */ + __pyx_t_2 = __pyx_v_self->data; + __pyx_v_info->buf = __pyx_t_2; + + /* "View.MemoryView":193 + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + * info.len = self.len # <<<<<<<<<<<<<< + * + * if flags & PyBUF_STRIDES: + */ + __pyx_t_3 = __pyx_v_self->len; + __pyx_v_info->len = __pyx_t_3; + + /* "View.MemoryView":195 + * info.len = self.len + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.ndim = self.ndim + * info.shape = self._shape + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_STRIDES) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":196 + * + * if flags & PyBUF_STRIDES: + * info.ndim = self.ndim # <<<<<<<<<<<<<< + * info.shape = self._shape + * info.strides = self._strides + */ + __pyx_t_4 = __pyx_v_self->ndim; + __pyx_v_info->ndim = __pyx_t_4; + + /* "View.MemoryView":197 + * if flags & PyBUF_STRIDES: + * info.ndim = self.ndim + * info.shape = self._shape # <<<<<<<<<<<<<< + * info.strides = self._strides + * else: + */ + __pyx_t_5 = __pyx_v_self->_shape; + __pyx_v_info->shape = __pyx_t_5; + + /* "View.MemoryView":198 + * info.ndim = self.ndim + * info.shape = self._shape + * info.strides = self._strides # <<<<<<<<<<<<<< + * else: + * info.ndim = 1 + */ + __pyx_t_5 = __pyx_v_self->_strides; + __pyx_v_info->strides = __pyx_t_5; + + /* "View.MemoryView":195 + * info.len = self.len + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.ndim = self.ndim + * info.shape = self._shape + */ + goto __pyx_L6; + } + + /* "View.MemoryView":200 + * info.strides = self._strides + * else: + * info.ndim = 1 # <<<<<<<<<<<<<< + * info.shape = &self.len if flags & PyBUF_ND else NULL + * info.strides = NULL + */ + /*else*/ { + __pyx_v_info->ndim = 1; + + /* "View.MemoryView":201 + * else: + * info.ndim = 1 + * info.shape = &self.len if flags & PyBUF_ND else NULL # <<<<<<<<<<<<<< + * info.strides = NULL + * + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_ND) != 0); + if (__pyx_t_1) { + __pyx_t_5 = (&__pyx_v_self->len); + } else { + __pyx_t_5 = NULL; + } + __pyx_v_info->shape = __pyx_t_5; + + /* "View.MemoryView":202 + * info.ndim = 1 + * info.shape = &self.len if flags & PyBUF_ND else NULL + * info.strides = NULL # <<<<<<<<<<<<<< + * + * info.suboffsets = NULL + */ + __pyx_v_info->strides = NULL; + } + __pyx_L6:; + + /* "View.MemoryView":204 + * info.strides = NULL + * + * info.suboffsets = NULL # <<<<<<<<<<<<<< + * info.itemsize = self.itemsize + * info.readonly = 0 + */ + __pyx_v_info->suboffsets = NULL; + + /* "View.MemoryView":205 + * + * info.suboffsets = NULL + * info.itemsize = self.itemsize # <<<<<<<<<<<<<< + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL + */ + __pyx_t_3 = __pyx_v_self->itemsize; + __pyx_v_info->itemsize = __pyx_t_3; + + /* "View.MemoryView":206 + * info.suboffsets = NULL + * info.itemsize = self.itemsize + * info.readonly = 0 # <<<<<<<<<<<<<< + * info.format = self.format if flags & PyBUF_FORMAT else NULL + * info.obj = self + */ + __pyx_v_info->readonly = 0; + + /* "View.MemoryView":207 + * info.itemsize = self.itemsize + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL # <<<<<<<<<<<<<< + * info.obj = self + * + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + __pyx_t_2 = __pyx_v_self->format; + } else { + __pyx_t_2 = NULL; + } + __pyx_v_info->format = __pyx_t_2; + + /* "View.MemoryView":208 + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL + * info.obj = self # <<<<<<<<<<<<<< + * + * def __dealloc__(array self): + */ + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); + __pyx_v_info->obj = ((PyObject *)__pyx_v_self); + + /* "View.MemoryView":182 + * _allocate_buffer(self) + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + if (__pyx_v_info->obj != NULL) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + goto __pyx_L2; + __pyx_L0:; + if (__pyx_v_info->obj == Py_None) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + __pyx_L2:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":210 + * info.obj = self + * + * def __dealloc__(array self): # <<<<<<<<<<<<<< + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + */ + +/* Python wrapper */ +static void __pyx_array___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_array___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(struct __pyx_array_obj *__pyx_v_self) { + int __pyx_t_1; + int __pyx_t_2; + + /* "View.MemoryView":211 + * + * def __dealloc__(array self): + * if self.callback_free_data != NULL: # <<<<<<<<<<<<<< + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + */ + __pyx_t_1 = (__pyx_v_self->callback_free_data != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":212 + * def __dealloc__(array self): + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) # <<<<<<<<<<<<<< + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: + */ + __pyx_v_self->callback_free_data(__pyx_v_self->data); + + /* "View.MemoryView":211 + * + * def __dealloc__(array self): + * if self.callback_free_data != NULL: # <<<<<<<<<<<<<< + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":213 + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + */ + if (__pyx_v_self->free_data) { + } else { + __pyx_t_1 = __pyx_v_self->free_data; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_self->data != NULL); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "View.MemoryView":214 + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":215 + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) # <<<<<<<<<<<<<< + * free(self.data) + * PyObject_Free(self._shape) + */ + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_self->data, __pyx_v_self->_shape, __pyx_v_self->_strides, __pyx_v_self->ndim, 0); + + /* "View.MemoryView":214 + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + */ + } + + /* "View.MemoryView":216 + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) # <<<<<<<<<<<<<< + * PyObject_Free(self._shape) + * + */ + free(__pyx_v_self->data); + + /* "View.MemoryView":213 + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + */ + } + __pyx_L3:; + + /* "View.MemoryView":217 + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + * PyObject_Free(self._shape) # <<<<<<<<<<<<<< + * + * @property + */ + PyObject_Free(__pyx_v_self->_shape); + + /* "View.MemoryView":210 + * info.obj = self + * + * def __dealloc__(array self): # <<<<<<<<<<<<<< + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + */ + + /* function exit code */ +} + +/* "View.MemoryView":219 + * PyObject_Free(self._shape) + * + * @property # <<<<<<<<<<<<<< + * def memview(self): + * return self.get_memview() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_5array_7memview___get__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_5array_7memview___get__(struct __pyx_array_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":221 + * @property + * def memview(self): + * return self.get_memview() # <<<<<<<<<<<<<< + * + * @cname('get_memview') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((struct __pyx_vtabstruct_array *)__pyx_v_self->__pyx_vtab)->get_memview(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":219 + * PyObject_Free(self._shape) + * + * @property # <<<<<<<<<<<<<< + * def memview(self): + * return self.get_memview() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.array.memview.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":224 + * + * @cname('get_memview') + * cdef get_memview(self): # <<<<<<<<<<<<<< + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) + */ + +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *__pyx_v_self) { + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_memview", 1); + + /* "View.MemoryView":225 + * @cname('get_memview') + * cdef get_memview(self): + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE # <<<<<<<<<<<<<< + * return memoryview(self, flags, self.dtype_is_object) + * + */ + __pyx_v_flags = ((PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) | PyBUF_WRITABLE); + + /* "View.MemoryView":226 + * cdef get_memview(self): + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) # <<<<<<<<<<<<<< + * + * def __len__(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_self->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_self))) __PYX_ERR(1, 226, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 226, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":224 + * + * @cname('get_memview') + * cdef get_memview(self): # <<<<<<<<<<<<<< + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.array.get_memview", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":228 + * return memoryview(self, flags, self.dtype_is_object) + * + * def __len__(self): # <<<<<<<<<<<<<< + * return self._shape[0] + * + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_array___len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_array___len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(struct __pyx_array_obj *__pyx_v_self) { + Py_ssize_t __pyx_r; + + /* "View.MemoryView":229 + * + * def __len__(self): + * return self._shape[0] # <<<<<<<<<<<<<< + * + * def __getattr__(self, attr): + */ + __pyx_r = (__pyx_v_self->_shape[0]); + goto __pyx_L0; + + /* "View.MemoryView":228 + * return memoryview(self, flags, self.dtype_is_object) + * + * def __len__(self): # <<<<<<<<<<<<<< + * return self._shape[0] + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":231 + * return self._shape[0] + * + * def __getattr__(self, attr): # <<<<<<<<<<<<<< + * return getattr(self.memview, attr) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_array___getattr__(PyObject *__pyx_v_self, PyObject *__pyx_v_attr); /*proto*/ +static PyObject *__pyx_array___getattr__(PyObject *__pyx_v_self, PyObject *__pyx_v_attr) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getattr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_attr)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_attr) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getattr__", 1); + + /* "View.MemoryView":232 + * + * def __getattr__(self, attr): + * return getattr(self.memview, attr) # <<<<<<<<<<<<<< + * + * def __getitem__(self, item): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_GetAttr(__pyx_t_1, __pyx_v_attr); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":231 + * return self._shape[0] + * + * def __getattr__(self, attr): # <<<<<<<<<<<<<< + * return getattr(self.memview, attr) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.array.__getattr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":234 + * return getattr(self.memview, attr) + * + * def __getitem__(self, item): # <<<<<<<<<<<<<< + * return self.memview[item] + * + */ + +/* Python wrapper */ +static PyObject *__pyx_array___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item); /*proto*/ +static PyObject *__pyx_array___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_item)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "View.MemoryView":235 + * + * def __getitem__(self, item): + * return self.memview[item] # <<<<<<<<<<<<<< + * + * def __setitem__(self, item, value): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 235, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_t_1, __pyx_v_item); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 235, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":234 + * return getattr(self.memview, attr) + * + * def __getitem__(self, item): # <<<<<<<<<<<<<< + * return self.memview[item] + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.array.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":237 + * return self.memview[item] + * + * def __setitem__(self, item, value): # <<<<<<<<<<<<<< + * self.memview[item] = value + * + */ + +/* Python wrapper */ +static int __pyx_array___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value); /*proto*/ +static int __pyx_array___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_item), ((PyObject *)__pyx_v_value)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setitem__", 1); + + /* "View.MemoryView":238 + * + * def __setitem__(self, item, value): + * self.memview[item] = value # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 238, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (unlikely((PyObject_SetItem(__pyx_t_1, __pyx_v_item, __pyx_v_value) < 0))) __PYX_ERR(1, 238, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "View.MemoryView":237 + * return self.memview[item] + * + * def __setitem__(self, item, value): # <<<<<<<<<<<<<< + * self.memview[item] = value + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.array.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_array_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_array_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_array___reduce_cython__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_array___reduce_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_array_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_array_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.array.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_array_2__setstate_cython__(((struct __pyx_array_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_array_2__setstate_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":248 + * + * @cname("__pyx_array_allocate_buffer") + * cdef int _allocate_buffer(array self) except -1: # <<<<<<<<<<<<<< + * + * + */ + +static int __pyx_array_allocate_buffer(struct __pyx_array_obj *__pyx_v_self) { + Py_ssize_t __pyx_v_i; + PyObject **__pyx_v_p; + int __pyx_r; + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "View.MemoryView":254 + * cdef PyObject **p + * + * self.free_data = True # <<<<<<<<<<<<<< + * self.data = malloc(self.len) + * if not self.data: + */ + __pyx_v_self->free_data = 1; + + /* "View.MemoryView":255 + * + * self.free_data = True + * self.data = malloc(self.len) # <<<<<<<<<<<<<< + * if not self.data: + * raise MemoryError, "unable to allocate array data." + */ + __pyx_v_self->data = ((char *)malloc(__pyx_v_self->len)); + + /* "View.MemoryView":256 + * self.free_data = True + * self.data = malloc(self.len) + * if not self.data: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate array data." + * + */ + __pyx_t_1 = (!(__pyx_v_self->data != 0)); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":257 + * self.data = malloc(self.len) + * if not self.data: + * raise MemoryError, "unable to allocate array data." # <<<<<<<<<<<<<< + * + * if self.dtype_is_object: + */ + __Pyx_Raise(__pyx_builtin_MemoryError, __pyx_kp_s_unable_to_allocate_array_data, 0, 0); + __PYX_ERR(1, 257, __pyx_L1_error) + + /* "View.MemoryView":256 + * self.free_data = True + * self.data = malloc(self.len) + * if not self.data: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate array data." + * + */ + } + + /* "View.MemoryView":259 + * raise MemoryError, "unable to allocate array data." + * + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * p = self.data + * for i in range(self.len // self.itemsize): + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":260 + * + * if self.dtype_is_object: + * p = self.data # <<<<<<<<<<<<<< + * for i in range(self.len // self.itemsize): + * p[i] = Py_None + */ + __pyx_v_p = ((PyObject **)__pyx_v_self->data); + + /* "View.MemoryView":261 + * if self.dtype_is_object: + * p = self.data + * for i in range(self.len // self.itemsize): # <<<<<<<<<<<<<< + * p[i] = Py_None + * Py_INCREF(Py_None) + */ + if (unlikely(__pyx_v_self->itemsize == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 261, __pyx_L1_error) + } + else if (sizeof(Py_ssize_t) == sizeof(long) && (!(((Py_ssize_t)-1) > 0)) && unlikely(__pyx_v_self->itemsize == (Py_ssize_t)-1) && unlikely(__Pyx_UNARY_NEG_WOULD_OVERFLOW(__pyx_v_self->len))) { + PyErr_SetString(PyExc_OverflowError, "value too large to perform division"); + __PYX_ERR(1, 261, __pyx_L1_error) + } + __pyx_t_2 = __Pyx_div_Py_ssize_t(__pyx_v_self->len, __pyx_v_self->itemsize); + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":262 + * p = self.data + * for i in range(self.len // self.itemsize): + * p[i] = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * return 0 + */ + (__pyx_v_p[__pyx_v_i]) = Py_None; + + /* "View.MemoryView":263 + * for i in range(self.len // self.itemsize): + * p[i] = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * return 0 + * + */ + Py_INCREF(Py_None); + } + + /* "View.MemoryView":259 + * raise MemoryError, "unable to allocate array data." + * + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * p = self.data + * for i in range(self.len // self.itemsize): + */ + } + + /* "View.MemoryView":264 + * p[i] = Py_None + * Py_INCREF(Py_None) + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":248 + * + * @cname("__pyx_array_allocate_buffer") + * cdef int _allocate_buffer(array self) except -1: # <<<<<<<<<<<<<< + * + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._allocate_buffer", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":268 + * + * @cname("__pyx_array_new") + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): # <<<<<<<<<<<<<< + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + */ + +static struct __pyx_array_obj *__pyx_array_new(PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, char *__pyx_v_format, char *__pyx_v_c_mode, char *__pyx_v_buf) { + struct __pyx_array_obj *__pyx_v_result = 0; + PyObject *__pyx_v_mode = 0; + struct __pyx_array_obj *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("array_cwrapper", 1); + + /* "View.MemoryView":270 + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. # <<<<<<<<<<<<<< + * + * if buf is NULL: + */ + __pyx_t_2 = ((__pyx_v_c_mode[0]) == 'f'); + if (__pyx_t_2) { + __Pyx_INCREF(__pyx_n_s_fortran); + __pyx_t_1 = __pyx_n_s_fortran; + } else { + __Pyx_INCREF(__pyx_n_s_c); + __pyx_t_1 = __pyx_n_s_c; + } + __pyx_v_mode = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":272 + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + * + * if buf is NULL: # <<<<<<<<<<<<<< + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + */ + __pyx_t_2 = (__pyx_v_buf == NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":273 + * + * if buf is NULL: + * result = array.__new__(array, shape, itemsize, format, mode) # <<<<<<<<<<<<<< + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) + */ + __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_itemsize); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_format); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_shape)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_mode); + __Pyx_GIVEREF(__pyx_v_mode); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 3, __pyx_v_mode)) __PYX_ERR(1, 273, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_3 = 0; + __pyx_t_3 = ((PyObject *)__pyx_tp_new_array(((PyTypeObject *)__pyx_array_type), __pyx_t_4, NULL)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_result = ((struct __pyx_array_obj *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":272 + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + * + * if buf is NULL: # <<<<<<<<<<<<<< + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":275 + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) # <<<<<<<<<<<<<< + * result.data = buf + * + */ + /*else*/ { + __pyx_t_3 = PyInt_FromSsize_t(__pyx_v_itemsize); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyBytes_FromString(__pyx_v_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_shape)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_mode); + __Pyx_GIVEREF(__pyx_v_mode); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_v_mode)) __PYX_ERR(1, 275, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_allocate_buffer, Py_False) < 0) __PYX_ERR(1, 275, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_tp_new_array(((PyTypeObject *)__pyx_array_type), __pyx_t_1, __pyx_t_4)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_result = ((struct __pyx_array_obj *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":276 + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) + * result.data = buf # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->data = __pyx_v_buf; + } + __pyx_L3:; + + /* "View.MemoryView":278 + * result.data = buf + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "View.MemoryView":268 + * + * @cname("__pyx_array_new") + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): # <<<<<<<<<<<<<< + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.array_cwrapper", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XDECREF(__pyx_v_mode); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":304 + * cdef class Enum(object): + * cdef object name + * def __init__(self, name): # <<<<<<<<<<<<<< + * self.name = name + * def __repr__(self): + */ + +/* Python wrapper */ +static int __pyx_MemviewEnum___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_MemviewEnum___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_name = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_name)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 304, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__init__") < 0)) __PYX_ERR(1, 304, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + } + __pyx_v_name = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 304, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.Enum.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self), __pyx_v_name); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v_name) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__", 1); + + /* "View.MemoryView":305 + * cdef object name + * def __init__(self, name): + * self.name = name # <<<<<<<<<<<<<< + * def __repr__(self): + * return self.name + */ + __Pyx_INCREF(__pyx_v_name); + __Pyx_GIVEREF(__pyx_v_name); + __Pyx_GOTREF(__pyx_v_self->name); + __Pyx_DECREF(__pyx_v_self->name); + __pyx_v_self->name = __pyx_v_name; + + /* "View.MemoryView":304 + * cdef class Enum(object): + * cdef object name + * def __init__(self, name): # <<<<<<<<<<<<<< + * self.name = name + * def __repr__(self): + */ + + /* function exit code */ + __pyx_r = 0; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":306 + * def __init__(self, name): + * self.name = name + * def __repr__(self): # <<<<<<<<<<<<<< + * return self.name + * + */ + +/* Python wrapper */ +static PyObject *__pyx_MemviewEnum___repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_MemviewEnum___repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(struct __pyx_MemviewEnum_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "View.MemoryView":307 + * self.name = name + * def __repr__(self): + * return self.name # <<<<<<<<<<<<<< + * + * cdef generic = Enum("") + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->name); + __pyx_r = __pyx_v_self->name; + goto __pyx_L0; + + /* "View.MemoryView":306 + * def __init__(self, name): + * self.name = name + * def __repr__(self): # <<<<<<<<<<<<<< + * return self.name + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_MemviewEnum_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_MemviewEnum_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_MemviewEnum___reduce_cython__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_MemviewEnum___reduce_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self) { + PyObject *__pyx_v_state = 0; + PyObject *__pyx_v__dict = 0; + int __pyx_v_use_setstate; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":5 + * cdef object _dict + * cdef bint use_setstate + * state = (self.name,) # <<<<<<<<<<<<<< + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_self->name); + __Pyx_GIVEREF(__pyx_v_self->name); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_self->name)) __PYX_ERR(1, 5, __pyx_L1_error); + __pyx_v_state = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "(tree fragment)":6 + * cdef bint use_setstate + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< + * if _dict is not None: + * state += (_dict,) + */ + __pyx_t_1 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__dict = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":7 + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + __pyx_t_2 = (__pyx_v__dict != Py_None); + if (__pyx_t_2) { + + /* "(tree fragment)":8 + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + * state += (_dict,) # <<<<<<<<<<<<<< + * use_setstate = True + * else: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v__dict); + __Pyx_GIVEREF(__pyx_v__dict); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v__dict)) __PYX_ERR(1, 8, __pyx_L1_error); + __pyx_t_3 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "(tree fragment)":9 + * if _dict is not None: + * state += (_dict,) + * use_setstate = True # <<<<<<<<<<<<<< + * else: + * use_setstate = self.name is not None + */ + __pyx_v_use_setstate = 1; + + /* "(tree fragment)":7 + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + goto __pyx_L3; + } + + /* "(tree fragment)":11 + * use_setstate = True + * else: + * use_setstate = self.name is not None # <<<<<<<<<<<<<< + * if use_setstate: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + */ + /*else*/ { + __pyx_t_2 = (__pyx_v_self->name != Py_None); + __pyx_v_use_setstate = __pyx_t_2; + } + __pyx_L3:; + + /* "(tree fragment)":12 + * else: + * use_setstate = self.name is not None + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + */ + if (__pyx_v_use_setstate) { + + /* "(tree fragment)":13 + * use_setstate = self.name is not None + * if use_setstate: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state # <<<<<<<<<<<<<< + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_pyx_unpickle_Enum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))))) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_136983863); + __Pyx_GIVEREF(__pyx_int_136983863); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_136983863)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, Py_None)) __PYX_ERR(1, 13, __pyx_L1_error); + __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_state)) __PYX_ERR(1, 13, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "(tree fragment)":12 + * else: + * use_setstate = self.name is not None + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + */ + } + + /* "(tree fragment)":15 + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pyx_unpickle_Enum); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))))) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_136983863); + __Pyx_GIVEREF(__pyx_int_136983863); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_136983863)) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_state)) __PYX_ERR(1, 15, __pyx_L1_error); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error); + __pyx_t_4 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + } + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.Enum.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_state); + __Pyx_XDECREF(__pyx_v__dict); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":16 + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_MemviewEnum_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_MemviewEnum_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 16, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 16, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 16, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.Enum.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_MemviewEnum_2__setstate_cython__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_MemviewEnum_2__setstate_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":17 + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle_Enum__set_state(self, __pyx_state) # <<<<<<<<<<<<<< + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None) || __Pyx_RaiseUnexpectedTypeError("tuple", __pyx_v___pyx_state))) __PYX_ERR(1, 17, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle_Enum__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":16 + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.Enum.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":349 + * cdef __Pyx_TypeInfo *typeinfo + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): # <<<<<<<<<<<<<< + * self.obj = obj + * self.flags = flags + */ + +/* Python wrapper */ +static int __pyx_memoryview___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_memoryview___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_obj = 0; + int __pyx_v_flags; + int __pyx_v_dtype_is_object; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_obj,&__pyx_n_s_flags,&__pyx_n_s_dtype_is_object,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_obj)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_flags)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 3, 1); __PYX_ERR(1, 349, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dtype_is_object); + if (value) { values[2] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(1, 349, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_obj = values[0]; + __pyx_v_flags = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + if (values[2]) { + __pyx_v_dtype_is_object = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_dtype_is_object == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + } else { + __pyx_v_dtype_is_object = ((int)0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 3, __pyx_nargs); __PYX_ERR(1, 349, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.memoryview.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_obj, __pyx_v_flags, __pyx_v_dtype_is_object); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj, int __pyx_v_flags, int __pyx_v_dtype_is_object) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + Py_intptr_t __pyx_t_4; + size_t __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "View.MemoryView":350 + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): + * self.obj = obj # <<<<<<<<<<<<<< + * self.flags = flags + * if type(self) is memoryview or obj is not None: + */ + __Pyx_INCREF(__pyx_v_obj); + __Pyx_GIVEREF(__pyx_v_obj); + __Pyx_GOTREF(__pyx_v_self->obj); + __Pyx_DECREF(__pyx_v_self->obj); + __pyx_v_self->obj = __pyx_v_obj; + + /* "View.MemoryView":351 + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): + * self.obj = obj + * self.flags = flags # <<<<<<<<<<<<<< + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + */ + __pyx_v_self->flags = __pyx_v_flags; + + /* "View.MemoryView":352 + * self.obj = obj + * self.flags = flags + * if type(self) is memoryview or obj is not None: # <<<<<<<<<<<<<< + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + */ + __pyx_t_2 = (((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))) == ((PyObject *)__pyx_memoryview_type)); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_obj != Py_None); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "View.MemoryView":353 + * self.flags = flags + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) # <<<<<<<<<<<<<< + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None + */ + __pyx_t_3 = __Pyx_GetBuffer(__pyx_v_obj, (&__pyx_v_self->view), __pyx_v_flags); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 353, __pyx_L1_error) + + /* "View.MemoryView":354 + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) + */ + __pyx_t_1 = (((PyObject *)__pyx_v_self->view.obj) == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":355 + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_self->view))->obj = Py_None; + + /* "View.MemoryView":356 + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + */ + Py_INCREF(Py_None); + + /* "View.MemoryView":354 + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) + */ + } + + /* "View.MemoryView":352 + * self.obj = obj + * self.flags = flags + * if type(self) is memoryview or obj is not None: # <<<<<<<<<<<<<< + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + */ + } + + /* "View.MemoryView":358 + * Py_INCREF(Py_None) + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): # <<<<<<<<<<<<<< + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + */ + __pyx_t_1 = (!__PYX_CYTHON_ATOMICS_ENABLED()); + if (__pyx_t_1) { + + /* "View.MemoryView":360 + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: # <<<<<<<<<<<<<< + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + */ + __pyx_t_1 = (__pyx_memoryview_thread_locks_used < 8); + if (__pyx_t_1) { + + /* "View.MemoryView":361 + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: + */ + __pyx_v_self->lock = (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]); + + /* "View.MemoryView":362 + * if __pyx_memoryview_thread_locks_used < 8: + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 # <<<<<<<<<<<<<< + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + */ + __pyx_memoryview_thread_locks_used = (__pyx_memoryview_thread_locks_used + 1); + + /* "View.MemoryView":360 + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: # <<<<<<<<<<<<<< + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + */ + } + + /* "View.MemoryView":363 + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: # <<<<<<<<<<<<<< + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + */ + __pyx_t_1 = (__pyx_v_self->lock == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":364 + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() # <<<<<<<<<<<<<< + * if self.lock is NULL: + * raise MemoryError + */ + __pyx_v_self->lock = PyThread_allocate_lock(); + + /* "View.MemoryView":365 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + __pyx_t_1 = (__pyx_v_self->lock == NULL); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":366 + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + * raise MemoryError # <<<<<<<<<<<<<< + * + * if flags & PyBUF_FORMAT: + */ + PyErr_NoMemory(); __PYX_ERR(1, 366, __pyx_L1_error) + + /* "View.MemoryView":365 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + } + + /* "View.MemoryView":363 + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: # <<<<<<<<<<<<<< + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + */ + } + + /* "View.MemoryView":358 + * Py_INCREF(Py_None) + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): # <<<<<<<<<<<<<< + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + */ + } + + /* "View.MemoryView":368 + * raise MemoryError + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":369 + * + * if flags & PyBUF_FORMAT: + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') # <<<<<<<<<<<<<< + * else: + * self.dtype_is_object = dtype_is_object + */ + __pyx_t_2 = ((__pyx_v_self->view.format[0]) == 'O'); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_2 = ((__pyx_v_self->view.format[1]) == '\x00'); + __pyx_t_1 = __pyx_t_2; + __pyx_L12_bool_binop_done:; + __pyx_v_self->dtype_is_object = __pyx_t_1; + + /* "View.MemoryView":368 + * raise MemoryError + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + */ + goto __pyx_L11; + } + + /* "View.MemoryView":371 + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + * self.dtype_is_object = dtype_is_object # <<<<<<<<<<<<<< + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 + */ + /*else*/ { + __pyx_v_self->dtype_is_object = __pyx_v_dtype_is_object; + } + __pyx_L11:; + + /* "View.MemoryView":373 + * self.dtype_is_object = dtype_is_object + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 # <<<<<<<<<<<<<< + * self.typeinfo = NULL + * + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_4 = ((Py_intptr_t)((void *)(&__pyx_v_self->acquisition_count))); + __pyx_t_5 = (sizeof(__pyx_atomic_int_type)); + if (unlikely(__pyx_t_5 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 373, __pyx_L1_error) + } + __pyx_t_1 = ((__pyx_t_4 % __pyx_t_5) == 0); + if (unlikely(!__pyx_t_1)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(1, 373, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(1, 373, __pyx_L1_error) + #endif + + /* "View.MemoryView":374 + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 + * self.typeinfo = NULL # <<<<<<<<<<<<<< + * + * def __dealloc__(memoryview self): + */ + __pyx_v_self->typeinfo = NULL; + + /* "View.MemoryView":349 + * cdef __Pyx_TypeInfo *typeinfo + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): # <<<<<<<<<<<<<< + * self.obj = obj + * self.flags = flags + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":376 + * self.typeinfo = NULL + * + * def __dealloc__(memoryview self): # <<<<<<<<<<<<<< + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + */ + +/* Python wrapper */ +static void __pyx_memoryview___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_memoryview___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(struct __pyx_memoryview_obj *__pyx_v_self) { + int __pyx_v_i; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyThread_type_lock __pyx_t_5; + PyThread_type_lock __pyx_t_6; + + /* "View.MemoryView":377 + * + * def __dealloc__(memoryview self): + * if self.obj is not None: # <<<<<<<<<<<<<< + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + */ + __pyx_t_1 = (__pyx_v_self->obj != Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":378 + * def __dealloc__(memoryview self): + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) # <<<<<<<<<<<<<< + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + * + */ + __Pyx_ReleaseBuffer((&__pyx_v_self->view)); + + /* "View.MemoryView":377 + * + * def __dealloc__(memoryview self): + * if self.obj is not None: # <<<<<<<<<<<<<< + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":379 + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: # <<<<<<<<<<<<<< + * + * (<__pyx_buffer *> &self.view).obj = NULL + */ + __pyx_t_1 = (((Py_buffer *)(&__pyx_v_self->view))->obj == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":381 + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + * + * (<__pyx_buffer *> &self.view).obj = NULL # <<<<<<<<<<<<<< + * Py_DECREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_self->view))->obj = NULL; + + /* "View.MemoryView":382 + * + * (<__pyx_buffer *> &self.view).obj = NULL + * Py_DECREF(Py_None) # <<<<<<<<<<<<<< + * + * cdef int i + */ + Py_DECREF(Py_None); + + /* "View.MemoryView":379 + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: # <<<<<<<<<<<<<< + * + * (<__pyx_buffer *> &self.view).obj = NULL + */ + } + __pyx_L3:; + + /* "View.MemoryView":386 + * cdef int i + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: # <<<<<<<<<<<<<< + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + */ + __pyx_t_1 = (__pyx_v_self->lock != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":387 + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): # <<<<<<<<<<<<<< + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + */ + __pyx_t_2 = __pyx_memoryview_thread_locks_used; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":388 + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + */ + __pyx_t_1 = ((__pyx_memoryview_thread_locks[__pyx_v_i]) == __pyx_v_self->lock); + if (__pyx_t_1) { + + /* "View.MemoryView":389 + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 # <<<<<<<<<<<<<< + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + */ + __pyx_memoryview_thread_locks_used = (__pyx_memoryview_thread_locks_used - 1); + + /* "View.MemoryView":390 + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + */ + __pyx_t_1 = (__pyx_v_i != __pyx_memoryview_thread_locks_used); + if (__pyx_t_1) { + + /* "View.MemoryView":392 + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) # <<<<<<<<<<<<<< + * break + * else: + */ + __pyx_t_5 = (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]); + __pyx_t_6 = (__pyx_memoryview_thread_locks[__pyx_v_i]); + + /* "View.MemoryView":391 + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + * break + */ + (__pyx_memoryview_thread_locks[__pyx_v_i]) = __pyx_t_5; + (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]) = __pyx_t_6; + + /* "View.MemoryView":390 + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + */ + } + + /* "View.MemoryView":393 + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + * break # <<<<<<<<<<<<<< + * else: + * PyThread_free_lock(self.lock) + */ + goto __pyx_L6_break; + + /* "View.MemoryView":388 + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + */ + } + } + /*else*/ { + + /* "View.MemoryView":395 + * break + * else: + * PyThread_free_lock(self.lock) # <<<<<<<<<<<<<< + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: + */ + PyThread_free_lock(__pyx_v_self->lock); + } + __pyx_L6_break:; + + /* "View.MemoryView":386 + * cdef int i + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: # <<<<<<<<<<<<<< + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + */ + } + + /* "View.MemoryView":376 + * self.typeinfo = NULL + * + * def __dealloc__(memoryview self): # <<<<<<<<<<<<<< + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + */ + + /* function exit code */ +} + +/* "View.MemoryView":397 + * PyThread_free_lock(self.lock) + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: # <<<<<<<<<<<<<< + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf + */ + +static char *__pyx_memoryview_get_item_pointer(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index) { + Py_ssize_t __pyx_v_dim; + char *__pyx_v_itemp; + PyObject *__pyx_v_idx = NULL; + char *__pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + Py_ssize_t __pyx_t_6; + char *__pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_item_pointer", 1); + + /* "View.MemoryView":399 + * cdef char *get_item_pointer(memoryview self, object index) except NULL: + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf # <<<<<<<<<<<<<< + * + * for dim, idx in enumerate(index): + */ + __pyx_v_itemp = ((char *)__pyx_v_self->view.buf); + + /* "View.MemoryView":401 + * cdef char *itemp = self.view.buf + * + * for dim, idx in enumerate(index): # <<<<<<<<<<<<<< + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + */ + __pyx_t_1 = 0; + if (likely(PyList_CheckExact(__pyx_v_index)) || PyTuple_CheckExact(__pyx_v_index)) { + __pyx_t_2 = __pyx_v_index; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_index); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 401, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 401, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_5); + } + __Pyx_XDECREF_SET(__pyx_v_idx, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_v_dim = __pyx_t_1; + __pyx_t_1 = (__pyx_t_1 + 1); + + /* "View.MemoryView":402 + * + * for dim, idx in enumerate(index): + * itemp = pybuffer_index(&self.view, itemp, idx, dim) # <<<<<<<<<<<<<< + * + * return itemp + */ + __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_v_idx); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 402, __pyx_L1_error) + __pyx_t_7 = __pyx_pybuffer_index((&__pyx_v_self->view), __pyx_v_itemp, __pyx_t_6, __pyx_v_dim); if (unlikely(__pyx_t_7 == ((char *)NULL))) __PYX_ERR(1, 402, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_7; + + /* "View.MemoryView":401 + * cdef char *itemp = self.view.buf + * + * for dim, idx in enumerate(index): # <<<<<<<<<<<<<< + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":404 + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + * return itemp # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_itemp; + goto __pyx_L0; + + /* "View.MemoryView":397 + * PyThread_free_lock(self.lock) + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: # <<<<<<<<<<<<<< + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.get_item_pointer", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_idx); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":407 + * + * + * def __getitem__(memoryview self, object index): # <<<<<<<<<<<<<< + * if index is Ellipsis: + * return self + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index); /*proto*/ +static PyObject *__pyx_memoryview___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((PyObject *)__pyx_v_index)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index) { + PyObject *__pyx_v_have_slices = NULL; + PyObject *__pyx_v_indices = NULL; + char *__pyx_v_itemp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + char *__pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "View.MemoryView":408 + * + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: # <<<<<<<<<<<<<< + * return self + * + */ + __pyx_t_1 = (__pyx_v_index == __pyx_builtin_Ellipsis); + if (__pyx_t_1) { + + /* "View.MemoryView":409 + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: + * return self # <<<<<<<<<<<<<< + * + * have_slices, indices = _unellipsify(index, self.view.ndim) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = ((PyObject *)__pyx_v_self); + goto __pyx_L0; + + /* "View.MemoryView":408 + * + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: # <<<<<<<<<<<<<< + * return self + * + */ + } + + /* "View.MemoryView":411 + * return self + * + * have_slices, indices = _unellipsify(index, self.view.ndim) # <<<<<<<<<<<<<< + * + * cdef char *itemp + */ + __pyx_t_2 = _unellipsify(__pyx_v_index, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (likely(__pyx_t_2 != Py_None)) { + PyObject* sequence = __pyx_t_2; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(1, 411, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else { + __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 411, __pyx_L1_error) + } + __pyx_v_have_slices = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_indices = __pyx_t_4; + __pyx_t_4 = 0; + + /* "View.MemoryView":414 + * + * cdef char *itemp + * if have_slices: # <<<<<<<<<<<<<< + * return memview_slice(self, indices) + * else: + */ + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_have_slices); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 414, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":415 + * cdef char *itemp + * if have_slices: + * return memview_slice(self, indices) # <<<<<<<<<<<<<< + * else: + * itemp = self.get_item_pointer(indices) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = ((PyObject *)__pyx_memview_slice(__pyx_v_self, __pyx_v_indices)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 415, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":414 + * + * cdef char *itemp + * if have_slices: # <<<<<<<<<<<<<< + * return memview_slice(self, indices) + * else: + */ + } + + /* "View.MemoryView":417 + * return memview_slice(self, indices) + * else: + * itemp = self.get_item_pointer(indices) # <<<<<<<<<<<<<< + * return self.convert_item_to_object(itemp) + * + */ + /*else*/ { + __pyx_t_5 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->get_item_pointer(__pyx_v_self, __pyx_v_indices); if (unlikely(__pyx_t_5 == ((char *)NULL))) __PYX_ERR(1, 417, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_5; + + /* "View.MemoryView":418 + * else: + * itemp = self.get_item_pointer(indices) + * return self.convert_item_to_object(itemp) # <<<<<<<<<<<<<< + * + * def __setitem__(memoryview self, object index, object value): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->convert_item_to_object(__pyx_v_self, __pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 418, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":407 + * + * + * def __getitem__(memoryview self, object index): # <<<<<<<<<<<<<< + * if index is Ellipsis: + * return self + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.memoryview.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_have_slices); + __Pyx_XDECREF(__pyx_v_indices); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":420 + * return self.convert_item_to_object(itemp) + * + * def __setitem__(memoryview self, object index, object value): # <<<<<<<<<<<<<< + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" + */ + +/* Python wrapper */ +static int __pyx_memoryview___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /*proto*/ +static int __pyx_memoryview___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((PyObject *)__pyx_v_index), ((PyObject *)__pyx_v_value)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + PyObject *__pyx_v_have_slices = NULL; + PyObject *__pyx_v_obj = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setitem__", 0); + __Pyx_INCREF(__pyx_v_index); + + /* "View.MemoryView":421 + * + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: # <<<<<<<<<<<<<< + * raise TypeError, "Cannot assign to read-only memoryview" + * + */ + if (unlikely(__pyx_v_self->view.readonly)) { + + /* "View.MemoryView":422 + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" # <<<<<<<<<<<<<< + * + * have_slices, index = _unellipsify(index, self.view.ndim) + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_Cannot_assign_to_read_only_memor, 0, 0); + __PYX_ERR(1, 422, __pyx_L1_error) + + /* "View.MemoryView":421 + * + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: # <<<<<<<<<<<<<< + * raise TypeError, "Cannot assign to read-only memoryview" + * + */ + } + + /* "View.MemoryView":424 + * raise TypeError, "Cannot assign to read-only memoryview" + * + * have_slices, index = _unellipsify(index, self.view.ndim) # <<<<<<<<<<<<<< + * + * if have_slices: + */ + __pyx_t_1 = _unellipsify(__pyx_v_index, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(__pyx_t_1 != Py_None)) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(1, 424, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + #else + __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 424, __pyx_L1_error) + } + __pyx_v_have_slices = __pyx_t_2; + __pyx_t_2 = 0; + __Pyx_DECREF_SET(__pyx_v_index, __pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":426 + * have_slices, index = _unellipsify(index, self.view.ndim) + * + * if have_slices: # <<<<<<<<<<<<<< + * obj = self.is_slice(value) + * if obj is not None: + */ + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_have_slices); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(1, 426, __pyx_L1_error) + if (__pyx_t_4) { + + /* "View.MemoryView":427 + * + * if have_slices: + * obj = self.is_slice(value) # <<<<<<<<<<<<<< + * if obj is not None: + * self.setitem_slice_assignment(self[index], obj) + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->is_slice(__pyx_v_self, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_obj = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":428 + * if have_slices: + * obj = self.is_slice(value) + * if obj is not None: # <<<<<<<<<<<<<< + * self.setitem_slice_assignment(self[index], obj) + * else: + */ + __pyx_t_4 = (__pyx_v_obj != Py_None); + if (__pyx_t_4) { + + /* "View.MemoryView":429 + * obj = self.is_slice(value) + * if obj is not None: + * self.setitem_slice_assignment(self[index], obj) # <<<<<<<<<<<<<< + * else: + * self.setitem_slice_assign_scalar(self[index], value) + */ + __pyx_t_1 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_self), __pyx_v_index); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_slice_assignment(__pyx_v_self, __pyx_t_1, __pyx_v_obj); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "View.MemoryView":428 + * if have_slices: + * obj = self.is_slice(value) + * if obj is not None: # <<<<<<<<<<<<<< + * self.setitem_slice_assignment(self[index], obj) + * else: + */ + goto __pyx_L5; + } + + /* "View.MemoryView":431 + * self.setitem_slice_assignment(self[index], obj) + * else: + * self.setitem_slice_assign_scalar(self[index], value) # <<<<<<<<<<<<<< + * else: + * self.setitem_indexed(index, value) + */ + /*else*/ { + __pyx_t_3 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_self), __pyx_v_index); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_memoryview_type))))) __PYX_ERR(1, 431, __pyx_L1_error) + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_slice_assign_scalar(__pyx_v_self, ((struct __pyx_memoryview_obj *)__pyx_t_3), __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_L5:; + + /* "View.MemoryView":426 + * have_slices, index = _unellipsify(index, self.view.ndim) + * + * if have_slices: # <<<<<<<<<<<<<< + * obj = self.is_slice(value) + * if obj is not None: + */ + goto __pyx_L4; + } + + /* "View.MemoryView":433 + * self.setitem_slice_assign_scalar(self[index], value) + * else: + * self.setitem_indexed(index, value) # <<<<<<<<<<<<<< + * + * cdef is_slice(self, obj): + */ + /*else*/ { + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_indexed(__pyx_v_self, __pyx_v_index, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_L4:; + + /* "View.MemoryView":420 + * return self.convert_item_to_object(itemp) + * + * def __setitem__(memoryview self, object index, object value): # <<<<<<<<<<<<<< + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_have_slices); + __Pyx_XDECREF(__pyx_v_obj); + __Pyx_XDECREF(__pyx_v_index); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":435 + * self.setitem_indexed(index, value) + * + * cdef is_slice(self, obj): # <<<<<<<<<<<<<< + * if not isinstance(obj, memoryview): + * try: + */ + +static PyObject *__pyx_memoryview_is_slice(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_slice", 0); + __Pyx_INCREF(__pyx_v_obj); + + /* "View.MemoryView":436 + * + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): # <<<<<<<<<<<<<< + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_obj, __pyx_memoryview_type); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_4, &__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_5); + /*try:*/ { + + /* "View.MemoryView":438 + * if not isinstance(obj, memoryview): + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, # <<<<<<<<<<<<<< + * self.dtype_is_object) + * except TypeError: + */ + __pyx_t_6 = __Pyx_PyInt_From_int(((__pyx_v_self->flags & (~PyBUF_WRITABLE)) | PyBUF_ANY_CONTIGUOUS)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "View.MemoryView":439 + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) # <<<<<<<<<<<<<< + * except TypeError: + * return None + */ + __pyx_t_7 = __Pyx_PyBool_FromLong(__pyx_v_self->dtype_is_object); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 439, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_7); + + /* "View.MemoryView":438 + * if not isinstance(obj, memoryview): + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, # <<<<<<<<<<<<<< + * self.dtype_is_object) + * except TypeError: + */ + __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_INCREF(__pyx_v_obj); + __Pyx_GIVEREF(__pyx_v_obj); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_v_obj)) __PYX_ERR(1, 438, __pyx_L4_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_6)) __PYX_ERR(1, 438, __pyx_L4_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_7)) __PYX_ERR(1, 438, __pyx_L4_error); + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_8, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF_SET(__pyx_v_obj, __pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L9_try_end; + __pyx_L4_error:; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "View.MemoryView":440 + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + * except TypeError: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_9 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_9) { + __Pyx_AddTraceback("View.MemoryView.memoryview.is_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_6) < 0) __PYX_ERR(1, 440, __pyx_L6_except_error) + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_6); + + /* "View.MemoryView":441 + * self.dtype_is_object) + * except TypeError: + * return None # <<<<<<<<<<<<<< + * + * return obj + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L7_except_return; + } + goto __pyx_L6_except_error; + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + __pyx_L6_except_error:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + goto __pyx_L1_error; + __pyx_L7_except_return:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + goto __pyx_L0; + __pyx_L9_try_end:; + } + + /* "View.MemoryView":436 + * + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): # <<<<<<<<<<<<<< + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + */ + } + + /* "View.MemoryView":443 + * return None + * + * return obj # <<<<<<<<<<<<<< + * + * cdef setitem_slice_assignment(self, dst, src): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_obj); + __pyx_r = __pyx_v_obj; + goto __pyx_L0; + + /* "View.MemoryView":435 + * self.setitem_indexed(index, value) + * + * cdef is_slice(self, obj): # <<<<<<<<<<<<<< + * if not isinstance(obj, memoryview): + * try: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_obj); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":445 + * return obj + * + * cdef setitem_slice_assignment(self, dst, src): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + */ + +static PyObject *__pyx_memoryview_setitem_slice_assignment(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_dst, PyObject *__pyx_v_src) { + __Pyx_memviewslice __pyx_v_dst_slice; + __Pyx_memviewslice __pyx_v_src_slice; + __Pyx_memviewslice __pyx_v_msrc; + __Pyx_memviewslice __pyx_v_mdst; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_slice_assignment", 1); + + /* "View.MemoryView":448 + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + * cdef __Pyx_memviewslice msrc = get_slice_from_memview(src, &src_slice)[0] # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] + * + */ + if (!(likely(((__pyx_v_src) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_src, __pyx_memoryview_type))))) __PYX_ERR(1, 448, __pyx_L1_error) + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(((struct __pyx_memoryview_obj *)__pyx_v_src), (&__pyx_v_src_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 448, __pyx_L1_error) + __pyx_v_msrc = (__pyx_t_1[0]); + + /* "View.MemoryView":449 + * cdef __Pyx_memviewslice src_slice + * cdef __Pyx_memviewslice msrc = get_slice_from_memview(src, &src_slice)[0] + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] # <<<<<<<<<<<<<< + * + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + */ + if (!(likely(((__pyx_v_dst) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_dst, __pyx_memoryview_type))))) __PYX_ERR(1, 449, __pyx_L1_error) + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(((struct __pyx_memoryview_obj *)__pyx_v_dst), (&__pyx_v_dst_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 449, __pyx_L1_error) + __pyx_v_mdst = (__pyx_t_1[0]); + + /* "View.MemoryView":451 + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] + * + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) # <<<<<<<<<<<<<< + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_src, __pyx_n_s_ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_dst, __pyx_n_s_ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __pyx_memoryview_copy_contents(__pyx_v_msrc, __pyx_v_mdst, __pyx_t_3, __pyx_t_4, __pyx_v_self->dtype_is_object); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 451, __pyx_L1_error) + + /* "View.MemoryView":445 + * return obj + * + * cdef setitem_slice_assignment(self, dst, src): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_slice_assignment", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":453 + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): # <<<<<<<<<<<<<< + * cdef int array[128] + * cdef void *tmp = NULL + */ + +static PyObject *__pyx_memoryview_setitem_slice_assign_scalar(struct __pyx_memoryview_obj *__pyx_v_self, struct __pyx_memoryview_obj *__pyx_v_dst, PyObject *__pyx_v_value) { + int __pyx_v_array[0x80]; + void *__pyx_v_tmp; + void *__pyx_v_item; + __Pyx_memviewslice *__pyx_v_dst_slice; + __Pyx_memviewslice __pyx_v_tmp_slice; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + char const *__pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_slice_assign_scalar", 1); + + /* "View.MemoryView":455 + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): + * cdef int array[128] + * cdef void *tmp = NULL # <<<<<<<<<<<<<< + * cdef void *item + * + */ + __pyx_v_tmp = NULL; + + /* "View.MemoryView":460 + * cdef __Pyx_memviewslice *dst_slice + * cdef __Pyx_memviewslice tmp_slice + * dst_slice = get_slice_from_memview(dst, &tmp_slice) # <<<<<<<<<<<<<< + * + * if self.view.itemsize > sizeof(array): + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_dst, (&__pyx_v_tmp_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 460, __pyx_L1_error) + __pyx_v_dst_slice = __pyx_t_1; + + /* "View.MemoryView":462 + * dst_slice = get_slice_from_memview(dst, &tmp_slice) + * + * if self.view.itemsize > sizeof(array): # <<<<<<<<<<<<<< + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + */ + __pyx_t_2 = (((size_t)__pyx_v_self->view.itemsize) > (sizeof(__pyx_v_array))); + if (__pyx_t_2) { + + /* "View.MemoryView":463 + * + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) # <<<<<<<<<<<<<< + * if tmp == NULL: + * raise MemoryError + */ + __pyx_v_tmp = PyMem_Malloc(__pyx_v_self->view.itemsize); + + /* "View.MemoryView":464 + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * item = tmp + */ + __pyx_t_2 = (__pyx_v_tmp == NULL); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":465 + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + * raise MemoryError # <<<<<<<<<<<<<< + * item = tmp + * else: + */ + PyErr_NoMemory(); __PYX_ERR(1, 465, __pyx_L1_error) + + /* "View.MemoryView":464 + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * item = tmp + */ + } + + /* "View.MemoryView":466 + * if tmp == NULL: + * raise MemoryError + * item = tmp # <<<<<<<<<<<<<< + * else: + * item = array + */ + __pyx_v_item = __pyx_v_tmp; + + /* "View.MemoryView":462 + * dst_slice = get_slice_from_memview(dst, &tmp_slice) + * + * if self.view.itemsize > sizeof(array): # <<<<<<<<<<<<<< + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":468 + * item = tmp + * else: + * item = array # <<<<<<<<<<<<<< + * + * try: + */ + /*else*/ { + __pyx_v_item = ((void *)__pyx_v_array); + } + __pyx_L3:; + + /* "View.MemoryView":470 + * item = array + * + * try: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * ( item)[0] = value + */ + /*try:*/ { + + /* "View.MemoryView":471 + * + * try: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * ( item)[0] = value + * else: + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":472 + * try: + * if self.dtype_is_object: + * ( item)[0] = value # <<<<<<<<<<<<<< + * else: + * self.assign_item_from_object( item, value) + */ + (((PyObject **)__pyx_v_item)[0]) = ((PyObject *)__pyx_v_value); + + /* "View.MemoryView":471 + * + * try: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * ( item)[0] = value + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":474 + * ( item)[0] = value + * else: + * self.assign_item_from_object( item, value) # <<<<<<<<<<<<<< + * + * + */ + /*else*/ { + __pyx_t_3 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->assign_item_from_object(__pyx_v_self, ((char *)__pyx_v_item), __pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 474, __pyx_L6_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L8:; + + /* "View.MemoryView":478 + * + * + * if self.view.suboffsets != NULL: # <<<<<<<<<<<<<< + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + */ + __pyx_t_2 = (__pyx_v_self->view.suboffsets != NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":479 + * + * if self.view.suboffsets != NULL: + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) # <<<<<<<<<<<<<< + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + * item, self.dtype_is_object) + */ + __pyx_t_4 = assert_direct_dimensions(__pyx_v_self->view.suboffsets, __pyx_v_self->view.ndim); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 479, __pyx_L6_error) + + /* "View.MemoryView":478 + * + * + * if self.view.suboffsets != NULL: # <<<<<<<<<<<<<< + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + */ + } + + /* "View.MemoryView":480 + * if self.view.suboffsets != NULL: + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, # <<<<<<<<<<<<<< + * item, self.dtype_is_object) + * finally: + */ + __pyx_memoryview_slice_assign_scalar(__pyx_v_dst_slice, __pyx_v_dst->view.ndim, __pyx_v_self->view.itemsize, __pyx_v_item, __pyx_v_self->dtype_is_object); + } + + /* "View.MemoryView":483 + * item, self.dtype_is_object) + * finally: + * PyMem_Free(tmp) # <<<<<<<<<<<<<< + * + * cdef setitem_indexed(self, index, value): + */ + /*finally:*/ { + /*normal exit:*/{ + PyMem_Free(__pyx_v_tmp); + goto __pyx_L7; + } + __pyx_L6_error:; + /*exception exit:*/{ + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_10, &__pyx_t_11, &__pyx_t_12); + if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9) < 0)) __Pyx_ErrFetch(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + __pyx_t_4 = __pyx_lineno; __pyx_t_5 = __pyx_clineno; __pyx_t_6 = __pyx_filename; + { + PyMem_Free(__pyx_v_tmp); + } + if (PY_MAJOR_VERSION >= 3) { + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); + } + __Pyx_XGIVEREF(__pyx_t_7); + __Pyx_XGIVEREF(__pyx_t_8); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_ErrRestore(__pyx_t_7, __pyx_t_8, __pyx_t_9); + __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; + __pyx_lineno = __pyx_t_4; __pyx_clineno = __pyx_t_5; __pyx_filename = __pyx_t_6; + goto __pyx_L1_error; + } + __pyx_L7:; + } + + /* "View.MemoryView":453 + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): # <<<<<<<<<<<<<< + * cdef int array[128] + * cdef void *tmp = NULL + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_slice_assign_scalar", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":485 + * PyMem_Free(tmp) + * + * cdef setitem_indexed(self, index, value): # <<<<<<<<<<<<<< + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) + */ + +static PyObject *__pyx_memoryview_setitem_indexed(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + char *__pyx_v_itemp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + char *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_indexed", 1); + + /* "View.MemoryView":486 + * + * cdef setitem_indexed(self, index, value): + * cdef char *itemp = self.get_item_pointer(index) # <<<<<<<<<<<<<< + * self.assign_item_from_object(itemp, value) + * + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->get_item_pointer(__pyx_v_self, __pyx_v_index); if (unlikely(__pyx_t_1 == ((char *)NULL))) __PYX_ERR(1, 486, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_1; + + /* "View.MemoryView":487 + * cdef setitem_indexed(self, index, value): + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) # <<<<<<<<<<<<<< + * + * cdef convert_item_to_object(self, char *itemp): + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->assign_item_from_object(__pyx_v_self, __pyx_v_itemp, __pyx_v_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":485 + * PyMem_Free(tmp) + * + * cdef setitem_indexed(self, index, value): # <<<<<<<<<<<<<< + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_indexed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":489 + * self.assign_item_from_object(itemp, value) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + +static PyObject *__pyx_memoryview_convert_item_to_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp) { + PyObject *__pyx_v_struct = NULL; + PyObject *__pyx_v_bytesitem = 0; + PyObject *__pyx_v_result = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + unsigned int __pyx_t_8; + Py_ssize_t __pyx_t_9; + int __pyx_t_10; + int __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("convert_item_to_object", 1); + + /* "View.MemoryView":492 + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + * import struct # <<<<<<<<<<<<<< + * cdef bytes bytesitem + * + */ + __pyx_t_1 = __Pyx_ImportDottedModule(__pyx_n_s_struct, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 492, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_struct = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":495 + * cdef bytes bytesitem + * + * bytesitem = itemp[:self.view.itemsize] # <<<<<<<<<<<<<< + * try: + * result = struct.unpack(self.view.format, bytesitem) + */ + __pyx_t_1 = __Pyx_PyBytes_FromStringAndSize(__pyx_v_itemp + 0, __pyx_v_self->view.itemsize - 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 495, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_bytesitem = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_2, &__pyx_t_3, &__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_4); + /*try:*/ { + + /* "View.MemoryView":497 + * bytesitem = itemp[:self.view.itemsize] + * try: + * result = struct.unpack(self.view.format, bytesitem) # <<<<<<<<<<<<<< + * except struct.error: + * raise ValueError, "Unable to convert item to object" + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_unpack); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_8 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_7, __pyx_t_6, __pyx_v_bytesitem}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_8, 2+__pyx_t_8); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __pyx_v_result = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + } + + /* "View.MemoryView":501 + * raise ValueError, "Unable to convert item to object" + * else: + * if len(self.view.format) == 1: # <<<<<<<<<<<<<< + * return result[0] + * return result + */ + /*else:*/ { + __pyx_t_9 = __Pyx_ssize_strlen(__pyx_v_self->view.format); if (unlikely(__pyx_t_9 == ((Py_ssize_t)-1))) __PYX_ERR(1, 501, __pyx_L5_except_error) + __pyx_t_10 = (__pyx_t_9 == 1); + if (__pyx_t_10) { + + /* "View.MemoryView":502 + * else: + * if len(self.view.format) == 1: + * return result[0] # <<<<<<<<<<<<<< + * return result + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_result, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 502, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L6_except_return; + + /* "View.MemoryView":501 + * raise ValueError, "Unable to convert item to object" + * else: + * if len(self.view.format) == 1: # <<<<<<<<<<<<<< + * return result[0] + * return result + */ + } + + /* "View.MemoryView":503 + * if len(self.view.format) == 1: + * return result[0] + * return result # <<<<<<<<<<<<<< + * + * cdef assign_item_from_object(self, char *itemp, object value): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L6_except_return; + } + __pyx_L3_error:; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":498 + * try: + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: # <<<<<<<<<<<<<< + * raise ValueError, "Unable to convert item to object" + * else: + */ + __Pyx_ErrFetch(&__pyx_t_1, &__pyx_t_5, &__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_error); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 498, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_11 = __Pyx_PyErr_GivenExceptionMatches(__pyx_t_1, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_ErrRestore(__pyx_t_1, __pyx_t_5, __pyx_t_6); + __pyx_t_1 = 0; __pyx_t_5 = 0; __pyx_t_6 = 0; + if (__pyx_t_11) { + __Pyx_AddTraceback("View.MemoryView.memoryview.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_5, &__pyx_t_1) < 0) __PYX_ERR(1, 498, __pyx_L5_except_error) + __Pyx_XGOTREF(__pyx_t_6); + __Pyx_XGOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_1); + + /* "View.MemoryView":499 + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + * raise ValueError, "Unable to convert item to object" # <<<<<<<<<<<<<< + * else: + * if len(self.view.format) == 1: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Unable_to_convert_item_to_object, 0, 0); + __PYX_ERR(1, 499, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + __pyx_L5_except_error:; + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_ExceptionReset(__pyx_t_2, __pyx_t_3, __pyx_t_4); + goto __pyx_L1_error; + __pyx_L6_except_return:; + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_ExceptionReset(__pyx_t_2, __pyx_t_3, __pyx_t_4); + goto __pyx_L0; + } + + /* "View.MemoryView":489 + * self.assign_item_from_object(itemp, value) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView.memoryview.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_struct); + __Pyx_XDECREF(__pyx_v_bytesitem); + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":505 + * return result + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + +static PyObject *__pyx_memoryview_assign_item_from_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value) { + PyObject *__pyx_v_struct = NULL; + char __pyx_v_c; + PyObject *__pyx_v_bytesvalue = 0; + Py_ssize_t __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + Py_ssize_t __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + char *__pyx_t_9; + char *__pyx_t_10; + char *__pyx_t_11; + char *__pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("assign_item_from_object", 1); + + /* "View.MemoryView":508 + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + * import struct # <<<<<<<<<<<<<< + * cdef char c + * cdef bytes bytesvalue + */ + __pyx_t_1 = __Pyx_ImportDottedModule(__pyx_n_s_struct, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_struct = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":513 + * cdef Py_ssize_t i + * + * if isinstance(value, tuple): # <<<<<<<<<<<<<< + * bytesvalue = struct.pack(self.view.format, *value) + * else: + */ + __pyx_t_2 = PyTuple_Check(__pyx_v_value); + if (__pyx_t_2) { + + /* "View.MemoryView":514 + * + * if isinstance(value, tuple): + * bytesvalue = struct.pack(self.view.format, *value) # <<<<<<<<<<<<<< + * else: + * bytesvalue = struct.pack(self.view.format, value) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_pack); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PySequence_Tuple(__pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = PyNumber_Add(__pyx_t_4, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_3))) __PYX_ERR(1, 514, __pyx_L1_error) + __pyx_v_bytesvalue = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":513 + * cdef Py_ssize_t i + * + * if isinstance(value, tuple): # <<<<<<<<<<<<<< + * bytesvalue = struct.pack(self.view.format, *value) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":516 + * bytesvalue = struct.pack(self.view.format, *value) + * else: + * bytesvalue = struct.pack(self.view.format, value) # <<<<<<<<<<<<<< + * + * for i, c in enumerate(bytesvalue): + */ + /*else*/ { + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_pack); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_1, __pyx_v_value}; + __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_3))) __PYX_ERR(1, 516, __pyx_L1_error) + __pyx_v_bytesvalue = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "View.MemoryView":518 + * bytesvalue = struct.pack(self.view.format, value) + * + * for i, c in enumerate(bytesvalue): # <<<<<<<<<<<<<< + * itemp[i] = c + * + */ + __pyx_t_7 = 0; + if (unlikely(__pyx_v_bytesvalue == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' is not iterable"); + __PYX_ERR(1, 518, __pyx_L1_error) + } + __Pyx_INCREF(__pyx_v_bytesvalue); + __pyx_t_8 = __pyx_v_bytesvalue; + __pyx_t_10 = PyBytes_AS_STRING(__pyx_t_8); + __pyx_t_11 = (__pyx_t_10 + PyBytes_GET_SIZE(__pyx_t_8)); + for (__pyx_t_12 = __pyx_t_10; __pyx_t_12 < __pyx_t_11; __pyx_t_12++) { + __pyx_t_9 = __pyx_t_12; + __pyx_v_c = (__pyx_t_9[0]); + + /* "View.MemoryView":519 + * + * for i, c in enumerate(bytesvalue): + * itemp[i] = c # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + __pyx_v_i = __pyx_t_7; + + /* "View.MemoryView":518 + * bytesvalue = struct.pack(self.view.format, value) + * + * for i, c in enumerate(bytesvalue): # <<<<<<<<<<<<<< + * itemp[i] = c + * + */ + __pyx_t_7 = (__pyx_t_7 + 1); + + /* "View.MemoryView":519 + * + * for i, c in enumerate(bytesvalue): + * itemp[i] = c # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + (__pyx_v_itemp[__pyx_v_i]) = __pyx_v_c; + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "View.MemoryView":505 + * return result + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memoryview.assign_item_from_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_struct); + __Pyx_XDECREF(__pyx_v_bytesvalue); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":521 + * itemp[i] = c + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + */ + +/* Python wrapper */ +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(struct __pyx_memoryview_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + Py_ssize_t *__pyx_t_3; + char *__pyx_t_4; + void *__pyx_t_5; + int __pyx_t_6; + Py_ssize_t __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + if (unlikely(__pyx_v_info == NULL)) { + PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); + return -1; + } + __Pyx_RefNannySetupContext("__getbuffer__", 0); + __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(__pyx_v_info->obj); + + /* "View.MemoryView":523 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: # <<<<<<<<<<<<<< + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + */ + __pyx_t_2 = ((__pyx_v_flags & PyBUF_WRITABLE) != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_1 = __pyx_v_self->view.readonly; + __pyx_L4_bool_binop_done:; + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":524 + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + * raise ValueError, "Cannot create writable memory view from read-only memoryview" # <<<<<<<<<<<<<< + * + * if flags & PyBUF_ND: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Cannot_create_writable_memory_vi, 0, 0); + __PYX_ERR(1, 524, __pyx_L1_error) + + /* "View.MemoryView":523 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: # <<<<<<<<<<<<<< + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + */ + } + + /* "View.MemoryView":526 + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + * if flags & PyBUF_ND: # <<<<<<<<<<<<<< + * info.shape = self.view.shape + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_ND) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":527 + * + * if flags & PyBUF_ND: + * info.shape = self.view.shape # <<<<<<<<<<<<<< + * else: + * info.shape = NULL + */ + __pyx_t_3 = __pyx_v_self->view.shape; + __pyx_v_info->shape = __pyx_t_3; + + /* "View.MemoryView":526 + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + * if flags & PyBUF_ND: # <<<<<<<<<<<<<< + * info.shape = self.view.shape + * else: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":529 + * info.shape = self.view.shape + * else: + * info.shape = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_STRIDES: + */ + /*else*/ { + __pyx_v_info->shape = NULL; + } + __pyx_L6:; + + /* "View.MemoryView":531 + * info.shape = NULL + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.strides = self.view.strides + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_STRIDES) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":532 + * + * if flags & PyBUF_STRIDES: + * info.strides = self.view.strides # <<<<<<<<<<<<<< + * else: + * info.strides = NULL + */ + __pyx_t_3 = __pyx_v_self->view.strides; + __pyx_v_info->strides = __pyx_t_3; + + /* "View.MemoryView":531 + * info.shape = NULL + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.strides = self.view.strides + * else: + */ + goto __pyx_L7; + } + + /* "View.MemoryView":534 + * info.strides = self.view.strides + * else: + * info.strides = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_INDIRECT: + */ + /*else*/ { + __pyx_v_info->strides = NULL; + } + __pyx_L7:; + + /* "View.MemoryView":536 + * info.strides = NULL + * + * if flags & PyBUF_INDIRECT: # <<<<<<<<<<<<<< + * info.suboffsets = self.view.suboffsets + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_INDIRECT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":537 + * + * if flags & PyBUF_INDIRECT: + * info.suboffsets = self.view.suboffsets # <<<<<<<<<<<<<< + * else: + * info.suboffsets = NULL + */ + __pyx_t_3 = __pyx_v_self->view.suboffsets; + __pyx_v_info->suboffsets = __pyx_t_3; + + /* "View.MemoryView":536 + * info.strides = NULL + * + * if flags & PyBUF_INDIRECT: # <<<<<<<<<<<<<< + * info.suboffsets = self.view.suboffsets + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":539 + * info.suboffsets = self.view.suboffsets + * else: + * info.suboffsets = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_FORMAT: + */ + /*else*/ { + __pyx_v_info->suboffsets = NULL; + } + __pyx_L8:; + + /* "View.MemoryView":541 + * info.suboffsets = NULL + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * info.format = self.view.format + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":542 + * + * if flags & PyBUF_FORMAT: + * info.format = self.view.format # <<<<<<<<<<<<<< + * else: + * info.format = NULL + */ + __pyx_t_4 = __pyx_v_self->view.format; + __pyx_v_info->format = __pyx_t_4; + + /* "View.MemoryView":541 + * info.suboffsets = NULL + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * info.format = self.view.format + * else: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":544 + * info.format = self.view.format + * else: + * info.format = NULL # <<<<<<<<<<<<<< + * + * info.buf = self.view.buf + */ + /*else*/ { + __pyx_v_info->format = NULL; + } + __pyx_L9:; + + /* "View.MemoryView":546 + * info.format = NULL + * + * info.buf = self.view.buf # <<<<<<<<<<<<<< + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize + */ + __pyx_t_5 = __pyx_v_self->view.buf; + __pyx_v_info->buf = __pyx_t_5; + + /* "View.MemoryView":547 + * + * info.buf = self.view.buf + * info.ndim = self.view.ndim # <<<<<<<<<<<<<< + * info.itemsize = self.view.itemsize + * info.len = self.view.len + */ + __pyx_t_6 = __pyx_v_self->view.ndim; + __pyx_v_info->ndim = __pyx_t_6; + + /* "View.MemoryView":548 + * info.buf = self.view.buf + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize # <<<<<<<<<<<<<< + * info.len = self.view.len + * info.readonly = self.view.readonly + */ + __pyx_t_7 = __pyx_v_self->view.itemsize; + __pyx_v_info->itemsize = __pyx_t_7; + + /* "View.MemoryView":549 + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize + * info.len = self.view.len # <<<<<<<<<<<<<< + * info.readonly = self.view.readonly + * info.obj = self + */ + __pyx_t_7 = __pyx_v_self->view.len; + __pyx_v_info->len = __pyx_t_7; + + /* "View.MemoryView":550 + * info.itemsize = self.view.itemsize + * info.len = self.view.len + * info.readonly = self.view.readonly # <<<<<<<<<<<<<< + * info.obj = self + * + */ + __pyx_t_1 = __pyx_v_self->view.readonly; + __pyx_v_info->readonly = __pyx_t_1; + + /* "View.MemoryView":551 + * info.len = self.view.len + * info.readonly = self.view.readonly + * info.obj = self # <<<<<<<<<<<<<< + * + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); + __pyx_v_info->obj = ((PyObject *)__pyx_v_self); + + /* "View.MemoryView":521 + * itemp[i] = c + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + if (__pyx_v_info->obj != NULL) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + goto __pyx_L2; + __pyx_L0:; + if (__pyx_v_info->obj == Py_None) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + __pyx_L2:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":554 + * + * + * @property # <<<<<<<<<<<<<< + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + struct __pyx_memoryviewslice_obj *__pyx_v_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":556 + * @property + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) # <<<<<<<<<<<<<< + * transpose_memslice(&result.from_slice) + * return result + */ + __pyx_t_1 = __pyx_memoryview_copy_object(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 556, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_memoryviewslice_type))))) __PYX_ERR(1, 556, __pyx_L1_error) + __pyx_v_result = ((struct __pyx_memoryviewslice_obj *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":557 + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + * transpose_memslice(&result.from_slice) # <<<<<<<<<<<<<< + * return result + * + */ + __pyx_t_2 = __pyx_memslice_transpose((&__pyx_v_result->from_slice)); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(1, 557, __pyx_L1_error) + + /* "View.MemoryView":558 + * cdef _memoryviewslice result = memoryview_copy(self) + * transpose_memslice(&result.from_slice) + * return result # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":554 + * + * + * @property # <<<<<<<<<<<<<< + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.T.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":560 + * return result + * + * @property # <<<<<<<<<<<<<< + * def base(self): + * return self._get_base() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":562 + * @property + * def base(self): + * return self._get_base() # <<<<<<<<<<<<<< + * + * cdef _get_base(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->_get_base(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 562, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":560 + * return result + * + * @property # <<<<<<<<<<<<<< + * def base(self): + * return self._get_base() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.base.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":564 + * return self._get_base() + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.obj + * + */ + +static PyObject *__pyx_memoryview__get_base(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_get_base", 1); + + /* "View.MemoryView":565 + * + * cdef _get_base(self): + * return self.obj # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->obj); + __pyx_r = __pyx_v_self->obj; + goto __pyx_L0; + + /* "View.MemoryView":564 + * return self._get_base() + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.obj + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":567 + * return self.obj + * + * @property # <<<<<<<<<<<<<< + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_7genexpr__pyx_v_length; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":569 + * @property + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = (__pyx_v_self->view.shape + __pyx_v_self->view.ndim); + for (__pyx_t_4 = __pyx_v_self->view.shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_7genexpr__pyx_v_length = (__pyx_t_2[0]); + __pyx_t_5 = PyInt_FromSsize_t(__pyx_7genexpr__pyx_v_length); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + } /* exit inner scope */ + __pyx_t_5 = PyList_AsTuple(((PyObject*)__pyx_t_1)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "View.MemoryView":567 + * return self.obj + * + * @property # <<<<<<<<<<<<<< + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.shape.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":571 + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def strides(self): + * if self.view.strides == NULL: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_8genexpr1__pyx_v_stride; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + Py_ssize_t *__pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":573 + * @property + * def strides(self): + * if self.view.strides == NULL: # <<<<<<<<<<<<<< + * + * raise ValueError, "Buffer view does not expose strides" + */ + __pyx_t_1 = (__pyx_v_self->view.strides == NULL); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":575 + * if self.view.strides == NULL: + * + * raise ValueError, "Buffer view does not expose strides" # <<<<<<<<<<<<<< + * + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Buffer_view_does_not_expose_stri, 0, 0); + __PYX_ERR(1, 575, __pyx_L1_error) + + /* "View.MemoryView":573 + * @property + * def strides(self): + * if self.view.strides == NULL: # <<<<<<<<<<<<<< + * + * raise ValueError, "Buffer view does not expose strides" + */ + } + + /* "View.MemoryView":577 + * raise ValueError, "Buffer view does not expose strides" + * + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (__pyx_v_self->view.strides + __pyx_v_self->view.ndim); + for (__pyx_t_5 = __pyx_v_self->view.strides; __pyx_t_5 < __pyx_t_4; __pyx_t_5++) { + __pyx_t_3 = __pyx_t_5; + __pyx_8genexpr1__pyx_v_stride = (__pyx_t_3[0]); + __pyx_t_6 = PyInt_FromSsize_t(__pyx_8genexpr1__pyx_v_stride); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } /* exit inner scope */ + __pyx_t_6 = PyList_AsTuple(((PyObject*)__pyx_t_2)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "View.MemoryView":571 + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def strides(self): + * if self.view.strides == NULL: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.memoryview.strides.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":579 + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def suboffsets(self): + * if self.view.suboffsets == NULL: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_8genexpr2__pyx_v_suboffset; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + Py_ssize_t *__pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":581 + * @property + * def suboffsets(self): + * if self.view.suboffsets == NULL: # <<<<<<<<<<<<<< + * return (-1,) * self.view.ndim + * + */ + __pyx_t_1 = (__pyx_v_self->view.suboffsets == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":582 + * def suboffsets(self): + * if self.view.suboffsets == NULL: + * return (-1,) * self.view.ndim # <<<<<<<<<<<<<< + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PySequence_Multiply(__pyx_tuple__4, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":581 + * @property + * def suboffsets(self): + * if self.view.suboffsets == NULL: # <<<<<<<<<<<<<< + * return (-1,) * self.view.ndim + * + */ + } + + /* "View.MemoryView":584 + * return (-1,) * self.view.ndim + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (__pyx_v_self->view.suboffsets + __pyx_v_self->view.ndim); + for (__pyx_t_5 = __pyx_v_self->view.suboffsets; __pyx_t_5 < __pyx_t_4; __pyx_t_5++) { + __pyx_t_3 = __pyx_t_5; + __pyx_8genexpr2__pyx_v_suboffset = (__pyx_t_3[0]); + __pyx_t_6 = PyInt_FromSsize_t(__pyx_8genexpr2__pyx_v_suboffset); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } /* exit inner scope */ + __pyx_t_6 = PyList_AsTuple(((PyObject*)__pyx_t_2)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "View.MemoryView":579 + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def suboffsets(self): + * if self.view.suboffsets == NULL: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.memoryview.suboffsets.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":586 + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def ndim(self): + * return self.view.ndim + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":588 + * @property + * def ndim(self): + * return self.view.ndim # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->view.ndim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 588, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":586 + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def ndim(self): + * return self.view.ndim + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.ndim.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":590 + * return self.view.ndim + * + * @property # <<<<<<<<<<<<<< + * def itemsize(self): + * return self.view.itemsize + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":592 + * @property + * def itemsize(self): + * return self.view.itemsize # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_self->view.itemsize); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":590 + * return self.view.ndim + * + * @property # <<<<<<<<<<<<<< + * def itemsize(self): + * return self.view.itemsize + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.itemsize.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":594 + * return self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def nbytes(self): + * return self.size * self.view.itemsize + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":596 + * @property + * def nbytes(self): + * return self.size * self.view.itemsize # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_self->view.itemsize); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "View.MemoryView":594 + * return self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def nbytes(self): + * return self.size * self.view.itemsize + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.nbytes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":598 + * return self.size * self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def size(self): + * if self._size is None: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_v_result = NULL; + PyObject *__pyx_v_length = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":600 + * @property + * def size(self): + * if self._size is None: # <<<<<<<<<<<<<< + * result = 1 + * + */ + __pyx_t_1 = (__pyx_v_self->_size == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":601 + * def size(self): + * if self._size is None: + * result = 1 # <<<<<<<<<<<<<< + * + * for length in self.view.shape[:self.view.ndim]: + */ + __Pyx_INCREF(__pyx_int_1); + __pyx_v_result = __pyx_int_1; + + /* "View.MemoryView":603 + * result = 1 + * + * for length in self.view.shape[:self.view.ndim]: # <<<<<<<<<<<<<< + * result *= length + * + */ + __pyx_t_3 = (__pyx_v_self->view.shape + __pyx_v_self->view.ndim); + for (__pyx_t_4 = __pyx_v_self->view.shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_t_5 = PyInt_FromSsize_t((__pyx_t_2[0])); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 603, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_5); + __pyx_t_5 = 0; + + /* "View.MemoryView":604 + * + * for length in self.view.shape[:self.view.ndim]: + * result *= length # <<<<<<<<<<<<<< + * + * self._size = result + */ + __pyx_t_5 = PyNumber_InPlaceMultiply(__pyx_v_result, __pyx_v_length); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 604, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_result, __pyx_t_5); + __pyx_t_5 = 0; + } + + /* "View.MemoryView":606 + * result *= length + * + * self._size = result # <<<<<<<<<<<<<< + * + * return self._size + */ + __Pyx_INCREF(__pyx_v_result); + __Pyx_GIVEREF(__pyx_v_result); + __Pyx_GOTREF(__pyx_v_self->_size); + __Pyx_DECREF(__pyx_v_self->_size); + __pyx_v_self->_size = __pyx_v_result; + + /* "View.MemoryView":600 + * @property + * def size(self): + * if self._size is None: # <<<<<<<<<<<<<< + * result = 1 + * + */ + } + + /* "View.MemoryView":608 + * self._size = result + * + * return self._size # <<<<<<<<<<<<<< + * + * def __len__(self): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->_size); + __pyx_r = __pyx_v_self->_size; + goto __pyx_L0; + + /* "View.MemoryView":598 + * return self.size * self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def size(self): + * if self._size is None: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.size.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_v_length); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":610 + * return self._size + * + * def __len__(self): # <<<<<<<<<<<<<< + * if self.view.ndim >= 1: + * return self.view.shape[0] + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_memoryview___len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_memoryview___len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_r; + int __pyx_t_1; + + /* "View.MemoryView":611 + * + * def __len__(self): + * if self.view.ndim >= 1: # <<<<<<<<<<<<<< + * return self.view.shape[0] + * + */ + __pyx_t_1 = (__pyx_v_self->view.ndim >= 1); + if (__pyx_t_1) { + + /* "View.MemoryView":612 + * def __len__(self): + * if self.view.ndim >= 1: + * return self.view.shape[0] # <<<<<<<<<<<<<< + * + * return 0 + */ + __pyx_r = (__pyx_v_self->view.shape[0]); + goto __pyx_L0; + + /* "View.MemoryView":611 + * + * def __len__(self): + * if self.view.ndim >= 1: # <<<<<<<<<<<<<< + * return self.view.shape[0] + * + */ + } + + /* "View.MemoryView":614 + * return self.view.shape[0] + * + * return 0 # <<<<<<<<<<<<<< + * + * def __repr__(self): + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":610 + * return self._size + * + * def __len__(self): # <<<<<<<<<<<<<< + * if self.view.ndim >= 1: + * return self.view.shape[0] + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":616 + * return 0 + * + * def __repr__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__, + * id(self)) + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_memoryview___repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "View.MemoryView":617 + * + * def __repr__(self): + * return "" % (self.base.__class__.__name__, # <<<<<<<<<<<<<< + * id(self)) + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_base); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_name_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":618 + * def __repr__(self): + * return "" % (self.base.__class__.__name__, + * id(self)) # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_id, ((PyObject *)__pyx_v_self)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 618, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "View.MemoryView":617 + * + * def __repr__(self): + * return "" % (self.base.__class__.__name__, # <<<<<<<<<<<<<< + * id(self)) + * + */ + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyString_Format(__pyx_kp_s_MemoryView_of_r_at_0x_x, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":616 + * return 0 + * + * def __repr__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__, + * id(self)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":620 + * id(self)) + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__,) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_memoryview___str__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 1); + + /* "View.MemoryView":621 + * + * def __str__(self): + * return "" % (self.base.__class__.__name__,) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_base); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_name_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_MemoryView_of_r_object, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":620 + * id(self)) + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__,) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":624 + * + * + * def is_c_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_is_c_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_is_c_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_c_contig (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("is_c_contig", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "is_c_contig", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice *__pyx_v_mslice; + __Pyx_memviewslice __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_c_contig", 1); + + /* "View.MemoryView":627 + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) # <<<<<<<<<<<<<< + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_self, (&__pyx_v_tmp)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 627, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":628 + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) + * return slice_is_contig(mslice[0], 'C', self.view.ndim) # <<<<<<<<<<<<<< + * + * def is_f_contig(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_memviewslice_is_contig((__pyx_v_mslice[0]), 'C', __pyx_v_self->view.ndim)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":624 + * + * + * def is_c_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_c_contig", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":630 + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + * def is_f_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_is_f_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_is_f_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_f_contig (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("is_f_contig", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "is_f_contig", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice *__pyx_v_mslice; + __Pyx_memviewslice __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_f_contig", 1); + + /* "View.MemoryView":633 + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) # <<<<<<<<<<<<<< + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_self, (&__pyx_v_tmp)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 633, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":634 + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) + * return slice_is_contig(mslice[0], 'F', self.view.ndim) # <<<<<<<<<<<<<< + * + * def copy(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_memviewslice_is_contig((__pyx_v_mslice[0]), 'F', __pyx_v_self->view.ndim)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":630 + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + * def is_f_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_f_contig", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":636 + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + * def copy(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice __pyx_v_mslice; + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("copy", 1); + + /* "View.MemoryView":638 + * def copy(self): + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS # <<<<<<<<<<<<<< + * + * slice_copy(self, &mslice) + */ + __pyx_v_flags = (__pyx_v_self->flags & (~PyBUF_F_CONTIGUOUS)); + + /* "View.MemoryView":640 + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + * + * slice_copy(self, &mslice) # <<<<<<<<<<<<<< + * mslice = slice_copy_contig(&mslice, "c", self.view.ndim, + * self.view.itemsize, + */ + __pyx_memoryview_slice_copy(__pyx_v_self, (&__pyx_v_mslice)); + + /* "View.MemoryView":641 + * + * slice_copy(self, &mslice) + * mslice = slice_copy_contig(&mslice, "c", self.view.ndim, # <<<<<<<<<<<<<< + * self.view.itemsize, + * flags|PyBUF_C_CONTIGUOUS, + */ + __pyx_t_1 = __pyx_memoryview_copy_new_contig((&__pyx_v_mslice), ((char *)"c"), __pyx_v_self->view.ndim, __pyx_v_self->view.itemsize, (__pyx_v_flags | PyBUF_C_CONTIGUOUS), __pyx_v_self->dtype_is_object); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 641, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":646 + * self.dtype_is_object) + * + * return memoryview_copy_from_slice(self, &mslice) # <<<<<<<<<<<<<< + * + * def copy_fortran(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_copy_object_from_slice(__pyx_v_self, (&__pyx_v_mslice)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":636 + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + * def copy(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.copy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":648 + * return memoryview_copy_from_slice(self, &mslice) + * + * def copy_fortran(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_copy_fortran(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_copy_fortran(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy_fortran (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy_fortran", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy_fortran", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice __pyx_v_src; + __Pyx_memviewslice __pyx_v_dst; + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("copy_fortran", 1); + + /* "View.MemoryView":650 + * def copy_fortran(self): + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS # <<<<<<<<<<<<<< + * + * slice_copy(self, &src) + */ + __pyx_v_flags = (__pyx_v_self->flags & (~PyBUF_C_CONTIGUOUS)); + + /* "View.MemoryView":652 + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + * + * slice_copy(self, &src) # <<<<<<<<<<<<<< + * dst = slice_copy_contig(&src, "fortran", self.view.ndim, + * self.view.itemsize, + */ + __pyx_memoryview_slice_copy(__pyx_v_self, (&__pyx_v_src)); + + /* "View.MemoryView":653 + * + * slice_copy(self, &src) + * dst = slice_copy_contig(&src, "fortran", self.view.ndim, # <<<<<<<<<<<<<< + * self.view.itemsize, + * flags|PyBUF_F_CONTIGUOUS, + */ + __pyx_t_1 = __pyx_memoryview_copy_new_contig((&__pyx_v_src), ((char *)"fortran"), __pyx_v_self->view.ndim, __pyx_v_self->view.itemsize, (__pyx_v_flags | PyBUF_F_CONTIGUOUS), __pyx_v_self->dtype_is_object); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 653, __pyx_L1_error) + __pyx_v_dst = __pyx_t_1; + + /* "View.MemoryView":658 + * self.dtype_is_object) + * + * return memoryview_copy_from_slice(self, &dst) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_copy_object_from_slice(__pyx_v_self, (&__pyx_v_dst)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":648 + * return memoryview_copy_from_slice(self, &mslice) + * + * def copy_fortran(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.copy_fortran", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryview_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryview_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_memoryview___reduce_cython__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryview___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryview_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryview_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.memoryview.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_memoryview_2__setstate_cython__(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryview_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":662 + * + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): # <<<<<<<<<<<<<< + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + */ + +static PyObject *__pyx_memoryview_new(PyObject *__pyx_v_o, int __pyx_v_flags, int __pyx_v_dtype_is_object, __Pyx_TypeInfo *__pyx_v_typeinfo) { + struct __pyx_memoryview_obj *__pyx_v_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_cwrapper", 1); + + /* "View.MemoryView":663 + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): + * cdef memoryview result = memoryview(o, flags, dtype_is_object) # <<<<<<<<<<<<<< + * result.typeinfo = typeinfo + * return result + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_o); + __Pyx_GIVEREF(__pyx_v_o); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_o)) __PYX_ERR(1, 663, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 663, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":664 + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo # <<<<<<<<<<<<<< + * return result + * + */ + __pyx_v_result->typeinfo = __pyx_v_typeinfo; + + /* "View.MemoryView":665 + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + * return result # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_check') + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":662 + * + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): # <<<<<<<<<<<<<< + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview_cwrapper", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":668 + * + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: # <<<<<<<<<<<<<< + * return isinstance(o, memoryview) + * + */ + +static CYTHON_INLINE int __pyx_memoryview_check(PyObject *__pyx_v_o) { + int __pyx_r; + int __pyx_t_1; + + /* "View.MemoryView":669 + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: + * return isinstance(o, memoryview) # <<<<<<<<<<<<<< + * + * cdef tuple _unellipsify(object index, int ndim): + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_o, __pyx_memoryview_type); + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "View.MemoryView":668 + * + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: # <<<<<<<<<<<<<< + * return isinstance(o, memoryview) + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":671 + * return isinstance(o, memoryview) + * + * cdef tuple _unellipsify(object index, int ndim): # <<<<<<<<<<<<<< + * """ + * Replace all ellipses with full slices and fill incomplete indices with + */ + +static PyObject *_unellipsify(PyObject *__pyx_v_index, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_idx; + PyObject *__pyx_v_tup = NULL; + PyObject *__pyx_v_result = NULL; + int __pyx_v_have_slices; + int __pyx_v_seen_ellipsis; + PyObject *__pyx_v_item = NULL; + Py_ssize_t __pyx_v_nslices; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + Py_UCS4 __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_unellipsify", 1); + + /* "View.MemoryView":677 + * """ + * cdef Py_ssize_t idx + * tup = index if isinstance(index, tuple) else (index,) # <<<<<<<<<<<<<< + * + * result = [slice(None)] * ndim + */ + __pyx_t_2 = PyTuple_Check(__pyx_v_index); + if (__pyx_t_2) { + __Pyx_INCREF(((PyObject*)__pyx_v_index)); + __pyx_t_1 = __pyx_v_index; + } else { + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 677, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_index); + __Pyx_GIVEREF(__pyx_v_index); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_index)) __PYX_ERR(1, 677, __pyx_L1_error); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + } + __pyx_v_tup = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":679 + * tup = index if isinstance(index, tuple) else (index,) + * + * result = [slice(None)] * ndim # <<<<<<<<<<<<<< + * have_slices = False + * seen_ellipsis = False + */ + __pyx_t_1 = PyList_New(1 * ((__pyx_v_ndim<0) ? 0:__pyx_v_ndim)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + { Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < __pyx_v_ndim; __pyx_temp++) { + __Pyx_INCREF(__pyx_slice__5); + __Pyx_GIVEREF(__pyx_slice__5); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, __pyx_temp, __pyx_slice__5)) __PYX_ERR(1, 679, __pyx_L1_error); + } + } + __pyx_v_result = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":680 + * + * result = [slice(None)] * ndim + * have_slices = False # <<<<<<<<<<<<<< + * seen_ellipsis = False + * idx = 0 + */ + __pyx_v_have_slices = 0; + + /* "View.MemoryView":681 + * result = [slice(None)] * ndim + * have_slices = False + * seen_ellipsis = False # <<<<<<<<<<<<<< + * idx = 0 + * for item in tup: + */ + __pyx_v_seen_ellipsis = 0; + + /* "View.MemoryView":682 + * have_slices = False + * seen_ellipsis = False + * idx = 0 # <<<<<<<<<<<<<< + * for item in tup: + * if item is Ellipsis: + */ + __pyx_v_idx = 0; + + /* "View.MemoryView":683 + * seen_ellipsis = False + * idx = 0 + * for item in tup: # <<<<<<<<<<<<<< + * if item is Ellipsis: + * if not seen_ellipsis: + */ + if (unlikely(__pyx_v_tup == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 683, __pyx_L1_error) + } + __pyx_t_1 = __pyx_v_tup; __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 683, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(1, 683, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 683, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_item, __pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":684 + * idx = 0 + * for item in tup: + * if item is Ellipsis: # <<<<<<<<<<<<<< + * if not seen_ellipsis: + * idx += ndim - len(tup) + */ + __pyx_t_2 = (__pyx_v_item == __pyx_builtin_Ellipsis); + if (__pyx_t_2) { + + /* "View.MemoryView":685 + * for item in tup: + * if item is Ellipsis: + * if not seen_ellipsis: # <<<<<<<<<<<<<< + * idx += ndim - len(tup) + * seen_ellipsis = True + */ + __pyx_t_2 = (!__pyx_v_seen_ellipsis); + if (__pyx_t_2) { + + /* "View.MemoryView":686 + * if item is Ellipsis: + * if not seen_ellipsis: + * idx += ndim - len(tup) # <<<<<<<<<<<<<< + * seen_ellipsis = True + * have_slices = True + */ + if (unlikely(__pyx_v_tup == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 686, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_PyTuple_GET_SIZE(__pyx_v_tup); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(1, 686, __pyx_L1_error) + __pyx_v_idx = (__pyx_v_idx + (__pyx_v_ndim - __pyx_t_5)); + + /* "View.MemoryView":687 + * if not seen_ellipsis: + * idx += ndim - len(tup) + * seen_ellipsis = True # <<<<<<<<<<<<<< + * have_slices = True + * else: + */ + __pyx_v_seen_ellipsis = 1; + + /* "View.MemoryView":685 + * for item in tup: + * if item is Ellipsis: + * if not seen_ellipsis: # <<<<<<<<<<<<<< + * idx += ndim - len(tup) + * seen_ellipsis = True + */ + } + + /* "View.MemoryView":688 + * idx += ndim - len(tup) + * seen_ellipsis = True + * have_slices = True # <<<<<<<<<<<<<< + * else: + * if isinstance(item, slice): + */ + __pyx_v_have_slices = 1; + + /* "View.MemoryView":684 + * idx = 0 + * for item in tup: + * if item is Ellipsis: # <<<<<<<<<<<<<< + * if not seen_ellipsis: + * idx += ndim - len(tup) + */ + goto __pyx_L5; + } + + /* "View.MemoryView":690 + * have_slices = True + * else: + * if isinstance(item, slice): # <<<<<<<<<<<<<< + * have_slices = True + * elif not PyIndex_Check(item): + */ + /*else*/ { + __pyx_t_2 = PySlice_Check(__pyx_v_item); + if (__pyx_t_2) { + + /* "View.MemoryView":691 + * else: + * if isinstance(item, slice): + * have_slices = True # <<<<<<<<<<<<<< + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" + */ + __pyx_v_have_slices = 1; + + /* "View.MemoryView":690 + * have_slices = True + * else: + * if isinstance(item, slice): # <<<<<<<<<<<<<< + * have_slices = True + * elif not PyIndex_Check(item): + */ + goto __pyx_L7; + } + + /* "View.MemoryView":692 + * if isinstance(item, slice): + * have_slices = True + * elif not PyIndex_Check(item): # <<<<<<<<<<<<<< + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + */ + __pyx_t_2 = (!(PyIndex_Check(__pyx_v_item) != 0)); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":693 + * have_slices = True + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" # <<<<<<<<<<<<<< + * result[idx] = item + * idx += 1 + */ + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = 0; + __pyx_t_6 = 127; + __Pyx_INCREF(__pyx_kp_u_Cannot_index_with_type); + __pyx_t_5 += 24; + __Pyx_GIVEREF(__pyx_kp_u_Cannot_index_with_type); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_kp_u_Cannot_index_with_type); + __pyx_t_7 = __Pyx_PyObject_FormatSimple(((PyObject *)Py_TYPE(__pyx_v_item)), __pyx_empty_unicode); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_7) > __pyx_t_6) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_7) : __pyx_t_6; + __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_7); + __pyx_t_7 = 0; + __Pyx_INCREF(__pyx_kp_u__6); + __pyx_t_5 += 1; + __Pyx_GIVEREF(__pyx_kp_u__6); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_kp_u__6); + __pyx_t_7 = __Pyx_PyUnicode_Join(__pyx_t_3, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_t_7, 0, 0); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __PYX_ERR(1, 693, __pyx_L1_error) + + /* "View.MemoryView":692 + * if isinstance(item, slice): + * have_slices = True + * elif not PyIndex_Check(item): # <<<<<<<<<<<<<< + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + */ + } + __pyx_L7:; + + /* "View.MemoryView":694 + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item # <<<<<<<<<<<<<< + * idx += 1 + * + */ + if (unlikely((__Pyx_SetItemInt(__pyx_v_result, __pyx_v_idx, __pyx_v_item, Py_ssize_t, 1, PyInt_FromSsize_t, 1, 1, 1) < 0))) __PYX_ERR(1, 694, __pyx_L1_error) + } + __pyx_L5:; + + /* "View.MemoryView":695 + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + * idx += 1 # <<<<<<<<<<<<<< + * + * nslices = ndim - idx + */ + __pyx_v_idx = (__pyx_v_idx + 1); + + /* "View.MemoryView":683 + * seen_ellipsis = False + * idx = 0 + * for item in tup: # <<<<<<<<<<<<<< + * if item is Ellipsis: + * if not seen_ellipsis: + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "View.MemoryView":697 + * idx += 1 + * + * nslices = ndim - idx # <<<<<<<<<<<<<< + * return have_slices or nslices, tuple(result) + * + */ + __pyx_v_nslices = (__pyx_v_ndim - __pyx_v_idx); + + /* "View.MemoryView":698 + * + * nslices = ndim - idx + * return have_slices or nslices, tuple(result) # <<<<<<<<<<<<<< + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + */ + __Pyx_XDECREF(__pyx_r); + if (!__pyx_v_have_slices) { + } else { + __pyx_t_7 = __Pyx_PyBool_FromLong(__pyx_v_have_slices); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_7 = PyInt_FromSsize_t(__pyx_v_nslices); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __pyx_t_7; + __pyx_t_7 = 0; + __pyx_L9_bool_binop_done:; + __pyx_t_7 = PyList_AsTuple(__pyx_v_result); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(1, 698, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_7 = 0; + __pyx_r = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "View.MemoryView":671 + * return isinstance(o, memoryview) + * + * cdef tuple _unellipsify(object index, int ndim): # <<<<<<<<<<<<<< + * """ + * Replace all ellipses with full slices and fill incomplete indices with + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView._unellipsify", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_tup); + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_v_item); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":700 + * return have_slices or nslices, tuple(result) + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: # <<<<<<<<<<<<<< + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + */ + +static int assert_direct_dimensions(Py_ssize_t *__pyx_v_suboffsets, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_suboffset; + int __pyx_r; + Py_ssize_t *__pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "View.MemoryView":701 + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: # <<<<<<<<<<<<<< + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" + */ + __pyx_t_2 = (__pyx_v_suboffsets + __pyx_v_ndim); + for (__pyx_t_3 = __pyx_v_suboffsets; __pyx_t_3 < __pyx_t_2; __pyx_t_3++) { + __pyx_t_1 = __pyx_t_3; + __pyx_v_suboffset = (__pyx_t_1[0]); + + /* "View.MemoryView":702 + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag + */ + __pyx_t_4 = (__pyx_v_suboffset >= 0); + if (unlikely(__pyx_t_4)) { + + /* "View.MemoryView":703 + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" # <<<<<<<<<<<<<< + * return 0 # return type just used as an error flag + * + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Indirect_dimensions_not_supporte, 0, 0); + __PYX_ERR(1, 703, __pyx_L1_error) + + /* "View.MemoryView":702 + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag + */ + } + } + + /* "View.MemoryView":704 + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":700 + * return have_slices or nslices, tuple(result) + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: # <<<<<<<<<<<<<< + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.assert_direct_dimensions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":711 + * + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): # <<<<<<<<<<<<<< + * cdef int new_ndim = 0, suboffset_dim = -1, dim + * cdef bint negative_step + */ + +static struct __pyx_memoryview_obj *__pyx_memview_slice(struct __pyx_memoryview_obj *__pyx_v_memview, PyObject *__pyx_v_indices) { + int __pyx_v_new_ndim; + int __pyx_v_suboffset_dim; + int __pyx_v_dim; + __Pyx_memviewslice __pyx_v_src; + __Pyx_memviewslice __pyx_v_dst; + __Pyx_memviewslice *__pyx_v_p_src; + struct __pyx_memoryviewslice_obj *__pyx_v_memviewsliceobj = 0; + __Pyx_memviewslice *__pyx_v_p_dst; + int *__pyx_v_p_suboffset_dim; + Py_ssize_t __pyx_v_start; + Py_ssize_t __pyx_v_stop; + Py_ssize_t __pyx_v_step; + Py_ssize_t __pyx_v_cindex; + int __pyx_v_have_start; + int __pyx_v_have_stop; + int __pyx_v_have_step; + PyObject *__pyx_v_index = NULL; + struct __pyx_memoryview_obj *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + struct __pyx_memoryview_obj *__pyx_t_3; + char *__pyx_t_4; + int __pyx_t_5; + Py_ssize_t __pyx_t_6; + PyObject *(*__pyx_t_7)(PyObject *); + PyObject *__pyx_t_8 = NULL; + Py_ssize_t __pyx_t_9; + int __pyx_t_10; + Py_ssize_t __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memview_slice", 1); + + /* "View.MemoryView":712 + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): + * cdef int new_ndim = 0, suboffset_dim = -1, dim # <<<<<<<<<<<<<< + * cdef bint negative_step + * cdef __Pyx_memviewslice src, dst + */ + __pyx_v_new_ndim = 0; + __pyx_v_suboffset_dim = -1; + + /* "View.MemoryView":719 + * + * + * memset(&dst, 0, sizeof(dst)) # <<<<<<<<<<<<<< + * + * cdef _memoryviewslice memviewsliceobj + */ + (void)(memset((&__pyx_v_dst), 0, (sizeof(__pyx_v_dst)))); + + /* "View.MemoryView":723 + * cdef _memoryviewslice memviewsliceobj + * + * assert memview.view.ndim > 0 # <<<<<<<<<<<<<< + * + * if isinstance(memview, _memoryviewslice): + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_1 = (__pyx_v_memview->view.ndim > 0); + if (unlikely(!__pyx_t_1)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(1, 723, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(1, 723, __pyx_L1_error) + #endif + + /* "View.MemoryView":725 + * assert memview.view.ndim > 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":726 + * + * if isinstance(memview, _memoryviewslice): + * memviewsliceobj = memview # <<<<<<<<<<<<<< + * p_src = &memviewsliceobj.from_slice + * else: + */ + if (!(likely(((((PyObject *)__pyx_v_memview)) == Py_None) || likely(__Pyx_TypeTest(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type))))) __PYX_ERR(1, 726, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_v_memview); + __Pyx_INCREF(__pyx_t_2); + __pyx_v_memviewsliceobj = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":727 + * if isinstance(memview, _memoryviewslice): + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice # <<<<<<<<<<<<<< + * else: + * slice_copy(memview, &src) + */ + __pyx_v_p_src = (&__pyx_v_memviewsliceobj->from_slice); + + /* "View.MemoryView":725 + * assert memview.view.ndim > 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice + */ + goto __pyx_L3; + } + + /* "View.MemoryView":729 + * p_src = &memviewsliceobj.from_slice + * else: + * slice_copy(memview, &src) # <<<<<<<<<<<<<< + * p_src = &src + * + */ + /*else*/ { + __pyx_memoryview_slice_copy(__pyx_v_memview, (&__pyx_v_src)); + + /* "View.MemoryView":730 + * else: + * slice_copy(memview, &src) + * p_src = &src # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_p_src = (&__pyx_v_src); + } + __pyx_L3:; + + /* "View.MemoryView":736 + * + * + * dst.memview = p_src.memview # <<<<<<<<<<<<<< + * dst.data = p_src.data + * + */ + __pyx_t_3 = __pyx_v_p_src->memview; + __pyx_v_dst.memview = __pyx_t_3; + + /* "View.MemoryView":737 + * + * dst.memview = p_src.memview + * dst.data = p_src.data # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_4 = __pyx_v_p_src->data; + __pyx_v_dst.data = __pyx_t_4; + + /* "View.MemoryView":742 + * + * + * cdef __Pyx_memviewslice *p_dst = &dst # <<<<<<<<<<<<<< + * cdef int *p_suboffset_dim = &suboffset_dim + * cdef Py_ssize_t start, stop, step, cindex + */ + __pyx_v_p_dst = (&__pyx_v_dst); + + /* "View.MemoryView":743 + * + * cdef __Pyx_memviewslice *p_dst = &dst + * cdef int *p_suboffset_dim = &suboffset_dim # <<<<<<<<<<<<<< + * cdef Py_ssize_t start, stop, step, cindex + * cdef bint have_start, have_stop, have_step + */ + __pyx_v_p_suboffset_dim = (&__pyx_v_suboffset_dim); + + /* "View.MemoryView":747 + * cdef bint have_start, have_stop, have_step + * + * for dim, index in enumerate(indices): # <<<<<<<<<<<<<< + * if PyIndex_Check(index): + * cindex = index + */ + __pyx_t_5 = 0; + if (likely(PyList_CheckExact(__pyx_v_indices)) || PyTuple_CheckExact(__pyx_v_indices)) { + __pyx_t_2 = __pyx_v_indices; __Pyx_INCREF(__pyx_t_2); + __pyx_t_6 = 0; + __pyx_t_7 = NULL; + } else { + __pyx_t_6 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_indices); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 747, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_7)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_8 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_8); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #else + __pyx_t_8 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_8 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_8); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #else + __pyx_t_8 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + #endif + } + } else { + __pyx_t_8 = __pyx_t_7(__pyx_t_2); + if (unlikely(!__pyx_t_8)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 747, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_8); + } + __Pyx_XDECREF_SET(__pyx_v_index, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_v_dim = __pyx_t_5; + __pyx_t_5 = (__pyx_t_5 + 1); + + /* "View.MemoryView":748 + * + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): # <<<<<<<<<<<<<< + * cindex = index + * slice_memviewslice( + */ + __pyx_t_1 = (PyIndex_Check(__pyx_v_index) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":749 + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): + * cindex = index # <<<<<<<<<<<<<< + * slice_memviewslice( + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + */ + __pyx_t_9 = __Pyx_PyIndex_AsSsize_t(__pyx_v_index); if (unlikely((__pyx_t_9 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 749, __pyx_L1_error) + __pyx_v_cindex = __pyx_t_9; + + /* "View.MemoryView":750 + * if PyIndex_Check(index): + * cindex = index + * slice_memviewslice( # <<<<<<<<<<<<<< + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + * dim, new_ndim, p_suboffset_dim, + */ + __pyx_t_10 = __pyx_memoryview_slice_memviewslice(__pyx_v_p_dst, (__pyx_v_p_src->shape[__pyx_v_dim]), (__pyx_v_p_src->strides[__pyx_v_dim]), (__pyx_v_p_src->suboffsets[__pyx_v_dim]), __pyx_v_dim, __pyx_v_new_ndim, __pyx_v_p_suboffset_dim, __pyx_v_cindex, 0, 0, 0, 0, 0, 0); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 750, __pyx_L1_error) + + /* "View.MemoryView":748 + * + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): # <<<<<<<<<<<<<< + * cindex = index + * slice_memviewslice( + */ + goto __pyx_L6; + } + + /* "View.MemoryView":756 + * 0, 0, 0, # have_{start,stop,step} + * False) + * elif index is None: # <<<<<<<<<<<<<< + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + */ + __pyx_t_1 = (__pyx_v_index == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":757 + * False) + * elif index is None: + * p_dst.shape[new_ndim] = 1 # <<<<<<<<<<<<<< + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 + */ + (__pyx_v_p_dst->shape[__pyx_v_new_ndim]) = 1; + + /* "View.MemoryView":758 + * elif index is None: + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 # <<<<<<<<<<<<<< + * p_dst.suboffsets[new_ndim] = -1 + * new_ndim += 1 + */ + (__pyx_v_p_dst->strides[__pyx_v_new_ndim]) = 0; + + /* "View.MemoryView":759 + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 # <<<<<<<<<<<<<< + * new_ndim += 1 + * else: + */ + (__pyx_v_p_dst->suboffsets[__pyx_v_new_ndim]) = -1L; + + /* "View.MemoryView":760 + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 + * new_ndim += 1 # <<<<<<<<<<<<<< + * else: + * start = index.start or 0 + */ + __pyx_v_new_ndim = (__pyx_v_new_ndim + 1); + + /* "View.MemoryView":756 + * 0, 0, 0, # have_{start,stop,step} + * False) + * elif index is None: # <<<<<<<<<<<<<< + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + */ + goto __pyx_L6; + } + + /* "View.MemoryView":762 + * new_ndim += 1 + * else: + * start = index.start or 0 # <<<<<<<<<<<<<< + * stop = index.stop or 0 + * step = index.step or 0 + */ + /*else*/ { + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_start); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 762, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 762, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 762, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L7_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L7_bool_binop_done:; + __pyx_v_start = __pyx_t_9; + + /* "View.MemoryView":763 + * else: + * start = index.start or 0 + * stop = index.stop or 0 # <<<<<<<<<<<<<< + * step = index.step or 0 + * + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_stop); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 763, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 763, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L9_bool_binop_done:; + __pyx_v_stop = __pyx_t_9; + + /* "View.MemoryView":764 + * start = index.start or 0 + * stop = index.stop or 0 + * step = index.step or 0 # <<<<<<<<<<<<<< + * + * have_start = index.start is not None + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_step); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 764, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 764, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L11_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L11_bool_binop_done:; + __pyx_v_step = __pyx_t_9; + + /* "View.MemoryView":766 + * step = index.step or 0 + * + * have_start = index.start is not None # <<<<<<<<<<<<<< + * have_stop = index.stop is not None + * have_step = index.step is not None + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_start); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_start = __pyx_t_1; + + /* "View.MemoryView":767 + * + * have_start = index.start is not None + * have_stop = index.stop is not None # <<<<<<<<<<<<<< + * have_step = index.step is not None + * + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_stop); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 767, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_stop = __pyx_t_1; + + /* "View.MemoryView":768 + * have_start = index.start is not None + * have_stop = index.stop is not None + * have_step = index.step is not None # <<<<<<<<<<<<<< + * + * slice_memviewslice( + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_step); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 768, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_step = __pyx_t_1; + + /* "View.MemoryView":770 + * have_step = index.step is not None + * + * slice_memviewslice( # <<<<<<<<<<<<<< + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + * dim, new_ndim, p_suboffset_dim, + */ + __pyx_t_10 = __pyx_memoryview_slice_memviewslice(__pyx_v_p_dst, (__pyx_v_p_src->shape[__pyx_v_dim]), (__pyx_v_p_src->strides[__pyx_v_dim]), (__pyx_v_p_src->suboffsets[__pyx_v_dim]), __pyx_v_dim, __pyx_v_new_ndim, __pyx_v_p_suboffset_dim, __pyx_v_start, __pyx_v_stop, __pyx_v_step, __pyx_v_have_start, __pyx_v_have_stop, __pyx_v_have_step, 1); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 770, __pyx_L1_error) + + /* "View.MemoryView":776 + * have_start, have_stop, have_step, + * True) + * new_ndim += 1 # <<<<<<<<<<<<<< + * + * if isinstance(memview, _memoryviewslice): + */ + __pyx_v_new_ndim = (__pyx_v_new_ndim + 1); + } + __pyx_L6:; + + /* "View.MemoryView":747 + * cdef bint have_start, have_stop, have_step + * + * for dim, index in enumerate(indices): # <<<<<<<<<<<<<< + * if PyIndex_Check(index): + * cindex = index + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":778 + * new_ndim += 1 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":779 + * + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, # <<<<<<<<<<<<<< + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + + /* "View.MemoryView":780 + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, # <<<<<<<<<<<<<< + * memviewsliceobj.to_dtype_func, + * memview.dtype_is_object) + */ + if (unlikely(!__pyx_v_memviewsliceobj)) { __Pyx_RaiseUnboundLocalError("memviewsliceobj"); __PYX_ERR(1, 780, __pyx_L1_error) } + + /* "View.MemoryView":781 + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * else: + */ + if (unlikely(!__pyx_v_memviewsliceobj)) { __Pyx_RaiseUnboundLocalError("memviewsliceobj"); __PYX_ERR(1, 781, __pyx_L1_error) } + + /* "View.MemoryView":779 + * + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, # <<<<<<<<<<<<<< + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, + */ + __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_dst, __pyx_v_new_ndim, __pyx_v_memviewsliceobj->to_object_func, __pyx_v_memviewsliceobj->to_dtype_func, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_memoryview_type))))) __PYX_ERR(1, 779, __pyx_L1_error) + __pyx_r = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":778 + * new_ndim += 1 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + */ + } + + /* "View.MemoryView":784 + * memview.dtype_is_object) + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * + */ + /*else*/ { + __Pyx_XDECREF((PyObject *)__pyx_r); + + /* "View.MemoryView":785 + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, + * memview.dtype_is_object) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_dst, __pyx_v_new_ndim, NULL, NULL, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 784, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "View.MemoryView":784 + * memview.dtype_is_object) + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * + */ + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_memoryview_type))))) __PYX_ERR(1, 784, __pyx_L1_error) + __pyx_r = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":711 + * + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): # <<<<<<<<<<<<<< + * cdef int new_ndim = 0, suboffset_dim = -1, dim + * cdef bint negative_step + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memview_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_memviewsliceobj); + __Pyx_XDECREF(__pyx_v_index); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":793 + * + * @cname('__pyx_memoryview_slice_memviewslice') + * cdef int slice_memviewslice( # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, + */ + +static int __pyx_memoryview_slice_memviewslice(__Pyx_memviewslice *__pyx_v_dst, Py_ssize_t __pyx_v_shape, Py_ssize_t __pyx_v_stride, Py_ssize_t __pyx_v_suboffset, int __pyx_v_dim, int __pyx_v_new_ndim, int *__pyx_v_suboffset_dim, Py_ssize_t __pyx_v_start, Py_ssize_t __pyx_v_stop, Py_ssize_t __pyx_v_step, int __pyx_v_have_start, int __pyx_v_have_stop, int __pyx_v_have_step, int __pyx_v_is_slice) { + Py_ssize_t __pyx_v_new_shape; + int __pyx_v_negative_step; + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":813 + * cdef bint negative_step + * + * if not is_slice: # <<<<<<<<<<<<<< + * + * if start < 0: + */ + __pyx_t_1 = (!__pyx_v_is_slice); + if (__pyx_t_1) { + + /* "View.MemoryView":815 + * if not is_slice: + * + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if not 0 <= start < shape: + */ + __pyx_t_1 = (__pyx_v_start < 0); + if (__pyx_t_1) { + + /* "View.MemoryView":816 + * + * if start < 0: + * start += shape # <<<<<<<<<<<<<< + * if not 0 <= start < shape: + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + */ + __pyx_v_start = (__pyx_v_start + __pyx_v_shape); + + /* "View.MemoryView":815 + * if not is_slice: + * + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if not 0 <= start < shape: + */ + } + + /* "View.MemoryView":817 + * if start < 0: + * start += shape + * if not 0 <= start < shape: # <<<<<<<<<<<<<< + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + * else: + */ + __pyx_t_1 = (0 <= __pyx_v_start); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_start < __pyx_v_shape); + } + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "View.MemoryView":818 + * start += shape + * if not 0 <= start < shape: + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) # <<<<<<<<<<<<<< + * else: + * + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_IndexError, __pyx_kp_s_Index_out_of_bounds_axis_d, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 818, __pyx_L1_error) + + /* "View.MemoryView":817 + * if start < 0: + * start += shape + * if not 0 <= start < shape: # <<<<<<<<<<<<<< + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + * else: + */ + } + + /* "View.MemoryView":813 + * cdef bint negative_step + * + * if not is_slice: # <<<<<<<<<<<<<< + * + * if start < 0: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":821 + * else: + * + * if have_step: # <<<<<<<<<<<<<< + * negative_step = step < 0 + * if step == 0: + */ + /*else*/ { + __pyx_t_2 = (__pyx_v_have_step != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":822 + * + * if have_step: + * negative_step = step < 0 # <<<<<<<<<<<<<< + * if step == 0: + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + */ + __pyx_v_negative_step = (__pyx_v_step < 0); + + /* "View.MemoryView":823 + * if have_step: + * negative_step = step < 0 + * if step == 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + */ + __pyx_t_2 = (__pyx_v_step == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":824 + * negative_step = step < 0 + * if step == 0: + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) # <<<<<<<<<<<<<< + * else: + * negative_step = False + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_ValueError, __pyx_kp_s_Step_may_not_be_zero_axis_d, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 824, __pyx_L1_error) + + /* "View.MemoryView":823 + * if have_step: + * negative_step = step < 0 + * if step == 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + */ + } + + /* "View.MemoryView":821 + * else: + * + * if have_step: # <<<<<<<<<<<<<< + * negative_step = step < 0 + * if step == 0: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":826 + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + * negative_step = False # <<<<<<<<<<<<<< + * step = 1 + * + */ + /*else*/ { + __pyx_v_negative_step = 0; + + /* "View.MemoryView":827 + * else: + * negative_step = False + * step = 1 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_step = 1; + } + __pyx_L6:; + + /* "View.MemoryView":830 + * + * + * if have_start: # <<<<<<<<<<<<<< + * if start < 0: + * start += shape + */ + __pyx_t_2 = (__pyx_v_have_start != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":831 + * + * if have_start: + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if start < 0: + */ + __pyx_t_2 = (__pyx_v_start < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":832 + * if have_start: + * if start < 0: + * start += shape # <<<<<<<<<<<<<< + * if start < 0: + * start = 0 + */ + __pyx_v_start = (__pyx_v_start + __pyx_v_shape); + + /* "View.MemoryView":833 + * if start < 0: + * start += shape + * if start < 0: # <<<<<<<<<<<<<< + * start = 0 + * elif start >= shape: + */ + __pyx_t_2 = (__pyx_v_start < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":834 + * start += shape + * if start < 0: + * start = 0 # <<<<<<<<<<<<<< + * elif start >= shape: + * if negative_step: + */ + __pyx_v_start = 0; + + /* "View.MemoryView":833 + * if start < 0: + * start += shape + * if start < 0: # <<<<<<<<<<<<<< + * start = 0 + * elif start >= shape: + */ + } + + /* "View.MemoryView":831 + * + * if have_start: + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if start < 0: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":835 + * if start < 0: + * start = 0 + * elif start >= shape: # <<<<<<<<<<<<<< + * if negative_step: + * start = shape - 1 + */ + __pyx_t_2 = (__pyx_v_start >= __pyx_v_shape); + if (__pyx_t_2) { + + /* "View.MemoryView":836 + * start = 0 + * elif start >= shape: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + if (__pyx_v_negative_step) { + + /* "View.MemoryView":837 + * elif start >= shape: + * if negative_step: + * start = shape - 1 # <<<<<<<<<<<<<< + * else: + * start = shape + */ + __pyx_v_start = (__pyx_v_shape - 1); + + /* "View.MemoryView":836 + * start = 0 + * elif start >= shape: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + goto __pyx_L11; + } + + /* "View.MemoryView":839 + * start = shape - 1 + * else: + * start = shape # <<<<<<<<<<<<<< + * else: + * if negative_step: + */ + /*else*/ { + __pyx_v_start = __pyx_v_shape; + } + __pyx_L11:; + + /* "View.MemoryView":835 + * if start < 0: + * start = 0 + * elif start >= shape: # <<<<<<<<<<<<<< + * if negative_step: + * start = shape - 1 + */ + } + __pyx_L9:; + + /* "View.MemoryView":830 + * + * + * if have_start: # <<<<<<<<<<<<<< + * if start < 0: + * start += shape + */ + goto __pyx_L8; + } + + /* "View.MemoryView":841 + * start = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + /*else*/ { + if (__pyx_v_negative_step) { + + /* "View.MemoryView":842 + * else: + * if negative_step: + * start = shape - 1 # <<<<<<<<<<<<<< + * else: + * start = 0 + */ + __pyx_v_start = (__pyx_v_shape - 1); + + /* "View.MemoryView":841 + * start = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + goto __pyx_L12; + } + + /* "View.MemoryView":844 + * start = shape - 1 + * else: + * start = 0 # <<<<<<<<<<<<<< + * + * if have_stop: + */ + /*else*/ { + __pyx_v_start = 0; + } + __pyx_L12:; + } + __pyx_L8:; + + /* "View.MemoryView":846 + * start = 0 + * + * if have_stop: # <<<<<<<<<<<<<< + * if stop < 0: + * stop += shape + */ + __pyx_t_2 = (__pyx_v_have_stop != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":847 + * + * if have_stop: + * if stop < 0: # <<<<<<<<<<<<<< + * stop += shape + * if stop < 0: + */ + __pyx_t_2 = (__pyx_v_stop < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":848 + * if have_stop: + * if stop < 0: + * stop += shape # <<<<<<<<<<<<<< + * if stop < 0: + * stop = 0 + */ + __pyx_v_stop = (__pyx_v_stop + __pyx_v_shape); + + /* "View.MemoryView":849 + * if stop < 0: + * stop += shape + * if stop < 0: # <<<<<<<<<<<<<< + * stop = 0 + * elif stop > shape: + */ + __pyx_t_2 = (__pyx_v_stop < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":850 + * stop += shape + * if stop < 0: + * stop = 0 # <<<<<<<<<<<<<< + * elif stop > shape: + * stop = shape + */ + __pyx_v_stop = 0; + + /* "View.MemoryView":849 + * if stop < 0: + * stop += shape + * if stop < 0: # <<<<<<<<<<<<<< + * stop = 0 + * elif stop > shape: + */ + } + + /* "View.MemoryView":847 + * + * if have_stop: + * if stop < 0: # <<<<<<<<<<<<<< + * stop += shape + * if stop < 0: + */ + goto __pyx_L14; + } + + /* "View.MemoryView":851 + * if stop < 0: + * stop = 0 + * elif stop > shape: # <<<<<<<<<<<<<< + * stop = shape + * else: + */ + __pyx_t_2 = (__pyx_v_stop > __pyx_v_shape); + if (__pyx_t_2) { + + /* "View.MemoryView":852 + * stop = 0 + * elif stop > shape: + * stop = shape # <<<<<<<<<<<<<< + * else: + * if negative_step: + */ + __pyx_v_stop = __pyx_v_shape; + + /* "View.MemoryView":851 + * if stop < 0: + * stop = 0 + * elif stop > shape: # <<<<<<<<<<<<<< + * stop = shape + * else: + */ + } + __pyx_L14:; + + /* "View.MemoryView":846 + * start = 0 + * + * if have_stop: # <<<<<<<<<<<<<< + * if stop < 0: + * stop += shape + */ + goto __pyx_L13; + } + + /* "View.MemoryView":854 + * stop = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * stop = -1 + * else: + */ + /*else*/ { + if (__pyx_v_negative_step) { + + /* "View.MemoryView":855 + * else: + * if negative_step: + * stop = -1 # <<<<<<<<<<<<<< + * else: + * stop = shape + */ + __pyx_v_stop = -1L; + + /* "View.MemoryView":854 + * stop = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * stop = -1 + * else: + */ + goto __pyx_L16; + } + + /* "View.MemoryView":857 + * stop = -1 + * else: + * stop = shape # <<<<<<<<<<<<<< + * + * + */ + /*else*/ { + __pyx_v_stop = __pyx_v_shape; + } + __pyx_L16:; + } + __pyx_L13:; + + /* "View.MemoryView":861 + * + * with cython.cdivision(True): + * new_shape = (stop - start) // step # <<<<<<<<<<<<<< + * + * if (stop - start) - step * new_shape: + */ + __pyx_v_new_shape = ((__pyx_v_stop - __pyx_v_start) / __pyx_v_step); + + /* "View.MemoryView":863 + * new_shape = (stop - start) // step + * + * if (stop - start) - step * new_shape: # <<<<<<<<<<<<<< + * new_shape += 1 + * + */ + __pyx_t_2 = (((__pyx_v_stop - __pyx_v_start) - (__pyx_v_step * __pyx_v_new_shape)) != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":864 + * + * if (stop - start) - step * new_shape: + * new_shape += 1 # <<<<<<<<<<<<<< + * + * if new_shape < 0: + */ + __pyx_v_new_shape = (__pyx_v_new_shape + 1); + + /* "View.MemoryView":863 + * new_shape = (stop - start) // step + * + * if (stop - start) - step * new_shape: # <<<<<<<<<<<<<< + * new_shape += 1 + * + */ + } + + /* "View.MemoryView":866 + * new_shape += 1 + * + * if new_shape < 0: # <<<<<<<<<<<<<< + * new_shape = 0 + * + */ + __pyx_t_2 = (__pyx_v_new_shape < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":867 + * + * if new_shape < 0: + * new_shape = 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_new_shape = 0; + + /* "View.MemoryView":866 + * new_shape += 1 + * + * if new_shape < 0: # <<<<<<<<<<<<<< + * new_shape = 0 + * + */ + } + + /* "View.MemoryView":870 + * + * + * dst.strides[new_ndim] = stride * step # <<<<<<<<<<<<<< + * dst.shape[new_ndim] = new_shape + * dst.suboffsets[new_ndim] = suboffset + */ + (__pyx_v_dst->strides[__pyx_v_new_ndim]) = (__pyx_v_stride * __pyx_v_step); + + /* "View.MemoryView":871 + * + * dst.strides[new_ndim] = stride * step + * dst.shape[new_ndim] = new_shape # <<<<<<<<<<<<<< + * dst.suboffsets[new_ndim] = suboffset + * + */ + (__pyx_v_dst->shape[__pyx_v_new_ndim]) = __pyx_v_new_shape; + + /* "View.MemoryView":872 + * dst.strides[new_ndim] = stride * step + * dst.shape[new_ndim] = new_shape + * dst.suboffsets[new_ndim] = suboffset # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_dst->suboffsets[__pyx_v_new_ndim]) = __pyx_v_suboffset; + } + __pyx_L3:; + + /* "View.MemoryView":875 + * + * + * if suboffset_dim[0] < 0: # <<<<<<<<<<<<<< + * dst.data += start * stride + * else: + */ + __pyx_t_2 = ((__pyx_v_suboffset_dim[0]) < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":876 + * + * if suboffset_dim[0] < 0: + * dst.data += start * stride # <<<<<<<<<<<<<< + * else: + * dst.suboffsets[suboffset_dim[0]] += start * stride + */ + __pyx_v_dst->data = (__pyx_v_dst->data + (__pyx_v_start * __pyx_v_stride)); + + /* "View.MemoryView":875 + * + * + * if suboffset_dim[0] < 0: # <<<<<<<<<<<<<< + * dst.data += start * stride + * else: + */ + goto __pyx_L19; + } + + /* "View.MemoryView":878 + * dst.data += start * stride + * else: + * dst.suboffsets[suboffset_dim[0]] += start * stride # <<<<<<<<<<<<<< + * + * if suboffset >= 0: + */ + /*else*/ { + __pyx_t_3 = (__pyx_v_suboffset_dim[0]); + (__pyx_v_dst->suboffsets[__pyx_t_3]) = ((__pyx_v_dst->suboffsets[__pyx_t_3]) + (__pyx_v_start * __pyx_v_stride)); + } + __pyx_L19:; + + /* "View.MemoryView":880 + * dst.suboffsets[suboffset_dim[0]] += start * stride + * + * if suboffset >= 0: # <<<<<<<<<<<<<< + * if not is_slice: + * if new_ndim == 0: + */ + __pyx_t_2 = (__pyx_v_suboffset >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":881 + * + * if suboffset >= 0: + * if not is_slice: # <<<<<<<<<<<<<< + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset + */ + __pyx_t_2 = (!__pyx_v_is_slice); + if (__pyx_t_2) { + + /* "View.MemoryView":882 + * if suboffset >= 0: + * if not is_slice: + * if new_ndim == 0: # <<<<<<<<<<<<<< + * dst.data = ( dst.data)[0] + suboffset + * else: + */ + __pyx_t_2 = (__pyx_v_new_ndim == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":883 + * if not is_slice: + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset # <<<<<<<<<<<<<< + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " + */ + __pyx_v_dst->data = ((((char **)__pyx_v_dst->data)[0]) + __pyx_v_suboffset); + + /* "View.MemoryView":882 + * if suboffset >= 0: + * if not is_slice: + * if new_ndim == 0: # <<<<<<<<<<<<<< + * dst.data = ( dst.data)[0] + suboffset + * else: + */ + goto __pyx_L22; + } + + /* "View.MemoryView":885 + * dst.data = ( dst.data)[0] + suboffset + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " # <<<<<<<<<<<<<< + * "must be indexed and not sliced", dim) + * else: + */ + /*else*/ { + + /* "View.MemoryView":886 + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " + * "must be indexed and not sliced", dim) # <<<<<<<<<<<<<< + * else: + * suboffset_dim[0] = new_ndim + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_IndexError, __pyx_kp_s_All_dimensions_preceding_dimensi, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 885, __pyx_L1_error) + } + __pyx_L22:; + + /* "View.MemoryView":881 + * + * if suboffset >= 0: + * if not is_slice: # <<<<<<<<<<<<<< + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset + */ + goto __pyx_L21; + } + + /* "View.MemoryView":888 + * "must be indexed and not sliced", dim) + * else: + * suboffset_dim[0] = new_ndim # <<<<<<<<<<<<<< + * + * return 0 + */ + /*else*/ { + (__pyx_v_suboffset_dim[0]) = __pyx_v_new_ndim; + } + __pyx_L21:; + + /* "View.MemoryView":880 + * dst.suboffsets[suboffset_dim[0]] += start * stride + * + * if suboffset >= 0: # <<<<<<<<<<<<<< + * if not is_slice: + * if new_ndim == 0: + */ + } + + /* "View.MemoryView":890 + * suboffset_dim[0] = new_ndim + * + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":793 + * + * @cname('__pyx_memoryview_slice_memviewslice') + * cdef int slice_memviewslice( # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.slice_memviewslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":896 + * + * @cname('__pyx_pybuffer_index') + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, # <<<<<<<<<<<<<< + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + */ + +static char *__pyx_pybuffer_index(Py_buffer *__pyx_v_view, char *__pyx_v_bufp, Py_ssize_t __pyx_v_index, Py_ssize_t __pyx_v_dim) { + Py_ssize_t __pyx_v_shape; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_v_suboffset; + Py_ssize_t __pyx_v_itemsize; + char *__pyx_v_resultp; + char *__pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_UCS4 __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("pybuffer_index", 1); + + /* "View.MemoryView":898 + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 # <<<<<<<<<<<<<< + * cdef Py_ssize_t itemsize = view.itemsize + * cdef char *resultp + */ + __pyx_v_suboffset = -1L; + + /* "View.MemoryView":899 + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + * cdef Py_ssize_t itemsize = view.itemsize # <<<<<<<<<<<<<< + * cdef char *resultp + * + */ + __pyx_t_1 = __pyx_v_view->itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":902 + * cdef char *resultp + * + * if view.ndim == 0: # <<<<<<<<<<<<<< + * shape = view.len // itemsize + * stride = itemsize + */ + __pyx_t_2 = (__pyx_v_view->ndim == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":903 + * + * if view.ndim == 0: + * shape = view.len // itemsize # <<<<<<<<<<<<<< + * stride = itemsize + * else: + */ + if (unlikely(__pyx_v_itemsize == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 903, __pyx_L1_error) + } + else if (sizeof(Py_ssize_t) == sizeof(long) && (!(((Py_ssize_t)-1) > 0)) && unlikely(__pyx_v_itemsize == (Py_ssize_t)-1) && unlikely(__Pyx_UNARY_NEG_WOULD_OVERFLOW(__pyx_v_view->len))) { + PyErr_SetString(PyExc_OverflowError, "value too large to perform division"); + __PYX_ERR(1, 903, __pyx_L1_error) + } + __pyx_v_shape = __Pyx_div_Py_ssize_t(__pyx_v_view->len, __pyx_v_itemsize); + + /* "View.MemoryView":904 + * if view.ndim == 0: + * shape = view.len // itemsize + * stride = itemsize # <<<<<<<<<<<<<< + * else: + * shape = view.shape[dim] + */ + __pyx_v_stride = __pyx_v_itemsize; + + /* "View.MemoryView":902 + * cdef char *resultp + * + * if view.ndim == 0: # <<<<<<<<<<<<<< + * shape = view.len // itemsize + * stride = itemsize + */ + goto __pyx_L3; + } + + /* "View.MemoryView":906 + * stride = itemsize + * else: + * shape = view.shape[dim] # <<<<<<<<<<<<<< + * stride = view.strides[dim] + * if view.suboffsets != NULL: + */ + /*else*/ { + __pyx_v_shape = (__pyx_v_view->shape[__pyx_v_dim]); + + /* "View.MemoryView":907 + * else: + * shape = view.shape[dim] + * stride = view.strides[dim] # <<<<<<<<<<<<<< + * if view.suboffsets != NULL: + * suboffset = view.suboffsets[dim] + */ + __pyx_v_stride = (__pyx_v_view->strides[__pyx_v_dim]); + + /* "View.MemoryView":908 + * shape = view.shape[dim] + * stride = view.strides[dim] + * if view.suboffsets != NULL: # <<<<<<<<<<<<<< + * suboffset = view.suboffsets[dim] + * + */ + __pyx_t_2 = (__pyx_v_view->suboffsets != NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":909 + * stride = view.strides[dim] + * if view.suboffsets != NULL: + * suboffset = view.suboffsets[dim] # <<<<<<<<<<<<<< + * + * if index < 0: + */ + __pyx_v_suboffset = (__pyx_v_view->suboffsets[__pyx_v_dim]); + + /* "View.MemoryView":908 + * shape = view.shape[dim] + * stride = view.strides[dim] + * if view.suboffsets != NULL: # <<<<<<<<<<<<<< + * suboffset = view.suboffsets[dim] + * + */ + } + } + __pyx_L3:; + + /* "View.MemoryView":911 + * suboffset = view.suboffsets[dim] + * + * if index < 0: # <<<<<<<<<<<<<< + * index += view.shape[dim] + * if index < 0: + */ + __pyx_t_2 = (__pyx_v_index < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":912 + * + * if index < 0: + * index += view.shape[dim] # <<<<<<<<<<<<<< + * if index < 0: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + */ + __pyx_v_index = (__pyx_v_index + (__pyx_v_view->shape[__pyx_v_dim])); + + /* "View.MemoryView":913 + * if index < 0: + * index += view.shape[dim] + * if index < 0: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + __pyx_t_2 = (__pyx_v_index < 0); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":914 + * index += view.shape[dim] + * if index < 0: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" # <<<<<<<<<<<<<< + * + * if index >= shape: + */ + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = 0; + __pyx_t_4 = 127; + __Pyx_INCREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_1 += 37; + __Pyx_GIVEREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_5 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_1 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_kp_u__7); + __pyx_t_5 = __Pyx_PyUnicode_Join(__pyx_t_3, 3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_5, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(1, 914, __pyx_L1_error) + + /* "View.MemoryView":913 + * if index < 0: + * index += view.shape[dim] + * if index < 0: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + } + + /* "View.MemoryView":911 + * suboffset = view.suboffsets[dim] + * + * if index < 0: # <<<<<<<<<<<<<< + * index += view.shape[dim] + * if index < 0: + */ + } + + /* "View.MemoryView":916 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * if index >= shape: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + __pyx_t_2 = (__pyx_v_index >= __pyx_v_shape); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":917 + * + * if index >= shape: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" # <<<<<<<<<<<<<< + * + * resultp = bufp + index * stride + */ + __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = 0; + __pyx_t_4 = 127; + __Pyx_INCREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_1 += 37; + __Pyx_GIVEREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_3 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3); + __pyx_t_3 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_1 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_kp_u__7); + __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_5, 3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_3, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 917, __pyx_L1_error) + + /* "View.MemoryView":916 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * if index >= shape: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + } + + /* "View.MemoryView":919 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * resultp = bufp + index * stride # <<<<<<<<<<<<<< + * if suboffset >= 0: + * resultp = ( resultp)[0] + suboffset + */ + __pyx_v_resultp = (__pyx_v_bufp + (__pyx_v_index * __pyx_v_stride)); + + /* "View.MemoryView":920 + * + * resultp = bufp + index * stride + * if suboffset >= 0: # <<<<<<<<<<<<<< + * resultp = ( resultp)[0] + suboffset + * + */ + __pyx_t_2 = (__pyx_v_suboffset >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":921 + * resultp = bufp + index * stride + * if suboffset >= 0: + * resultp = ( resultp)[0] + suboffset # <<<<<<<<<<<<<< + * + * return resultp + */ + __pyx_v_resultp = ((((char **)__pyx_v_resultp)[0]) + __pyx_v_suboffset); + + /* "View.MemoryView":920 + * + * resultp = bufp + index * stride + * if suboffset >= 0: # <<<<<<<<<<<<<< + * resultp = ( resultp)[0] + suboffset + * + */ + } + + /* "View.MemoryView":923 + * resultp = ( resultp)[0] + suboffset + * + * return resultp # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_resultp; + goto __pyx_L0; + + /* "View.MemoryView":896 + * + * @cname('__pyx_pybuffer_index') + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, # <<<<<<<<<<<<<< + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.pybuffer_index", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":929 + * + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: # <<<<<<<<<<<<<< + * cdef int ndim = memslice.memview.view.ndim + * + */ + +static int __pyx_memslice_transpose(__Pyx_memviewslice *__pyx_v_memslice) { + int __pyx_v_ndim; + Py_ssize_t *__pyx_v_shape; + Py_ssize_t *__pyx_v_strides; + int __pyx_v_i; + int __pyx_v_j; + int __pyx_r; + int __pyx_t_1; + Py_ssize_t *__pyx_t_2; + long __pyx_t_3; + long __pyx_t_4; + Py_ssize_t __pyx_t_5; + Py_ssize_t __pyx_t_6; + int __pyx_t_7; + int __pyx_t_8; + int __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":930 + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: + * cdef int ndim = memslice.memview.view.ndim # <<<<<<<<<<<<<< + * + * cdef Py_ssize_t *shape = memslice.shape + */ + __pyx_t_1 = __pyx_v_memslice->memview->view.ndim; + __pyx_v_ndim = __pyx_t_1; + + /* "View.MemoryView":932 + * cdef int ndim = memslice.memview.view.ndim + * + * cdef Py_ssize_t *shape = memslice.shape # <<<<<<<<<<<<<< + * cdef Py_ssize_t *strides = memslice.strides + * + */ + __pyx_t_2 = __pyx_v_memslice->shape; + __pyx_v_shape = __pyx_t_2; + + /* "View.MemoryView":933 + * + * cdef Py_ssize_t *shape = memslice.shape + * cdef Py_ssize_t *strides = memslice.strides # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_v_memslice->strides; + __pyx_v_strides = __pyx_t_2; + + /* "View.MemoryView":937 + * + * cdef int i, j + * for i in range(ndim // 2): # <<<<<<<<<<<<<< + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] + */ + __pyx_t_3 = __Pyx_div_long(__pyx_v_ndim, 2); + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_4; __pyx_t_1+=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":938 + * cdef int i, j + * for i in range(ndim // 2): + * j = ndim - 1 - i # <<<<<<<<<<<<<< + * strides[i], strides[j] = strides[j], strides[i] + * shape[i], shape[j] = shape[j], shape[i] + */ + __pyx_v_j = ((__pyx_v_ndim - 1) - __pyx_v_i); + + /* "View.MemoryView":939 + * for i in range(ndim // 2): + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] # <<<<<<<<<<<<<< + * shape[i], shape[j] = shape[j], shape[i] + * + */ + __pyx_t_5 = (__pyx_v_strides[__pyx_v_j]); + __pyx_t_6 = (__pyx_v_strides[__pyx_v_i]); + (__pyx_v_strides[__pyx_v_i]) = __pyx_t_5; + (__pyx_v_strides[__pyx_v_j]) = __pyx_t_6; + + /* "View.MemoryView":940 + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] + * shape[i], shape[j] = shape[j], shape[i] # <<<<<<<<<<<<<< + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: + */ + __pyx_t_6 = (__pyx_v_shape[__pyx_v_j]); + __pyx_t_5 = (__pyx_v_shape[__pyx_v_i]); + (__pyx_v_shape[__pyx_v_i]) = __pyx_t_6; + (__pyx_v_shape[__pyx_v_j]) = __pyx_t_5; + + /* "View.MemoryView":942 + * shape[i], shape[j] = shape[j], shape[i] + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: # <<<<<<<<<<<<<< + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + */ + __pyx_t_8 = ((__pyx_v_memslice->suboffsets[__pyx_v_i]) >= 0); + if (!__pyx_t_8) { + } else { + __pyx_t_7 = __pyx_t_8; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_8 = ((__pyx_v_memslice->suboffsets[__pyx_v_j]) >= 0); + __pyx_t_7 = __pyx_t_8; + __pyx_L6_bool_binop_done:; + if (__pyx_t_7) { + + /* "View.MemoryView":943 + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") # <<<<<<<<<<<<<< + * + * return 0 + */ + __pyx_t_9 = __pyx_memoryview_err(PyExc_ValueError, __pyx_kp_s_Cannot_transpose_memoryview_with); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(1, 943, __pyx_L1_error) + + /* "View.MemoryView":942 + * shape[i], shape[j] = shape[j], shape[i] + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: # <<<<<<<<<<<<<< + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + */ + } + } + + /* "View.MemoryView":945 + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":929 + * + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: # <<<<<<<<<<<<<< + * cdef int ndim = memslice.memview.view.ndim + * + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.transpose_memslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":963 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + */ + +/* Python wrapper */ +static void __pyx_memoryviewslice___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_memoryviewslice___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(struct __pyx_memoryviewslice_obj *__pyx_v_self) { + + /* "View.MemoryView":964 + * + * def __dealloc__(self): + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) # <<<<<<<<<<<<<< + * + * cdef convert_item_to_object(self, char *itemp): + */ + __PYX_XCLEAR_MEMVIEW((&__pyx_v_self->from_slice), 1); + + /* "View.MemoryView":963 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + */ + + /* function exit code */ +} + +/* "View.MemoryView":966 + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) + */ + +static PyObject *__pyx_memoryviewslice_convert_item_to_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("convert_item_to_object", 1); + + /* "View.MemoryView":967 + * + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: # <<<<<<<<<<<<<< + * return self.to_object_func(itemp) + * else: + */ + __pyx_t_1 = (__pyx_v_self->to_object_func != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":968 + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) # <<<<<<<<<<<<<< + * else: + * return memoryview.convert_item_to_object(self, itemp) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_v_self->to_object_func(__pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 968, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":967 + * + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: # <<<<<<<<<<<<<< + * return self.to_object_func(itemp) + * else: + */ + } + + /* "View.MemoryView":970 + * return self.to_object_func(itemp) + * else: + * return memoryview.convert_item_to_object(self, itemp) # <<<<<<<<<<<<<< + * + * cdef assign_item_from_object(self, char *itemp, object value): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_convert_item_to_object(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 970, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":966 + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":972 + * return memoryview.convert_item_to_object(self, itemp) + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) + */ + +static PyObject *__pyx_memoryviewslice_assign_item_from_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("assign_item_from_object", 1); + + /* "View.MemoryView":973 + * + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: # <<<<<<<<<<<<<< + * self.to_dtype_func(itemp, value) + * else: + */ + __pyx_t_1 = (__pyx_v_self->to_dtype_func != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":974 + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) # <<<<<<<<<<<<<< + * else: + * memoryview.assign_item_from_object(self, itemp, value) + */ + __pyx_t_2 = __pyx_v_self->to_dtype_func(__pyx_v_itemp, __pyx_v_value); if (unlikely(__pyx_t_2 == ((int)0))) __PYX_ERR(1, 974, __pyx_L1_error) + + /* "View.MemoryView":973 + * + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: # <<<<<<<<<<<<<< + * self.to_dtype_func(itemp, value) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":976 + * self.to_dtype_func(itemp, value) + * else: + * memoryview.assign_item_from_object(self, itemp, value) # <<<<<<<<<<<<<< + * + * cdef _get_base(self): + */ + /*else*/ { + __pyx_t_3 = __pyx_memoryview_assign_item_from_object(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_itemp, __pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 976, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "View.MemoryView":972 + * return memoryview.convert_item_to_object(self, itemp) + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.assign_item_from_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":978 + * memoryview.assign_item_from_object(self, itemp, value) + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.from_object + * + */ + +static PyObject *__pyx_memoryviewslice__get_base(struct __pyx_memoryviewslice_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_get_base", 1); + + /* "View.MemoryView":979 + * + * cdef _get_base(self): + * return self.from_object # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->from_object); + __pyx_r = __pyx_v_self->from_object; + goto __pyx_L0; + + /* "View.MemoryView":978 + * memoryview.assign_item_from_object(self, itemp, value) + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.from_object + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryviewslice_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryviewslice_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_memoryviewslice___reduce_cython__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryviewslice___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryviewslice_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryviewslice_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_memoryviewslice_2__setstate_cython__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryviewslice_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":999 + * + * @cname('__pyx_memoryview_fromslice') + * cdef memoryview_fromslice(__Pyx_memviewslice memviewslice, # <<<<<<<<<<<<<< + * int ndim, + * object (*to_object_func)(char *), + */ + +static PyObject *__pyx_memoryview_fromslice(__Pyx_memviewslice __pyx_v_memviewslice, int __pyx_v_ndim, PyObject *(*__pyx_v_to_object_func)(char *), int (*__pyx_v_to_dtype_func)(char *, PyObject *), int __pyx_v_dtype_is_object) { + struct __pyx_memoryviewslice_obj *__pyx_v_result = 0; + Py_ssize_t __pyx_v_suboffset; + PyObject *__pyx_v_length = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + __Pyx_TypeInfo *__pyx_t_4; + Py_buffer __pyx_t_5; + Py_ssize_t *__pyx_t_6; + Py_ssize_t *__pyx_t_7; + Py_ssize_t *__pyx_t_8; + Py_ssize_t __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_fromslice", 1); + + /* "View.MemoryView":1007 + * cdef _memoryviewslice result + * + * if memviewslice.memview == Py_None: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_1 = (((PyObject *)__pyx_v_memviewslice.memview) == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":1008 + * + * if memviewslice.memview == Py_None: + * return None # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "View.MemoryView":1007 + * cdef _memoryviewslice result + * + * if memviewslice.memview == Py_None: # <<<<<<<<<<<<<< + * return None + * + */ + } + + /* "View.MemoryView":1013 + * + * + * result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object) # <<<<<<<<<<<<<< + * + * result.from_slice = memviewslice + */ + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, Py_None)) __PYX_ERR(1, 1013, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_int_0)) __PYX_ERR(1, 1013, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_2 = ((PyObject *)__pyx_tp_new__memoryviewslice(((PyTypeObject *)__pyx_memoryviewslice_type), __pyx_t_3, NULL)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1015 + * result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object) + * + * result.from_slice = memviewslice # <<<<<<<<<<<<<< + * __PYX_INC_MEMVIEW(&memviewslice, 1) + * + */ + __pyx_v_result->from_slice = __pyx_v_memviewslice; + + /* "View.MemoryView":1016 + * + * result.from_slice = memviewslice + * __PYX_INC_MEMVIEW(&memviewslice, 1) # <<<<<<<<<<<<<< + * + * result.from_object = ( memviewslice.memview)._get_base() + */ + __PYX_INC_MEMVIEW((&__pyx_v_memviewslice), 1); + + /* "View.MemoryView":1018 + * __PYX_INC_MEMVIEW(&memviewslice, 1) + * + * result.from_object = ( memviewslice.memview)._get_base() # <<<<<<<<<<<<<< + * result.typeinfo = memviewslice.memview.typeinfo + * + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)->__pyx_vtab)->_get_base(((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1018, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_2); + __Pyx_GOTREF(__pyx_v_result->from_object); + __Pyx_DECREF(__pyx_v_result->from_object); + __pyx_v_result->from_object = __pyx_t_2; + __pyx_t_2 = 0; + + /* "View.MemoryView":1019 + * + * result.from_object = ( memviewslice.memview)._get_base() + * result.typeinfo = memviewslice.memview.typeinfo # <<<<<<<<<<<<<< + * + * result.view = memviewslice.memview.view + */ + __pyx_t_4 = __pyx_v_memviewslice.memview->typeinfo; + __pyx_v_result->__pyx_base.typeinfo = __pyx_t_4; + + /* "View.MemoryView":1021 + * result.typeinfo = memviewslice.memview.typeinfo + * + * result.view = memviewslice.memview.view # <<<<<<<<<<<<<< + * result.view.buf = memviewslice.data + * result.view.ndim = ndim + */ + __pyx_t_5 = __pyx_v_memviewslice.memview->view; + __pyx_v_result->__pyx_base.view = __pyx_t_5; + + /* "View.MemoryView":1022 + * + * result.view = memviewslice.memview.view + * result.view.buf = memviewslice.data # <<<<<<<<<<<<<< + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None + */ + __pyx_v_result->__pyx_base.view.buf = ((void *)__pyx_v_memviewslice.data); + + /* "View.MemoryView":1023 + * result.view = memviewslice.memview.view + * result.view.buf = memviewslice.data + * result.view.ndim = ndim # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &result.view).obj = Py_None + * Py_INCREF(Py_None) + */ + __pyx_v_result->__pyx_base.view.ndim = __pyx_v_ndim; + + /* "View.MemoryView":1024 + * result.view.buf = memviewslice.data + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_result->__pyx_base.view))->obj = Py_None; + + /* "View.MemoryView":1025 + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: + */ + Py_INCREF(Py_None); + + /* "View.MemoryView":1027 + * Py_INCREF(Py_None) + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: # <<<<<<<<<<<<<< + * result.flags = PyBUF_RECORDS + * else: + */ + __pyx_t_1 = ((((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)->flags & PyBUF_WRITABLE) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":1028 + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: + * result.flags = PyBUF_RECORDS # <<<<<<<<<<<<<< + * else: + * result.flags = PyBUF_RECORDS_RO + */ + __pyx_v_result->__pyx_base.flags = PyBUF_RECORDS; + + /* "View.MemoryView":1027 + * Py_INCREF(Py_None) + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: # <<<<<<<<<<<<<< + * result.flags = PyBUF_RECORDS + * else: + */ + goto __pyx_L4; + } + + /* "View.MemoryView":1030 + * result.flags = PyBUF_RECORDS + * else: + * result.flags = PyBUF_RECORDS_RO # <<<<<<<<<<<<<< + * + * result.view.shape = result.from_slice.shape + */ + /*else*/ { + __pyx_v_result->__pyx_base.flags = PyBUF_RECORDS_RO; + } + __pyx_L4:; + + /* "View.MemoryView":1032 + * result.flags = PyBUF_RECORDS_RO + * + * result.view.shape = result.from_slice.shape # <<<<<<<<<<<<<< + * result.view.strides = result.from_slice.strides + * + */ + __pyx_v_result->__pyx_base.view.shape = ((Py_ssize_t *)__pyx_v_result->from_slice.shape); + + /* "View.MemoryView":1033 + * + * result.view.shape = result.from_slice.shape + * result.view.strides = result.from_slice.strides # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_result->__pyx_base.view.strides = ((Py_ssize_t *)__pyx_v_result->from_slice.strides); + + /* "View.MemoryView":1036 + * + * + * result.view.suboffsets = NULL # <<<<<<<<<<<<<< + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: + */ + __pyx_v_result->__pyx_base.view.suboffsets = NULL; + + /* "View.MemoryView":1037 + * + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: # <<<<<<<<<<<<<< + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets + */ + __pyx_t_7 = (__pyx_v_result->from_slice.suboffsets + __pyx_v_ndim); + for (__pyx_t_8 = __pyx_v_result->from_slice.suboffsets; __pyx_t_8 < __pyx_t_7; __pyx_t_8++) { + __pyx_t_6 = __pyx_t_8; + __pyx_v_suboffset = (__pyx_t_6[0]); + + /* "View.MemoryView":1038 + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * result.view.suboffsets = result.from_slice.suboffsets + * break + */ + __pyx_t_1 = (__pyx_v_suboffset >= 0); + if (__pyx_t_1) { + + /* "View.MemoryView":1039 + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_result->__pyx_base.view.suboffsets = ((Py_ssize_t *)__pyx_v_result->from_slice.suboffsets); + + /* "View.MemoryView":1040 + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets + * break # <<<<<<<<<<<<<< + * + * result.view.len = result.view.itemsize + */ + goto __pyx_L6_break; + + /* "View.MemoryView":1038 + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * result.view.suboffsets = result.from_slice.suboffsets + * break + */ + } + } + __pyx_L6_break:; + + /* "View.MemoryView":1042 + * break + * + * result.view.len = result.view.itemsize # <<<<<<<<<<<<<< + * for length in result.view.shape[:ndim]: + * result.view.len *= length + */ + __pyx_t_9 = __pyx_v_result->__pyx_base.view.itemsize; + __pyx_v_result->__pyx_base.view.len = __pyx_t_9; + + /* "View.MemoryView":1043 + * + * result.view.len = result.view.itemsize + * for length in result.view.shape[:ndim]: # <<<<<<<<<<<<<< + * result.view.len *= length + * + */ + __pyx_t_7 = (__pyx_v_result->__pyx_base.view.shape + __pyx_v_ndim); + for (__pyx_t_8 = __pyx_v_result->__pyx_base.view.shape; __pyx_t_8 < __pyx_t_7; __pyx_t_8++) { + __pyx_t_6 = __pyx_t_8; + __pyx_t_2 = PyInt_FromSsize_t((__pyx_t_6[0])); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1043, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1044 + * result.view.len = result.view.itemsize + * for length in result.view.shape[:ndim]: + * result.view.len *= length # <<<<<<<<<<<<<< + * + * result.to_object_func = to_object_func + */ + __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_result->__pyx_base.view.len); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_InPlaceMultiply(__pyx_t_2, __pyx_v_length); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyIndex_AsSsize_t(__pyx_t_3); if (unlikely((__pyx_t_9 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result->__pyx_base.view.len = __pyx_t_9; + } + + /* "View.MemoryView":1046 + * result.view.len *= length + * + * result.to_object_func = to_object_func # <<<<<<<<<<<<<< + * result.to_dtype_func = to_dtype_func + * + */ + __pyx_v_result->to_object_func = __pyx_v_to_object_func; + + /* "View.MemoryView":1047 + * + * result.to_object_func = to_object_func + * result.to_dtype_func = to_dtype_func # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->to_dtype_func = __pyx_v_to_dtype_func; + + /* "View.MemoryView":1049 + * result.to_dtype_func = to_dtype_func + * + * return result # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":999 + * + * @cname('__pyx_memoryview_fromslice') + * cdef memoryview_fromslice(__Pyx_memviewslice memviewslice, # <<<<<<<<<<<<<< + * int ndim, + * object (*to_object_func)(char *), + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview_fromslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XDECREF(__pyx_v_length); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1052 + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + * cdef __Pyx_memviewslice *get_slice_from_memview(memoryview memview, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + */ + +static __Pyx_memviewslice *__pyx_memoryview_get_slice_from_memoryview(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_mslice) { + struct __pyx_memoryviewslice_obj *__pyx_v_obj = 0; + __Pyx_memviewslice *__pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_slice_from_memview", 1); + + /* "View.MemoryView":1055 + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * obj = memview + * return &obj.from_slice + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":1056 + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): + * obj = memview # <<<<<<<<<<<<<< + * return &obj.from_slice + * else: + */ + if (!(likely(((((PyObject *)__pyx_v_memview)) == Py_None) || likely(__Pyx_TypeTest(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type))))) __PYX_ERR(1, 1056, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_v_memview); + __Pyx_INCREF(__pyx_t_2); + __pyx_v_obj = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1057 + * if isinstance(memview, _memoryviewslice): + * obj = memview + * return &obj.from_slice # <<<<<<<<<<<<<< + * else: + * slice_copy(memview, mslice) + */ + __pyx_r = (&__pyx_v_obj->from_slice); + goto __pyx_L0; + + /* "View.MemoryView":1055 + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * obj = memview + * return &obj.from_slice + */ + } + + /* "View.MemoryView":1059 + * return &obj.from_slice + * else: + * slice_copy(memview, mslice) # <<<<<<<<<<<<<< + * return mslice + * + */ + /*else*/ { + __pyx_memoryview_slice_copy(__pyx_v_memview, __pyx_v_mslice); + + /* "View.MemoryView":1060 + * else: + * slice_copy(memview, mslice) + * return mslice # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_slice_copy') + */ + __pyx_r = __pyx_v_mslice; + goto __pyx_L0; + } + + /* "View.MemoryView":1052 + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + * cdef __Pyx_memviewslice *get_slice_from_memview(memoryview memview, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.get_slice_from_memview", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_obj); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1063 + * + * @cname('__pyx_memoryview_slice_copy') + * cdef void slice_copy(memoryview memview, __Pyx_memviewslice *dst) noexcept: # <<<<<<<<<<<<<< + * cdef int dim + * cdef (Py_ssize_t*) shape, strides, suboffsets + */ + +static void __pyx_memoryview_slice_copy(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_dst) { + int __pyx_v_dim; + Py_ssize_t *__pyx_v_shape; + Py_ssize_t *__pyx_v_strides; + Py_ssize_t *__pyx_v_suboffsets; + Py_ssize_t *__pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + Py_ssize_t __pyx_t_5; + int __pyx_t_6; + + /* "View.MemoryView":1067 + * cdef (Py_ssize_t*) shape, strides, suboffsets + * + * shape = memview.view.shape # <<<<<<<<<<<<<< + * strides = memview.view.strides + * suboffsets = memview.view.suboffsets + */ + __pyx_t_1 = __pyx_v_memview->view.shape; + __pyx_v_shape = __pyx_t_1; + + /* "View.MemoryView":1068 + * + * shape = memview.view.shape + * strides = memview.view.strides # <<<<<<<<<<<<<< + * suboffsets = memview.view.suboffsets + * + */ + __pyx_t_1 = __pyx_v_memview->view.strides; + __pyx_v_strides = __pyx_t_1; + + /* "View.MemoryView":1069 + * shape = memview.view.shape + * strides = memview.view.strides + * suboffsets = memview.view.suboffsets # <<<<<<<<<<<<<< + * + * dst.memview = <__pyx_memoryview *> memview + */ + __pyx_t_1 = __pyx_v_memview->view.suboffsets; + __pyx_v_suboffsets = __pyx_t_1; + + /* "View.MemoryView":1071 + * suboffsets = memview.view.suboffsets + * + * dst.memview = <__pyx_memoryview *> memview # <<<<<<<<<<<<<< + * dst.data = memview.view.buf + * + */ + __pyx_v_dst->memview = ((struct __pyx_memoryview_obj *)__pyx_v_memview); + + /* "View.MemoryView":1072 + * + * dst.memview = <__pyx_memoryview *> memview + * dst.data = memview.view.buf # <<<<<<<<<<<<<< + * + * for dim in range(memview.view.ndim): + */ + __pyx_v_dst->data = ((char *)__pyx_v_memview->view.buf); + + /* "View.MemoryView":1074 + * dst.data = memview.view.buf + * + * for dim in range(memview.view.ndim): # <<<<<<<<<<<<<< + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] + */ + __pyx_t_2 = __pyx_v_memview->view.ndim; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_dim = __pyx_t_4; + + /* "View.MemoryView":1075 + * + * for dim in range(memview.view.ndim): + * dst.shape[dim] = shape[dim] # <<<<<<<<<<<<<< + * dst.strides[dim] = strides[dim] + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 + */ + (__pyx_v_dst->shape[__pyx_v_dim]) = (__pyx_v_shape[__pyx_v_dim]); + + /* "View.MemoryView":1076 + * for dim in range(memview.view.ndim): + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] # <<<<<<<<<<<<<< + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 + * + */ + (__pyx_v_dst->strides[__pyx_v_dim]) = (__pyx_v_strides[__pyx_v_dim]); + + /* "View.MemoryView":1077 + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_object') + */ + __pyx_t_6 = (__pyx_v_suboffsets != 0); + if (__pyx_t_6) { + __pyx_t_5 = (__pyx_v_suboffsets[__pyx_v_dim]); + } else { + __pyx_t_5 = -1L; + } + (__pyx_v_dst->suboffsets[__pyx_v_dim]) = __pyx_t_5; + } + + /* "View.MemoryView":1063 + * + * @cname('__pyx_memoryview_slice_copy') + * cdef void slice_copy(memoryview memview, __Pyx_memviewslice *dst) noexcept: # <<<<<<<<<<<<<< + * cdef int dim + * cdef (Py_ssize_t*) shape, strides, suboffsets + */ + + /* function exit code */ +} + +/* "View.MemoryView":1080 + * + * @cname('__pyx_memoryview_copy_object') + * cdef memoryview_copy(memoryview memview): # <<<<<<<<<<<<<< + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + */ + +static PyObject *__pyx_memoryview_copy_object(struct __pyx_memoryview_obj *__pyx_v_memview) { + __Pyx_memviewslice __pyx_v_memviewslice; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_copy", 1); + + /* "View.MemoryView":1083 + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + * slice_copy(memview, &memviewslice) # <<<<<<<<<<<<<< + * return memoryview_copy_from_slice(memview, &memviewslice) + * + */ + __pyx_memoryview_slice_copy(__pyx_v_memview, (&__pyx_v_memviewslice)); + + /* "View.MemoryView":1084 + * cdef __Pyx_memviewslice memviewslice + * slice_copy(memview, &memviewslice) + * return memoryview_copy_from_slice(memview, &memviewslice) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_object_from_slice') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_memoryview_copy_object_from_slice(__pyx_v_memview, (&__pyx_v_memviewslice)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":1080 + * + * @cname('__pyx_memoryview_copy_object') + * cdef memoryview_copy(memoryview memview): # <<<<<<<<<<<<<< + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview_copy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1087 + * + * @cname('__pyx_memoryview_copy_object_from_slice') + * cdef memoryview_copy_from_slice(memoryview memview, __Pyx_memviewslice *memviewslice): # <<<<<<<<<<<<<< + * """ + * Create a new memoryview object from a given memoryview object and slice. + */ + +static PyObject *__pyx_memoryview_copy_object_from_slice(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_memviewslice) { + PyObject *(*__pyx_v_to_object_func)(char *); + int (*__pyx_v_to_dtype_func)(char *, PyObject *); + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *(*__pyx_t_2)(char *); + int (*__pyx_t_3)(char *, PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_copy_from_slice", 1); + + /* "View.MemoryView":1094 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":1095 + * + * if isinstance(memview, _memoryviewslice): + * to_object_func = (<_memoryviewslice> memview).to_object_func # <<<<<<<<<<<<<< + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + * else: + */ + __pyx_t_2 = ((struct __pyx_memoryviewslice_obj *)__pyx_v_memview)->to_object_func; + __pyx_v_to_object_func = __pyx_t_2; + + /* "View.MemoryView":1096 + * if isinstance(memview, _memoryviewslice): + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func # <<<<<<<<<<<<<< + * else: + * to_object_func = NULL + */ + __pyx_t_3 = ((struct __pyx_memoryviewslice_obj *)__pyx_v_memview)->to_dtype_func; + __pyx_v_to_dtype_func = __pyx_t_3; + + /* "View.MemoryView":1094 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1098 + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + * else: + * to_object_func = NULL # <<<<<<<<<<<<<< + * to_dtype_func = NULL + * + */ + /*else*/ { + __pyx_v_to_object_func = NULL; + + /* "View.MemoryView":1099 + * else: + * to_object_func = NULL + * to_dtype_func = NULL # <<<<<<<<<<<<<< + * + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, + */ + __pyx_v_to_dtype_func = NULL; + } + __pyx_L3:; + + /* "View.MemoryView":1101 + * to_dtype_func = NULL + * + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, # <<<<<<<<<<<<<< + * to_object_func, to_dtype_func, + * memview.dtype_is_object) + */ + __Pyx_XDECREF(__pyx_r); + + /* "View.MemoryView":1103 + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, + * to_object_func, to_dtype_func, + * memview.dtype_is_object) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_4 = __pyx_memoryview_fromslice((__pyx_v_memviewslice[0]), __pyx_v_memview->view.ndim, __pyx_v_to_object_func, __pyx_v_to_dtype_func, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "View.MemoryView":1087 + * + * @cname('__pyx_memoryview_copy_object_from_slice') + * cdef memoryview_copy_from_slice(memoryview memview, __Pyx_memviewslice *memviewslice): # <<<<<<<<<<<<<< + * """ + * Create a new memoryview object from a given memoryview object and slice. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.memoryview_copy_from_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1109 + * + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: # <<<<<<<<<<<<<< + * return -arg if arg < 0 else arg + * + */ + +static Py_ssize_t abs_py_ssize_t(Py_ssize_t __pyx_v_arg) { + Py_ssize_t __pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + + /* "View.MemoryView":1110 + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: + * return -arg if arg < 0 else arg # <<<<<<<<<<<<<< + * + * @cname('__pyx_get_best_slice_order') + */ + __pyx_t_2 = (__pyx_v_arg < 0); + if (__pyx_t_2) { + __pyx_t_1 = (-__pyx_v_arg); + } else { + __pyx_t_1 = __pyx_v_arg; + } + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "View.MemoryView":1109 + * + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: # <<<<<<<<<<<<<< + * return -arg if arg < 0 else arg + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1113 + * + * @cname('__pyx_get_best_slice_order') + * cdef char get_best_order(__Pyx_memviewslice *mslice, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * """ + * Figure out the best memory access order for a given slice. + */ + +static char __pyx_get_best_slice_order(__Pyx_memviewslice *__pyx_v_mslice, int __pyx_v_ndim) { + int __pyx_v_i; + Py_ssize_t __pyx_v_c_stride; + Py_ssize_t __pyx_v_f_stride; + char __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1118 + * """ + * cdef int i + * cdef Py_ssize_t c_stride = 0 # <<<<<<<<<<<<<< + * cdef Py_ssize_t f_stride = 0 + * + */ + __pyx_v_c_stride = 0; + + /* "View.MemoryView":1119 + * cdef int i + * cdef Py_ssize_t c_stride = 0 + * cdef Py_ssize_t f_stride = 0 # <<<<<<<<<<<<<< + * + * for i in range(ndim - 1, -1, -1): + */ + __pyx_v_f_stride = 0; + + /* "View.MemoryView":1121 + * cdef Py_ssize_t f_stride = 0 + * + * for i in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] + */ + for (__pyx_t_1 = (__pyx_v_ndim - 1); __pyx_t_1 > -1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":1122 + * + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * c_stride = mslice.strides[i] + * break + */ + __pyx_t_2 = ((__pyx_v_mslice->shape[__pyx_v_i]) > 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1123 + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_c_stride = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1124 + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] + * break # <<<<<<<<<<<<<< + * + * for i in range(ndim): + */ + goto __pyx_L4_break; + + /* "View.MemoryView":1122 + * + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * c_stride = mslice.strides[i] + * break + */ + } + } + __pyx_L4_break:; + + /* "View.MemoryView":1126 + * break + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] + */ + __pyx_t_1 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_1; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1127 + * + * for i in range(ndim): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * f_stride = mslice.strides[i] + * break + */ + __pyx_t_2 = ((__pyx_v_mslice->shape[__pyx_v_i]) > 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1128 + * for i in range(ndim): + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_f_stride = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1129 + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] + * break # <<<<<<<<<<<<<< + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): + */ + goto __pyx_L7_break; + + /* "View.MemoryView":1127 + * + * for i in range(ndim): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * f_stride = mslice.strides[i] + * break + */ + } + } + __pyx_L7_break:; + + /* "View.MemoryView":1131 + * break + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): # <<<<<<<<<<<<<< + * return 'C' + * else: + */ + __pyx_t_2 = (abs_py_ssize_t(__pyx_v_c_stride) <= abs_py_ssize_t(__pyx_v_f_stride)); + if (__pyx_t_2) { + + /* "View.MemoryView":1132 + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): + * return 'C' # <<<<<<<<<<<<<< + * else: + * return 'F' + */ + __pyx_r = 'C'; + goto __pyx_L0; + + /* "View.MemoryView":1131 + * break + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): # <<<<<<<<<<<<<< + * return 'C' + * else: + */ + } + + /* "View.MemoryView":1134 + * return 'C' + * else: + * return 'F' # <<<<<<<<<<<<<< + * + * @cython.cdivision(True) + */ + /*else*/ { + __pyx_r = 'F'; + goto __pyx_L0; + } + + /* "View.MemoryView":1113 + * + * @cname('__pyx_get_best_slice_order') + * cdef char get_best_order(__Pyx_memviewslice *mslice, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * """ + * Figure out the best memory access order for a given slice. + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1137 + * + * @cython.cdivision(True) + * cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, # <<<<<<<<<<<<<< + * char *dst_data, Py_ssize_t *dst_strides, + * Py_ssize_t *src_shape, Py_ssize_t *dst_shape, + */ + +static void _copy_strided_to_strided(char *__pyx_v_src_data, Py_ssize_t *__pyx_v_src_strides, char *__pyx_v_dst_data, Py_ssize_t *__pyx_v_dst_strides, Py_ssize_t *__pyx_v_src_shape, Py_ssize_t *__pyx_v_dst_shape, int __pyx_v_ndim, size_t __pyx_v_itemsize) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + CYTHON_UNUSED Py_ssize_t __pyx_v_src_extent; + Py_ssize_t __pyx_v_dst_extent; + Py_ssize_t __pyx_v_src_stride; + Py_ssize_t __pyx_v_dst_stride; + int __pyx_t_1; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + + /* "View.MemoryView":1144 + * + * cdef Py_ssize_t i + * cdef Py_ssize_t src_extent = src_shape[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] + */ + __pyx_v_src_extent = (__pyx_v_src_shape[0]); + + /* "View.MemoryView":1145 + * cdef Py_ssize_t i + * cdef Py_ssize_t src_extent = src_shape[0] + * cdef Py_ssize_t dst_extent = dst_shape[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t src_stride = src_strides[0] + * cdef Py_ssize_t dst_stride = dst_strides[0] + */ + __pyx_v_dst_extent = (__pyx_v_dst_shape[0]); + + /* "View.MemoryView":1146 + * cdef Py_ssize_t src_extent = src_shape[0] + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + */ + __pyx_v_src_stride = (__pyx_v_src_strides[0]); + + /* "View.MemoryView":1147 + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] + * cdef Py_ssize_t dst_stride = dst_strides[0] # <<<<<<<<<<<<<< + * + * if ndim == 1: + */ + __pyx_v_dst_stride = (__pyx_v_dst_strides[0]); + + /* "View.MemoryView":1149 + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + */ + __pyx_t_1 = (__pyx_v_ndim == 1); + if (__pyx_t_1) { + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + __pyx_t_2 = (__pyx_v_src_stride > 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_dst_stride > 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + + /* "View.MemoryView":1151 + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): # <<<<<<<<<<<<<< + * memcpy(dst_data, src_data, itemsize * dst_extent) + * else: + */ + __pyx_t_2 = (((size_t)__pyx_v_src_stride) == __pyx_v_itemsize); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_itemsize == ((size_t)__pyx_v_dst_stride)); + } + __pyx_t_1 = __pyx_t_2; + __pyx_L5_bool_binop_done:; + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + if (__pyx_t_1) { + + /* "View.MemoryView":1152 + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) # <<<<<<<<<<<<<< + * else: + * for i in range(dst_extent): + */ + (void)(memcpy(__pyx_v_dst_data, __pyx_v_src_data, (__pyx_v_itemsize * __pyx_v_dst_extent))); + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + goto __pyx_L4; + } + + /* "View.MemoryView":1154 + * memcpy(dst_data, src_data, itemsize * dst_extent) + * else: + * for i in range(dst_extent): # <<<<<<<<<<<<<< + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride + */ + /*else*/ { + __pyx_t_3 = __pyx_v_dst_extent; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "View.MemoryView":1155 + * else: + * for i in range(dst_extent): + * memcpy(dst_data, src_data, itemsize) # <<<<<<<<<<<<<< + * src_data += src_stride + * dst_data += dst_stride + */ + (void)(memcpy(__pyx_v_dst_data, __pyx_v_src_data, __pyx_v_itemsize)); + + /* "View.MemoryView":1156 + * for i in range(dst_extent): + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride # <<<<<<<<<<<<<< + * dst_data += dst_stride + * else: + */ + __pyx_v_src_data = (__pyx_v_src_data + __pyx_v_src_stride); + + /* "View.MemoryView":1157 + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride + * dst_data += dst_stride # <<<<<<<<<<<<<< + * else: + * for i in range(dst_extent): + */ + __pyx_v_dst_data = (__pyx_v_dst_data + __pyx_v_dst_stride); + } + } + __pyx_L4:; + + /* "View.MemoryView":1149 + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1159 + * dst_data += dst_stride + * else: + * for i in range(dst_extent): # <<<<<<<<<<<<<< + * _copy_strided_to_strided(src_data, src_strides + 1, + * dst_data, dst_strides + 1, + */ + /*else*/ { + __pyx_t_3 = __pyx_v_dst_extent; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "View.MemoryView":1160 + * else: + * for i in range(dst_extent): + * _copy_strided_to_strided(src_data, src_strides + 1, # <<<<<<<<<<<<<< + * dst_data, dst_strides + 1, + * src_shape + 1, dst_shape + 1, + */ + _copy_strided_to_strided(__pyx_v_src_data, (__pyx_v_src_strides + 1), __pyx_v_dst_data, (__pyx_v_dst_strides + 1), (__pyx_v_src_shape + 1), (__pyx_v_dst_shape + 1), (__pyx_v_ndim - 1), __pyx_v_itemsize); + + /* "View.MemoryView":1164 + * src_shape + 1, dst_shape + 1, + * ndim - 1, itemsize) + * src_data += src_stride # <<<<<<<<<<<<<< + * dst_data += dst_stride + * + */ + __pyx_v_src_data = (__pyx_v_src_data + __pyx_v_src_stride); + + /* "View.MemoryView":1165 + * ndim - 1, itemsize) + * src_data += src_stride + * dst_data += dst_stride # <<<<<<<<<<<<<< + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, + */ + __pyx_v_dst_data = (__pyx_v_dst_data + __pyx_v_dst_stride); + } + } + __pyx_L3:; + + /* "View.MemoryView":1137 + * + * @cython.cdivision(True) + * cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, # <<<<<<<<<<<<<< + * char *dst_data, Py_ssize_t *dst_strides, + * Py_ssize_t *src_shape, Py_ssize_t *dst_shape, + */ + + /* function exit code */ +} + +/* "View.MemoryView":1167 + * dst_data += dst_stride + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + */ + +static void copy_strided_to_strided(__Pyx_memviewslice *__pyx_v_src, __Pyx_memviewslice *__pyx_v_dst, int __pyx_v_ndim, size_t __pyx_v_itemsize) { + + /* "View.MemoryView":1170 + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + * _copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides, # <<<<<<<<<<<<<< + * src.shape, dst.shape, ndim, itemsize) + * + */ + _copy_strided_to_strided(__pyx_v_src->data, __pyx_v_src->strides, __pyx_v_dst->data, __pyx_v_dst->strides, __pyx_v_src->shape, __pyx_v_dst->shape, __pyx_v_ndim, __pyx_v_itemsize); + + /* "View.MemoryView":1167 + * dst_data += dst_stride + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1174 + * + * @cname('__pyx_memoryview_slice_get_size') + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + */ + +static Py_ssize_t __pyx_memoryview_slice_get_size(__Pyx_memviewslice *__pyx_v_src, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_shape; + Py_ssize_t __pyx_v_size; + Py_ssize_t __pyx_r; + Py_ssize_t __pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + + /* "View.MemoryView":1176 + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize # <<<<<<<<<<<<<< + * + * for shape in src.shape[:ndim]: + */ + __pyx_t_1 = __pyx_v_src->memview->view.itemsize; + __pyx_v_size = __pyx_t_1; + + /* "View.MemoryView":1178 + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + * + * for shape in src.shape[:ndim]: # <<<<<<<<<<<<<< + * size *= shape + * + */ + __pyx_t_3 = (__pyx_v_src->shape + __pyx_v_ndim); + for (__pyx_t_4 = __pyx_v_src->shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_v_shape = (__pyx_t_2[0]); + + /* "View.MemoryView":1179 + * + * for shape in src.shape[:ndim]: + * size *= shape # <<<<<<<<<<<<<< + * + * return size + */ + __pyx_v_size = (__pyx_v_size * __pyx_v_shape); + } + + /* "View.MemoryView":1181 + * size *= shape + * + * return size # <<<<<<<<<<<<<< + * + * @cname('__pyx_fill_contig_strides_array') + */ + __pyx_r = __pyx_v_size; + goto __pyx_L0; + + /* "View.MemoryView":1174 + * + * @cname('__pyx_memoryview_slice_get_size') + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1184 + * + * @cname('__pyx_fill_contig_strides_array') + * cdef Py_ssize_t fill_contig_strides_array( # <<<<<<<<<<<<<< + * Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, + * int ndim, char order) noexcept nogil: + */ + +static Py_ssize_t __pyx_fill_contig_strides_array(Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, Py_ssize_t __pyx_v_stride, int __pyx_v_ndim, char __pyx_v_order) { + int __pyx_v_idx; + Py_ssize_t __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1193 + * cdef int idx + * + * if order == 'F': # <<<<<<<<<<<<<< + * for idx in range(ndim): + * strides[idx] = stride + */ + __pyx_t_1 = (__pyx_v_order == 'F'); + if (__pyx_t_1) { + + /* "View.MemoryView":1194 + * + * if order == 'F': + * for idx in range(ndim): # <<<<<<<<<<<<<< + * strides[idx] = stride + * stride *= shape[idx] + */ + __pyx_t_2 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_idx = __pyx_t_4; + + /* "View.MemoryView":1195 + * if order == 'F': + * for idx in range(ndim): + * strides[idx] = stride # <<<<<<<<<<<<<< + * stride *= shape[idx] + * else: + */ + (__pyx_v_strides[__pyx_v_idx]) = __pyx_v_stride; + + /* "View.MemoryView":1196 + * for idx in range(ndim): + * strides[idx] = stride + * stride *= shape[idx] # <<<<<<<<<<<<<< + * else: + * for idx in range(ndim - 1, -1, -1): + */ + __pyx_v_stride = (__pyx_v_stride * (__pyx_v_shape[__pyx_v_idx])); + } + + /* "View.MemoryView":1193 + * cdef int idx + * + * if order == 'F': # <<<<<<<<<<<<<< + * for idx in range(ndim): + * strides[idx] = stride + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1198 + * stride *= shape[idx] + * else: + * for idx in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * strides[idx] = stride + * stride *= shape[idx] + */ + /*else*/ { + for (__pyx_t_2 = (__pyx_v_ndim - 1); __pyx_t_2 > -1; __pyx_t_2-=1) { + __pyx_v_idx = __pyx_t_2; + + /* "View.MemoryView":1199 + * else: + * for idx in range(ndim - 1, -1, -1): + * strides[idx] = stride # <<<<<<<<<<<<<< + * stride *= shape[idx] + * + */ + (__pyx_v_strides[__pyx_v_idx]) = __pyx_v_stride; + + /* "View.MemoryView":1200 + * for idx in range(ndim - 1, -1, -1): + * strides[idx] = stride + * stride *= shape[idx] # <<<<<<<<<<<<<< + * + * return stride + */ + __pyx_v_stride = (__pyx_v_stride * (__pyx_v_shape[__pyx_v_idx])); + } + } + __pyx_L3:; + + /* "View.MemoryView":1202 + * stride *= shape[idx] + * + * return stride # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_data_to_temp') + */ + __pyx_r = __pyx_v_stride; + goto __pyx_L0; + + /* "View.MemoryView":1184 + * + * @cname('__pyx_fill_contig_strides_array') + * cdef Py_ssize_t fill_contig_strides_array( # <<<<<<<<<<<<<< + * Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, + * int ndim, char order) noexcept nogil: + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1205 + * + * @cname('__pyx_memoryview_copy_data_to_temp') + * cdef void *copy_data_to_temp(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *tmpslice, + * char order, + */ + +static void *__pyx_memoryview_copy_data_to_temp(__Pyx_memviewslice *__pyx_v_src, __Pyx_memviewslice *__pyx_v_tmpslice, char __pyx_v_order, int __pyx_v_ndim) { + int __pyx_v_i; + void *__pyx_v_result; + size_t __pyx_v_itemsize; + size_t __pyx_v_size; + void *__pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + struct __pyx_memoryview_obj *__pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":1216 + * cdef void *result + * + * cdef size_t itemsize = src.memview.view.itemsize # <<<<<<<<<<<<<< + * cdef size_t size = slice_get_size(src, ndim) + * + */ + __pyx_t_1 = __pyx_v_src->memview->view.itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":1217 + * + * cdef size_t itemsize = src.memview.view.itemsize + * cdef size_t size = slice_get_size(src, ndim) # <<<<<<<<<<<<<< + * + * result = malloc(size) + */ + __pyx_v_size = __pyx_memoryview_slice_get_size(__pyx_v_src, __pyx_v_ndim); + + /* "View.MemoryView":1219 + * cdef size_t size = slice_get_size(src, ndim) + * + * result = malloc(size) # <<<<<<<<<<<<<< + * if not result: + * _err_no_memory() + */ + __pyx_v_result = malloc(__pyx_v_size); + + /* "View.MemoryView":1220 + * + * result = malloc(size) + * if not result: # <<<<<<<<<<<<<< + * _err_no_memory() + * + */ + __pyx_t_2 = (!(__pyx_v_result != 0)); + if (__pyx_t_2) { + + /* "View.MemoryView":1221 + * result = malloc(size) + * if not result: + * _err_no_memory() # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_3 = __pyx_memoryview_err_no_memory(); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 1221, __pyx_L1_error) + + /* "View.MemoryView":1220 + * + * result = malloc(size) + * if not result: # <<<<<<<<<<<<<< + * _err_no_memory() + * + */ + } + + /* "View.MemoryView":1224 + * + * + * tmpslice.data = result # <<<<<<<<<<<<<< + * tmpslice.memview = src.memview + * for i in range(ndim): + */ + __pyx_v_tmpslice->data = ((char *)__pyx_v_result); + + /* "View.MemoryView":1225 + * + * tmpslice.data = result + * tmpslice.memview = src.memview # <<<<<<<<<<<<<< + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] + */ + __pyx_t_4 = __pyx_v_src->memview; + __pyx_v_tmpslice->memview = __pyx_t_4; + + /* "View.MemoryView":1226 + * tmpslice.data = result + * tmpslice.memview = src.memview + * for i in range(ndim): # <<<<<<<<<<<<<< + * tmpslice.shape[i] = src.shape[i] + * tmpslice.suboffsets[i] = -1 + */ + __pyx_t_3 = __pyx_v_ndim; + __pyx_t_5 = __pyx_t_3; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "View.MemoryView":1227 + * tmpslice.memview = src.memview + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] # <<<<<<<<<<<<<< + * tmpslice.suboffsets[i] = -1 + * + */ + (__pyx_v_tmpslice->shape[__pyx_v_i]) = (__pyx_v_src->shape[__pyx_v_i]); + + /* "View.MemoryView":1228 + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] + * tmpslice.suboffsets[i] = -1 # <<<<<<<<<<<<<< + * + * fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order) + */ + (__pyx_v_tmpslice->suboffsets[__pyx_v_i]) = -1L; + } + + /* "View.MemoryView":1230 + * tmpslice.suboffsets[i] = -1 + * + * fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order) # <<<<<<<<<<<<<< + * + * + */ + (void)(__pyx_fill_contig_strides_array((&(__pyx_v_tmpslice->shape[0])), (&(__pyx_v_tmpslice->strides[0])), __pyx_v_itemsize, __pyx_v_ndim, __pyx_v_order)); + + /* "View.MemoryView":1233 + * + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if tmpslice.shape[i] == 1: + * tmpslice.strides[i] = 0 + */ + __pyx_t_3 = __pyx_v_ndim; + __pyx_t_5 = __pyx_t_3; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "View.MemoryView":1234 + * + * for i in range(ndim): + * if tmpslice.shape[i] == 1: # <<<<<<<<<<<<<< + * tmpslice.strides[i] = 0 + * + */ + __pyx_t_2 = ((__pyx_v_tmpslice->shape[__pyx_v_i]) == 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1235 + * for i in range(ndim): + * if tmpslice.shape[i] == 1: + * tmpslice.strides[i] = 0 # <<<<<<<<<<<<<< + * + * if slice_is_contig(src[0], order, ndim): + */ + (__pyx_v_tmpslice->strides[__pyx_v_i]) = 0; + + /* "View.MemoryView":1234 + * + * for i in range(ndim): + * if tmpslice.shape[i] == 1: # <<<<<<<<<<<<<< + * tmpslice.strides[i] = 0 + * + */ + } + } + + /* "View.MemoryView":1237 + * tmpslice.strides[i] = 0 + * + * if slice_is_contig(src[0], order, ndim): # <<<<<<<<<<<<<< + * memcpy(result, src.data, size) + * else: + */ + __pyx_t_2 = __pyx_memviewslice_is_contig((__pyx_v_src[0]), __pyx_v_order, __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1238 + * + * if slice_is_contig(src[0], order, ndim): + * memcpy(result, src.data, size) # <<<<<<<<<<<<<< + * else: + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) + */ + (void)(memcpy(__pyx_v_result, __pyx_v_src->data, __pyx_v_size)); + + /* "View.MemoryView":1237 + * tmpslice.strides[i] = 0 + * + * if slice_is_contig(src[0], order, ndim): # <<<<<<<<<<<<<< + * memcpy(result, src.data, size) + * else: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":1240 + * memcpy(result, src.data, size) + * else: + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) # <<<<<<<<<<<<<< + * + * return result + */ + /*else*/ { + copy_strided_to_strided(__pyx_v_src, __pyx_v_tmpslice, __pyx_v_ndim, __pyx_v_itemsize); + } + __pyx_L9:; + + /* "View.MemoryView":1242 + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "View.MemoryView":1205 + * + * @cname('__pyx_memoryview_copy_data_to_temp') + * cdef void *copy_data_to_temp(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *tmpslice, + * char order, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.copy_data_to_temp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1247 + * + * @cname('__pyx_memoryview_err_extents') + * cdef int _err_extents(int i, Py_ssize_t extent1, # <<<<<<<<<<<<<< + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" + */ + +static int __pyx_memoryview_err_extents(int __pyx_v_i, Py_ssize_t __pyx_v_extent1, Py_ssize_t __pyx_v_extent2) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + Py_UCS4 __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err_extents", 0); + + /* "View.MemoryView":1249 + * cdef int _err_extents(int i, Py_ssize_t extent1, + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err_dim') + */ + __pyx_t_1 = PyTuple_New(7); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = 127; + __Pyx_INCREF(__pyx_kp_u_got_differing_extents_in_dimensi); + __pyx_t_2 += 35; + __Pyx_GIVEREF(__pyx_kp_u_got_differing_extents_in_dimensi); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_kp_u_got_differing_extents_in_dimensi); + __pyx_t_4 = __Pyx_PyUnicode_From_int(__pyx_v_i, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u_got); + __pyx_t_2 += 6; + __Pyx_GIVEREF(__pyx_kp_u_got); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_kp_u_got); + __pyx_t_4 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_extent1, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u_and); + __pyx_t_2 += 5; + __Pyx_GIVEREF(__pyx_kp_u_and); + PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_kp_u_and); + __pyx_t_4 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_extent2, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_1, 6, __pyx_kp_u__7); + __pyx_t_4 = __Pyx_PyUnicode_Join(__pyx_t_1, 7, __pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_4, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 1249, __pyx_L1_error) + + /* "View.MemoryView":1247 + * + * @cname('__pyx_memoryview_err_extents') + * cdef int _err_extents(int i, Py_ssize_t extent1, # <<<<<<<<<<<<<< + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView._err_extents", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1252 + * + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg % dim + * + */ + +static int __pyx_memoryview_err_dim(PyObject *__pyx_v_error, PyObject *__pyx_v_msg, int __pyx_v_dim) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err_dim", 0); + __Pyx_INCREF(__pyx_v_msg); + + /* "View.MemoryView":1253 + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: + * raise error, msg % dim # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err') + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_dim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyString_FormatSafe(__pyx_v_msg, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(((PyObject *)__pyx_v_error), __pyx_t_2, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(1, 1253, __pyx_L1_error) + + /* "View.MemoryView":1252 + * + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg % dim + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView._err_dim", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_XDECREF(__pyx_v_msg); + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1256 + * + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg + * + */ + +static int __pyx_memoryview_err(PyObject *__pyx_v_error, PyObject *__pyx_v_msg) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err", 0); + __Pyx_INCREF(__pyx_v_msg); + + /* "View.MemoryView":1257 + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: + * raise error, msg # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err_no_memory') + */ + __Pyx_Raise(((PyObject *)__pyx_v_error), __pyx_v_msg, 0, 0); + __PYX_ERR(1, 1257, __pyx_L1_error) + + /* "View.MemoryView":1256 + * + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._err", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_XDECREF(__pyx_v_msg); + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1260 + * + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + +static int __pyx_memoryview_err_no_memory(void) { + int __pyx_r; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + + /* "View.MemoryView":1261 + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: + * raise MemoryError # <<<<<<<<<<<<<< + * + * + */ + PyErr_NoMemory(); __PYX_ERR(1, 1261, __pyx_L1_error) + + /* "View.MemoryView":1260 + * + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._err_no_memory", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1265 + * + * @cname('__pyx_memoryview_copy_contents') + * cdef int memoryview_copy_contents(__Pyx_memviewslice src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice dst, + * int src_ndim, int dst_ndim, + */ + +static int __pyx_memoryview_copy_contents(__Pyx_memviewslice __pyx_v_src, __Pyx_memviewslice __pyx_v_dst, int __pyx_v_src_ndim, int __pyx_v_dst_ndim, int __pyx_v_dtype_is_object) { + void *__pyx_v_tmpdata; + size_t __pyx_v_itemsize; + int __pyx_v_i; + char __pyx_v_order; + int __pyx_v_broadcasting; + int __pyx_v_direct_copy; + __Pyx_memviewslice __pyx_v_tmp; + int __pyx_v_ndim; + int __pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + void *__pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":1273 + * Check for overlapping memory and verify the shapes. + * """ + * cdef void *tmpdata = NULL # <<<<<<<<<<<<<< + * cdef size_t itemsize = src.memview.view.itemsize + * cdef int i + */ + __pyx_v_tmpdata = NULL; + + /* "View.MemoryView":1274 + * """ + * cdef void *tmpdata = NULL + * cdef size_t itemsize = src.memview.view.itemsize # <<<<<<<<<<<<<< + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) + */ + __pyx_t_1 = __pyx_v_src.memview->view.itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":1276 + * cdef size_t itemsize = src.memview.view.itemsize + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) # <<<<<<<<<<<<<< + * cdef bint broadcasting = False + * cdef bint direct_copy = False + */ + __pyx_v_order = __pyx_get_best_slice_order((&__pyx_v_src), __pyx_v_src_ndim); + + /* "View.MemoryView":1277 + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) + * cdef bint broadcasting = False # <<<<<<<<<<<<<< + * cdef bint direct_copy = False + * cdef __Pyx_memviewslice tmp + */ + __pyx_v_broadcasting = 0; + + /* "View.MemoryView":1278 + * cdef char order = get_best_order(&src, src_ndim) + * cdef bint broadcasting = False + * cdef bint direct_copy = False # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice tmp + * + */ + __pyx_v_direct_copy = 0; + + /* "View.MemoryView":1281 + * cdef __Pyx_memviewslice tmp + * + * if src_ndim < dst_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + */ + __pyx_t_2 = (__pyx_v_src_ndim < __pyx_v_dst_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1282 + * + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) # <<<<<<<<<<<<<< + * elif dst_ndim < src_ndim: + * broadcast_leading(&dst, dst_ndim, src_ndim) + */ + __pyx_memoryview_broadcast_leading((&__pyx_v_src), __pyx_v_src_ndim, __pyx_v_dst_ndim); + + /* "View.MemoryView":1281 + * cdef __Pyx_memviewslice tmp + * + * if src_ndim < dst_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1283 + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + */ + __pyx_t_2 = (__pyx_v_dst_ndim < __pyx_v_src_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1284 + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + * broadcast_leading(&dst, dst_ndim, src_ndim) # <<<<<<<<<<<<<< + * + * cdef int ndim = max(src_ndim, dst_ndim) + */ + __pyx_memoryview_broadcast_leading((&__pyx_v_dst), __pyx_v_dst_ndim, __pyx_v_src_ndim); + + /* "View.MemoryView":1283 + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + */ + } + __pyx_L3:; + + /* "View.MemoryView":1286 + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + * cdef int ndim = max(src_ndim, dst_ndim) # <<<<<<<<<<<<<< + * + * for i in range(ndim): + */ + __pyx_t_3 = __pyx_v_dst_ndim; + __pyx_t_4 = __pyx_v_src_ndim; + __pyx_t_2 = (__pyx_t_3 > __pyx_t_4); + if (__pyx_t_2) { + __pyx_t_5 = __pyx_t_3; + } else { + __pyx_t_5 = __pyx_t_4; + } + __pyx_v_ndim = __pyx_t_5; + + /* "View.MemoryView":1288 + * cdef int ndim = max(src_ndim, dst_ndim) + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: + */ + __pyx_t_5 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_5; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1289 + * + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: # <<<<<<<<<<<<<< + * if src.shape[i] == 1: + * broadcasting = True + */ + __pyx_t_2 = ((__pyx_v_src.shape[__pyx_v_i]) != (__pyx_v_dst.shape[__pyx_v_i])); + if (__pyx_t_2) { + + /* "View.MemoryView":1290 + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: # <<<<<<<<<<<<<< + * broadcasting = True + * src.strides[i] = 0 + */ + __pyx_t_2 = ((__pyx_v_src.shape[__pyx_v_i]) == 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1291 + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: + * broadcasting = True # <<<<<<<<<<<<<< + * src.strides[i] = 0 + * else: + */ + __pyx_v_broadcasting = 1; + + /* "View.MemoryView":1292 + * if src.shape[i] == 1: + * broadcasting = True + * src.strides[i] = 0 # <<<<<<<<<<<<<< + * else: + * _err_extents(i, dst.shape[i], src.shape[i]) + */ + (__pyx_v_src.strides[__pyx_v_i]) = 0; + + /* "View.MemoryView":1290 + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: # <<<<<<<<<<<<<< + * broadcasting = True + * src.strides[i] = 0 + */ + goto __pyx_L7; + } + + /* "View.MemoryView":1294 + * src.strides[i] = 0 + * else: + * _err_extents(i, dst.shape[i], src.shape[i]) # <<<<<<<<<<<<<< + * + * if src.suboffsets[i] >= 0: + */ + /*else*/ { + __pyx_t_6 = __pyx_memoryview_err_extents(__pyx_v_i, (__pyx_v_dst.shape[__pyx_v_i]), (__pyx_v_src.shape[__pyx_v_i])); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(1, 1294, __pyx_L1_error) + } + __pyx_L7:; + + /* "View.MemoryView":1289 + * + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: # <<<<<<<<<<<<<< + * if src.shape[i] == 1: + * broadcasting = True + */ + } + + /* "View.MemoryView":1296 + * _err_extents(i, dst.shape[i], src.shape[i]) + * + * if src.suboffsets[i] >= 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + */ + __pyx_t_2 = ((__pyx_v_src.suboffsets[__pyx_v_i]) >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":1297 + * + * if src.suboffsets[i] >= 0: + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) # <<<<<<<<<<<<<< + * + * if slices_overlap(&src, &dst, ndim, itemsize): + */ + __pyx_t_6 = __pyx_memoryview_err_dim(PyExc_ValueError, __pyx_kp_s_Dimension_d_is_not_direct, __pyx_v_i); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(1, 1297, __pyx_L1_error) + + /* "View.MemoryView":1296 + * _err_extents(i, dst.shape[i], src.shape[i]) + * + * if src.suboffsets[i] >= 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + */ + } + } + + /* "View.MemoryView":1299 + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + * if slices_overlap(&src, &dst, ndim, itemsize): # <<<<<<<<<<<<<< + * + * if not slice_is_contig(src, order, ndim): + */ + __pyx_t_2 = __pyx_slices_overlap((&__pyx_v_src), (&__pyx_v_dst), __pyx_v_ndim, __pyx_v_itemsize); + if (__pyx_t_2) { + + /* "View.MemoryView":1301 + * if slices_overlap(&src, &dst, ndim, itemsize): + * + * if not slice_is_contig(src, order, ndim): # <<<<<<<<<<<<<< + * order = get_best_order(&dst, ndim) + * + */ + __pyx_t_2 = (!__pyx_memviewslice_is_contig(__pyx_v_src, __pyx_v_order, __pyx_v_ndim)); + if (__pyx_t_2) { + + /* "View.MemoryView":1302 + * + * if not slice_is_contig(src, order, ndim): + * order = get_best_order(&dst, ndim) # <<<<<<<<<<<<<< + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) + */ + __pyx_v_order = __pyx_get_best_slice_order((&__pyx_v_dst), __pyx_v_ndim); + + /* "View.MemoryView":1301 + * if slices_overlap(&src, &dst, ndim, itemsize): + * + * if not slice_is_contig(src, order, ndim): # <<<<<<<<<<<<<< + * order = get_best_order(&dst, ndim) + * + */ + } + + /* "View.MemoryView":1304 + * order = get_best_order(&dst, ndim) + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) # <<<<<<<<<<<<<< + * src = tmp + * + */ + __pyx_t_7 = __pyx_memoryview_copy_data_to_temp((&__pyx_v_src), (&__pyx_v_tmp), __pyx_v_order, __pyx_v_ndim); if (unlikely(__pyx_t_7 == ((void *)NULL))) __PYX_ERR(1, 1304, __pyx_L1_error) + __pyx_v_tmpdata = __pyx_t_7; + + /* "View.MemoryView":1305 + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) + * src = tmp # <<<<<<<<<<<<<< + * + * if not broadcasting: + */ + __pyx_v_src = __pyx_v_tmp; + + /* "View.MemoryView":1299 + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + * if slices_overlap(&src, &dst, ndim, itemsize): # <<<<<<<<<<<<<< + * + * if not slice_is_contig(src, order, ndim): + */ + } + + /* "View.MemoryView":1307 + * src = tmp + * + * if not broadcasting: # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (!__pyx_v_broadcasting); + if (__pyx_t_2) { + + /* "View.MemoryView":1310 + * + * + * if slice_is_contig(src, 'C', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + */ + __pyx_t_2 = __pyx_memviewslice_is_contig(__pyx_v_src, 'C', __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1311 + * + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) # <<<<<<<<<<<<<< + * elif slice_is_contig(src, 'F', ndim): + * direct_copy = slice_is_contig(dst, 'F', ndim) + */ + __pyx_v_direct_copy = __pyx_memviewslice_is_contig(__pyx_v_dst, 'C', __pyx_v_ndim); + + /* "View.MemoryView":1310 + * + * + * if slice_is_contig(src, 'C', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + */ + goto __pyx_L12; + } + + /* "View.MemoryView":1312 + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + */ + __pyx_t_2 = __pyx_memviewslice_is_contig(__pyx_v_src, 'F', __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1313 + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + * direct_copy = slice_is_contig(dst, 'F', ndim) # <<<<<<<<<<<<<< + * + * if direct_copy: + */ + __pyx_v_direct_copy = __pyx_memviewslice_is_contig(__pyx_v_dst, 'F', __pyx_v_ndim); + + /* "View.MemoryView":1312 + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + */ + } + __pyx_L12:; + + /* "View.MemoryView":1315 + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + * if direct_copy: # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + if (__pyx_v_direct_copy) { + + /* "View.MemoryView":1317 + * if direct_copy: + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1318 + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) # <<<<<<<<<<<<<< + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) + */ + (void)(memcpy(__pyx_v_dst.data, __pyx_v_src.data, __pyx_memoryview_slice_get_size((&__pyx_v_src), __pyx_v_ndim))); + + /* "View.MemoryView":1319 + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * free(tmpdata) + * return 0 + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1320 + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) # <<<<<<<<<<<<<< + * return 0 + * + */ + free(__pyx_v_tmpdata); + + /* "View.MemoryView":1321 + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) + * return 0 # <<<<<<<<<<<<<< + * + * if order == 'F' == get_best_order(&dst, ndim): + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":1315 + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + * if direct_copy: # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + } + + /* "View.MemoryView":1307 + * src = tmp + * + * if not broadcasting: # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":1323 + * return 0 + * + * if order == 'F' == get_best_order(&dst, ndim): # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (__pyx_v_order == 'F'); + if (__pyx_t_2) { + __pyx_t_2 = ('F' == __pyx_get_best_slice_order((&__pyx_v_dst), __pyx_v_ndim)); + } + if (__pyx_t_2) { + + /* "View.MemoryView":1326 + * + * + * transpose_memslice(&src) # <<<<<<<<<<<<<< + * transpose_memslice(&dst) + * + */ + __pyx_t_5 = __pyx_memslice_transpose((&__pyx_v_src)); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 1326, __pyx_L1_error) + + /* "View.MemoryView":1327 + * + * transpose_memslice(&src) + * transpose_memslice(&dst) # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + __pyx_t_5 = __pyx_memslice_transpose((&__pyx_v_dst)); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 1327, __pyx_L1_error) + + /* "View.MemoryView":1323 + * return 0 + * + * if order == 'F' == get_best_order(&dst, ndim): # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":1329 + * transpose_memslice(&dst) + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * copy_strided_to_strided(&src, &dst, ndim, itemsize) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1330 + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * copy_strided_to_strided(&src, &dst, ndim, itemsize) # <<<<<<<<<<<<<< + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * + */ + copy_strided_to_strided((&__pyx_v_src), (&__pyx_v_dst), __pyx_v_ndim, __pyx_v_itemsize); + + /* "View.MemoryView":1331 + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * copy_strided_to_strided(&src, &dst, ndim, itemsize) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * + * free(tmpdata) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1333 + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * + * free(tmpdata) # <<<<<<<<<<<<<< + * return 0 + * + */ + free(__pyx_v_tmpdata); + + /* "View.MemoryView":1334 + * + * free(tmpdata) + * return 0 # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_broadcast_leading') + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":1265 + * + * @cname('__pyx_memoryview_copy_contents') + * cdef int memoryview_copy_contents(__Pyx_memviewslice src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice dst, + * int src_ndim, int dst_ndim, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.memoryview_copy_contents", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1337 + * + * @cname('__pyx_memoryview_broadcast_leading') + * cdef void broadcast_leading(__Pyx_memviewslice *mslice, # <<<<<<<<<<<<<< + * int ndim, + * int ndim_other) noexcept nogil: + */ + +static void __pyx_memoryview_broadcast_leading(__Pyx_memviewslice *__pyx_v_mslice, int __pyx_v_ndim, int __pyx_v_ndim_other) { + int __pyx_v_i; + int __pyx_v_offset; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + + /* "View.MemoryView":1341 + * int ndim_other) noexcept nogil: + * cdef int i + * cdef int offset = ndim_other - ndim # <<<<<<<<<<<<<< + * + * for i in range(ndim - 1, -1, -1): + */ + __pyx_v_offset = (__pyx_v_ndim_other - __pyx_v_ndim); + + /* "View.MemoryView":1343 + * cdef int offset = ndim_other - ndim + * + * for i in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] + */ + for (__pyx_t_1 = (__pyx_v_ndim - 1); __pyx_t_1 > -1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":1344 + * + * for i in range(ndim - 1, -1, -1): + * mslice.shape[i + offset] = mslice.shape[i] # <<<<<<<<<<<<<< + * mslice.strides[i + offset] = mslice.strides[i] + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + */ + (__pyx_v_mslice->shape[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->shape[__pyx_v_i]); + + /* "View.MemoryView":1345 + * for i in range(ndim - 1, -1, -1): + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] # <<<<<<<<<<<<<< + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + * + */ + (__pyx_v_mslice->strides[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1346 + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] # <<<<<<<<<<<<<< + * + * for i in range(offset): + */ + (__pyx_v_mslice->suboffsets[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->suboffsets[__pyx_v_i]); + } + + /* "View.MemoryView":1348 + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + * + * for i in range(offset): # <<<<<<<<<<<<<< + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] + */ + __pyx_t_1 = __pyx_v_offset; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "View.MemoryView":1349 + * + * for i in range(offset): + * mslice.shape[i] = 1 # <<<<<<<<<<<<<< + * mslice.strides[i] = mslice.strides[0] + * mslice.suboffsets[i] = -1 + */ + (__pyx_v_mslice->shape[__pyx_v_i]) = 1; + + /* "View.MemoryView":1350 + * for i in range(offset): + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] # <<<<<<<<<<<<<< + * mslice.suboffsets[i] = -1 + * + */ + (__pyx_v_mslice->strides[__pyx_v_i]) = (__pyx_v_mslice->strides[0]); + + /* "View.MemoryView":1351 + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] + * mslice.suboffsets[i] = -1 # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_mslice->suboffsets[__pyx_v_i]) = -1L; + } + + /* "View.MemoryView":1337 + * + * @cname('__pyx_memoryview_broadcast_leading') + * cdef void broadcast_leading(__Pyx_memviewslice *mslice, # <<<<<<<<<<<<<< + * int ndim, + * int ndim_other) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1359 + * + * @cname('__pyx_memoryview_refcount_copying') + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: # <<<<<<<<<<<<<< + * + * if dtype_is_object: + */ + +static void __pyx_memoryview_refcount_copying(__Pyx_memviewslice *__pyx_v_dst, int __pyx_v_dtype_is_object, int __pyx_v_ndim, int __pyx_v_inc) { + + /* "View.MemoryView":1361 + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: + * + * if dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) + * + */ + if (__pyx_v_dtype_is_object) { + + /* "View.MemoryView":1362 + * + * if dtype_is_object: + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + */ + __pyx_memoryview_refcount_objects_in_slice_with_gil(__pyx_v_dst->data, __pyx_v_dst->shape, __pyx_v_dst->strides, __pyx_v_ndim, __pyx_v_inc); + + /* "View.MemoryView":1361 + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: + * + * if dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) + * + */ + } + + /* "View.MemoryView":1359 + * + * @cname('__pyx_memoryview_refcount_copying') + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: # <<<<<<<<<<<<<< + * + * if dtype_is_object: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1365 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + * cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + */ + +static void __pyx_memoryview_refcount_objects_in_slice_with_gil(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, int __pyx_v_inc) { + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + + /* "View.MemoryView":1368 + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + * refcount_objects_in_slice(data, shape, strides, ndim, inc) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + */ + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_data, __pyx_v_shape, __pyx_v_strides, __pyx_v_ndim, __pyx_v_inc); + + /* "View.MemoryView":1365 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + * cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + */ + + /* function exit code */ + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif +} + +/* "View.MemoryView":1371 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + * cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + */ + +static void __pyx_memoryview_refcount_objects_in_slice(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, int __pyx_v_inc) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1374 + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] # <<<<<<<<<<<<<< + * + * for i in range(shape[0]): + */ + __pyx_v_stride = (__pyx_v_strides[0]); + + /* "View.MemoryView":1376 + * cdef Py_ssize_t stride = strides[0] + * + * for i in range(shape[0]): # <<<<<<<<<<<<<< + * if ndim == 1: + * if inc: + */ + __pyx_t_1 = (__pyx_v_shape[0]); + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "View.MemoryView":1377 + * + * for i in range(shape[0]): + * if ndim == 1: # <<<<<<<<<<<<<< + * if inc: + * Py_INCREF(( data)[0]) + */ + __pyx_t_4 = (__pyx_v_ndim == 1); + if (__pyx_t_4) { + + /* "View.MemoryView":1378 + * for i in range(shape[0]): + * if ndim == 1: + * if inc: # <<<<<<<<<<<<<< + * Py_INCREF(( data)[0]) + * else: + */ + if (__pyx_v_inc) { + + /* "View.MemoryView":1379 + * if ndim == 1: + * if inc: + * Py_INCREF(( data)[0]) # <<<<<<<<<<<<<< + * else: + * Py_DECREF(( data)[0]) + */ + Py_INCREF((((PyObject **)__pyx_v_data)[0])); + + /* "View.MemoryView":1378 + * for i in range(shape[0]): + * if ndim == 1: + * if inc: # <<<<<<<<<<<<<< + * Py_INCREF(( data)[0]) + * else: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":1381 + * Py_INCREF(( data)[0]) + * else: + * Py_DECREF(( data)[0]) # <<<<<<<<<<<<<< + * else: + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) + */ + /*else*/ { + Py_DECREF((((PyObject **)__pyx_v_data)[0])); + } + __pyx_L6:; + + /* "View.MemoryView":1377 + * + * for i in range(shape[0]): + * if ndim == 1: # <<<<<<<<<<<<<< + * if inc: + * Py_INCREF(( data)[0]) + */ + goto __pyx_L5; + } + + /* "View.MemoryView":1383 + * Py_DECREF(( data)[0]) + * else: + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) # <<<<<<<<<<<<<< + * + * data += stride + */ + /*else*/ { + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_data, (__pyx_v_shape + 1), (__pyx_v_strides + 1), (__pyx_v_ndim - 1), __pyx_v_inc); + } + __pyx_L5:; + + /* "View.MemoryView":1385 + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) + * + * data += stride # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + + /* "View.MemoryView":1371 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + * cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + */ + + /* function exit code */ +} + +/* "View.MemoryView":1391 + * + * @cname('__pyx_memoryview_slice_assign_scalar') + * cdef void slice_assign_scalar(__Pyx_memviewslice *dst, int ndim, # <<<<<<<<<<<<<< + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + */ + +static void __pyx_memoryview_slice_assign_scalar(__Pyx_memviewslice *__pyx_v_dst, int __pyx_v_ndim, size_t __pyx_v_itemsize, void *__pyx_v_item, int __pyx_v_dtype_is_object) { + + /* "View.MemoryView":1394 + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + * refcount_copying(dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) + * refcount_copying(dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying(__pyx_v_dst, __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1395 + * bint dtype_is_object) noexcept nogil: + * refcount_copying(dst, dtype_is_object, ndim, inc=False) + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) # <<<<<<<<<<<<<< + * refcount_copying(dst, dtype_is_object, ndim, inc=True) + * + */ + __pyx_memoryview__slice_assign_scalar(__pyx_v_dst->data, __pyx_v_dst->shape, __pyx_v_dst->strides, __pyx_v_ndim, __pyx_v_itemsize, __pyx_v_item); + + /* "View.MemoryView":1396 + * refcount_copying(dst, dtype_is_object, ndim, inc=False) + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) + * refcount_copying(dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * + * + */ + __pyx_memoryview_refcount_copying(__pyx_v_dst, __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1391 + * + * @cname('__pyx_memoryview_slice_assign_scalar') + * cdef void slice_assign_scalar(__Pyx_memviewslice *dst, int ndim, # <<<<<<<<<<<<<< + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1400 + * + * @cname('__pyx_memoryview__slice_assign_scalar') + * cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * size_t itemsize, void *item) noexcept nogil: + */ + +static void __pyx_memoryview__slice_assign_scalar(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, size_t __pyx_v_itemsize, void *__pyx_v_item) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_v_extent; + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + + /* "View.MemoryView":1404 + * size_t itemsize, void *item) noexcept nogil: + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t extent = shape[0] + * + */ + __pyx_v_stride = (__pyx_v_strides[0]); + + /* "View.MemoryView":1405 + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] + * cdef Py_ssize_t extent = shape[0] # <<<<<<<<<<<<<< + * + * if ndim == 1: + */ + __pyx_v_extent = (__pyx_v_shape[0]); + + /* "View.MemoryView":1407 + * cdef Py_ssize_t extent = shape[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * for i in range(extent): + * memcpy(data, item, itemsize) + */ + __pyx_t_1 = (__pyx_v_ndim == 1); + if (__pyx_t_1) { + + /* "View.MemoryView":1408 + * + * if ndim == 1: + * for i in range(extent): # <<<<<<<<<<<<<< + * memcpy(data, item, itemsize) + * data += stride + */ + __pyx_t_2 = __pyx_v_extent; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1409 + * if ndim == 1: + * for i in range(extent): + * memcpy(data, item, itemsize) # <<<<<<<<<<<<<< + * data += stride + * else: + */ + (void)(memcpy(__pyx_v_data, __pyx_v_item, __pyx_v_itemsize)); + + /* "View.MemoryView":1410 + * for i in range(extent): + * memcpy(data, item, itemsize) + * data += stride # <<<<<<<<<<<<<< + * else: + * for i in range(extent): + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + + /* "View.MemoryView":1407 + * cdef Py_ssize_t extent = shape[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * for i in range(extent): + * memcpy(data, item, itemsize) + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1412 + * data += stride + * else: + * for i in range(extent): # <<<<<<<<<<<<<< + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) + * data += stride + */ + /*else*/ { + __pyx_t_2 = __pyx_v_extent; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1413 + * else: + * for i in range(extent): + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) # <<<<<<<<<<<<<< + * data += stride + * + */ + __pyx_memoryview__slice_assign_scalar(__pyx_v_data, (__pyx_v_shape + 1), (__pyx_v_strides + 1), (__pyx_v_ndim - 1), __pyx_v_itemsize, __pyx_v_item); + + /* "View.MemoryView":1414 + * for i in range(extent): + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) + * data += stride # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + } + __pyx_L3:; + + /* "View.MemoryView":1400 + * + * @cname('__pyx_memoryview__slice_assign_scalar') + * cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * size_t itemsize, void *item) noexcept nogil: + */ + + /* function exit code */ +} + +/* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_15View_dot_MemoryView_1__pyx_unpickle_Enum = {"__pyx_unpickle_Enum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v___pyx_type = 0; + long __pyx_v___pyx_checksum; + PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_type)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_checksum)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__pyx_unpickle_Enum") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v___pyx_type = values[0]; + __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_v___pyx_state = values[2]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, __pyx_nargs); __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_v___pyx_PickleError = 0; + PyObject *__pyx_v___pyx_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum", 1); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__8, Py_NE)); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_2) { + + /* "(tree fragment)":5 + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): + * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_PickleError); + __Pyx_GIVEREF(__pyx_n_s_PickleError); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError)) __PYX_ERR(1, 5, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __pyx_v___pyx_PickleError = __pyx_t_1; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "(tree fragment)":6 + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum # <<<<<<<<<<<<<< + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: + */ + __pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_v___pyx_PickleError, __pyx_t_1, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 6, __pyx_L1_error) + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + } + + /* "(tree fragment)":7 + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) # <<<<<<<<<<<<<< + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_MemviewEnum_type), __pyx_n_s_new); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v___pyx_type}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_v___pyx_result = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + */ + __pyx_t_2 = (__pyx_v___pyx_state != Py_None); + if (__pyx_t_2) { + + /* "(tree fragment)":9 + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) # <<<<<<<<<<<<<< + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None) || __Pyx_RaiseUnexpectedTypeError("tuple", __pyx_v___pyx_state))) __PYX_ERR(1, 9, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle_Enum__set_state(((struct __pyx_MemviewEnum_obj *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + */ + } + + /* "(tree fragment)":10 + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result # <<<<<<<<<<<<<< + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v___pyx_result); + __pyx_r = __pyx_v___pyx_result; + goto __pyx_L0; + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v___pyx_PickleError); + __Pyx_XDECREF(__pyx_v___pyx_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":11 + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + */ + +static PyObject *__pyx_unpickle_Enum__set_state(struct __pyx_MemviewEnum_obj *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + unsigned int __pyx_t_8; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum__set_state", 1); + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] # <<<<<<<<<<<<<< + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 12, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v___pyx_result->name); + __Pyx_DECREF(__pyx_v___pyx_result->name); + __pyx_v___pyx_result->name = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":13 + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 13, __pyx_L1_error) + } + __pyx_t_3 = __Pyx_PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(1, 13, __pyx_L1_error) + __pyx_t_4 = (__pyx_t_3 > 1); + if (__pyx_t_4) { + } else { + __pyx_t_2 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 13, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (__pyx_t_2) { + + /* "(tree fragment)":14 + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[1]) # <<<<<<<<<<<<<< + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_update); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 14, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_8 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+1-__pyx_t_8, 1+__pyx_t_8); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":13 + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + } + + /* "(tree fragment)":11 + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + +static CYTHON_INLINE PyObject *__pyx_f_5ezdxf_3acc_8matrix44_swap(double *__pyx_v_a, double *__pyx_v_b) { + double __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("swap", 1); + + /* "ezdxf/acc/matrix44.pxd":13 + * + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] # <<<<<<<<<<<<<< + * a[0] = b[0] + * b[0] = tmp + */ + __pyx_v_tmp = (__pyx_v_a[0]); + + /* "ezdxf/acc/matrix44.pxd":14 + * cdef inline swap(double *a, double *b): + * cdef double tmp = a[0] + * a[0] = b[0] # <<<<<<<<<<<<<< + * b[0] = tmp + */ + (__pyx_v_a[0]) = (__pyx_v_b[0]); + + /* "ezdxf/acc/matrix44.pxd":15 + * cdef double tmp = a[0] + * a[0] = b[0] + * b[0] = tmp # <<<<<<<<<<<<<< + */ + (__pyx_v_b[0]) = __pyx_v_tmp; + + /* "ezdxf/acc/matrix44.pxd":12 + * cdef Vec3 get_uz(self: Matrix44) + * + * cdef inline swap(double *a, double *b): # <<<<<<<<<<<<<< + * cdef double tmp = a[0] + * a[0] = b[0] + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":31 + * ] + * + * cdef void set_floats(double *m, object values) except *: # <<<<<<<<<<<<<< + * cdef int i = 0 + * for v in values: + */ + +static void __pyx_f_5ezdxf_3acc_8matrix44_set_floats(double *__pyx_v_m, PyObject *__pyx_v_values) { + int __pyx_v_i; + PyObject *__pyx_v_v = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + double __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set_floats", 1); + + /* "ezdxf/acc/matrix44.pyx":32 + * + * cdef void set_floats(double *m, object values) except *: + * cdef int i = 0 # <<<<<<<<<<<<<< + * for v in values: + * if i < 16: # Do not write beyond array bounds + */ + __pyx_v_i = 0; + + /* "ezdxf/acc/matrix44.pyx":33 + * cdef void set_floats(double *m, object values) except *: + * cdef int i = 0 + * for v in values: # <<<<<<<<<<<<<< + * if i < 16: # Do not write beyond array bounds + * m[i] = v + */ + if (likely(PyList_CheckExact(__pyx_v_values)) || PyTuple_CheckExact(__pyx_v_values)) { + __pyx_t_1 = __pyx_v_values; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_values); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 33, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 33, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 33, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 33, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 33, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 33, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":34 + * cdef int i = 0 + * for v in values: + * if i < 16: # Do not write beyond array bounds # <<<<<<<<<<<<<< + * m[i] = v + * i += 1 + */ + __pyx_t_5 = (__pyx_v_i < 16); + if (__pyx_t_5) { + + /* "ezdxf/acc/matrix44.pyx":35 + * for v in values: + * if i < 16: # Do not write beyond array bounds + * m[i] = v # <<<<<<<<<<<<<< + * i += 1 + * if i != 16: + */ + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_v_v); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 35, __pyx_L1_error) + (__pyx_v_m[__pyx_v_i]) = __pyx_t_6; + + /* "ezdxf/acc/matrix44.pyx":34 + * cdef int i = 0 + * for v in values: + * if i < 16: # Do not write beyond array bounds # <<<<<<<<<<<<<< + * m[i] = v + * i += 1 + */ + } + + /* "ezdxf/acc/matrix44.pyx":36 + * if i < 16: # Do not write beyond array bounds + * m[i] = v + * i += 1 # <<<<<<<<<<<<<< + * if i != 16: + * raise ValueError("invalid argument count") + */ + __pyx_v_i = (__pyx_v_i + 1); + + /* "ezdxf/acc/matrix44.pyx":33 + * cdef void set_floats(double *m, object values) except *: + * cdef int i = 0 + * for v in values: # <<<<<<<<<<<<<< + * if i < 16: # Do not write beyond array bounds + * m[i] = v + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":37 + * m[i] = v + * i += 1 + * if i != 16: # <<<<<<<<<<<<<< + * raise ValueError("invalid argument count") + * + */ + __pyx_t_5 = (__pyx_v_i != 16); + if (unlikely(__pyx_t_5)) { + + /* "ezdxf/acc/matrix44.pyx":38 + * i += 1 + * if i != 16: + * raise ValueError("invalid argument count") # <<<<<<<<<<<<<< + * + * cdef class Matrix44: + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 38, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":37 + * m[i] = v + * i += 1 + * if i != 16: # <<<<<<<<<<<<<< + * raise ValueError("invalid argument count") + * + */ + } + + /* "ezdxf/acc/matrix44.pyx":31 + * ] + * + * cdef void set_floats(double *m, object values) except *: # <<<<<<<<<<<<<< + * cdef int i = 0 + * for v in values: + */ + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.matrix44.set_floats", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_v); + __Pyx_RefNannyFinishContext(); +} + +/* "ezdxf/acc/matrix44.pyx":41 + * + * cdef class Matrix44: + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef int nargs = len(args) + * if nargs == 0: # default constructor Matrix44(): fastest setup + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_args = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_VARARGS(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __Pyx_INCREF(__pyx_args); + __pyx_v_args = __pyx_args; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44___cinit__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_args); + + /* function exit code */ + __Pyx_DECREF(__pyx_v_args); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44___cinit__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_args) { + int __pyx_v_nargs; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "ezdxf/acc/matrix44.pyx":42 + * cdef class Matrix44: + * def __cinit__(self, *args): + * cdef int nargs = len(args) # <<<<<<<<<<<<<< + * if nargs == 0: # default constructor Matrix44(): fastest setup + * self.m = IDENTITY # memcopy! + */ + __pyx_t_1 = __Pyx_PyTuple_GET_SIZE(__pyx_v_args); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 42, __pyx_L1_error) + __pyx_v_nargs = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":43 + * def __cinit__(self, *args): + * cdef int nargs = len(args) + * if nargs == 0: # default constructor Matrix44(): fastest setup # <<<<<<<<<<<<<< + * self.m = IDENTITY # memcopy! + * elif nargs == 1: # 16 numbers: slow setup + */ + switch (__pyx_v_nargs) { + case 0: + + /* "ezdxf/acc/matrix44.pyx":44 + * cdef int nargs = len(args) + * if nargs == 0: # default constructor Matrix44(): fastest setup + * self.m = IDENTITY # memcopy! # <<<<<<<<<<<<<< + * elif nargs == 1: # 16 numbers: slow setup + * set_floats(self.m, args[0]) + */ + memcpy(&(__pyx_v_self->m[0]), __pyx_v_5ezdxf_3acc_8matrix44_IDENTITY, sizeof(__pyx_v_self->m[0]) * (16)); + + /* "ezdxf/acc/matrix44.pyx":43 + * def __cinit__(self, *args): + * cdef int nargs = len(args) + * if nargs == 0: # default constructor Matrix44(): fastest setup # <<<<<<<<<<<<<< + * self.m = IDENTITY # memcopy! + * elif nargs == 1: # 16 numbers: slow setup + */ + break; + case 1: + + /* "ezdxf/acc/matrix44.pyx":46 + * self.m = IDENTITY # memcopy! + * elif nargs == 1: # 16 numbers: slow setup + * set_floats(self.m, args[0]) # <<<<<<<<<<<<<< + * elif nargs == 4: # 4 rows of 4 numbers: slowest setup + * set_floats(self.m, chain(*args)) + */ + __pyx_t_2 = __Pyx_GetItemInt_Tuple(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_f_5ezdxf_3acc_8matrix44_set_floats(__pyx_v_self->m, __pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":45 + * if nargs == 0: # default constructor Matrix44(): fastest setup + * self.m = IDENTITY # memcopy! + * elif nargs == 1: # 16 numbers: slow setup # <<<<<<<<<<<<<< + * set_floats(self.m, args[0]) + * elif nargs == 4: # 4 rows of 4 numbers: slowest setup + */ + break; + case 4: + + /* "ezdxf/acc/matrix44.pyx":48 + * set_floats(self.m, args[0]) + * elif nargs == 4: # 4 rows of 4 numbers: slowest setup + * set_floats(self.m, chain(*args)) # <<<<<<<<<<<<<< + * else: + * raise ValueError("invalid argument count: 4 row vectors or " + */ + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_chain); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_v_args, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_f_5ezdxf_3acc_8matrix44_set_floats(__pyx_v_self->m, __pyx_t_3); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/matrix44.pyx":47 + * elif nargs == 1: # 16 numbers: slow setup + * set_floats(self.m, args[0]) + * elif nargs == 4: # 4 rows of 4 numbers: slowest setup # <<<<<<<<<<<<<< + * set_floats(self.m, chain(*args)) + * else: + */ + break; + default: + + /* "ezdxf/acc/matrix44.pyx":50 + * set_floats(self.m, chain(*args)) + * else: + * raise ValueError("invalid argument count: 4 row vectors or " # <<<<<<<<<<<<<< + * "iterable of 16 numbers") + * + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 50, __pyx_L1_error) + break; + } + + /* "ezdxf/acc/matrix44.pyx":41 + * + * cdef class Matrix44: + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef int nargs = len(args) + * if nargs == 0: # default constructor Matrix44(): fastest setup + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":53 + * "iterable of 16 numbers") + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Matrix44, (tuple(self),) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__ = {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2__reduce__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2__reduce__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce__", 1); + + /* "ezdxf/acc/matrix44.pyx":54 + * + * def __reduce__(self): + * return Matrix44, (tuple(self),) # <<<<<<<<<<<<<< + * + * def __getitem__(self, tuple index) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PySequence_Tuple(((PyObject *)__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44))) __PYX_ERR(0, 54, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_2)) __PYX_ERR(0, 54, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":53 + * "iterable of 16 numbers") + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Matrix44, (tuple(self),) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":56 + * return Matrix44, (tuple(self),) + * + * def __getitem__(self, tuple index) -> float: # <<<<<<<<<<<<<< + * cdef int row = index[0] + * cdef int col = index[1] + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_5__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_5__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_index), (&PyTuple_Type), 1, "index", 1))) __PYX_ERR(0, 56, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4__getitem__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((PyObject*)__pyx_v_index)); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4__getitem__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_index) { + int __pyx_v_row; + int __pyx_v_col; + int __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "ezdxf/acc/matrix44.pyx":57 + * + * def __getitem__(self, tuple index) -> float: + * cdef int row = index[0] # <<<<<<<<<<<<<< + * cdef int col = index[1] + * cdef int i = row * 4 + col + */ + if (unlikely(__pyx_v_index == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 57, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_index, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 57, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_row = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":58 + * def __getitem__(self, tuple index) -> float: + * cdef int row = index[0] + * cdef int col = index[1] # <<<<<<<<<<<<<< + * cdef int i = row * 4 + col + * + */ + if (unlikely(__pyx_v_index == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 58, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_index, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_col = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":59 + * cdef int row = index[0] + * cdef int col = index[1] + * cdef int i = row * 4 + col # <<<<<<<<<<<<<< + * + * if 0 <= i < 16 and 0 <= col < 4: + */ + __pyx_v_i = ((__pyx_v_row * 4) + __pyx_v_col); + + /* "ezdxf/acc/matrix44.pyx":61 + * cdef int i = row * 4 + col + * + * if 0 <= i < 16 and 0 <= col < 4: # <<<<<<<<<<<<<< + * return self.m[i] + * else: + */ + __pyx_t_4 = (0 <= __pyx_v_i); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_i < 16); + } + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = (0 <= __pyx_v_col); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_col < 4); + } + __pyx_t_3 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (likely(__pyx_t_3)) { + + /* "ezdxf/acc/matrix44.pyx":62 + * + * if 0 <= i < 16 and 0 <= col < 4: + * return self.m[i] # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'index out of range: {index}') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble((__pyx_v_self->m[__pyx_v_i])); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":61 + * cdef int i = row * 4 + col + * + * if 0 <= i < 16 and 0 <= col < 4: # <<<<<<<<<<<<<< + * return self.m[i] + * else: + */ + } + + /* "ezdxf/acc/matrix44.pyx":64 + * return self.m[i] + * else: + * raise IndexError(f'index out of range: {index}') # <<<<<<<<<<<<<< + * + * def __setitem__(self, tuple index, double value): + */ + /*else*/ { + __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_v_index, __pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_kp_u_index_out_of_range, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 64, __pyx_L1_error) + } + + /* "ezdxf/acc/matrix44.pyx":56 + * return Matrix44, (tuple(self),) + * + * def __getitem__(self, tuple index) -> float: # <<<<<<<<<<<<<< + * cdef int row = index[0] + * cdef int col = index[1] + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":66 + * raise IndexError(f'index out of range: {index}') + * + * def __setitem__(self, tuple index, double value): # <<<<<<<<<<<<<< + * cdef int row = index[0] + * cdef int col = index[1] + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_7__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_arg_value); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_7__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_arg_value) { + double __pyx_v_value; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_value); { + __pyx_v_value = __pyx_PyFloat_AsDouble(__pyx_arg_value); if (unlikely((__pyx_v_value == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 66, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_index), (&PyTuple_Type), 1, "index", 1))) __PYX_ERR(0, 66, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6__setitem__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((PyObject*)__pyx_v_index), ((double)__pyx_v_value)); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6__setitem__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_index, double __pyx_v_value) { + int __pyx_v_row; + int __pyx_v_col; + int __pyx_v_i; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setitem__", 1); + + /* "ezdxf/acc/matrix44.pyx":67 + * + * def __setitem__(self, tuple index, double value): + * cdef int row = index[0] # <<<<<<<<<<<<<< + * cdef int col = index[1] + * cdef int i = row * 4 + col + */ + if (unlikely(__pyx_v_index == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 67, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_index, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_row = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":68 + * def __setitem__(self, tuple index, double value): + * cdef int row = index[0] + * cdef int col = index[1] # <<<<<<<<<<<<<< + * cdef int i = row * 4 + col + * + */ + if (unlikely(__pyx_v_index == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(0, 68, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v_index, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_col = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":69 + * cdef int row = index[0] + * cdef int col = index[1] + * cdef int i = row * 4 + col # <<<<<<<<<<<<<< + * + * if 0 <= i < 16 and 0 <= col < 4: + */ + __pyx_v_i = ((__pyx_v_row * 4) + __pyx_v_col); + + /* "ezdxf/acc/matrix44.pyx":71 + * cdef int i = row * 4 + col + * + * if 0 <= i < 16 and 0 <= col < 4: # <<<<<<<<<<<<<< + * self.m[i] = value + * else: + */ + __pyx_t_4 = (0 <= __pyx_v_i); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_i < 16); + } + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = (0 <= __pyx_v_col); + if (__pyx_t_4) { + __pyx_t_4 = (__pyx_v_col < 4); + } + __pyx_t_3 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (likely(__pyx_t_3)) { + + /* "ezdxf/acc/matrix44.pyx":72 + * + * if 0 <= i < 16 and 0 <= col < 4: + * self.m[i] = value # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'index out of range: {index}') + */ + (__pyx_v_self->m[__pyx_v_i]) = __pyx_v_value; + + /* "ezdxf/acc/matrix44.pyx":71 + * cdef int i = row * 4 + col + * + * if 0 <= i < 16 and 0 <= col < 4: # <<<<<<<<<<<<<< + * self.m[i] = value + * else: + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/matrix44.pyx":74 + * self.m[i] = value + * else: + * raise IndexError(f'index out of range: {index}') # <<<<<<<<<<<<<< + * + * def __iter__(self): + */ + /*else*/ { + __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_v_index, __pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_kp_u_index_out_of_range, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 74, __pyx_L1_error) + } + __pyx_L3:; + + /* "ezdxf/acc/matrix44.pyx":66 + * raise IndexError(f'index out of range: {index}') + * + * def __setitem__(self, tuple index, double value): # <<<<<<<<<<<<<< + * cdef int row = index[0] + * cdef int col = index[1] + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_10generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":76 + * raise IndexError(f'index out of range: {index}') + * + * def __iter__(self): # <<<<<<<<<<<<<< + * cdef int i + * for i in range(16): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_9__iter__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_9__iter__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__iter__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__iter__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__iter__", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 76, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_10generator, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_Matrix44___iter, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_10generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 76, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":78 + * def __iter__(self): + * cdef int i + * for i in range(16): # <<<<<<<<<<<<<< + * yield self.m[i] + * + */ + for (__pyx_t_1 = 0; __pyx_t_1 < 16; __pyx_t_1+=1) { + __pyx_cur_scope->__pyx_v_i = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":79 + * cdef int i + * for i in range(16): + * yield self.m[i] # <<<<<<<<<<<<<< + * + * def __repr__(self) -> str: + */ + __pyx_t_2 = PyFloat_FromDouble((__pyx_cur_scope->__pyx_v_self->m[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 79, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 79, __pyx_L1_error) + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/matrix44.pyx":76 + * raise IndexError(f'index out of range: {index}') + * + * def __iter__(self): # <<<<<<<<<<<<<< + * cdef int i + * for i in range(16): + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":81 + * yield self.m[i] + * + * def __repr__(self) -> str: # <<<<<<<<<<<<<< + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_11__repr__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":82 + * + * def __repr__(self) -> str: + * def format_row(row): # <<<<<<<<<<<<<< + * return "(%s)" % ", ".join(str(value) for value in row) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___1format_row(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___1format_row = {"format_row", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___1format_row, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___1format_row(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_row = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("format_row (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_row,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_row)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 82, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "format_row") < 0)) __PYX_ERR(0, 82, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_row = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("format_row", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 82, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__repr__.format_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___format_row(__pyx_self, __pyx_v_row); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_2generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":83 + * def __repr__(self) -> str: + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) # <<<<<<<<<<<<<< + * + * return "Matrix44(%s)" % \ + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 83, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_2generator4, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_repr___locals_format_row_local, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__repr__.format_row.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_2generator4(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 83, __pyx_L1_error) + __pyx_r = PyList_New(0); if (unlikely(!__pyx_r)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_r); + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 83, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 83, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 83, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 83, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 83, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 83, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 83, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_value); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_value, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Unicode(__pyx_cur_scope->__pyx_v_value); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(__Pyx_ListComp_Append(__pyx_r, (PyObject*)__pyx_t_4))) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":82 + * + * def __repr__(self) -> str: + * def format_row(row): # <<<<<<<<<<<<<< + * return "(%s)" % ", ".join(str(value) for value in row) + * + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___format_row(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_row) { + PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_2generator4 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("format_row", 1); + + /* "ezdxf/acc/matrix44.pyx":83 + * def __repr__(self) -> str: + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) # <<<<<<<<<<<<<< + * + * return "Matrix44(%s)" % \ + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_genexpr(NULL, __pyx_v_row); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_Generator_Next(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyUnicode_Join(__pyx_kp_u__11, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyUnicode_Format(__pyx_kp_u_s, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":82 + * + * def __repr__(self) -> str: + * def format_row(row): # <<<<<<<<<<<<<< + * return "(%s)" % ", ".join(str(value) for value in row) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__repr__.format_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___10format_row_2generator4); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___4generator5(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":86 + * + * return "Matrix44(%s)" % \ + * ", ".join(format_row(row) for row in self.rows()) # <<<<<<<<<<<<<< + * + * def get_2d_transformation(self) -> Tuple[float, ...]: + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___2genexpr(PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 86, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___4generator5, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_repr___locals_genexpr, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__repr__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___4generator5(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 86, __pyx_L1_error) + __pyx_r = PyList_New(0); if (unlikely(!__pyx_r)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_r); + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 86, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 86, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 86, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 86, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 86, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 86, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 86, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_row); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_row, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_format_row)) { __Pyx_RaiseClosureNameError("format_row"); __PYX_ERR(0, 86, __pyx_L1_error) } + __pyx_t_4 = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___format_row(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_format_row, __pyx_cur_scope->__pyx_v_row); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(__Pyx_ListComp_Append(__pyx_r, (PyObject*)__pyx_t_4))) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":81 + * yield self.m[i] + * + * def __repr__(self) -> str: # <<<<<<<<<<<<<< + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_11__repr__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *__pyx_cur_scope; + PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___4generator5 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 81, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + + /* "ezdxf/acc/matrix44.pyx":82 + * + * def __repr__(self) -> str: + * def format_row(row): # <<<<<<<<<<<<<< + * return "(%s)" % ", ".join(str(value) for value in row) + * + */ + __pyx_t_1 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___1format_row, 0, __pyx_n_s_repr___locals_format_row, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_v_format_row = __pyx_t_1; + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":85 + * return "(%s)" % ", ".join(str(value) for value in row) + * + * return "Matrix44(%s)" % \ # <<<<<<<<<<<<<< + * ", ".join(format_row(row) for row in self.rows()) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "ezdxf/acc/matrix44.pyx":86 + * + * return "Matrix44(%s)" % \ + * ", ".join(format_row(row) for row in self.rows()) # <<<<<<<<<<<<<< + * + * def get_2d_transformation(self) -> Tuple[float, ...]: + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_rows); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___2genexpr(((PyObject*)__pyx_cur_scope), __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_Generator_Next(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyUnicode_Join(__pyx_kp_u__11, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":85 + * return "(%s)" % ", ".join(str(value) for value in row) + * + * return "Matrix44(%s)" % \ # <<<<<<<<<<<<<< + * ", ".join(format_row(row) for row in self.rows()) + * + */ + __pyx_t_1 = PyUnicode_Format(__pyx_kp_u_Matrix44_s, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 85, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":81 + * yield self.m[i] + * + * def __repr__(self) -> str: # <<<<<<<<<<<<<< + * def format_row(row): + * return "(%s)" % ", ".join(str(value) for value in row) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_8__repr___4generator5); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":88 + * ", ".join(format_row(row) for row in self.rows()) + * + * def get_2d_transformation(self) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation = {"get_2d_transformation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_2d_transformation (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("get_2d_transformation", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "get_2d_transformation", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13get_2d_transformation(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13get_2d_transformation(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + double *__pyx_v_m; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_2d_transformation", 1); + + /* "ezdxf/acc/matrix44.pyx":89 + * + * def get_2d_transformation(self) -> Tuple[float, ...]: + * cdef double *m = self.m # <<<<<<<<<<<<<< + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + * + */ + __pyx_t_1 = __pyx_v_self->m; + __pyx_v_m = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":90 + * def get_2d_transformation(self) -> Tuple[float, ...]: + * cdef double *m = self.m + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble((__pyx_v_m[0])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_m[1])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_m[4])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyFloat_FromDouble((__pyx_v_m[5])); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyFloat_FromDouble((__pyx_v_m[12])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_m[13])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyTuple_New(9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 90, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_3)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_float_0_0)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 3, __pyx_t_4)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 4, __pyx_t_5)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 5, __pyx_float_0_0)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 6, __pyx_t_6)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 7, __pyx_t_7)) __PYX_ERR(0, 90, __pyx_L1_error); + __Pyx_INCREF(__pyx_float_1_0); + __Pyx_GIVEREF(__pyx_float_1_0); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 8, __pyx_float_1_0)) __PYX_ERR(0, 90, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_r = ((PyObject*)__pyx_t_8); + __pyx_t_8 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":88 + * ", ".join(format_row(row) for row in self.rows()) + * + * def get_2d_transformation(self) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_2d_transformation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":92 + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation = {"from_2d_transformation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_components = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("from_2d_transformation (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_components,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_components)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 92, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "from_2d_transformation") < 0)) __PYX_ERR(0, 92, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_components = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("from_2d_transformation", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 92, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.from_2d_transformation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_15from_2d_transformation(__pyx_v_components); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_15from_2d_transformation(PyObject *__pyx_v_components) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_m44 = NULL; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("from_2d_transformation", 1); + + /* "ezdxf/acc/matrix44.pyx":94 + * @staticmethod + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: # <<<<<<<<<<<<<< + * raise ValueError( + * "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + */ + __pyx_t_1 = PyObject_Length(__pyx_v_components); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 94, __pyx_L1_error) + __pyx_t_2 = (__pyx_t_1 != 6); + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/matrix44.pyx":95 + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + * raise ValueError( # <<<<<<<<<<<<<< + * "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + * ) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__14, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 95, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":94 + * @staticmethod + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: # <<<<<<<<<<<<<< + * raise ValueError( + * "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + */ + } + + /* "ezdxf/acc/matrix44.pyx":99 + * ) + * + * m44 = Matrix44() # <<<<<<<<<<<<<< + * m44.m[0] = components[0] + * m44.m[1] = components[1] + */ + __pyx_t_3 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 99, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_v_m44 = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/matrix44.pyx":100 + * + * m44 = Matrix44() + * m44.m[0] = components[0] # <<<<<<<<<<<<<< + * m44.m[1] = components[1] + * m44.m[4] = components[2] + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 100, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[0]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":101 + * m44 = Matrix44() + * m44.m[0] = components[0] + * m44.m[1] = components[1] # <<<<<<<<<<<<<< + * m44.m[4] = components[2] + * m44.m[5] = components[3] + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[1]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":102 + * m44.m[0] = components[0] + * m44.m[1] = components[1] + * m44.m[4] = components[2] # <<<<<<<<<<<<<< + * m44.m[5] = components[3] + * m44.m[12] = components[4] + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[4]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":103 + * m44.m[1] = components[1] + * m44.m[4] = components[2] + * m44.m[5] = components[3] # <<<<<<<<<<<<<< + * m44.m[12] = components[4] + * m44.m[13] = components[5] + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[5]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":104 + * m44.m[4] = components[2] + * m44.m[5] = components[3] + * m44.m[12] = components[4] # <<<<<<<<<<<<<< + * m44.m[13] = components[5] + * return m44 + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 4, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[12]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":105 + * m44.m[5] = components[3] + * m44.m[12] = components[4] + * m44.m[13] = components[5] # <<<<<<<<<<<<<< + * return m44 + * + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_components, 5, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + (__pyx_v_m44->m[13]) = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":106 + * m44.m[12] = components[4] + * m44.m[13] = components[5] + * return m44 # <<<<<<<<<<<<<< + * + * def get_row(self, int row) -> Tuple[float, ...]: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_m44); + __pyx_r = __pyx_v_m44; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":92 + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.from_2d_transformation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_m44); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":108 + * return m44 + * + * def get_row(self, int row) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef int index = row * 4 + * if 0 <= index < 13: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_18get_row(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_18get_row = {"get_row", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_18get_row, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_18get_row(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_row; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_row (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_row,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_row)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 108, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_row") < 0)) __PYX_ERR(0, 108, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_row = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_row == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 108, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("get_row", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 108, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_17get_row(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_row); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_17get_row(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_row) { + int __pyx_v_index; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_row", 1); + + /* "ezdxf/acc/matrix44.pyx":109 + * + * def get_row(self, int row) -> Tuple[float, ...]: + * cdef int index = row * 4 # <<<<<<<<<<<<<< + * if 0 <= index < 13: + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ + */ + __pyx_v_index = (__pyx_v_row * 4); + + /* "ezdxf/acc/matrix44.pyx":110 + * def get_row(self, int row) -> Tuple[float, ...]: + * cdef int index = row * 4 + * if 0 <= index < 13: # <<<<<<<<<<<<<< + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ + * index + 3] + */ + __pyx_t_1 = (0 <= __pyx_v_index); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_index < 13); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/matrix44.pyx":111 + * cdef int index = row * 4 + * if 0 <= index < 13: + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ # <<<<<<<<<<<<<< + * index + 3] + * else: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble((__pyx_v_self->m[__pyx_v_index])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_index + 1)])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_index + 2)])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "ezdxf/acc/matrix44.pyx":112 + * if 0 <= index < 13: + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ + * index + 3] # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid row index: {row}') + */ + __pyx_t_5 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_index + 3)])); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "ezdxf/acc/matrix44.pyx":111 + * cdef int index = row * 4 + * if 0 <= index < 13: + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ # <<<<<<<<<<<<<< + * index + 3] + * else: + */ + __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 111, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2)) __PYX_ERR(0, 111, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_3)) __PYX_ERR(0, 111, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_4)) __PYX_ERR(0, 111, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_5)) __PYX_ERR(0, 111, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_r = ((PyObject*)__pyx_t_6); + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":110 + * def get_row(self, int row) -> Tuple[float, ...]: + * cdef int index = row * 4 + * if 0 <= index < 13: # <<<<<<<<<<<<<< + * return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ + * index + 3] + */ + } + + /* "ezdxf/acc/matrix44.pyx":114 + * index + 3] + * else: + * raise IndexError(f'invalid row index: {row}') # <<<<<<<<<<<<<< + * + * def set_row(self, int row, values: Sequence[float]) -> None: + */ + /*else*/ { + __pyx_t_6 = __Pyx_PyUnicode_From_int(__pyx_v_row, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_row_index, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_6, 0, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(0, 114, __pyx_L1_error) + } + + /* "ezdxf/acc/matrix44.pyx":108 + * return m44 + * + * def get_row(self, int row) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef int index = row * 4 + * if 0 <= index < 13: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":116 + * raise IndexError(f'invalid row index: {row}') + * + * def set_row(self, int row, values: Sequence[float]) -> None: # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t start = row * 4 + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_20set_row(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_20set_row = {"set_row", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_20set_row, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_20set_row(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_row; + PyObject *__pyx_v_values = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set_row (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_row,&__pyx_n_s_values,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_row)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 116, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_values)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 116, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("set_row", 1, 2, 2, 1); __PYX_ERR(0, 116, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "set_row") < 0)) __PYX_ERR(0, 116, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_row = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_row == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 116, __pyx_L3_error) + __pyx_v_values = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set_row", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 116, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.set_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_19set_row(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_row, __pyx_v_values); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_19set_row(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_row, PyObject *__pyx_v_values) { + Py_ssize_t __pyx_v_count; + Py_ssize_t __pyx_v_start; + Py_ssize_t __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + double __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set_row", 1); + + /* "ezdxf/acc/matrix44.pyx":117 + * + * def set_row(self, int row, values: Sequence[float]) -> None: + * cdef Py_ssize_t count = len(values) # <<<<<<<<<<<<<< + * cdef Py_ssize_t start = row * 4 + * cdef Py_ssize_t i + */ + __pyx_t_1 = PyObject_Length(__pyx_v_values); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 117, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":118 + * def set_row(self, int row, values: Sequence[float]) -> None: + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t start = row * 4 # <<<<<<<<<<<<<< + * cdef Py_ssize_t i + * if 0 <= row < 4: + */ + __pyx_v_start = (__pyx_v_row * 4); + + /* "ezdxf/acc/matrix44.pyx":120 + * cdef Py_ssize_t start = row * 4 + * cdef Py_ssize_t i + * if 0 <= row < 4: # <<<<<<<<<<<<<< + * if count > 4: + * count = 4 + */ + __pyx_t_2 = (0 <= __pyx_v_row); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_row < 4); + } + if (likely(__pyx_t_2)) { + + /* "ezdxf/acc/matrix44.pyx":121 + * cdef Py_ssize_t i + * if 0 <= row < 4: + * if count > 4: # <<<<<<<<<<<<<< + * count = 4 + * for i in range(count): + */ + __pyx_t_2 = (__pyx_v_count > 4); + if (__pyx_t_2) { + + /* "ezdxf/acc/matrix44.pyx":122 + * if 0 <= row < 4: + * if count > 4: + * count = 4 # <<<<<<<<<<<<<< + * for i in range(count): + * self.m[start + i] = values[i] + */ + __pyx_v_count = 4; + + /* "ezdxf/acc/matrix44.pyx":121 + * cdef Py_ssize_t i + * if 0 <= row < 4: + * if count > 4: # <<<<<<<<<<<<<< + * count = 4 + * for i in range(count): + */ + } + + /* "ezdxf/acc/matrix44.pyx":123 + * if count > 4: + * count = 4 + * for i in range(count): # <<<<<<<<<<<<<< + * self.m[start + i] = values[i] + * else: + */ + __pyx_t_1 = __pyx_v_count; + __pyx_t_3 = __pyx_t_1; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":124 + * count = 4 + * for i in range(count): + * self.m[start + i] = values[i] # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid row index: {row}') + */ + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_values, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 124, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 124, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + (__pyx_v_self->m[(__pyx_v_start + __pyx_v_i)]) = __pyx_t_6; + } + + /* "ezdxf/acc/matrix44.pyx":120 + * cdef Py_ssize_t start = row * 4 + * cdef Py_ssize_t i + * if 0 <= row < 4: # <<<<<<<<<<<<<< + * if count > 4: + * count = 4 + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/matrix44.pyx":126 + * self.m[start + i] = values[i] + * else: + * raise IndexError(f'invalid row index: {row}') # <<<<<<<<<<<<<< + * + * def get_col(self, int col) -> Tuple[float, ...]: + */ + /*else*/ { + __pyx_t_5 = __Pyx_PyUnicode_From_int(__pyx_v_row, 0, ' ', 'd'); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_row_index, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_7); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 126, __pyx_L1_error) + } + __pyx_L3:; + + /* "ezdxf/acc/matrix44.pyx":116 + * raise IndexError(f'invalid row index: {row}') + * + * def set_row(self, int row, values: Sequence[float]) -> None: # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t start = row * 4 + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.set_row", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":128 + * raise IndexError(f'invalid row index: {row}') + * + * def get_col(self, int col) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_22get_col(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_22get_col = {"get_col", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_22get_col, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_22get_col(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_col; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_col (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_col,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_col)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_col") < 0)) __PYX_ERR(0, 128, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_col = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_col == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("get_col", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 128, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_col", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_21get_col(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_col); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_21get_col(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_col) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_col", 1); + + /* "ezdxf/acc/matrix44.pyx":129 + * + * def get_col(self, int col) -> Tuple[float, ...]: + * if 0 <= col < 4: # <<<<<<<<<<<<<< + * return self.m[col], self.m[col + 4], \ + * self.m[col + 8], self.m[col + 12] + */ + __pyx_t_1 = (0 <= __pyx_v_col); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_col < 4); + } + if (likely(__pyx_t_1)) { + + /* "ezdxf/acc/matrix44.pyx":130 + * def get_col(self, int col) -> Tuple[float, ...]: + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ # <<<<<<<<<<<<<< + * self.m[col + 8], self.m[col + 12] + * else: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble((__pyx_v_self->m[__pyx_v_col])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_col + 4)])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "ezdxf/acc/matrix44.pyx":131 + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ + * self.m[col + 8], self.m[col + 12] # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid col index: {col}') + */ + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_col + 8)])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyFloat_FromDouble((__pyx_v_self->m[(__pyx_v_col + 12)])); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "ezdxf/acc/matrix44.pyx":130 + * def get_col(self, int col) -> Tuple[float, ...]: + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ # <<<<<<<<<<<<<< + * self.m[col + 8], self.m[col + 12] + * else: + */ + __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_3)) __PYX_ERR(0, 130, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_4)) __PYX_ERR(0, 130, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_5)) __PYX_ERR(0, 130, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_r = ((PyObject*)__pyx_t_6); + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":129 + * + * def get_col(self, int col) -> Tuple[float, ...]: + * if 0 <= col < 4: # <<<<<<<<<<<<<< + * return self.m[col], self.m[col + 4], \ + * self.m[col + 8], self.m[col + 12] + */ + } + + /* "ezdxf/acc/matrix44.pyx":133 + * self.m[col + 8], self.m[col + 12] + * else: + * raise IndexError(f'invalid col index: {col}') # <<<<<<<<<<<<<< + * + * def set_col(self, int col, values: Sequence[float]): + */ + /*else*/ { + __pyx_t_6 = __Pyx_PyUnicode_From_int(__pyx_v_col, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_col_index, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_6, 0, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(0, 133, __pyx_L1_error) + } + + /* "ezdxf/acc/matrix44.pyx":128 + * raise IndexError(f'invalid row index: {row}') + * + * def get_col(self, int col) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_col", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":135 + * raise IndexError(f'invalid col index: {col}') + * + * def set_col(self, int col, values: Sequence[float]): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_24set_col(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_24set_col = {"set_col", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_24set_col, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_24set_col(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + int __pyx_v_col; + PyObject *__pyx_v_values = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set_col (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_col,&__pyx_n_s_values,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_col)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_values)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("set_col", 1, 2, 2, 1); __PYX_ERR(0, 135, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "set_col") < 0)) __PYX_ERR(0, 135, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_col = __Pyx_PyInt_As_int(values[0]); if (unlikely((__pyx_v_col == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L3_error) + __pyx_v_values = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set_col", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 135, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.set_col", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_23set_col(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_col, __pyx_v_values); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_23set_col(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, int __pyx_v_col, PyObject *__pyx_v_values) { + Py_ssize_t __pyx_v_count; + Py_ssize_t __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + double __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set_col", 1); + + /* "ezdxf/acc/matrix44.pyx":136 + * + * def set_col(self, int col, values: Sequence[float]): + * cdef Py_ssize_t count = len(values) # <<<<<<<<<<<<<< + * cdef Py_ssize_t i + * if 0 <= col < 4: + */ + __pyx_t_1 = PyObject_Length(__pyx_v_values); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 136, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":138 + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + * if 0 <= col < 4: # <<<<<<<<<<<<<< + * if count > 4: + * count = 4 + */ + __pyx_t_2 = (0 <= __pyx_v_col); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_col < 4); + } + if (likely(__pyx_t_2)) { + + /* "ezdxf/acc/matrix44.pyx":139 + * cdef Py_ssize_t i + * if 0 <= col < 4: + * if count > 4: # <<<<<<<<<<<<<< + * count = 4 + * for i in range(count): + */ + __pyx_t_2 = (__pyx_v_count > 4); + if (__pyx_t_2) { + + /* "ezdxf/acc/matrix44.pyx":140 + * if 0 <= col < 4: + * if count > 4: + * count = 4 # <<<<<<<<<<<<<< + * for i in range(count): + * self.m[col + i * 4] = values[i] + */ + __pyx_v_count = 4; + + /* "ezdxf/acc/matrix44.pyx":139 + * cdef Py_ssize_t i + * if 0 <= col < 4: + * if count > 4: # <<<<<<<<<<<<<< + * count = 4 + * for i in range(count): + */ + } + + /* "ezdxf/acc/matrix44.pyx":141 + * if count > 4: + * count = 4 + * for i in range(count): # <<<<<<<<<<<<<< + * self.m[col + i * 4] = values[i] + * else: + */ + __pyx_t_1 = __pyx_v_count; + __pyx_t_3 = __pyx_t_1; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "ezdxf/acc/matrix44.pyx":142 + * count = 4 + * for i in range(count): + * self.m[col + i * 4] = values[i] # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid col index: {col}') + */ + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_values, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_5); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + (__pyx_v_self->m[(__pyx_v_col + (__pyx_v_i * 4))]) = __pyx_t_6; + } + + /* "ezdxf/acc/matrix44.pyx":138 + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + * if 0 <= col < 4: # <<<<<<<<<<<<<< + * if count > 4: + * count = 4 + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/matrix44.pyx":144 + * self.m[col + i * 4] = values[i] + * else: + * raise IndexError(f'invalid col index: {col}') # <<<<<<<<<<<<<< + * + * def rows(self) -> Iterator[Tuple[float, ...]]: + */ + /*else*/ { + __pyx_t_5 = __Pyx_PyUnicode_From_int(__pyx_v_col, 0, ' ', 'd'); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_col_index, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_7); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 144, __pyx_L1_error) + } + __pyx_L3:; + + /* "ezdxf/acc/matrix44.pyx":135 + * raise IndexError(f'invalid col index: {col}') + * + * def set_col(self, int col, values: Sequence[float]): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.set_col", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_26rows(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_26rows = {"rows", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_26rows, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_26rows(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rows (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("rows", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "rows", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_25rows(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_4rows_2generator6(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":147 + * + * def rows(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_row(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4rows_genexpr(PyObject *__pyx_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 147, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_4rows_2generator6, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_rows_locals_genexpr, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.rows.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_4rows_2generator6(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 147, __pyx_L1_error) + __pyx_t_1 = __pyx_tuple__15; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + if (__pyx_t_2 >= 4) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 147, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_index); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_index, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __pyx_t_3 = 0; + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); __PYX_ERR(0, 147, __pyx_L1_error) } + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_n_s_get_row); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_cur_scope->__pyx_v_index}; + __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 147, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_25rows(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *__pyx_cur_scope; + PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_4rows_2generator6 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("rows", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 146, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + + /* "ezdxf/acc/matrix44.pyx":147 + * + * def rows(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_row(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_4rows_genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.rows", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_4rows_2generator6); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_28columns(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_28columns = {"columns", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_28columns, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_28columns(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("columns (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("columns", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "columns", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_27columns(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_7columns_2generator7(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":150 + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_col(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def copy(self) -> Matrix44: + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_7columns_genexpr(PyObject *__pyx_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 150, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *) __pyx_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_outer_scope); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_7columns_2generator7, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_columns_locals_genexpr, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.columns.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_7columns_2generator7(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 150, __pyx_L1_error) + __pyx_t_1 = __pyx_tuple__15; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + if (__pyx_t_2 >= 4) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 150, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_index); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_index, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __pyx_t_3 = 0; + if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); __PYX_ERR(0, 150, __pyx_L1_error) } + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_n_s_get_col); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_cur_scope->__pyx_v_index}; + __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 150, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_27columns(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *__pyx_cur_scope; + PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_7columns_2generator7 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("columns", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 149, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + + /* "ezdxf/acc/matrix44.pyx":150 + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_col(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def copy(self) -> Matrix44: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_7columns_genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.columns", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_7columns_2generator7); + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":152 + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + * def copy(self) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_30copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_30copy = {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_30copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_30copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_29copy(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_29copy(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v__copy = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double *__pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("copy", 1); + + /* "ezdxf/acc/matrix44.pyx":153 + * + * def copy(self) -> Matrix44: + * cdef Matrix44 _copy = Matrix44() # <<<<<<<<<<<<<< + * _copy.m = self.m + * return _copy + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__copy = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":154 + * def copy(self) -> Matrix44: + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m # <<<<<<<<<<<<<< + * return _copy + * + */ + __pyx_t_2 = __pyx_v_self->m; + memcpy(&(__pyx_v__copy->m[0]), __pyx_t_2, sizeof(__pyx_v__copy->m[0]) * (16 - 0)); + + /* "ezdxf/acc/matrix44.pyx":155 + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m + * return _copy # <<<<<<<<<<<<<< + * + * __copy__ = copy + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v__copy); + __pyx_r = __pyx_v__copy; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":152 + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + * def copy(self) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.copy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v__copy); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":159 + * __copy__ = copy + * + * @property # <<<<<<<<<<<<<< + * def origin(self) -> Vec3: + * cdef Vec3 v = Vec3() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":161 + * @property + * def origin(self) -> Vec3: + * cdef Vec3 v = Vec3() # <<<<<<<<<<<<<< + * v.x = self.m[12] + * v.y = self.m[13] + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":162 + * def origin(self) -> Vec3: + * cdef Vec3 v = Vec3() + * v.x = self.m[12] # <<<<<<<<<<<<<< + * v.y = self.m[13] + * v.z = self.m[14] + */ + __pyx_v_v->x = (__pyx_v_self->m[12]); + + /* "ezdxf/acc/matrix44.pyx":163 + * cdef Vec3 v = Vec3() + * v.x = self.m[12] + * v.y = self.m[13] # <<<<<<<<<<<<<< + * v.z = self.m[14] + * return v + */ + __pyx_v_v->y = (__pyx_v_self->m[13]); + + /* "ezdxf/acc/matrix44.pyx":164 + * v.x = self.m[12] + * v.y = self.m[13] + * v.z = self.m[14] # <<<<<<<<<<<<<< + * return v + * + */ + __pyx_v_v->z = (__pyx_v_self->m[14]); + + /* "ezdxf/acc/matrix44.pyx":165 + * v.y = self.m[13] + * v.z = self.m[14] + * return v # <<<<<<<<<<<<<< + * + * @origin.setter + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_v); + __pyx_r = ((PyObject *)__pyx_v_v); + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":159 + * __copy__ = copy + * + * @property # <<<<<<<<<<<<<< + * def origin(self) -> Vec3: + * cdef Vec3 v = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.origin.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_v); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":167 + * return v + * + * @origin.setter # <<<<<<<<<<<<<< + * def origin(self, v: UVec) -> None: + * cdef Vec3 origin = Vec3(v) + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_v); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_v) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__set__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin_2__set__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((PyObject *)__pyx_v_v)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_6origin_2__set__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_v) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_origin = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__set__", 1); + + /* "ezdxf/acc/matrix44.pyx":169 + * @origin.setter + * def origin(self, v: UVec) -> None: + * cdef Vec3 origin = Vec3(v) # <<<<<<<<<<<<<< + * self.m[12] = origin.x + * self.m[13] = origin.y + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_v); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 169, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_origin = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":170 + * def origin(self, v: UVec) -> None: + * cdef Vec3 origin = Vec3(v) + * self.m[12] = origin.x # <<<<<<<<<<<<<< + * self.m[13] = origin.y + * self.m[14] = origin.z + */ + __pyx_t_2 = __pyx_v_origin->x; + (__pyx_v_self->m[12]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":171 + * cdef Vec3 origin = Vec3(v) + * self.m[12] = origin.x + * self.m[13] = origin.y # <<<<<<<<<<<<<< + * self.m[14] = origin.z + * + */ + __pyx_t_2 = __pyx_v_origin->y; + (__pyx_v_self->m[13]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":172 + * self.m[12] = origin.x + * self.m[13] = origin.y + * self.m[14] = origin.z # <<<<<<<<<<<<<< + * + * @property + */ + __pyx_t_2 = __pyx_v_origin->z; + (__pyx_v_self->m[14]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":167 + * return v + * + * @origin.setter # <<<<<<<<<<<<<< + * def origin(self, v: UVec) -> None: + * cdef Vec3 origin = Vec3(v) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.origin.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_origin); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":174 + * self.m[14] = origin.z + * + * @property # <<<<<<<<<<<<<< + * def ux(self) -> Vec3: + * return self.get_ux() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2ux_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2ux_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2ux___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2ux___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":176 + * @property + * def ux(self) -> Vec3: + * return self.get_ux() # <<<<<<<<<<<<<< + * + * cdef Vec3 get_ux(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_ux(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 176, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":174 + * self.m[14] = origin.z + * + * @property # <<<<<<<<<<<<<< + * def ux(self) -> Vec3: + * return self.get_ux() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ux.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":178 + * return self.get_ux() + * + * cdef Vec3 get_ux(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[0] + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_ux(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_ux", 1); + + /* "ezdxf/acc/matrix44.pyx":179 + * + * cdef Vec3 get_ux(self): + * cdef Vec3 v = Vec3() # <<<<<<<<<<<<<< + * v.x = self.m[0] + * v.y = self.m[1] + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 179, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":180 + * cdef Vec3 get_ux(self): + * cdef Vec3 v = Vec3() + * v.x = self.m[0] # <<<<<<<<<<<<<< + * v.y = self.m[1] + * v.z = self.m[2] + */ + __pyx_v_v->x = (__pyx_v_self->m[0]); + + /* "ezdxf/acc/matrix44.pyx":181 + * cdef Vec3 v = Vec3() + * v.x = self.m[0] + * v.y = self.m[1] # <<<<<<<<<<<<<< + * v.z = self.m[2] + * return v + */ + __pyx_v_v->y = (__pyx_v_self->m[1]); + + /* "ezdxf/acc/matrix44.pyx":182 + * v.x = self.m[0] + * v.y = self.m[1] + * v.z = self.m[2] # <<<<<<<<<<<<<< + * return v + * + */ + __pyx_v_v->z = (__pyx_v_self->m[2]); + + /* "ezdxf/acc/matrix44.pyx":183 + * v.y = self.m[1] + * v.z = self.m[2] + * return v # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_v); + __pyx_r = __pyx_v_v; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":178 + * return self.get_ux() + * + * cdef Vec3 get_ux(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[0] + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_ux", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_v); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":185 + * return v + * + * @property # <<<<<<<<<<<<<< + * def uy(self) -> Vec3: + * return self.get_uy() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uy_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uy_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uy___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uy___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":187 + * @property + * def uy(self) -> Vec3: + * return self.get_uy() # <<<<<<<<<<<<<< + * + * cdef Vec3 get_uy(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uy(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":185 + * return v + * + * @property # <<<<<<<<<<<<<< + * def uy(self) -> Vec3: + * return self.get_uy() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.uy.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":189 + * return self.get_uy() + * + * cdef Vec3 get_uy(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[4] + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uy(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_uy", 1); + + /* "ezdxf/acc/matrix44.pyx":190 + * + * cdef Vec3 get_uy(self): + * cdef Vec3 v = Vec3() # <<<<<<<<<<<<<< + * v.x = self.m[4] + * v.y = self.m[5] + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":191 + * cdef Vec3 get_uy(self): + * cdef Vec3 v = Vec3() + * v.x = self.m[4] # <<<<<<<<<<<<<< + * v.y = self.m[5] + * v.z = self.m[6] + */ + __pyx_v_v->x = (__pyx_v_self->m[4]); + + /* "ezdxf/acc/matrix44.pyx":192 + * cdef Vec3 v = Vec3() + * v.x = self.m[4] + * v.y = self.m[5] # <<<<<<<<<<<<<< + * v.z = self.m[6] + * return v + */ + __pyx_v_v->y = (__pyx_v_self->m[5]); + + /* "ezdxf/acc/matrix44.pyx":193 + * v.x = self.m[4] + * v.y = self.m[5] + * v.z = self.m[6] # <<<<<<<<<<<<<< + * return v + * + */ + __pyx_v_v->z = (__pyx_v_self->m[6]); + + /* "ezdxf/acc/matrix44.pyx":194 + * v.y = self.m[5] + * v.z = self.m[6] + * return v # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_v); + __pyx_r = __pyx_v_v; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":189 + * return self.get_uy() + * + * cdef Vec3 get_uy(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[4] + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_uy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_v); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":196 + * return v + * + * @property # <<<<<<<<<<<<<< + * def uz(self) -> Vec3: + * return self.get_uz() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uz_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uz_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uz___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_2uz___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":198 + * @property + * def uz(self) -> Vec3: + * return self.get_uz() # <<<<<<<<<<<<<< + * + * cdef Vec3 get_uz(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uz(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":196 + * return v + * + * @property # <<<<<<<<<<<<<< + * def uz(self) -> Vec3: + * return self.get_uz() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.uz.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":200 + * return self.get_uz() + * + * cdef Vec3 get_uz(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[8] + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uz(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_uz", 1); + + /* "ezdxf/acc/matrix44.pyx":201 + * + * cdef Vec3 get_uz(self): + * cdef Vec3 v = Vec3() # <<<<<<<<<<<<<< + * v.x = self.m[8] + * v.y = self.m[9] + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 201, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":202 + * cdef Vec3 get_uz(self): + * cdef Vec3 v = Vec3() + * v.x = self.m[8] # <<<<<<<<<<<<<< + * v.y = self.m[9] + * v.z = self.m[10] + */ + __pyx_v_v->x = (__pyx_v_self->m[8]); + + /* "ezdxf/acc/matrix44.pyx":203 + * cdef Vec3 v = Vec3() + * v.x = self.m[8] + * v.y = self.m[9] # <<<<<<<<<<<<<< + * v.z = self.m[10] + * return v + */ + __pyx_v_v->y = (__pyx_v_self->m[9]); + + /* "ezdxf/acc/matrix44.pyx":204 + * v.x = self.m[8] + * v.y = self.m[9] + * v.z = self.m[10] # <<<<<<<<<<<<<< + * return v + * + */ + __pyx_v_v->z = (__pyx_v_self->m[10]); + + /* "ezdxf/acc/matrix44.pyx":205 + * v.y = self.m[9] + * v.z = self.m[10] + * return v # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_v); + __pyx_r = __pyx_v_v; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":200 + * return self.get_uz() + * + * cdef Vec3 get_uz(self): # <<<<<<<<<<<<<< + * cdef Vec3 v = Vec3() + * v.x = self.m[8] + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.get_uz", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_v); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":207 + * return v + * + * @property # <<<<<<<<<<<<<< + * def is_cartesian(self) -> bool: + * cdef Vec3 x_axis = v3_cross(self.get_uy(), self.get_uz()) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_x_axis = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":209 + * @property + * def is_cartesian(self) -> bool: + * cdef Vec3 x_axis = v3_cross(self.get_uy(), self.get_uz()) # <<<<<<<<<<<<<< + * return v3_isclose(x_axis, self.get_ux(), REL_TOL, ABS_TOL) + * + */ + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uy(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uz(__pyx_v_self)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_cross(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_x_axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/matrix44.pyx":210 + * def is_cartesian(self) -> bool: + * cdef Vec3 x_axis = v3_cross(self.get_uy(), self.get_uz()) + * return v3_isclose(x_axis, self.get_ux(), REL_TOL, ABS_TOL) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_ux(__pyx_v_self)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_v_x_axis, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3), REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 210, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":207 + * return v + * + * @property # <<<<<<<<<<<<<< + * def is_cartesian(self) -> bool: + * cdef Vec3 x_axis = v3_cross(self.get_uy(), self.get_uz()) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.is_cartesian.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_x_axis); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":212 + * return v3_isclose(x_axis, self.get_ux(), REL_TOL, ABS_TOL) + * + * @property # <<<<<<<<<<<<<< + * def is_orthogonal(self) -> bool: + * cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal___get__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal___get__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_ux = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_uy = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_uz = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/matrix44.pyx":214 + * @property + * def is_orthogonal(self) -> bool: + * cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) # <<<<<<<<<<<<<< + * cdef Vec3 uy = v3_normalize(self.get_uy(), 1.0) + * cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) + */ + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_ux(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_ux = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":215 + * def is_orthogonal(self) -> bool: + * cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) + * cdef Vec3 uy = v3_normalize(self.get_uy(), 1.0) # <<<<<<<<<<<<<< + * cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) + * return fabs(v3_dot(ux, uy)) < 1e-9 and \ + */ + __pyx_t_2 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uy(__pyx_v_self)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2), 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_uy = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":216 + * cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) + * cdef Vec3 uy = v3_normalize(self.get_uy(), 1.0) + * cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) # <<<<<<<<<<<<<< + * return fabs(v3_dot(ux, uy)) < 1e-9 and \ + * fabs(v3_dot(ux, uz)) < 1e-9 and \ + */ + __pyx_t_1 = ((PyObject *)((struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self->__pyx_vtab)->get_uz(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 216, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 216, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_uz = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":217 + * cdef Vec3 uy = v3_normalize(self.get_uy(), 1.0) + * cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) + * return fabs(v3_dot(ux, uy)) < 1e-9 and \ # <<<<<<<<<<<<<< + * fabs(v3_dot(ux, uz)) < 1e-9 and \ + * fabs(v3_dot(uy, uz)) < 1e-9 + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_ux, __pyx_v_uy); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 217, __pyx_L1_error) + __pyx_t_4 = (fabs(__pyx_t_3) < 1e-9); + if (__pyx_t_4) { + } else { + __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/matrix44.pyx":218 + * cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) + * return fabs(v3_dot(ux, uy)) < 1e-9 and \ + * fabs(v3_dot(ux, uz)) < 1e-9 and \ # <<<<<<<<<<<<<< + * fabs(v3_dot(uy, uz)) < 1e-9 + * + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_ux, __pyx_v_uz); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 218, __pyx_L1_error) + __pyx_t_4 = (fabs(__pyx_t_3) < 1e-9); + if (__pyx_t_4) { + } else { + __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 218, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/matrix44.pyx":219 + * return fabs(v3_dot(ux, uy)) < 1e-9 and \ + * fabs(v3_dot(ux, uz)) < 1e-9 and \ + * fabs(v3_dot(uy, uz)) < 1e-9 # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_uy, __pyx_v_uz); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 219, __pyx_L1_error) + __pyx_t_4 = (fabs(__pyx_t_3) < 1e-9); + __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __pyx_t_1 = 0; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":212 + * return v3_isclose(x_axis, self.get_ux(), REL_TOL, ABS_TOL) + * + * @property # <<<<<<<<<<<<<< + * def is_orthogonal(self) -> bool: + * cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.is_orthogonal.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_ux); + __Pyx_XDECREF((PyObject *)__pyx_v_uy); + __Pyx_XDECREF((PyObject *)__pyx_v_uz); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":221 + * fabs(v3_dot(uy, uz)) < 1e-9 + * + * @staticmethod # <<<<<<<<<<<<<< + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_32scale(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_32scale = {"scale", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_32scale, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_32scale(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_sx; + PyObject *__pyx_v_sy = 0; + PyObject *__pyx_v_sz = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("scale (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_sx,&__pyx_n_s_sy,&__pyx_n_s_sz,0}; + + /* "ezdxf/acc/matrix44.pyx":222 + * + * @staticmethod + * def scale(double sx, sy = None, sz = None) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 mat = Matrix44() + * mat.m[0] = sx + */ + values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_None)); + values[2] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_None)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_sx)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 221, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_sy); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 221, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_sz); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 221, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "scale") < 0)) __PYX_ERR(0, 221, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_sx = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_sx == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 222, __pyx_L3_error) + __pyx_v_sy = values[1]; + __pyx_v_sz = values[2]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("scale", 0, 1, 3, __pyx_nargs); __PYX_ERR(0, 221, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.scale", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_31scale(__pyx_v_sx, __pyx_v_sy, __pyx_v_sz); + + /* "ezdxf/acc/matrix44.pyx":221 + * fabs(v3_dot(uy, uz)) < 1e-9 + * + * @staticmethod # <<<<<<<<<<<<<< + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_31scale(double __pyx_v_sx, PyObject *__pyx_v_sy, PyObject *__pyx_v_sz) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + double __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("scale", 1); + + /* "ezdxf/acc/matrix44.pyx":223 + * @staticmethod + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * mat.m[0] = sx + * mat.m[5] = sx if sy is None else sy + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":224 + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * mat.m[0] = sx # <<<<<<<<<<<<<< + * mat.m[5] = sx if sy is None else sy + * mat.m[10] = sx if sz is None else sz + */ + (__pyx_v_mat->m[0]) = __pyx_v_sx; + + /* "ezdxf/acc/matrix44.pyx":225 + * cdef Matrix44 mat = Matrix44() + * mat.m[0] = sx + * mat.m[5] = sx if sy is None else sy # <<<<<<<<<<<<<< + * mat.m[10] = sx if sz is None else sz + * return mat + */ + __pyx_t_3 = (__pyx_v_sy == Py_None); + if (__pyx_t_3) { + __pyx_t_2 = __pyx_v_sx; + } else { + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_sy); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 225, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + } + (__pyx_v_mat->m[5]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":226 + * mat.m[0] = sx + * mat.m[5] = sx if sy is None else sy + * mat.m[10] = sx if sz is None else sz # <<<<<<<<<<<<<< + * return mat + * + */ + __pyx_t_3 = (__pyx_v_sz == Py_None); + if (__pyx_t_3) { + __pyx_t_2 = __pyx_v_sx; + } else { + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_sz); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 226, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + } + (__pyx_v_mat->m[10]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":227 + * mat.m[5] = sx if sy is None else sy + * mat.m[10] = sx if sz is None else sz + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":221 + * fabs(v3_dot(uy, uz)) < 1e-9 + * + * @staticmethod # <<<<<<<<<<<<<< + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.scale", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":229 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_34translate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_34translate = {"translate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_34translate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_34translate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_dx; + double __pyx_v_dy; + double __pyx_v_dz; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("translate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_dx,&__pyx_n_s_dy,&__pyx_n_s_dz,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dx)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 229, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dy)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 229, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("translate", 1, 3, 3, 1); __PYX_ERR(0, 229, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dz)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 229, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("translate", 1, 3, 3, 2); __PYX_ERR(0, 229, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "translate") < 0)) __PYX_ERR(0, 229, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v_dx = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_dx == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 230, __pyx_L3_error) + __pyx_v_dy = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_dy == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 230, __pyx_L3_error) + __pyx_v_dz = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_dz == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 230, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("translate", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 229, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.translate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_33translate(__pyx_v_dx, __pyx_v_dy, __pyx_v_dz); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_33translate(double __pyx_v_dx, double __pyx_v_dy, double __pyx_v_dz) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("translate", 1); + + /* "ezdxf/acc/matrix44.pyx":231 + * @staticmethod + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * mat.m[12] = dx + * mat.m[13] = dy + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 231, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":232 + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * mat.m[12] = dx # <<<<<<<<<<<<<< + * mat.m[13] = dy + * mat.m[14] = dz + */ + (__pyx_v_mat->m[12]) = __pyx_v_dx; + + /* "ezdxf/acc/matrix44.pyx":233 + * cdef Matrix44 mat = Matrix44() + * mat.m[12] = dx + * mat.m[13] = dy # <<<<<<<<<<<<<< + * mat.m[14] = dz + * return mat + */ + (__pyx_v_mat->m[13]) = __pyx_v_dy; + + /* "ezdxf/acc/matrix44.pyx":234 + * mat.m[12] = dx + * mat.m[13] = dy + * mat.m[14] = dz # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[14]) = __pyx_v_dz; + + /* "ezdxf/acc/matrix44.pyx":235 + * mat.m[13] = dy + * mat.m[14] = dz + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":229 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.translate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":237 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate = {"x_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("x_rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 237, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "x_rotate") < 0)) __PYX_ERR(0, 237, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 238, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("x_rotate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 237, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.x_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_35x_rotate(__pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_35x_rotate(double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_cos_a; + double __pyx_v_sin_a; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("x_rotate", 1); + + /* "ezdxf/acc/matrix44.pyx":239 + * @staticmethod + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 239, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":240 + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) # <<<<<<<<<<<<<< + * cdef double sin_a = sin(angle) + * mat.m[5] = cos_a + */ + __pyx_v_cos_a = cos(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":241 + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) # <<<<<<<<<<<<<< + * mat.m[5] = cos_a + * mat.m[6] = sin_a + */ + __pyx_v_sin_a = sin(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":242 + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + * mat.m[5] = cos_a # <<<<<<<<<<<<<< + * mat.m[6] = sin_a + * mat.m[9] = -sin_a + */ + (__pyx_v_mat->m[5]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":243 + * cdef double sin_a = sin(angle) + * mat.m[5] = cos_a + * mat.m[6] = sin_a # <<<<<<<<<<<<<< + * mat.m[9] = -sin_a + * mat.m[10] = cos_a + */ + (__pyx_v_mat->m[6]) = __pyx_v_sin_a; + + /* "ezdxf/acc/matrix44.pyx":244 + * mat.m[5] = cos_a + * mat.m[6] = sin_a + * mat.m[9] = -sin_a # <<<<<<<<<<<<<< + * mat.m[10] = cos_a + * return mat + */ + (__pyx_v_mat->m[9]) = (-__pyx_v_sin_a); + + /* "ezdxf/acc/matrix44.pyx":245 + * mat.m[6] = sin_a + * mat.m[9] = -sin_a + * mat.m[10] = cos_a # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[10]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":246 + * mat.m[9] = -sin_a + * mat.m[10] = cos_a + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":237 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.x_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":248 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate = {"y_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("y_rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 248, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "y_rotate") < 0)) __PYX_ERR(0, 248, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 249, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("y_rotate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 248, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.y_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_37y_rotate(__pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_37y_rotate(double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_cos_a; + double __pyx_v_sin_a; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("y_rotate", 1); + + /* "ezdxf/acc/matrix44.pyx":250 + * @staticmethod + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 250, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":251 + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) # <<<<<<<<<<<<<< + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a + */ + __pyx_v_cos_a = cos(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":252 + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) # <<<<<<<<<<<<<< + * mat.m[0] = cos_a + * mat.m[2] = -sin_a + */ + __pyx_v_sin_a = sin(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":253 + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a # <<<<<<<<<<<<<< + * mat.m[2] = -sin_a + * mat.m[8] = sin_a + */ + (__pyx_v_mat->m[0]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":254 + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a + * mat.m[2] = -sin_a # <<<<<<<<<<<<<< + * mat.m[8] = sin_a + * mat.m[10] = cos_a + */ + (__pyx_v_mat->m[2]) = (-__pyx_v_sin_a); + + /* "ezdxf/acc/matrix44.pyx":255 + * mat.m[0] = cos_a + * mat.m[2] = -sin_a + * mat.m[8] = sin_a # <<<<<<<<<<<<<< + * mat.m[10] = cos_a + * return mat + */ + (__pyx_v_mat->m[8]) = __pyx_v_sin_a; + + /* "ezdxf/acc/matrix44.pyx":256 + * mat.m[2] = -sin_a + * mat.m[8] = sin_a + * mat.m[10] = cos_a # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[10]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":257 + * mat.m[8] = sin_a + * mat.m[10] = cos_a + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":248 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.y_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":259 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate = {"z_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("z_rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 259, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "z_rotate") < 0)) __PYX_ERR(0, 259, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 260, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("z_rotate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 259, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.z_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_39z_rotate(__pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_39z_rotate(double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_cos_a; + double __pyx_v_sin_a; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("z_rotate", 1); + + /* "ezdxf/acc/matrix44.pyx":261 + * @staticmethod + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":262 + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) # <<<<<<<<<<<<<< + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a + */ + __pyx_v_cos_a = cos(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":263 + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) # <<<<<<<<<<<<<< + * mat.m[0] = cos_a + * mat.m[1] = sin_a + */ + __pyx_v_sin_a = sin(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":264 + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a # <<<<<<<<<<<<<< + * mat.m[1] = sin_a + * mat.m[4] = -sin_a + */ + (__pyx_v_mat->m[0]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":265 + * cdef double sin_a = sin(angle) + * mat.m[0] = cos_a + * mat.m[1] = sin_a # <<<<<<<<<<<<<< + * mat.m[4] = -sin_a + * mat.m[5] = cos_a + */ + (__pyx_v_mat->m[1]) = __pyx_v_sin_a; + + /* "ezdxf/acc/matrix44.pyx":266 + * mat.m[0] = cos_a + * mat.m[1] = sin_a + * mat.m[4] = -sin_a # <<<<<<<<<<<<<< + * mat.m[5] = cos_a + * return mat + */ + (__pyx_v_mat->m[4]) = (-__pyx_v_sin_a); + + /* "ezdxf/acc/matrix44.pyx":267 + * mat.m[1] = sin_a + * mat.m[4] = -sin_a + * mat.m[5] = cos_a # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[5]) = __pyx_v_cos_a; + + /* "ezdxf/acc/matrix44.pyx":268 + * mat.m[4] = -sin_a + * mat.m[5] = cos_a + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":259 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.z_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":270 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate = {"axis_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_axis = 0; + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("axis_rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_axis,&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_axis)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 270, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 270, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("axis_rotate", 1, 2, 2, 1); __PYX_ERR(0, 270, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "axis_rotate") < 0)) __PYX_ERR(0, 270, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_axis = values[0]; + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 271, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("axis_rotate", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 270, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.axis_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_41axis_rotate(__pyx_v_axis, __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_41axis_rotate(PyObject *__pyx_v_axis, double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_cos_a; + double __pyx_v_sin_a; + double __pyx_v_one_m_cos; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v__axis = 0; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + double __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("axis_rotate", 1); + + /* "ezdxf/acc/matrix44.pyx":272 + * @staticmethod + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":273 + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) # <<<<<<<<<<<<<< + * cdef double sin_a = sin(angle) + * cdef double one_m_cos = 1.0 - cos_a + */ + __pyx_v_cos_a = cos(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":274 + * cdef Matrix44 mat = Matrix44() + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) # <<<<<<<<<<<<<< + * cdef double one_m_cos = 1.0 - cos_a + * cdef Vec3 _axis = Vec3(axis).normalize() + */ + __pyx_v_sin_a = sin(__pyx_v_angle); + + /* "ezdxf/acc/matrix44.pyx":275 + * cdef double cos_a = cos(angle) + * cdef double sin_a = sin(angle) + * cdef double one_m_cos = 1.0 - cos_a # <<<<<<<<<<<<<< + * cdef Vec3 _axis = Vec3(axis).normalize() + * cdef double x = _axis.x + */ + __pyx_v_one_m_cos = (1.0 - __pyx_v_cos_a); + + /* "ezdxf/acc/matrix44.pyx":276 + * cdef double sin_a = sin(angle) + * cdef double one_m_cos = 1.0 - cos_a + * cdef Vec3 _axis = Vec3(axis).normalize() # <<<<<<<<<<<<<< + * cdef double x = _axis.x + * cdef double y = _axis.y + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_axis); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_normalize); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 276, __pyx_L1_error) + __pyx_v__axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":277 + * cdef double one_m_cos = 1.0 - cos_a + * cdef Vec3 _axis = Vec3(axis).normalize() + * cdef double x = _axis.x # <<<<<<<<<<<<<< + * cdef double y = _axis.y + * cdef double z = _axis.z + */ + __pyx_t_5 = __pyx_v__axis->x; + __pyx_v_x = __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":278 + * cdef Vec3 _axis = Vec3(axis).normalize() + * cdef double x = _axis.x + * cdef double y = _axis.y # <<<<<<<<<<<<<< + * cdef double z = _axis.z + * + */ + __pyx_t_5 = __pyx_v__axis->y; + __pyx_v_y = __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":279 + * cdef double x = _axis.x + * cdef double y = _axis.y + * cdef double z = _axis.z # <<<<<<<<<<<<<< + * + * mat.m[0] = x * x * one_m_cos + cos_a + */ + __pyx_t_5 = __pyx_v__axis->z; + __pyx_v_z = __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":281 + * cdef double z = _axis.z + * + * mat.m[0] = x * x * one_m_cos + cos_a # <<<<<<<<<<<<<< + * mat.m[1] = y * x * one_m_cos + z * sin_a + * mat.m[2] = x * z * one_m_cos - y * sin_a + */ + (__pyx_v_mat->m[0]) = (((__pyx_v_x * __pyx_v_x) * __pyx_v_one_m_cos) + __pyx_v_cos_a); + + /* "ezdxf/acc/matrix44.pyx":282 + * + * mat.m[0] = x * x * one_m_cos + cos_a + * mat.m[1] = y * x * one_m_cos + z * sin_a # <<<<<<<<<<<<<< + * mat.m[2] = x * z * one_m_cos - y * sin_a + * + */ + (__pyx_v_mat->m[1]) = (((__pyx_v_y * __pyx_v_x) * __pyx_v_one_m_cos) + (__pyx_v_z * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":283 + * mat.m[0] = x * x * one_m_cos + cos_a + * mat.m[1] = y * x * one_m_cos + z * sin_a + * mat.m[2] = x * z * one_m_cos - y * sin_a # <<<<<<<<<<<<<< + * + * mat.m[4] = x * y * one_m_cos - z * sin_a + */ + (__pyx_v_mat->m[2]) = (((__pyx_v_x * __pyx_v_z) * __pyx_v_one_m_cos) - (__pyx_v_y * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":285 + * mat.m[2] = x * z * one_m_cos - y * sin_a + * + * mat.m[4] = x * y * one_m_cos - z * sin_a # <<<<<<<<<<<<<< + * mat.m[5] = y * y * one_m_cos + cos_a + * mat.m[6] = y * z * one_m_cos + x * sin_a + */ + (__pyx_v_mat->m[4]) = (((__pyx_v_x * __pyx_v_y) * __pyx_v_one_m_cos) - (__pyx_v_z * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":286 + * + * mat.m[4] = x * y * one_m_cos - z * sin_a + * mat.m[5] = y * y * one_m_cos + cos_a # <<<<<<<<<<<<<< + * mat.m[6] = y * z * one_m_cos + x * sin_a + * + */ + (__pyx_v_mat->m[5]) = (((__pyx_v_y * __pyx_v_y) * __pyx_v_one_m_cos) + __pyx_v_cos_a); + + /* "ezdxf/acc/matrix44.pyx":287 + * mat.m[4] = x * y * one_m_cos - z * sin_a + * mat.m[5] = y * y * one_m_cos + cos_a + * mat.m[6] = y * z * one_m_cos + x * sin_a # <<<<<<<<<<<<<< + * + * mat.m[8] = x * z * one_m_cos + y * sin_a + */ + (__pyx_v_mat->m[6]) = (((__pyx_v_y * __pyx_v_z) * __pyx_v_one_m_cos) + (__pyx_v_x * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":289 + * mat.m[6] = y * z * one_m_cos + x * sin_a + * + * mat.m[8] = x * z * one_m_cos + y * sin_a # <<<<<<<<<<<<<< + * mat.m[9] = y * z * one_m_cos - x * sin_a + * mat.m[10] = z * z * one_m_cos + cos_a + */ + (__pyx_v_mat->m[8]) = (((__pyx_v_x * __pyx_v_z) * __pyx_v_one_m_cos) + (__pyx_v_y * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":290 + * + * mat.m[8] = x * z * one_m_cos + y * sin_a + * mat.m[9] = y * z * one_m_cos - x * sin_a # <<<<<<<<<<<<<< + * mat.m[10] = z * z * one_m_cos + cos_a + * + */ + (__pyx_v_mat->m[9]) = (((__pyx_v_y * __pyx_v_z) * __pyx_v_one_m_cos) - (__pyx_v_x * __pyx_v_sin_a)); + + /* "ezdxf/acc/matrix44.pyx":291 + * mat.m[8] = x * z * one_m_cos + y * sin_a + * mat.m[9] = y * z * one_m_cos - x * sin_a + * mat.m[10] = z * z * one_m_cos + cos_a # <<<<<<<<<<<<<< + * + * return mat + */ + (__pyx_v_mat->m[10]) = (((__pyx_v_z * __pyx_v_z) * __pyx_v_one_m_cos) + __pyx_v_cos_a); + + /* "ezdxf/acc/matrix44.pyx":293 + * mat.m[10] = z * z * one_m_cos + cos_a + * + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":270 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.axis_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XDECREF((PyObject *)__pyx_v__axis); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":295 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def xyz_rotate(double angle_x, double angle_y, + * double angle_z) -> Matrix44: + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate = {"xyz_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle_x; + double __pyx_v_angle_y; + double __pyx_v_angle_z; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("xyz_rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle_x,&__pyx_n_s_angle_y,&__pyx_n_s_angle_z,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle_x)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 295, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle_y)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 295, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("xyz_rotate", 1, 3, 3, 1); __PYX_ERR(0, 295, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle_z)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 295, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("xyz_rotate", 1, 3, 3, 2); __PYX_ERR(0, 295, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "xyz_rotate") < 0)) __PYX_ERR(0, 295, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v_angle_x = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle_x == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + __pyx_v_angle_y = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_angle_y == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L3_error) + __pyx_v_angle_z = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_angle_z == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 297, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("xyz_rotate", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 295, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.xyz_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_43xyz_rotate(__pyx_v_angle_x, __pyx_v_angle_y, __pyx_v_angle_z); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_43xyz_rotate(double __pyx_v_angle_x, double __pyx_v_angle_y, double __pyx_v_angle_z) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_cx; + double __pyx_v_sx; + double __pyx_v_cy; + double __pyx_v_sy; + double __pyx_v_cz; + double __pyx_v_sz; + double __pyx_v_sxsy; + double __pyx_v_cxsy; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("xyz_rotate", 1); + + /* "ezdxf/acc/matrix44.pyx":298 + * def xyz_rotate(double angle_x, double angle_y, + * double angle_z) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double cx = cos(angle_x) + * cdef double sx = sin(angle_x) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 298, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":299 + * double angle_z) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double cx = cos(angle_x) # <<<<<<<<<<<<<< + * cdef double sx = sin(angle_x) + * cdef double cy = cos(angle_y) + */ + __pyx_v_cx = cos(__pyx_v_angle_x); + + /* "ezdxf/acc/matrix44.pyx":300 + * cdef Matrix44 mat = Matrix44() + * cdef double cx = cos(angle_x) + * cdef double sx = sin(angle_x) # <<<<<<<<<<<<<< + * cdef double cy = cos(angle_y) + * cdef double sy = sin(angle_y) + */ + __pyx_v_sx = sin(__pyx_v_angle_x); + + /* "ezdxf/acc/matrix44.pyx":301 + * cdef double cx = cos(angle_x) + * cdef double sx = sin(angle_x) + * cdef double cy = cos(angle_y) # <<<<<<<<<<<<<< + * cdef double sy = sin(angle_y) + * cdef double cz = cos(angle_z) + */ + __pyx_v_cy = cos(__pyx_v_angle_y); + + /* "ezdxf/acc/matrix44.pyx":302 + * cdef double sx = sin(angle_x) + * cdef double cy = cos(angle_y) + * cdef double sy = sin(angle_y) # <<<<<<<<<<<<<< + * cdef double cz = cos(angle_z) + * cdef double sz = sin(angle_z) + */ + __pyx_v_sy = sin(__pyx_v_angle_y); + + /* "ezdxf/acc/matrix44.pyx":303 + * cdef double cy = cos(angle_y) + * cdef double sy = sin(angle_y) + * cdef double cz = cos(angle_z) # <<<<<<<<<<<<<< + * cdef double sz = sin(angle_z) + * cdef double sxsy = sx * sy + */ + __pyx_v_cz = cos(__pyx_v_angle_z); + + /* "ezdxf/acc/matrix44.pyx":304 + * cdef double sy = sin(angle_y) + * cdef double cz = cos(angle_z) + * cdef double sz = sin(angle_z) # <<<<<<<<<<<<<< + * cdef double sxsy = sx * sy + * cdef double cxsy = cx * sy + */ + __pyx_v_sz = sin(__pyx_v_angle_z); + + /* "ezdxf/acc/matrix44.pyx":305 + * cdef double cz = cos(angle_z) + * cdef double sz = sin(angle_z) + * cdef double sxsy = sx * sy # <<<<<<<<<<<<<< + * cdef double cxsy = cx * sy + * + */ + __pyx_v_sxsy = (__pyx_v_sx * __pyx_v_sy); + + /* "ezdxf/acc/matrix44.pyx":306 + * cdef double sz = sin(angle_z) + * cdef double sxsy = sx * sy + * cdef double cxsy = cx * sy # <<<<<<<<<<<<<< + * + * mat.m[0] = cy * cz + */ + __pyx_v_cxsy = (__pyx_v_cx * __pyx_v_sy); + + /* "ezdxf/acc/matrix44.pyx":308 + * cdef double cxsy = cx * sy + * + * mat.m[0] = cy * cz # <<<<<<<<<<<<<< + * mat.m[1] = sxsy * cz + cx * sz + * mat.m[2] = -cxsy * cz + sx * sz + */ + (__pyx_v_mat->m[0]) = (__pyx_v_cy * __pyx_v_cz); + + /* "ezdxf/acc/matrix44.pyx":309 + * + * mat.m[0] = cy * cz + * mat.m[1] = sxsy * cz + cx * sz # <<<<<<<<<<<<<< + * mat.m[2] = -cxsy * cz + sx * sz + * mat.m[4] = -cy * sz + */ + (__pyx_v_mat->m[1]) = ((__pyx_v_sxsy * __pyx_v_cz) + (__pyx_v_cx * __pyx_v_sz)); + + /* "ezdxf/acc/matrix44.pyx":310 + * mat.m[0] = cy * cz + * mat.m[1] = sxsy * cz + cx * sz + * mat.m[2] = -cxsy * cz + sx * sz # <<<<<<<<<<<<<< + * mat.m[4] = -cy * sz + * mat.m[5] = -sxsy * sz + cx * cz + */ + (__pyx_v_mat->m[2]) = (((-__pyx_v_cxsy) * __pyx_v_cz) + (__pyx_v_sx * __pyx_v_sz)); + + /* "ezdxf/acc/matrix44.pyx":311 + * mat.m[1] = sxsy * cz + cx * sz + * mat.m[2] = -cxsy * cz + sx * sz + * mat.m[4] = -cy * sz # <<<<<<<<<<<<<< + * mat.m[5] = -sxsy * sz + cx * cz + * mat.m[6] = cxsy * sz + sx * cz + */ + (__pyx_v_mat->m[4]) = ((-__pyx_v_cy) * __pyx_v_sz); + + /* "ezdxf/acc/matrix44.pyx":312 + * mat.m[2] = -cxsy * cz + sx * sz + * mat.m[4] = -cy * sz + * mat.m[5] = -sxsy * sz + cx * cz # <<<<<<<<<<<<<< + * mat.m[6] = cxsy * sz + sx * cz + * mat.m[8] = sy + */ + (__pyx_v_mat->m[5]) = (((-__pyx_v_sxsy) * __pyx_v_sz) + (__pyx_v_cx * __pyx_v_cz)); + + /* "ezdxf/acc/matrix44.pyx":313 + * mat.m[4] = -cy * sz + * mat.m[5] = -sxsy * sz + cx * cz + * mat.m[6] = cxsy * sz + sx * cz # <<<<<<<<<<<<<< + * mat.m[8] = sy + * mat.m[9] = -sx * cy + */ + (__pyx_v_mat->m[6]) = ((__pyx_v_cxsy * __pyx_v_sz) + (__pyx_v_sx * __pyx_v_cz)); + + /* "ezdxf/acc/matrix44.pyx":314 + * mat.m[5] = -sxsy * sz + cx * cz + * mat.m[6] = cxsy * sz + sx * cz + * mat.m[8] = sy # <<<<<<<<<<<<<< + * mat.m[9] = -sx * cy + * mat.m[10] = cx * cy + */ + (__pyx_v_mat->m[8]) = __pyx_v_sy; + + /* "ezdxf/acc/matrix44.pyx":315 + * mat.m[6] = cxsy * sz + sx * cz + * mat.m[8] = sy + * mat.m[9] = -sx * cy # <<<<<<<<<<<<<< + * mat.m[10] = cx * cy + * return mat + */ + (__pyx_v_mat->m[9]) = ((-__pyx_v_sx) * __pyx_v_cy); + + /* "ezdxf/acc/matrix44.pyx":316 + * mat.m[8] = sy + * mat.m[9] = -sx * cy + * mat.m[10] = cx * cy # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[10]) = (__pyx_v_cx * __pyx_v_cy); + + /* "ezdxf/acc/matrix44.pyx":317 + * mat.m[9] = -sx * cy + * mat.m[10] = cx * cy + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":295 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def xyz_rotate(double angle_x, double angle_y, + * double angle_z) -> Matrix44: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.xyz_rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":319 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy = {"shear_xy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle_x; + double __pyx_v_angle_y; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("shear_xy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle_x,&__pyx_n_s_angle_y,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle_x); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 319, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle_y); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 319, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "shear_xy") < 0)) __PYX_ERR(0, 319, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + if (values[0]) { + __pyx_v_angle_x = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle_x == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 320, __pyx_L3_error) + } else { + __pyx_v_angle_x = ((double)0.0); + } + if (values[1]) { + __pyx_v_angle_y = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_angle_y == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 320, __pyx_L3_error) + } else { + __pyx_v_angle_y = ((double)0.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("shear_xy", 0, 0, 2, __pyx_nargs); __PYX_ERR(0, 319, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.shear_xy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_45shear_xy(__pyx_v_angle_x, __pyx_v_angle_y); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_45shear_xy(double __pyx_v_angle_x, double __pyx_v_angle_y) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + double __pyx_v_tx; + double __pyx_v_ty; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("shear_xy", 1); + + /* "ezdxf/acc/matrix44.pyx":321 + * @staticmethod + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef double tx = tan(angle_x) + * cdef double ty = tan(angle_y) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 321, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":322 + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef double tx = tan(angle_x) # <<<<<<<<<<<<<< + * cdef double ty = tan(angle_y) + * mat.m[1] = ty + */ + __pyx_v_tx = tan(__pyx_v_angle_x); + + /* "ezdxf/acc/matrix44.pyx":323 + * cdef Matrix44 mat = Matrix44() + * cdef double tx = tan(angle_x) + * cdef double ty = tan(angle_y) # <<<<<<<<<<<<<< + * mat.m[1] = ty + * mat.m[4] = tx + */ + __pyx_v_ty = tan(__pyx_v_angle_y); + + /* "ezdxf/acc/matrix44.pyx":324 + * cdef double tx = tan(angle_x) + * cdef double ty = tan(angle_y) + * mat.m[1] = ty # <<<<<<<<<<<<<< + * mat.m[4] = tx + * return mat + */ + (__pyx_v_mat->m[1]) = __pyx_v_ty; + + /* "ezdxf/acc/matrix44.pyx":325 + * cdef double ty = tan(angle_y) + * mat.m[1] = ty + * mat.m[4] = tx # <<<<<<<<<<<<<< + * return mat + * + */ + (__pyx_v_mat->m[4]) = __pyx_v_tx; + + /* "ezdxf/acc/matrix44.pyx":326 + * mat.m[1] = ty + * mat.m[4] = tx + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":319 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.shear_xy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":328 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection(double left, double right, double top, + * double bottom, double near, + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection = {"perspective_projection", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_left; + double __pyx_v_right; + double __pyx_v_top; + double __pyx_v_bottom; + double __pyx_v_near; + double __pyx_v_far; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[6] = {0,0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("perspective_projection (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_left,&__pyx_n_s_right,&__pyx_n_s_top,&__pyx_n_s_bottom,&__pyx_n_s_near,&__pyx_n_s_far,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 6: values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5); + CYTHON_FALLTHROUGH; + case 5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_left)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_right)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, 1); __PYX_ERR(0, 328, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_top)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, 2); __PYX_ERR(0, 328, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_bottom)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, 3); __PYX_ERR(0, 328, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (likely((values[4] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_near)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[4]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, 4); __PYX_ERR(0, 328, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 5: + if (likely((values[5] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_far)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[5]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 328, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, 5); __PYX_ERR(0, 328, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "perspective_projection") < 0)) __PYX_ERR(0, 328, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 6)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5); + } + __pyx_v_left = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_left == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 329, __pyx_L3_error) + __pyx_v_right = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_right == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 329, __pyx_L3_error) + __pyx_v_top = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_top == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 329, __pyx_L3_error) + __pyx_v_bottom = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_bottom == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 330, __pyx_L3_error) + __pyx_v_near = __pyx_PyFloat_AsDouble(values[4]); if (unlikely((__pyx_v_near == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 330, __pyx_L3_error) + __pyx_v_far = __pyx_PyFloat_AsDouble(values[5]); if (unlikely((__pyx_v_far == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 331, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("perspective_projection", 1, 6, 6, __pyx_nargs); __PYX_ERR(0, 328, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.perspective_projection", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_47perspective_projection(__pyx_v_left, __pyx_v_right, __pyx_v_top, __pyx_v_bottom, __pyx_v_near, __pyx_v_far); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_47perspective_projection(double __pyx_v_left, double __pyx_v_right, double __pyx_v_top, double __pyx_v_bottom, double __pyx_v_near, double __pyx_v_far) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + double __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("perspective_projection", 1); + + /* "ezdxf/acc/matrix44.pyx":332 + * double bottom, double near, + * double far) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * mat.m[0] = (2. * near) / (right - left) + * mat.m[5] = (2. * near) / (top - bottom) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 332, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":333 + * double far) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * mat.m[0] = (2. * near) / (right - left) # <<<<<<<<<<<<<< + * mat.m[5] = (2. * near) / (top - bottom) + * mat.m[8] = (right + left) / (right - left) + */ + __pyx_t_2 = (2. * __pyx_v_near); + __pyx_t_3 = (__pyx_v_right - __pyx_v_left); + if (unlikely(__pyx_t_3 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 333, __pyx_L1_error) + } + (__pyx_v_mat->m[0]) = (__pyx_t_2 / __pyx_t_3); + + /* "ezdxf/acc/matrix44.pyx":334 + * cdef Matrix44 mat = Matrix44() + * mat.m[0] = (2. * near) / (right - left) + * mat.m[5] = (2. * near) / (top - bottom) # <<<<<<<<<<<<<< + * mat.m[8] = (right + left) / (right - left) + * mat.m[9] = (top + bottom) / (top - bottom) + */ + __pyx_t_3 = (2. * __pyx_v_near); + __pyx_t_2 = (__pyx_v_top - __pyx_v_bottom); + if (unlikely(__pyx_t_2 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 334, __pyx_L1_error) + } + (__pyx_v_mat->m[5]) = (__pyx_t_3 / __pyx_t_2); + + /* "ezdxf/acc/matrix44.pyx":335 + * mat.m[0] = (2. * near) / (right - left) + * mat.m[5] = (2. * near) / (top - bottom) + * mat.m[8] = (right + left) / (right - left) # <<<<<<<<<<<<<< + * mat.m[9] = (top + bottom) / (top - bottom) + * mat.m[10] = -((far + near) / (far - near)) + */ + __pyx_t_2 = (__pyx_v_right + __pyx_v_left); + __pyx_t_3 = (__pyx_v_right - __pyx_v_left); + if (unlikely(__pyx_t_3 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 335, __pyx_L1_error) + } + (__pyx_v_mat->m[8]) = (__pyx_t_2 / __pyx_t_3); + + /* "ezdxf/acc/matrix44.pyx":336 + * mat.m[5] = (2. * near) / (top - bottom) + * mat.m[8] = (right + left) / (right - left) + * mat.m[9] = (top + bottom) / (top - bottom) # <<<<<<<<<<<<<< + * mat.m[10] = -((far + near) / (far - near)) + * mat.m[11] = -1 + */ + __pyx_t_3 = (__pyx_v_top + __pyx_v_bottom); + __pyx_t_2 = (__pyx_v_top - __pyx_v_bottom); + if (unlikely(__pyx_t_2 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 336, __pyx_L1_error) + } + (__pyx_v_mat->m[9]) = (__pyx_t_3 / __pyx_t_2); + + /* "ezdxf/acc/matrix44.pyx":337 + * mat.m[8] = (right + left) / (right - left) + * mat.m[9] = (top + bottom) / (top - bottom) + * mat.m[10] = -((far + near) / (far - near)) # <<<<<<<<<<<<<< + * mat.m[11] = -1 + * mat.m[14] = -((2. * far * near) / (far - near)) + */ + __pyx_t_2 = (__pyx_v_far + __pyx_v_near); + __pyx_t_3 = (__pyx_v_far - __pyx_v_near); + if (unlikely(__pyx_t_3 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 337, __pyx_L1_error) + } + (__pyx_v_mat->m[10]) = (-(__pyx_t_2 / __pyx_t_3)); + + /* "ezdxf/acc/matrix44.pyx":338 + * mat.m[9] = (top + bottom) / (top - bottom) + * mat.m[10] = -((far + near) / (far - near)) + * mat.m[11] = -1 # <<<<<<<<<<<<<< + * mat.m[14] = -((2. * far * near) / (far - near)) + * return mat + */ + (__pyx_v_mat->m[11]) = -1.0; + + /* "ezdxf/acc/matrix44.pyx":339 + * mat.m[10] = -((far + near) / (far - near)) + * mat.m[11] = -1 + * mat.m[14] = -((2. * far * near) / (far - near)) # <<<<<<<<<<<<<< + * return mat + * + */ + __pyx_t_3 = ((2. * __pyx_v_far) * __pyx_v_near); + __pyx_t_2 = (__pyx_v_far - __pyx_v_near); + if (unlikely(__pyx_t_2 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 339, __pyx_L1_error) + } + (__pyx_v_mat->m[14]) = (-(__pyx_t_3 / __pyx_t_2)); + + /* "ezdxf/acc/matrix44.pyx":340 + * mat.m[11] = -1 + * mat.m[14] = -((2. * far * near) / (far - near)) + * return mat # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":328 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection(double left, double right, double top, + * double bottom, double near, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.perspective_projection", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":342 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection_fov(fov: float, aspect: float, near: float, + * far: float) -> Matrix44: + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov = {"perspective_projection_fov", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_fov; + double __pyx_v_aspect; + double __pyx_v_near; + double __pyx_v_far; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("perspective_projection_fov (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_fov,&__pyx_n_s_aspect,&__pyx_n_s_near,&__pyx_n_s_far,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_fov)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 342, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_aspect)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 342, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection_fov", 1, 4, 4, 1); __PYX_ERR(0, 342, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_near)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 342, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection_fov", 1, 4, 4, 2); __PYX_ERR(0, 342, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_far)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 342, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("perspective_projection_fov", 1, 4, 4, 3); __PYX_ERR(0, 342, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "perspective_projection_fov") < 0)) __PYX_ERR(0, 342, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 4)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + } + __pyx_v_fov = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_fov == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 343, __pyx_L3_error) + __pyx_v_aspect = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_aspect == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 343, __pyx_L3_error) + __pyx_v_near = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_near == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 343, __pyx_L3_error) + __pyx_v_far = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_far == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 344, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("perspective_projection_fov", 1, 4, 4, __pyx_nargs); __PYX_ERR(0, 342, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.perspective_projection_fov", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_49perspective_projection_fov(__pyx_v_fov, __pyx_v_aspect, __pyx_v_near, __pyx_v_far); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_49perspective_projection_fov(double __pyx_v_fov, double __pyx_v_aspect, double __pyx_v_near, double __pyx_v_far) { + PyObject *__pyx_v_vrange = NULL; + PyObject *__pyx_v_left = NULL; + PyObject *__pyx_v_right = NULL; + PyObject *__pyx_v_bottom = NULL; + PyObject *__pyx_v_top = NULL; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("perspective_projection_fov", 1); + + /* "ezdxf/acc/matrix44.pyx":345 + * def perspective_projection_fov(fov: float, aspect: float, near: float, + * far: float) -> Matrix44: + * vrange = near * math.tan(fov / 2.) # <<<<<<<<<<<<<< + * left = -vrange * aspect + * right = vrange * aspect + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_near); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_math); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_tan); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_fov / 2.)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_6, 1+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __pyx_t_4 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 345, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_vrange = __pyx_t_4; + __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":346 + * far: float) -> Matrix44: + * vrange = near * math.tan(fov / 2.) + * left = -vrange * aspect # <<<<<<<<<<<<<< + * right = vrange * aspect + * bottom = -vrange + */ + __pyx_t_4 = PyNumber_Negative(__pyx_v_vrange); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 346, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_aspect); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 346, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyNumber_Multiply(__pyx_t_4, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 346, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_left = __pyx_t_1; + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":347 + * vrange = near * math.tan(fov / 2.) + * left = -vrange * aspect + * right = vrange * aspect # <<<<<<<<<<<<<< + * bottom = -vrange + * top = vrange + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_aspect); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyNumber_Multiply(__pyx_v_vrange, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_right = __pyx_t_2; + __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":348 + * left = -vrange * aspect + * right = vrange * aspect + * bottom = -vrange # <<<<<<<<<<<<<< + * top = vrange + * return Matrix44.perspective_projection(left, right, bottom, top, near, + */ + __pyx_t_2 = PyNumber_Negative(__pyx_v_vrange); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 348, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_bottom = __pyx_t_2; + __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":349 + * right = vrange * aspect + * bottom = -vrange + * top = vrange # <<<<<<<<<<<<<< + * return Matrix44.perspective_projection(left, right, bottom, top, near, + * far) + */ + __Pyx_INCREF(__pyx_v_vrange); + __pyx_v_top = __pyx_v_vrange; + + /* "ezdxf/acc/matrix44.pyx":350 + * bottom = -vrange + * top = vrange + * return Matrix44.perspective_projection(left, right, bottom, top, near, # <<<<<<<<<<<<<< + * far) + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44), __pyx_n_s_perspective_projection); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 350, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_near); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 350, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "ezdxf/acc/matrix44.pyx":351 + * top = vrange + * return Matrix44.perspective_projection(left, right, bottom, top, near, + * far) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_far); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[7] = {__pyx_t_5, __pyx_v_left, __pyx_v_right, __pyx_v_bottom, __pyx_v_top, __pyx_t_4, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_6, 6+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 350, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + + /* "ezdxf/acc/matrix44.pyx":350 + * bottom = -vrange + * top = vrange + * return Matrix44.perspective_projection(left, right, bottom, top, near, # <<<<<<<<<<<<<< + * far) + * + */ + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44))))) __PYX_ERR(0, 350, __pyx_L1_error) + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":342 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection_fov(fov: float, aspect: float, near: float, + * far: float) -> Matrix44: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.perspective_projection_fov", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_vrange); + __Pyx_XDECREF(__pyx_v_left); + __Pyx_XDECREF(__pyx_v_right); + __Pyx_XDECREF(__pyx_v_bottom); + __Pyx_XDECREF(__pyx_v_top); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":353 + * far) + * + * @staticmethod # <<<<<<<<<<<<<< + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_52chain(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_52chain = {"chain", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_52chain, METH_VARARGS|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_52chain(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_matrices = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("chain (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_VARARGS(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "chain", 0))) return NULL; + __Pyx_INCREF(__pyx_args); + __pyx_v_matrices = __pyx_args; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_51chain(__pyx_self, __pyx_v_matrices); + + /* function exit code */ + __Pyx_DECREF(__pyx_v_matrices); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_51chain(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_matrices) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_transformation = 0; + PyObject *__pyx_v_matrix = NULL; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("chain", 1); + + /* "ezdxf/acc/matrix44.pyx":355 + * @staticmethod + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() # <<<<<<<<<<<<<< + * for matrix in matrices: + * transformation *= matrix + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_transformation = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":356 + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + * for matrix in matrices: # <<<<<<<<<<<<<< + * transformation *= matrix + * return transformation + */ + __pyx_t_1 = __pyx_v_matrices; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 356, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 356, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 356, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_matrix, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/matrix44.pyx":357 + * cdef Matrix44 transformation = Matrix44() + * for matrix in matrices: + * transformation *= matrix # <<<<<<<<<<<<<< + * return transformation + * + */ + __pyx_t_3 = PyNumber_InPlaceMultiply(((PyObject *)__pyx_v_transformation), __pyx_v_matrix); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 357, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44))))) __PYX_ERR(0, 357, __pyx_L1_error) + __Pyx_DECREF_SET(__pyx_v_transformation, ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "ezdxf/acc/matrix44.pyx":356 + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + * for matrix in matrices: # <<<<<<<<<<<<<< + * transformation *= matrix + * return transformation + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":358 + * for matrix in matrices: + * transformation *= matrix + * return transformation # <<<<<<<<<<<<<< + * + * def __imul__(self, Matrix44 other) -> Matrix44: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_transformation); + __pyx_r = __pyx_v_transformation; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":353 + * far) + * + * @staticmethod # <<<<<<<<<<<<<< + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.chain", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_transformation); + __Pyx_XDECREF(__pyx_v_matrix); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":360 + * return transformation + * + * def __imul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef double[16] m1 = self.m + * cdef double *m2 = other.m + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_54__imul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_54__imul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__imul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, 1, "other", 0))) __PYX_ERR(0, 360, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_53__imul__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_other)); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_53__imul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other) { + double __pyx_v_m1[16]; + double *__pyx_v_m2; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double *__pyx_t_1; + __Pyx_RefNannySetupContext("__imul__", 1); + + /* "ezdxf/acc/matrix44.pyx":361 + * + * def __imul__(self, Matrix44 other) -> Matrix44: + * cdef double[16] m1 = self.m # <<<<<<<<<<<<<< + * cdef double *m2 = other.m + * + */ + __pyx_t_1 = __pyx_v_self->m; + memcpy(&(__pyx_v_m1[0]), __pyx_t_1, sizeof(__pyx_v_m1[0]) * (16 - 0)); + + /* "ezdxf/acc/matrix44.pyx":362 + * def __imul__(self, Matrix44 other) -> Matrix44: + * cdef double[16] m1 = self.m + * cdef double *m2 = other.m # <<<<<<<<<<<<<< + * + * self.m[0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[2] * m2[8] + \ + */ + __pyx_t_1 = __pyx_v_other->m; + __pyx_v_m2 = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":364 + * cdef double *m2 = other.m + * + * self.m[0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[2] * m2[8] + \ # <<<<<<<<<<<<<< + * m1[3] * m2[12] + * self.m[1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[2] * m2[9] + \ + */ + (__pyx_v_self->m[0]) = (((((__pyx_v_m1[0]) * (__pyx_v_m2[0])) + ((__pyx_v_m1[1]) * (__pyx_v_m2[4]))) + ((__pyx_v_m1[2]) * (__pyx_v_m2[8]))) + ((__pyx_v_m1[3]) * (__pyx_v_m2[12]))); + + /* "ezdxf/acc/matrix44.pyx":366 + * self.m[0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[2] * m2[8] + \ + * m1[3] * m2[12] + * self.m[1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[2] * m2[9] + \ # <<<<<<<<<<<<<< + * m1[3] * m2[13] + * self.m[2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[2] * m2[10] + \ + */ + (__pyx_v_self->m[1]) = (((((__pyx_v_m1[0]) * (__pyx_v_m2[1])) + ((__pyx_v_m1[1]) * (__pyx_v_m2[5]))) + ((__pyx_v_m1[2]) * (__pyx_v_m2[9]))) + ((__pyx_v_m1[3]) * (__pyx_v_m2[13]))); + + /* "ezdxf/acc/matrix44.pyx":368 + * self.m[1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[2] * m2[9] + \ + * m1[3] * m2[13] + * self.m[2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[2] * m2[10] + \ # <<<<<<<<<<<<<< + * m1[3] * m2[14] + * self.m[3] = m1[0] * m2[3] + m1[1] * m2[7] + m1[2] * m2[11] + \ + */ + (__pyx_v_self->m[2]) = (((((__pyx_v_m1[0]) * (__pyx_v_m2[2])) + ((__pyx_v_m1[1]) * (__pyx_v_m2[6]))) + ((__pyx_v_m1[2]) * (__pyx_v_m2[10]))) + ((__pyx_v_m1[3]) * (__pyx_v_m2[14]))); + + /* "ezdxf/acc/matrix44.pyx":370 + * self.m[2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[2] * m2[10] + \ + * m1[3] * m2[14] + * self.m[3] = m1[0] * m2[3] + m1[1] * m2[7] + m1[2] * m2[11] + \ # <<<<<<<<<<<<<< + * m1[3] * m2[15] + * + */ + (__pyx_v_self->m[3]) = (((((__pyx_v_m1[0]) * (__pyx_v_m2[3])) + ((__pyx_v_m1[1]) * (__pyx_v_m2[7]))) + ((__pyx_v_m1[2]) * (__pyx_v_m2[11]))) + ((__pyx_v_m1[3]) * (__pyx_v_m2[15]))); + + /* "ezdxf/acc/matrix44.pyx":373 + * m1[3] * m2[15] + * + * self.m[4] = m1[4] * m2[0] + m1[5] * m2[4] + m1[6] * m2[8] + \ # <<<<<<<<<<<<<< + * m1[7] * m2[12] + * self.m[5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[6] * m2[9] + \ + */ + (__pyx_v_self->m[4]) = (((((__pyx_v_m1[4]) * (__pyx_v_m2[0])) + ((__pyx_v_m1[5]) * (__pyx_v_m2[4]))) + ((__pyx_v_m1[6]) * (__pyx_v_m2[8]))) + ((__pyx_v_m1[7]) * (__pyx_v_m2[12]))); + + /* "ezdxf/acc/matrix44.pyx":375 + * self.m[4] = m1[4] * m2[0] + m1[5] * m2[4] + m1[6] * m2[8] + \ + * m1[7] * m2[12] + * self.m[5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[6] * m2[9] + \ # <<<<<<<<<<<<<< + * m1[7] * m2[13] + * self.m[6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[6] * m2[10] + \ + */ + (__pyx_v_self->m[5]) = (((((__pyx_v_m1[4]) * (__pyx_v_m2[1])) + ((__pyx_v_m1[5]) * (__pyx_v_m2[5]))) + ((__pyx_v_m1[6]) * (__pyx_v_m2[9]))) + ((__pyx_v_m1[7]) * (__pyx_v_m2[13]))); + + /* "ezdxf/acc/matrix44.pyx":377 + * self.m[5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[6] * m2[9] + \ + * m1[7] * m2[13] + * self.m[6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[6] * m2[10] + \ # <<<<<<<<<<<<<< + * m1[7] * m2[14] + * self.m[7] = m1[4] * m2[3] + m1[5] * m2[7] + m1[6] * m2[11] + \ + */ + (__pyx_v_self->m[6]) = (((((__pyx_v_m1[4]) * (__pyx_v_m2[2])) + ((__pyx_v_m1[5]) * (__pyx_v_m2[6]))) + ((__pyx_v_m1[6]) * (__pyx_v_m2[10]))) + ((__pyx_v_m1[7]) * (__pyx_v_m2[14]))); + + /* "ezdxf/acc/matrix44.pyx":379 + * self.m[6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[6] * m2[10] + \ + * m1[7] * m2[14] + * self.m[7] = m1[4] * m2[3] + m1[5] * m2[7] + m1[6] * m2[11] + \ # <<<<<<<<<<<<<< + * m1[7] * m2[15] + * + */ + (__pyx_v_self->m[7]) = (((((__pyx_v_m1[4]) * (__pyx_v_m2[3])) + ((__pyx_v_m1[5]) * (__pyx_v_m2[7]))) + ((__pyx_v_m1[6]) * (__pyx_v_m2[11]))) + ((__pyx_v_m1[7]) * (__pyx_v_m2[15]))); + + /* "ezdxf/acc/matrix44.pyx":382 + * m1[7] * m2[15] + * + * self.m[8] = m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[8] + \ # <<<<<<<<<<<<<< + * m1[11] * m2[12] + * self.m[9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[9] + \ + */ + (__pyx_v_self->m[8]) = (((((__pyx_v_m1[8]) * (__pyx_v_m2[0])) + ((__pyx_v_m1[9]) * (__pyx_v_m2[4]))) + ((__pyx_v_m1[10]) * (__pyx_v_m2[8]))) + ((__pyx_v_m1[11]) * (__pyx_v_m2[12]))); + + /* "ezdxf/acc/matrix44.pyx":384 + * self.m[8] = m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[8] + \ + * m1[11] * m2[12] + * self.m[9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[9] + \ # <<<<<<<<<<<<<< + * m1[11] * m2[13] + * self.m[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10] + \ + */ + (__pyx_v_self->m[9]) = (((((__pyx_v_m1[8]) * (__pyx_v_m2[1])) + ((__pyx_v_m1[9]) * (__pyx_v_m2[5]))) + ((__pyx_v_m1[10]) * (__pyx_v_m2[9]))) + ((__pyx_v_m1[11]) * (__pyx_v_m2[13]))); + + /* "ezdxf/acc/matrix44.pyx":386 + * self.m[9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[9] + \ + * m1[11] * m2[13] + * self.m[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10] + \ # <<<<<<<<<<<<<< + * m1[11] * m2[14] + * self.m[11] = m1[8] * m2[3] + m1[9] * m2[7] + m1[10] * m2[11] + \ + */ + (__pyx_v_self->m[10]) = (((((__pyx_v_m1[8]) * (__pyx_v_m2[2])) + ((__pyx_v_m1[9]) * (__pyx_v_m2[6]))) + ((__pyx_v_m1[10]) * (__pyx_v_m2[10]))) + ((__pyx_v_m1[11]) * (__pyx_v_m2[14]))); + + /* "ezdxf/acc/matrix44.pyx":388 + * self.m[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10] + \ + * m1[11] * m2[14] + * self.m[11] = m1[8] * m2[3] + m1[9] * m2[7] + m1[10] * m2[11] + \ # <<<<<<<<<<<<<< + * m1[11] * m2[15] + * + */ + (__pyx_v_self->m[11]) = (((((__pyx_v_m1[8]) * (__pyx_v_m2[3])) + ((__pyx_v_m1[9]) * (__pyx_v_m2[7]))) + ((__pyx_v_m1[10]) * (__pyx_v_m2[11]))) + ((__pyx_v_m1[11]) * (__pyx_v_m2[15]))); + + /* "ezdxf/acc/matrix44.pyx":391 + * m1[11] * m2[15] + * + * self.m[12] = m1[12] * m2[0] + m1[13] * m2[4] + m1[14] * m2[8] + \ # <<<<<<<<<<<<<< + * m1[15] * m2[12] + * self.m[13] = m1[12] * m2[1] + m1[13] * m2[5] + m1[14] * m2[9] + \ + */ + (__pyx_v_self->m[12]) = (((((__pyx_v_m1[12]) * (__pyx_v_m2[0])) + ((__pyx_v_m1[13]) * (__pyx_v_m2[4]))) + ((__pyx_v_m1[14]) * (__pyx_v_m2[8]))) + ((__pyx_v_m1[15]) * (__pyx_v_m2[12]))); + + /* "ezdxf/acc/matrix44.pyx":393 + * self.m[12] = m1[12] * m2[0] + m1[13] * m2[4] + m1[14] * m2[8] + \ + * m1[15] * m2[12] + * self.m[13] = m1[12] * m2[1] + m1[13] * m2[5] + m1[14] * m2[9] + \ # <<<<<<<<<<<<<< + * m1[15] * m2[13] + * self.m[14] = m1[12] * m2[2] + m1[13] * m2[6] + m1[14] * m2[10] + \ + */ + (__pyx_v_self->m[13]) = (((((__pyx_v_m1[12]) * (__pyx_v_m2[1])) + ((__pyx_v_m1[13]) * (__pyx_v_m2[5]))) + ((__pyx_v_m1[14]) * (__pyx_v_m2[9]))) + ((__pyx_v_m1[15]) * (__pyx_v_m2[13]))); + + /* "ezdxf/acc/matrix44.pyx":395 + * self.m[13] = m1[12] * m2[1] + m1[13] * m2[5] + m1[14] * m2[9] + \ + * m1[15] * m2[13] + * self.m[14] = m1[12] * m2[2] + m1[13] * m2[6] + m1[14] * m2[10] + \ # <<<<<<<<<<<<<< + * m1[15] * m2[14] + * self.m[15] = m1[12] * m2[3] + m1[13] * m2[7] + m1[14] * m2[11] + \ + */ + (__pyx_v_self->m[14]) = (((((__pyx_v_m1[12]) * (__pyx_v_m2[2])) + ((__pyx_v_m1[13]) * (__pyx_v_m2[6]))) + ((__pyx_v_m1[14]) * (__pyx_v_m2[10]))) + ((__pyx_v_m1[15]) * (__pyx_v_m2[14]))); + + /* "ezdxf/acc/matrix44.pyx":397 + * self.m[14] = m1[12] * m2[2] + m1[13] * m2[6] + m1[14] * m2[10] + \ + * m1[15] * m2[14] + * self.m[15] = m1[12] * m2[3] + m1[13] * m2[7] + m1[14] * m2[11] + \ # <<<<<<<<<<<<<< + * m1[15] * m2[15] + * return self + */ + (__pyx_v_self->m[15]) = (((((__pyx_v_m1[12]) * (__pyx_v_m2[3])) + ((__pyx_v_m1[13]) * (__pyx_v_m2[7]))) + ((__pyx_v_m1[14]) * (__pyx_v_m2[11]))) + ((__pyx_v_m1[15]) * (__pyx_v_m2[15]))); + + /* "ezdxf/acc/matrix44.pyx":399 + * self.m[15] = m1[12] * m2[3] + m1[13] * m2[7] + m1[14] * m2[11] + \ + * m1[15] * m2[15] + * return self # <<<<<<<<<<<<<< + * + * def __mul__(self, Matrix44 other) -> Matrix44: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = ((PyObject *)__pyx_v_self); + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":360 + * return transformation + * + * def __imul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef double[16] m1 = self.m + * cdef double *m2 = other.m + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":401 + * return self + * + * def __mul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_56__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_56__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__mul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, 1, "other", 0))) __PYX_ERR(0, 401, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_55__mul__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_other)); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_55__mul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_res_matrix = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__mul__", 1); + + /* "ezdxf/acc/matrix44.pyx":402 + * + * def __mul__(self, Matrix44 other) -> Matrix44: + * cdef Matrix44 res_matrix = self.copy() # <<<<<<<<<<<<<< + * return res_matrix.__imul__(other) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_copy); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 402, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 402, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44))))) __PYX_ERR(0, 402, __pyx_L1_error) + __pyx_v_res_matrix = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":403 + * def __mul__(self, Matrix44 other) -> Matrix44: + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) # <<<<<<<<<<<<<< + * + * # __matmul__ = __mul__ does not work! + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_res_matrix), __pyx_n_s_imul); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 403, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, ((PyObject *)__pyx_v_other)}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 403, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":401 + * return self + * + * def __mul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__mul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res_matrix); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":407 + * # __matmul__ = __mul__ does not work! + * + * def __matmul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) + */ + +/* Python wrapper */ +#if PY_VERSION_HEX >= 0x03050000 +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_58__matmul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_58__matmul__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__matmul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, 1, "other", 0))) __PYX_ERR(0, 407, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_57__matmul__(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_other)); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +#endif /*!(#if PY_VERSION_HEX >= 0x03050000)*/ + +#if PY_VERSION_HEX >= 0x03050000 +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_57__matmul__(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_res_matrix = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__matmul__", 1); + + /* "ezdxf/acc/matrix44.pyx":408 + * + * def __matmul__(self, Matrix44 other) -> Matrix44: + * cdef Matrix44 res_matrix = self.copy() # <<<<<<<<<<<<<< + * return res_matrix.__imul__(other) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_copy); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 408, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 408, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44))))) __PYX_ERR(0, 408, __pyx_L1_error) + __pyx_v_res_matrix = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":409 + * def __matmul__(self, Matrix44 other) -> Matrix44: + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) # <<<<<<<<<<<<<< + * + * def transpose(self) -> None: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_res_matrix), __pyx_n_s_imul); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 409, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, ((PyObject *)__pyx_v_other)}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 409, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":407 + * # __matmul__ = __mul__ does not work! + * + * def __matmul__(self, Matrix44 other) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 res_matrix = self.copy() + * return res_matrix.__imul__(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.__matmul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res_matrix); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +#endif /*!(#if PY_VERSION_HEX >= 0x03050000)*/ + +/* "ezdxf/acc/matrix44.pyx":411 + * return res_matrix.__imul__(other) + * + * def transpose(self) -> None: # <<<<<<<<<<<<<< + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_60transpose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_60transpose = {"transpose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_60transpose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_60transpose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transpose (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("transpose", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "transpose", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_59transpose(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_59transpose(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transpose", 1); + + /* "ezdxf/acc/matrix44.pyx":412 + * + * def transpose(self) -> None: + * swap(&self.m[1], &self.m[4]) # <<<<<<<<<<<<<< + * swap(&self.m[2], &self.m[8]) + * swap(&self.m[3], &self.m[12]) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[1])), (&(__pyx_v_self->m[4]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 412, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":413 + * def transpose(self) -> None: + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) # <<<<<<<<<<<<<< + * swap(&self.m[3], &self.m[12]) + * swap(&self.m[6], &self.m[9]) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[2])), (&(__pyx_v_self->m[8]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":414 + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) + * swap(&self.m[3], &self.m[12]) # <<<<<<<<<<<<<< + * swap(&self.m[6], &self.m[9]) + * swap(&self.m[7], &self.m[13]) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[3])), (&(__pyx_v_self->m[12]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 414, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":415 + * swap(&self.m[2], &self.m[8]) + * swap(&self.m[3], &self.m[12]) + * swap(&self.m[6], &self.m[9]) # <<<<<<<<<<<<<< + * swap(&self.m[7], &self.m[13]) + * swap(&self.m[11], &self.m[14]) + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[6])), (&(__pyx_v_self->m[9]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 415, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":416 + * swap(&self.m[3], &self.m[12]) + * swap(&self.m[6], &self.m[9]) + * swap(&self.m[7], &self.m[13]) # <<<<<<<<<<<<<< + * swap(&self.m[11], &self.m[14]) + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[7])), (&(__pyx_v_self->m[13]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":417 + * swap(&self.m[6], &self.m[9]) + * swap(&self.m[7], &self.m[13]) + * swap(&self.m[11], &self.m[14]) # <<<<<<<<<<<<<< + * + * def determinant(self) -> float: + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_8matrix44_swap((&(__pyx_v_self->m[11])), (&(__pyx_v_self->m[14]))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 417, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":411 + * return res_matrix.__imul__(other) + * + * def transpose(self) -> None: # <<<<<<<<<<<<<< + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transpose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":419 + * swap(&self.m[11], &self.m[14]) + * + * def determinant(self) -> float: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_62determinant(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_62determinant = {"determinant", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_62determinant, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_62determinant(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("determinant (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("determinant", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "determinant", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_61determinant(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_61determinant(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + double *__pyx_v_m; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("determinant", 1); + + /* "ezdxf/acc/matrix44.pyx":420 + * + * def determinant(self) -> float: + * cdef double *m = self.m # <<<<<<<<<<<<<< + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + * m[0] * m[6] * m[11] * m[13] - m[0] * m[6] * m[9] * m[15] + \ + */ + __pyx_t_1 = __pyx_v_self->m; + __pyx_v_m = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":421 + * def determinant(self) -> float: + * cdef double *m = self.m + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ # <<<<<<<<<<<<<< + * m[0] * m[6] * m[11] * m[13] - m[0] * m[6] * m[9] * m[15] + \ + * m[0] * m[7] * m[9] * m[14] - m[0] * m[7] * m[10] * m[13] - \ + */ + __Pyx_XDECREF(__pyx_r); + + /* "ezdxf/acc/matrix44.pyx":432 + * m[3] * m[4] * m[9] * m[14] + m[3] * m[4] * m[10] * m[13] - \ + * m[3] * m[5] * m[10] * m[12] + m[3] * m[5] * m[8] * m[14] - \ + * m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] # <<<<<<<<<<<<<< + * + * def inverse(self) -> None: + */ + __pyx_t_2 = PyFloat_FromDouble((((((((((((((((((((((((((((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[10])) * (__pyx_v_m[15])) - ((((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) + ((((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[11])) * (__pyx_v_m[13]))) - ((((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) + ((((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) - ((((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[10])) * (__pyx_v_m[13]))) - ((((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[11])) * (__pyx_v_m[12]))) + ((((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) - ((((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) + ((((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[10])) * (__pyx_v_m[12]))) - ((((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[10])) * (__pyx_v_m[15]))) + ((((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) + ((((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) - ((((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[9])) * (__pyx_v_m[12]))) + ((((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) - ((((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[11])) * (__pyx_v_m[13]))) + ((((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[11])) * (__pyx_v_m[12]))) - ((((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) - ((((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) + ((((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[10])) * (__pyx_v_m[13]))) - ((((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[10])) * (__pyx_v_m[12]))) + ((((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) - ((((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) + ((((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[9])) * (__pyx_v_m[12])))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":419 + * swap(&self.m[11], &self.m[14]) + * + * def determinant(self) -> float: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.determinant", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":434 + * m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] + * + * def inverse(self) -> None: # <<<<<<<<<<<<<< + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_64inverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_64inverse = {"inverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_64inverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_64inverse(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("inverse (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("inverse", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "inverse", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_63inverse(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_63inverse(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self) { + double __pyx_v_m[16]; + double __pyx_v_det; + double __pyx_v_f; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + double __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("inverse", 1); + + /* "ezdxf/acc/matrix44.pyx":435 + * + * def inverse(self) -> None: + * cdef double[16] m = self.m # memcopy # <<<<<<<<<<<<<< + * cdef double det = self.determinant() + * cdef double f = 1. / det + */ + __pyx_t_1 = __pyx_v_self->m; + memcpy(&(__pyx_v_m[0]), __pyx_t_1, sizeof(__pyx_v_m[0]) * (16 - 0)); + + /* "ezdxf/acc/matrix44.pyx":436 + * def inverse(self) -> None: + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() # <<<<<<<<<<<<<< + * cdef double f = 1. / det + * self.m[0] = (m[6] * m[11] * m[13] - m[7] * m[10] * m[13] + m[7] * m[9] * + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_determinant); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_5, 0+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_t_6 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_6 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_det = __pyx_t_6; + + /* "ezdxf/acc/matrix44.pyx":437 + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() + * cdef double f = 1. / det # <<<<<<<<<<<<<< + * self.m[0] = (m[6] * m[11] * m[13] - m[7] * m[10] * m[13] + m[7] * m[9] * + * m[14] - m[5] * m[11] * m[14] - m[6] * m[9] * m[15] + m[5] * + */ + if (unlikely(__pyx_v_det == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 437, __pyx_L1_error) + } + __pyx_v_f = (1. / __pyx_v_det); + + /* "ezdxf/acc/matrix44.pyx":438 + * cdef double det = self.determinant() + * cdef double f = 1. / det + * self.m[0] = (m[6] * m[11] * m[13] - m[7] * m[10] * m[13] + m[7] * m[9] * # <<<<<<<<<<<<<< + * m[14] - m[5] * m[11] * m[14] - m[6] * m[9] * m[15] + m[5] * + * m[10] * m[15]) * f + */ + (__pyx_v_self->m[0]) = (((((((((__pyx_v_m[6]) * (__pyx_v_m[11])) * (__pyx_v_m[13])) - (((__pyx_v_m[7]) * (__pyx_v_m[10])) * (__pyx_v_m[13]))) + (((__pyx_v_m[7]) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) - (((__pyx_v_m[5]) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) - (((__pyx_v_m[6]) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) + (((__pyx_v_m[5]) * (__pyx_v_m[10])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":442 + * m[10] * m[15]) * f + * + * self.m[1] = (m[3] * m[10] * m[13] - m[2] * m[11] * m[13] - m[3] * m[9] * # <<<<<<<<<<<<<< + * m[14] + m[1] * m[11] * m[14] + m[2] * m[9] * m[15] - + * m[1] * m[10] * m[15]) * f + */ + (__pyx_v_self->m[1]) = (((((((((__pyx_v_m[3]) * (__pyx_v_m[10])) * (__pyx_v_m[13])) - (((__pyx_v_m[2]) * (__pyx_v_m[11])) * (__pyx_v_m[13]))) - (((__pyx_v_m[3]) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) + (((__pyx_v_m[1]) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) + (((__pyx_v_m[2]) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) - (((__pyx_v_m[1]) * (__pyx_v_m[10])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":445 + * m[14] + m[1] * m[11] * m[14] + m[2] * m[9] * m[15] - + * m[1] * m[10] * m[15]) * f + * self.m[2] = (m[2] * m[7] * m[13] - m[3] * m[6] * m[13] + m[3] * m[5] * # <<<<<<<<<<<<<< + * m[14] - m[1] * m[7] * m[14] - m[2] * m[5] * m[15] + + * m[1] * m[6] * m[15]) * f + */ + (__pyx_v_self->m[2]) = (((((((((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[13])) - (((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[13]))) + (((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[14]))) - (((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[14]))) - (((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[15]))) + (((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":449 + * m[1] * m[6] * m[15]) * f + * + * self.m[3] = (m[3] * m[6] * m[9] - m[2] * m[7] * m[9] - m[3] * m[5] * # <<<<<<<<<<<<<< + * m[10] + m[1] * m[7] * m[10] + m[2] * m[5] * m[11] - m[1] * + * m[6] * m[11]) * f + */ + (__pyx_v_self->m[3]) = (((((((((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[9])) - (((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[9]))) - (((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[10]))) + (((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[10]))) + (((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[11]))) - (((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[11]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":453 + * m[6] * m[11]) * f + * + * self.m[4] = (m[7] * m[10] * m[12] - m[6] * m[11] * m[12] - m[7] * m[8] * # <<<<<<<<<<<<<< + * m[14] + m[4] * m[11] * m[14] + m[6] * m[8] * m[15] - + * m[4] * m[10] * m[15]) * f + */ + (__pyx_v_self->m[4]) = (((((((((__pyx_v_m[7]) * (__pyx_v_m[10])) * (__pyx_v_m[12])) - (((__pyx_v_m[6]) * (__pyx_v_m[11])) * (__pyx_v_m[12]))) - (((__pyx_v_m[7]) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) + (((__pyx_v_m[4]) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) + (((__pyx_v_m[6]) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) - (((__pyx_v_m[4]) * (__pyx_v_m[10])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":457 + * m[4] * m[10] * m[15]) * f + * + * self.m[5] = (m[2] * m[11] * m[12] - m[3] * m[10] * m[12] + m[3] * m[8] * # <<<<<<<<<<<<<< + * m[14] - m[0] * m[11] * m[14] - m[2] * m[8] * m[15] + + * m[0] * m[10] * m[15]) * f + */ + (__pyx_v_self->m[5]) = (((((((((__pyx_v_m[2]) * (__pyx_v_m[11])) * (__pyx_v_m[12])) - (((__pyx_v_m[3]) * (__pyx_v_m[10])) * (__pyx_v_m[12]))) + (((__pyx_v_m[3]) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) - (((__pyx_v_m[0]) * (__pyx_v_m[11])) * (__pyx_v_m[14]))) - (((__pyx_v_m[2]) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) + (((__pyx_v_m[0]) * (__pyx_v_m[10])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":461 + * m[0] * m[10] * m[15]) * f + * + * self.m[6] = (m[3] * m[6] * m[12] - m[2] * m[7] * m[12] - m[3] * m[4] * # <<<<<<<<<<<<<< + * m[14] + m[0] * m[7] * m[14] + m[2] * m[4] * m[15] - + * m[0] * m[6] * m[15]) * f + */ + (__pyx_v_self->m[6]) = (((((((((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[12])) - (((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[12]))) - (((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[14]))) + (((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[14]))) + (((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[15]))) - (((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":465 + * m[0] * m[6] * m[15]) * f + * + * self.m[7] = (m[2] * m[7] * m[8] - m[3] * m[6] * m[8] + m[3] * m[4] * # <<<<<<<<<<<<<< + * m[10] - m[0] * m[7] * m[10] - m[2] * m[4] * m[11] + + * m[0] * m[6] * m[11]) * f + */ + (__pyx_v_self->m[7]) = (((((((((__pyx_v_m[2]) * (__pyx_v_m[7])) * (__pyx_v_m[8])) - (((__pyx_v_m[3]) * (__pyx_v_m[6])) * (__pyx_v_m[8]))) + (((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[10]))) - (((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[10]))) - (((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[11]))) + (((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[11]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":469 + * m[0] * m[6] * m[11]) * f + * + * self.m[8] = (m[5] * m[11] * m[12] - m[7] * m[9] * m[12] + m[7] * m[8] * # <<<<<<<<<<<<<< + * m[13] - m[4] * m[11] * m[13] - m[5] * m[8] * m[15] + + * m[4] * m[9] * m[15]) * f + */ + (__pyx_v_self->m[8]) = (((((((((__pyx_v_m[5]) * (__pyx_v_m[11])) * (__pyx_v_m[12])) - (((__pyx_v_m[7]) * (__pyx_v_m[9])) * (__pyx_v_m[12]))) + (((__pyx_v_m[7]) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) - (((__pyx_v_m[4]) * (__pyx_v_m[11])) * (__pyx_v_m[13]))) - (((__pyx_v_m[5]) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) + (((__pyx_v_m[4]) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":473 + * m[4] * m[9] * m[15]) * f + * + * self.m[9] = (m[3] * m[9] * m[12] - m[1] * m[11] * m[12] - m[3] * # <<<<<<<<<<<<<< + * m[8] * m[13] + m[0] * m[11] * m[13] + m[1] * m[8] * + * m[15] - m[0] * m[9] * m[15]) * f + */ + (__pyx_v_self->m[9]) = (((((((((__pyx_v_m[3]) * (__pyx_v_m[9])) * (__pyx_v_m[12])) - (((__pyx_v_m[1]) * (__pyx_v_m[11])) * (__pyx_v_m[12]))) - (((__pyx_v_m[3]) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) + (((__pyx_v_m[0]) * (__pyx_v_m[11])) * (__pyx_v_m[13]))) + (((__pyx_v_m[1]) * (__pyx_v_m[8])) * (__pyx_v_m[15]))) - (((__pyx_v_m[0]) * (__pyx_v_m[9])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":477 + * m[15] - m[0] * m[9] * m[15]) * f + * + * self.m[10] = (m[1] * m[7] * m[12] - m[3] * m[5] * m[12] + m[3] * # <<<<<<<<<<<<<< + * m[4] * m[13] - m[0] * m[7] * m[13] - m[1] * m[4] * + * m[15] + m[0] * m[5] * m[15]) * f + */ + (__pyx_v_self->m[10]) = (((((((((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[12])) - (((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[12]))) + (((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[13]))) - (((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[13]))) - (((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[15]))) + (((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[15]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":481 + * m[15] + m[0] * m[5] * m[15]) * f + * + * self.m[11] = (m[3] * m[5] * m[8] - m[1] * m[7] * m[8] - m[3] * m[4] * # <<<<<<<<<<<<<< + * m[9] + m[0] * m[7] * m[9] + m[1] * m[4] * m[11] - + * m[0] * m[5] * m[11]) * f + */ + (__pyx_v_self->m[11]) = (((((((((__pyx_v_m[3]) * (__pyx_v_m[5])) * (__pyx_v_m[8])) - (((__pyx_v_m[1]) * (__pyx_v_m[7])) * (__pyx_v_m[8]))) - (((__pyx_v_m[3]) * (__pyx_v_m[4])) * (__pyx_v_m[9]))) + (((__pyx_v_m[0]) * (__pyx_v_m[7])) * (__pyx_v_m[9]))) + (((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[11]))) - (((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[11]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":485 + * m[0] * m[5] * m[11]) * f + * + * self.m[12] = (m[6] * m[9] * m[12] - m[5] * m[10] * m[12] - m[6] * # <<<<<<<<<<<<<< + * m[8] * m[13] + m[4] * m[10] * m[13] + m[5] * m[8] * + * m[14] - m[4] * m[9] * m[14]) * f + */ + (__pyx_v_self->m[12]) = (((((((((__pyx_v_m[6]) * (__pyx_v_m[9])) * (__pyx_v_m[12])) - (((__pyx_v_m[5]) * (__pyx_v_m[10])) * (__pyx_v_m[12]))) - (((__pyx_v_m[6]) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) + (((__pyx_v_m[4]) * (__pyx_v_m[10])) * (__pyx_v_m[13]))) + (((__pyx_v_m[5]) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) - (((__pyx_v_m[4]) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":489 + * m[14] - m[4] * m[9] * m[14]) * f + * + * self.m[13] = (m[1] * m[10] * m[12] - m[2] * m[9] * m[12] + m[2] * # <<<<<<<<<<<<<< + * m[8] * m[13] - m[0] * m[10] * m[13] - m[1] * m[8] * + * m[14] + m[0] * m[9] * m[14]) * f + */ + (__pyx_v_self->m[13]) = (((((((((__pyx_v_m[1]) * (__pyx_v_m[10])) * (__pyx_v_m[12])) - (((__pyx_v_m[2]) * (__pyx_v_m[9])) * (__pyx_v_m[12]))) + (((__pyx_v_m[2]) * (__pyx_v_m[8])) * (__pyx_v_m[13]))) - (((__pyx_v_m[0]) * (__pyx_v_m[10])) * (__pyx_v_m[13]))) - (((__pyx_v_m[1]) * (__pyx_v_m[8])) * (__pyx_v_m[14]))) + (((__pyx_v_m[0]) * (__pyx_v_m[9])) * (__pyx_v_m[14]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":493 + * m[14] + m[0] * m[9] * m[14]) * f + * + * self.m[14] = (m[2] * m[5] * m[12] - m[1] * m[6] * m[12] - m[2] * # <<<<<<<<<<<<<< + * m[4] * m[13] + m[0] * m[6] * m[13] + m[1] * m[4] * + * m[14] - m[0] * m[5] * m[14]) * f + */ + (__pyx_v_self->m[14]) = (((((((((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[12])) - (((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[12]))) - (((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[13]))) + (((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[13]))) + (((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[14]))) - (((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[14]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":497 + * m[14] - m[0] * m[5] * m[14]) * f + * + * self.m[15] = (m[1] * m[6] * m[8] - m[2] * m[5] * m[8] + m[2] * m[4] * # <<<<<<<<<<<<<< + * m[9] - m[0] * m[6] * m[9] - m[1] * m[4] * m[10] + + * m[0] * m[5] * m[10]) * f + */ + (__pyx_v_self->m[15]) = (((((((((__pyx_v_m[1]) * (__pyx_v_m[6])) * (__pyx_v_m[8])) - (((__pyx_v_m[2]) * (__pyx_v_m[5])) * (__pyx_v_m[8]))) + (((__pyx_v_m[2]) * (__pyx_v_m[4])) * (__pyx_v_m[9]))) - (((__pyx_v_m[0]) * (__pyx_v_m[6])) * (__pyx_v_m[9]))) - (((__pyx_v_m[1]) * (__pyx_v_m[4])) * (__pyx_v_m[10]))) + (((__pyx_v_m[0]) * (__pyx_v_m[5])) * (__pyx_v_m[10]))) * __pyx_v_f); + + /* "ezdxf/acc/matrix44.pyx":434 + * m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] + * + * def inverse(self) -> None: # <<<<<<<<<<<<<< + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.inverse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":501 + * m[0] * m[5] * m[10]) * f + * + * @staticmethod # <<<<<<<<<<<<<< + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_66ucs(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_66ucs = {"ucs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_66ucs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_66ucs(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ux = 0; + PyObject *__pyx_v_uy = 0; + PyObject *__pyx_v_uz = 0; + PyObject *__pyx_v_origin = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[4] = {0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("ucs (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ux,&__pyx_n_s_uy,&__pyx_n_s_uz,&__pyx_n_s_origin,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__16); + values[1] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__17); + values[2] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__18); + values[3] = __Pyx_Arg_NewRef_FASTCALL(__pyx_k__19); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ux); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 501, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_uy); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 501, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_uz); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 501, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_origin); + if (value) { values[3] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 501, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "ucs") < 0)) __PYX_ERR(0, 501, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ux = values[0]; + __pyx_v_uy = values[1]; + __pyx_v_uz = values[2]; + __pyx_v_origin = values[3]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("ucs", 0, 0, 4, __pyx_nargs); __PYX_ERR(0, 501, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_65ucs(__pyx_v_ux, __pyx_v_uy, __pyx_v_uz, __pyx_v_origin); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_65ucs(PyObject *__pyx_v_ux, PyObject *__pyx_v_uy, PyObject *__pyx_v_uz, PyObject *__pyx_v_origin) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_mat = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v__ux = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v__uy = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v__uz = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v__origin = 0; + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("ucs", 1); + + /* "ezdxf/acc/matrix44.pyx":503 + * @staticmethod + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() # <<<<<<<<<<<<<< + * cdef Vec3 _ux = Vec3(ux) + * cdef Vec3 _uy = Vec3(uy) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_mat = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":504 + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + * cdef Vec3 _ux = Vec3(ux) # <<<<<<<<<<<<<< + * cdef Vec3 _uy = Vec3(uy) + * cdef Vec3 _uz = Vec3(uz) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_ux); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__ux = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":505 + * cdef Matrix44 mat = Matrix44() + * cdef Vec3 _ux = Vec3(ux) + * cdef Vec3 _uy = Vec3(uy) # <<<<<<<<<<<<<< + * cdef Vec3 _uz = Vec3(uz) + * cdef Vec3 _origin = Vec3(origin) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_uy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 505, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__uy = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":506 + * cdef Vec3 _ux = Vec3(ux) + * cdef Vec3 _uy = Vec3(uy) + * cdef Vec3 _uz = Vec3(uz) # <<<<<<<<<<<<<< + * cdef Vec3 _origin = Vec3(origin) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_uz); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__uz = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":507 + * cdef Vec3 _uy = Vec3(uy) + * cdef Vec3 _uz = Vec3(uz) + * cdef Vec3 _origin = Vec3(origin) # <<<<<<<<<<<<<< + * + * mat.m[0] = _ux.x + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_origin); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 507, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__origin = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":509 + * cdef Vec3 _origin = Vec3(origin) + * + * mat.m[0] = _ux.x # <<<<<<<<<<<<<< + * mat.m[1] = _ux.y + * mat.m[2] = _ux.z + */ + __pyx_t_2 = __pyx_v__ux->x; + (__pyx_v_mat->m[0]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":510 + * + * mat.m[0] = _ux.x + * mat.m[1] = _ux.y # <<<<<<<<<<<<<< + * mat.m[2] = _ux.z + * + */ + __pyx_t_2 = __pyx_v__ux->y; + (__pyx_v_mat->m[1]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":511 + * mat.m[0] = _ux.x + * mat.m[1] = _ux.y + * mat.m[2] = _ux.z # <<<<<<<<<<<<<< + * + * mat.m[4] = _uy.x + */ + __pyx_t_2 = __pyx_v__ux->z; + (__pyx_v_mat->m[2]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":513 + * mat.m[2] = _ux.z + * + * mat.m[4] = _uy.x # <<<<<<<<<<<<<< + * mat.m[5] = _uy.y + * mat.m[6] = _uy.z + */ + __pyx_t_2 = __pyx_v__uy->x; + (__pyx_v_mat->m[4]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":514 + * + * mat.m[4] = _uy.x + * mat.m[5] = _uy.y # <<<<<<<<<<<<<< + * mat.m[6] = _uy.z + * + */ + __pyx_t_2 = __pyx_v__uy->y; + (__pyx_v_mat->m[5]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":515 + * mat.m[4] = _uy.x + * mat.m[5] = _uy.y + * mat.m[6] = _uy.z # <<<<<<<<<<<<<< + * + * mat.m[8] = _uz.x + */ + __pyx_t_2 = __pyx_v__uy->z; + (__pyx_v_mat->m[6]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":517 + * mat.m[6] = _uy.z + * + * mat.m[8] = _uz.x # <<<<<<<<<<<<<< + * mat.m[9] = _uz.y + * mat.m[10] = _uz.z + */ + __pyx_t_2 = __pyx_v__uz->x; + (__pyx_v_mat->m[8]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":518 + * + * mat.m[8] = _uz.x + * mat.m[9] = _uz.y # <<<<<<<<<<<<<< + * mat.m[10] = _uz.z + * + */ + __pyx_t_2 = __pyx_v__uz->y; + (__pyx_v_mat->m[9]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":519 + * mat.m[8] = _uz.x + * mat.m[9] = _uz.y + * mat.m[10] = _uz.z # <<<<<<<<<<<<<< + * + * mat.m[12] = _origin.x + */ + __pyx_t_2 = __pyx_v__uz->z; + (__pyx_v_mat->m[10]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":521 + * mat.m[10] = _uz.z + * + * mat.m[12] = _origin.x # <<<<<<<<<<<<<< + * mat.m[13] = _origin.y + * mat.m[14] = _origin.z + */ + __pyx_t_2 = __pyx_v__origin->x; + (__pyx_v_mat->m[12]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":522 + * + * mat.m[12] = _origin.x + * mat.m[13] = _origin.y # <<<<<<<<<<<<<< + * mat.m[14] = _origin.z + * + */ + __pyx_t_2 = __pyx_v__origin->y; + (__pyx_v_mat->m[13]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":523 + * mat.m[12] = _origin.x + * mat.m[13] = _origin.y + * mat.m[14] = _origin.z # <<<<<<<<<<<<<< + * + * return mat + */ + __pyx_t_2 = __pyx_v__origin->z; + (__pyx_v_mat->m[14]) = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":525 + * mat.m[14] = _origin.z + * + * return mat # <<<<<<<<<<<<<< + * + * def transform(self, vector: UVec) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_mat); + __pyx_r = __pyx_v_mat; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":501 + * m[0] * m[5] * m[10]) * f + * + * @staticmethod # <<<<<<<<<<<<<< + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_mat); + __Pyx_XDECREF((PyObject *)__pyx_v__ux); + __Pyx_XDECREF((PyObject *)__pyx_v__uy); + __Pyx_XDECREF((PyObject *)__pyx_v__uz); + __Pyx_XDECREF((PyObject *)__pyx_v__origin); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":527 + * return mat + * + * def transform(self, vector: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_68transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_68transform = {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_68transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_68transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vector = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vector,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vector)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 527, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform") < 0)) __PYX_ERR(0, 527, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_vector = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 527, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_67transform(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_vector); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_67transform(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vector) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + double *__pyx_v_m; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + double *__pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform", 1); + + /* "ezdxf/acc/matrix44.pyx":528 + * + * def transform(self, vector: UVec) -> Vec3: + * cdef Vec3 res = Vec3(vector) # <<<<<<<<<<<<<< + * cdef double x = res.x + * cdef double y = res.y + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_vector); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 528, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":529 + * def transform(self, vector: UVec) -> Vec3: + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x # <<<<<<<<<<<<<< + * cdef double y = res.y + * cdef double z = res.z + */ + __pyx_t_2 = __pyx_v_res->x; + __pyx_v_x = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":530 + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + * cdef double y = res.y # <<<<<<<<<<<<<< + * cdef double z = res.z + * cdef double *m = self.m + */ + __pyx_t_2 = __pyx_v_res->y; + __pyx_v_y = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":531 + * cdef double x = res.x + * cdef double y = res.y + * cdef double z = res.z # <<<<<<<<<<<<<< + * cdef double *m = self.m + * + */ + __pyx_t_2 = __pyx_v_res->z; + __pyx_v_z = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":532 + * cdef double y = res.y + * cdef double z = res.z + * cdef double *m = self.m # <<<<<<<<<<<<<< + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + */ + __pyx_t_3 = __pyx_v_self->m; + __pyx_v_m = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":534 + * cdef double *m = self.m + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] # <<<<<<<<<<<<<< + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + */ + __pyx_v_res->x = ((((__pyx_v_x * (__pyx_v_m[0])) + (__pyx_v_y * (__pyx_v_m[4]))) + (__pyx_v_z * (__pyx_v_m[8]))) + (__pyx_v_m[12])); + + /* "ezdxf/acc/matrix44.pyx":535 + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] # <<<<<<<<<<<<<< + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + * return res + */ + __pyx_v_res->y = ((((__pyx_v_x * (__pyx_v_m[1])) + (__pyx_v_y * (__pyx_v_m[5]))) + (__pyx_v_z * (__pyx_v_m[9]))) + (__pyx_v_m[13])); + + /* "ezdxf/acc/matrix44.pyx":536 + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = ((((__pyx_v_x * (__pyx_v_m[2])) + (__pyx_v_y * (__pyx_v_m[6]))) + (__pyx_v_z * (__pyx_v_m[10]))) + (__pyx_v_m[14])); + + /* "ezdxf/acc/matrix44.pyx":537 + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + * return res # <<<<<<<<<<<<<< + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":527 + * return mat + * + * def transform(self, vector: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":539 + * return res + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction = {"transform_direction", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vector = 0; + PyObject *__pyx_v_normalize = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_direction (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vector,&__pyx_n_s_normalize,0}; + values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_False)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vector)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 539, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_normalize); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 539, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform_direction") < 0)) __PYX_ERR(0, 539, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_vector = values[0]; + __pyx_v_normalize = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform_direction", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 539, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_direction", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_69transform_direction(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_vector, __pyx_v_normalize); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_69transform_direction(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vector, PyObject *__pyx_v_normalize) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + double *__pyx_v_m; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + double *__pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform_direction", 1); + + /* "ezdxf/acc/matrix44.pyx":540 + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: + * cdef Vec3 res = Vec3(vector) # <<<<<<<<<<<<<< + * cdef double x = res.x + * cdef double y = res.y + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_vector); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 540, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/matrix44.pyx":541 + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x # <<<<<<<<<<<<<< + * cdef double y = res.y + * cdef double z = res.z + */ + __pyx_t_2 = __pyx_v_res->x; + __pyx_v_x = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":542 + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + * cdef double y = res.y # <<<<<<<<<<<<<< + * cdef double z = res.z + * cdef double *m = self.m + */ + __pyx_t_2 = __pyx_v_res->y; + __pyx_v_y = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":543 + * cdef double x = res.x + * cdef double y = res.y + * cdef double z = res.z # <<<<<<<<<<<<<< + * cdef double *m = self.m + * + */ + __pyx_t_2 = __pyx_v_res->z; + __pyx_v_z = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":544 + * cdef double y = res.y + * cdef double z = res.z + * cdef double *m = self.m # <<<<<<<<<<<<<< + * + * res.x = x * m[0] + y * m[4] + z * m[8] + */ + __pyx_t_3 = __pyx_v_self->m; + __pyx_v_m = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":546 + * cdef double *m = self.m + * + * res.x = x * m[0] + y * m[4] + z * m[8] # <<<<<<<<<<<<<< + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] + */ + __pyx_v_res->x = (((__pyx_v_x * (__pyx_v_m[0])) + (__pyx_v_y * (__pyx_v_m[4]))) + (__pyx_v_z * (__pyx_v_m[8]))); + + /* "ezdxf/acc/matrix44.pyx":547 + * + * res.x = x * m[0] + y * m[4] + z * m[8] + * res.y = x * m[1] + y * m[5] + z * m[9] # <<<<<<<<<<<<<< + * res.z = x * m[2] + y * m[6] + z * m[10] + * if normalize: + */ + __pyx_v_res->y = (((__pyx_v_x * (__pyx_v_m[1])) + (__pyx_v_y * (__pyx_v_m[5]))) + (__pyx_v_z * (__pyx_v_m[9]))); + + /* "ezdxf/acc/matrix44.pyx":548 + * res.x = x * m[0] + y * m[4] + z * m[8] + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] # <<<<<<<<<<<<<< + * if normalize: + * return v3_normalize(res, 1.0) + */ + __pyx_v_res->z = (((__pyx_v_x * (__pyx_v_m[2])) + (__pyx_v_y * (__pyx_v_m[6]))) + (__pyx_v_z * (__pyx_v_m[10]))); + + /* "ezdxf/acc/matrix44.pyx":549 + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] + * if normalize: # <<<<<<<<<<<<<< + * return v3_normalize(res, 1.0) + * else: + */ + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_normalize); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 549, __pyx_L1_error) + if (__pyx_t_4) { + + /* "ezdxf/acc/matrix44.pyx":550 + * res.z = x * m[2] + y * m[6] + z * m[10] + * if normalize: + * return v3_normalize(res, 1.0) # <<<<<<<<<<<<<< + * else: + * return res + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_res, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 550, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":549 + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] + * if normalize: # <<<<<<<<<<<<<< + * return v3_normalize(res, 1.0) + * else: + */ + } + + /* "ezdxf/acc/matrix44.pyx":552 + * return v3_normalize(res, 1.0) + * else: + * return res # <<<<<<<<<<<<<< + * + * ocs_to_wcs = transform_direction + */ + /*else*/ { + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + } + + /* "ezdxf/acc/matrix44.pyx":539 + * return res + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_direction", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_73generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":556 + * ocs_to_wcs = transform_direction + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices = {"transform_vertices", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vectors = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_vertices (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vectors,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vectors)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 556, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform_vertices") < 0)) __PYX_ERR(0, 556, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_vectors = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform_vertices", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 556, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_vertices", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_71transform_vertices(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_vectors); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_71transform_vertices(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vectors) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform_vertices", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 556, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_vectors = __pyx_v_vectors; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_vectors); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_vectors); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_73generator1, __pyx_codeobj__20, (PyObject *) __pyx_cur_scope, __pyx_n_s_transform_vertices, __pyx_n_s_Matrix44_transform_vertices, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 556, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_vertices", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_73generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + double *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + double __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_vertices", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 556, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":557 + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: + * cdef double *m = self.m # <<<<<<<<<<<<<< + * cdef Vec3 res + * cdef double x, y, z + */ + __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->m; + __pyx_cur_scope->__pyx_v_m = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":561 + * cdef double x, y, z + * + * for vector in vectors: # <<<<<<<<<<<<<< + * res = Vec3(vector) + * x = res.x + */ + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_vectors)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_vectors)) { + __pyx_t_2 = __pyx_cur_scope->__pyx_v_vectors; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_vectors); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 561, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 561, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 561, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 561, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 561, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 561, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 561, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 561, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 561, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_5); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_vector); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_vector, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/matrix44.pyx":562 + * + * for vector in vectors: + * res = Vec3(vector) # <<<<<<<<<<<<<< + * x = res.x + * y = res.y + */ + __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_vector); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 562, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_res, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_5)); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + + /* "ezdxf/acc/matrix44.pyx":563 + * for vector in vectors: + * res = Vec3(vector) + * x = res.x # <<<<<<<<<<<<<< + * y = res.y + * z = res.z + */ + __pyx_t_6 = __pyx_cur_scope->__pyx_v_res->x; + __pyx_cur_scope->__pyx_v_x = __pyx_t_6; + + /* "ezdxf/acc/matrix44.pyx":564 + * res = Vec3(vector) + * x = res.x + * y = res.y # <<<<<<<<<<<<<< + * z = res.z + * + */ + __pyx_t_6 = __pyx_cur_scope->__pyx_v_res->y; + __pyx_cur_scope->__pyx_v_y = __pyx_t_6; + + /* "ezdxf/acc/matrix44.pyx":565 + * x = res.x + * y = res.y + * z = res.z # <<<<<<<<<<<<<< + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + */ + __pyx_t_6 = __pyx_cur_scope->__pyx_v_res->z; + __pyx_cur_scope->__pyx_v_z = __pyx_t_6; + + /* "ezdxf/acc/matrix44.pyx":567 + * z = res.z + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] # <<<<<<<<<<<<<< + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + */ + __pyx_cur_scope->__pyx_v_res->x = ((((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[0])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[4]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[8]))) + (__pyx_cur_scope->__pyx_v_m[12])); + + /* "ezdxf/acc/matrix44.pyx":568 + * + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] # <<<<<<<<<<<<<< + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + * yield res + */ + __pyx_cur_scope->__pyx_v_res->y = ((((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[1])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[5]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[9]))) + (__pyx_cur_scope->__pyx_v_m[13])); + + /* "ezdxf/acc/matrix44.pyx":569 + * res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] # <<<<<<<<<<<<<< + * yield res + * + */ + __pyx_cur_scope->__pyx_v_res->z = ((((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[2])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[6]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[10]))) + (__pyx_cur_scope->__pyx_v_m[14])); + + /* "ezdxf/acc/matrix44.pyx":570 + * res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + * res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + * yield res # <<<<<<<<<<<<<< + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: + */ + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_res); + __Pyx_XGIVEREF(__pyx_t_2); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_3; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_4; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_2 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_4 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 570, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":561 + * cdef double x, y, z + * + * for vector in vectors: # <<<<<<<<<<<<<< + * res = Vec3(vector) + * x = res.x + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/matrix44.pyx":556 + * ocs_to_wcs = transform_direction + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("transform_vertices", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_76generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":572 + * yield res + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: # <<<<<<<<<<<<<< + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform = {"fast_2d_transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_points = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("fast_2d_transform (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_points,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_points)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 572, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "fast_2d_transform") < 0)) __PYX_ERR(0, 572, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_points = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("fast_2d_transform", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 572, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.fast_2d_transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_74fast_2d_transform(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_points); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_74fast_2d_transform(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_points) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("fast_2d_transform", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 572, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_points = __pyx_v_points; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_points); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_points); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_76generator2, __pyx_codeobj__21, (PyObject *) __pyx_cur_scope, __pyx_n_s_fast_2d_transform, __pyx_n_s_Matrix44_fast_2d_transform, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.fast_2d_transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_76generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + double __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("fast_2d_transform", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 572, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":573 + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: + * cdef double m0 = self.m[0] # <<<<<<<<<<<<<< + * cdef double m1 = self.m[1] + * cdef double m4 = self.m[4] + */ + __pyx_cur_scope->__pyx_v_m0 = (__pyx_cur_scope->__pyx_v_self->m[0]); + + /* "ezdxf/acc/matrix44.pyx":574 + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] # <<<<<<<<<<<<<< + * cdef double m4 = self.m[4] + * cdef double m5 = self.m[5] + */ + __pyx_cur_scope->__pyx_v_m1 = (__pyx_cur_scope->__pyx_v_self->m[1]); + + /* "ezdxf/acc/matrix44.pyx":575 + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + * cdef double m4 = self.m[4] # <<<<<<<<<<<<<< + * cdef double m5 = self.m[5] + * cdef double m12 = self.m[12] + */ + __pyx_cur_scope->__pyx_v_m4 = (__pyx_cur_scope->__pyx_v_self->m[4]); + + /* "ezdxf/acc/matrix44.pyx":576 + * cdef double m1 = self.m[1] + * cdef double m4 = self.m[4] + * cdef double m5 = self.m[5] # <<<<<<<<<<<<<< + * cdef double m12 = self.m[12] + * cdef double m13 = self.m[13] + */ + __pyx_cur_scope->__pyx_v_m5 = (__pyx_cur_scope->__pyx_v_self->m[5]); + + /* "ezdxf/acc/matrix44.pyx":577 + * cdef double m4 = self.m[4] + * cdef double m5 = self.m[5] + * cdef double m12 = self.m[12] # <<<<<<<<<<<<<< + * cdef double m13 = self.m[13] + * cdef double x, y + */ + __pyx_cur_scope->__pyx_v_m12 = (__pyx_cur_scope->__pyx_v_self->m[12]); + + /* "ezdxf/acc/matrix44.pyx":578 + * cdef double m5 = self.m[5] + * cdef double m12 = self.m[12] + * cdef double m13 = self.m[13] # <<<<<<<<<<<<<< + * cdef double x, y + * cdef Vec2 res + */ + __pyx_cur_scope->__pyx_v_m13 = (__pyx_cur_scope->__pyx_v_self->m[13]); + + /* "ezdxf/acc/matrix44.pyx":582 + * cdef Vec2 res + * + * for pnt in points: # <<<<<<<<<<<<<< + * res = Vec2(pnt) + * x = res.x + */ + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_points)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_points)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_v_points; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_points); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 582, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 582, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 582, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 582, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 582, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 582, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_pnt); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_pnt, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":583 + * + * for pnt in points: + * res = Vec2(pnt) # <<<<<<<<<<<<<< + * x = res.x + * y = res.y + */ + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_cur_scope->__pyx_v_pnt); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_res, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_4)); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":584 + * for pnt in points: + * res = Vec2(pnt) + * x = res.x # <<<<<<<<<<<<<< + * y = res.y + * res.x = x * m0 + y * m4 + m12 + */ + __pyx_t_5 = __pyx_cur_scope->__pyx_v_res->x; + __pyx_cur_scope->__pyx_v_x = __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":585 + * res = Vec2(pnt) + * x = res.x + * y = res.y # <<<<<<<<<<<<<< + * res.x = x * m0 + y * m4 + m12 + * res.y = x * m1 + y * m5 + m13 + */ + __pyx_t_5 = __pyx_cur_scope->__pyx_v_res->y; + __pyx_cur_scope->__pyx_v_y = __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":586 + * x = res.x + * y = res.y + * res.x = x * m0 + y * m4 + m12 # <<<<<<<<<<<<<< + * res.y = x * m1 + y * m5 + m13 + * yield res + */ + __pyx_cur_scope->__pyx_v_res->x = (((__pyx_cur_scope->__pyx_v_x * __pyx_cur_scope->__pyx_v_m0) + (__pyx_cur_scope->__pyx_v_y * __pyx_cur_scope->__pyx_v_m4)) + __pyx_cur_scope->__pyx_v_m12); + + /* "ezdxf/acc/matrix44.pyx":587 + * y = res.y + * res.x = x * m0 + y * m4 + m12 + * res.y = x * m1 + y * m5 + m13 # <<<<<<<<<<<<<< + * yield res + * + */ + __pyx_cur_scope->__pyx_v_res->y = (((__pyx_cur_scope->__pyx_v_x * __pyx_cur_scope->__pyx_v_m1) + (__pyx_cur_scope->__pyx_v_y * __pyx_cur_scope->__pyx_v_m5)) + __pyx_cur_scope->__pyx_v_m13); + + /* "ezdxf/acc/matrix44.pyx":588 + * res.x = x * m0 + y * m4 + m12 + * res.y = x * m1 + y * m5 + m13 + * yield res # <<<<<<<<<<<<<< + * + * def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: + */ + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_res); + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 588, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":582 + * cdef Vec2 res + * + * for pnt in points: # <<<<<<<<<<<<<< + * res = Vec2(pnt) + * x = res.x + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/matrix44.pyx":572 + * yield res + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: # <<<<<<<<<<<<<< + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("fast_2d_transform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":590 + * yield res + * + * def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: # <<<<<<<<<<<<<< + * """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + * to transform, this allows 2D/3D transformation on arrays with more columns + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace, "Transforms a numpy array inplace, the argument `ndim` defines the dimensions\n to transform, this allows 2D/3D transformation on arrays with more columns\n e.g. a polyline array which stores points as (x, y, start_width, end_width,\n bulge) values.\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace = {"transform_array_inplace", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_array = 0; + PyObject *__pyx_v_ndim = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_array_inplace (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_array,&__pyx_n_s_ndim,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_array)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 590, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ndim)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 590, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("transform_array_inplace", 1, 2, 2, 1); __PYX_ERR(0, 590, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform_array_inplace") < 0)) __PYX_ERR(0, 590, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_array = values[0]; + __pyx_v_ndim = ((PyObject*)values[1]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform_array_inplace", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 590, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_array_inplace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ndim), (&PyInt_Type), 0, "ndim", 1))) __PYX_ERR(0, 590, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_array, __pyx_v_ndim); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_array, PyObject *__pyx_v_ndim) { + int __pyx_v__ndim; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + __Pyx_memviewslice __pyx_t_5 = { 0, 0, { 0 }, { 0 }, { 0 } }; + Py_ssize_t __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform_array_inplace", 1); + + /* "ezdxf/acc/matrix44.pyx":597 + * + * """ + * cdef int _ndim = ndim # <<<<<<<<<<<<<< + * if _ndim == 2: + * assert array.shape[1] > 1 + */ + __pyx_t_1 = __Pyx_PyInt_As_int(__pyx_v_ndim); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 597, __pyx_L1_error) + __pyx_v__ndim = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":598 + * """ + * cdef int _ndim = ndim + * if _ndim == 2: # <<<<<<<<<<<<<< + * assert array.shape[1] > 1 + * transform_2d_array_inplace(self.m, array, array.shape[0]) + */ + switch (__pyx_v__ndim) { + case 2: + + /* "ezdxf/acc/matrix44.pyx":599 + * cdef int _ndim = ndim + * if _ndim == 2: + * assert array.shape[1] > 1 # <<<<<<<<<<<<<< + * transform_2d_array_inplace(self.m, array, array.shape[0]) + * elif _ndim == 3: + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_array, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 599, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 599, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyObject_RichCompare(__pyx_t_3, __pyx_int_1, Py_GT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 599, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 599, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_4)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(0, 599, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(0, 599, __pyx_L1_error) + #endif + + /* "ezdxf/acc/matrix44.pyx":600 + * if _ndim == 2: + * assert array.shape[1] > 1 + * transform_2d_array_inplace(self.m, array, array.shape[0]) # <<<<<<<<<<<<<< + * elif _ndim == 3: + * assert array.shape[1] > 2 + */ + __pyx_t_5 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_array, PyBUF_WRITABLE); if (unlikely(!__pyx_t_5.memview)) __PYX_ERR(0, 600, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_array, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 600, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 600, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_t_3); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 600, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_f_5ezdxf_3acc_8matrix44_transform_2d_array_inplace(__pyx_v_self->m, __pyx_t_5, __pyx_t_6); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 600, __pyx_L1_error) + __PYX_XCLEAR_MEMVIEW(&__pyx_t_5, 1); + __pyx_t_5.memview = NULL; __pyx_t_5.data = NULL; + + /* "ezdxf/acc/matrix44.pyx":598 + * """ + * cdef int _ndim = ndim + * if _ndim == 2: # <<<<<<<<<<<<<< + * assert array.shape[1] > 1 + * transform_2d_array_inplace(self.m, array, array.shape[0]) + */ + break; + case 3: + + /* "ezdxf/acc/matrix44.pyx":602 + * transform_2d_array_inplace(self.m, array, array.shape[0]) + * elif _ndim == 3: + * assert array.shape[1] > 2 # <<<<<<<<<<<<<< + * transform_3d_array_inplace(self.m, array, array.shape[0]) + * else: + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_array, __pyx_n_s_shape); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 602, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_3, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 602, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_int_2, Py_GT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 602, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 602, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_4)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(0, 602, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(0, 602, __pyx_L1_error) + #endif + + /* "ezdxf/acc/matrix44.pyx":603 + * elif _ndim == 3: + * assert array.shape[1] > 2 + * transform_3d_array_inplace(self.m, array, array.shape[0]) # <<<<<<<<<<<<<< + * else: + * raise ValueError("ndim has to be 2 or 3") + */ + __pyx_t_5 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_array, PyBUF_WRITABLE); if (unlikely(!__pyx_t_5.memview)) __PYX_ERR(0, 603, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_array, __pyx_n_s_shape); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 603, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 603, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_t_2); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 603, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_f_5ezdxf_3acc_8matrix44_transform_3d_array_inplace(__pyx_v_self->m, __pyx_t_5, __pyx_t_6); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 603, __pyx_L1_error) + __PYX_XCLEAR_MEMVIEW(&__pyx_t_5, 1); + __pyx_t_5.memview = NULL; __pyx_t_5.data = NULL; + + /* "ezdxf/acc/matrix44.pyx":601 + * assert array.shape[1] > 1 + * transform_2d_array_inplace(self.m, array, array.shape[0]) + * elif _ndim == 3: # <<<<<<<<<<<<<< + * assert array.shape[1] > 2 + * transform_3d_array_inplace(self.m, array, array.shape[0]) + */ + break; + default: + + /* "ezdxf/acc/matrix44.pyx":605 + * transform_3d_array_inplace(self.m, array, array.shape[0]) + * else: + * raise ValueError("ndim has to be 2 or 3") # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__22, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 605, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 605, __pyx_L1_error) + break; + } + + /* "ezdxf/acc/matrix44.pyx":590 + * yield res + * + * def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: # <<<<<<<<<<<<<< + * """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + * to transform, this allows 2D/3D transformation on arrays with more columns + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_5, 1); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_array_inplace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_81generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions = {"transform_directions", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vectors = 0; + PyObject *__pyx_v_normalize = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_directions (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vectors,&__pyx_n_s_normalize,0}; + + /* "ezdxf/acc/matrix44.pyx":609 + * + * def transform_directions( + * self, vectors: Iterable[UVec], normalize=False # <<<<<<<<<<<<<< + * ) -> Iterator[Vec3]: + * cdef double *m = self.m + */ + values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_False)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vectors)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 608, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_normalize); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 608, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "transform_directions") < 0)) __PYX_ERR(0, 608, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_vectors = values[0]; + __pyx_v_normalize = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("transform_directions", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 608, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_directions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_79transform_directions(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_vectors, __pyx_v_normalize); + + /* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_79transform_directions(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_vectors, PyObject *__pyx_v_normalize) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("transform_directions", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 608, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __pyx_cur_scope->__pyx_v_vectors = __pyx_v_vectors; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_vectors); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_vectors); + __pyx_cur_scope->__pyx_v_normalize = __pyx_v_normalize; + __Pyx_INCREF(__pyx_cur_scope->__pyx_v_normalize); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_normalize); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_81generator3, __pyx_codeobj__23, (PyObject *) __pyx_cur_scope, __pyx_n_s_transform_directions, __pyx_n_s_Matrix44_transform_directions, __pyx_n_s_ezdxf_acc_matrix44); if (unlikely(!gen)) __PYX_ERR(0, 608, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.transform_directions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_8matrix44_8Matrix44_81generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + double *__pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + PyObject *(*__pyx_t_5)(PyObject *); + PyObject *__pyx_t_6 = NULL; + double __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("transform_directions", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 608, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":611 + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + * cdef double *m = self.m # <<<<<<<<<<<<<< + * cdef Vec3 res + * cdef double x, y, z + */ + __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->m; + __pyx_cur_scope->__pyx_v_m = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":614 + * cdef Vec3 res + * cdef double x, y, z + * cdef bint _normalize = normalize # <<<<<<<<<<<<<< + * + * for vector in vectors: + */ + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_normalize); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 614, __pyx_L1_error) + __pyx_cur_scope->__pyx_v__normalize = __pyx_t_2; + + /* "ezdxf/acc/matrix44.pyx":616 + * cdef bint _normalize = normalize + * + * for vector in vectors: # <<<<<<<<<<<<<< + * res = Vec3(vector) + * x = res.x + */ + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_vectors)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_vectors)) { + __pyx_t_3 = __pyx_cur_scope->__pyx_v_vectors; __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = 0; + __pyx_t_5 = NULL; + } else { + __pyx_t_4 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_vectors); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 616, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 616, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_5)) { + if (likely(PyList_CheckExact(__pyx_t_3))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 616, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_6 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_6); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 616, __pyx_L1_error) + #else + __pyx_t_6 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 616, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_3); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 616, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_6); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(0, 616, __pyx_L1_error) + #else + __pyx_t_6 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 616, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + #endif + } + } else { + __pyx_t_6 = __pyx_t_5(__pyx_t_3); + if (unlikely(!__pyx_t_6)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 616, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_6); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_vector); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_vector, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_6); + __pyx_t_6 = 0; + + /* "ezdxf/acc/matrix44.pyx":617 + * + * for vector in vectors: + * res = Vec3(vector) # <<<<<<<<<<<<<< + * x = res.x + * y = res.y + */ + __pyx_t_6 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_vector); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_XGOTREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_res, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_6)); + __Pyx_GIVEREF(__pyx_t_6); + __pyx_t_6 = 0; + + /* "ezdxf/acc/matrix44.pyx":618 + * for vector in vectors: + * res = Vec3(vector) + * x = res.x # <<<<<<<<<<<<<< + * y = res.y + * z = res.z + */ + __pyx_t_7 = __pyx_cur_scope->__pyx_v_res->x; + __pyx_cur_scope->__pyx_v_x = __pyx_t_7; + + /* "ezdxf/acc/matrix44.pyx":619 + * res = Vec3(vector) + * x = res.x + * y = res.y # <<<<<<<<<<<<<< + * z = res.z + * + */ + __pyx_t_7 = __pyx_cur_scope->__pyx_v_res->y; + __pyx_cur_scope->__pyx_v_y = __pyx_t_7; + + /* "ezdxf/acc/matrix44.pyx":620 + * x = res.x + * y = res.y + * z = res.z # <<<<<<<<<<<<<< + * + * res.x = x * m[0] + y * m[4] + z * m[8] + */ + __pyx_t_7 = __pyx_cur_scope->__pyx_v_res->z; + __pyx_cur_scope->__pyx_v_z = __pyx_t_7; + + /* "ezdxf/acc/matrix44.pyx":622 + * z = res.z + * + * res.x = x * m[0] + y * m[4] + z * m[8] # <<<<<<<<<<<<<< + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] + */ + __pyx_cur_scope->__pyx_v_res->x = (((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[0])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[4]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[8]))); + + /* "ezdxf/acc/matrix44.pyx":623 + * + * res.x = x * m[0] + y * m[4] + z * m[8] + * res.y = x * m[1] + y * m[5] + z * m[9] # <<<<<<<<<<<<<< + * res.z = x * m[2] + y * m[6] + z * m[10] + * yield v3_normalize(res, 1.0) if _normalize else res + */ + __pyx_cur_scope->__pyx_v_res->y = (((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[1])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[5]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[9]))); + + /* "ezdxf/acc/matrix44.pyx":624 + * res.x = x * m[0] + y * m[4] + z * m[8] + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] # <<<<<<<<<<<<<< + * yield v3_normalize(res, 1.0) if _normalize else res + * + */ + __pyx_cur_scope->__pyx_v_res->z = (((__pyx_cur_scope->__pyx_v_x * (__pyx_cur_scope->__pyx_v_m[2])) + (__pyx_cur_scope->__pyx_v_y * (__pyx_cur_scope->__pyx_v_m[6]))) + (__pyx_cur_scope->__pyx_v_z * (__pyx_cur_scope->__pyx_v_m[10]))); + + /* "ezdxf/acc/matrix44.pyx":625 + * res.y = x * m[1] + y * m[5] + z * m[9] + * res.z = x * m[2] + y * m[6] + z * m[10] + * yield v3_normalize(res, 1.0) if _normalize else res # <<<<<<<<<<<<<< + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: + */ + if (__pyx_cur_scope->__pyx_v__normalize) { + __pyx_t_8 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_cur_scope->__pyx_v_res, 1.0)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 625, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_6 = __pyx_t_8; + __pyx_t_8 = 0; + } else { + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_res); + __pyx_t_6 = ((PyObject *)__pyx_cur_scope->__pyx_v_res); + } + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + __Pyx_XGIVEREF(__pyx_t_3); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_3; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_4; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_5; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_5 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 625, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":616 + * cdef bint _normalize = normalize + * + * for vector in vectors: # <<<<<<<<<<<<<< + * res = Vec3(vector) + * x = res.x + */ + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("transform_directions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":627 + * yield v3_normalize(res, 1.0) if _normalize else res + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: # <<<<<<<<<<<<<< + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs = {"ucs_vertex_from_wcs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_wcs = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("ucs_vertex_from_wcs (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_wcs,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_wcs)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 627, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "ucs_vertex_from_wcs") < 0)) __PYX_ERR(0, 627, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_wcs = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("ucs_vertex_from_wcs", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 627, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs_vertex_from_wcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_wcs), __pyx_ptype_5ezdxf_3acc_6vector_Vec3, 0, "wcs", 0))) __PYX_ERR(0, 627, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_82ucs_vertex_from_wcs(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_wcs); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_82ucs_vertex_from_wcs(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_wcs) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("ucs_vertex_from_wcs", 1); + + /* "ezdxf/acc/matrix44.pyx":628 + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: + * return self.ucs_direction_from_wcs(wcs - self.origin) # <<<<<<<<<<<<<< + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_ucs_direction_from_wcs); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_origin); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyNumber_Subtract(((PyObject *)__pyx_v_wcs), __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 628, __pyx_L1_error) + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":627 + * yield v3_normalize(res, 1.0) if _normalize else res + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: # <<<<<<<<<<<<<< + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs_vertex_from_wcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":630 + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs = {"ucs_direction_from_wcs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_wcs = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("ucs_direction_from_wcs (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_wcs,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_wcs)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 630, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "ucs_direction_from_wcs") < 0)) __PYX_ERR(0, 630, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_wcs = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("ucs_direction_from_wcs", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 630, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs_direction_from_wcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_84ucs_direction_from_wcs(((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)__pyx_v_self), __pyx_v_wcs); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_8matrix44_8Matrix44_84ucs_direction_from_wcs(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *__pyx_v_self, PyObject *__pyx_v_wcs) { + double *__pyx_v_m; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("ucs_direction_from_wcs", 1); + + /* "ezdxf/acc/matrix44.pyx":631 + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: + * cdef double *m = self.m # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(wcs) + * cdef double x = res.x + */ + __pyx_t_1 = __pyx_v_self->m; + __pyx_v_m = __pyx_t_1; + + /* "ezdxf/acc/matrix44.pyx":632 + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) # <<<<<<<<<<<<<< + * cdef double x = res.x + * cdef double y = res.y + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_wcs); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/matrix44.pyx":633 + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) + * cdef double x = res.x # <<<<<<<<<<<<<< + * cdef double y = res.y + * cdef double z = res.z + */ + __pyx_t_3 = __pyx_v_res->x; + __pyx_v_x = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":634 + * cdef Vec3 res = Vec3(wcs) + * cdef double x = res.x + * cdef double y = res.y # <<<<<<<<<<<<<< + * cdef double z = res.z + * + */ + __pyx_t_3 = __pyx_v_res->y; + __pyx_v_y = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":635 + * cdef double x = res.x + * cdef double y = res.y + * cdef double z = res.z # <<<<<<<<<<<<<< + * + * res.x = x * m[0] + y * m[1] + z * m[2] + */ + __pyx_t_3 = __pyx_v_res->z; + __pyx_v_z = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":637 + * cdef double z = res.z + * + * res.x = x * m[0] + y * m[1] + z * m[2] # <<<<<<<<<<<<<< + * res.y = x * m[4] + y * m[5] + z * m[6] + * res.z = x * m[8] + y * m[9] + z * m[10] + */ + __pyx_v_res->x = (((__pyx_v_x * (__pyx_v_m[0])) + (__pyx_v_y * (__pyx_v_m[1]))) + (__pyx_v_z * (__pyx_v_m[2]))); + + /* "ezdxf/acc/matrix44.pyx":638 + * + * res.x = x * m[0] + y * m[1] + z * m[2] + * res.y = x * m[4] + y * m[5] + z * m[6] # <<<<<<<<<<<<<< + * res.z = x * m[8] + y * m[9] + z * m[10] + * return res + */ + __pyx_v_res->y = (((__pyx_v_x * (__pyx_v_m[4])) + (__pyx_v_y * (__pyx_v_m[5]))) + (__pyx_v_z * (__pyx_v_m[6]))); + + /* "ezdxf/acc/matrix44.pyx":639 + * res.x = x * m[0] + y * m[1] + z * m[2] + * res.y = x * m[4] + y * m[5] + z * m[6] + * res.z = x * m[8] + y * m[9] + z * m[10] # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (((__pyx_v_x * (__pyx_v_m[8])) + (__pyx_v_y * (__pyx_v_m[9]))) + (__pyx_v_z * (__pyx_v_m[10]))); + + /* "ezdxf/acc/matrix44.pyx":640 + * res.y = x * m[4] + y * m[5] + z * m[6] + * res.z = x * m[8] + y * m[9] + z * m[10] + * return res # <<<<<<<<<<<<<< + * + * ocs_from_wcs = ucs_direction_from_wcs + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/matrix44.pyx":630 + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.matrix44.Matrix44.ucs_direction_from_wcs", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/matrix44.pyx":647 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef void transform_2d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef double m0 = m[0] + * cdef double m1 = m[1] + */ + +static void __pyx_f_5ezdxf_3acc_8matrix44_transform_2d_array_inplace(double *__pyx_v_m, __Pyx_memviewslice __pyx_v_array, Py_ssize_t __pyx_v_size) { + double __pyx_v_m0; + double __pyx_v_m1; + double __pyx_v_m4; + double __pyx_v_m5; + double __pyx_v_m12; + double __pyx_v_m13; + double __pyx_v_x; + double __pyx_v_y; + Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":648 + * @cython.wraparound(False) + * cdef void transform_2d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): + * cdef double m0 = m[0] # <<<<<<<<<<<<<< + * cdef double m1 = m[1] + * cdef double m4 = m[4] + */ + __pyx_v_m0 = (__pyx_v_m[0]); + + /* "ezdxf/acc/matrix44.pyx":649 + * cdef void transform_2d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): + * cdef double m0 = m[0] + * cdef double m1 = m[1] # <<<<<<<<<<<<<< + * cdef double m4 = m[4] + * cdef double m5 = m[5] + */ + __pyx_v_m1 = (__pyx_v_m[1]); + + /* "ezdxf/acc/matrix44.pyx":650 + * cdef double m0 = m[0] + * cdef double m1 = m[1] + * cdef double m4 = m[4] # <<<<<<<<<<<<<< + * cdef double m5 = m[5] + * cdef double m12 = m[12] + */ + __pyx_v_m4 = (__pyx_v_m[4]); + + /* "ezdxf/acc/matrix44.pyx":651 + * cdef double m1 = m[1] + * cdef double m4 = m[4] + * cdef double m5 = m[5] # <<<<<<<<<<<<<< + * cdef double m12 = m[12] + * cdef double m13 = m[13] + */ + __pyx_v_m5 = (__pyx_v_m[5]); + + /* "ezdxf/acc/matrix44.pyx":652 + * cdef double m4 = m[4] + * cdef double m5 = m[5] + * cdef double m12 = m[12] # <<<<<<<<<<<<<< + * cdef double m13 = m[13] + * cdef double x, y + */ + __pyx_v_m12 = (__pyx_v_m[12]); + + /* "ezdxf/acc/matrix44.pyx":653 + * cdef double m5 = m[5] + * cdef double m12 = m[12] + * cdef double m13 = m[13] # <<<<<<<<<<<<<< + * cdef double x, y + * cdef Py_ssize_t i + */ + __pyx_v_m13 = (__pyx_v_m[13]); + + /* "ezdxf/acc/matrix44.pyx":657 + * cdef Py_ssize_t i + * + * for i in range(size): # <<<<<<<<<<<<<< + * x = array[i, 0] + * y = array[i, 1] + */ + __pyx_t_1 = __pyx_v_size; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":658 + * + * for i in range(size): + * x = array[i, 0] # <<<<<<<<<<<<<< + * y = array[i, 1] + * array[i, 0] = x * m0 + y * m4 + m12 + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_5 = 0; + __pyx_v_x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_4 * __pyx_v_array.strides[0]) )) + __pyx_t_5)) ))); + + /* "ezdxf/acc/matrix44.pyx":659 + * for i in range(size): + * x = array[i, 0] + * y = array[i, 1] # <<<<<<<<<<<<<< + * array[i, 0] = x * m0 + y * m4 + m12 + * array[i, 1] = x * m1 + y * m5 + m13 + */ + __pyx_t_5 = __pyx_v_i; + __pyx_t_4 = 1; + __pyx_v_y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_5 * __pyx_v_array.strides[0]) )) + __pyx_t_4)) ))); + + /* "ezdxf/acc/matrix44.pyx":660 + * x = array[i, 0] + * y = array[i, 1] + * array[i, 0] = x * m0 + y * m4 + m12 # <<<<<<<<<<<<<< + * array[i, 1] = x * m1 + y * m5 + m13 + * + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_5 = 0; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_4 * __pyx_v_array.strides[0]) )) + __pyx_t_5)) )) = (((__pyx_v_x * __pyx_v_m0) + (__pyx_v_y * __pyx_v_m4)) + __pyx_v_m12); + + /* "ezdxf/acc/matrix44.pyx":661 + * y = array[i, 1] + * array[i, 0] = x * m0 + y * m4 + m12 + * array[i, 1] = x * m1 + y * m5 + m13 # <<<<<<<<<<<<<< + * + * @cython.boundscheck(False) + */ + __pyx_t_5 = __pyx_v_i; + __pyx_t_4 = 1; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_5 * __pyx_v_array.strides[0]) )) + __pyx_t_4)) )) = (((__pyx_v_x * __pyx_v_m1) + (__pyx_v_y * __pyx_v_m5)) + __pyx_v_m13); + } + + /* "ezdxf/acc/matrix44.pyx":647 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef void transform_2d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef double m0 = m[0] + * cdef double m1 = m[1] + */ + + /* function exit code */ +} + +/* "ezdxf/acc/matrix44.pyx":665 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef void transform_3d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef double x, y, z + * cdef Py_ssize_t i + */ + +static void __pyx_f_5ezdxf_3acc_8matrix44_transform_3d_array_inplace(double *__pyx_v_m, __Pyx_memviewslice __pyx_v_array, Py_ssize_t __pyx_v_size) { + double __pyx_v_x; + double __pyx_v_y; + double __pyx_v_z; + Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + + /* "ezdxf/acc/matrix44.pyx":669 + * cdef Py_ssize_t i + * + * for i in range(size): # <<<<<<<<<<<<<< + * x = array[i, 0] + * y = array[i, 1] + */ + __pyx_t_1 = __pyx_v_size; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "ezdxf/acc/matrix44.pyx":670 + * + * for i in range(size): + * x = array[i, 0] # <<<<<<<<<<<<<< + * y = array[i, 1] + * z = array[i, 2] + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_5 = 0; + __pyx_v_x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_4 * __pyx_v_array.strides[0]) )) + __pyx_t_5)) ))); + + /* "ezdxf/acc/matrix44.pyx":671 + * for i in range(size): + * x = array[i, 0] + * y = array[i, 1] # <<<<<<<<<<<<<< + * z = array[i, 2] + * + */ + __pyx_t_5 = __pyx_v_i; + __pyx_t_4 = 1; + __pyx_v_y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_5 * __pyx_v_array.strides[0]) )) + __pyx_t_4)) ))); + + /* "ezdxf/acc/matrix44.pyx":672 + * x = array[i, 0] + * y = array[i, 1] + * z = array[i, 2] # <<<<<<<<<<<<<< + * + * array[i, 0] = x * m[0] + y * m[4] + z * m[8] + m[12] + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_5 = 2; + __pyx_v_z = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_4 * __pyx_v_array.strides[0]) )) + __pyx_t_5)) ))); + + /* "ezdxf/acc/matrix44.pyx":674 + * z = array[i, 2] + * + * array[i, 0] = x * m[0] + y * m[4] + z * m[8] + m[12] # <<<<<<<<<<<<<< + * array[i, 1] = x * m[1] + y * m[5] + z * m[9] + m[13] + * array[i, 2] = x * m[2] + y * m[6] + z * m[10] + m[14] + */ + __pyx_t_5 = __pyx_v_i; + __pyx_t_4 = 0; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_5 * __pyx_v_array.strides[0]) )) + __pyx_t_4)) )) = ((((__pyx_v_x * (__pyx_v_m[0])) + (__pyx_v_y * (__pyx_v_m[4]))) + (__pyx_v_z * (__pyx_v_m[8]))) + (__pyx_v_m[12])); + + /* "ezdxf/acc/matrix44.pyx":675 + * + * array[i, 0] = x * m[0] + y * m[4] + z * m[8] + m[12] + * array[i, 1] = x * m[1] + y * m[5] + z * m[9] + m[13] # <<<<<<<<<<<<<< + * array[i, 2] = x * m[2] + y * m[6] + z * m[10] + m[14] + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_5 = 1; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_4 * __pyx_v_array.strides[0]) )) + __pyx_t_5)) )) = ((((__pyx_v_x * (__pyx_v_m[1])) + (__pyx_v_y * (__pyx_v_m[5]))) + (__pyx_v_z * (__pyx_v_m[9]))) + (__pyx_v_m[13])); + + /* "ezdxf/acc/matrix44.pyx":676 + * array[i, 0] = x * m[0] + y * m[4] + z * m[8] + m[12] + * array[i, 1] = x * m[1] + y * m[5] + z * m[9] + m[13] + * array[i, 2] = x * m[2] + y * m[6] + z * m[10] + m[14] # <<<<<<<<<<<<<< + */ + __pyx_t_5 = __pyx_v_i; + __pyx_t_4 = 2; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_5 * __pyx_v_array.strides[0]) )) + __pyx_t_4)) )) = ((((__pyx_v_x * (__pyx_v_m[2])) + (__pyx_v_y * (__pyx_v_m[6]))) + (__pyx_v_z * (__pyx_v_m[10]))) + (__pyx_v_m[14])); + } + + /* "ezdxf/acc/matrix44.pyx":665 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef void transform_3d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef double x, y, z + * cdef Py_ssize_t i + */ + + /* function exit code */ +} +static struct __pyx_vtabstruct_5ezdxf_3acc_8matrix44_Matrix44 __pyx_vtable_5ezdxf_3acc_8matrix44_Matrix44; + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44_Matrix44(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)o); + p->__pyx_vtab = __pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44; + if (unlikely(__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44_Matrix44(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44_Matrix44) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} +static PyObject *__pyx_sq_item_5ezdxf_3acc_8matrix44_Matrix44(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static int __pyx_mp_ass_subscript_5ezdxf_3acc_8matrix44_Matrix44(PyObject *o, PyObject *i, PyObject *v) { + if (v) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_7__setitem__(o, i, v); + } + else { + __Pyx_TypeName o_type_name; + o_type_name = __Pyx_PyType_GetName(Py_TYPE(o)); + PyErr_Format(PyExc_NotImplementedError, + "Subscript deletion not supported by " __Pyx_FMT_TYPENAME, o_type_name); + __Pyx_DECREF_TypeName(o_type_name); + return -1; + } +} + +static CYTHON_INLINE PyObject *__pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44_maybe_call_slot(PyTypeObject* type, PyObject *left, PyObject *right ) { + binaryfunc slot; +#if CYTHON_USE_TYPE_SLOTS || PY_MAJOR_VERSION < 3 || CYTHON_COMPILING_IN_PYPY + slot = type->tp_as_number ? type->tp_as_number->nb_multiply : NULL; +#else + slot = (binaryfunc) PyType_GetSlot(type, Py_nb_multiply); +#endif + return slot ? slot(left, right ) : __Pyx_NewRef(Py_NotImplemented); +} +static PyObject *__pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44(PyObject *left, PyObject *right ) { + int maybe_self_is_left, maybe_self_is_right = 0; + maybe_self_is_left = Py_TYPE(left) == Py_TYPE(right) +#if CYTHON_USE_TYPE_SLOTS + || (Py_TYPE(left)->tp_as_number && Py_TYPE(left)->tp_as_number->nb_multiply == &__pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44) +#endif + || __Pyx_TypeCheck(left, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + if (maybe_self_is_left) { + PyObject *res; + res = __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_56__mul__(left, right); + if (res != Py_NotImplemented) return res; + Py_DECREF(res); + } + maybe_self_is_right = Py_TYPE(left) == Py_TYPE(right) +#if CYTHON_USE_TYPE_SLOTS + || (Py_TYPE(right)->tp_as_number && Py_TYPE(right)->tp_as_number->nb_multiply == &__pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44) +#endif + || PyType_IsSubtype(Py_TYPE(right), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + if (maybe_self_is_right) { + return __pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44_maybe_call_slot(__Pyx_PyType_GetSlot(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, tp_base, PyTypeObject*), left, right ); + } + return __Pyx_NewRef(Py_NotImplemented); +} + + + +#if PY_VERSION_HEX >= 0x03050000 +static CYTHON_INLINE PyObject *__pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44_maybe_call_slot(PyTypeObject* type, PyObject *left, PyObject *right ) { + binaryfunc slot; +#if CYTHON_USE_TYPE_SLOTS || PY_MAJOR_VERSION < 3 || CYTHON_COMPILING_IN_PYPY + slot = type->tp_as_number ? type->tp_as_number->nb_matrix_multiply : NULL; +#else + slot = (binaryfunc) PyType_GetSlot(type, Py_nb_matrix_multiply); +#endif + return slot ? slot(left, right ) : __Pyx_NewRef(Py_NotImplemented); +} +static PyObject *__pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44(PyObject *left, PyObject *right ) { + int maybe_self_is_left, maybe_self_is_right = 0; + maybe_self_is_left = Py_TYPE(left) == Py_TYPE(right) +#if CYTHON_USE_TYPE_SLOTS + || (Py_TYPE(left)->tp_as_number && Py_TYPE(left)->tp_as_number->nb_matrix_multiply == &__pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44) +#endif + || __Pyx_TypeCheck(left, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + if (maybe_self_is_left) { + PyObject *res; + res = __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_58__matmul__(left, right); + if (res != Py_NotImplemented) return res; + Py_DECREF(res); + } + maybe_self_is_right = Py_TYPE(left) == Py_TYPE(right) +#if CYTHON_USE_TYPE_SLOTS + || (Py_TYPE(right)->tp_as_number && Py_TYPE(right)->tp_as_number->nb_matrix_multiply == &__pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44) +#endif + || PyType_IsSubtype(Py_TYPE(right), __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + if (maybe_self_is_right) { + return __pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44_maybe_call_slot(__Pyx_PyType_GetSlot(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, tp_base, PyTypeObject*), left, right ); + } + return __Pyx_NewRef(Py_NotImplemented); +} + + +#endif + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_origin(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_1__get__(o); +} + +static int __pyx_setprop_5ezdxf_3acc_8matrix44_8Matrix44_origin(PyObject *o, PyObject *v, CYTHON_UNUSED void *x) { + if (v) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_6origin_3__set__(o, v); + } + else { + PyErr_SetString(PyExc_NotImplementedError, "__del__"); + return -1; + } +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_ux(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2ux_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_uy(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uy_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_uz(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_2uz_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_is_cartesian(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12is_cartesian_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_is_orthogonal(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_13is_orthogonal_1__get__(o); +} + +static PyObject *__pyx_specialmethod___pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__(self); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_8matrix44_Matrix44[] = { + {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__, METH_NOARGS|METH_COEXIST, 0}, + {"get_2d_transformation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"from_2d_transformation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"get_row", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_18get_row, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"set_row", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_20set_row, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"get_col", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_22get_col, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"set_col", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_24set_col, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"rows", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_26rows, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"columns", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_28columns, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_30copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"scale", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_32scale, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"translate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_34translate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"x_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"y_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"z_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"axis_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"xyz_rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"shear_xy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"perspective_projection", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"perspective_projection_fov", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"chain", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_52chain, METH_VARARGS|METH_KEYWORDS, 0}, + {"transpose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_60transpose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"determinant", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_62determinant, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"inverse", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_64inverse, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"ucs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_66ucs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_68transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform_direction", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform_vertices", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"fast_2d_transform", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"transform_array_inplace", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_8matrix44_8Matrix44_77transform_array_inplace}, + {"transform_directions", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"ucs_vertex_from_wcs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"ucs_direction_from_wcs", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_8matrix44_Matrix44[] = { + {(char *)"origin", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_origin, __pyx_setprop_5ezdxf_3acc_8matrix44_8Matrix44_origin, (char *)0, 0}, + {(char *)"ux", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_ux, 0, (char *)0, 0}, + {(char *)"uy", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_uy, 0, (char *)0, 0}, + {(char *)"uz", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_uz, 0, (char *)0, 0}, + {(char *)"is_cartesian", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_is_cartesian, 0, (char *)0, 0}, + {(char *)"is_orthogonal", __pyx_getprop_5ezdxf_3acc_8matrix44_8Matrix44_is_orthogonal, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44_Matrix44_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_tp_repr, (void *)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__}, + {Py_nb_multiply, (void *)__pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_nb_inplace_multiply, (void *)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_54__imul__}, + #if PY_VERSION_HEX >= 0x03050000 + {Py_nb_matrix_multiply, (void *)__pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44}, + #endif + {Py_sq_item, (void *)__pyx_sq_item_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_mp_subscript, (void *)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_5__getitem__}, + {Py_mp_ass_subscript, (void *)__pyx_mp_ass_subscript_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_tp_iter, (void *)__pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_9__iter__}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_8matrix44_Matrix44}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44_Matrix44}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44_Matrix44_spec = { + "ezdxf.acc.matrix44.Matrix44", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_8matrix44_Matrix44_slots, +}; +#else + +static PyNumberMethods __pyx_tp_as_number_Matrix44 = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + __pyx_nb_multiply_5ezdxf_3acc_8matrix44_Matrix44, /*nb_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_divide*/ + #endif + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + 0, /*nb_bool*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_coerce*/ + #endif + 0, /*nb_int*/ + #if PY_MAJOR_VERSION < 3 + 0, /*nb_long*/ + #else + 0, /*reserved*/ + #endif + 0, /*nb_float*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_oct*/ + #endif + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_hex*/ + #endif + 0, /*nb_inplace_add*/ + 0, /*nb_inplace_subtract*/ + __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_54__imul__, /*nb_inplace_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_inplace_divide*/ + #endif + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + 0, /*nb_inplace_and*/ + 0, /*nb_inplace_xor*/ + 0, /*nb_inplace_or*/ + 0, /*nb_floor_divide*/ + 0, /*nb_true_divide*/ + 0, /*nb_inplace_floor_divide*/ + 0, /*nb_inplace_true_divide*/ + 0, /*nb_index*/ + #if PY_VERSION_HEX >= 0x03050000 + __pyx_nb_matrix_multiply_5ezdxf_3acc_8matrix44_Matrix44, /*nb_matrix_multiply*/ + #endif + #if PY_VERSION_HEX >= 0x03050000 + 0, /*nb_inplace_matrix_multiply*/ + #endif +}; + +static PySequenceMethods __pyx_tp_as_sequence_Matrix44 = { + 0, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_5ezdxf_3acc_8matrix44_Matrix44, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_Matrix44 = { + 0, /*mp_length*/ + __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_5__getitem__, /*mp_subscript*/ + __pyx_mp_ass_subscript_5ezdxf_3acc_8matrix44_Matrix44, /*mp_ass_subscript*/ +}; + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44_Matrix44 = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""Matrix44", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44_Matrix44, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_12__repr__, /*tp_repr*/ + &__pyx_tp_as_number_Matrix44, /*tp_as_number*/ + &__pyx_tp_as_sequence_Matrix44, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_Matrix44, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + __pyx_pw_5ezdxf_3acc_8matrix44_8Matrix44_9__iter__, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_8matrix44_Matrix44, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_8matrix44_Matrix44, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44_Matrix44, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter___slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter___spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct____iter__", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter___slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct____iter__", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_format_row); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)o; + if (p->__pyx_v_format_row) { + e = (*v)(p->__pyx_v_format_row, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ *)o; + tmp = ((PyObject*)p->__pyx_v_format_row); + p->__pyx_v_format_row = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr___slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr___spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_1___repr__", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr___slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_1___repr__", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_value); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr *)o; + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + } + if (p->__pyx_v_value) { + e = (*v)(p->__pyx_v_value, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_2_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_2_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_outer_scope); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_row); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr *)o; + if (p->__pyx_outer_scope) { + e = (*v)(((PyObject *)p->__pyx_outer_scope), a); if (e) return e; + } + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + } + if (p->__pyx_v_row) { + e = (*v)(p->__pyx_v_row, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_3_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_3_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows *)o; + tmp = ((PyObject*)p->__pyx_v_self); + p->__pyx_v_self = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_4_rows", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_4_rows", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_outer_scope); + Py_CLEAR(p->__pyx_v_index); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr *)o; + if (p->__pyx_outer_scope) { + e = (*v)(((PyObject *)p->__pyx_outer_scope), a); if (e) return e; + } + if (p->__pyx_v_index) { + e = (*v)(p->__pyx_v_index, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_5_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_5_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns *)o; + tmp = ((PyObject*)p->__pyx_v_self); + p->__pyx_v_self = ((struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *)Py_None); Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns}, + {Py_tp_clear, (void *)__pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_6_columns", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_6_columns", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns, /*tp_traverse*/ + __pyx_tp_clear_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_outer_scope); + Py_CLEAR(p->__pyx_v_index); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr *)o; + if (p->__pyx_outer_scope) { + e = (*v)(((PyObject *)p->__pyx_outer_scope), a); if (e) return e; + } + if (p->__pyx_v_index) { + e = (*v)(p->__pyx_v_index, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_7_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_7_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_res); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_v_vector); + Py_CLEAR(p->__pyx_v_vectors); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices *)o; + if (p->__pyx_v_res) { + e = (*v)(((PyObject *)p->__pyx_v_res), a); if (e) return e; + } + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_v_vector) { + e = (*v)(p->__pyx_v_vector, a); if (e) return e; + } + if (p->__pyx_v_vectors) { + e = (*v)(p->__pyx_v_vectors, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_8_transform_vertices", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_8_transform_vertices", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_pnt); + Py_CLEAR(p->__pyx_v_points); + Py_CLEAR(p->__pyx_v_res); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform *)o; + if (p->__pyx_v_pnt) { + e = (*v)(p->__pyx_v_pnt, a); if (e) return e; + } + if (p->__pyx_v_points) { + e = (*v)(p->__pyx_v_points, a); if (e) return e; + } + if (p->__pyx_v_res) { + e = (*v)(((PyObject *)p->__pyx_v_res), a); if (e) return e; + } + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_9_fast_2d_transform", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_9_fast_2d_transform", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions[8]; +static int __pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions[--__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_normalize); + Py_CLEAR(p->__pyx_v_res); + Py_CLEAR(p->__pyx_v_self); + Py_CLEAR(p->__pyx_v_vector); + Py_CLEAR(p->__pyx_v_vectors); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions)))) { + __pyx_freelist_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions[__pyx_freecount_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions++] = ((struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *p = (struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions *)o; + if (p->__pyx_v_normalize) { + e = (*v)(p->__pyx_v_normalize, a); if (e) return e; + } + if (p->__pyx_v_res) { + e = (*v)(((PyObject *)p->__pyx_v_res), a); if (e) return e; + } + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + if (p->__pyx_v_vector) { + e = (*v)(p->__pyx_v_vector, a); if (e) return e; + } + if (p->__pyx_v_vectors) { + e = (*v)(p->__pyx_v_vectors, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions_spec = { + "ezdxf.acc.matrix44.__pyx_scope_struct_10_transform_directions", + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""__pyx_scope_struct_10_transform_directions", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_array __pyx_vtable_array; + +static PyObject *__pyx_tp_new_array(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_array_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_array_obj *)o); + p->__pyx_vtab = __pyx_vtabptr_array; + p->mode = ((PyObject*)Py_None); Py_INCREF(Py_None); + p->_format = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_array___cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_array(PyObject *o) { + struct __pyx_array_obj *p = (struct __pyx_array_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_array) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_array___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->mode); + Py_CLEAR(p->_format); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} +static PyObject *__pyx_sq_item_array(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static int __pyx_mp_ass_subscript_array(PyObject *o, PyObject *i, PyObject *v) { + if (v) { + return __pyx_array___setitem__(o, i, v); + } + else { + __Pyx_TypeName o_type_name; + o_type_name = __Pyx_PyType_GetName(Py_TYPE(o)); + PyErr_Format(PyExc_NotImplementedError, + "Subscript deletion not supported by " __Pyx_FMT_TYPENAME, o_type_name); + __Pyx_DECREF_TypeName(o_type_name); + return -1; + } +} + +static PyObject *__pyx_tp_getattro_array(PyObject *o, PyObject *n) { + PyObject *v = __Pyx_PyObject_GenericGetAttr(o, n); + if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + v = __pyx_array___getattr__(o, n); + } + return v; +} + +static PyObject *__pyx_getprop___pyx_array_memview(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(o); +} + +static PyMethodDef __pyx_methods_array[] = { + {"__getattr__", (PyCFunction)__pyx_array___getattr__, METH_O|METH_COEXIST, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_array_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_array_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_array[] = { + {(char *)"memview", __pyx_getprop___pyx_array_memview, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +#if !CYTHON_COMPILING_IN_LIMITED_API + +static PyBufferProcs __pyx_tp_as_buffer_array = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_array_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; +#endif +static PyType_Slot __pyx_type___pyx_array_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_array}, + {Py_sq_length, (void *)__pyx_array___len__}, + {Py_sq_item, (void *)__pyx_sq_item_array}, + {Py_mp_length, (void *)__pyx_array___len__}, + {Py_mp_subscript, (void *)__pyx_array___getitem__}, + {Py_mp_ass_subscript, (void *)__pyx_mp_ass_subscript_array}, + {Py_tp_getattro, (void *)__pyx_tp_getattro_array}, + #if defined(Py_bf_getbuffer) + {Py_bf_getbuffer, (void *)__pyx_array_getbuffer}, + #endif + {Py_tp_methods, (void *)__pyx_methods_array}, + {Py_tp_getset, (void *)__pyx_getsets_array}, + {Py_tp_new, (void *)__pyx_tp_new_array}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_array_spec = { + "ezdxf.acc.matrix44.array", + sizeof(struct __pyx_array_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_SEQUENCE, + __pyx_type___pyx_array_slots, +}; +#else + +static PySequenceMethods __pyx_tp_as_sequence_array = { + __pyx_array___len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_array, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_array = { + __pyx_array___len__, /*mp_length*/ + __pyx_array___getitem__, /*mp_subscript*/ + __pyx_mp_ass_subscript_array, /*mp_ass_subscript*/ +}; + +static PyBufferProcs __pyx_tp_as_buffer_array = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_array_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; + +static PyTypeObject __pyx_type___pyx_array = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""array", /*tp_name*/ + sizeof(struct __pyx_array_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_array, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence_array, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_array, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + __pyx_tp_getattro_array, /*tp_getattro*/ + 0, /*tp_setattro*/ + &__pyx_tp_as_buffer_array, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_SEQUENCE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_array, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_array, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_array, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + struct __pyx_MemviewEnum_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_MemviewEnum_obj *)o); + p->name = Py_None; Py_INCREF(Py_None); + return o; +} + +static void __pyx_tp_dealloc_Enum(PyObject *o) { + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_Enum) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->name); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_Enum(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + if (p->name) { + e = (*v)(p->name, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_Enum(PyObject *o) { + PyObject* tmp; + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + tmp = ((PyObject*)p->name); + p->name = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyObject *__pyx_specialmethod___pyx_MemviewEnum___repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_MemviewEnum___repr__(self); +} + +static PyMethodDef __pyx_methods_Enum[] = { + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_MemviewEnum___repr__, METH_NOARGS|METH_COEXIST, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_MemviewEnum_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_MemviewEnum_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type___pyx_MemviewEnum_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_Enum}, + {Py_tp_repr, (void *)__pyx_MemviewEnum___repr__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_Enum}, + {Py_tp_clear, (void *)__pyx_tp_clear_Enum}, + {Py_tp_methods, (void *)__pyx_methods_Enum}, + {Py_tp_init, (void *)__pyx_MemviewEnum___init__}, + {Py_tp_new, (void *)__pyx_tp_new_Enum}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_MemviewEnum_spec = { + "ezdxf.acc.matrix44.Enum", + sizeof(struct __pyx_MemviewEnum_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type___pyx_MemviewEnum_slots, +}; +#else + +static PyTypeObject __pyx_type___pyx_MemviewEnum = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""Enum", /*tp_name*/ + sizeof(struct __pyx_MemviewEnum_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_Enum, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_MemviewEnum___repr__, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_Enum, /*tp_traverse*/ + __pyx_tp_clear_Enum, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_Enum, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + __pyx_MemviewEnum___init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_Enum, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_memoryview __pyx_vtable_memoryview; + +static PyObject *__pyx_tp_new_memoryview(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_memoryview_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_memoryview_obj *)o); + p->__pyx_vtab = __pyx_vtabptr_memoryview; + p->obj = Py_None; Py_INCREF(Py_None); + p->_size = Py_None; Py_INCREF(Py_None); + p->_array_interface = Py_None; Py_INCREF(Py_None); + p->view.obj = NULL; + if (unlikely(__pyx_memoryview___cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_memoryview(PyObject *o) { + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_memoryview) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_memoryview___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->obj); + Py_CLEAR(p->_size); + Py_CLEAR(p->_array_interface); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_memoryview(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + if (p->obj) { + e = (*v)(p->obj, a); if (e) return e; + } + if (p->_size) { + e = (*v)(p->_size, a); if (e) return e; + } + if (p->_array_interface) { + e = (*v)(p->_array_interface, a); if (e) return e; + } + if (p->view.obj) { + e = (*v)(p->view.obj, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_memoryview(PyObject *o) { + PyObject* tmp; + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + tmp = ((PyObject*)p->obj); + p->obj = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->_size); + p->_size = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->_array_interface); + p->_array_interface = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + Py_CLEAR(p->view.obj); + return 0; +} +static PyObject *__pyx_sq_item_memoryview(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static int __pyx_mp_ass_subscript_memoryview(PyObject *o, PyObject *i, PyObject *v) { + if (v) { + return __pyx_memoryview___setitem__(o, i, v); + } + else { + __Pyx_TypeName o_type_name; + o_type_name = __Pyx_PyType_GetName(Py_TYPE(o)); + PyErr_Format(PyExc_NotImplementedError, + "Subscript deletion not supported by " __Pyx_FMT_TYPENAME, o_type_name); + __Pyx_DECREF_TypeName(o_type_name); + return -1; + } +} + +static PyObject *__pyx_getprop___pyx_memoryview_T(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_base(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_shape(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_strides(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_suboffsets(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_ndim(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_itemsize(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_nbytes(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_size(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(o); +} + +static PyObject *__pyx_specialmethod___pyx_memoryview___repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_memoryview___repr__(self); +} + +static PyMethodDef __pyx_methods_memoryview[] = { + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_memoryview___repr__, METH_NOARGS|METH_COEXIST, 0}, + {"is_c_contig", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_is_c_contig, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"is_f_contig", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_is_f_contig, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"copy_fortran", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_copy_fortran, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryview_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryview_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_memoryview[] = { + {(char *)"T", __pyx_getprop___pyx_memoryview_T, 0, (char *)0, 0}, + {(char *)"base", __pyx_getprop___pyx_memoryview_base, 0, (char *)0, 0}, + {(char *)"shape", __pyx_getprop___pyx_memoryview_shape, 0, (char *)0, 0}, + {(char *)"strides", __pyx_getprop___pyx_memoryview_strides, 0, (char *)0, 0}, + {(char *)"suboffsets", __pyx_getprop___pyx_memoryview_suboffsets, 0, (char *)0, 0}, + {(char *)"ndim", __pyx_getprop___pyx_memoryview_ndim, 0, (char *)0, 0}, + {(char *)"itemsize", __pyx_getprop___pyx_memoryview_itemsize, 0, (char *)0, 0}, + {(char *)"nbytes", __pyx_getprop___pyx_memoryview_nbytes, 0, (char *)0, 0}, + {(char *)"size", __pyx_getprop___pyx_memoryview_size, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +#if !CYTHON_COMPILING_IN_LIMITED_API + +static PyBufferProcs __pyx_tp_as_buffer_memoryview = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_memoryview_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; +#endif +static PyType_Slot __pyx_type___pyx_memoryview_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_memoryview}, + {Py_tp_repr, (void *)__pyx_memoryview___repr__}, + {Py_sq_length, (void *)__pyx_memoryview___len__}, + {Py_sq_item, (void *)__pyx_sq_item_memoryview}, + {Py_mp_length, (void *)__pyx_memoryview___len__}, + {Py_mp_subscript, (void *)__pyx_memoryview___getitem__}, + {Py_mp_ass_subscript, (void *)__pyx_mp_ass_subscript_memoryview}, + {Py_tp_str, (void *)__pyx_memoryview___str__}, + #if defined(Py_bf_getbuffer) + {Py_bf_getbuffer, (void *)__pyx_memoryview_getbuffer}, + #endif + {Py_tp_traverse, (void *)__pyx_tp_traverse_memoryview}, + {Py_tp_clear, (void *)__pyx_tp_clear_memoryview}, + {Py_tp_methods, (void *)__pyx_methods_memoryview}, + {Py_tp_getset, (void *)__pyx_getsets_memoryview}, + {Py_tp_new, (void *)__pyx_tp_new_memoryview}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_memoryview_spec = { + "ezdxf.acc.matrix44.memoryview", + sizeof(struct __pyx_memoryview_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type___pyx_memoryview_slots, +}; +#else + +static PySequenceMethods __pyx_tp_as_sequence_memoryview = { + __pyx_memoryview___len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_memoryview, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_memoryview = { + __pyx_memoryview___len__, /*mp_length*/ + __pyx_memoryview___getitem__, /*mp_subscript*/ + __pyx_mp_ass_subscript_memoryview, /*mp_ass_subscript*/ +}; + +static PyBufferProcs __pyx_tp_as_buffer_memoryview = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_memoryview_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; + +static PyTypeObject __pyx_type___pyx_memoryview = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""memoryview", /*tp_name*/ + sizeof(struct __pyx_memoryview_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_memoryview, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_memoryview___repr__, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence_memoryview, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_memoryview, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_memoryview___str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &__pyx_tp_as_buffer_memoryview, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_memoryview, /*tp_traverse*/ + __pyx_tp_clear_memoryview, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_memoryview, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_memoryview, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_memoryview, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct__memoryviewslice __pyx_vtable__memoryviewslice; + +static PyObject *__pyx_tp_new__memoryviewslice(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_memoryviewslice_obj *p; + PyObject *o = __pyx_tp_new_memoryview(t, a, k); + if (unlikely(!o)) return 0; + p = ((struct __pyx_memoryviewslice_obj *)o); + p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_memoryview*)__pyx_vtabptr__memoryviewslice; + p->from_object = Py_None; Py_INCREF(Py_None); + p->from_slice.memview = NULL; + return o; +} + +static void __pyx_tp_dealloc__memoryviewslice(PyObject *o) { + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc__memoryviewslice) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_memoryviewslice___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->from_object); + PyObject_GC_Track(o); + __pyx_tp_dealloc_memoryview(o); +} + +static int __pyx_tp_traverse__memoryviewslice(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + e = __pyx_tp_traverse_memoryview(o, v, a); if (e) return e; + if (p->from_object) { + e = (*v)(p->from_object, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear__memoryviewslice(PyObject *o) { + PyObject* tmp; + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + __pyx_tp_clear_memoryview(o); + tmp = ((PyObject*)p->from_object); + p->from_object = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + __PYX_XCLEAR_MEMVIEW(&p->from_slice, 1); + return 0; +} + +static PyMethodDef __pyx_methods__memoryviewslice[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryviewslice_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryviewslice_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type___pyx_memoryviewslice_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc__memoryviewslice}, + {Py_tp_doc, (void *)PyDoc_STR("Internal class for passing memoryview slices to Python")}, + {Py_tp_traverse, (void *)__pyx_tp_traverse__memoryviewslice}, + {Py_tp_clear, (void *)__pyx_tp_clear__memoryviewslice}, + {Py_tp_methods, (void *)__pyx_methods__memoryviewslice}, + {Py_tp_new, (void *)__pyx_tp_new__memoryviewslice}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_memoryviewslice_spec = { + "ezdxf.acc.matrix44._memoryviewslice", + sizeof(struct __pyx_memoryviewslice_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_SEQUENCE, + __pyx_type___pyx_memoryviewslice_slots, +}; +#else + +static PyTypeObject __pyx_type___pyx_memoryviewslice = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.matrix44.""_memoryviewslice", /*tp_name*/ + sizeof(struct __pyx_memoryviewslice_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc__memoryviewslice, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + #if CYTHON_COMPILING_IN_PYPY || 0 + __pyx_memoryview___repr__, /*tp_repr*/ + #else + 0, /*tp_repr*/ + #endif + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + #if CYTHON_COMPILING_IN_PYPY || 0 + __pyx_memoryview___str__, /*tp_str*/ + #else + 0, /*tp_str*/ + #endif + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_SEQUENCE, /*tp_flags*/ + PyDoc_STR("Internal class for passing memoryview slices to Python"), /*tp_doc*/ + __pyx_tp_traverse__memoryviewslice, /*tp_traverse*/ + __pyx_tp_clear__memoryviewslice, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods__memoryviewslice, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new__memoryviewslice, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_u_, __pyx_k_, sizeof(__pyx_k_), 0, 1, 0, 0}, + {&__pyx_n_s_ASCII, __pyx_k_ASCII, sizeof(__pyx_k_ASCII), 0, 0, 1, 1}, + {&__pyx_kp_s_All_dimensions_preceding_dimensi, __pyx_k_All_dimensions_preceding_dimensi, sizeof(__pyx_k_All_dimensions_preceding_dimensi), 0, 0, 1, 0}, + {&__pyx_n_s_AssertionError, __pyx_k_AssertionError, sizeof(__pyx_k_AssertionError), 0, 0, 1, 1}, + {&__pyx_kp_s_Buffer_view_does_not_expose_stri, __pyx_k_Buffer_view_does_not_expose_stri, sizeof(__pyx_k_Buffer_view_does_not_expose_stri), 0, 0, 1, 0}, + {&__pyx_kp_s_Can_only_create_a_buffer_that_is, __pyx_k_Can_only_create_a_buffer_that_is, sizeof(__pyx_k_Can_only_create_a_buffer_that_is), 0, 0, 1, 0}, + {&__pyx_kp_s_Cannot_assign_to_read_only_memor, __pyx_k_Cannot_assign_to_read_only_memor, sizeof(__pyx_k_Cannot_assign_to_read_only_memor), 0, 0, 1, 0}, + {&__pyx_kp_s_Cannot_create_writable_memory_vi, __pyx_k_Cannot_create_writable_memory_vi, sizeof(__pyx_k_Cannot_create_writable_memory_vi), 0, 0, 1, 0}, + {&__pyx_kp_u_Cannot_index_with_type, __pyx_k_Cannot_index_with_type, sizeof(__pyx_k_Cannot_index_with_type), 0, 1, 0, 0}, + {&__pyx_kp_s_Cannot_transpose_memoryview_with, __pyx_k_Cannot_transpose_memoryview_with, sizeof(__pyx_k_Cannot_transpose_memoryview_with), 0, 0, 1, 0}, + {&__pyx_kp_s_Dimension_d_is_not_direct, __pyx_k_Dimension_d_is_not_direct, sizeof(__pyx_k_Dimension_d_is_not_direct), 0, 0, 1, 0}, + {&__pyx_n_s_Ellipsis, __pyx_k_Ellipsis, sizeof(__pyx_k_Ellipsis), 0, 0, 1, 1}, + {&__pyx_kp_s_Empty_shape_tuple_for_cython_arr, __pyx_k_Empty_shape_tuple_for_cython_arr, sizeof(__pyx_k_Empty_shape_tuple_for_cython_arr), 0, 0, 1, 0}, + {&__pyx_kp_u_First_2_columns_of_a_3x3_matrix, __pyx_k_First_2_columns_of_a_3x3_matrix, sizeof(__pyx_k_First_2_columns_of_a_3x3_matrix), 0, 1, 0, 0}, + {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_k_Incompatible_checksums_0x_x_vs_0, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0), 0, 0, 1, 0}, + {&__pyx_n_s_IndexError, __pyx_k_IndexError, sizeof(__pyx_k_IndexError), 0, 0, 1, 1}, + {&__pyx_kp_s_Index_out_of_bounds_axis_d, __pyx_k_Index_out_of_bounds_axis_d, sizeof(__pyx_k_Index_out_of_bounds_axis_d), 0, 0, 1, 0}, + {&__pyx_kp_s_Indirect_dimensions_not_supporte, __pyx_k_Indirect_dimensions_not_supporte, sizeof(__pyx_k_Indirect_dimensions_not_supporte), 0, 0, 1, 0}, + {&__pyx_kp_u_Invalid_mode_expected_c_or_fortr, __pyx_k_Invalid_mode_expected_c_or_fortr, sizeof(__pyx_k_Invalid_mode_expected_c_or_fortr), 0, 1, 0, 0}, + {&__pyx_kp_u_Invalid_shape_in_axis, __pyx_k_Invalid_shape_in_axis, sizeof(__pyx_k_Invalid_shape_in_axis), 0, 1, 0, 0}, + {&__pyx_n_s_Iterable, __pyx_k_Iterable, sizeof(__pyx_k_Iterable), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterable_UVec, __pyx_k_Iterable_UVec, sizeof(__pyx_k_Iterable_UVec), 0, 0, 1, 0}, + {&__pyx_n_s_Iterator, __pyx_k_Iterator, sizeof(__pyx_k_Iterator), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterator_Tuple_float, __pyx_k_Iterator_Tuple_float, sizeof(__pyx_k_Iterator_Tuple_float), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterator_Vec2, __pyx_k_Iterator_Vec2, sizeof(__pyx_k_Iterator_Vec2), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterator_Vec3, __pyx_k_Iterator_Vec3, sizeof(__pyx_k_Iterator_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_Matrix44, __pyx_k_Matrix44, sizeof(__pyx_k_Matrix44), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44___iter, __pyx_k_Matrix44___iter, sizeof(__pyx_k_Matrix44___iter), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44___reduce, __pyx_k_Matrix44___reduce, sizeof(__pyx_k_Matrix44___reduce), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_axis_rotate, __pyx_k_Matrix44_axis_rotate, sizeof(__pyx_k_Matrix44_axis_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_chain, __pyx_k_Matrix44_chain, sizeof(__pyx_k_Matrix44_chain), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_columns, __pyx_k_Matrix44_columns, sizeof(__pyx_k_Matrix44_columns), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_copy, __pyx_k_Matrix44_copy, sizeof(__pyx_k_Matrix44_copy), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_determinant, __pyx_k_Matrix44_determinant, sizeof(__pyx_k_Matrix44_determinant), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_fast_2d_transform, __pyx_k_Matrix44_fast_2d_transform, sizeof(__pyx_k_Matrix44_fast_2d_transform), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_from_2d_transformation, __pyx_k_Matrix44_from_2d_transformation, sizeof(__pyx_k_Matrix44_from_2d_transformation), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_get_2d_transformation, __pyx_k_Matrix44_get_2d_transformation, sizeof(__pyx_k_Matrix44_get_2d_transformation), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_get_col, __pyx_k_Matrix44_get_col, sizeof(__pyx_k_Matrix44_get_col), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_get_row, __pyx_k_Matrix44_get_row, sizeof(__pyx_k_Matrix44_get_row), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_inverse, __pyx_k_Matrix44_inverse, sizeof(__pyx_k_Matrix44_inverse), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_perspective_projection, __pyx_k_Matrix44_perspective_projection, sizeof(__pyx_k_Matrix44_perspective_projection), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_perspective_projection_2, __pyx_k_Matrix44_perspective_projection_2, sizeof(__pyx_k_Matrix44_perspective_projection_2), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_rows, __pyx_k_Matrix44_rows, sizeof(__pyx_k_Matrix44_rows), 0, 0, 1, 1}, + {&__pyx_kp_u_Matrix44_s, __pyx_k_Matrix44_s, sizeof(__pyx_k_Matrix44_s), 0, 1, 0, 0}, + {&__pyx_n_s_Matrix44_scale, __pyx_k_Matrix44_scale, sizeof(__pyx_k_Matrix44_scale), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_set_col, __pyx_k_Matrix44_set_col, sizeof(__pyx_k_Matrix44_set_col), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_set_row, __pyx_k_Matrix44_set_row, sizeof(__pyx_k_Matrix44_set_row), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_shear_xy, __pyx_k_Matrix44_shear_xy, sizeof(__pyx_k_Matrix44_shear_xy), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transform, __pyx_k_Matrix44_transform, sizeof(__pyx_k_Matrix44_transform), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transform_array_inplace, __pyx_k_Matrix44_transform_array_inplace, sizeof(__pyx_k_Matrix44_transform_array_inplace), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transform_direction, __pyx_k_Matrix44_transform_direction, sizeof(__pyx_k_Matrix44_transform_direction), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transform_directions, __pyx_k_Matrix44_transform_directions, sizeof(__pyx_k_Matrix44_transform_directions), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transform_vertices, __pyx_k_Matrix44_transform_vertices, sizeof(__pyx_k_Matrix44_transform_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_translate, __pyx_k_Matrix44_translate, sizeof(__pyx_k_Matrix44_translate), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_transpose, __pyx_k_Matrix44_transpose, sizeof(__pyx_k_Matrix44_transpose), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_ucs, __pyx_k_Matrix44_ucs, sizeof(__pyx_k_Matrix44_ucs), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_ucs_direction_from_wcs, __pyx_k_Matrix44_ucs_direction_from_wcs, sizeof(__pyx_k_Matrix44_ucs_direction_from_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_ucs_vertex_from_wcs, __pyx_k_Matrix44_ucs_vertex_from_wcs, sizeof(__pyx_k_Matrix44_ucs_vertex_from_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_x_rotate, __pyx_k_Matrix44_x_rotate, sizeof(__pyx_k_Matrix44_x_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_xyz_rotate, __pyx_k_Matrix44_xyz_rotate, sizeof(__pyx_k_Matrix44_xyz_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_y_rotate, __pyx_k_Matrix44_y_rotate, sizeof(__pyx_k_Matrix44_y_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Matrix44_z_rotate, __pyx_k_Matrix44_z_rotate, sizeof(__pyx_k_Matrix44_z_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_MemoryError, __pyx_k_MemoryError, sizeof(__pyx_k_MemoryError), 0, 0, 1, 1}, + {&__pyx_kp_s_MemoryView_of_r_at_0x_x, __pyx_k_MemoryView_of_r_at_0x_x, sizeof(__pyx_k_MemoryView_of_r_at_0x_x), 0, 0, 1, 0}, + {&__pyx_kp_s_MemoryView_of_r_object, __pyx_k_MemoryView_of_r_object, sizeof(__pyx_k_MemoryView_of_r_object), 0, 0, 1, 0}, + {&__pyx_n_s_NULLVEC, __pyx_k_NULLVEC, sizeof(__pyx_k_NULLVEC), 0, 0, 1, 1}, + {&__pyx_n_s_None, __pyx_k_None, sizeof(__pyx_k_None), 0, 0, 1, 1}, + {&__pyx_n_b_O, __pyx_k_O, sizeof(__pyx_k_O), 0, 0, 0, 1}, + {&__pyx_kp_u_Out_of_bounds_on_buffer_access_a, __pyx_k_Out_of_bounds_on_buffer_access_a, sizeof(__pyx_k_Out_of_bounds_on_buffer_access_a), 0, 1, 0, 0}, + {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_kp_s_Sequence_float, __pyx_k_Sequence_float, sizeof(__pyx_k_Sequence_float), 0, 0, 1, 0}, + {&__pyx_kp_s_Step_may_not_be_zero_axis_d, __pyx_k_Step_may_not_be_zero_axis_d, sizeof(__pyx_k_Step_may_not_be_zero_axis_d), 0, 0, 1, 0}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_n_s_Tuple, __pyx_k_Tuple, sizeof(__pyx_k_Tuple), 0, 0, 1, 1}, + {&__pyx_kp_s_Tuple_float, __pyx_k_Tuple_float, sizeof(__pyx_k_Tuple_float), 0, 0, 1, 0}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_kp_s_Unable_to_convert_item_to_object, __pyx_k_Unable_to_convert_item_to_object, sizeof(__pyx_k_Unable_to_convert_item_to_object), 0, 0, 1, 0}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3, __pyx_k_Vec3, sizeof(__pyx_k_Vec3), 0, 0, 1, 1}, + {&__pyx_n_s_View_MemoryView, __pyx_k_View_MemoryView, sizeof(__pyx_k_View_MemoryView), 0, 0, 1, 1}, + {&__pyx_n_s_X_AXIS, __pyx_k_X_AXIS, sizeof(__pyx_k_X_AXIS), 0, 0, 1, 1}, + {&__pyx_n_s_Y_AXIS, __pyx_k_Y_AXIS, sizeof(__pyx_k_Y_AXIS), 0, 0, 1, 1}, + {&__pyx_n_s_Z_AXIS, __pyx_k_Z_AXIS, sizeof(__pyx_k_Z_AXIS), 0, 0, 1, 1}, + {&__pyx_kp_u__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 1, 0, 0}, + {&__pyx_kp_u__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0, 0}, + {&__pyx_n_s__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 0, 1, 1}, + {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0}, + {&__pyx_kp_u__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 1, 0, 0}, + {&__pyx_n_s__96, __pyx_k__96, sizeof(__pyx_k__96), 0, 0, 1, 1}, + {&__pyx_n_s_abc, __pyx_k_abc, sizeof(__pyx_k_abc), 0, 0, 1, 1}, + {&__pyx_n_s_allocate_buffer, __pyx_k_allocate_buffer, sizeof(__pyx_k_allocate_buffer), 0, 0, 1, 1}, + {&__pyx_kp_u_and, __pyx_k_and, sizeof(__pyx_k_and), 0, 1, 0, 0}, + {&__pyx_n_s_angle, __pyx_k_angle, sizeof(__pyx_k_angle), 0, 0, 1, 1}, + {&__pyx_n_s_angle_x, __pyx_k_angle_x, sizeof(__pyx_k_angle_x), 0, 0, 1, 1}, + {&__pyx_n_s_angle_y, __pyx_k_angle_y, sizeof(__pyx_k_angle_y), 0, 0, 1, 1}, + {&__pyx_n_s_angle_z, __pyx_k_angle_z, sizeof(__pyx_k_angle_z), 0, 0, 1, 1}, + {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1}, + {&__pyx_n_s_array, __pyx_k_array, sizeof(__pyx_k_array), 0, 0, 1, 1}, + {&__pyx_n_s_aspect, __pyx_k_aspect, sizeof(__pyx_k_aspect), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_axis, __pyx_k_axis, sizeof(__pyx_k_axis), 0, 0, 1, 1}, + {&__pyx_n_s_axis_2, __pyx_k_axis_2, sizeof(__pyx_k_axis_2), 0, 0, 1, 1}, + {&__pyx_n_s_axis_rotate, __pyx_k_axis_rotate, sizeof(__pyx_k_axis_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_base, __pyx_k_base, sizeof(__pyx_k_base), 0, 0, 1, 1}, + {&__pyx_n_s_bottom, __pyx_k_bottom, sizeof(__pyx_k_bottom), 0, 0, 1, 1}, + {&__pyx_n_s_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 0, 1, 1}, + {&__pyx_n_u_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 1, 0, 1}, + {&__pyx_n_s_chain, __pyx_k_chain, sizeof(__pyx_k_chain), 0, 0, 1, 1}, + {&__pyx_n_s_class, __pyx_k_class, sizeof(__pyx_k_class), 0, 0, 1, 1}, + {&__pyx_n_s_class_getitem, __pyx_k_class_getitem, sizeof(__pyx_k_class_getitem), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1}, + {&__pyx_n_s_col, __pyx_k_col, sizeof(__pyx_k_col), 0, 0, 1, 1}, + {&__pyx_n_s_collections, __pyx_k_collections, sizeof(__pyx_k_collections), 0, 0, 1, 1}, + {&__pyx_kp_s_collections_abc, __pyx_k_collections_abc, sizeof(__pyx_k_collections_abc), 0, 0, 1, 0}, + {&__pyx_n_s_columns, __pyx_k_columns, sizeof(__pyx_k_columns), 0, 0, 1, 1}, + {&__pyx_n_s_columns_locals_genexpr, __pyx_k_columns_locals_genexpr, sizeof(__pyx_k_columns_locals_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_components, __pyx_k_components, sizeof(__pyx_k_components), 0, 0, 1, 1}, + {&__pyx_kp_s_contiguous_and_direct, __pyx_k_contiguous_and_direct, sizeof(__pyx_k_contiguous_and_direct), 0, 0, 1, 0}, + {&__pyx_kp_s_contiguous_and_indirect, __pyx_k_contiguous_and_indirect, sizeof(__pyx_k_contiguous_and_indirect), 0, 0, 1, 0}, + {&__pyx_n_s_copy, __pyx_k_copy, sizeof(__pyx_k_copy), 0, 0, 1, 1}, + {&__pyx_n_s_copy_2, __pyx_k_copy_2, sizeof(__pyx_k_copy_2), 0, 0, 1, 1}, + {&__pyx_n_s_copy_3, __pyx_k_copy_3, sizeof(__pyx_k_copy_3), 0, 0, 1, 1}, + {&__pyx_n_s_cos_a, __pyx_k_cos_a, sizeof(__pyx_k_cos_a), 0, 0, 1, 1}, + {&__pyx_n_s_count, __pyx_k_count, sizeof(__pyx_k_count), 0, 0, 1, 1}, + {&__pyx_n_s_cx, __pyx_k_cx, sizeof(__pyx_k_cx), 0, 0, 1, 1}, + {&__pyx_n_s_cxsy, __pyx_k_cxsy, sizeof(__pyx_k_cxsy), 0, 0, 1, 1}, + {&__pyx_n_s_cy, __pyx_k_cy, sizeof(__pyx_k_cy), 0, 0, 1, 1}, + {&__pyx_n_s_cz, __pyx_k_cz, sizeof(__pyx_k_cz), 0, 0, 1, 1}, + {&__pyx_n_s_det, __pyx_k_det, sizeof(__pyx_k_det), 0, 0, 1, 1}, + {&__pyx_n_s_determinant, __pyx_k_determinant, sizeof(__pyx_k_determinant), 0, 0, 1, 1}, + {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_dtype_is_object, __pyx_k_dtype_is_object, sizeof(__pyx_k_dtype_is_object), 0, 0, 1, 1}, + {&__pyx_n_s_dx, __pyx_k_dx, sizeof(__pyx_k_dx), 0, 0, 1, 1}, + {&__pyx_n_s_dy, __pyx_k_dy, sizeof(__pyx_k_dy), 0, 0, 1, 1}, + {&__pyx_n_s_dz, __pyx_k_dz, sizeof(__pyx_k_dz), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1}, + {&__pyx_n_s_enumerate, __pyx_k_enumerate, sizeof(__pyx_k_enumerate), 0, 0, 1, 1}, + {&__pyx_n_s_error, __pyx_k_error, sizeof(__pyx_k_error), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_matrix44, __pyx_k_ezdxf_acc_matrix44, sizeof(__pyx_k_ezdxf_acc_matrix44), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_n_s_f, __pyx_k_f, sizeof(__pyx_k_f), 0, 0, 1, 1}, + {&__pyx_n_s_far, __pyx_k_far, sizeof(__pyx_k_far), 0, 0, 1, 1}, + {&__pyx_n_s_fast_2d_transform, __pyx_k_fast_2d_transform, sizeof(__pyx_k_fast_2d_transform), 0, 0, 1, 1}, + {&__pyx_n_s_flags, __pyx_k_flags, sizeof(__pyx_k_flags), 0, 0, 1, 1}, + {&__pyx_n_s_float, __pyx_k_float, sizeof(__pyx_k_float), 0, 0, 1, 1}, + {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1}, + {&__pyx_n_s_format_row, __pyx_k_format_row, sizeof(__pyx_k_format_row), 0, 0, 1, 1}, + {&__pyx_n_s_fortran, __pyx_k_fortran, sizeof(__pyx_k_fortran), 0, 0, 1, 1}, + {&__pyx_n_u_fortran, __pyx_k_fortran, sizeof(__pyx_k_fortran), 0, 1, 0, 1}, + {&__pyx_n_s_fov, __pyx_k_fov, sizeof(__pyx_k_fov), 0, 0, 1, 1}, + {&__pyx_n_s_from_2d_transformation, __pyx_k_from_2d_transformation, sizeof(__pyx_k_from_2d_transformation), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_genexpr, __pyx_k_genexpr, sizeof(__pyx_k_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_get_2d_transformation, __pyx_k_get_2d_transformation, sizeof(__pyx_k_get_2d_transformation), 0, 0, 1, 1}, + {&__pyx_n_s_get_col, __pyx_k_get_col, sizeof(__pyx_k_get_col), 0, 0, 1, 1}, + {&__pyx_n_s_get_row, __pyx_k_get_row, sizeof(__pyx_k_get_row), 0, 0, 1, 1}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_kp_u_got, __pyx_k_got, sizeof(__pyx_k_got), 0, 1, 0, 0}, + {&__pyx_kp_u_got_differing_extents_in_dimensi, __pyx_k_got_differing_extents_in_dimensi, sizeof(__pyx_k_got_differing_extents_in_dimensi), 0, 1, 0, 0}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_id, __pyx_k_id, sizeof(__pyx_k_id), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_imul, __pyx_k_imul, sizeof(__pyx_k_imul), 0, 0, 1, 1}, + {&__pyx_n_s_index, __pyx_k_index, sizeof(__pyx_k_index), 0, 0, 1, 1}, + {&__pyx_kp_u_index_out_of_range, __pyx_k_index_out_of_range, sizeof(__pyx_k_index_out_of_range), 0, 1, 0, 0}, + {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_kp_u_invalid_argument_count, __pyx_k_invalid_argument_count, sizeof(__pyx_k_invalid_argument_count), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_argument_count_4_row_vec, __pyx_k_invalid_argument_count_4_row_vec, sizeof(__pyx_k_invalid_argument_count_4_row_vec), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_col_index, __pyx_k_invalid_col_index, sizeof(__pyx_k_invalid_col_index), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_row_index, __pyx_k_invalid_row_index, sizeof(__pyx_k_invalid_row_index), 0, 1, 0, 0}, + {&__pyx_n_s_inverse, __pyx_k_inverse, sizeof(__pyx_k_inverse), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_itemsize, __pyx_k_itemsize, sizeof(__pyx_k_itemsize), 0, 0, 1, 1}, + {&__pyx_kp_s_itemsize_0_for_cython_array, __pyx_k_itemsize_0_for_cython_array, sizeof(__pyx_k_itemsize_0_for_cython_array), 0, 0, 1, 0}, + {&__pyx_n_s_iter, __pyx_k_iter, sizeof(__pyx_k_iter), 0, 0, 1, 1}, + {&__pyx_n_s_itertools, __pyx_k_itertools, sizeof(__pyx_k_itertools), 0, 0, 1, 1}, + {&__pyx_n_s_left, __pyx_k_left, sizeof(__pyx_k_left), 0, 0, 1, 1}, + {&__pyx_n_s_m, __pyx_k_m, sizeof(__pyx_k_m), 0, 0, 1, 1}, + {&__pyx_n_s_m0, __pyx_k_m0, sizeof(__pyx_k_m0), 0, 0, 1, 1}, + {&__pyx_n_s_m1, __pyx_k_m1, sizeof(__pyx_k_m1), 0, 0, 1, 1}, + {&__pyx_n_s_m12, __pyx_k_m12, sizeof(__pyx_k_m12), 0, 0, 1, 1}, + {&__pyx_n_s_m13, __pyx_k_m13, sizeof(__pyx_k_m13), 0, 0, 1, 1}, + {&__pyx_n_s_m4, __pyx_k_m4, sizeof(__pyx_k_m4), 0, 0, 1, 1}, + {&__pyx_n_s_m44, __pyx_k_m44, sizeof(__pyx_k_m44), 0, 0, 1, 1}, + {&__pyx_n_s_m5, __pyx_k_m5, sizeof(__pyx_k_m5), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_mat, __pyx_k_mat, sizeof(__pyx_k_mat), 0, 0, 1, 1}, + {&__pyx_n_s_math, __pyx_k_math, sizeof(__pyx_k_math), 0, 0, 1, 1}, + {&__pyx_n_s_matrices, __pyx_k_matrices, sizeof(__pyx_k_matrices), 0, 0, 1, 1}, + {&__pyx_n_s_matrix, __pyx_k_matrix, sizeof(__pyx_k_matrix), 0, 0, 1, 1}, + {&__pyx_n_s_memview, __pyx_k_memview, sizeof(__pyx_k_memview), 0, 0, 1, 1}, + {&__pyx_n_s_mode, __pyx_k_mode, sizeof(__pyx_k_mode), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, + {&__pyx_n_s_ndim, __pyx_k_ndim, sizeof(__pyx_k_ndim), 0, 0, 1, 1}, + {&__pyx_n_s_ndim_2, __pyx_k_ndim_2, sizeof(__pyx_k_ndim_2), 0, 0, 1, 1}, + {&__pyx_kp_u_ndim_has_to_be_2_or_3, __pyx_k_ndim_has_to_be_2_or_3, sizeof(__pyx_k_ndim_has_to_be_2_or_3), 0, 1, 0, 0}, + {&__pyx_n_s_near, __pyx_k_near, sizeof(__pyx_k_near), 0, 0, 1, 1}, + {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_normalize, __pyx_k_normalize, sizeof(__pyx_k_normalize), 0, 0, 1, 1}, + {&__pyx_n_s_normalize_2, __pyx_k_normalize_2, sizeof(__pyx_k_normalize_2), 0, 0, 1, 1}, + {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, + {&__pyx_kp_s_np_ndarray, __pyx_k_np_ndarray, sizeof(__pyx_k_np_ndarray), 0, 0, 1, 0}, + {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, + {&__pyx_n_s_obj, __pyx_k_obj, sizeof(__pyx_k_obj), 0, 0, 1, 1}, + {&__pyx_n_s_ocs_from_wcs, __pyx_k_ocs_from_wcs, sizeof(__pyx_k_ocs_from_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_ocs_to_wcs, __pyx_k_ocs_to_wcs, sizeof(__pyx_k_ocs_to_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_one_m_cos, __pyx_k_one_m_cos, sizeof(__pyx_k_one_m_cos), 0, 0, 1, 1}, + {&__pyx_n_s_origin, __pyx_k_origin, sizeof(__pyx_k_origin), 0, 0, 1, 1}, + {&__pyx_n_s_origin_2, __pyx_k_origin_2, sizeof(__pyx_k_origin_2), 0, 0, 1, 1}, + {&__pyx_n_s_pack, __pyx_k_pack, sizeof(__pyx_k_pack), 0, 0, 1, 1}, + {&__pyx_n_s_perspective_projection, __pyx_k_perspective_projection, sizeof(__pyx_k_perspective_projection), 0, 0, 1, 1}, + {&__pyx_n_s_perspective_projection_fov, __pyx_k_perspective_projection_fov, sizeof(__pyx_k_perspective_projection_fov), 0, 0, 1, 1}, + {&__pyx_n_s_pickle, __pyx_k_pickle, sizeof(__pyx_k_pickle), 0, 0, 1, 1}, + {&__pyx_n_s_pnt, __pyx_k_pnt, sizeof(__pyx_k_pnt), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_PickleError, __pyx_k_pyx_PickleError, sizeof(__pyx_k_pyx_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_checksum, __pyx_k_pyx_checksum, sizeof(__pyx_k_pyx_checksum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_result, __pyx_k_pyx_result, sizeof(__pyx_k_pyx_result), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_type, __pyx_k_pyx_type, sizeof(__pyx_k_pyx_type), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_unpickle_Enum, __pyx_k_pyx_unpickle_Enum, sizeof(__pyx_k_pyx_unpickle_Enum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_register, __pyx_k_register, sizeof(__pyx_k_register), 0, 0, 1, 1}, + {&__pyx_n_s_repr___locals_format_row, __pyx_k_repr___locals_format_row, sizeof(__pyx_k_repr___locals_format_row), 0, 0, 1, 1}, + {&__pyx_n_s_repr___locals_format_row_local, __pyx_k_repr___locals_format_row_local, sizeof(__pyx_k_repr___locals_format_row_local), 0, 0, 1, 1}, + {&__pyx_n_s_repr___locals_genexpr, __pyx_k_repr___locals_genexpr, sizeof(__pyx_k_repr___locals_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_right, __pyx_k_right, sizeof(__pyx_k_right), 0, 0, 1, 1}, + {&__pyx_n_s_row, __pyx_k_row, sizeof(__pyx_k_row), 0, 0, 1, 1}, + {&__pyx_n_s_rows, __pyx_k_rows, sizeof(__pyx_k_rows), 0, 0, 1, 1}, + {&__pyx_n_s_rows_locals_genexpr, __pyx_k_rows_locals_genexpr, sizeof(__pyx_k_rows_locals_genexpr), 0, 0, 1, 1}, + {&__pyx_kp_u_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 1, 0, 0}, + {&__pyx_n_s_scale, __pyx_k_scale, sizeof(__pyx_k_scale), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1}, + {&__pyx_n_s_set_col, __pyx_k_set_col, sizeof(__pyx_k_set_col), 0, 0, 1, 1}, + {&__pyx_n_s_set_row, __pyx_k_set_row, sizeof(__pyx_k_set_row), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1}, + {&__pyx_n_s_shear_xy, __pyx_k_shear_xy, sizeof(__pyx_k_shear_xy), 0, 0, 1, 1}, + {&__pyx_n_s_sin_a, __pyx_k_sin_a, sizeof(__pyx_k_sin_a), 0, 0, 1, 1}, + {&__pyx_n_s_size, __pyx_k_size, sizeof(__pyx_k_size), 0, 0, 1, 1}, + {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_k_src_ezdxf_acc_matrix44_pyx, sizeof(__pyx_k_src_ezdxf_acc_matrix44_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1}, + {&__pyx_n_s_staticmethod, __pyx_k_staticmethod, sizeof(__pyx_k_staticmethod), 0, 0, 1, 1}, + {&__pyx_n_s_step, __pyx_k_step, sizeof(__pyx_k_step), 0, 0, 1, 1}, + {&__pyx_n_s_stop, __pyx_k_stop, sizeof(__pyx_k_stop), 0, 0, 1, 1}, + {&__pyx_kp_s_strided_and_direct, __pyx_k_strided_and_direct, sizeof(__pyx_k_strided_and_direct), 0, 0, 1, 0}, + {&__pyx_kp_s_strided_and_direct_or_indirect, __pyx_k_strided_and_direct_or_indirect, sizeof(__pyx_k_strided_and_direct_or_indirect), 0, 0, 1, 0}, + {&__pyx_kp_s_strided_and_indirect, __pyx_k_strided_and_indirect, sizeof(__pyx_k_strided_and_indirect), 0, 0, 1, 0}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_struct, __pyx_k_struct, sizeof(__pyx_k_struct), 0, 0, 1, 1}, + {&__pyx_n_s_sx, __pyx_k_sx, sizeof(__pyx_k_sx), 0, 0, 1, 1}, + {&__pyx_n_s_sxsy, __pyx_k_sxsy, sizeof(__pyx_k_sxsy), 0, 0, 1, 1}, + {&__pyx_n_s_sy, __pyx_k_sy, sizeof(__pyx_k_sy), 0, 0, 1, 1}, + {&__pyx_n_s_sys, __pyx_k_sys, sizeof(__pyx_k_sys), 0, 0, 1, 1}, + {&__pyx_n_s_sz, __pyx_k_sz, sizeof(__pyx_k_sz), 0, 0, 1, 1}, + {&__pyx_n_s_tan, __pyx_k_tan, sizeof(__pyx_k_tan), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1}, + {&__pyx_n_s_top, __pyx_k_top, sizeof(__pyx_k_top), 0, 0, 1, 1}, + {&__pyx_n_s_transform, __pyx_k_transform, sizeof(__pyx_k_transform), 0, 0, 1, 1}, + {&__pyx_n_s_transform_array_inplace, __pyx_k_transform_array_inplace, sizeof(__pyx_k_transform_array_inplace), 0, 0, 1, 1}, + {&__pyx_n_s_transform_direction, __pyx_k_transform_direction, sizeof(__pyx_k_transform_direction), 0, 0, 1, 1}, + {&__pyx_n_s_transform_directions, __pyx_k_transform_directions, sizeof(__pyx_k_transform_directions), 0, 0, 1, 1}, + {&__pyx_n_s_transform_vertices, __pyx_k_transform_vertices, sizeof(__pyx_k_transform_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_transformation, __pyx_k_transformation, sizeof(__pyx_k_transformation), 0, 0, 1, 1}, + {&__pyx_n_s_translate, __pyx_k_translate, sizeof(__pyx_k_translate), 0, 0, 1, 1}, + {&__pyx_n_s_transpose, __pyx_k_transpose, sizeof(__pyx_k_transpose), 0, 0, 1, 1}, + {&__pyx_n_s_tx, __pyx_k_tx, sizeof(__pyx_k_tx), 0, 0, 1, 1}, + {&__pyx_n_s_ty, __pyx_k_ty, sizeof(__pyx_k_ty), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_ucs, __pyx_k_ucs, sizeof(__pyx_k_ucs), 0, 0, 1, 1}, + {&__pyx_n_s_ucs_direction_from_wcs, __pyx_k_ucs_direction_from_wcs, sizeof(__pyx_k_ucs_direction_from_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_ucs_vertex_from_wcs, __pyx_k_ucs_vertex_from_wcs, sizeof(__pyx_k_ucs_vertex_from_wcs), 0, 0, 1, 1}, + {&__pyx_kp_s_unable_to_allocate_array_data, __pyx_k_unable_to_allocate_array_data, sizeof(__pyx_k_unable_to_allocate_array_data), 0, 0, 1, 0}, + {&__pyx_kp_s_unable_to_allocate_shape_and_str, __pyx_k_unable_to_allocate_shape_and_str, sizeof(__pyx_k_unable_to_allocate_shape_and_str), 0, 0, 1, 0}, + {&__pyx_n_s_unpack, __pyx_k_unpack, sizeof(__pyx_k_unpack), 0, 0, 1, 1}, + {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, + {&__pyx_n_s_ux, __pyx_k_ux, sizeof(__pyx_k_ux), 0, 0, 1, 1}, + {&__pyx_n_s_ux_2, __pyx_k_ux_2, sizeof(__pyx_k_ux_2), 0, 0, 1, 1}, + {&__pyx_n_s_uy, __pyx_k_uy, sizeof(__pyx_k_uy), 0, 0, 1, 1}, + {&__pyx_n_s_uy_2, __pyx_k_uy_2, sizeof(__pyx_k_uy_2), 0, 0, 1, 1}, + {&__pyx_n_s_uz, __pyx_k_uz, sizeof(__pyx_k_uz), 0, 0, 1, 1}, + {&__pyx_n_s_uz_2, __pyx_k_uz_2, sizeof(__pyx_k_uz_2), 0, 0, 1, 1}, + {&__pyx_n_s_values, __pyx_k_values, sizeof(__pyx_k_values), 0, 0, 1, 1}, + {&__pyx_n_s_vector, __pyx_k_vector, sizeof(__pyx_k_vector), 0, 0, 1, 1}, + {&__pyx_n_s_vectors, __pyx_k_vectors, sizeof(__pyx_k_vectors), 0, 0, 1, 1}, + {&__pyx_n_s_version_info, __pyx_k_version_info, sizeof(__pyx_k_version_info), 0, 0, 1, 1}, + {&__pyx_n_s_vrange, __pyx_k_vrange, sizeof(__pyx_k_vrange), 0, 0, 1, 1}, + {&__pyx_n_s_wcs, __pyx_k_wcs, sizeof(__pyx_k_wcs), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_x_rotate, __pyx_k_x_rotate, sizeof(__pyx_k_x_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_xyz_rotate, __pyx_k_xyz_rotate, sizeof(__pyx_k_xyz_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {&__pyx_n_s_y_rotate, __pyx_k_y_rotate, sizeof(__pyx_k_y_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_z, __pyx_k_z, sizeof(__pyx_k_z), 0, 0, 1, 1}, + {&__pyx_n_s_z_rotate, __pyx_k_z_rotate, sizeof(__pyx_k_z_rotate), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_staticmethod = __Pyx_GetBuiltinName(__pyx_n_s_staticmethod); if (!__pyx_builtin_staticmethod) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 38, __pyx_L1_error) + __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) __PYX_ERR(0, 64, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 78, __pyx_L1_error) + __pyx_builtin_AssertionError = __Pyx_GetBuiltinName(__pyx_n_s_AssertionError); if (!__pyx_builtin_AssertionError) __PYX_ERR(0, 599, __pyx_L1_error) + __pyx_builtin___import__ = __Pyx_GetBuiltinName(__pyx_n_s_import); if (!__pyx_builtin___import__) __PYX_ERR(1, 100, __pyx_L1_error) + __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(1, 156, __pyx_L1_error) + __pyx_builtin_enumerate = __Pyx_GetBuiltinName(__pyx_n_s_enumerate); if (!__pyx_builtin_enumerate) __PYX_ERR(1, 159, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + __pyx_builtin_Ellipsis = __Pyx_GetBuiltinName(__pyx_n_s_Ellipsis); if (!__pyx_builtin_Ellipsis) __PYX_ERR(1, 408, __pyx_L1_error) + __pyx_builtin_id = __Pyx_GetBuiltinName(__pyx_n_s_id); if (!__pyx_builtin_id) __PYX_ERR(1, 618, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "View.MemoryView":582 + * def suboffsets(self): + * if self.view.suboffsets == NULL: + * return (-1,) * self.view.ndim # <<<<<<<<<<<<<< + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + */ + __pyx_tuple__4 = PyTuple_New(1); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_INCREF(__pyx_int_neg_1); + __Pyx_GIVEREF(__pyx_int_neg_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_tuple__4, 0, __pyx_int_neg_1)) __PYX_ERR(1, 582, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "View.MemoryView":679 + * tup = index if isinstance(index, tuple) else (index,) + * + * result = [slice(None)] * ndim # <<<<<<<<<<<<<< + * have_slices = False + * seen_ellipsis = False + */ + __pyx_slice__5 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__5)) __PYX_ERR(1, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__5); + __Pyx_GIVEREF(__pyx_slice__5); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + __pyx_tuple__8 = PyTuple_Pack(3, __pyx_int_136983863, __pyx_int_112105877, __pyx_int_184977713); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "ezdxf/acc/matrix44.pyx":38 + * i += 1 + * if i != 16: + * raise ValueError("invalid argument count") # <<<<<<<<<<<<<< + * + * cdef class Matrix44: + */ + __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_u_invalid_argument_count); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + + /* "ezdxf/acc/matrix44.pyx":50 + * set_floats(self.m, chain(*args)) + * else: + * raise ValueError("invalid argument count: 4 row vectors or " # <<<<<<<<<<<<<< + * "iterable of 16 numbers") + * + */ + __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_u_invalid_argument_count_4_row_vec); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + + /* "ezdxf/acc/matrix44.pyx":82 + * + * def __repr__(self) -> str: + * def format_row(row): # <<<<<<<<<<<<<< + * return "(%s)" % ", ".join(str(value) for value in row) + * + */ + __pyx_tuple__12 = PyTuple_Pack(3, __pyx_n_s_row, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_format_row, 82, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 82, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":95 + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + * raise ValueError( # <<<<<<<<<<<<<< + * "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + * ) + */ + __pyx_tuple__14 = PyTuple_Pack(1, __pyx_kp_u_First_2_columns_of_a_3x3_matrix); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + + /* "ezdxf/acc/matrix44.pyx":147 + * + * def rows(self) -> Iterator[Tuple[float, ...]]: + * return (self.get_row(index) for index in (0, 1, 2, 3)) # <<<<<<<<<<<<<< + * + * def columns(self) -> Iterator[Tuple[float, ...]]: + */ + __pyx_tuple__15 = PyTuple_Pack(4, __pyx_int_0, __pyx_int_1, __pyx_int_2, __pyx_int_3); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + + /* "ezdxf/acc/matrix44.pyx":605 + * transform_3d_array_inplace(self.m, array, array.shape[0]) + * else: + * raise ValueError("ndim has to be 2 or 3") # <<<<<<<<<<<<<< + * + * + */ + __pyx_tuple__22 = PyTuple_Pack(1, __pyx_kp_u_ndim_has_to_be_2_or_3); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 605, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + __pyx_tuple__24 = PyTuple_Pack(1, __pyx_n_s_sys); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__24); + __Pyx_GIVEREF(__pyx_tuple__24); + __pyx_tuple__25 = PyTuple_Pack(2, __pyx_int_3, __pyx_int_3); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__25); + __Pyx_GIVEREF(__pyx_tuple__25); + + /* "View.MemoryView":101 + * try: + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence # <<<<<<<<<<<<<< + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + */ + __pyx_tuple__26 = PyTuple_Pack(1, __pyx_kp_s_collections_abc); if (unlikely(!__pyx_tuple__26)) __PYX_ERR(1, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__26); + __Pyx_GIVEREF(__pyx_tuple__26); + + /* "View.MemoryView":103 + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence # <<<<<<<<<<<<<< + * except: + * + */ + __pyx_tuple__27 = PyTuple_Pack(1, __pyx_n_s_collections); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(1, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + + /* "View.MemoryView":309 + * return self.name + * + * cdef generic = Enum("") # <<<<<<<<<<<<<< + * cdef strided = Enum("") # default + * cdef indirect = Enum("") + */ + __pyx_tuple__28 = PyTuple_Pack(1, __pyx_kp_s_strided_and_direct_or_indirect); if (unlikely(!__pyx_tuple__28)) __PYX_ERR(1, 309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__28); + __Pyx_GIVEREF(__pyx_tuple__28); + + /* "View.MemoryView":310 + * + * cdef generic = Enum("") + * cdef strided = Enum("") # default # <<<<<<<<<<<<<< + * cdef indirect = Enum("") + * + */ + __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_s_strided_and_direct); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(1, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__29); + __Pyx_GIVEREF(__pyx_tuple__29); + + /* "View.MemoryView":311 + * cdef generic = Enum("") + * cdef strided = Enum("") # default + * cdef indirect = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_tuple__30 = PyTuple_Pack(1, __pyx_kp_s_strided_and_indirect); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__30); + __Pyx_GIVEREF(__pyx_tuple__30); + + /* "View.MemoryView":314 + * + * + * cdef contiguous = Enum("") # <<<<<<<<<<<<<< + * cdef indirect_contiguous = Enum("") + * + */ + __pyx_tuple__31 = PyTuple_Pack(1, __pyx_kp_s_contiguous_and_direct); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(1, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__31); + __Pyx_GIVEREF(__pyx_tuple__31); + + /* "View.MemoryView":315 + * + * cdef contiguous = Enum("") + * cdef indirect_contiguous = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_tuple__32 = PyTuple_Pack(1, __pyx_kp_s_contiguous_and_indirect); if (unlikely(!__pyx_tuple__32)) __PYX_ERR(1, 315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__32); + __Pyx_GIVEREF(__pyx_tuple__32); + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_tuple__33 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__33); + __Pyx_GIVEREF(__pyx_tuple__33); + __pyx_codeobj__34 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle_Enum, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__34)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":53 + * "iterable of 16 numbers") + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Matrix44, (tuple(self),) + * + */ + __pyx_tuple__35 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__35); + __Pyx_GIVEREF(__pyx_tuple__35); + __pyx_codeobj__36 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_reduce, 53, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__36)) __PYX_ERR(0, 53, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":88 + * ", ".join(format_row(row) for row in self.rows()) + * + * def get_2d_transformation(self) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + */ + __pyx_tuple__37 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_m); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__37); + __Pyx_GIVEREF(__pyx_tuple__37); + __pyx_codeobj__38 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__37, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_get_2d_transformation, 88, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__38)) __PYX_ERR(0, 88, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":92 + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + */ + __pyx_tuple__39 = PyTuple_Pack(2, __pyx_n_s_components, __pyx_n_s_m44); if (unlikely(!__pyx_tuple__39)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__39); + __Pyx_GIVEREF(__pyx_tuple__39); + __pyx_codeobj__40 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__39, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_from_2d_transformation, 92, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__40)) __PYX_ERR(0, 92, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":108 + * return m44 + * + * def get_row(self, int row) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef int index = row * 4 + * if 0 <= index < 13: + */ + __pyx_tuple__41 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_row, __pyx_n_s_index); if (unlikely(!__pyx_tuple__41)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__41); + __Pyx_GIVEREF(__pyx_tuple__41); + __pyx_codeobj__42 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__41, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_get_row, 108, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__42)) __PYX_ERR(0, 108, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":116 + * raise IndexError(f'invalid row index: {row}') + * + * def set_row(self, int row, values: Sequence[float]) -> None: # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t start = row * 4 + */ + __pyx_tuple__43 = PyTuple_Pack(6, __pyx_n_s_self, __pyx_n_s_row, __pyx_n_s_values, __pyx_n_s_count, __pyx_n_s_start, __pyx_n_s_i); if (unlikely(!__pyx_tuple__43)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__43); + __Pyx_GIVEREF(__pyx_tuple__43); + __pyx_codeobj__44 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_set_row, 116, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__44)) __PYX_ERR(0, 116, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":128 + * raise IndexError(f'invalid row index: {row}') + * + * def get_col(self, int col) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ + */ + __pyx_tuple__45 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_col); if (unlikely(!__pyx_tuple__45)) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__45); + __Pyx_GIVEREF(__pyx_tuple__45); + __pyx_codeobj__46 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__45, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_get_col, 128, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__46)) __PYX_ERR(0, 128, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":135 + * raise IndexError(f'invalid col index: {col}') + * + * def set_col(self, int col, values: Sequence[float]): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + */ + __pyx_tuple__47 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_col, __pyx_n_s_values, __pyx_n_s_count, __pyx_n_s_i); if (unlikely(!__pyx_tuple__47)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__47); + __Pyx_GIVEREF(__pyx_tuple__47); + __pyx_codeobj__48 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__47, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_set_col, 135, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__48)) __PYX_ERR(0, 135, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ + __pyx_tuple__49 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__49)) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__49); + __Pyx_GIVEREF(__pyx_tuple__49); + __pyx_codeobj__50 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__49, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_rows, 146, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__50)) __PYX_ERR(0, 146, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ + __pyx_codeobj__51 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__49, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_columns, 149, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__51)) __PYX_ERR(0, 149, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":152 + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + * def copy(self) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m + */ + __pyx_tuple__52 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_copy_2); if (unlikely(!__pyx_tuple__52)) __PYX_ERR(0, 152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__52); + __Pyx_GIVEREF(__pyx_tuple__52); + __pyx_codeobj__53 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__52, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_copy, 152, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__53)) __PYX_ERR(0, 152, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":221 + * fabs(v3_dot(uy, uz)) < 1e-9 + * + * @staticmethod # <<<<<<<<<<<<<< + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__54 = PyTuple_Pack(4, __pyx_n_s_sx, __pyx_n_s_sy, __pyx_n_s_sz, __pyx_n_s_mat); if (unlikely(!__pyx_tuple__54)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__54); + __Pyx_GIVEREF(__pyx_tuple__54); + __pyx_codeobj__55 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__54, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_scale, 221, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__55)) __PYX_ERR(0, 221, __pyx_L1_error) + __pyx_tuple__56 = PyTuple_Pack(2, Py_None, Py_None); if (unlikely(!__pyx_tuple__56)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__56); + __Pyx_GIVEREF(__pyx_tuple__56); + + /* "ezdxf/acc/matrix44.pyx":229 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__57 = PyTuple_Pack(4, __pyx_n_s_dx, __pyx_n_s_dy, __pyx_n_s_dz, __pyx_n_s_mat); if (unlikely(!__pyx_tuple__57)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__57); + __Pyx_GIVEREF(__pyx_tuple__57); + __pyx_codeobj__58 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__57, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_translate, 229, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__58)) __PYX_ERR(0, 229, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":237 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__59 = PyTuple_Pack(4, __pyx_n_s_angle, __pyx_n_s_mat, __pyx_n_s_cos_a, __pyx_n_s_sin_a); if (unlikely(!__pyx_tuple__59)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__59); + __Pyx_GIVEREF(__pyx_tuple__59); + __pyx_codeobj__60 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_x_rotate, 237, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__60)) __PYX_ERR(0, 237, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":248 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_codeobj__61 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_y_rotate, 248, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__61)) __PYX_ERR(0, 248, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":259 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_codeobj__62 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_z_rotate, 259, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__62)) __PYX_ERR(0, 259, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":270 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__63 = PyTuple_Pack(10, __pyx_n_s_axis, __pyx_n_s_angle, __pyx_n_s_mat, __pyx_n_s_cos_a, __pyx_n_s_sin_a, __pyx_n_s_one_m_cos, __pyx_n_s_axis_2, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z); if (unlikely(!__pyx_tuple__63)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__63); + __Pyx_GIVEREF(__pyx_tuple__63); + __pyx_codeobj__64 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__63, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_axis_rotate, 270, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__64)) __PYX_ERR(0, 270, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":295 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def xyz_rotate(double angle_x, double angle_y, + * double angle_z) -> Matrix44: + */ + __pyx_tuple__65 = PyTuple_Pack(12, __pyx_n_s_angle_x, __pyx_n_s_angle_y, __pyx_n_s_angle_z, __pyx_n_s_mat, __pyx_n_s_cx, __pyx_n_s_sx, __pyx_n_s_cy, __pyx_n_s_sy, __pyx_n_s_cz, __pyx_n_s_sz, __pyx_n_s_sxsy, __pyx_n_s_cxsy); if (unlikely(!__pyx_tuple__65)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__65); + __Pyx_GIVEREF(__pyx_tuple__65); + __pyx_codeobj__66 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__65, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_xyz_rotate, 295, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__66)) __PYX_ERR(0, 295, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":319 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__67 = PyTuple_Pack(5, __pyx_n_s_angle_x, __pyx_n_s_angle_y, __pyx_n_s_mat, __pyx_n_s_tx, __pyx_n_s_ty); if (unlikely(!__pyx_tuple__67)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__67); + __Pyx_GIVEREF(__pyx_tuple__67); + __pyx_codeobj__68 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__67, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_shear_xy, 319, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__68)) __PYX_ERR(0, 319, __pyx_L1_error) + __pyx_tuple__69 = PyTuple_Pack(2, __pyx_float_0_0, __pyx_float_0_0); if (unlikely(!__pyx_tuple__69)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__69); + __Pyx_GIVEREF(__pyx_tuple__69); + + /* "ezdxf/acc/matrix44.pyx":328 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection(double left, double right, double top, + * double bottom, double near, + */ + __pyx_tuple__70 = PyTuple_Pack(7, __pyx_n_s_left, __pyx_n_s_right, __pyx_n_s_top, __pyx_n_s_bottom, __pyx_n_s_near, __pyx_n_s_far, __pyx_n_s_mat); if (unlikely(!__pyx_tuple__70)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__70); + __Pyx_GIVEREF(__pyx_tuple__70); + __pyx_codeobj__71 = (PyObject*)__Pyx_PyCode_New(6, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__70, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_perspective_projection, 328, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__71)) __PYX_ERR(0, 328, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":342 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection_fov(fov: float, aspect: float, near: float, + * far: float) -> Matrix44: + */ + __pyx_tuple__72 = PyTuple_Pack(9, __pyx_n_s_fov, __pyx_n_s_aspect, __pyx_n_s_near, __pyx_n_s_far, __pyx_n_s_vrange, __pyx_n_s_left, __pyx_n_s_right, __pyx_n_s_bottom, __pyx_n_s_top); if (unlikely(!__pyx_tuple__72)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__72); + __Pyx_GIVEREF(__pyx_tuple__72); + __pyx_codeobj__73 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__72, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_perspective_projection_fov, 342, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__73)) __PYX_ERR(0, 342, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":353 + * far) + * + * @staticmethod # <<<<<<<<<<<<<< + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + */ + __pyx_tuple__74 = PyTuple_Pack(3, __pyx_n_s_matrices, __pyx_n_s_transformation, __pyx_n_s_matrix); if (unlikely(!__pyx_tuple__74)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__74); + __Pyx_GIVEREF(__pyx_tuple__74); + __pyx_codeobj__75 = (PyObject*)__Pyx_PyCode_New(0, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_VARARGS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__74, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_chain, 353, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__75)) __PYX_ERR(0, 353, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":411 + * return res_matrix.__imul__(other) + * + * def transpose(self) -> None: # <<<<<<<<<<<<<< + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) + */ + __pyx_codeobj__76 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transpose, 411, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__76)) __PYX_ERR(0, 411, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":419 + * swap(&self.m[11], &self.m[14]) + * + * def determinant(self) -> float: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + */ + __pyx_codeobj__77 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__37, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_determinant, 419, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__77)) __PYX_ERR(0, 419, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":434 + * m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] + * + * def inverse(self) -> None: # <<<<<<<<<<<<<< + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() + */ + __pyx_tuple__78 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_m, __pyx_n_s_det, __pyx_n_s_f); if (unlikely(!__pyx_tuple__78)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__78); + __Pyx_GIVEREF(__pyx_tuple__78); + __pyx_codeobj__79 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__78, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_inverse, 434, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__79)) __PYX_ERR(0, 434, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":501 + * m[0] * m[5] * m[10]) * f + * + * @staticmethod # <<<<<<<<<<<<<< + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_tuple__80 = PyTuple_Pack(9, __pyx_n_s_ux, __pyx_n_s_uy, __pyx_n_s_uz, __pyx_n_s_origin, __pyx_n_s_mat, __pyx_n_s_ux_2, __pyx_n_s_uy_2, __pyx_n_s_uz_2, __pyx_n_s_origin_2); if (unlikely(!__pyx_tuple__80)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__80); + __Pyx_GIVEREF(__pyx_tuple__80); + __pyx_codeobj__81 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__80, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_ucs, 501, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__81)) __PYX_ERR(0, 501, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":527 + * return mat + * + * def transform(self, vector: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + __pyx_tuple__82 = PyTuple_Pack(7, __pyx_n_s_self, __pyx_n_s_vector, __pyx_n_s_res, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z, __pyx_n_s_m); if (unlikely(!__pyx_tuple__82)) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__82); + __Pyx_GIVEREF(__pyx_tuple__82); + __pyx_codeobj__83 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__82, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transform, 527, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__83)) __PYX_ERR(0, 527, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":539 + * return res + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + __pyx_tuple__84 = PyTuple_Pack(8, __pyx_n_s_self, __pyx_n_s_vector, __pyx_n_s_normalize, __pyx_n_s_res, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z, __pyx_n_s_m); if (unlikely(!__pyx_tuple__84)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__84); + __Pyx_GIVEREF(__pyx_tuple__84); + __pyx_codeobj__85 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__84, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transform_direction, 539, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__85)) __PYX_ERR(0, 539, __pyx_L1_error) + __pyx_tuple__86 = PyTuple_Pack(1, Py_False); if (unlikely(!__pyx_tuple__86)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__86); + __Pyx_GIVEREF(__pyx_tuple__86); + + /* "ezdxf/acc/matrix44.pyx":556 + * ocs_to_wcs = transform_direction + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res + */ + __pyx_tuple__87 = PyTuple_Pack(8, __pyx_n_s_self, __pyx_n_s_vectors, __pyx_n_s_m, __pyx_n_s_res, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z, __pyx_n_s_vector); if (unlikely(!__pyx_tuple__87)) __PYX_ERR(0, 556, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__87); + __Pyx_GIVEREF(__pyx_tuple__87); + __pyx_codeobj__20 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__87, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transform_vertices, 556, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(0, 556, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":572 + * yield res + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: # <<<<<<<<<<<<<< + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + */ + __pyx_tuple__88 = PyTuple_Pack(12, __pyx_n_s_self, __pyx_n_s_points, __pyx_n_s_m0, __pyx_n_s_m1, __pyx_n_s_m4, __pyx_n_s_m5, __pyx_n_s_m12, __pyx_n_s_m13, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_res, __pyx_n_s_pnt); if (unlikely(!__pyx_tuple__88)) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__88); + __Pyx_GIVEREF(__pyx_tuple__88); + __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__88, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_fast_2d_transform, 572, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(0, 572, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":590 + * yield res + * + * def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: # <<<<<<<<<<<<<< + * """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + * to transform, this allows 2D/3D transformation on arrays with more columns + */ + __pyx_tuple__89 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_array, __pyx_n_s_ndim, __pyx_n_s_ndim_2); if (unlikely(!__pyx_tuple__89)) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__89); + __Pyx_GIVEREF(__pyx_tuple__89); + __pyx_codeobj__90 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__89, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transform_array_inplace, 590, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__90)) __PYX_ERR(0, 590, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ + __pyx_tuple__91 = PyTuple_Pack(10, __pyx_n_s_self, __pyx_n_s_vectors, __pyx_n_s_normalize, __pyx_n_s_m, __pyx_n_s_res, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z, __pyx_n_s_normalize_2, __pyx_n_s_vector); if (unlikely(!__pyx_tuple__91)) __PYX_ERR(0, 608, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__91); + __Pyx_GIVEREF(__pyx_tuple__91); + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__91, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_transform_directions, 608, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 608, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":627 + * yield v3_normalize(res, 1.0) if _normalize else res + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: # <<<<<<<<<<<<<< + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + */ + __pyx_tuple__92 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_wcs); if (unlikely(!__pyx_tuple__92)) __PYX_ERR(0, 627, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__92); + __Pyx_GIVEREF(__pyx_tuple__92); + __pyx_codeobj__93 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__92, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_ucs_vertex_from_wcs, 627, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__93)) __PYX_ERR(0, 627, __pyx_L1_error) + + /* "ezdxf/acc/matrix44.pyx":630 + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) + */ + __pyx_tuple__94 = PyTuple_Pack(7, __pyx_n_s_self, __pyx_n_s_wcs, __pyx_n_s_m, __pyx_n_s_res, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z); if (unlikely(!__pyx_tuple__94)) __PYX_ERR(0, 630, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__94); + __Pyx_GIVEREF(__pyx_tuple__94); + __pyx_codeobj__95 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__94, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_matrix44_pyx, __pyx_n_s_ucs_direction_from_wcs, 630, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__95)) __PYX_ERR(0, 630, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_float_0_0 = PyFloat_FromDouble(0.0); if (unlikely(!__pyx_float_0_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_1_0 = PyFloat_FromDouble(1.0); if (unlikely(!__pyx_float_1_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_112105877 = PyInt_FromLong(112105877L); if (unlikely(!__pyx_int_112105877)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_136983863 = PyInt_FromLong(136983863L); if (unlikely(!__pyx_int_136983863)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_184977713 = PyInt_FromLong(184977713L); if (unlikely(!__pyx_int_184977713)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + /* AssertionsEnabled.init */ + if (likely(__Pyx_init_assertions_enabled() == 0)); else + +if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __pyx_collections_abc_Sequence = Py_None; Py_INCREF(Py_None); + generic = Py_None; Py_INCREF(Py_None); + strided = Py_None; Py_INCREF(Py_None); + indirect = Py_None; Py_INCREF(Py_None); + contiguous = Py_None; Py_INCREF(Py_None); + indirect_contiguous = Py_None; Py_INCREF(Py_None); + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44 = &__pyx_vtable_5ezdxf_3acc_8matrix44_Matrix44; + __pyx_vtable_5ezdxf_3acc_8matrix44_Matrix44.get_ux = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *))__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_ux; + __pyx_vtable_5ezdxf_3acc_8matrix44_Matrix44.get_uy = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *))__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uy; + __pyx_vtable_5ezdxf_3acc_8matrix44_Matrix44.get_uz = (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(*)(struct __pyx_obj_5ezdxf_3acc_8matrix44_Matrix44 *))__pyx_f_5ezdxf_3acc_8matrix44_8Matrix44_get_uz; + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44_Matrix44_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44)) __PYX_ERR(0, 40, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44_Matrix44_spec, __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44 = &__pyx_type_5ezdxf_3acc_8matrix44_Matrix44; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_vtabptr_5ezdxf_3acc_8matrix44_Matrix44) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Matrix44, (PyObject *) __pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44) < 0) __PYX_ERR(0, 40, __pyx_L1_error) + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter___spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__)) __PYX_ERR(0, 76, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter___spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__) < 0) __PYX_ERR(0, 76, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__ = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__) < 0) __PYX_ERR(0, 76, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct____iter__->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr___spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__)) __PYX_ERR(0, 81, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr___spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__) < 0) __PYX_ERR(0, 81, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__ = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__) < 0) __PYX_ERR(0, 81, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_1___repr__->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr)) __PYX_ERR(0, 83, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr) < 0) __PYX_ERR(0, 83, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr) < 0) __PYX_ERR(0, 83, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_2_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr)) __PYX_ERR(0, 86, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 86, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr) < 0) __PYX_ERR(0, 86, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_3_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows)) __PYX_ERR(0, 146, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows) < 0) __PYX_ERR(0, 146, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows) < 0) __PYX_ERR(0, 146, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_4_rows->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr)) __PYX_ERR(0, 147, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr) < 0) __PYX_ERR(0, 147, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr) < 0) __PYX_ERR(0, 147, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_5_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns)) __PYX_ERR(0, 149, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns) < 0) __PYX_ERR(0, 149, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns) < 0) __PYX_ERR(0, 149, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_6_columns->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr)) __PYX_ERR(0, 150, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr) < 0) __PYX_ERR(0, 150, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr) < 0) __PYX_ERR(0, 150, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_7_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices)) __PYX_ERR(0, 556, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices) < 0) __PYX_ERR(0, 556, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices) < 0) __PYX_ERR(0, 556, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_8_transform_vertices->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform)) __PYX_ERR(0, 572, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform) < 0) __PYX_ERR(0, 572, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform) < 0) __PYX_ERR(0, 572, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_9_fast_2d_transform->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions)) __PYX_ERR(0, 608, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions_spec, __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions) < 0) __PYX_ERR(0, 608, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions = &__pyx_type_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions) < 0) __PYX_ERR(0, 608, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_8matrix44___pyx_scope_struct_10_transform_directions->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + __pyx_vtabptr_array = &__pyx_vtable_array; + __pyx_vtable_array.get_memview = (PyObject *(*)(struct __pyx_array_obj *))__pyx_array_get_memview; + #if CYTHON_USE_TYPE_SPECS + __pyx_array_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_array_spec, NULL); if (unlikely(!__pyx_array_type)) __PYX_ERR(1, 114, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_array_type->tp_as_buffer = &__pyx_tp_as_buffer_array; + if (!__pyx_array_type->tp_as_buffer->bf_releasebuffer && __pyx_array_type->tp_base->tp_as_buffer && __pyx_array_type->tp_base->tp_as_buffer->bf_releasebuffer) { + __pyx_array_type->tp_as_buffer->bf_releasebuffer = __pyx_array_type->tp_base->tp_as_buffer->bf_releasebuffer; + } + #elif defined(Py_bf_getbuffer) && defined(Py_bf_releasebuffer) + /* PY_VERSION_HEX >= 0x03090000 || Py_LIMITED_API >= 0x030B0000 */ + #elif defined(_MSC_VER) + #pragma message ("The buffer protocol is not supported in the Limited C-API < 3.11.") + #else + #warning "The buffer protocol is not supported in the Limited C-API < 3.11." + #endif + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_array_spec, __pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #else + __pyx_array_type = &__pyx_type___pyx_array; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_array_type->tp_print = 0; + #endif + if (__Pyx_SetVtable(__pyx_array_type, __pyx_vtabptr_array) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_MemviewEnum_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_MemviewEnum_spec, NULL); if (unlikely(!__pyx_MemviewEnum_type)) __PYX_ERR(1, 302, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_MemviewEnum_spec, __pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #else + __pyx_MemviewEnum_type = &__pyx_type___pyx_MemviewEnum; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_MemviewEnum_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_MemviewEnum_type->tp_dictoffset && __pyx_MemviewEnum_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_MemviewEnum_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #endif + __pyx_vtabptr_memoryview = &__pyx_vtable_memoryview; + __pyx_vtable_memoryview.get_item_pointer = (char *(*)(struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_get_item_pointer; + __pyx_vtable_memoryview.is_slice = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_is_slice; + __pyx_vtable_memoryview.setitem_slice_assignment = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *, PyObject *))__pyx_memoryview_setitem_slice_assignment; + __pyx_vtable_memoryview.setitem_slice_assign_scalar = (PyObject *(*)(struct __pyx_memoryview_obj *, struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_setitem_slice_assign_scalar; + __pyx_vtable_memoryview.setitem_indexed = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *, PyObject *))__pyx_memoryview_setitem_indexed; + __pyx_vtable_memoryview.convert_item_to_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *))__pyx_memoryview_convert_item_to_object; + __pyx_vtable_memoryview.assign_item_from_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *, PyObject *))__pyx_memoryview_assign_item_from_object; + __pyx_vtable_memoryview._get_base = (PyObject *(*)(struct __pyx_memoryview_obj *))__pyx_memoryview__get_base; + #if CYTHON_USE_TYPE_SPECS + __pyx_memoryview_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_memoryview_spec, NULL); if (unlikely(!__pyx_memoryview_type)) __PYX_ERR(1, 337, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_memoryview_type->tp_as_buffer = &__pyx_tp_as_buffer_memoryview; + if (!__pyx_memoryview_type->tp_as_buffer->bf_releasebuffer && __pyx_memoryview_type->tp_base->tp_as_buffer && __pyx_memoryview_type->tp_base->tp_as_buffer->bf_releasebuffer) { + __pyx_memoryview_type->tp_as_buffer->bf_releasebuffer = __pyx_memoryview_type->tp_base->tp_as_buffer->bf_releasebuffer; + } + #elif defined(Py_bf_getbuffer) && defined(Py_bf_releasebuffer) + /* PY_VERSION_HEX >= 0x03090000 || Py_LIMITED_API >= 0x030B0000 */ + #elif defined(_MSC_VER) + #pragma message ("The buffer protocol is not supported in the Limited C-API < 3.11.") + #else + #warning "The buffer protocol is not supported in the Limited C-API < 3.11." + #endif + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_memoryview_spec, __pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #else + __pyx_memoryview_type = &__pyx_type___pyx_memoryview; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_memoryview_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_memoryview_type->tp_dictoffset && __pyx_memoryview_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_memoryview_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_memoryview_type, __pyx_vtabptr_memoryview) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + __pyx_vtabptr__memoryviewslice = &__pyx_vtable__memoryviewslice; + __pyx_vtable__memoryviewslice.__pyx_base = *__pyx_vtabptr_memoryview; + __pyx_vtable__memoryviewslice.__pyx_base.convert_item_to_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *))__pyx_memoryviewslice_convert_item_to_object; + __pyx_vtable__memoryviewslice.__pyx_base.assign_item_from_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *, PyObject *))__pyx_memoryviewslice_assign_item_from_object; + __pyx_vtable__memoryviewslice.__pyx_base._get_base = (PyObject *(*)(struct __pyx_memoryview_obj *))__pyx_memoryviewslice__get_base; + #if CYTHON_USE_TYPE_SPECS + __pyx_t_1 = PyTuple_Pack(1, (PyObject *)__pyx_memoryview_type); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 952, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_memoryviewslice_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_memoryviewslice_spec, __pyx_t_1); + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(!__pyx_memoryviewslice_type)) __PYX_ERR(1, 952, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_memoryviewslice_spec, __pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #else + __pyx_memoryviewslice_type = &__pyx_type___pyx_memoryviewslice; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_memoryviewslice_type->tp_base = __pyx_memoryview_type; + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_memoryviewslice_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_memoryviewslice_type->tp_dictoffset && __pyx_memoryviewslice_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_memoryviewslice_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_memoryviewslice_type, __pyx_vtabptr__memoryviewslice) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_dot", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_dot, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_cross", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_cross, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_normalize", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_normalize, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "v3_isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_v3_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_matrix44(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_matrix44}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "matrix44", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initmatrix44(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initmatrix44(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_matrix44(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_matrix44(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_matrix44(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + static PyThread_type_lock __pyx_t_8[8]; + static double __pyx_t_9[16]; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'matrix44' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("matrix44", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "matrix44" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_matrix44(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__matrix44) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name_2, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.matrix44")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.matrix44", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__24, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_version_info); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyObject_RichCompare(__pyx_t_5, __pyx_tuple__25, Py_GE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + + /* "View.MemoryView":101 + * try: + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence # <<<<<<<<<<<<<< + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__26, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_abc); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":103 + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence # <<<<<<<<<<<<<< + * except: + * + */ + /*else*/ { + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__27, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 103, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 103, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + } + __pyx_L8:; + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L7_try_end; + __pyx_L2_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "View.MemoryView":104 + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + * except: # <<<<<<<<<<<<<< + * + * __pyx_collections_abc_Sequence = None + */ + /*except:*/ { + __Pyx_AddTraceback("View.MemoryView", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_4, &__pyx_t_7) < 0) __PYX_ERR(1, 104, __pyx_L4_except_error) + __Pyx_XGOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_7); + + /* "View.MemoryView":106 + * except: + * + * __pyx_collections_abc_Sequence = None # <<<<<<<<<<<<<< + * + * + */ + __Pyx_INCREF(Py_None); + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L3_exception_handled; + } + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + __pyx_L4_except_error:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L3_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + __pyx_L7_try_end:; + } + + /* "View.MemoryView":241 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_2, &__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_1); + /*try:*/ { + + /* "View.MemoryView":242 + * + * try: + * count = __pyx_collections_abc_Sequence.count # <<<<<<<<<<<<<< + * index = __pyx_collections_abc_Sequence.index + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_count); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 242, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_array_type, __pyx_n_s_count, __pyx_t_7) < 0) __PYX_ERR(1, 242, __pyx_L11_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_array_type); + + /* "View.MemoryView":243 + * try: + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index # <<<<<<<<<<<<<< + * except: + * pass + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_index); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 243, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_array_type, __pyx_n_s_index, __pyx_t_7) < 0) __PYX_ERR(1, 243, __pyx_L11_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_array_type); + + /* "View.MemoryView":241 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L16_try_end; + __pyx_L11_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":244 + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + * except: # <<<<<<<<<<<<<< + * pass + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L12_exception_handled; + } + __pyx_L12_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_2, __pyx_t_1); + __pyx_L16_try_end:; + } + + /* "View.MemoryView":309 + * return self.name + * + * cdef generic = Enum("") # <<<<<<<<<<<<<< + * cdef strided = Enum("") # default + * cdef indirect = Enum("") + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__28, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(generic); + __Pyx_DECREF_SET(generic, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":310 + * + * cdef generic = Enum("") + * cdef strided = Enum("") # default # <<<<<<<<<<<<<< + * cdef indirect = Enum("") + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(strided); + __Pyx_DECREF_SET(strided, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":311 + * cdef generic = Enum("") + * cdef strided = Enum("") # default + * cdef indirect = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__30, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(indirect); + __Pyx_DECREF_SET(indirect, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":314 + * + * + * cdef contiguous = Enum("") # <<<<<<<<<<<<<< + * cdef indirect_contiguous = Enum("") + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__31, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(contiguous); + __Pyx_DECREF_SET(contiguous, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":315 + * + * cdef contiguous = Enum("") + * cdef indirect_contiguous = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__32, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(indirect_contiguous); + __Pyx_DECREF_SET(indirect_contiguous, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":323 + * + * + * cdef int __pyx_memoryview_thread_locks_used = 0 # <<<<<<<<<<<<<< + * cdef PyThread_type_lock[8] __pyx_memoryview_thread_locks = [ + * PyThread_allocate_lock(), + */ + __pyx_memoryview_thread_locks_used = 0; + + /* "View.MemoryView":324 + * + * cdef int __pyx_memoryview_thread_locks_used = 0 + * cdef PyThread_type_lock[8] __pyx_memoryview_thread_locks = [ # <<<<<<<<<<<<<< + * PyThread_allocate_lock(), + * PyThread_allocate_lock(), + */ + __pyx_t_8[0] = PyThread_allocate_lock(); + __pyx_t_8[1] = PyThread_allocate_lock(); + __pyx_t_8[2] = PyThread_allocate_lock(); + __pyx_t_8[3] = PyThread_allocate_lock(); + __pyx_t_8[4] = PyThread_allocate_lock(); + __pyx_t_8[5] = PyThread_allocate_lock(); + __pyx_t_8[6] = PyThread_allocate_lock(); + __pyx_t_8[7] = PyThread_allocate_lock(); + memcpy(&(__pyx_memoryview_thread_locks[0]), __pyx_t_8, sizeof(__pyx_memoryview_thread_locks[0]) * (8)); + + /* "View.MemoryView":982 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "View.MemoryView":983 + * + * try: + * count = __pyx_collections_abc_Sequence.count # <<<<<<<<<<<<<< + * index = __pyx_collections_abc_Sequence.index + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_count); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 983, __pyx_L17_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_memoryviewslice_type, __pyx_n_s_count, __pyx_t_7) < 0) __PYX_ERR(1, 983, __pyx_L17_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_memoryviewslice_type); + + /* "View.MemoryView":984 + * try: + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index # <<<<<<<<<<<<<< + * except: + * pass + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_index); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 984, __pyx_L17_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_memoryviewslice_type, __pyx_n_s_index, __pyx_t_7) < 0) __PYX_ERR(1, 984, __pyx_L17_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_memoryviewslice_type); + + /* "View.MemoryView":982 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L22_try_end; + __pyx_L17_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":985 + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + * except: # <<<<<<<<<<<<<< + * pass + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L18_exception_handled; + } + __pyx_L18_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + __pyx_L22_try_end:; + } + + /* "View.MemoryView":988 + * pass + * + * try: # <<<<<<<<<<<<<< + * if __pyx_collections_abc_Sequence: + * + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_2, &__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_1); + /*try:*/ { + + /* "View.MemoryView":989 + * + * try: + * if __pyx_collections_abc_Sequence: # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_collections_abc_Sequence); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 989, __pyx_L23_error) + if (__pyx_t_6) { + + /* "View.MemoryView":993 + * + * + * __pyx_collections_abc_Sequence.register(_memoryviewslice) # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence.register(array) + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_register); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 993, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, ((PyObject *)__pyx_memoryviewslice_type)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 993, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "View.MemoryView":994 + * + * __pyx_collections_abc_Sequence.register(_memoryviewslice) + * __pyx_collections_abc_Sequence.register(array) # <<<<<<<<<<<<<< + * except: + * pass # ignore failure, it's a minor issue + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_register); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 994, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_4, ((PyObject *)__pyx_array_type)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 994, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":989 + * + * try: + * if __pyx_collections_abc_Sequence: # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":988 + * pass + * + * try: # <<<<<<<<<<<<<< + * if __pyx_collections_abc_Sequence: + * + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L28_try_end; + __pyx_L23_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":995 + * __pyx_collections_abc_Sequence.register(_memoryviewslice) + * __pyx_collections_abc_Sequence.register(array) + * except: # <<<<<<<<<<<<<< + * pass # ignore failure, it's a minor issue + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L24_exception_handled; + } + __pyx_L24_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_2, __pyx_t_1); + __pyx_L28_try_end:; + } + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_t_7 = PyCFunction_NewEx(&__pyx_mdef_15View_dot_MemoryView_1__pyx_unpickle_Enum, NULL, __pyx_n_s_View_MemoryView); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle_Enum, __pyx_t_7) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/matrix44.pyx":4 + * # Copyright (c) 2020-2024, Manfred Moitzi + * # License: MIT License + * from typing import Sequence, Iterable, Tuple, TYPE_CHECKING, Iterator # <<<<<<<<<<<<<< + * from itertools import chain + * import math + */ + __pyx_t_7 = PyList_New(5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 0, __pyx_n_s_Sequence)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterable); + __Pyx_GIVEREF(__pyx_n_s_Iterable); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 1, __pyx_n_s_Iterable)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Tuple); + __Pyx_GIVEREF(__pyx_n_s_Tuple); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 2, __pyx_n_s_Tuple)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 3, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 4, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterator); + __Pyx_GIVEREF(__pyx_n_s_Iterator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 4, __pyx_n_s_Iterator)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_4 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_7, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Iterable); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterable, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Tuple); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Tuple, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Iterator); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterator, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":5 + * # License: MIT License + * from typing import Sequence, Iterable, Tuple, TYPE_CHECKING, Iterator + * from itertools import chain # <<<<<<<<<<<<<< + * import math + * import numpy as np + */ + __pyx_t_4 = PyList_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_n_s_chain); + __Pyx_GIVEREF(__pyx_n_s_chain); + if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_n_s_chain)) __PYX_ERR(0, 5, __pyx_L1_error); + __pyx_t_7 = __Pyx_Import(__pyx_n_s_itertools, __pyx_t_4, 0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_ImportFrom(__pyx_t_7, __pyx_n_s_chain); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_chain, __pyx_t_4) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/matrix44.pyx":6 + * from typing import Sequence, Iterable, Tuple, TYPE_CHECKING, Iterator + * from itertools import chain + * import math # <<<<<<<<<<<<<< + * import numpy as np + * import cython + */ + __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_math, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_math, __pyx_t_7) < 0) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/matrix44.pyx":7 + * from itertools import chain + * import math + * import numpy as np # <<<<<<<<<<<<<< + * import cython + * + */ + __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_7) < 0) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/matrix44.pyx":13 + * Vec2, Vec3, v3_normalize, v3_isclose, v3_cross, v3_dot, + * ) + * from .vector import X_AXIS, Y_AXIS, Z_AXIS, NULLVEC # <<<<<<<<<<<<<< + * + * from libc.math cimport fabs, sin, cos, tan + */ + __pyx_t_7 = PyList_New(4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(__pyx_n_s_X_AXIS); + __Pyx_GIVEREF(__pyx_n_s_X_AXIS); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 0, __pyx_n_s_X_AXIS)) __PYX_ERR(0, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Y_AXIS); + __Pyx_GIVEREF(__pyx_n_s_Y_AXIS); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 1, __pyx_n_s_Y_AXIS)) __PYX_ERR(0, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Z_AXIS); + __Pyx_GIVEREF(__pyx_n_s_Z_AXIS); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 2, __pyx_n_s_Z_AXIS)) __PYX_ERR(0, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_NULLVEC); + __Pyx_GIVEREF(__pyx_n_s_NULLVEC); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 3, __pyx_n_s_NULLVEC)) __PYX_ERR(0, 13, __pyx_L1_error); + __pyx_t_4 = __Pyx_Import(__pyx_n_s_vector, __pyx_t_7, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_X_AXIS); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_X_AXIS, __pyx_t_7) < 0) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Y_AXIS); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Y_AXIS, __pyx_t_7) < 0) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_Z_AXIS); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Z_AXIS, __pyx_t_7) < 0) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_NULLVEC); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_NULLVEC, __pyx_t_7) < 0) __PYX_ERR(0, 13, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":17 + * from libc.math cimport fabs, sin, cos, tan + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 17, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + + /* "ezdxf/acc/matrix44.pyx":18 + * + * if TYPE_CHECKING: + * from ezdxf.math import UVec # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_4 = PyList_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_n_s_UVec)) __PYX_ERR(0, 18, __pyx_L1_error); + __pyx_t_7 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_4, 0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_ImportFrom(__pyx_t_7, __pyx_n_s_UVec); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_4) < 0) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/matrix44.pyx":17 + * from libc.math cimport fabs, sin, cos, tan + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import UVec + * + */ + } + + /* "ezdxf/acc/matrix44.pyx":24 + * const double REL_TOL + * + * cdef double[16] IDENTITY = [ # <<<<<<<<<<<<<< + * 1.0, 0.0, 0.0, 0.0, + * 0.0, 1.0, 0.0, 0.0, + */ + __pyx_t_9[0] = 1.0; + __pyx_t_9[1] = 0.0; + __pyx_t_9[2] = 0.0; + __pyx_t_9[3] = 0.0; + __pyx_t_9[4] = 0.0; + __pyx_t_9[5] = 1.0; + __pyx_t_9[6] = 0.0; + __pyx_t_9[7] = 0.0; + __pyx_t_9[8] = 0.0; + __pyx_t_9[9] = 0.0; + __pyx_t_9[10] = 1.0; + __pyx_t_9[11] = 0.0; + __pyx_t_9[12] = 0.0; + __pyx_t_9[13] = 0.0; + __pyx_t_9[14] = 0.0; + __pyx_t_9[15] = 1.0; + memcpy(&(__pyx_v_5ezdxf_3acc_8matrix44_IDENTITY[0]), __pyx_t_9, sizeof(__pyx_v_5ezdxf_3acc_8matrix44_IDENTITY[0]) * (16)); + + /* "ezdxf/acc/matrix44.pyx":53 + * "iterable of 16 numbers") + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Matrix44, (tuple(self),) + * + */ + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_3__reduce__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44___reduce, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__36)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_reduce, __pyx_t_7) < 0) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":88 + * ", ".join(format_row(row) for row in self.rows()) + * + * def get_2d_transformation(self) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_kp_s_Tuple_float) < 0) __PYX_ERR(0, 88, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_14get_2d_transformation, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_get_2d_transformation, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__38)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_get_2d_transformation, __pyx_t_4) < 0) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":92 + * return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_2d_transformation(components: Sequence[float]) -> Matrix44: + * if len(components) != 6: + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_components, __pyx_kp_s_Sequence_float) < 0) __PYX_ERR(0, 92, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_16from_2d_transformation, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_from_2d_transformation, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__40)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_from_2d_transformation, __pyx_t_7) < 0) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_7, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_from_2d_transformation); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_from_2d_transformation, __pyx_t_4) < 0) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":108 + * return m44 + * + * def get_row(self, int row) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * cdef int index = row * 4 + * if 0 <= index < 13: + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Tuple_float) < 0) __PYX_ERR(0, 108, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_18get_row, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_get_row, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__42)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_get_row, __pyx_t_7) < 0) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":116 + * raise IndexError(f'invalid row index: {row}') + * + * def set_row(self, int row, values: Sequence[float]) -> None: # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t start = row * 4 + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_values, __pyx_kp_s_Sequence_float) < 0) __PYX_ERR(0, 116, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_None) < 0) __PYX_ERR(0, 116, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_20set_row, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_set_row, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__44)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_set_row, __pyx_t_4) < 0) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":128 + * raise IndexError(f'invalid row index: {row}') + * + * def get_col(self, int col) -> Tuple[float, ...]: # <<<<<<<<<<<<<< + * if 0 <= col < 4: + * return self.m[col], self.m[col + 4], \ + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Tuple_float) < 0) __PYX_ERR(0, 128, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_22get_col, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_get_col, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__46)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_get_col, __pyx_t_7) < 0) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":135 + * raise IndexError(f'invalid col index: {col}') + * + * def set_col(self, int col, values: Sequence[float]): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len(values) + * cdef Py_ssize_t i + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_values, __pyx_kp_s_Sequence_float) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_24set_col, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_set_col, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__48)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_set_col, __pyx_t_4) < 0) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":146 + * raise IndexError(f'invalid col index: {col}') + * + * def rows(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_kp_s_Iterator_Tuple_float) < 0) __PYX_ERR(0, 146, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_26rows, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_rows, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__50)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_rows, __pyx_t_7) < 0) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":149 + * return (self.get_row(index) for index in (0, 1, 2, 3)) + * + * def columns(self) -> Iterator[Tuple[float, ...]]: # <<<<<<<<<<<<<< + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_kp_s_Iterator_Tuple_float) < 0) __PYX_ERR(0, 149, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_28columns, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_columns, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__51)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_columns, __pyx_t_4) < 0) __PYX_ERR(0, 149, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":152 + * return (self.get_col(index) for index in (0, 1, 2, 3)) + * + * def copy(self) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 _copy = Matrix44() + * _copy.m = self.m + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 152, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_30copy, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_copy, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__53)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_copy, __pyx_t_7) < 0) __PYX_ERR(0, 152, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":157 + * return _copy + * + * __copy__ = copy # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_GetNameInClass(__pyx_t_7, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_copy); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_copy_3, __pyx_t_7) < 0) __PYX_ERR(0, 157, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":221 + * fabs(v3_dot(uy, uz)) < 1e-9 + * + * @staticmethod # <<<<<<<<<<<<<< + * def scale(double sx, sy = None, sz = None) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 221, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_32scale, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_scale, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__55)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_4, __pyx_tuple__56); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_scale, __pyx_t_4) < 0) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_scale); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_scale, __pyx_t_7) < 0) __PYX_ERR(0, 221, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":229 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def translate(double dx, double dy, double dz) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 229, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_34translate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_translate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__58)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_translate, __pyx_t_4) < 0) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_translate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_translate, __pyx_t_7) < 0) __PYX_ERR(0, 229, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":237 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def x_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 237, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_36x_rotate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_x_rotate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__60)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_x_rotate, __pyx_t_4) < 0) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_x_rotate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_x_rotate, __pyx_t_7) < 0) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":248 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def y_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 248, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_38y_rotate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_y_rotate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__61)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_y_rotate, __pyx_t_4) < 0) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_y_rotate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_y_rotate, __pyx_t_7) < 0) __PYX_ERR(0, 248, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":259 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def z_rotate(double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 259, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_40z_rotate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_z_rotate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__62)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_z_rotate, __pyx_t_4) < 0) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_z_rotate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_z_rotate, __pyx_t_7) < 0) __PYX_ERR(0, 259, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":270 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def axis_rotate(axis: UVec, double angle) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_axis, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 270, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 270, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_42axis_rotate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_axis_rotate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__64)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_axis_rotate, __pyx_t_4) < 0) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_axis_rotate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_axis_rotate, __pyx_t_7) < 0) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":295 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def xyz_rotate(double angle_x, double angle_y, + * double angle_z) -> Matrix44: + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_44xyz_rotate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_xyz_rotate, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__66)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_xyz_rotate, __pyx_t_4) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_xyz_rotate); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_xyz_rotate, __pyx_t_7) < 0) __PYX_ERR(0, 295, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":319 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 319, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_46shear_xy, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_shear_xy, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__68)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_4, __pyx_tuple__69); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_shear_xy, __pyx_t_4) < 0) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_shear_xy); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_shear_xy, __pyx_t_7) < 0) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":328 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection(double left, double right, double top, + * double bottom, double near, + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 328, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_48perspective_projection, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_perspective_projection, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__71)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection, __pyx_t_4) < 0) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection, __pyx_t_7) < 0) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":342 + * return mat + * + * @staticmethod # <<<<<<<<<<<<<< + * def perspective_projection_fov(fov: float, aspect: float, near: float, + * far: float) -> Matrix44: + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_fov, __pyx_n_s_float) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_aspect, __pyx_n_s_float) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_near, __pyx_n_s_float) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_far, __pyx_n_s_float) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_50perspective_projection_fov, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_perspective_projection_2, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__73)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection_fov, __pyx_t_4) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection_fov); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_perspective_projection_fov, __pyx_t_7) < 0) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":353 + * far) + * + * @staticmethod # <<<<<<<<<<<<<< + * def chain(*matrices: Matrix44) -> Matrix44: + * cdef Matrix44 transformation = Matrix44() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_matrices, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 353, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 353, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_52chain, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_chain, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__75)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_chain, __pyx_t_4) < 0) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_4, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_chain); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_chain, __pyx_t_7) < 0) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":411 + * return res_matrix.__imul__(other) + * + * def transpose(self) -> None: # <<<<<<<<<<<<<< + * swap(&self.m[1], &self.m[4]) + * swap(&self.m[2], &self.m[8]) + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_None) < 0) __PYX_ERR(0, 411, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_60transpose, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transpose, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__76)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transpose, __pyx_t_4) < 0) __PYX_ERR(0, 411, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":419 + * swap(&self.m[11], &self.m[14]) + * + * def determinant(self) -> float: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 419, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 419, __pyx_L1_error) + __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_62determinant, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_determinant, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__77)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 419, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_7, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_determinant, __pyx_t_7) < 0) __PYX_ERR(0, 419, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":434 + * m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] + * + * def inverse(self) -> None: # <<<<<<<<<<<<<< + * cdef double[16] m = self.m # memcopy + * cdef double det = self.determinant() + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_return, __pyx_n_s_None) < 0) __PYX_ERR(0, 434, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_64inverse, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_inverse, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__79)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_inverse, __pyx_t_4) < 0) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":502 + * + * @staticmethod + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 mat = Matrix44() + * cdef Vec3 _ux = Vec3(ux) + */ + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_X_AXIS); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_k__16 = __pyx_t_4; + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_Y_AXIS); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_k__17 = __pyx_t_4; + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_Z_AXIS); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_k__18 = __pyx_t_4; + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NULLVEC); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_k__19 = __pyx_t_4; + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/matrix44.pyx":501 + * m[0] * m[5] * m[10]) * f + * + * @staticmethod # <<<<<<<<<<<<<< + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_X_AXIS); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "ezdxf/acc/matrix44.pyx":502 + * + * @staticmethod + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: # <<<<<<<<<<<<<< + * cdef Matrix44 mat = Matrix44() + * cdef Vec3 _ux = Vec3(ux) + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_Y_AXIS); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_Z_AXIS); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_n_s_NULLVEC); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + + /* "ezdxf/acc/matrix44.pyx":501 + * m[0] * m[5] * m[10]) * f + * + * @staticmethod # <<<<<<<<<<<<<< + * def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + * cdef Matrix44 mat = Matrix44() + */ + __pyx_t_11 = PyTuple_New(4); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_4)) __PYX_ERR(0, 501, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_7)) __PYX_ERR(0, 501, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_t_5)) __PYX_ERR(0, 501, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_10); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 3, __pyx_t_10)) __PYX_ERR(0, 501, __pyx_L1_error); + __pyx_t_4 = 0; + __pyx_t_7 = 0; + __pyx_t_5 = 0; + __pyx_t_10 = 0; + __pyx_t_10 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_return, __pyx_n_s_Matrix44) < 0) __PYX_ERR(0, 501, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_66ucs, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_ucs, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__81)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_t_11); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_10); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs, __pyx_t_5) < 0) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs, __pyx_t_10) < 0) __PYX_ERR(0, 501, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":527 + * return mat + * + * def transform(self, vector: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + __pyx_t_10 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_vector, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 527, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 527, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_68transform, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transform, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__83)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform, __pyx_t_5) < 0) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":539 + * return res + * + * def transform_direction(self, vector: UVec, normalize=False) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3(vector) + * cdef double x = res.x + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_vector, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 539, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 539, __pyx_L1_error) + __pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_70transform_direction, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transform_direction, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__85)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_10, __pyx_tuple__86); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_10, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform_direction, __pyx_t_10) < 0) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":554 + * return res + * + * ocs_to_wcs = transform_direction # <<<<<<<<<<<<<< + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: + */ + __Pyx_GetNameInClass(__pyx_t_10, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform_direction); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 554, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ocs_to_wcs, __pyx_t_10) < 0) __PYX_ERR(0, 554, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":556 + * ocs_to_wcs = transform_direction + * + * def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res + */ + __pyx_t_10 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 556, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_vectors, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 556, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec3) < 0) __PYX_ERR(0, 556, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_72transform_vertices, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transform_vertices, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__20)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 556, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform_vertices, __pyx_t_5) < 0) __PYX_ERR(0, 556, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":572 + * yield res + * + * def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: # <<<<<<<<<<<<<< + * cdef double m0 = self.m[0] + * cdef double m1 = self.m[1] + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_points, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 572, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec2) < 0) __PYX_ERR(0, 572, __pyx_L1_error) + __pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_75fast_2d_transform, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_fast_2d_transform, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_10, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_fast_2d_transform, __pyx_t_10) < 0) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":590 + * yield res + * + * def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: # <<<<<<<<<<<<<< + * """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + * to transform, this allows 2D/3D transformation on arrays with more columns + */ + __pyx_t_10 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_array, __pyx_kp_s_np_ndarray) < 0) __PYX_ERR(0, 590, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_ndim, __pyx_n_s_int) < 0) __PYX_ERR(0, 590, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_return, __pyx_n_s_None) < 0) __PYX_ERR(0, 590, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_78transform_array_inplace, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transform_array_inplace, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__90)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform_array_inplace, __pyx_t_5) < 0) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":608 + * + * + * def transform_directions( # <<<<<<<<<<<<<< + * self, vectors: Iterable[UVec], normalize=False + * ) -> Iterator[Vec3]: + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 608, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_vectors, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 608, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec3) < 0) __PYX_ERR(0, 608, __pyx_L1_error) + __pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_80transform_directions, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_transform_directions, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 608, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_10, __pyx_tuple__86); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_10, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_transform_directions, __pyx_t_10) < 0) __PYX_ERR(0, 608, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":627 + * yield v3_normalize(res, 1.0) if _normalize else res + * + * def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: # <<<<<<<<<<<<<< + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + */ + __pyx_t_10 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 627, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_wcs, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 627, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 627, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_83ucs_vertex_from_wcs, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_ucs_vertex_from_wcs, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__93)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 627, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs_vertex_from_wcs, __pyx_t_5) < 0) __PYX_ERR(0, 627, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":630 + * return self.ucs_direction_from_wcs(wcs - self.origin) + * + * def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef double *m = self.m + * cdef Vec3 res = Vec3(wcs) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 630, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_wcs, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 630, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 630, __pyx_L1_error) + __pyx_t_10 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_8matrix44_8Matrix44_85ucs_direction_from_wcs, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Matrix44_ucs_direction_from_wcs, NULL, __pyx_n_s_ezdxf_acc_matrix44, __pyx_d, ((PyObject *)__pyx_codeobj__95)); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 630, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_10, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs_direction_from_wcs, __pyx_t_10) < 0) __PYX_ERR(0, 630, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":642 + * return res + * + * ocs_from_wcs = ucs_direction_from_wcs # <<<<<<<<<<<<<< + * + * + */ + __Pyx_GetNameInClass(__pyx_t_10, (PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ucs_direction_from_wcs); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 642, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44, __pyx_n_s_ocs_from_wcs, __pyx_t_10) < 0) __PYX_ERR(0, 642, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_8matrix44_Matrix44); + + /* "ezdxf/acc/matrix44.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2020-2024, Manfred Moitzi + * # License: MIT License + */ + __pyx_t_10 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_10) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_11); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.matrix44", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.matrix44"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* CIntToDigits */ +static const char DIGIT_PAIRS_10[2*10*10+1] = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; +static const char DIGIT_PAIRS_8[2*8*8+1] = { + "0001020304050607" + "1011121314151617" + "2021222324252627" + "3031323334353637" + "4041424344454647" + "5051525354555657" + "6061626364656667" + "7071727374757677" +}; +static const char DIGITS_HEX[2*16+1] = { + "0123456789abcdef" + "0123456789ABCDEF" +}; + +/* BuildPyUnicode */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char) { + PyObject *uval; + Py_ssize_t uoffset = ulength - clength; +#if CYTHON_USE_UNICODE_INTERNALS + Py_ssize_t i; +#if CYTHON_PEP393_ENABLED + void *udata; + uval = PyUnicode_New(ulength, 127); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_DATA(uval); +#else + Py_UNICODE *udata; + uval = PyUnicode_FromUnicode(NULL, ulength); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_AS_UNICODE(uval); +#endif + if (uoffset > 0) { + i = 0; + if (prepend_sign) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, 0, '-'); + i++; + } + for (; i < uoffset; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, i, padding_char); + } + } + for (i=0; i < clength; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, uoffset+i, chars[i]); + } +#else + { + PyObject *sign = NULL, *padding = NULL; + uval = NULL; + if (uoffset > 0) { + prepend_sign = !!prepend_sign; + if (uoffset > prepend_sign) { + padding = PyUnicode_FromOrdinal(padding_char); + if (likely(padding) && uoffset > prepend_sign + 1) { + PyObject *tmp; + PyObject *repeat = PyInt_FromSsize_t(uoffset - prepend_sign); + if (unlikely(!repeat)) goto done_or_error; + tmp = PyNumber_Multiply(padding, repeat); + Py_DECREF(repeat); + Py_DECREF(padding); + padding = tmp; + } + if (unlikely(!padding)) goto done_or_error; + } + if (prepend_sign) { + sign = PyUnicode_FromOrdinal('-'); + if (unlikely(!sign)) goto done_or_error; + } + } + uval = PyUnicode_DecodeASCII(chars, clength, NULL); + if (likely(uval) && padding) { + PyObject *tmp = PyNumber_Add(padding, uval); + Py_DECREF(uval); + uval = tmp; + } + if (likely(uval) && sign) { + PyObject *tmp = PyNumber_Add(sign, uval); + Py_DECREF(uval); + uval = tmp; + } +done_or_error: + Py_XDECREF(padding); + Py_XDECREF(sign); + } +#endif + return uval; +} + +/* CIntToPyUnicode */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char) { + char digits[sizeof(int)*3+2]; + char *dpos, *end = digits + sizeof(int)*3+2; + const char *hex_digits = DIGITS_HEX; + Py_ssize_t length, ulength; + int prepend_sign, last_one_off; + int remaining; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (format_char == 'X') { + hex_digits += 16; + format_char = 'x'; + } + remaining = value; + last_one_off = 0; + dpos = end; + do { + int digit_pos; + switch (format_char) { + case 'o': + digit_pos = abs((int)(remaining % (8*8))); + remaining = (int) (remaining / (8*8)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2); + last_one_off = (digit_pos < 8); + break; + case 'd': + digit_pos = abs((int)(remaining % (10*10))); + remaining = (int) (remaining / (10*10)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2); + last_one_off = (digit_pos < 10); + break; + case 'x': + *(--dpos) = hex_digits[abs((int)(remaining % 16))]; + remaining = (int) (remaining / 16); + break; + default: + assert(0); + break; + } + } while (unlikely(remaining != 0)); + assert(!last_one_off || *dpos == '0'); + dpos += last_one_off; + length = end - dpos; + ulength = length; + prepend_sign = 0; + if (!is_unsigned && value <= neg_one) { + if (padding_char == ' ' || width <= length + 1) { + *(--dpos) = '-'; + ++length; + } else { + prepend_sign = 1; + } + ++ulength; + } + if (width > ulength) { + ulength = width; + } + if (ulength == 1) { + return PyUnicode_FromOrdinal(*dpos); + } + return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char); +} + +/* CIntToPyUnicode */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char) { + char digits[sizeof(Py_ssize_t)*3+2]; + char *dpos, *end = digits + sizeof(Py_ssize_t)*3+2; + const char *hex_digits = DIGITS_HEX; + Py_ssize_t length, ulength; + int prepend_sign, last_one_off; + Py_ssize_t remaining; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const Py_ssize_t neg_one = (Py_ssize_t) -1, const_zero = (Py_ssize_t) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (format_char == 'X') { + hex_digits += 16; + format_char = 'x'; + } + remaining = value; + last_one_off = 0; + dpos = end; + do { + int digit_pos; + switch (format_char) { + case 'o': + digit_pos = abs((int)(remaining % (8*8))); + remaining = (Py_ssize_t) (remaining / (8*8)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2); + last_one_off = (digit_pos < 8); + break; + case 'd': + digit_pos = abs((int)(remaining % (10*10))); + remaining = (Py_ssize_t) (remaining / (10*10)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2); + last_one_off = (digit_pos < 10); + break; + case 'x': + *(--dpos) = hex_digits[abs((int)(remaining % 16))]; + remaining = (Py_ssize_t) (remaining / 16); + break; + default: + assert(0); + break; + } + } while (unlikely(remaining != 0)); + assert(!last_one_off || *dpos == '0'); + dpos += last_one_off; + length = end - dpos; + ulength = length; + prepend_sign = 0; + if (!is_unsigned && value <= neg_one) { + if (padding_char == ' ' || width <= length + 1) { + *(--dpos) = '-'; + ++length; + } else { + prepend_sign = 1; + } + ++ulength; + } + if (width > ulength) { + ulength = width; + } + if (ulength == 1) { + return PyUnicode_FromOrdinal(*dpos); + } + return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char); +} + +/* JoinPyUnicode */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char) { +#if CYTHON_USE_UNICODE_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + PyObject *result_uval; + int result_ukind, kind_shift; + Py_ssize_t i, char_pos; + void *result_udata; + CYTHON_MAYBE_UNUSED_VAR(max_char); +#if CYTHON_PEP393_ENABLED + result_uval = PyUnicode_New(result_ulength, max_char); + if (unlikely(!result_uval)) return NULL; + result_ukind = (max_char <= 255) ? PyUnicode_1BYTE_KIND : (max_char <= 65535) ? PyUnicode_2BYTE_KIND : PyUnicode_4BYTE_KIND; + kind_shift = (result_ukind == PyUnicode_4BYTE_KIND) ? 2 : result_ukind - 1; + result_udata = PyUnicode_DATA(result_uval); +#else + result_uval = PyUnicode_FromUnicode(NULL, result_ulength); + if (unlikely(!result_uval)) return NULL; + result_ukind = sizeof(Py_UNICODE); + kind_shift = (result_ukind == 4) ? 2 : result_ukind - 1; + result_udata = PyUnicode_AS_UNICODE(result_uval); +#endif + assert(kind_shift == 2 || kind_shift == 1 || kind_shift == 0); + char_pos = 0; + for (i=0; i < value_count; i++) { + int ukind; + Py_ssize_t ulength; + void *udata; + PyObject *uval = PyTuple_GET_ITEM(value_tuple, i); + if (unlikely(__Pyx_PyUnicode_READY(uval))) + goto bad; + ulength = __Pyx_PyUnicode_GET_LENGTH(uval); + if (unlikely(!ulength)) + continue; + if (unlikely((PY_SSIZE_T_MAX >> kind_shift) - ulength < char_pos)) + goto overflow; + ukind = __Pyx_PyUnicode_KIND(uval); + udata = __Pyx_PyUnicode_DATA(uval); + if (!CYTHON_PEP393_ENABLED || ukind == result_ukind) { + memcpy((char *)result_udata + (char_pos << kind_shift), udata, (size_t) (ulength << kind_shift)); + } else { + #if PY_VERSION_HEX >= 0x030d0000 + if (unlikely(PyUnicode_CopyCharacters(result_uval, char_pos, uval, 0, ulength) < 0)) goto bad; + #elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030300F0 || defined(_PyUnicode_FastCopyCharacters) + _PyUnicode_FastCopyCharacters(result_uval, char_pos, uval, 0, ulength); + #else + Py_ssize_t j; + for (j=0; j < ulength; j++) { + Py_UCS4 uchar = __Pyx_PyUnicode_READ(ukind, udata, j); + __Pyx_PyUnicode_WRITE(result_ukind, result_udata, char_pos+j, uchar); + } + #endif + } + char_pos += ulength; + } + return result_uval; +overflow: + PyErr_SetString(PyExc_OverflowError, "join() result is too long for a Python string"); +bad: + Py_DECREF(result_uval); + return NULL; +#else + CYTHON_UNUSED_VAR(max_char); + CYTHON_UNUSED_VAR(result_ulength); + CYTHON_UNUSED_VAR(value_count); + return PyUnicode_Join(__pyx_empty_unicode, value_tuple); +#endif +} + +/* GetAttr */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { +#if CYTHON_USE_TYPE_SLOTS +#if PY_MAJOR_VERSION >= 3 + if (likely(PyUnicode_Check(n))) +#else + if (likely(PyString_Check(n))) +#endif + return __Pyx_PyObject_GetAttrStr(o, n); +#endif + return PyObject_GetAttr(o, n); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* ObjectGetItem */ +#if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject *index) { + PyObject *runerr = NULL; + Py_ssize_t key_value; + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + __Pyx_TypeName index_type_name = __Pyx_PyType_GetName(Py_TYPE(index)); + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, + "cannot fit '" __Pyx_FMT_TYPENAME "' into an index-sized integer", index_type_name); + __Pyx_DECREF_TypeName(index_type_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem_Slow(PyObject *obj, PyObject *key) { + __Pyx_TypeName obj_type_name; + if (likely(PyType_Check(obj))) { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(obj, __pyx_n_s_class_getitem); + if (!meth) { + PyErr_Clear(); + } else { + PyObject *result = __Pyx_PyObject_CallOneArg(meth, key); + Py_DECREF(meth); + return result; + } + } + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "'" __Pyx_FMT_TYPENAME "' object is not subscriptable", obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key) { + PyTypeObject *tp = Py_TYPE(obj); + PyMappingMethods *mm = tp->tp_as_mapping; + PySequenceMethods *sm = tp->tp_as_sequence; + if (likely(mm && mm->mp_subscript)) { + return mm->mp_subscript(obj, key); + } + if (likely(sm && sm->sq_item)) { + return __Pyx_PyObject_GetIndex(obj, key); + } + return __Pyx_PyObject_GetItem_Slow(obj, key); +} +#endif + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* DivInt[Py_ssize_t] */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t a, Py_ssize_t b) { + Py_ssize_t q = a / b; + Py_ssize_t r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* GetAttr3 */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static PyObject *__Pyx_GetAttr3Default(PyObject *d) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (unlikely(!__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + __Pyx_PyErr_Clear(); + Py_INCREF(d); + return d; +} +#endif +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { + PyObject *r; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + int res = PyObject_GetOptionalAttr(o, n, &r); + return (res != 0) ? r : __Pyx_NewRef(d); +#else + #if CYTHON_USE_TYPE_SLOTS + if (likely(PyString_Check(n))) { + r = __Pyx_PyObject_GetAttrStrNoError(o, n); + if (unlikely(!r) && likely(!PyErr_Occurred())) { + r = __Pyx_NewRef(d); + } + return r; + } + #endif + r = PyObject_GetAttr(o, n); + return (likely(r)) ? r : __Pyx_GetAttr3Default(d); +#endif +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* RaiseTooManyValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* RaiseNoneIterError */ +static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* GetTopmostException */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportDottedModule */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { + PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; + if (unlikely(PyErr_Occurred())) { + PyErr_Clear(); + } + if (likely(PyTuple_GET_SIZE(parts_tuple) == count)) { + partial_name = name; + } else { + slice = PySequence_GetSlice(parts_tuple, 0, count); + if (unlikely(!slice)) + goto bad; + sep = PyUnicode_FromStringAndSize(".", 1); + if (unlikely(!sep)) + goto bad; + partial_name = PyUnicode_Join(sep, slice); + } + PyErr_Format( +#if PY_MAJOR_VERSION < 3 + PyExc_ImportError, + "No module named '%s'", PyString_AS_STRING(partial_name)); +#else +#if PY_VERSION_HEX >= 0x030600B1 + PyExc_ModuleNotFoundError, +#else + PyExc_ImportError, +#endif + "No module named '%U'", partial_name); +#endif +bad: + Py_XDECREF(sep); + Py_XDECREF(slice); + Py_XDECREF(partial_name); + return NULL; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { + PyObject *imported_module; +#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + return NULL; + imported_module = __Pyx_PyDict_GetItemStr(modules, name); + Py_XINCREF(imported_module); +#else + imported_module = PyImport_GetModule(name); +#endif + return imported_module; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { + Py_ssize_t i, nparts; + nparts = PyTuple_GET_SIZE(parts_tuple); + for (i=1; i < nparts && module; i++) { + PyObject *part, *submodule; +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + part = PyTuple_GET_ITEM(parts_tuple, i); +#else + part = PySequence_ITEM(parts_tuple, i); +#endif + submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); +#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(part); +#endif + Py_DECREF(module); + module = submodule; + } + if (unlikely(!module)) { + return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); + } + return module; +} +#endif +static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if PY_MAJOR_VERSION < 3 + PyObject *module, *from_list, *star = __pyx_n_s__3; + CYTHON_UNUSED_VAR(parts_tuple); + from_list = PyList_New(1); + if (unlikely(!from_list)) + return NULL; + Py_INCREF(star); + PyList_SET_ITEM(from_list, 0, star); + module = __Pyx_Import(name, from_list, 0); + Py_DECREF(from_list); + return module; +#else + PyObject *imported_module; + PyObject *module = __Pyx_Import(name, NULL, 0); + if (!parts_tuple || unlikely(!module)) + return module; + imported_module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(imported_module)) { + Py_DECREF(module); + return imported_module; + } + PyErr_Clear(); + return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); +#endif +} +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1 + PyObject *module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(module)) { + PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_n_s_spec); + if (likely(spec)) { + PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_n_s_initializing); + if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { + Py_DECREF(spec); + spec = NULL; + } + Py_XDECREF(unsafe); + } + if (likely(!spec)) { + PyErr_Clear(); + return module; + } + Py_DECREF(spec); + Py_DECREF(module); + } else if (PyErr_Occurred()) { + PyErr_Clear(); + } +#endif + return __Pyx__ImportDottedModule(name, parts_tuple); +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; itp_as_sequence && type->tp_as_sequence->sq_repeat)) { + return type->tp_as_sequence->sq_repeat(seq, mul); + } else +#endif + { + return __Pyx_PySequence_Multiply_Generic(seq, mul); + } +} + +/* SetItemInt */ +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { + int r; + if (unlikely(!j)) return -1; + r = PyObject_SetItem(o, j, v); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, + CYTHON_NCP_UNUSED int wraparound, CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o)); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o)))) { + PyObject* old = PyList_GET_ITEM(o, n); + Py_INCREF(v); + PyList_SET_ITEM(o, n, v); + Py_DECREF(old); + return 1; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_ass_subscript) { + int r; + PyObject *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return -1; + r = mm->mp_ass_subscript(o, key, v); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_ass_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return -1; + PyErr_Clear(); + } + } + return sm->sq_ass_item(o, i, v); + } + } +#else + if (is_list || !PyMapping_Check(o)) + { + return PySequence_SetItem(o, i, v); + } +#endif + return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v); +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* DivInt[long] */ +static CYTHON_INLINE long __Pyx_div_long(long a, long b) { + long q = a / b; + long r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__2); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* HasAttr */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *r; + if (unlikely(!__Pyx_PyBaseString_Check(n))) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return -1; + } + r = __Pyx_GetAttr(o, n); + if (!r) { + PyErr_Clear(); + return 0; + } else { + Py_DECREF(r); + return 1; + } +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc; + __Pyx_PyThreadState_declare + #ifdef __Pyx_StopAsyncIteration_USED + int is_async_stopiteration = 0; + #endif + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + cur_exc = PyErr_Occurred(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + #ifdef __Pyx_StopAsyncIteration_USED + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else + #endif + return; + } + __Pyx_PyThreadState_assign + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + PyErr_SetString(PyExc_RuntimeError, + #ifdef __Pyx_StopAsyncIteration_USED + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + #endif + "generator raised StopIteration"); +} + +/* RaiseClosureNameError */ +static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) { + PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname); +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name_2); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* GetNameInClass */ +static PyObject *__Pyx__GetNameInClass(PyObject *nmspace, PyObject *name) { + PyObject *result; + PyObject *dict; + assert(PyType_Check(nmspace)); +#if CYTHON_USE_TYPE_SLOTS + dict = ((PyTypeObject*)nmspace)->tp_dict; + Py_XINCREF(dict); +#else + dict = PyObject_GetAttr(nmspace, __pyx_n_s_dict); +#endif + if (likely(dict)) { + result = PyObject_GetItem(dict, name); + Py_DECREF(dict); + if (result) { + return result; + } + } + PyErr_Clear(); + __Pyx_GetModuleGlobalNameUncached(result, name); + return result; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +#if PY_MAJOR_VERSION < 3 +static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { + __Pyx_TypeName obj_type_name; + if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); + if (__Pyx_TypeCheck(obj, __pyx_array_type)) return __pyx_array_getbuffer(obj, view, flags); + if (__Pyx_TypeCheck(obj, __pyx_memoryview_type)) return __pyx_memoryview_getbuffer(obj, view, flags); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "'" __Pyx_FMT_TYPENAME "' does not have the buffer interface", + obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return -1; +} +static void __Pyx_ReleaseBuffer(Py_buffer *view) { + PyObject *obj = view->obj; + if (!obj) return; + if (PyObject_CheckBuffer(obj)) { + PyBuffer_Release(view); + return; + } + if ((0)) {} + view->obj = NULL; + Py_DECREF(obj); +} +#endif + + +/* MemviewSliceIsContig */ +static int +__pyx_memviewslice_is_contig(const __Pyx_memviewslice mvs, char order, int ndim) +{ + int i, index, step, start; + Py_ssize_t itemsize = mvs.memview->view.itemsize; + if (order == 'F') { + step = 1; + start = 0; + } else { + step = -1; + start = ndim - 1; + } + for (i = 0; i < ndim; i++) { + index = start + step * i; + if (mvs.suboffsets[index] >= 0 || mvs.strides[index] != itemsize) + return 0; + itemsize *= mvs.shape[index]; + } + return 1; +} + +/* OverlappingSlices */ +static void +__pyx_get_array_memory_extents(__Pyx_memviewslice *slice, + void **out_start, void **out_end, + int ndim, size_t itemsize) +{ + char *start, *end; + int i; + start = end = slice->data; + for (i = 0; i < ndim; i++) { + Py_ssize_t stride = slice->strides[i]; + Py_ssize_t extent = slice->shape[i]; + if (extent == 0) { + *out_start = *out_end = start; + return; + } else { + if (stride > 0) + end += stride * (extent - 1); + else + start += stride * (extent - 1); + } + } + *out_start = start; + *out_end = end + itemsize; +} +static int +__pyx_slices_overlap(__Pyx_memviewslice *slice1, + __Pyx_memviewslice *slice2, + int ndim, size_t itemsize) +{ + void *start1, *end1, *start2, *end2; + __pyx_get_array_memory_extents(slice1, &start1, &end1, ndim, itemsize); + __pyx_get_array_memory_extents(slice2, &start2, &end2, ndim, itemsize); + return (start1 < end2) && (start2 < end1); +} + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* IsLittleEndian */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } S; + S.u32 = 0x01020304; + return S.u8[0] == 4; +} + +/* BufferFormatCheck */ +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type) { + stack[0].field = &ctx->root; + stack[0].parent_offset = 0; + ctx->root.type = type; + ctx->root.name = "buffer dtype"; + ctx->root.offset = 0; + ctx->head = stack; + ctx->head->field = &ctx->root; + ctx->fmt_offset = 0; + ctx->head->parent_offset = 0; + ctx->new_packmode = '@'; + ctx->enc_packmode = '@'; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->is_complex = 0; + ctx->is_valid_array = 0; + ctx->struct_alignment = 0; + while (type->typegroup == 'S') { + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = 0; + type = type->fields->type; + } +} +static int __Pyx_BufFmt_ParseNumber(const char** ts) { + int count; + const char* t = *ts; + if (*t < '0' || *t > '9') { + return -1; + } else { + count = *t++ - '0'; + while (*t >= '0' && *t <= '9') { + count *= 10; + count += *t++ - '0'; + } + } + *ts = t; + return count; +} +static int __Pyx_BufFmt_ExpectNumber(const char **ts) { + int number = __Pyx_BufFmt_ParseNumber(ts); + if (number == -1) + PyErr_Format(PyExc_ValueError,\ + "Does not understand character buffer dtype format string ('%c')", **ts); + return number; +} +static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { + PyErr_Format(PyExc_ValueError, + "Unexpected format string character: '%c'", ch); +} +static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { + switch (ch) { + case '?': return "'bool'"; + case 'c': return "'char'"; + case 'b': return "'signed char'"; + case 'B': return "'unsigned char'"; + case 'h': return "'short'"; + case 'H': return "'unsigned short'"; + case 'i': return "'int'"; + case 'I': return "'unsigned int'"; + case 'l': return "'long'"; + case 'L': return "'unsigned long'"; + case 'q': return "'long long'"; + case 'Q': return "'unsigned long long'"; + case 'f': return (is_complex ? "'complex float'" : "'float'"); + case 'd': return (is_complex ? "'complex double'" : "'double'"); + case 'g': return (is_complex ? "'complex long double'" : "'long double'"); + case 'T': return "a struct"; + case 'O': return "Python object"; + case 'P': return "a pointer"; + case 's': case 'p': return "a string"; + case 0: return "end"; + default: return "unparsable format string"; + } +} +static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return 2; + case 'i': case 'I': case 'l': case 'L': return 4; + case 'q': case 'Q': return 8; + case 'f': return (is_complex ? 8 : 4); + case 'd': return (is_complex ? 16 : 8); + case 'g': { + PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g').."); + return 0; + } + case 'O': case 'P': return sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(short); + case 'i': case 'I': return sizeof(int); + case 'l': case 'L': return sizeof(long); + #ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(PY_LONG_LONG); + #endif + case 'f': return sizeof(float) * (is_complex ? 2 : 1); + case 'd': return sizeof(double) * (is_complex ? 2 : 1); + case 'g': return sizeof(long double) * (is_complex ? 2 : 1); + case 'O': case 'P': return sizeof(void*); + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +typedef struct { char c; short x; } __Pyx_st_short; +typedef struct { char c; int x; } __Pyx_st_int; +typedef struct { char c; long x; } __Pyx_st_long; +typedef struct { char c; float x; } __Pyx_st_float; +typedef struct { char c; double x; } __Pyx_st_double; +typedef struct { char c; long double x; } __Pyx_st_longdouble; +typedef struct { char c; void *x; } __Pyx_st_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { char c; PY_LONG_LONG x; } __Pyx_st_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, int is_complex) { + CYTHON_UNUSED_VAR(is_complex); + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_st_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_st_float) - sizeof(float); + case 'd': return sizeof(__Pyx_st_double) - sizeof(double); + case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +/* These are for computing the padding at the end of the struct to align + on the first member of the struct. This will probably the same as above, + but we don't have any guarantees. + */ +typedef struct { short x; char c; } __Pyx_pad_short; +typedef struct { int x; char c; } __Pyx_pad_int; +typedef struct { long x; char c; } __Pyx_pad_long; +typedef struct { float x; char c; } __Pyx_pad_float; +typedef struct { double x; char c; } __Pyx_pad_double; +typedef struct { long double x; char c; } __Pyx_pad_longdouble; +typedef struct { void *x; char c; } __Pyx_pad_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { PY_LONG_LONG x; char c; } __Pyx_pad_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToPadding(char ch, int is_complex) { + CYTHON_UNUSED_VAR(is_complex); + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_pad_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_pad_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_pad_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_pad_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_pad_float) - sizeof(float); + case 'd': return sizeof(__Pyx_pad_double) - sizeof(double); + case 'g': return sizeof(__Pyx_pad_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_pad_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { + switch (ch) { + case 'c': + return 'H'; + case 'b': case 'h': case 'i': + case 'l': case 'q': case 's': case 'p': + return 'I'; + case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': + return 'U'; + case 'f': case 'd': case 'g': + return (is_complex ? 'C' : 'R'); + case 'O': + return 'O'; + case 'P': + return 'P'; + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) { + if (ctx->head == NULL || ctx->head->field == &ctx->root) { + const char* expected; + const char* quote; + if (ctx->head == NULL) { + expected = "end"; + quote = ""; + } else { + expected = ctx->head->field->type->name; + quote = "'"; + } + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected %s%s%s but got %s", + quote, expected, quote, + __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex)); + } else { + __Pyx_StructField* field = ctx->head->field; + __Pyx_StructField* parent = (ctx->head - 1)->field; + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'", + field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex), + parent->type->name, field->name); + } +} +static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) { + char group; + size_t size, offset, arraysize = 1; + if (ctx->enc_type == 0) return 0; + if (ctx->head->field->type->arraysize[0]) { + int i, ndim = 0; + if (ctx->enc_type == 's' || ctx->enc_type == 'p') { + ctx->is_valid_array = ctx->head->field->type->ndim == 1; + ndim = 1; + if (ctx->enc_count != ctx->head->field->type->arraysize[0]) { + PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %zu", + ctx->head->field->type->arraysize[0], ctx->enc_count); + return -1; + } + } + if (!ctx->is_valid_array) { + PyErr_Format(PyExc_ValueError, "Expected %d dimensions, got %d", + ctx->head->field->type->ndim, ndim); + return -1; + } + for (i = 0; i < ctx->head->field->type->ndim; i++) { + arraysize *= ctx->head->field->type->arraysize[i]; + } + ctx->is_valid_array = 0; + ctx->enc_count = 1; + } + group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex); + do { + __Pyx_StructField* field = ctx->head->field; + __Pyx_TypeInfo* type = field->type; + if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') { + size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex); + } else { + size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex); + } + if (ctx->enc_packmode == '@') { + size_t align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex); + size_t align_mod_offset; + if (align_at == 0) return -1; + align_mod_offset = ctx->fmt_offset % align_at; + if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset; + if (ctx->struct_alignment == 0) + ctx->struct_alignment = __Pyx_BufFmt_TypeCharToPadding(ctx->enc_type, + ctx->is_complex); + } + if (type->size != size || type->typegroup != group) { + if (type->typegroup == 'C' && type->fields != NULL) { + size_t parent_offset = ctx->head->parent_offset + field->offset; + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = parent_offset; + continue; + } + if ((type->typegroup == 'H' || group == 'H') && type->size == size) { + } else { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + } + offset = ctx->head->parent_offset + field->offset; + if (ctx->fmt_offset != offset) { + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch; next field is at offset %" CYTHON_FORMAT_SSIZE_T "d but %" CYTHON_FORMAT_SSIZE_T "d expected", + (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset); + return -1; + } + ctx->fmt_offset += size; + if (arraysize) + ctx->fmt_offset += (arraysize - 1) * size; + --ctx->enc_count; + while (1) { + if (field == &ctx->root) { + ctx->head = NULL; + if (ctx->enc_count != 0) { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + break; + } + ctx->head->field = ++field; + if (field->type == NULL) { + --ctx->head; + field = ctx->head->field; + continue; + } else if (field->type->typegroup == 'S') { + size_t parent_offset = ctx->head->parent_offset + field->offset; + if (field->type->fields->type == NULL) continue; + field = field->type->fields; + ++ctx->head; + ctx->head->field = field; + ctx->head->parent_offset = parent_offset; + break; + } else { + break; + } + } + } while (ctx->enc_count); + ctx->enc_type = 0; + ctx->is_complex = 0; + return 0; +} +static int +__pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) +{ + const char *ts = *tsp; + int i = 0, number, ndim; + ++ts; + if (ctx->new_count != 1) { + PyErr_SetString(PyExc_ValueError, + "Cannot handle repeated arrays in format string"); + return -1; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return -1; + ndim = ctx->head->field->type->ndim; + while (*ts && *ts != ')') { + switch (*ts) { + case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; + default: break; + } + number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return -1; + if (i < ndim && (size_t) number != ctx->head->field->type->arraysize[i]) { + PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %d", + ctx->head->field->type->arraysize[i], number); + return -1; + } + if (*ts != ',' && *ts != ')') { + PyErr_Format(PyExc_ValueError, + "Expected a comma in format string, got '%c'", *ts); + return -1; + } + if (*ts == ',') ts++; + i++; + } + if (i != ndim) { + PyErr_Format(PyExc_ValueError, "Expected %d dimension(s), got %d", + ctx->head->field->type->ndim, i); + return -1; + } + if (!*ts) { + PyErr_SetString(PyExc_ValueError, + "Unexpected end of format string, expected ')'"); + return -1; + } + ctx->is_valid_array = 1; + ctx->new_count = 1; + *tsp = ++ts; + return 0; +} +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) { + int got_Z = 0; + while (1) { + switch(*ts) { + case 0: + if (ctx->enc_type != 0 && ctx->head == NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + if (ctx->head != NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + return ts; + case ' ': + case '\r': + case '\n': + ++ts; + break; + case '<': + if (!__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '>': + case '!': + if (__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '=': + case '@': + case '^': + ctx->new_packmode = *ts++; + break; + case 'T': + { + const char* ts_after_sub; + size_t i, struct_count = ctx->new_count; + size_t struct_alignment = ctx->struct_alignment; + ctx->new_count = 1; + ++ts; + if (*ts != '{') { + PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'"); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + ctx->enc_count = 0; + ctx->struct_alignment = 0; + ++ts; + ts_after_sub = ts; + for (i = 0; i != struct_count; ++i) { + ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts); + if (!ts_after_sub) return NULL; + } + ts = ts_after_sub; + if (struct_alignment) ctx->struct_alignment = struct_alignment; + } + break; + case '}': + { + size_t alignment = ctx->struct_alignment; + ++ts; + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + if (alignment && ctx->fmt_offset % alignment) { + ctx->fmt_offset += alignment - (ctx->fmt_offset % alignment); + } + } + return ts; + case 'x': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->fmt_offset += ctx->new_count; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->enc_packmode = ctx->new_packmode; + ++ts; + break; + case 'Z': + got_Z = 1; + ++ts; + if (*ts != 'f' && *ts != 'd' && *ts != 'g') { + __Pyx_BufFmt_RaiseUnexpectedChar('Z'); + return NULL; + } + CYTHON_FALLTHROUGH; + case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': + case 'l': case 'L': case 'q': case 'Q': + case 'f': case 'd': case 'g': + case 'O': case 'p': + if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && + (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { + ctx->enc_count += ctx->new_count; + ctx->new_count = 1; + got_Z = 0; + ++ts; + break; + } + CYTHON_FALLTHROUGH; + case 's': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_count = ctx->new_count; + ctx->enc_packmode = ctx->new_packmode; + ctx->enc_type = *ts; + ctx->is_complex = got_Z; + ++ts; + ctx->new_count = 1; + got_Z = 0; + break; + case ':': + ++ts; + while(*ts != ':') ++ts; + ++ts; + break; + case '(': + if (__pyx_buffmt_parse_array(ctx, &ts) < 0) return NULL; + break; + default: + { + int number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return NULL; + ctx->new_count = (size_t)number; + } + } + } +} + +/* TypeInfoCompare */ + static int +__pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b) +{ + int i; + if (!a || !b) + return 0; + if (a == b) + return 1; + if (a->size != b->size || a->typegroup != b->typegroup || + a->is_unsigned != b->is_unsigned || a->ndim != b->ndim) { + if (a->typegroup == 'H' || b->typegroup == 'H') { + return a->size == b->size; + } else { + return 0; + } + } + if (a->ndim) { + for (i = 0; i < a->ndim; i++) + if (a->arraysize[i] != b->arraysize[i]) + return 0; + } + if (a->typegroup == 'S') { + if (a->flags != b->flags) + return 0; + if (a->fields || b->fields) { + if (!(a->fields && b->fields)) + return 0; + for (i = 0; a->fields[i].type && b->fields[i].type; i++) { + __Pyx_StructField *field_a = a->fields + i; + __Pyx_StructField *field_b = b->fields + i; + if (field_a->offset != field_b->offset || + !__pyx_typeinfo_cmp(field_a->type, field_b->type)) + return 0; + } + return !a->fields[i].type && !b->fields[i].type; + } + } + return 1; +} + +/* MemviewSliceValidateAndInit */ + static int +__pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec) +{ + if (buf->shape[dim] <= 1) + return 1; + if (buf->strides) { + if (spec & __Pyx_MEMVIEW_CONTIG) { + if (spec & (__Pyx_MEMVIEW_PTR|__Pyx_MEMVIEW_FULL)) { + if (unlikely(buf->strides[dim] != sizeof(void *))) { + PyErr_Format(PyExc_ValueError, + "Buffer is not indirectly contiguous " + "in dimension %d.", dim); + goto fail; + } + } else if (unlikely(buf->strides[dim] != buf->itemsize)) { + PyErr_SetString(PyExc_ValueError, + "Buffer and memoryview are not contiguous " + "in the same dimension."); + goto fail; + } + } + if (spec & __Pyx_MEMVIEW_FOLLOW) { + Py_ssize_t stride = buf->strides[dim]; + if (stride < 0) + stride = -stride; + if (unlikely(stride < buf->itemsize)) { + PyErr_SetString(PyExc_ValueError, + "Buffer and memoryview are not contiguous " + "in the same dimension."); + goto fail; + } + } + } else { + if (unlikely(spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1)) { + PyErr_Format(PyExc_ValueError, + "C-contiguous buffer is not contiguous in " + "dimension %d", dim); + goto fail; + } else if (unlikely(spec & (__Pyx_MEMVIEW_PTR))) { + PyErr_Format(PyExc_ValueError, + "C-contiguous buffer is not indirect in " + "dimension %d", dim); + goto fail; + } else if (unlikely(buf->suboffsets)) { + PyErr_SetString(PyExc_ValueError, + "Buffer exposes suboffsets but no strides"); + goto fail; + } + } + return 1; +fail: + return 0; +} +static int +__pyx_check_suboffsets(Py_buffer *buf, int dim, int ndim, int spec) +{ + CYTHON_UNUSED_VAR(ndim); + if (spec & __Pyx_MEMVIEW_DIRECT) { + if (unlikely(buf->suboffsets && buf->suboffsets[dim] >= 0)) { + PyErr_Format(PyExc_ValueError, + "Buffer not compatible with direct access " + "in dimension %d.", dim); + goto fail; + } + } + if (spec & __Pyx_MEMVIEW_PTR) { + if (unlikely(!buf->suboffsets || (buf->suboffsets[dim] < 0))) { + PyErr_Format(PyExc_ValueError, + "Buffer is not indirectly accessible " + "in dimension %d.", dim); + goto fail; + } + } + return 1; +fail: + return 0; +} +static int +__pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag) +{ + int i; + if (c_or_f_flag & __Pyx_IS_F_CONTIG) { + Py_ssize_t stride = 1; + for (i = 0; i < ndim; i++) { + if (unlikely(stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1)) { + PyErr_SetString(PyExc_ValueError, + "Buffer not fortran contiguous."); + goto fail; + } + stride = stride * buf->shape[i]; + } + } else if (c_or_f_flag & __Pyx_IS_C_CONTIG) { + Py_ssize_t stride = 1; + for (i = ndim - 1; i >- 1; i--) { + if (unlikely(stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1)) { + PyErr_SetString(PyExc_ValueError, + "Buffer not C contiguous."); + goto fail; + } + stride = stride * buf->shape[i]; + } + } + return 1; +fail: + return 0; +} +static int __Pyx_ValidateAndInit_memviewslice( + int *axes_specs, + int c_or_f_flag, + int buf_flags, + int ndim, + __Pyx_TypeInfo *dtype, + __Pyx_BufFmt_StackElem stack[], + __Pyx_memviewslice *memviewslice, + PyObject *original_obj) +{ + struct __pyx_memoryview_obj *memview, *new_memview; + __Pyx_RefNannyDeclarations + Py_buffer *buf; + int i, spec = 0, retval = -1; + __Pyx_BufFmt_Context ctx; + int from_memoryview = __pyx_memoryview_check(original_obj); + __Pyx_RefNannySetupContext("ValidateAndInit_memviewslice", 0); + if (from_memoryview && __pyx_typeinfo_cmp(dtype, ((struct __pyx_memoryview_obj *) + original_obj)->typeinfo)) { + memview = (struct __pyx_memoryview_obj *) original_obj; + new_memview = NULL; + } else { + memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( + original_obj, buf_flags, 0, dtype); + new_memview = memview; + if (unlikely(!memview)) + goto fail; + } + buf = &memview->view; + if (unlikely(buf->ndim != ndim)) { + PyErr_Format(PyExc_ValueError, + "Buffer has wrong number of dimensions (expected %d, got %d)", + ndim, buf->ndim); + goto fail; + } + if (new_memview) { + __Pyx_BufFmt_Init(&ctx, stack, dtype); + if (unlikely(!__Pyx_BufFmt_CheckString(&ctx, buf->format))) goto fail; + } + if (unlikely((unsigned) buf->itemsize != dtype->size)) { + PyErr_Format(PyExc_ValueError, + "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "u byte%s) " + "does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "u byte%s)", + buf->itemsize, + (buf->itemsize > 1) ? "s" : "", + dtype->name, + dtype->size, + (dtype->size > 1) ? "s" : ""); + goto fail; + } + if (buf->len > 0) { + for (i = 0; i < ndim; i++) { + spec = axes_specs[i]; + if (unlikely(!__pyx_check_strides(buf, i, ndim, spec))) + goto fail; + if (unlikely(!__pyx_check_suboffsets(buf, i, ndim, spec))) + goto fail; + } + if (unlikely(buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))) + goto fail; + } + if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice, + new_memview != NULL) == -1)) { + goto fail; + } + retval = 0; + goto no_fail; +fail: + Py_XDECREF(new_memview); + retval = -1; +no_fail: + __Pyx_RefNannyFinishContext(); + return retval; +} + +/* ObjectToMemviewSlice */ + static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(PyObject *obj, int writable_flag) { + __Pyx_memviewslice result = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_BufFmt_StackElem stack[1]; + int axes_specs[] = { (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_FOLLOW), (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_CONTIG) }; + int retcode; + if (obj == Py_None) { + result.memview = (struct __pyx_memoryview_obj *) Py_None; + return result; + } + retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, __Pyx_IS_C_CONTIG, + (PyBUF_C_CONTIGUOUS | PyBUF_FORMAT) | writable_flag, 2, + &__Pyx_TypeInfo_double, stack, + &result, obj); + if (unlikely(retcode == -1)) + goto __pyx_fail; + return result; +__pyx_fail: + result.memview = NULL; + result.data = NULL; + return result; +} + +/* MemviewSliceCopyTemplate */ + static __Pyx_memviewslice +__pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, + const char *mode, int ndim, + size_t sizeof_dtype, int contig_flag, + int dtype_is_object) +{ + __Pyx_RefNannyDeclarations + int i; + __Pyx_memviewslice new_mvs = { 0, 0, { 0 }, { 0 }, { 0 } }; + struct __pyx_memoryview_obj *from_memview = from_mvs->memview; + Py_buffer *buf = &from_memview->view; + PyObject *shape_tuple = NULL; + PyObject *temp_int = NULL; + struct __pyx_array_obj *array_obj = NULL; + struct __pyx_memoryview_obj *memview_obj = NULL; + __Pyx_RefNannySetupContext("__pyx_memoryview_copy_new_contig", 0); + for (i = 0; i < ndim; i++) { + if (unlikely(from_mvs->suboffsets[i] >= 0)) { + PyErr_Format(PyExc_ValueError, "Cannot copy memoryview slice with " + "indirect dimensions (axis %d)", i); + goto fail; + } + } + shape_tuple = PyTuple_New(ndim); + if (unlikely(!shape_tuple)) { + goto fail; + } + __Pyx_GOTREF(shape_tuple); + for(i = 0; i < ndim; i++) { + temp_int = PyInt_FromSsize_t(from_mvs->shape[i]); + if(unlikely(!temp_int)) { + goto fail; + } else { + PyTuple_SET_ITEM(shape_tuple, i, temp_int); + temp_int = NULL; + } + } + array_obj = __pyx_array_new(shape_tuple, sizeof_dtype, buf->format, (char *) mode, NULL); + if (unlikely(!array_obj)) { + goto fail; + } + __Pyx_GOTREF(array_obj); + memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( + (PyObject *) array_obj, contig_flag, + dtype_is_object, + from_mvs->memview->typeinfo); + if (unlikely(!memview_obj)) + goto fail; + if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs, 1) < 0)) + goto fail; + if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim, + dtype_is_object) < 0)) + goto fail; + goto no_fail; +fail: + __Pyx_XDECREF(new_mvs.memview); + new_mvs.memview = NULL; + new_mvs.data = NULL; +no_fail: + __Pyx_XDECREF(shape_tuple); + __Pyx_XDECREF(temp_int); + __Pyx_XDECREF(array_obj); + __Pyx_RefNannyFinishContext(); + return new_mvs; +} + +/* MemviewSliceInit */ + static int +__Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview, + int ndim, + __Pyx_memviewslice *memviewslice, + int memview_is_new_reference) +{ + __Pyx_RefNannyDeclarations + int i, retval=-1; + Py_buffer *buf = &memview->view; + __Pyx_RefNannySetupContext("init_memviewslice", 0); + if (unlikely(memviewslice->memview || memviewslice->data)) { + PyErr_SetString(PyExc_ValueError, + "memviewslice is already initialized!"); + goto fail; + } + if (buf->strides) { + for (i = 0; i < ndim; i++) { + memviewslice->strides[i] = buf->strides[i]; + } + } else { + Py_ssize_t stride = buf->itemsize; + for (i = ndim - 1; i >= 0; i--) { + memviewslice->strides[i] = stride; + stride *= buf->shape[i]; + } + } + for (i = 0; i < ndim; i++) { + memviewslice->shape[i] = buf->shape[i]; + if (buf->suboffsets) { + memviewslice->suboffsets[i] = buf->suboffsets[i]; + } else { + memviewslice->suboffsets[i] = -1; + } + } + memviewslice->memview = memview; + memviewslice->data = (char *)buf->buf; + if (__pyx_add_acquisition_count(memview) == 0 && !memview_is_new_reference) { + Py_INCREF(memview); + } + retval = 0; + goto no_fail; +fail: + memviewslice->memview = 0; + memviewslice->data = 0; + retval = -1; +no_fail: + __Pyx_RefNannyFinishContext(); + return retval; +} +#ifndef Py_NO_RETURN +#define Py_NO_RETURN +#endif +static void __pyx_fatalerror(const char *fmt, ...) Py_NO_RETURN { + va_list vargs; + char msg[200]; +#if PY_VERSION_HEX >= 0x030A0000 || defined(HAVE_STDARG_PROTOTYPES) + va_start(vargs, fmt); +#else + va_start(vargs); +#endif + vsnprintf(msg, 200, fmt, vargs); + va_end(vargs); + Py_FatalError(msg); +} +static CYTHON_INLINE int +__pyx_add_acquisition_count_locked(__pyx_atomic_int_type *acquisition_count, + PyThread_type_lock lock) +{ + int result; + PyThread_acquire_lock(lock, 1); + result = (*acquisition_count)++; + PyThread_release_lock(lock); + return result; +} +static CYTHON_INLINE int +__pyx_sub_acquisition_count_locked(__pyx_atomic_int_type *acquisition_count, + PyThread_type_lock lock) +{ + int result; + PyThread_acquire_lock(lock, 1); + result = (*acquisition_count)--; + PyThread_release_lock(lock); + return result; +} +static CYTHON_INLINE void +__Pyx_INC_MEMVIEW(__Pyx_memviewslice *memslice, int have_gil, int lineno) +{ + __pyx_nonatomic_int_type old_acquisition_count; + struct __pyx_memoryview_obj *memview = memslice->memview; + if (unlikely(!memview || (PyObject *) memview == Py_None)) { + return; + } + old_acquisition_count = __pyx_add_acquisition_count(memview); + if (unlikely(old_acquisition_count <= 0)) { + if (likely(old_acquisition_count == 0)) { + if (have_gil) { + Py_INCREF((PyObject *) memview); + } else { + PyGILState_STATE _gilstate = PyGILState_Ensure(); + Py_INCREF((PyObject *) memview); + PyGILState_Release(_gilstate); + } + } else { + __pyx_fatalerror("Acquisition count is %d (line %d)", + old_acquisition_count+1, lineno); + } + } +} +static CYTHON_INLINE void __Pyx_XCLEAR_MEMVIEW(__Pyx_memviewslice *memslice, + int have_gil, int lineno) { + __pyx_nonatomic_int_type old_acquisition_count; + struct __pyx_memoryview_obj *memview = memslice->memview; + if (unlikely(!memview || (PyObject *) memview == Py_None)) { + memslice->memview = NULL; + return; + } + old_acquisition_count = __pyx_sub_acquisition_count(memview); + memslice->data = NULL; + if (likely(old_acquisition_count > 1)) { + memslice->memview = NULL; + } else if (likely(old_acquisition_count == 1)) { + if (have_gil) { + Py_CLEAR(memslice->memview); + } else { + PyGILState_STATE _gilstate = PyGILState_Ensure(); + Py_CLEAR(memslice->memview); + PyGILState_Release(_gilstate); + } + } else { + __pyx_fatalerror("Acquisition count is %d (line %d)", + old_acquisition_count-1, lineno); + } +} + +/* CIntFromPy */ + static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ + static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ + static CYTHON_INLINE char __Pyx_PyInt_As_char(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const char neg_one = (char) -1, const_zero = (char) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(char) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(char, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (char) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + char val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (char) -1; + val = __Pyx_PyInt_As_char(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(char, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(char) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 2 * PyLong_SHIFT)) { + return (char) (((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(char) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 3 * PyLong_SHIFT)) { + return (char) (((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(char) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 4 * PyLong_SHIFT)) { + return (char) (((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (char) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(char) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(char, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(char) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(char, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(char, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(char) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(char) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + return (char) ((((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(char) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + return (char) ((((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 4 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(char) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 4 * PyLong_SHIFT)) { + return (char) ((((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(char) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(char, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(char) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(char, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + char val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (char) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (char) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (char) -1; + } else { + stepval = v; + } + v = NULL; + val = (char) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(char) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((char) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(char) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((char) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((char) 1) << (sizeof(char) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (char) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to char"); + return (char) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to char"); + return (char) -1; +} + +/* FormatTypeName */ + #if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name_2); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__96); + } + return name; +} +#endif + +/* PyObjectCall2Args */ + static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 */ + #if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2 + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_GetMethod; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* CoroutineBase */ + #include +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } +#if PY_VERSION_HEX >= 0x030300A0 + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); + } +#endif + else if (unlikely(PyTuple_Check(ev))) { + if (PyTuple_GET_SIZE(ev) >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#else + value = PySequence_ITEM(ev, 0); +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if PY_VERSION_HEX >= 0x030300A0 + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); +#else + { + PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args); + Py_DECREF(ev); + if (likely(args)) { + value = PySequence_GetItem(args, 0); + Py_DECREF(args); + } + if (unlikely(!value)) { + __Pyx_ErrRestore(NULL, NULL, NULL); + Py_INCREF(Py_None); + value = Py_None; + } + } +#endif + *pvalue = value; + return 0; +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +#define __Pyx_Coroutine_NotStartedError(gen) (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_NotStartedError(PyObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(gen)) { + msg = "can't send non-None value to a just-started coroutine"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a just-started async generator"; + #endif + } else { + msg = "can't send non-None value to a just-started generator"; + } + PyErr_SetString(PyExc_TypeError, msg); +} +#define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing) (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(!self->is_running); + if (unlikely(self->resume_label == 0)) { + if (unlikely(value && value != Py_None)) { + return __Pyx_Coroutine_NotStartedError((PyObject*)self); + } + } + if (unlikely(self->resume_label == -1)) { + return __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + self->is_running = 1; + retval = self->body(self, tstate, value); + self->is_running = 0; +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + return retval; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_MethodReturn(PyObject* gen, PyObject *retval) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (unlikely(!retval)) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (!__Pyx_PyErr_Occurred()) { + PyObject *exc = PyExc_StopIteration; + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + exc = __Pyx_PyExc_StopAsyncIteration; + #endif + __Pyx_PyErr_SetNone(exc); + } + } + return retval; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) { + PyObject *ret; + PyObject *val = NULL; + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + ret = __Pyx_Coroutine_SendEx(gen, val, 0); + Py_XDECREF(val); + return ret; +} +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03050000 && defined(PyCoro_CheckExact) && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + { + if (value == Py_None) + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + else + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value); + } + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + retval = __Pyx_Coroutine_FinishDelegation(gen); + } else { + retval = __Pyx_Coroutine_SendEx(gen, value, 0); + } + return __Pyx_Coroutine_MethodReturn(self, retval); +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + PyObject *retval = NULL; + int err = 0; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + retval = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf, NULL); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + } else + #endif + { + PyObject *meth; + gen->is_running = 1; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) + err = -1; + } + gen->is_running = 0; + } + Py_XDECREF(retval); + return err; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + return __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_SendEx(gen, Py_None, 0); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + return __Pyx_Coroutine_Close(self); +} +static PyObject *__Pyx_Coroutine_Close(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *retval, *raised_exception; + PyObject *yf = gen->yieldfrom; + int err = 0; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = __Pyx_Coroutine_SendEx(gen, NULL, 1); + if (unlikely(retval)) { + const char *msg; + Py_DECREF(retval); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { +#if PY_VERSION_HEX < 0x03060000 + msg = "async generator ignored GeneratorExit - might require Python 3.6+ finalisation (PEP 525)"; +#else + msg = "async generator ignored GeneratorExit"; +#endif + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + return NULL; + } + raised_exception = PyErr_Occurred(); + if (likely(!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration))) { + if (raised_exception) PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); + goto throw_here; + } + gen->is_running = 1; + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + gen->is_running = 0; + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + gen->is_running = 0; + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + gen->is_running = 0; + Py_DECREF(yf); + if (!ret) { + ret = __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_MethodReturn(self, ret); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + Py_CLEAR(gen->yieldfrom); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if PY_VERSION_HEX >= 0x030400a1 && CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + Py_TYPE(gen)->tp_del(self); + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } +#if !CYTHON_USE_TP_FINALIZE + assert(self->ob_refcnt == 0); + __Pyx_SET_REFCNT(self, 1); +#endif + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); +#if PY_MAJOR_VERSION >= 3 || defined(PyErr_WarnFormat) + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); +#else + {PyObject *msg; + char *cmsg; + #if CYTHON_COMPILING_IN_PYPY + msg = NULL; + cmsg = (char*) "coroutine was never awaited"; + #else + char *cname; + PyObject *qualname; + qualname = gen->gi_qualname; + cname = PyString_AS_STRING(qualname); + msg = PyString_FromFormat("coroutine '%.50s' was never awaited", cname); + if (unlikely(!msg)) { + PyErr_Clear(); + cmsg = (char*) "coroutine was never awaited"; + } else { + cmsg = PyString_AS_STRING(msg); + } + #endif + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, cmsg, 1) < 0)) + PyErr_WriteUnraisable(self); + Py_XDECREF(msg);} +#endif + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *res = __Pyx_Coroutine_Close(self); + if (unlikely(!res)) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +#if !CYTHON_USE_TP_FINALIZE + assert(Py_REFCNT(self) > 0); + if (likely(--self->ob_refcnt == 0)) { + return; + } + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReference(self); + __Pyx_SET_REFCNT(self, refcnt); + } +#if CYTHON_COMPILING_IN_CPYTHON + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + _Py_DEC_REFTOTAL; +#endif +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif +#endif +} +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) +{ + PyObject *frame = self->gi_frame; + CYTHON_UNUSED_VAR(context); + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (unlikely(!frame)) + return NULL; + self->gi_frame = frame; + } + Py_INCREF(frame); + return frame; +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif + gen->gi_weakreflist = NULL; + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} + +/* PatchModuleWithCoroutine */ + static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + int result; + PyObject *globals, *result_obj; + globals = PyDict_New(); if (unlikely(!globals)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_coroutine_type", + #ifdef __Pyx_Coroutine_USED + (PyObject*)__pyx_CoroutineType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_generator_type", + #ifdef __Pyx_Generator_USED + (PyObject*)__pyx_GeneratorType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore; + result_obj = PyRun_String(py_code, Py_file_input, globals, globals); + if (unlikely(!result_obj)) goto ignore; + Py_DECREF(result_obj); + Py_DECREF(globals); + return module; +ignore: + Py_XDECREF(globals); + PyErr_WriteUnraisable(module); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) { + Py_DECREF(module); + module = NULL; + } +#else + py_code++; +#endif + return module; +} + +/* PatchGeneratorABC */ + #ifndef CYTHON_REGISTER_ABCS +#define CYTHON_REGISTER_ABCS 1 +#endif +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) +static PyObject* __Pyx_patch_abc_module(PyObject *module); +static PyObject* __Pyx_patch_abc_module(PyObject *module) { + module = __Pyx_Coroutine_patch_module( + module, "" +"if _cython_generator_type is not None:\n" +" try: Generator = _module.Generator\n" +" except AttributeError: pass\n" +" else: Generator.register(_cython_generator_type)\n" +"if _cython_coroutine_type is not None:\n" +" try: Coroutine = _module.Coroutine\n" +" except AttributeError: pass\n" +" else: Coroutine.register(_cython_coroutine_type)\n" + ); + return module; +} +#endif +static int __Pyx_patch_abc(void) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + static int abc_patched = 0; + if (CYTHON_REGISTER_ABCS && !abc_patched) { + PyObject *module; + module = PyImport_ImportModule((PY_MAJOR_VERSION >= 3) ? "collections.abc" : "collections"); + if (unlikely(!module)) { + PyErr_WriteUnraisable(NULL); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, + ((PY_MAJOR_VERSION >= 3) ? + "Cython module failed to register with collections.abc module" : + "Cython module failed to register with collections module"), 1) < 0)) { + return -1; + } + } else { + module = __Pyx_patch_abc_module(module); + abc_patched = 1; + if (unlikely(!module)) + return -1; + Py_DECREF(module); + } + module = PyImport_ImportModule("backports_abc"); + if (module) { + module = __Pyx_patch_abc_module(module); + Py_XDECREF(module); + } + if (!module) { + PyErr_Clear(); + } + } +#else + if ((0)) __Pyx_Coroutine_patch_module(NULL, NULL); +#endif + return 0; +} + +/* Generator */ + static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL}, + {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, + {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + (char*) PyDoc_STR("name of the generator"), 0}, + {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + (char*) PyDoc_STR("qualified name of the generator"), 0}, + {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + (char*) PyDoc_STR("Frame of the generator"), 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + __pyx_GeneratorType_slots +}; +#else +static PyTypeObject __pyx_GeneratorType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + (destructor) __Pyx_Coroutine_dealloc, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + 0, + (traverseproc) __Pyx_Coroutine_traverse, + 0, + 0, + offsetof(__pyx_CoroutineObject, gi_weakreflist), + 0, + (iternextfunc) __Pyx_Generator_Next, + __pyx_Generator_methods, + __pyx_Generator_memberlist, + __pyx_Generator_getsets, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if CYTHON_USE_TP_FINALIZE + 0, +#else + __Pyx_Coroutine_del, +#endif + 0, +#if CYTHON_USE_TP_FINALIZE + __Pyx_Coroutine_del, +#elif PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; + __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif + if (unlikely(!__pyx_GeneratorType)) { + return -1; + } + return 0; +} + +/* CheckBinaryVersion */ + static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ + #ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ + #if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.cpython-312-darwin.so new file mode 100755 index 0000000..09c5ecf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pxd b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pxd new file mode 100644 index 0000000..a6a1c43 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pxd @@ -0,0 +1,15 @@ +# cython: language_level=3 +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from .vector cimport Vec3 + +cdef class Matrix44: + cdef double m[16] + cdef Vec3 get_ux(self: Matrix44) + cdef Vec3 get_uy(self: Matrix44) + cdef Vec3 get_uz(self: Matrix44) + +cdef inline swap(double *a, double *b): + cdef double tmp = a[0] + a[0] = b[0] + b[0] = tmp \ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pyx new file mode 100644 index 0000000..a2ca6a7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/matrix44.pyx @@ -0,0 +1,676 @@ +# cython: language_level=3 +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from typing import Sequence, Iterable, Tuple, TYPE_CHECKING, Iterator +from itertools import chain +import math +import numpy as np +import cython + +from .vector cimport ( +Vec2, Vec3, v3_normalize, v3_isclose, v3_cross, v3_dot, +) +from .vector import X_AXIS, Y_AXIS, Z_AXIS, NULLVEC + +from libc.math cimport fabs, sin, cos, tan + +if TYPE_CHECKING: + from ezdxf.math import UVec + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + +cdef double[16] IDENTITY = [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 +] + +cdef void set_floats(double *m, object values) except *: + cdef int i = 0 + for v in values: + if i < 16: # Do not write beyond array bounds + m[i] = v + i += 1 + if i != 16: + raise ValueError("invalid argument count") + +cdef class Matrix44: + def __cinit__(self, *args): + cdef int nargs = len(args) + if nargs == 0: # default constructor Matrix44(): fastest setup + self.m = IDENTITY # memcopy! + elif nargs == 1: # 16 numbers: slow setup + set_floats(self.m, args[0]) + elif nargs == 4: # 4 rows of 4 numbers: slowest setup + set_floats(self.m, chain(*args)) + else: + raise ValueError("invalid argument count: 4 row vectors or " + "iterable of 16 numbers") + + def __reduce__(self): + return Matrix44, (tuple(self),) + + def __getitem__(self, tuple index) -> float: + cdef int row = index[0] + cdef int col = index[1] + cdef int i = row * 4 + col + + if 0 <= i < 16 and 0 <= col < 4: + return self.m[i] + else: + raise IndexError(f'index out of range: {index}') + + def __setitem__(self, tuple index, double value): + cdef int row = index[0] + cdef int col = index[1] + cdef int i = row * 4 + col + + if 0 <= i < 16 and 0 <= col < 4: + self.m[i] = value + else: + raise IndexError(f'index out of range: {index}') + + def __iter__(self): + cdef int i + for i in range(16): + yield self.m[i] + + def __repr__(self) -> str: + def format_row(row): + return "(%s)" % ", ".join(str(value) for value in row) + + return "Matrix44(%s)" % \ + ", ".join(format_row(row) for row in self.rows()) + + def get_2d_transformation(self) -> Tuple[float, ...]: + cdef double *m = self.m + return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + + @staticmethod + def from_2d_transformation(components: Sequence[float]) -> Matrix44: + if len(components) != 6: + raise ValueError( + "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + ) + + m44 = Matrix44() + m44.m[0] = components[0] + m44.m[1] = components[1] + m44.m[4] = components[2] + m44.m[5] = components[3] + m44.m[12] = components[4] + m44.m[13] = components[5] + return m44 + + def get_row(self, int row) -> Tuple[float, ...]: + cdef int index = row * 4 + if 0 <= index < 13: + return self.m[index], self.m[index + 1], self.m[index + 2], self.m[ + index + 3] + else: + raise IndexError(f'invalid row index: {row}') + + def set_row(self, int row, values: Sequence[float]) -> None: + cdef Py_ssize_t count = len(values) + cdef Py_ssize_t start = row * 4 + cdef Py_ssize_t i + if 0 <= row < 4: + if count > 4: + count = 4 + for i in range(count): + self.m[start + i] = values[i] + else: + raise IndexError(f'invalid row index: {row}') + + def get_col(self, int col) -> Tuple[float, ...]: + if 0 <= col < 4: + return self.m[col], self.m[col + 4], \ + self.m[col + 8], self.m[col + 12] + else: + raise IndexError(f'invalid col index: {col}') + + def set_col(self, int col, values: Sequence[float]): + cdef Py_ssize_t count = len(values) + cdef Py_ssize_t i + if 0 <= col < 4: + if count > 4: + count = 4 + for i in range(count): + self.m[col + i * 4] = values[i] + else: + raise IndexError(f'invalid col index: {col}') + + def rows(self) -> Iterator[Tuple[float, ...]]: + return (self.get_row(index) for index in (0, 1, 2, 3)) + + def columns(self) -> Iterator[Tuple[float, ...]]: + return (self.get_col(index) for index in (0, 1, 2, 3)) + + def copy(self) -> Matrix44: + cdef Matrix44 _copy = Matrix44() + _copy.m = self.m + return _copy + + __copy__ = copy + + @property + def origin(self) -> Vec3: + cdef Vec3 v = Vec3() + v.x = self.m[12] + v.y = self.m[13] + v.z = self.m[14] + return v + + @origin.setter + def origin(self, v: UVec) -> None: + cdef Vec3 origin = Vec3(v) + self.m[12] = origin.x + self.m[13] = origin.y + self.m[14] = origin.z + + @property + def ux(self) -> Vec3: + return self.get_ux() + + cdef Vec3 get_ux(self): + cdef Vec3 v = Vec3() + v.x = self.m[0] + v.y = self.m[1] + v.z = self.m[2] + return v + + @property + def uy(self) -> Vec3: + return self.get_uy() + + cdef Vec3 get_uy(self): + cdef Vec3 v = Vec3() + v.x = self.m[4] + v.y = self.m[5] + v.z = self.m[6] + return v + + @property + def uz(self) -> Vec3: + return self.get_uz() + + cdef Vec3 get_uz(self): + cdef Vec3 v = Vec3() + v.x = self.m[8] + v.y = self.m[9] + v.z = self.m[10] + return v + + @property + def is_cartesian(self) -> bool: + cdef Vec3 x_axis = v3_cross(self.get_uy(), self.get_uz()) + return v3_isclose(x_axis, self.get_ux(), REL_TOL, ABS_TOL) + + @property + def is_orthogonal(self) -> bool: + cdef Vec3 ux = v3_normalize(self.get_ux(), 1.0) + cdef Vec3 uy = v3_normalize(self.get_uy(), 1.0) + cdef Vec3 uz = v3_normalize(self.get_uz(), 1.0) + return fabs(v3_dot(ux, uy)) < 1e-9 and \ + fabs(v3_dot(ux, uz)) < 1e-9 and \ + fabs(v3_dot(uy, uz)) < 1e-9 + + @staticmethod + def scale(double sx, sy = None, sz = None) -> Matrix44: + cdef Matrix44 mat = Matrix44() + mat.m[0] = sx + mat.m[5] = sx if sy is None else sy + mat.m[10] = sx if sz is None else sz + return mat + + @staticmethod + def translate(double dx, double dy, double dz) -> Matrix44: + cdef Matrix44 mat = Matrix44() + mat.m[12] = dx + mat.m[13] = dy + mat.m[14] = dz + return mat + + @staticmethod + def x_rotate(double angle) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double cos_a = cos(angle) + cdef double sin_a = sin(angle) + mat.m[5] = cos_a + mat.m[6] = sin_a + mat.m[9] = -sin_a + mat.m[10] = cos_a + return mat + + @staticmethod + def y_rotate(double angle) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double cos_a = cos(angle) + cdef double sin_a = sin(angle) + mat.m[0] = cos_a + mat.m[2] = -sin_a + mat.m[8] = sin_a + mat.m[10] = cos_a + return mat + + @staticmethod + def z_rotate(double angle) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double cos_a = cos(angle) + cdef double sin_a = sin(angle) + mat.m[0] = cos_a + mat.m[1] = sin_a + mat.m[4] = -sin_a + mat.m[5] = cos_a + return mat + + @staticmethod + def axis_rotate(axis: UVec, double angle) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double cos_a = cos(angle) + cdef double sin_a = sin(angle) + cdef double one_m_cos = 1.0 - cos_a + cdef Vec3 _axis = Vec3(axis).normalize() + cdef double x = _axis.x + cdef double y = _axis.y + cdef double z = _axis.z + + mat.m[0] = x * x * one_m_cos + cos_a + mat.m[1] = y * x * one_m_cos + z * sin_a + mat.m[2] = x * z * one_m_cos - y * sin_a + + mat.m[4] = x * y * one_m_cos - z * sin_a + mat.m[5] = y * y * one_m_cos + cos_a + mat.m[6] = y * z * one_m_cos + x * sin_a + + mat.m[8] = x * z * one_m_cos + y * sin_a + mat.m[9] = y * z * one_m_cos - x * sin_a + mat.m[10] = z * z * one_m_cos + cos_a + + return mat + + @staticmethod + def xyz_rotate(double angle_x, double angle_y, + double angle_z) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double cx = cos(angle_x) + cdef double sx = sin(angle_x) + cdef double cy = cos(angle_y) + cdef double sy = sin(angle_y) + cdef double cz = cos(angle_z) + cdef double sz = sin(angle_z) + cdef double sxsy = sx * sy + cdef double cxsy = cx * sy + + mat.m[0] = cy * cz + mat.m[1] = sxsy * cz + cx * sz + mat.m[2] = -cxsy * cz + sx * sz + mat.m[4] = -cy * sz + mat.m[5] = -sxsy * sz + cx * cz + mat.m[6] = cxsy * sz + sx * cz + mat.m[8] = sy + mat.m[9] = -sx * cy + mat.m[10] = cx * cy + return mat + + @staticmethod + def shear_xy(double angle_x = 0, double angle_y = 0) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef double tx = tan(angle_x) + cdef double ty = tan(angle_y) + mat.m[1] = ty + mat.m[4] = tx + return mat + + @staticmethod + def perspective_projection(double left, double right, double top, + double bottom, double near, + double far) -> Matrix44: + cdef Matrix44 mat = Matrix44() + mat.m[0] = (2. * near) / (right - left) + mat.m[5] = (2. * near) / (top - bottom) + mat.m[8] = (right + left) / (right - left) + mat.m[9] = (top + bottom) / (top - bottom) + mat.m[10] = -((far + near) / (far - near)) + mat.m[11] = -1 + mat.m[14] = -((2. * far * near) / (far - near)) + return mat + + @staticmethod + def perspective_projection_fov(fov: float, aspect: float, near: float, + far: float) -> Matrix44: + vrange = near * math.tan(fov / 2.) + left = -vrange * aspect + right = vrange * aspect + bottom = -vrange + top = vrange + return Matrix44.perspective_projection(left, right, bottom, top, near, + far) + + @staticmethod + def chain(*matrices: Matrix44) -> Matrix44: + cdef Matrix44 transformation = Matrix44() + for matrix in matrices: + transformation *= matrix + return transformation + + def __imul__(self, Matrix44 other) -> Matrix44: + cdef double[16] m1 = self.m + cdef double *m2 = other.m + + self.m[0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[2] * m2[8] + \ + m1[3] * m2[12] + self.m[1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[2] * m2[9] + \ + m1[3] * m2[13] + self.m[2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[2] * m2[10] + \ + m1[3] * m2[14] + self.m[3] = m1[0] * m2[3] + m1[1] * m2[7] + m1[2] * m2[11] + \ + m1[3] * m2[15] + + self.m[4] = m1[4] * m2[0] + m1[5] * m2[4] + m1[6] * m2[8] + \ + m1[7] * m2[12] + self.m[5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[6] * m2[9] + \ + m1[7] * m2[13] + self.m[6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[6] * m2[10] + \ + m1[7] * m2[14] + self.m[7] = m1[4] * m2[3] + m1[5] * m2[7] + m1[6] * m2[11] + \ + m1[7] * m2[15] + + self.m[8] = m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[8] + \ + m1[11] * m2[12] + self.m[9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[9] + \ + m1[11] * m2[13] + self.m[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10] + \ + m1[11] * m2[14] + self.m[11] = m1[8] * m2[3] + m1[9] * m2[7] + m1[10] * m2[11] + \ + m1[11] * m2[15] + + self.m[12] = m1[12] * m2[0] + m1[13] * m2[4] + m1[14] * m2[8] + \ + m1[15] * m2[12] + self.m[13] = m1[12] * m2[1] + m1[13] * m2[5] + m1[14] * m2[9] + \ + m1[15] * m2[13] + self.m[14] = m1[12] * m2[2] + m1[13] * m2[6] + m1[14] * m2[10] + \ + m1[15] * m2[14] + self.m[15] = m1[12] * m2[3] + m1[13] * m2[7] + m1[14] * m2[11] + \ + m1[15] * m2[15] + return self + + def __mul__(self, Matrix44 other) -> Matrix44: + cdef Matrix44 res_matrix = self.copy() + return res_matrix.__imul__(other) + + # __matmul__ = __mul__ does not work! + + def __matmul__(self, Matrix44 other) -> Matrix44: + cdef Matrix44 res_matrix = self.copy() + return res_matrix.__imul__(other) + + def transpose(self) -> None: + swap(&self.m[1], &self.m[4]) + swap(&self.m[2], &self.m[8]) + swap(&self.m[3], &self.m[12]) + swap(&self.m[6], &self.m[9]) + swap(&self.m[7], &self.m[13]) + swap(&self.m[11], &self.m[14]) + + def determinant(self) -> float: + cdef double *m = self.m + return m[0] * m[5] * m[10] * m[15] - m[0] * m[5] * m[11] * m[14] + \ + m[0] * m[6] * m[11] * m[13] - m[0] * m[6] * m[9] * m[15] + \ + m[0] * m[7] * m[9] * m[14] - m[0] * m[7] * m[10] * m[13] - \ + m[1] * m[6] * m[11] * m[12] + m[1] * m[6] * m[8] * m[15] - \ + m[1] * m[7] * m[8] * m[14] + m[1] * m[7] * m[10] * m[12] - \ + m[1] * m[4] * m[10] * m[15] + m[1] * m[4] * m[11] * m[14] + \ + m[2] * m[7] * m[8] * m[13] - m[2] * m[7] * m[9] * m[12] + \ + m[2] * m[4] * m[9] * m[15] - m[2] * m[4] * m[11] * m[13] + \ + m[2] * m[5] * m[11] * m[12] - m[2] * m[5] * m[8] * m[15] - \ + m[3] * m[4] * m[9] * m[14] + m[3] * m[4] * m[10] * m[13] - \ + m[3] * m[5] * m[10] * m[12] + m[3] * m[5] * m[8] * m[14] - \ + m[3] * m[6] * m[8] * m[13] + m[3] * m[6] * m[9] * m[12] + + def inverse(self) -> None: + cdef double[16] m = self.m # memcopy + cdef double det = self.determinant() + cdef double f = 1. / det + self.m[0] = (m[6] * m[11] * m[13] - m[7] * m[10] * m[13] + m[7] * m[9] * + m[14] - m[5] * m[11] * m[14] - m[6] * m[9] * m[15] + m[5] * + m[10] * m[15]) * f + + self.m[1] = (m[3] * m[10] * m[13] - m[2] * m[11] * m[13] - m[3] * m[9] * + m[14] + m[1] * m[11] * m[14] + m[2] * m[9] * m[15] - + m[1] * m[10] * m[15]) * f + self.m[2] = (m[2] * m[7] * m[13] - m[3] * m[6] * m[13] + m[3] * m[5] * + m[14] - m[1] * m[7] * m[14] - m[2] * m[5] * m[15] + + m[1] * m[6] * m[15]) * f + + self.m[3] = (m[3] * m[6] * m[9] - m[2] * m[7] * m[9] - m[3] * m[5] * + m[10] + m[1] * m[7] * m[10] + m[2] * m[5] * m[11] - m[1] * + m[6] * m[11]) * f + + self.m[4] = (m[7] * m[10] * m[12] - m[6] * m[11] * m[12] - m[7] * m[8] * + m[14] + m[4] * m[11] * m[14] + m[6] * m[8] * m[15] - + m[4] * m[10] * m[15]) * f + + self.m[5] = (m[2] * m[11] * m[12] - m[3] * m[10] * m[12] + m[3] * m[8] * + m[14] - m[0] * m[11] * m[14] - m[2] * m[8] * m[15] + + m[0] * m[10] * m[15]) * f + + self.m[6] = (m[3] * m[6] * m[12] - m[2] * m[7] * m[12] - m[3] * m[4] * + m[14] + m[0] * m[7] * m[14] + m[2] * m[4] * m[15] - + m[0] * m[6] * m[15]) * f + + self.m[7] = (m[2] * m[7] * m[8] - m[3] * m[6] * m[8] + m[3] * m[4] * + m[10] - m[0] * m[7] * m[10] - m[2] * m[4] * m[11] + + m[0] * m[6] * m[11]) * f + + self.m[8] = (m[5] * m[11] * m[12] - m[7] * m[9] * m[12] + m[7] * m[8] * + m[13] - m[4] * m[11] * m[13] - m[5] * m[8] * m[15] + + m[4] * m[9] * m[15]) * f + + self.m[9] = (m[3] * m[9] * m[12] - m[1] * m[11] * m[12] - m[3] * + m[8] * m[13] + m[0] * m[11] * m[13] + m[1] * m[8] * + m[15] - m[0] * m[9] * m[15]) * f + + self.m[10] = (m[1] * m[7] * m[12] - m[3] * m[5] * m[12] + m[3] * + m[4] * m[13] - m[0] * m[7] * m[13] - m[1] * m[4] * + m[15] + m[0] * m[5] * m[15]) * f + + self.m[11] = (m[3] * m[5] * m[8] - m[1] * m[7] * m[8] - m[3] * m[4] * + m[9] + m[0] * m[7] * m[9] + m[1] * m[4] * m[11] - + m[0] * m[5] * m[11]) * f + + self.m[12] = (m[6] * m[9] * m[12] - m[5] * m[10] * m[12] - m[6] * + m[8] * m[13] + m[4] * m[10] * m[13] + m[5] * m[8] * + m[14] - m[4] * m[9] * m[14]) * f + + self.m[13] = (m[1] * m[10] * m[12] - m[2] * m[9] * m[12] + m[2] * + m[8] * m[13] - m[0] * m[10] * m[13] - m[1] * m[8] * + m[14] + m[0] * m[9] * m[14]) * f + + self.m[14] = (m[2] * m[5] * m[12] - m[1] * m[6] * m[12] - m[2] * + m[4] * m[13] + m[0] * m[6] * m[13] + m[1] * m[4] * + m[14] - m[0] * m[5] * m[14]) * f + + self.m[15] = (m[1] * m[6] * m[8] - m[2] * m[5] * m[8] + m[2] * m[4] * + m[9] - m[0] * m[6] * m[9] - m[1] * m[4] * m[10] + + m[0] * m[5] * m[10]) * f + + @staticmethod + def ucs(ux=X_AXIS, uy=Y_AXIS, uz=Z_AXIS, origin=NULLVEC) -> Matrix44: + cdef Matrix44 mat = Matrix44() + cdef Vec3 _ux = Vec3(ux) + cdef Vec3 _uy = Vec3(uy) + cdef Vec3 _uz = Vec3(uz) + cdef Vec3 _origin = Vec3(origin) + + mat.m[0] = _ux.x + mat.m[1] = _ux.y + mat.m[2] = _ux.z + + mat.m[4] = _uy.x + mat.m[5] = _uy.y + mat.m[6] = _uy.z + + mat.m[8] = _uz.x + mat.m[9] = _uz.y + mat.m[10] = _uz.z + + mat.m[12] = _origin.x + mat.m[13] = _origin.y + mat.m[14] = _origin.z + + return mat + + def transform(self, vector: UVec) -> Vec3: + cdef Vec3 res = Vec3(vector) + cdef double x = res.x + cdef double y = res.y + cdef double z = res.z + cdef double *m = self.m + + res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + return res + + def transform_direction(self, vector: UVec, normalize=False) -> Vec3: + cdef Vec3 res = Vec3(vector) + cdef double x = res.x + cdef double y = res.y + cdef double z = res.z + cdef double *m = self.m + + res.x = x * m[0] + y * m[4] + z * m[8] + res.y = x * m[1] + y * m[5] + z * m[9] + res.z = x * m[2] + y * m[6] + z * m[10] + if normalize: + return v3_normalize(res, 1.0) + else: + return res + + ocs_to_wcs = transform_direction + + def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: + cdef double *m = self.m + cdef Vec3 res + cdef double x, y, z + + for vector in vectors: + res = Vec3(vector) + x = res.x + y = res.y + z = res.z + + res.x = x * m[0] + y * m[4] + z * m[8] + m[12] + res.y = x * m[1] + y * m[5] + z * m[9] + m[13] + res.z = x * m[2] + y * m[6] + z * m[10] + m[14] + yield res + + def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: + cdef double m0 = self.m[0] + cdef double m1 = self.m[1] + cdef double m4 = self.m[4] + cdef double m5 = self.m[5] + cdef double m12 = self.m[12] + cdef double m13 = self.m[13] + cdef double x, y + cdef Vec2 res + + for pnt in points: + res = Vec2(pnt) + x = res.x + y = res.y + res.x = x * m0 + y * m4 + m12 + res.y = x * m1 + y * m5 + m13 + yield res + + def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: + """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + to transform, this allows 2D/3D transformation on arrays with more columns + e.g. a polyline array which stores points as (x, y, start_width, end_width, + bulge) values. + + """ + cdef int _ndim = ndim + if _ndim == 2: + assert array.shape[1] > 1 + transform_2d_array_inplace(self.m, array, array.shape[0]) + elif _ndim == 3: + assert array.shape[1] > 2 + transform_3d_array_inplace(self.m, array, array.shape[0]) + else: + raise ValueError("ndim has to be 2 or 3") + + + def transform_directions( + self, vectors: Iterable[UVec], normalize=False + ) -> Iterator[Vec3]: + cdef double *m = self.m + cdef Vec3 res + cdef double x, y, z + cdef bint _normalize = normalize + + for vector in vectors: + res = Vec3(vector) + x = res.x + y = res.y + z = res.z + + res.x = x * m[0] + y * m[4] + z * m[8] + res.y = x * m[1] + y * m[5] + z * m[9] + res.z = x * m[2] + y * m[6] + z * m[10] + yield v3_normalize(res, 1.0) if _normalize else res + + def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: + return self.ucs_direction_from_wcs(wcs - self.origin) + + def ucs_direction_from_wcs(self, wcs: UVec) -> Vec3: + cdef double *m = self.m + cdef Vec3 res = Vec3(wcs) + cdef double x = res.x + cdef double y = res.y + cdef double z = res.z + + res.x = x * m[0] + y * m[1] + z * m[2] + res.y = x * m[4] + y * m[5] + z * m[6] + res.z = x * m[8] + y * m[9] + z * m[10] + return res + + ocs_from_wcs = ucs_direction_from_wcs + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef void transform_2d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): + cdef double m0 = m[0] + cdef double m1 = m[1] + cdef double m4 = m[4] + cdef double m5 = m[5] + cdef double m12 = m[12] + cdef double m13 = m[13] + cdef double x, y + cdef Py_ssize_t i + + for i in range(size): + x = array[i, 0] + y = array[i, 1] + array[i, 0] = x * m0 + y * m4 + m12 + array[i, 1] = x * m1 + y * m5 + m13 + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef void transform_3d_array_inplace(double *m, double [:, ::1] array, Py_ssize_t size): + cdef double x, y, z + cdef Py_ssize_t i + + for i in range(size): + x = array[i, 0] + y = array[i, 1] + z = array[i, 2] + + array[i, 0] = x * m[0] + y * m[4] + z * m[8] + m[12] + array[i, 1] = x * m[1] + y * m[5] + z * m[9] + m[13] + array[i, 2] = x * m[2] + y * m[6] + z * m[10] + m[14] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.c new file mode 100644 index 0000000..01659d8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.c @@ -0,0 +1,29254 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.np_support", + "sources": [ + "src/ezdxf/acc/np_support.pyx" + ] + }, + "module_name": "ezdxf.acc.np_support" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__np_support +#define __PYX_HAVE_API__ezdxf__acc__np_support +/* Early includes */ +#include "constants.h" +#include "pythread.h" +#include +#include +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/np_support.pyx", + "", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* NoFastGil.proto */ +#define __Pyx_PyGILState_Ensure PyGILState_Ensure +#define __Pyx_PyGILState_Release PyGILState_Release +#define __Pyx_FastGIL_Remember() +#define __Pyx_FastGIL_Forget() +#define __Pyx_FastGilFuncInit() + +/* BufferFormatStructs.proto */ +struct __Pyx_StructField_; +#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0) +typedef struct { + const char* name; + struct __Pyx_StructField_* fields; + size_t size; + size_t arraysize[8]; + int ndim; + char typegroup; + char is_unsigned; + int flags; +} __Pyx_TypeInfo; +typedef struct __Pyx_StructField_ { + __Pyx_TypeInfo* type; + const char* name; + size_t offset; +} __Pyx_StructField; +typedef struct { + __Pyx_StructField* field; + size_t parent_offset; +} __Pyx_BufFmt_StackElem; +typedef struct { + __Pyx_StructField root; + __Pyx_BufFmt_StackElem* head; + size_t fmt_offset; + size_t new_count, enc_count; + size_t struct_alignment; + int is_complex; + char enc_type; + char new_packmode; + char enc_packmode; + char is_valid_array; +} __Pyx_BufFmt_Context; + +/* Atomics.proto */ +#include +#ifndef CYTHON_ATOMICS + #define CYTHON_ATOMICS 1 +#endif +#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS +#define __pyx_atomic_int_type int +#define __pyx_nonatomic_int_type int +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__)) + #include +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ + (defined(_MSC_VER) && _MSC_VER >= 1700))) + #include +#endif +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type atomic_int + #define __pyx_atomic_incr_aligned(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) + #define __pyx_atomic_decr_aligned(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C atomics" + #endif +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ +\ + (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type std::atomic_int + #define __pyx_atomic_incr_aligned(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) + #define __pyx_atomic_decr_aligned(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C++ atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C++ atomics" + #endif +#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ + (__GNUC_MINOR__ > 1 ||\ + (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) + #define __pyx_atomic_incr_aligned(value) __sync_fetch_and_add(value, 1) + #define __pyx_atomic_decr_aligned(value) __sync_fetch_and_sub(value, 1) + #ifdef __PYX_DEBUG_ATOMICS + #warning "Using GNU atomics" + #endif +#elif CYTHON_ATOMICS && defined(_MSC_VER) + #include + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type long + #undef __pyx_nonatomic_int_type + #define __pyx_nonatomic_int_type long + #pragma intrinsic (_InterlockedExchangeAdd) + #define __pyx_atomic_incr_aligned(value) _InterlockedExchangeAdd(value, 1) + #define __pyx_atomic_decr_aligned(value) _InterlockedExchangeAdd(value, -1) + #ifdef __PYX_DEBUG_ATOMICS + #pragma message ("Using MSVC atomics") + #endif +#else + #undef CYTHON_ATOMICS + #define CYTHON_ATOMICS 0 + #ifdef __PYX_DEBUG_ATOMICS + #warning "Not using atomics" + #endif +#endif +#if CYTHON_ATOMICS + #define __pyx_add_acquisition_count(memview)\ + __pyx_atomic_incr_aligned(__pyx_get_slice_count_pointer(memview)) + #define __pyx_sub_acquisition_count(memview)\ + __pyx_atomic_decr_aligned(__pyx_get_slice_count_pointer(memview)) +#else + #define __pyx_add_acquisition_count(memview)\ + __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) + #define __pyx_sub_acquisition_count(memview)\ + __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) +#endif + +/* MemviewSliceStruct.proto */ +struct __pyx_memoryview_obj; +typedef struct { + struct __pyx_memoryview_obj *memview; + char *data; + Py_ssize_t shape[8]; + Py_ssize_t strides[8]; + Py_ssize_t suboffsets[8]; +} __Pyx_memviewslice; +#define __Pyx_MemoryView_Len(m) (m.shape[0]) + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_array_obj; +struct __pyx_MemviewEnum_obj; +struct __pyx_memoryview_obj; +struct __pyx_memoryviewslice_obj; + +/* "vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "View.MemoryView":114 + * @cython.collection_type("sequence") + * @cname("__pyx_array") + * cdef class array: # <<<<<<<<<<<<<< + * + * cdef: + */ +struct __pyx_array_obj { + PyObject_HEAD + struct __pyx_vtabstruct_array *__pyx_vtab; + char *data; + Py_ssize_t len; + char *format; + int ndim; + Py_ssize_t *_shape; + Py_ssize_t *_strides; + Py_ssize_t itemsize; + PyObject *mode; + PyObject *_format; + void (*callback_free_data)(void *); + int free_data; + int dtype_is_object; +}; + + +/* "View.MemoryView":302 + * + * @cname('__pyx_MemviewEnum') + * cdef class Enum(object): # <<<<<<<<<<<<<< + * cdef object name + * def __init__(self, name): + */ +struct __pyx_MemviewEnum_obj { + PyObject_HEAD + PyObject *name; +}; + + +/* "View.MemoryView":337 + * + * @cname('__pyx_memoryview') + * cdef class memoryview: # <<<<<<<<<<<<<< + * + * cdef object obj + */ +struct __pyx_memoryview_obj { + PyObject_HEAD + struct __pyx_vtabstruct_memoryview *__pyx_vtab; + PyObject *obj; + PyObject *_size; + PyObject *_array_interface; + PyThread_type_lock lock; + __pyx_atomic_int_type acquisition_count; + Py_buffer view; + int flags; + int dtype_is_object; + __Pyx_TypeInfo *typeinfo; +}; + + +/* "View.MemoryView":952 + * @cython.collection_type("sequence") + * @cname('__pyx_memoryviewslice') + * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<< + * "Internal class for passing memoryview slices to Python" + * + */ +struct __pyx_memoryviewslice_obj { + struct __pyx_memoryview_obj __pyx_base; + __Pyx_memviewslice from_slice; + PyObject *from_object; + PyObject *(*to_object_func)(char *); + int (*to_dtype_func)(char *, PyObject *); +}; + + + +/* "View.MemoryView":114 + * @cython.collection_type("sequence") + * @cname("__pyx_array") + * cdef class array: # <<<<<<<<<<<<<< + * + * cdef: + */ + +struct __pyx_vtabstruct_array { + PyObject *(*get_memview)(struct __pyx_array_obj *); +}; +static struct __pyx_vtabstruct_array *__pyx_vtabptr_array; + + +/* "View.MemoryView":337 + * + * @cname('__pyx_memoryview') + * cdef class memoryview: # <<<<<<<<<<<<<< + * + * cdef object obj + */ + +struct __pyx_vtabstruct_memoryview { + char *(*get_item_pointer)(struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*is_slice)(struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*setitem_slice_assignment)(struct __pyx_memoryview_obj *, PyObject *, PyObject *); + PyObject *(*setitem_slice_assign_scalar)(struct __pyx_memoryview_obj *, struct __pyx_memoryview_obj *, PyObject *); + PyObject *(*setitem_indexed)(struct __pyx_memoryview_obj *, PyObject *, PyObject *); + PyObject *(*convert_item_to_object)(struct __pyx_memoryview_obj *, char *); + PyObject *(*assign_item_from_object)(struct __pyx_memoryview_obj *, char *, PyObject *); + PyObject *(*_get_base)(struct __pyx_memoryview_obj *); +}; +static struct __pyx_vtabstruct_memoryview *__pyx_vtabptr_memoryview; + + +/* "View.MemoryView":952 + * @cython.collection_type("sequence") + * @cname('__pyx_memoryviewslice') + * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<< + * "Internal class for passing memoryview slices to Python" + * + */ + +struct __pyx_vtabstruct__memoryviewslice { + struct __pyx_vtabstruct_memoryview __pyx_base; +}; +static struct __pyx_vtabstruct__memoryviewslice *__pyx_vtabptr__memoryviewslice; +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* RaiseUnexpectedTypeError.proto */ +static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* BuildPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char); + +/* CIntToPyUnicode.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char); + +/* CIntToPyUnicode.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char); + +/* JoinPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char); + +/* StrEquals.proto */ +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals +#else +#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals +#endif + +/* PyObjectFormatSimple.proto */ +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#elif PY_MAJOR_VERSION < 3 + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyString_CheckExact(s)) ? PyUnicode_FromEncodedObject(s, NULL, "strict") :\ + PyObject_Format(s, f)) +#elif CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyLong_CheckExact(s)) ? PyLong_Type.tp_repr(s) :\ + likely(PyFloat_CheckExact(s)) ? PyFloat_Type.tp_repr(s) :\ + PyObject_Format(s, f)) +#else + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#endif + +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *); /*proto*/ +/* GetAttr.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* DivInt[Py_ssize_t].proto */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t, Py_ssize_t); + +/* UnaryNegOverflows.proto */ +#define __Pyx_UNARY_NEG_WOULD_OVERFLOW(x)\ + (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) + +/* GetAttr3.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* AssertionsEnabled.proto */ +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define __Pyx_init_assertions_enabled() (0) + #define __pyx_assertions_enabled() (1) +#elif CYTHON_COMPILING_IN_LIMITED_API || (CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030C0000) + static int __pyx_assertions_enabled_flag; + #define __pyx_assertions_enabled() (__pyx_assertions_enabled_flag) + static int __Pyx_init_assertions_enabled(void) { + PyObject *builtins, *debug, *debug_str; + int flag; + builtins = PyEval_GetBuiltins(); + if (!builtins) goto bad; + debug_str = PyUnicode_FromStringAndSize("__debug__", 9); + if (!debug_str) goto bad; + debug = PyObject_GetItem(builtins, debug_str); + Py_DECREF(debug_str); + if (!debug) goto bad; + flag = PyObject_IsTrue(debug); + Py_DECREF(debug); + if (flag == -1) goto bad; + __pyx_assertions_enabled_flag = flag; + return 0; + bad: + __pyx_assertions_enabled_flag = 1; + return -1; + } +#else + #define __Pyx_init_assertions_enabled() (0) + #define __pyx_assertions_enabled() (!Py_OptimizeFlag) +#endif + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* RaiseNoneIterError.proto */ +static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportDottedModule.proto */ +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); +#endif + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +/* ListCompAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len)) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) +#endif + +/* PySequenceMultiply.proto */ +#define __Pyx_PySequence_Multiply_Left(mul, seq) __Pyx_PySequence_Multiply(seq, mul) +static CYTHON_INLINE PyObject* __Pyx_PySequence_Multiply(PyObject *seq, Py_ssize_t mul); + +/* SetItemInt.proto */ +#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) :\ + __Pyx_SetItemInt_Generic(o, to_py_func(i), v))) +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v); +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, + int is_list, int wraparound, int boundscheck); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* DivInt[long].proto */ +static CYTHON_INLINE long __Pyx_div_long(long, long); + +/* PySequenceContains.proto */ +static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { + int result = PySequence_Contains(seq, item); + return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); +} + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* HasAttr.proto */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyTypeObject* typeptr , void* vtable); + +/* GetVTable.proto */ +static void* __Pyx_GetVtable(PyTypeObject *type); + +/* MergeVTables.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type); +#endif + +/* SetupReduce.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce(PyObject* type_obj); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto_3_0_11 +#define __PYX_HAVE_RT_ImportType_proto_3_0_11 +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#include +#endif +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) alignof(s) +#else +#define __PYX_GET_STRUCT_ALIGNMENT_3_0_11(s) sizeof(void*) +#endif +enum __Pyx_ImportType_CheckSize_3_0_11 { + __Pyx_ImportType_CheckSize_Error_3_0_11 = 0, + __Pyx_ImportType_CheckSize_Warn_3_0_11 = 1, + __Pyx_ImportType_CheckSize_Ignore_3_0_11 = 2 +}; +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +#if PY_MAJOR_VERSION < 3 + static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); + static void __Pyx_ReleaseBuffer(Py_buffer *view); +#else + #define __Pyx_GetBuffer PyObject_GetBuffer + #define __Pyx_ReleaseBuffer PyBuffer_Release +#endif + + +/* BufferStructDeclare.proto */ +typedef struct { + Py_ssize_t shape, strides, suboffsets; +} __Pyx_Buf_DimInfo; +typedef struct { + size_t refcount; + Py_buffer pybuffer; +} __Pyx_Buffer; +typedef struct { + __Pyx_Buffer *rcbuffer; + char *data; + __Pyx_Buf_DimInfo diminfo[8]; +} __Pyx_LocalBuf_ND; + +/* MemviewSliceIsContig.proto */ +static int __pyx_memviewslice_is_contig(const __Pyx_memviewslice mvs, char order, int ndim); + +/* OverlappingSlices.proto */ +static int __pyx_slices_overlap(__Pyx_memviewslice *slice1, + __Pyx_memviewslice *slice2, + int ndim, size_t itemsize); + +/* IsLittleEndian.proto */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void); + +/* BufferFormatCheck.proto */ +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts); +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type); + +/* TypeInfoCompare.proto */ +static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b); + +/* MemviewSliceValidateAndInit.proto */ +static int __Pyx_ValidateAndInit_memviewslice( + int *axes_specs, + int c_or_f_flag, + int buf_flags, + int ndim, + __Pyx_TypeInfo *dtype, + __Pyx_BufFmt_StackElem stack[], + __Pyx_memviewslice *memviewslice, + PyObject *original_obj); + +/* ObjectToMemviewSlice.proto */ +static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(PyObject *, int writable_flag); + +/* ObjectToMemviewSlice.proto */ +static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_dc_int(PyObject *, int writable_flag); + +/* ObjectToMemviewSlice.proto */ +static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_dc_double(PyObject *, int writable_flag); + +/* MemviewDtypeToObject.proto */ +static CYTHON_INLINE PyObject *__pyx_memview_get_double(const char *itemp); +static CYTHON_INLINE int __pyx_memview_set_double(const char *itemp, PyObject *obj); + +/* MemviewSliceCopyTemplate.proto */ +static __Pyx_memviewslice +__pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, + const char *mode, int ndim, + size_t sizeof_dtype, int contig_flag, + int dtype_is_object); + +/* MemviewSliceInit.proto */ +#define __Pyx_BUF_MAX_NDIMS %(BUF_MAX_NDIMS)d +#define __Pyx_MEMVIEW_DIRECT 1 +#define __Pyx_MEMVIEW_PTR 2 +#define __Pyx_MEMVIEW_FULL 4 +#define __Pyx_MEMVIEW_CONTIG 8 +#define __Pyx_MEMVIEW_STRIDED 16 +#define __Pyx_MEMVIEW_FOLLOW 32 +#define __Pyx_IS_C_CONTIG 1 +#define __Pyx_IS_F_CONTIG 2 +static int __Pyx_init_memviewslice( + struct __pyx_memoryview_obj *memview, + int ndim, + __Pyx_memviewslice *memviewslice, + int memview_is_new_reference); +static CYTHON_INLINE int __pyx_add_acquisition_count_locked( + __pyx_atomic_int_type *acquisition_count, PyThread_type_lock lock); +static CYTHON_INLINE int __pyx_sub_acquisition_count_locked( + __pyx_atomic_int_type *acquisition_count, PyThread_type_lock lock); +#define __pyx_get_slice_count_pointer(memview) (&memview->acquisition_count) +#define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__) +#define __PYX_XCLEAR_MEMVIEW(slice, have_gil) __Pyx_XCLEAR_MEMVIEW(slice, have_gil, __LINE__) +static CYTHON_INLINE void __Pyx_INC_MEMVIEW(__Pyx_memviewslice *, int, int); +static CYTHON_INLINE void __Pyx_XCLEAR_MEMVIEW(__Pyx_memviewslice *, int, int); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE char __Pyx_PyInt_As_char(PyObject *); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionImport.proto */ +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *__pyx_v_self); /* proto*/ +static char *__pyx_memoryview_get_item_pointer(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto*/ +static PyObject *__pyx_memoryview_is_slice(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj); /* proto*/ +static PyObject *__pyx_memoryview_setitem_slice_assignment(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_dst, PyObject *__pyx_v_src); /* proto*/ +static PyObject *__pyx_memoryview_setitem_slice_assign_scalar(struct __pyx_memoryview_obj *__pyx_v_self, struct __pyx_memoryview_obj *__pyx_v_dst, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview_setitem_indexed(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview_convert_item_to_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/ +static PyObject *__pyx_memoryview_assign_item_from_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryview__get_base(struct __pyx_memoryview_obj *__pyx_v_self); /* proto*/ +static PyObject *__pyx_memoryviewslice_convert_item_to_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/ +static PyObject *__pyx_memoryviewslice_assign_item_from_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/ +static PyObject *__pyx_memoryviewslice__get_base(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto*/ + +/* Module declarations from "cython.view" */ + +/* Module declarations from "cython.dataclasses" */ + +/* Module declarations from "cython" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static int (*__pyx_f_5ezdxf_3acc_6vector_isclose)(double, double, double, double); /*proto*/ + +/* Module declarations from "ezdxf.acc.np_support" */ +static PyObject *__pyx_collections_abc_Sequence = 0; +static PyObject *generic = 0; +static PyObject *strided = 0; +static PyObject *indirect = 0; +static PyObject *contiguous = 0; +static PyObject *indirect_contiguous = 0; +static int __pyx_memoryview_thread_locks_used; +static PyThread_type_lock __pyx_memoryview_thread_locks[8]; +static int __pyx_f_5ezdxf_3acc_10np_support__has_clockwise_orientation(__Pyx_memviewslice, Py_ssize_t); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_10np_support__lu_decompose_cext(__Pyx_memviewslice, __Pyx_memviewslice, __Pyx_memviewslice, int, int, int); /*proto*/ +static PyObject *__pyx_f_5ezdxf_3acc_10np_support__solve_vector_banded_matrix_cext(__Pyx_memviewslice, __Pyx_memviewslice, __Pyx_memviewslice, __Pyx_memviewslice, int, int, int); /*proto*/ +static int __pyx_array_allocate_buffer(struct __pyx_array_obj *); /*proto*/ +static struct __pyx_array_obj *__pyx_array_new(PyObject *, Py_ssize_t, char *, char *, char *); /*proto*/ +static PyObject *__pyx_memoryview_new(PyObject *, int, int, __Pyx_TypeInfo *); /*proto*/ +static CYTHON_INLINE int __pyx_memoryview_check(PyObject *); /*proto*/ +static PyObject *_unellipsify(PyObject *, int); /*proto*/ +static int assert_direct_dimensions(Py_ssize_t *, int); /*proto*/ +static struct __pyx_memoryview_obj *__pyx_memview_slice(struct __pyx_memoryview_obj *, PyObject *); /*proto*/ +static int __pyx_memoryview_slice_memviewslice(__Pyx_memviewslice *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int, int); /*proto*/ +static char *__pyx_pybuffer_index(Py_buffer *, char *, Py_ssize_t, Py_ssize_t); /*proto*/ +static int __pyx_memslice_transpose(__Pyx_memviewslice *); /*proto*/ +static PyObject *__pyx_memoryview_fromslice(__Pyx_memviewslice, int, PyObject *(*)(char *), int (*)(char *, PyObject *), int); /*proto*/ +static __Pyx_memviewslice *__pyx_memoryview_get_slice_from_memoryview(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static void __pyx_memoryview_slice_copy(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static PyObject *__pyx_memoryview_copy_object(struct __pyx_memoryview_obj *); /*proto*/ +static PyObject *__pyx_memoryview_copy_object_from_slice(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/ +static Py_ssize_t abs_py_ssize_t(Py_ssize_t); /*proto*/ +static char __pyx_get_best_slice_order(__Pyx_memviewslice *, int); /*proto*/ +static void _copy_strided_to_strided(char *, Py_ssize_t *, char *, Py_ssize_t *, Py_ssize_t *, Py_ssize_t *, int, size_t); /*proto*/ +static void copy_strided_to_strided(__Pyx_memviewslice *, __Pyx_memviewslice *, int, size_t); /*proto*/ +static Py_ssize_t __pyx_memoryview_slice_get_size(__Pyx_memviewslice *, int); /*proto*/ +static Py_ssize_t __pyx_fill_contig_strides_array(Py_ssize_t *, Py_ssize_t *, Py_ssize_t, int, char); /*proto*/ +static void *__pyx_memoryview_copy_data_to_temp(__Pyx_memviewslice *, __Pyx_memviewslice *, char, int); /*proto*/ +static int __pyx_memoryview_err_extents(int, Py_ssize_t, Py_ssize_t); /*proto*/ +static int __pyx_memoryview_err_dim(PyObject *, PyObject *, int); /*proto*/ +static int __pyx_memoryview_err(PyObject *, PyObject *); /*proto*/ +static int __pyx_memoryview_err_no_memory(void); /*proto*/ +static int __pyx_memoryview_copy_contents(__Pyx_memviewslice, __Pyx_memviewslice, int, int, int); /*proto*/ +static void __pyx_memoryview_broadcast_leading(__Pyx_memviewslice *, int, int); /*proto*/ +static void __pyx_memoryview_refcount_copying(__Pyx_memviewslice *, int, int, int); /*proto*/ +static void __pyx_memoryview_refcount_objects_in_slice_with_gil(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/ +static void __pyx_memoryview_refcount_objects_in_slice(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/ +static void __pyx_memoryview_slice_assign_scalar(__Pyx_memviewslice *, int, size_t, void *, int); /*proto*/ +static void __pyx_memoryview__slice_assign_scalar(char *, Py_ssize_t *, Py_ssize_t *, int, size_t, void *); /*proto*/ +static PyObject *__pyx_unpickle_Enum__set_state(struct __pyx_MemviewEnum_obj *, PyObject *); /*proto*/ +/* #### Code section: typeinfo ### */ +static __Pyx_TypeInfo __Pyx_TypeInfo_double = { "double", NULL, sizeof(double), { 0 }, 0, 'R', 0, 0 }; +static __Pyx_TypeInfo __Pyx_TypeInfo_int = { "int", NULL, sizeof(int), { 0 }, 0, __PYX_IS_UNSIGNED(int) ? 'U' : 'I', __PYX_IS_UNSIGNED(int), 0 }; +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.np_support" +extern int __pyx_module_is_main_ezdxf__acc__np_support; +int __pyx_module_is_main_ezdxf__acc__np_support = 0; + +/* Implementation of "ezdxf.acc.np_support" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin___import__; +static PyObject *__pyx_builtin_MemoryError; +static PyObject *__pyx_builtin_enumerate; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_AssertionError; +static PyObject *__pyx_builtin_Ellipsis; +static PyObject *__pyx_builtin_id; +static PyObject *__pyx_builtin_IndexError; +/* #### Code section: string_decls ### */ +static const char __pyx_k_[] = ": "; +static const char __pyx_k_A[] = "A"; +static const char __pyx_k_O[] = "O"; +static const char __pyx_k_c[] = "c"; +static const char __pyx_k_n[] = "n"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k__2[] = "."; +static const char __pyx_k__3[] = "*"; +static const char __pyx_k__6[] = "'"; +static const char __pyx_k__7[] = ")"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_id[] = "id"; +static const char __pyx_k_m1[] = "m1"; +static const char __pyx_k_m2[] = "m2"; +static const char __pyx_k_np[] = "np"; +static const char __pyx_k__29[] = "?"; +static const char __pyx_k_abc[] = "abc"; +static const char __pyx_k_and[] = " and "; +static const char __pyx_k_got[] = " (got "; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_new[] = "__new__"; +static const char __pyx_k_npt[] = "npt"; +static const char __pyx_k_obj[] = "obj"; +static const char __pyx_k_sys[] = "sys"; +static const char __pyx_k_base[] = "base"; +static const char __pyx_k_bool[] = "bool"; +static const char __pyx_k_dict[] = "__dict__"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_mode[] = "mode"; +static const char __pyx_k_name[] = "name"; +static const char __pyx_k_ndim[] = "ndim"; +static const char __pyx_k_pack[] = "pack"; +static const char __pyx_k_size[] = "size"; +static const char __pyx_k_spec[] = "__spec__"; +static const char __pyx_k_step[] = "step"; +static const char __pyx_k_stop[] = "stop"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_ASCII[] = "ASCII"; +static const char __pyx_k_array[] = "array"; +static const char __pyx_k_class[] = "__class__"; +static const char __pyx_k_count[] = "count"; +static const char __pyx_k_dtype[] = "dtype"; +static const char __pyx_k_error[] = "error"; +static const char __pyx_k_flags[] = "flags"; +static const char __pyx_k_index[] = "index"; +static const char __pyx_k_int32[] = "int32"; +static const char __pyx_k_lower[] = "lower"; +static const char __pyx_k_numpy[] = "numpy"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_shape[] = "shape"; +static const char __pyx_k_start[] = "start"; +static const char __pyx_k_upper[] = "upper"; +static const char __pyx_k_zeros[] = "zeros"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_encode[] = "encode"; +static const char __pyx_k_format[] = "format"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_name_2[] = "__name__"; +static const char __pyx_k_pickle[] = "pickle"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_struct[] = "struct"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_unpack[] = "unpack"; +static const char __pyx_k_update[] = "update"; +static const char __pyx_k_NDArray[] = "NDArray"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_float64[] = "float64"; +static const char __pyx_k_fortran[] = "fortran"; +static const char __pyx_k_memview[] = "memview"; +static const char __pyx_k_Ellipsis[] = "Ellipsis"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_itemsize[] = "itemsize"; +static const char __pyx_k_pyx_type[] = "__pyx_type"; +static const char __pyx_k_register[] = "register"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_vertices[] = "vertices"; +static const char __pyx_k_TypeAlias[] = "TypeAlias"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_enumerate[] = "enumerate"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_IndexError[] = "IndexError"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_np_ndarray[] = "np.ndarray"; +static const char __pyx_k_pyx_result[] = "__pyx_result"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_MemoryError[] = "MemoryError"; +static const char __pyx_k_PickleError[] = "PickleError"; +static const char __pyx_k_collections[] = "collections"; +static const char __pyx_k_initializing[] = "_initializing"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_lu_decompose[] = "lu_decompose"; +static const char __pyx_k_numpy_typing[] = "numpy.typing"; +static const char __pyx_k_pyx_checksum[] = "__pyx_checksum"; +static const char __pyx_k_stringsource[] = ""; +static const char __pyx_k_version_info[] = "version_info"; +static const char __pyx_k_class_getitem[] = "__class_getitem__"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_AssertionError[] = "AssertionError"; +static const char __pyx_k_View_MemoryView[] = "View.MemoryView"; +static const char __pyx_k_allocate_buffer[] = "allocate_buffer"; +static const char __pyx_k_collections_abc[] = "collections.abc"; +static const char __pyx_k_dtype_is_object[] = "dtype_is_object"; +static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_pyx_unpickle_Enum[] = "__pyx_unpickle_Enum"; +static const char __pyx_k_typing_extensions[] = "typing_extensions"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_strided_and_direct[] = ""; +static const char __pyx_k_ezdxf_acc_np_support[] = "ezdxf.acc.np_support"; +static const char __pyx_k_strided_and_indirect[] = ""; +static const char __pyx_k_Invalid_shape_in_axis[] = "Invalid shape in axis "; +static const char __pyx_k_contiguous_and_direct[] = ""; +static const char __pyx_k_Cannot_index_with_type[] = "Cannot index with type '"; +static const char __pyx_k_MemoryView_of_r_object[] = ""; +static const char __pyx_k_MemoryView_of_r_at_0x_x[] = ""; +static const char __pyx_k_contiguous_and_indirect[] = ""; +static const char __pyx_k_Dimension_d_is_not_direct[] = "Dimension %d is not direct"; +static const char __pyx_k_has_clockwise_orientation[] = "has_clockwise_orientation"; +static const char __pyx_k_Index_out_of_bounds_axis_d[] = "Index out of bounds (axis %d)"; +static const char __pyx_k_solve_vector_banded_matrix[] = "solve_vector_banded_matrix"; +static const char __pyx_k_Step_may_not_be_zero_axis_d[] = "Step may not be zero (axis %d)"; +static const char __pyx_k_itemsize_0_for_cython_array[] = "itemsize <= 0 for cython.array"; +static const char __pyx_k_At_least_3_vertices_required[] = "At least 3 vertices required."; +static const char __pyx_k_src_ezdxf_acc_np_support_pyx[] = "src/ezdxf/acc/np_support.pyx"; +static const char __pyx_k_tuple_NDArray_NDArray_NDArray[] = "tuple[NDArray, NDArray, NDArray]"; +static const char __pyx_k_unable_to_allocate_array_data[] = "unable to allocate array data."; +static const char __pyx_k_strided_and_direct_or_indirect[] = ""; +static const char __pyx_k_All_dimensions_preceding_dimensi[] = "All dimensions preceding dimension %d must be indexed and not sliced"; +static const char __pyx_k_Buffer_view_does_not_expose_stri[] = "Buffer view does not expose strides"; +static const char __pyx_k_Can_only_create_a_buffer_that_is[] = "Can only create a buffer that is contiguous in memory."; +static const char __pyx_k_Cannot_assign_to_read_only_memor[] = "Cannot assign to read-only memoryview"; +static const char __pyx_k_Cannot_create_writable_memory_vi[] = "Cannot create writable memory view from read-only memoryview"; +static const char __pyx_k_Cannot_transpose_memoryview_with[] = "Cannot transpose memoryview with indirect dimensions"; +static const char __pyx_k_Empty_shape_tuple_for_cython_arr[] = "Empty shape tuple for cython.array"; +static const char __pyx_k_Incompatible_checksums_0x_x_vs_0[] = "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))"; +static const char __pyx_k_Indirect_dimensions_not_supporte[] = "Indirect dimensions not supported"; +static const char __pyx_k_Invalid_mode_expected_c_or_fortr[] = "Invalid mode, expected 'c' or 'fortran', got "; +static const char __pyx_k_Item_count_of_vector_x_has_to_ma[] = "Item count of vector has to match the row count of matrix ."; +static const char __pyx_k_Out_of_bounds_on_buffer_access_a[] = "Out of bounds on buffer access (axis "; +static const char __pyx_k_Unable_to_convert_item_to_object[] = "Unable to convert item to object"; +static const char __pyx_k_got_differing_extents_in_dimensi[] = "got differing extents in dimension "; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +static const char __pyx_k_unable_to_allocate_shape_and_str[] = "unable to allocate shape and strides."; +/* #### Code section: decls ### */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer); /* proto */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(struct __pyx_array_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ +static void __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_5array_7memview___get__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_attr); /* proto */ +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item); /* proto */ +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value); /* proto */ +static PyObject *__pyx_pf___pyx_array___reduce_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_array_2__setstate_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_MemviewEnum___reduce_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_MemviewEnum_2__setstate_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj, int __pyx_v_flags, int __pyx_v_dtype_is_object); /* proto */ +static void __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto */ +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(struct __pyx_memoryview_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryview___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryview_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static void __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryviewslice___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf___pyx_memoryviewslice_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_has_clockwise_orientation(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_vertices); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_2lu_decompose(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_A, PyObject *__pyx_v_m1, PyObject *__pyx_v_m2); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_4solve_vector_banded_matrix(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_x, PyObject *__pyx_v_upper, PyObject *__pyx_v_lower, PyObject *__pyx_v_index, PyObject *__pyx_v_m1, PyObject *__pyx_v_m2); /* proto */ +static PyObject *__pyx_tp_new_array(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_memoryview(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new__memoryviewslice(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type___pyx_array; + PyObject *__pyx_type___pyx_MemviewEnum; + PyObject *__pyx_type___pyx_memoryview; + PyObject *__pyx_type___pyx_memoryviewslice; + #endif + PyTypeObject *__pyx_array_type; + PyTypeObject *__pyx_MemviewEnum_type; + PyTypeObject *__pyx_memoryview_type; + PyTypeObject *__pyx_memoryviewslice_type; + PyObject *__pyx_kp_u_; + PyObject *__pyx_n_s_A; + PyObject *__pyx_n_s_ASCII; + PyObject *__pyx_kp_s_All_dimensions_preceding_dimensi; + PyObject *__pyx_n_s_AssertionError; + PyObject *__pyx_kp_u_At_least_3_vertices_required; + PyObject *__pyx_kp_s_Buffer_view_does_not_expose_stri; + PyObject *__pyx_kp_s_Can_only_create_a_buffer_that_is; + PyObject *__pyx_kp_s_Cannot_assign_to_read_only_memor; + PyObject *__pyx_kp_s_Cannot_create_writable_memory_vi; + PyObject *__pyx_kp_u_Cannot_index_with_type; + PyObject *__pyx_kp_s_Cannot_transpose_memoryview_with; + PyObject *__pyx_kp_s_Dimension_d_is_not_direct; + PyObject *__pyx_n_s_Ellipsis; + PyObject *__pyx_kp_s_Empty_shape_tuple_for_cython_arr; + PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0; + PyObject *__pyx_n_s_IndexError; + PyObject *__pyx_kp_s_Index_out_of_bounds_axis_d; + PyObject *__pyx_kp_s_Indirect_dimensions_not_supporte; + PyObject *__pyx_kp_u_Invalid_mode_expected_c_or_fortr; + PyObject *__pyx_kp_u_Invalid_shape_in_axis; + PyObject *__pyx_kp_u_Item_count_of_vector_x_has_to_ma; + PyObject *__pyx_n_s_MemoryError; + PyObject *__pyx_kp_s_MemoryView_of_r_at_0x_x; + PyObject *__pyx_kp_s_MemoryView_of_r_object; + PyObject *__pyx_n_s_NDArray; + PyObject *__pyx_n_b_O; + PyObject *__pyx_kp_u_Out_of_bounds_on_buffer_access_a; + PyObject *__pyx_n_s_PickleError; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_kp_s_Step_may_not_be_zero_axis_d; + PyObject *__pyx_n_s_TypeAlias; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_kp_s_Unable_to_convert_item_to_object; + PyObject *__pyx_n_s_ValueError; + PyObject *__pyx_n_s_View_MemoryView; + PyObject *__pyx_kp_u__2; + PyObject *__pyx_n_s__29; + PyObject *__pyx_n_s__3; + PyObject *__pyx_kp_u__6; + PyObject *__pyx_kp_u__7; + PyObject *__pyx_n_s_abc; + PyObject *__pyx_n_s_allocate_buffer; + PyObject *__pyx_kp_u_and; + PyObject *__pyx_n_s_array; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_base; + PyObject *__pyx_n_s_bool; + PyObject *__pyx_n_s_c; + PyObject *__pyx_n_u_c; + PyObject *__pyx_n_s_class; + PyObject *__pyx_n_s_class_getitem; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_collections; + PyObject *__pyx_kp_s_collections_abc; + PyObject *__pyx_kp_s_contiguous_and_direct; + PyObject *__pyx_kp_s_contiguous_and_indirect; + PyObject *__pyx_n_s_count; + PyObject *__pyx_n_s_dict; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_dtype; + PyObject *__pyx_n_s_dtype_is_object; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_encode; + PyObject *__pyx_n_s_enumerate; + PyObject *__pyx_n_s_error; + PyObject *__pyx_n_s_ezdxf_acc_np_support; + PyObject *__pyx_n_s_flags; + PyObject *__pyx_n_s_float64; + PyObject *__pyx_n_s_format; + PyObject *__pyx_n_s_fortran; + PyObject *__pyx_n_u_fortran; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_getstate; + PyObject *__pyx_kp_u_got; + PyObject *__pyx_kp_u_got_differing_extents_in_dimensi; + PyObject *__pyx_n_s_has_clockwise_orientation; + PyObject *__pyx_n_s_id; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_index; + PyObject *__pyx_n_s_initializing; + PyObject *__pyx_n_s_int; + PyObject *__pyx_n_s_int32; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_itemsize; + PyObject *__pyx_kp_s_itemsize_0_for_cython_array; + PyObject *__pyx_n_s_lower; + PyObject *__pyx_n_s_lu_decompose; + PyObject *__pyx_n_s_m1; + PyObject *__pyx_n_s_m2; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_memview; + PyObject *__pyx_n_s_mode; + PyObject *__pyx_n_s_n; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_name_2; + PyObject *__pyx_n_s_ndim; + PyObject *__pyx_n_s_new; + PyObject *__pyx_kp_s_no_default___reduce___due_to_non; + PyObject *__pyx_n_s_np; + PyObject *__pyx_kp_s_np_ndarray; + PyObject *__pyx_n_s_npt; + PyObject *__pyx_n_s_numpy; + PyObject *__pyx_n_s_numpy_typing; + PyObject *__pyx_n_s_obj; + PyObject *__pyx_n_s_pack; + PyObject *__pyx_n_s_pickle; + PyObject *__pyx_n_s_pyx_PickleError; + PyObject *__pyx_n_s_pyx_checksum; + PyObject *__pyx_n_s_pyx_result; + PyObject *__pyx_n_s_pyx_state; + PyObject *__pyx_n_s_pyx_type; + PyObject *__pyx_n_s_pyx_unpickle_Enum; + PyObject *__pyx_n_s_pyx_vtable; + PyObject *__pyx_n_s_range; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_reduce_cython; + PyObject *__pyx_n_s_reduce_ex; + PyObject *__pyx_n_s_register; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_setstate; + PyObject *__pyx_n_s_setstate_cython; + PyObject *__pyx_n_s_shape; + PyObject *__pyx_n_s_size; + PyObject *__pyx_n_s_solve_vector_banded_matrix; + PyObject *__pyx_n_s_spec; + PyObject *__pyx_kp_s_src_ezdxf_acc_np_support_pyx; + PyObject *__pyx_n_s_start; + PyObject *__pyx_n_s_step; + PyObject *__pyx_n_s_stop; + PyObject *__pyx_kp_s_strided_and_direct; + PyObject *__pyx_kp_s_strided_and_direct_or_indirect; + PyObject *__pyx_kp_s_strided_and_indirect; + PyObject *__pyx_kp_s_stringsource; + PyObject *__pyx_n_s_struct; + PyObject *__pyx_n_s_sys; + PyObject *__pyx_n_s_test; + PyObject *__pyx_kp_s_tuple_NDArray_NDArray_NDArray; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_typing_extensions; + PyObject *__pyx_kp_s_unable_to_allocate_array_data; + PyObject *__pyx_kp_s_unable_to_allocate_shape_and_str; + PyObject *__pyx_n_s_unpack; + PyObject *__pyx_n_s_update; + PyObject *__pyx_n_s_upper; + PyObject *__pyx_n_s_version_info; + PyObject *__pyx_n_s_vertices; + PyObject *__pyx_n_s_x; + PyObject *__pyx_n_s_zeros; + PyObject *__pyx_int_0; + PyObject *__pyx_int_1; + PyObject *__pyx_int_3; + PyObject *__pyx_int_112105877; + PyObject *__pyx_int_136983863; + PyObject *__pyx_int_184977713; + PyObject *__pyx_int_neg_1; + PyObject *__pyx_slice__5; + PyObject *__pyx_tuple__4; + PyObject *__pyx_tuple__8; + PyObject *__pyx_tuple__9; + PyObject *__pyx_tuple__10; + PyObject *__pyx_tuple__11; + PyObject *__pyx_tuple__12; + PyObject *__pyx_tuple__13; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__15; + PyObject *__pyx_tuple__16; + PyObject *__pyx_tuple__17; + PyObject *__pyx_tuple__18; + PyObject *__pyx_tuple__19; + PyObject *__pyx_tuple__20; + PyObject *__pyx_tuple__22; + PyObject *__pyx_tuple__23; + PyObject *__pyx_tuple__25; + PyObject *__pyx_tuple__27; + PyObject *__pyx_codeobj__21; + PyObject *__pyx_codeobj__24; + PyObject *__pyx_codeobj__26; + PyObject *__pyx_codeobj__28; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_array_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_array); + Py_CLEAR(clear_module_state->__pyx_MemviewEnum_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_MemviewEnum); + Py_CLEAR(clear_module_state->__pyx_memoryview_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_memoryview); + Py_CLEAR(clear_module_state->__pyx_memoryviewslice_type); + Py_CLEAR(clear_module_state->__pyx_type___pyx_memoryviewslice); + Py_CLEAR(clear_module_state->__pyx_kp_u_); + Py_CLEAR(clear_module_state->__pyx_n_s_A); + Py_CLEAR(clear_module_state->__pyx_n_s_ASCII); + Py_CLEAR(clear_module_state->__pyx_kp_s_All_dimensions_preceding_dimensi); + Py_CLEAR(clear_module_state->__pyx_n_s_AssertionError); + Py_CLEAR(clear_module_state->__pyx_kp_u_At_least_3_vertices_required); + Py_CLEAR(clear_module_state->__pyx_kp_s_Buffer_view_does_not_expose_stri); + Py_CLEAR(clear_module_state->__pyx_kp_s_Can_only_create_a_buffer_that_is); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_assign_to_read_only_memor); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_create_writable_memory_vi); + Py_CLEAR(clear_module_state->__pyx_kp_u_Cannot_index_with_type); + Py_CLEAR(clear_module_state->__pyx_kp_s_Cannot_transpose_memoryview_with); + Py_CLEAR(clear_module_state->__pyx_kp_s_Dimension_d_is_not_direct); + Py_CLEAR(clear_module_state->__pyx_n_s_Ellipsis); + Py_CLEAR(clear_module_state->__pyx_kp_s_Empty_shape_tuple_for_cython_arr); + Py_CLEAR(clear_module_state->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0); + Py_CLEAR(clear_module_state->__pyx_n_s_IndexError); + Py_CLEAR(clear_module_state->__pyx_kp_s_Index_out_of_bounds_axis_d); + Py_CLEAR(clear_module_state->__pyx_kp_s_Indirect_dimensions_not_supporte); + Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_mode_expected_c_or_fortr); + Py_CLEAR(clear_module_state->__pyx_kp_u_Invalid_shape_in_axis); + Py_CLEAR(clear_module_state->__pyx_kp_u_Item_count_of_vector_x_has_to_ma); + Py_CLEAR(clear_module_state->__pyx_n_s_MemoryError); + Py_CLEAR(clear_module_state->__pyx_kp_s_MemoryView_of_r_at_0x_x); + Py_CLEAR(clear_module_state->__pyx_kp_s_MemoryView_of_r_object); + Py_CLEAR(clear_module_state->__pyx_n_s_NDArray); + Py_CLEAR(clear_module_state->__pyx_n_b_O); + Py_CLEAR(clear_module_state->__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + Py_CLEAR(clear_module_state->__pyx_n_s_PickleError); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_kp_s_Step_may_not_be_zero_axis_d); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeAlias); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_kp_s_Unable_to_convert_item_to_object); + Py_CLEAR(clear_module_state->__pyx_n_s_ValueError); + Py_CLEAR(clear_module_state->__pyx_n_s_View_MemoryView); + Py_CLEAR(clear_module_state->__pyx_kp_u__2); + Py_CLEAR(clear_module_state->__pyx_n_s__29); + Py_CLEAR(clear_module_state->__pyx_n_s__3); + Py_CLEAR(clear_module_state->__pyx_kp_u__6); + Py_CLEAR(clear_module_state->__pyx_kp_u__7); + Py_CLEAR(clear_module_state->__pyx_n_s_abc); + Py_CLEAR(clear_module_state->__pyx_n_s_allocate_buffer); + Py_CLEAR(clear_module_state->__pyx_kp_u_and); + Py_CLEAR(clear_module_state->__pyx_n_s_array); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_base); + Py_CLEAR(clear_module_state->__pyx_n_s_bool); + Py_CLEAR(clear_module_state->__pyx_n_s_c); + Py_CLEAR(clear_module_state->__pyx_n_u_c); + Py_CLEAR(clear_module_state->__pyx_n_s_class); + Py_CLEAR(clear_module_state->__pyx_n_s_class_getitem); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_collections); + Py_CLEAR(clear_module_state->__pyx_kp_s_collections_abc); + Py_CLEAR(clear_module_state->__pyx_kp_s_contiguous_and_direct); + Py_CLEAR(clear_module_state->__pyx_kp_s_contiguous_and_indirect); + Py_CLEAR(clear_module_state->__pyx_n_s_count); + Py_CLEAR(clear_module_state->__pyx_n_s_dict); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_dtype); + Py_CLEAR(clear_module_state->__pyx_n_s_dtype_is_object); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_encode); + Py_CLEAR(clear_module_state->__pyx_n_s_enumerate); + Py_CLEAR(clear_module_state->__pyx_n_s_error); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_np_support); + Py_CLEAR(clear_module_state->__pyx_n_s_flags); + Py_CLEAR(clear_module_state->__pyx_n_s_float64); + Py_CLEAR(clear_module_state->__pyx_n_s_format); + Py_CLEAR(clear_module_state->__pyx_n_s_fortran); + Py_CLEAR(clear_module_state->__pyx_n_u_fortran); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_getstate); + Py_CLEAR(clear_module_state->__pyx_kp_u_got); + Py_CLEAR(clear_module_state->__pyx_kp_u_got_differing_extents_in_dimensi); + Py_CLEAR(clear_module_state->__pyx_n_s_has_clockwise_orientation); + Py_CLEAR(clear_module_state->__pyx_n_s_id); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_index); + Py_CLEAR(clear_module_state->__pyx_n_s_initializing); + Py_CLEAR(clear_module_state->__pyx_n_s_int); + Py_CLEAR(clear_module_state->__pyx_n_s_int32); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_itemsize); + Py_CLEAR(clear_module_state->__pyx_kp_s_itemsize_0_for_cython_array); + Py_CLEAR(clear_module_state->__pyx_n_s_lower); + Py_CLEAR(clear_module_state->__pyx_n_s_lu_decompose); + Py_CLEAR(clear_module_state->__pyx_n_s_m1); + Py_CLEAR(clear_module_state->__pyx_n_s_m2); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_memview); + Py_CLEAR(clear_module_state->__pyx_n_s_mode); + Py_CLEAR(clear_module_state->__pyx_n_s_n); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_name_2); + Py_CLEAR(clear_module_state->__pyx_n_s_ndim); + Py_CLEAR(clear_module_state->__pyx_n_s_new); + Py_CLEAR(clear_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_CLEAR(clear_module_state->__pyx_n_s_np); + Py_CLEAR(clear_module_state->__pyx_kp_s_np_ndarray); + Py_CLEAR(clear_module_state->__pyx_n_s_npt); + Py_CLEAR(clear_module_state->__pyx_n_s_numpy); + Py_CLEAR(clear_module_state->__pyx_n_s_numpy_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_obj); + Py_CLEAR(clear_module_state->__pyx_n_s_pack); + Py_CLEAR(clear_module_state->__pyx_n_s_pickle); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_PickleError); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_checksum); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_result); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_state); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_type); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_unpickle_Enum); + Py_CLEAR(clear_module_state->__pyx_n_s_pyx_vtable); + Py_CLEAR(clear_module_state->__pyx_n_s_range); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce_ex); + Py_CLEAR(clear_module_state->__pyx_n_s_register); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate); + Py_CLEAR(clear_module_state->__pyx_n_s_setstate_cython); + Py_CLEAR(clear_module_state->__pyx_n_s_shape); + Py_CLEAR(clear_module_state->__pyx_n_s_size); + Py_CLEAR(clear_module_state->__pyx_n_s_solve_vector_banded_matrix); + Py_CLEAR(clear_module_state->__pyx_n_s_spec); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_np_support_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_start); + Py_CLEAR(clear_module_state->__pyx_n_s_step); + Py_CLEAR(clear_module_state->__pyx_n_s_stop); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_direct); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_direct_or_indirect); + Py_CLEAR(clear_module_state->__pyx_kp_s_strided_and_indirect); + Py_CLEAR(clear_module_state->__pyx_kp_s_stringsource); + Py_CLEAR(clear_module_state->__pyx_n_s_struct); + Py_CLEAR(clear_module_state->__pyx_n_s_sys); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_kp_s_tuple_NDArray_NDArray_NDArray); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_typing_extensions); + Py_CLEAR(clear_module_state->__pyx_kp_s_unable_to_allocate_array_data); + Py_CLEAR(clear_module_state->__pyx_kp_s_unable_to_allocate_shape_and_str); + Py_CLEAR(clear_module_state->__pyx_n_s_unpack); + Py_CLEAR(clear_module_state->__pyx_n_s_update); + Py_CLEAR(clear_module_state->__pyx_n_s_upper); + Py_CLEAR(clear_module_state->__pyx_n_s_version_info); + Py_CLEAR(clear_module_state->__pyx_n_s_vertices); + Py_CLEAR(clear_module_state->__pyx_n_s_x); + Py_CLEAR(clear_module_state->__pyx_n_s_zeros); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_1); + Py_CLEAR(clear_module_state->__pyx_int_3); + Py_CLEAR(clear_module_state->__pyx_int_112105877); + Py_CLEAR(clear_module_state->__pyx_int_136983863); + Py_CLEAR(clear_module_state->__pyx_int_184977713); + Py_CLEAR(clear_module_state->__pyx_int_neg_1); + Py_CLEAR(clear_module_state->__pyx_slice__5); + Py_CLEAR(clear_module_state->__pyx_tuple__4); + Py_CLEAR(clear_module_state->__pyx_tuple__8); + Py_CLEAR(clear_module_state->__pyx_tuple__9); + Py_CLEAR(clear_module_state->__pyx_tuple__10); + Py_CLEAR(clear_module_state->__pyx_tuple__11); + Py_CLEAR(clear_module_state->__pyx_tuple__12); + Py_CLEAR(clear_module_state->__pyx_tuple__13); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__15); + Py_CLEAR(clear_module_state->__pyx_tuple__16); + Py_CLEAR(clear_module_state->__pyx_tuple__17); + Py_CLEAR(clear_module_state->__pyx_tuple__18); + Py_CLEAR(clear_module_state->__pyx_tuple__19); + Py_CLEAR(clear_module_state->__pyx_tuple__20); + Py_CLEAR(clear_module_state->__pyx_tuple__22); + Py_CLEAR(clear_module_state->__pyx_tuple__23); + Py_CLEAR(clear_module_state->__pyx_tuple__25); + Py_CLEAR(clear_module_state->__pyx_tuple__27); + Py_CLEAR(clear_module_state->__pyx_codeobj__21); + Py_CLEAR(clear_module_state->__pyx_codeobj__24); + Py_CLEAR(clear_module_state->__pyx_codeobj__26); + Py_CLEAR(clear_module_state->__pyx_codeobj__28); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_array_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_array); + Py_VISIT(traverse_module_state->__pyx_MemviewEnum_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_MemviewEnum); + Py_VISIT(traverse_module_state->__pyx_memoryview_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_memoryview); + Py_VISIT(traverse_module_state->__pyx_memoryviewslice_type); + Py_VISIT(traverse_module_state->__pyx_type___pyx_memoryviewslice); + Py_VISIT(traverse_module_state->__pyx_kp_u_); + Py_VISIT(traverse_module_state->__pyx_n_s_A); + Py_VISIT(traverse_module_state->__pyx_n_s_ASCII); + Py_VISIT(traverse_module_state->__pyx_kp_s_All_dimensions_preceding_dimensi); + Py_VISIT(traverse_module_state->__pyx_n_s_AssertionError); + Py_VISIT(traverse_module_state->__pyx_kp_u_At_least_3_vertices_required); + Py_VISIT(traverse_module_state->__pyx_kp_s_Buffer_view_does_not_expose_stri); + Py_VISIT(traverse_module_state->__pyx_kp_s_Can_only_create_a_buffer_that_is); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_assign_to_read_only_memor); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_create_writable_memory_vi); + Py_VISIT(traverse_module_state->__pyx_kp_u_Cannot_index_with_type); + Py_VISIT(traverse_module_state->__pyx_kp_s_Cannot_transpose_memoryview_with); + Py_VISIT(traverse_module_state->__pyx_kp_s_Dimension_d_is_not_direct); + Py_VISIT(traverse_module_state->__pyx_n_s_Ellipsis); + Py_VISIT(traverse_module_state->__pyx_kp_s_Empty_shape_tuple_for_cython_arr); + Py_VISIT(traverse_module_state->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0); + Py_VISIT(traverse_module_state->__pyx_n_s_IndexError); + Py_VISIT(traverse_module_state->__pyx_kp_s_Index_out_of_bounds_axis_d); + Py_VISIT(traverse_module_state->__pyx_kp_s_Indirect_dimensions_not_supporte); + Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_mode_expected_c_or_fortr); + Py_VISIT(traverse_module_state->__pyx_kp_u_Invalid_shape_in_axis); + Py_VISIT(traverse_module_state->__pyx_kp_u_Item_count_of_vector_x_has_to_ma); + Py_VISIT(traverse_module_state->__pyx_n_s_MemoryError); + Py_VISIT(traverse_module_state->__pyx_kp_s_MemoryView_of_r_at_0x_x); + Py_VISIT(traverse_module_state->__pyx_kp_s_MemoryView_of_r_object); + Py_VISIT(traverse_module_state->__pyx_n_s_NDArray); + Py_VISIT(traverse_module_state->__pyx_n_b_O); + Py_VISIT(traverse_module_state->__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + Py_VISIT(traverse_module_state->__pyx_n_s_PickleError); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_kp_s_Step_may_not_be_zero_axis_d); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeAlias); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_kp_s_Unable_to_convert_item_to_object); + Py_VISIT(traverse_module_state->__pyx_n_s_ValueError); + Py_VISIT(traverse_module_state->__pyx_n_s_View_MemoryView); + Py_VISIT(traverse_module_state->__pyx_kp_u__2); + Py_VISIT(traverse_module_state->__pyx_n_s__29); + Py_VISIT(traverse_module_state->__pyx_n_s__3); + Py_VISIT(traverse_module_state->__pyx_kp_u__6); + Py_VISIT(traverse_module_state->__pyx_kp_u__7); + Py_VISIT(traverse_module_state->__pyx_n_s_abc); + Py_VISIT(traverse_module_state->__pyx_n_s_allocate_buffer); + Py_VISIT(traverse_module_state->__pyx_kp_u_and); + Py_VISIT(traverse_module_state->__pyx_n_s_array); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_base); + Py_VISIT(traverse_module_state->__pyx_n_s_bool); + Py_VISIT(traverse_module_state->__pyx_n_s_c); + Py_VISIT(traverse_module_state->__pyx_n_u_c); + Py_VISIT(traverse_module_state->__pyx_n_s_class); + Py_VISIT(traverse_module_state->__pyx_n_s_class_getitem); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_collections); + Py_VISIT(traverse_module_state->__pyx_kp_s_collections_abc); + Py_VISIT(traverse_module_state->__pyx_kp_s_contiguous_and_direct); + Py_VISIT(traverse_module_state->__pyx_kp_s_contiguous_and_indirect); + Py_VISIT(traverse_module_state->__pyx_n_s_count); + Py_VISIT(traverse_module_state->__pyx_n_s_dict); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_dtype); + Py_VISIT(traverse_module_state->__pyx_n_s_dtype_is_object); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_encode); + Py_VISIT(traverse_module_state->__pyx_n_s_enumerate); + Py_VISIT(traverse_module_state->__pyx_n_s_error); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_np_support); + Py_VISIT(traverse_module_state->__pyx_n_s_flags); + Py_VISIT(traverse_module_state->__pyx_n_s_float64); + Py_VISIT(traverse_module_state->__pyx_n_s_format); + Py_VISIT(traverse_module_state->__pyx_n_s_fortran); + Py_VISIT(traverse_module_state->__pyx_n_u_fortran); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_getstate); + Py_VISIT(traverse_module_state->__pyx_kp_u_got); + Py_VISIT(traverse_module_state->__pyx_kp_u_got_differing_extents_in_dimensi); + Py_VISIT(traverse_module_state->__pyx_n_s_has_clockwise_orientation); + Py_VISIT(traverse_module_state->__pyx_n_s_id); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_index); + Py_VISIT(traverse_module_state->__pyx_n_s_initializing); + Py_VISIT(traverse_module_state->__pyx_n_s_int); + Py_VISIT(traverse_module_state->__pyx_n_s_int32); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_itemsize); + Py_VISIT(traverse_module_state->__pyx_kp_s_itemsize_0_for_cython_array); + Py_VISIT(traverse_module_state->__pyx_n_s_lower); + Py_VISIT(traverse_module_state->__pyx_n_s_lu_decompose); + Py_VISIT(traverse_module_state->__pyx_n_s_m1); + Py_VISIT(traverse_module_state->__pyx_n_s_m2); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_memview); + Py_VISIT(traverse_module_state->__pyx_n_s_mode); + Py_VISIT(traverse_module_state->__pyx_n_s_n); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_name_2); + Py_VISIT(traverse_module_state->__pyx_n_s_ndim); + Py_VISIT(traverse_module_state->__pyx_n_s_new); + Py_VISIT(traverse_module_state->__pyx_kp_s_no_default___reduce___due_to_non); + Py_VISIT(traverse_module_state->__pyx_n_s_np); + Py_VISIT(traverse_module_state->__pyx_kp_s_np_ndarray); + Py_VISIT(traverse_module_state->__pyx_n_s_npt); + Py_VISIT(traverse_module_state->__pyx_n_s_numpy); + Py_VISIT(traverse_module_state->__pyx_n_s_numpy_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_obj); + Py_VISIT(traverse_module_state->__pyx_n_s_pack); + Py_VISIT(traverse_module_state->__pyx_n_s_pickle); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_PickleError); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_checksum); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_result); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_state); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_type); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_unpickle_Enum); + Py_VISIT(traverse_module_state->__pyx_n_s_pyx_vtable); + Py_VISIT(traverse_module_state->__pyx_n_s_range); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce_ex); + Py_VISIT(traverse_module_state->__pyx_n_s_register); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate); + Py_VISIT(traverse_module_state->__pyx_n_s_setstate_cython); + Py_VISIT(traverse_module_state->__pyx_n_s_shape); + Py_VISIT(traverse_module_state->__pyx_n_s_size); + Py_VISIT(traverse_module_state->__pyx_n_s_solve_vector_banded_matrix); + Py_VISIT(traverse_module_state->__pyx_n_s_spec); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_np_support_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_start); + Py_VISIT(traverse_module_state->__pyx_n_s_step); + Py_VISIT(traverse_module_state->__pyx_n_s_stop); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_direct); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_direct_or_indirect); + Py_VISIT(traverse_module_state->__pyx_kp_s_strided_and_indirect); + Py_VISIT(traverse_module_state->__pyx_kp_s_stringsource); + Py_VISIT(traverse_module_state->__pyx_n_s_struct); + Py_VISIT(traverse_module_state->__pyx_n_s_sys); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_kp_s_tuple_NDArray_NDArray_NDArray); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_typing_extensions); + Py_VISIT(traverse_module_state->__pyx_kp_s_unable_to_allocate_array_data); + Py_VISIT(traverse_module_state->__pyx_kp_s_unable_to_allocate_shape_and_str); + Py_VISIT(traverse_module_state->__pyx_n_s_unpack); + Py_VISIT(traverse_module_state->__pyx_n_s_update); + Py_VISIT(traverse_module_state->__pyx_n_s_upper); + Py_VISIT(traverse_module_state->__pyx_n_s_version_info); + Py_VISIT(traverse_module_state->__pyx_n_s_vertices); + Py_VISIT(traverse_module_state->__pyx_n_s_x); + Py_VISIT(traverse_module_state->__pyx_n_s_zeros); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_1); + Py_VISIT(traverse_module_state->__pyx_int_3); + Py_VISIT(traverse_module_state->__pyx_int_112105877); + Py_VISIT(traverse_module_state->__pyx_int_136983863); + Py_VISIT(traverse_module_state->__pyx_int_184977713); + Py_VISIT(traverse_module_state->__pyx_int_neg_1); + Py_VISIT(traverse_module_state->__pyx_slice__5); + Py_VISIT(traverse_module_state->__pyx_tuple__4); + Py_VISIT(traverse_module_state->__pyx_tuple__8); + Py_VISIT(traverse_module_state->__pyx_tuple__9); + Py_VISIT(traverse_module_state->__pyx_tuple__10); + Py_VISIT(traverse_module_state->__pyx_tuple__11); + Py_VISIT(traverse_module_state->__pyx_tuple__12); + Py_VISIT(traverse_module_state->__pyx_tuple__13); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__15); + Py_VISIT(traverse_module_state->__pyx_tuple__16); + Py_VISIT(traverse_module_state->__pyx_tuple__17); + Py_VISIT(traverse_module_state->__pyx_tuple__18); + Py_VISIT(traverse_module_state->__pyx_tuple__19); + Py_VISIT(traverse_module_state->__pyx_tuple__20); + Py_VISIT(traverse_module_state->__pyx_tuple__22); + Py_VISIT(traverse_module_state->__pyx_tuple__23); + Py_VISIT(traverse_module_state->__pyx_tuple__25); + Py_VISIT(traverse_module_state->__pyx_tuple__27); + Py_VISIT(traverse_module_state->__pyx_codeobj__21); + Py_VISIT(traverse_module_state->__pyx_codeobj__24); + Py_VISIT(traverse_module_state->__pyx_codeobj__26); + Py_VISIT(traverse_module_state->__pyx_codeobj__28); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#if CYTHON_USE_MODULE_STATE +#define __pyx_type___pyx_array __pyx_mstate_global->__pyx_type___pyx_array +#define __pyx_type___pyx_MemviewEnum __pyx_mstate_global->__pyx_type___pyx_MemviewEnum +#define __pyx_type___pyx_memoryview __pyx_mstate_global->__pyx_type___pyx_memoryview +#define __pyx_type___pyx_memoryviewslice __pyx_mstate_global->__pyx_type___pyx_memoryviewslice +#endif +#define __pyx_array_type __pyx_mstate_global->__pyx_array_type +#define __pyx_MemviewEnum_type __pyx_mstate_global->__pyx_MemviewEnum_type +#define __pyx_memoryview_type __pyx_mstate_global->__pyx_memoryview_type +#define __pyx_memoryviewslice_type __pyx_mstate_global->__pyx_memoryviewslice_type +#define __pyx_kp_u_ __pyx_mstate_global->__pyx_kp_u_ +#define __pyx_n_s_A __pyx_mstate_global->__pyx_n_s_A +#define __pyx_n_s_ASCII __pyx_mstate_global->__pyx_n_s_ASCII +#define __pyx_kp_s_All_dimensions_preceding_dimensi __pyx_mstate_global->__pyx_kp_s_All_dimensions_preceding_dimensi +#define __pyx_n_s_AssertionError __pyx_mstate_global->__pyx_n_s_AssertionError +#define __pyx_kp_u_At_least_3_vertices_required __pyx_mstate_global->__pyx_kp_u_At_least_3_vertices_required +#define __pyx_kp_s_Buffer_view_does_not_expose_stri __pyx_mstate_global->__pyx_kp_s_Buffer_view_does_not_expose_stri +#define __pyx_kp_s_Can_only_create_a_buffer_that_is __pyx_mstate_global->__pyx_kp_s_Can_only_create_a_buffer_that_is +#define __pyx_kp_s_Cannot_assign_to_read_only_memor __pyx_mstate_global->__pyx_kp_s_Cannot_assign_to_read_only_memor +#define __pyx_kp_s_Cannot_create_writable_memory_vi __pyx_mstate_global->__pyx_kp_s_Cannot_create_writable_memory_vi +#define __pyx_kp_u_Cannot_index_with_type __pyx_mstate_global->__pyx_kp_u_Cannot_index_with_type +#define __pyx_kp_s_Cannot_transpose_memoryview_with __pyx_mstate_global->__pyx_kp_s_Cannot_transpose_memoryview_with +#define __pyx_kp_s_Dimension_d_is_not_direct __pyx_mstate_global->__pyx_kp_s_Dimension_d_is_not_direct +#define __pyx_n_s_Ellipsis __pyx_mstate_global->__pyx_n_s_Ellipsis +#define __pyx_kp_s_Empty_shape_tuple_for_cython_arr __pyx_mstate_global->__pyx_kp_s_Empty_shape_tuple_for_cython_arr +#define __pyx_kp_s_Incompatible_checksums_0x_x_vs_0 __pyx_mstate_global->__pyx_kp_s_Incompatible_checksums_0x_x_vs_0 +#define __pyx_n_s_IndexError __pyx_mstate_global->__pyx_n_s_IndexError +#define __pyx_kp_s_Index_out_of_bounds_axis_d __pyx_mstate_global->__pyx_kp_s_Index_out_of_bounds_axis_d +#define __pyx_kp_s_Indirect_dimensions_not_supporte __pyx_mstate_global->__pyx_kp_s_Indirect_dimensions_not_supporte +#define __pyx_kp_u_Invalid_mode_expected_c_or_fortr __pyx_mstate_global->__pyx_kp_u_Invalid_mode_expected_c_or_fortr +#define __pyx_kp_u_Invalid_shape_in_axis __pyx_mstate_global->__pyx_kp_u_Invalid_shape_in_axis +#define __pyx_kp_u_Item_count_of_vector_x_has_to_ma __pyx_mstate_global->__pyx_kp_u_Item_count_of_vector_x_has_to_ma +#define __pyx_n_s_MemoryError __pyx_mstate_global->__pyx_n_s_MemoryError +#define __pyx_kp_s_MemoryView_of_r_at_0x_x __pyx_mstate_global->__pyx_kp_s_MemoryView_of_r_at_0x_x +#define __pyx_kp_s_MemoryView_of_r_object __pyx_mstate_global->__pyx_kp_s_MemoryView_of_r_object +#define __pyx_n_s_NDArray __pyx_mstate_global->__pyx_n_s_NDArray +#define __pyx_n_b_O __pyx_mstate_global->__pyx_n_b_O +#define __pyx_kp_u_Out_of_bounds_on_buffer_access_a __pyx_mstate_global->__pyx_kp_u_Out_of_bounds_on_buffer_access_a +#define __pyx_n_s_PickleError __pyx_mstate_global->__pyx_n_s_PickleError +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_kp_s_Step_may_not_be_zero_axis_d __pyx_mstate_global->__pyx_kp_s_Step_may_not_be_zero_axis_d +#define __pyx_n_s_TypeAlias __pyx_mstate_global->__pyx_n_s_TypeAlias +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_kp_s_Unable_to_convert_item_to_object __pyx_mstate_global->__pyx_kp_s_Unable_to_convert_item_to_object +#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError +#define __pyx_n_s_View_MemoryView __pyx_mstate_global->__pyx_n_s_View_MemoryView +#define __pyx_kp_u__2 __pyx_mstate_global->__pyx_kp_u__2 +#define __pyx_n_s__29 __pyx_mstate_global->__pyx_n_s__29 +#define __pyx_n_s__3 __pyx_mstate_global->__pyx_n_s__3 +#define __pyx_kp_u__6 __pyx_mstate_global->__pyx_kp_u__6 +#define __pyx_kp_u__7 __pyx_mstate_global->__pyx_kp_u__7 +#define __pyx_n_s_abc __pyx_mstate_global->__pyx_n_s_abc +#define __pyx_n_s_allocate_buffer __pyx_mstate_global->__pyx_n_s_allocate_buffer +#define __pyx_kp_u_and __pyx_mstate_global->__pyx_kp_u_and +#define __pyx_n_s_array __pyx_mstate_global->__pyx_n_s_array +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_base __pyx_mstate_global->__pyx_n_s_base +#define __pyx_n_s_bool __pyx_mstate_global->__pyx_n_s_bool +#define __pyx_n_s_c __pyx_mstate_global->__pyx_n_s_c +#define __pyx_n_u_c __pyx_mstate_global->__pyx_n_u_c +#define __pyx_n_s_class __pyx_mstate_global->__pyx_n_s_class +#define __pyx_n_s_class_getitem __pyx_mstate_global->__pyx_n_s_class_getitem +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_collections __pyx_mstate_global->__pyx_n_s_collections +#define __pyx_kp_s_collections_abc __pyx_mstate_global->__pyx_kp_s_collections_abc +#define __pyx_kp_s_contiguous_and_direct __pyx_mstate_global->__pyx_kp_s_contiguous_and_direct +#define __pyx_kp_s_contiguous_and_indirect __pyx_mstate_global->__pyx_kp_s_contiguous_and_indirect +#define __pyx_n_s_count __pyx_mstate_global->__pyx_n_s_count +#define __pyx_n_s_dict __pyx_mstate_global->__pyx_n_s_dict +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_dtype __pyx_mstate_global->__pyx_n_s_dtype +#define __pyx_n_s_dtype_is_object __pyx_mstate_global->__pyx_n_s_dtype_is_object +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_encode __pyx_mstate_global->__pyx_n_s_encode +#define __pyx_n_s_enumerate __pyx_mstate_global->__pyx_n_s_enumerate +#define __pyx_n_s_error __pyx_mstate_global->__pyx_n_s_error +#define __pyx_n_s_ezdxf_acc_np_support __pyx_mstate_global->__pyx_n_s_ezdxf_acc_np_support +#define __pyx_n_s_flags __pyx_mstate_global->__pyx_n_s_flags +#define __pyx_n_s_float64 __pyx_mstate_global->__pyx_n_s_float64 +#define __pyx_n_s_format __pyx_mstate_global->__pyx_n_s_format +#define __pyx_n_s_fortran __pyx_mstate_global->__pyx_n_s_fortran +#define __pyx_n_u_fortran __pyx_mstate_global->__pyx_n_u_fortran +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_getstate __pyx_mstate_global->__pyx_n_s_getstate +#define __pyx_kp_u_got __pyx_mstate_global->__pyx_kp_u_got +#define __pyx_kp_u_got_differing_extents_in_dimensi __pyx_mstate_global->__pyx_kp_u_got_differing_extents_in_dimensi +#define __pyx_n_s_has_clockwise_orientation __pyx_mstate_global->__pyx_n_s_has_clockwise_orientation +#define __pyx_n_s_id __pyx_mstate_global->__pyx_n_s_id +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_index __pyx_mstate_global->__pyx_n_s_index +#define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing +#define __pyx_n_s_int __pyx_mstate_global->__pyx_n_s_int +#define __pyx_n_s_int32 __pyx_mstate_global->__pyx_n_s_int32 +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_itemsize __pyx_mstate_global->__pyx_n_s_itemsize +#define __pyx_kp_s_itemsize_0_for_cython_array __pyx_mstate_global->__pyx_kp_s_itemsize_0_for_cython_array +#define __pyx_n_s_lower __pyx_mstate_global->__pyx_n_s_lower +#define __pyx_n_s_lu_decompose __pyx_mstate_global->__pyx_n_s_lu_decompose +#define __pyx_n_s_m1 __pyx_mstate_global->__pyx_n_s_m1 +#define __pyx_n_s_m2 __pyx_mstate_global->__pyx_n_s_m2 +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_memview __pyx_mstate_global->__pyx_n_s_memview +#define __pyx_n_s_mode __pyx_mstate_global->__pyx_n_s_mode +#define __pyx_n_s_n __pyx_mstate_global->__pyx_n_s_n +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_name_2 __pyx_mstate_global->__pyx_n_s_name_2 +#define __pyx_n_s_ndim __pyx_mstate_global->__pyx_n_s_ndim +#define __pyx_n_s_new __pyx_mstate_global->__pyx_n_s_new +#define __pyx_kp_s_no_default___reduce___due_to_non __pyx_mstate_global->__pyx_kp_s_no_default___reduce___due_to_non +#define __pyx_n_s_np __pyx_mstate_global->__pyx_n_s_np +#define __pyx_kp_s_np_ndarray __pyx_mstate_global->__pyx_kp_s_np_ndarray +#define __pyx_n_s_npt __pyx_mstate_global->__pyx_n_s_npt +#define __pyx_n_s_numpy __pyx_mstate_global->__pyx_n_s_numpy +#define __pyx_n_s_numpy_typing __pyx_mstate_global->__pyx_n_s_numpy_typing +#define __pyx_n_s_obj __pyx_mstate_global->__pyx_n_s_obj +#define __pyx_n_s_pack __pyx_mstate_global->__pyx_n_s_pack +#define __pyx_n_s_pickle __pyx_mstate_global->__pyx_n_s_pickle +#define __pyx_n_s_pyx_PickleError __pyx_mstate_global->__pyx_n_s_pyx_PickleError +#define __pyx_n_s_pyx_checksum __pyx_mstate_global->__pyx_n_s_pyx_checksum +#define __pyx_n_s_pyx_result __pyx_mstate_global->__pyx_n_s_pyx_result +#define __pyx_n_s_pyx_state __pyx_mstate_global->__pyx_n_s_pyx_state +#define __pyx_n_s_pyx_type __pyx_mstate_global->__pyx_n_s_pyx_type +#define __pyx_n_s_pyx_unpickle_Enum __pyx_mstate_global->__pyx_n_s_pyx_unpickle_Enum +#define __pyx_n_s_pyx_vtable __pyx_mstate_global->__pyx_n_s_pyx_vtable +#define __pyx_n_s_range __pyx_mstate_global->__pyx_n_s_range +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_reduce_cython __pyx_mstate_global->__pyx_n_s_reduce_cython +#define __pyx_n_s_reduce_ex __pyx_mstate_global->__pyx_n_s_reduce_ex +#define __pyx_n_s_register __pyx_mstate_global->__pyx_n_s_register +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_setstate __pyx_mstate_global->__pyx_n_s_setstate +#define __pyx_n_s_setstate_cython __pyx_mstate_global->__pyx_n_s_setstate_cython +#define __pyx_n_s_shape __pyx_mstate_global->__pyx_n_s_shape +#define __pyx_n_s_size __pyx_mstate_global->__pyx_n_s_size +#define __pyx_n_s_solve_vector_banded_matrix __pyx_mstate_global->__pyx_n_s_solve_vector_banded_matrix +#define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec +#define __pyx_kp_s_src_ezdxf_acc_np_support_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_np_support_pyx +#define __pyx_n_s_start __pyx_mstate_global->__pyx_n_s_start +#define __pyx_n_s_step __pyx_mstate_global->__pyx_n_s_step +#define __pyx_n_s_stop __pyx_mstate_global->__pyx_n_s_stop +#define __pyx_kp_s_strided_and_direct __pyx_mstate_global->__pyx_kp_s_strided_and_direct +#define __pyx_kp_s_strided_and_direct_or_indirect __pyx_mstate_global->__pyx_kp_s_strided_and_direct_or_indirect +#define __pyx_kp_s_strided_and_indirect __pyx_mstate_global->__pyx_kp_s_strided_and_indirect +#define __pyx_kp_s_stringsource __pyx_mstate_global->__pyx_kp_s_stringsource +#define __pyx_n_s_struct __pyx_mstate_global->__pyx_n_s_struct +#define __pyx_n_s_sys __pyx_mstate_global->__pyx_n_s_sys +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_kp_s_tuple_NDArray_NDArray_NDArray __pyx_mstate_global->__pyx_kp_s_tuple_NDArray_NDArray_NDArray +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_typing_extensions __pyx_mstate_global->__pyx_n_s_typing_extensions +#define __pyx_kp_s_unable_to_allocate_array_data __pyx_mstate_global->__pyx_kp_s_unable_to_allocate_array_data +#define __pyx_kp_s_unable_to_allocate_shape_and_str __pyx_mstate_global->__pyx_kp_s_unable_to_allocate_shape_and_str +#define __pyx_n_s_unpack __pyx_mstate_global->__pyx_n_s_unpack +#define __pyx_n_s_update __pyx_mstate_global->__pyx_n_s_update +#define __pyx_n_s_upper __pyx_mstate_global->__pyx_n_s_upper +#define __pyx_n_s_version_info __pyx_mstate_global->__pyx_n_s_version_info +#define __pyx_n_s_vertices __pyx_mstate_global->__pyx_n_s_vertices +#define __pyx_n_s_x __pyx_mstate_global->__pyx_n_s_x +#define __pyx_n_s_zeros __pyx_mstate_global->__pyx_n_s_zeros +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_1 __pyx_mstate_global->__pyx_int_1 +#define __pyx_int_3 __pyx_mstate_global->__pyx_int_3 +#define __pyx_int_112105877 __pyx_mstate_global->__pyx_int_112105877 +#define __pyx_int_136983863 __pyx_mstate_global->__pyx_int_136983863 +#define __pyx_int_184977713 __pyx_mstate_global->__pyx_int_184977713 +#define __pyx_int_neg_1 __pyx_mstate_global->__pyx_int_neg_1 +#define __pyx_slice__5 __pyx_mstate_global->__pyx_slice__5 +#define __pyx_tuple__4 __pyx_mstate_global->__pyx_tuple__4 +#define __pyx_tuple__8 __pyx_mstate_global->__pyx_tuple__8 +#define __pyx_tuple__9 __pyx_mstate_global->__pyx_tuple__9 +#define __pyx_tuple__10 __pyx_mstate_global->__pyx_tuple__10 +#define __pyx_tuple__11 __pyx_mstate_global->__pyx_tuple__11 +#define __pyx_tuple__12 __pyx_mstate_global->__pyx_tuple__12 +#define __pyx_tuple__13 __pyx_mstate_global->__pyx_tuple__13 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__15 __pyx_mstate_global->__pyx_tuple__15 +#define __pyx_tuple__16 __pyx_mstate_global->__pyx_tuple__16 +#define __pyx_tuple__17 __pyx_mstate_global->__pyx_tuple__17 +#define __pyx_tuple__18 __pyx_mstate_global->__pyx_tuple__18 +#define __pyx_tuple__19 __pyx_mstate_global->__pyx_tuple__19 +#define __pyx_tuple__20 __pyx_mstate_global->__pyx_tuple__20 +#define __pyx_tuple__22 __pyx_mstate_global->__pyx_tuple__22 +#define __pyx_tuple__23 __pyx_mstate_global->__pyx_tuple__23 +#define __pyx_tuple__25 __pyx_mstate_global->__pyx_tuple__25 +#define __pyx_tuple__27 __pyx_mstate_global->__pyx_tuple__27 +#define __pyx_codeobj__21 __pyx_mstate_global->__pyx_codeobj__21 +#define __pyx_codeobj__24 __pyx_mstate_global->__pyx_codeobj__24 +#define __pyx_codeobj__26 __pyx_mstate_global->__pyx_codeobj__26 +#define __pyx_codeobj__28 __pyx_mstate_global->__pyx_codeobj__28 +/* #### Code section: module_code ### */ + +/* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + +/* Python wrapper */ +static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_shape = 0; + Py_ssize_t __pyx_v_itemsize; + PyObject *__pyx_v_format = 0; + PyObject *__pyx_v_mode = 0; + int __pyx_v_allocate_buffer; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[5] = {0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_shape,&__pyx_n_s_itemsize,&__pyx_n_s_format,&__pyx_n_s_mode,&__pyx_n_s_allocate_buffer,0}; + values[3] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)__pyx_n_s_c)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_shape)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_itemsize)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 1); __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_format)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 2); __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_mode); + if (value) { values[3] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_allocate_buffer); + if (value) { values[4] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(1, 131, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_shape = ((PyObject*)values[0]); + __pyx_v_itemsize = __Pyx_PyIndex_AsSsize_t(values[1]); if (unlikely((__pyx_v_itemsize == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 131, __pyx_L3_error) + __pyx_v_format = values[2]; + __pyx_v_mode = values[3]; + if (values[4]) { + __pyx_v_allocate_buffer = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_allocate_buffer == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 132, __pyx_L3_error) + } else { + + /* "View.MemoryView":132 + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, + * mode="c", bint allocate_buffer=True): # <<<<<<<<<<<<<< + * + * cdef int idx + */ + __pyx_v_allocate_buffer = ((int)1); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, __pyx_nargs); __PYX_ERR(1, 131, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.array.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_shape), (&PyTuple_Type), 1, "shape", 1))) __PYX_ERR(1, 131, __pyx_L1_error) + if (unlikely(((PyObject *)__pyx_v_format) == Py_None)) { + PyErr_Format(PyExc_TypeError, "Argument '%.200s' must not be None", "format"); __PYX_ERR(1, 131, __pyx_L1_error) + } + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(((struct __pyx_array_obj *)__pyx_v_self), __pyx_v_shape, __pyx_v_itemsize, __pyx_v_format, __pyx_v_mode, __pyx_v_allocate_buffer); + + /* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = -1; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer) { + int __pyx_v_idx; + Py_ssize_t __pyx_v_dim; + char __pyx_v_order; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + unsigned int __pyx_t_7; + char *__pyx_t_8; + int __pyx_t_9; + Py_ssize_t __pyx_t_10; + Py_UCS4 __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + __Pyx_INCREF(__pyx_v_format); + + /* "View.MemoryView":137 + * cdef Py_ssize_t dim + * + * self.ndim = len(shape) # <<<<<<<<<<<<<< + * self.itemsize = itemsize + * + */ + if (unlikely(__pyx_v_shape == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 137, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyTuple_GET_SIZE(__pyx_v_shape); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(1, 137, __pyx_L1_error) + __pyx_v_self->ndim = ((int)__pyx_t_1); + + /* "View.MemoryView":138 + * + * self.ndim = len(shape) + * self.itemsize = itemsize # <<<<<<<<<<<<<< + * + * if not self.ndim: + */ + __pyx_v_self->itemsize = __pyx_v_itemsize; + + /* "View.MemoryView":140 + * self.itemsize = itemsize + * + * if not self.ndim: # <<<<<<<<<<<<<< + * raise ValueError, "Empty shape tuple for cython.array" + * + */ + __pyx_t_2 = (!(__pyx_v_self->ndim != 0)); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":141 + * + * if not self.ndim: + * raise ValueError, "Empty shape tuple for cython.array" # <<<<<<<<<<<<<< + * + * if itemsize <= 0: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Empty_shape_tuple_for_cython_arr, 0, 0); + __PYX_ERR(1, 141, __pyx_L1_error) + + /* "View.MemoryView":140 + * self.itemsize = itemsize + * + * if not self.ndim: # <<<<<<<<<<<<<< + * raise ValueError, "Empty shape tuple for cython.array" + * + */ + } + + /* "View.MemoryView":143 + * raise ValueError, "Empty shape tuple for cython.array" + * + * if itemsize <= 0: # <<<<<<<<<<<<<< + * raise ValueError, "itemsize <= 0 for cython.array" + * + */ + __pyx_t_2 = (__pyx_v_itemsize <= 0); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":144 + * + * if itemsize <= 0: + * raise ValueError, "itemsize <= 0 for cython.array" # <<<<<<<<<<<<<< + * + * if not isinstance(format, bytes): + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_itemsize_0_for_cython_array, 0, 0); + __PYX_ERR(1, 144, __pyx_L1_error) + + /* "View.MemoryView":143 + * raise ValueError, "Empty shape tuple for cython.array" + * + * if itemsize <= 0: # <<<<<<<<<<<<<< + * raise ValueError, "itemsize <= 0 for cython.array" + * + */ + } + + /* "View.MemoryView":146 + * raise ValueError, "itemsize <= 0 for cython.array" + * + * if not isinstance(format, bytes): # <<<<<<<<<<<<<< + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + */ + __pyx_t_2 = PyBytes_Check(__pyx_v_format); + __pyx_t_3 = (!__pyx_t_2); + if (__pyx_t_3) { + + /* "View.MemoryView":147 + * + * if not isinstance(format, bytes): + * format = format.encode('ASCII') # <<<<<<<<<<<<<< + * self._format = format # keep a reference to the byte string + * self.format = self._format + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_format, __pyx_n_s_encode); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + __pyx_t_7 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_7 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_n_s_ASCII}; + __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_7, 1+__pyx_t_7); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF_SET(__pyx_v_format, __pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":146 + * raise ValueError, "itemsize <= 0 for cython.array" + * + * if not isinstance(format, bytes): # <<<<<<<<<<<<<< + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + */ + } + + /* "View.MemoryView":148 + * if not isinstance(format, bytes): + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string # <<<<<<<<<<<<<< + * self.format = self._format + * + */ + if (!(likely(PyBytes_CheckExact(__pyx_v_format))||((__pyx_v_format) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_v_format))) __PYX_ERR(1, 148, __pyx_L1_error) + __pyx_t_4 = __pyx_v_format; + __Pyx_INCREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_v_self->_format); + __Pyx_DECREF(__pyx_v_self->_format); + __pyx_v_self->_format = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":149 + * format = format.encode('ASCII') + * self._format = format # keep a reference to the byte string + * self.format = self._format # <<<<<<<<<<<<<< + * + * + */ + if (unlikely(__pyx_v_self->_format == Py_None)) { + PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found"); + __PYX_ERR(1, 149, __pyx_L1_error) + } + __pyx_t_8 = __Pyx_PyBytes_AsWritableString(__pyx_v_self->_format); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) __PYX_ERR(1, 149, __pyx_L1_error) + __pyx_v_self->format = __pyx_t_8; + + /* "View.MemoryView":152 + * + * + * self._shape = PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2) # <<<<<<<<<<<<<< + * self._strides = self._shape + self.ndim + * + */ + __pyx_v_self->_shape = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * __pyx_v_self->ndim) * 2))); + + /* "View.MemoryView":153 + * + * self._shape = PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2) + * self._strides = self._shape + self.ndim # <<<<<<<<<<<<<< + * + * if not self._shape: + */ + __pyx_v_self->_strides = (__pyx_v_self->_shape + __pyx_v_self->ndim); + + /* "View.MemoryView":155 + * self._strides = self._shape + self.ndim + * + * if not self._shape: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate shape and strides." + * + */ + __pyx_t_3 = (!(__pyx_v_self->_shape != 0)); + if (unlikely(__pyx_t_3)) { + + /* "View.MemoryView":156 + * + * if not self._shape: + * raise MemoryError, "unable to allocate shape and strides." # <<<<<<<<<<<<<< + * + * + */ + __Pyx_Raise(__pyx_builtin_MemoryError, __pyx_kp_s_unable_to_allocate_shape_and_str, 0, 0); + __PYX_ERR(1, 156, __pyx_L1_error) + + /* "View.MemoryView":155 + * self._strides = self._shape + self.ndim + * + * if not self._shape: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate shape and strides." + * + */ + } + + /* "View.MemoryView":159 + * + * + * for idx, dim in enumerate(shape): # <<<<<<<<<<<<<< + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + */ + __pyx_t_9 = 0; + __pyx_t_4 = __pyx_v_shape; __Pyx_INCREF(__pyx_t_4); + __pyx_t_1 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 159, __pyx_L1_error) + #endif + if (__pyx_t_1 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_5); __pyx_t_1++; if (unlikely((0 < 0))) __PYX_ERR(1, 159, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_t_5); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 159, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_dim = __pyx_t_10; + __pyx_v_idx = __pyx_t_9; + __pyx_t_9 = (__pyx_t_9 + 1); + + /* "View.MemoryView":160 + * + * for idx, dim in enumerate(shape): + * if dim <= 0: # <<<<<<<<<<<<<< + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim + */ + __pyx_t_3 = (__pyx_v_dim <= 0); + if (unlikely(__pyx_t_3)) { + + /* "View.MemoryView":161 + * for idx, dim in enumerate(shape): + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." # <<<<<<<<<<<<<< + * self._shape[idx] = dim + * + */ + __pyx_t_5 = PyTuple_New(5); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = 0; + __pyx_t_11 = 127; + __Pyx_INCREF(__pyx_kp_u_Invalid_shape_in_axis); + __pyx_t_10 += 22; + __Pyx_GIVEREF(__pyx_kp_u_Invalid_shape_in_axis); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_kp_u_Invalid_shape_in_axis); + __pyx_t_6 = __Pyx_PyUnicode_From_int(__pyx_v_idx, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_10 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_6); + __pyx_t_6 = 0; + __Pyx_INCREF(__pyx_kp_u_); + __pyx_t_10 += 2; + __Pyx_GIVEREF(__pyx_kp_u_); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_kp_u_); + __pyx_t_6 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_10 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_6); + __pyx_t_6 = 0; + __Pyx_INCREF(__pyx_kp_u__2); + __pyx_t_10 += 1; + __Pyx_GIVEREF(__pyx_kp_u__2); + PyTuple_SET_ITEM(__pyx_t_5, 4, __pyx_kp_u__2); + __pyx_t_6 = __Pyx_PyUnicode_Join(__pyx_t_5, 5, __pyx_t_10, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_6, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(1, 161, __pyx_L1_error) + + /* "View.MemoryView":160 + * + * for idx, dim in enumerate(shape): + * if dim <= 0: # <<<<<<<<<<<<<< + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim + */ + } + + /* "View.MemoryView":162 + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + * self._shape[idx] = dim # <<<<<<<<<<<<<< + * + * cdef char order + */ + (__pyx_v_self->_shape[__pyx_v_idx]) = __pyx_v_dim; + + /* "View.MemoryView":159 + * + * + * for idx, dim in enumerate(shape): # <<<<<<<<<<<<<< + * if dim <= 0: + * raise ValueError, f"Invalid shape in axis {idx}: {dim}." + */ + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "View.MemoryView":165 + * + * cdef char order + * if mode == 'c': # <<<<<<<<<<<<<< + * order = b'C' + * self.mode = u'c' + */ + __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_v_mode, __pyx_n_s_c, Py_EQ)); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(1, 165, __pyx_L1_error) + if (__pyx_t_3) { + + /* "View.MemoryView":166 + * cdef char order + * if mode == 'c': + * order = b'C' # <<<<<<<<<<<<<< + * self.mode = u'c' + * elif mode == 'fortran': + */ + __pyx_v_order = 'C'; + + /* "View.MemoryView":167 + * if mode == 'c': + * order = b'C' + * self.mode = u'c' # <<<<<<<<<<<<<< + * elif mode == 'fortran': + * order = b'F' + */ + __Pyx_INCREF(__pyx_n_u_c); + __Pyx_GIVEREF(__pyx_n_u_c); + __Pyx_GOTREF(__pyx_v_self->mode); + __Pyx_DECREF(__pyx_v_self->mode); + __pyx_v_self->mode = __pyx_n_u_c; + + /* "View.MemoryView":165 + * + * cdef char order + * if mode == 'c': # <<<<<<<<<<<<<< + * order = b'C' + * self.mode = u'c' + */ + goto __pyx_L11; + } + + /* "View.MemoryView":168 + * order = b'C' + * self.mode = u'c' + * elif mode == 'fortran': # <<<<<<<<<<<<<< + * order = b'F' + * self.mode = u'fortran' + */ + __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_v_mode, __pyx_n_s_fortran, Py_EQ)); if (unlikely((__pyx_t_3 < 0))) __PYX_ERR(1, 168, __pyx_L1_error) + if (likely(__pyx_t_3)) { + + /* "View.MemoryView":169 + * self.mode = u'c' + * elif mode == 'fortran': + * order = b'F' # <<<<<<<<<<<<<< + * self.mode = u'fortran' + * else: + */ + __pyx_v_order = 'F'; + + /* "View.MemoryView":170 + * elif mode == 'fortran': + * order = b'F' + * self.mode = u'fortran' # <<<<<<<<<<<<<< + * else: + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" + */ + __Pyx_INCREF(__pyx_n_u_fortran); + __Pyx_GIVEREF(__pyx_n_u_fortran); + __Pyx_GOTREF(__pyx_v_self->mode); + __Pyx_DECREF(__pyx_v_self->mode); + __pyx_v_self->mode = __pyx_n_u_fortran; + + /* "View.MemoryView":168 + * order = b'C' + * self.mode = u'c' + * elif mode == 'fortran': # <<<<<<<<<<<<<< + * order = b'F' + * self.mode = u'fortran' + */ + goto __pyx_L11; + } + + /* "View.MemoryView":172 + * self.mode = u'fortran' + * else: + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" # <<<<<<<<<<<<<< + * + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) + */ + /*else*/ { + __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_v_mode, __pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyUnicode_Concat(__pyx_kp_u_Invalid_mode_expected_c_or_fortr, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_6, 0, 0); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __PYX_ERR(1, 172, __pyx_L1_error) + } + __pyx_L11:; + + /* "View.MemoryView":174 + * raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}" + * + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) # <<<<<<<<<<<<<< + * + * self.free_data = allocate_buffer + */ + __pyx_v_self->len = __pyx_fill_contig_strides_array(__pyx_v_self->_shape, __pyx_v_self->_strides, __pyx_v_itemsize, __pyx_v_self->ndim, __pyx_v_order); + + /* "View.MemoryView":176 + * self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) + * + * self.free_data = allocate_buffer # <<<<<<<<<<<<<< + * self.dtype_is_object = format == b'O' + * + */ + __pyx_v_self->free_data = __pyx_v_allocate_buffer; + + /* "View.MemoryView":177 + * + * self.free_data = allocate_buffer + * self.dtype_is_object = format == b'O' # <<<<<<<<<<<<<< + * + * if allocate_buffer: + */ + __pyx_t_6 = PyObject_RichCompare(__pyx_v_format, __pyx_n_b_O, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 177, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 177, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_self->dtype_is_object = __pyx_t_3; + + /* "View.MemoryView":179 + * self.dtype_is_object = format == b'O' + * + * if allocate_buffer: # <<<<<<<<<<<<<< + * _allocate_buffer(self) + * + */ + if (__pyx_v_allocate_buffer) { + + /* "View.MemoryView":180 + * + * if allocate_buffer: + * _allocate_buffer(self) # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + __pyx_t_9 = __pyx_array_allocate_buffer(__pyx_v_self); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(1, 180, __pyx_L1_error) + + /* "View.MemoryView":179 + * self.dtype_is_object = format == b'O' + * + * if allocate_buffer: # <<<<<<<<<<<<<< + * _allocate_buffer(self) + * + */ + } + + /* "View.MemoryView":131 + * cdef bint dtype_is_object + * + * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<< + * mode="c", bint allocate_buffer=True): + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.array.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_format); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":182 + * _allocate_buffer(self) + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + */ + +/* Python wrapper */ +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +CYTHON_UNUSED static int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(((struct __pyx_array_obj *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(struct __pyx_array_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_v_bufmode; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + char *__pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + Py_ssize_t *__pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + if (unlikely(__pyx_v_info == NULL)) { + PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); + return -1; + } + __Pyx_RefNannySetupContext("__getbuffer__", 0); + __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(__pyx_v_info->obj); + + /* "View.MemoryView":184 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 # <<<<<<<<<<<<<< + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": + */ + __pyx_v_bufmode = -1; + + /* "View.MemoryView":185 + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): # <<<<<<<<<<<<<< + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + __pyx_t_1 = ((__pyx_v_flags & ((PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS) | PyBUF_ANY_CONTIGUOUS)) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":186 + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": # <<<<<<<<<<<<<< + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + */ + __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_self->mode, __pyx_n_u_c, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 186, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":187 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS # <<<<<<<<<<<<<< + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + __pyx_v_bufmode = (PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS); + + /* "View.MemoryView":186 + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): + * if self.mode == u"c": # <<<<<<<<<<<<<< + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + */ + goto __pyx_L4; + } + + /* "View.MemoryView":188 + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": # <<<<<<<<<<<<<< + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + */ + __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_self->mode, __pyx_n_u_fortran, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 188, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":189 + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS # <<<<<<<<<<<<<< + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." + */ + __pyx_v_bufmode = (PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS); + + /* "View.MemoryView":188 + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * elif self.mode == u"fortran": # <<<<<<<<<<<<<< + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + */ + } + __pyx_L4:; + + /* "View.MemoryView":190 + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): # <<<<<<<<<<<<<< + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + */ + __pyx_t_1 = (!((__pyx_v_flags & __pyx_v_bufmode) != 0)); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":191 + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." # <<<<<<<<<<<<<< + * info.buf = self.data + * info.len = self.len + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Can_only_create_a_buffer_that_is, 0, 0); + __PYX_ERR(1, 191, __pyx_L1_error) + + /* "View.MemoryView":190 + * elif self.mode == u"fortran": + * bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + * if not (flags & bufmode): # <<<<<<<<<<<<<< + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + */ + } + + /* "View.MemoryView":185 + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + * if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS): # <<<<<<<<<<<<<< + * if self.mode == u"c": + * bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS + */ + } + + /* "View.MemoryView":192 + * if not (flags & bufmode): + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data # <<<<<<<<<<<<<< + * info.len = self.len + * + */ + __pyx_t_2 = __pyx_v_self->data; + __pyx_v_info->buf = __pyx_t_2; + + /* "View.MemoryView":193 + * raise ValueError, "Can only create a buffer that is contiguous in memory." + * info.buf = self.data + * info.len = self.len # <<<<<<<<<<<<<< + * + * if flags & PyBUF_STRIDES: + */ + __pyx_t_3 = __pyx_v_self->len; + __pyx_v_info->len = __pyx_t_3; + + /* "View.MemoryView":195 + * info.len = self.len + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.ndim = self.ndim + * info.shape = self._shape + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_STRIDES) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":196 + * + * if flags & PyBUF_STRIDES: + * info.ndim = self.ndim # <<<<<<<<<<<<<< + * info.shape = self._shape + * info.strides = self._strides + */ + __pyx_t_4 = __pyx_v_self->ndim; + __pyx_v_info->ndim = __pyx_t_4; + + /* "View.MemoryView":197 + * if flags & PyBUF_STRIDES: + * info.ndim = self.ndim + * info.shape = self._shape # <<<<<<<<<<<<<< + * info.strides = self._strides + * else: + */ + __pyx_t_5 = __pyx_v_self->_shape; + __pyx_v_info->shape = __pyx_t_5; + + /* "View.MemoryView":198 + * info.ndim = self.ndim + * info.shape = self._shape + * info.strides = self._strides # <<<<<<<<<<<<<< + * else: + * info.ndim = 1 + */ + __pyx_t_5 = __pyx_v_self->_strides; + __pyx_v_info->strides = __pyx_t_5; + + /* "View.MemoryView":195 + * info.len = self.len + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.ndim = self.ndim + * info.shape = self._shape + */ + goto __pyx_L6; + } + + /* "View.MemoryView":200 + * info.strides = self._strides + * else: + * info.ndim = 1 # <<<<<<<<<<<<<< + * info.shape = &self.len if flags & PyBUF_ND else NULL + * info.strides = NULL + */ + /*else*/ { + __pyx_v_info->ndim = 1; + + /* "View.MemoryView":201 + * else: + * info.ndim = 1 + * info.shape = &self.len if flags & PyBUF_ND else NULL # <<<<<<<<<<<<<< + * info.strides = NULL + * + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_ND) != 0); + if (__pyx_t_1) { + __pyx_t_5 = (&__pyx_v_self->len); + } else { + __pyx_t_5 = NULL; + } + __pyx_v_info->shape = __pyx_t_5; + + /* "View.MemoryView":202 + * info.ndim = 1 + * info.shape = &self.len if flags & PyBUF_ND else NULL + * info.strides = NULL # <<<<<<<<<<<<<< + * + * info.suboffsets = NULL + */ + __pyx_v_info->strides = NULL; + } + __pyx_L6:; + + /* "View.MemoryView":204 + * info.strides = NULL + * + * info.suboffsets = NULL # <<<<<<<<<<<<<< + * info.itemsize = self.itemsize + * info.readonly = 0 + */ + __pyx_v_info->suboffsets = NULL; + + /* "View.MemoryView":205 + * + * info.suboffsets = NULL + * info.itemsize = self.itemsize # <<<<<<<<<<<<<< + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL + */ + __pyx_t_3 = __pyx_v_self->itemsize; + __pyx_v_info->itemsize = __pyx_t_3; + + /* "View.MemoryView":206 + * info.suboffsets = NULL + * info.itemsize = self.itemsize + * info.readonly = 0 # <<<<<<<<<<<<<< + * info.format = self.format if flags & PyBUF_FORMAT else NULL + * info.obj = self + */ + __pyx_v_info->readonly = 0; + + /* "View.MemoryView":207 + * info.itemsize = self.itemsize + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL # <<<<<<<<<<<<<< + * info.obj = self + * + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + __pyx_t_2 = __pyx_v_self->format; + } else { + __pyx_t_2 = NULL; + } + __pyx_v_info->format = __pyx_t_2; + + /* "View.MemoryView":208 + * info.readonly = 0 + * info.format = self.format if flags & PyBUF_FORMAT else NULL + * info.obj = self # <<<<<<<<<<<<<< + * + * def __dealloc__(array self): + */ + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); + __pyx_v_info->obj = ((PyObject *)__pyx_v_self); + + /* "View.MemoryView":182 + * _allocate_buffer(self) + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * cdef int bufmode = -1 + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + if (__pyx_v_info->obj != NULL) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + goto __pyx_L2; + __pyx_L0:; + if (__pyx_v_info->obj == Py_None) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + __pyx_L2:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":210 + * info.obj = self + * + * def __dealloc__(array self): # <<<<<<<<<<<<<< + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + */ + +/* Python wrapper */ +static void __pyx_array___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_array___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(struct __pyx_array_obj *__pyx_v_self) { + int __pyx_t_1; + int __pyx_t_2; + + /* "View.MemoryView":211 + * + * def __dealloc__(array self): + * if self.callback_free_data != NULL: # <<<<<<<<<<<<<< + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + */ + __pyx_t_1 = (__pyx_v_self->callback_free_data != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":212 + * def __dealloc__(array self): + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) # <<<<<<<<<<<<<< + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: + */ + __pyx_v_self->callback_free_data(__pyx_v_self->data); + + /* "View.MemoryView":211 + * + * def __dealloc__(array self): + * if self.callback_free_data != NULL: # <<<<<<<<<<<<<< + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":213 + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + */ + if (__pyx_v_self->free_data) { + } else { + __pyx_t_1 = __pyx_v_self->free_data; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_self->data != NULL); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "View.MemoryView":214 + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":215 + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) # <<<<<<<<<<<<<< + * free(self.data) + * PyObject_Free(self._shape) + */ + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_self->data, __pyx_v_self->_shape, __pyx_v_self->_strides, __pyx_v_self->ndim, 0); + + /* "View.MemoryView":214 + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + */ + } + + /* "View.MemoryView":216 + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) # <<<<<<<<<<<<<< + * PyObject_Free(self._shape) + * + */ + free(__pyx_v_self->data); + + /* "View.MemoryView":213 + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + * elif self.free_data and self.data is not NULL: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + */ + } + __pyx_L3:; + + /* "View.MemoryView":217 + * refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False) + * free(self.data) + * PyObject_Free(self._shape) # <<<<<<<<<<<<<< + * + * @property + */ + PyObject_Free(__pyx_v_self->_shape); + + /* "View.MemoryView":210 + * info.obj = self + * + * def __dealloc__(array self): # <<<<<<<<<<<<<< + * if self.callback_free_data != NULL: + * self.callback_free_data(self.data) + */ + + /* function exit code */ +} + +/* "View.MemoryView":219 + * PyObject_Free(self._shape) + * + * @property # <<<<<<<<<<<<<< + * def memview(self): + * return self.get_memview() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_5array_7memview___get__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_5array_7memview___get__(struct __pyx_array_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":221 + * @property + * def memview(self): + * return self.get_memview() # <<<<<<<<<<<<<< + * + * @cname('get_memview') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((struct __pyx_vtabstruct_array *)__pyx_v_self->__pyx_vtab)->get_memview(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 221, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":219 + * PyObject_Free(self._shape) + * + * @property # <<<<<<<<<<<<<< + * def memview(self): + * return self.get_memview() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.array.memview.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":224 + * + * @cname('get_memview') + * cdef get_memview(self): # <<<<<<<<<<<<<< + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) + */ + +static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *__pyx_v_self) { + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_memview", 1); + + /* "View.MemoryView":225 + * @cname('get_memview') + * cdef get_memview(self): + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE # <<<<<<<<<<<<<< + * return memoryview(self, flags, self.dtype_is_object) + * + */ + __pyx_v_flags = ((PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) | PyBUF_WRITABLE); + + /* "View.MemoryView":226 + * cdef get_memview(self): + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) # <<<<<<<<<<<<<< + * + * def __len__(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_self->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_self))) __PYX_ERR(1, 226, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 226, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 226, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":224 + * + * @cname('get_memview') + * cdef get_memview(self): # <<<<<<<<<<<<<< + * flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE + * return memoryview(self, flags, self.dtype_is_object) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.array.get_memview", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":228 + * return memoryview(self, flags, self.dtype_is_object) + * + * def __len__(self): # <<<<<<<<<<<<<< + * return self._shape[0] + * + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_array___len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_array___len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(struct __pyx_array_obj *__pyx_v_self) { + Py_ssize_t __pyx_r; + + /* "View.MemoryView":229 + * + * def __len__(self): + * return self._shape[0] # <<<<<<<<<<<<<< + * + * def __getattr__(self, attr): + */ + __pyx_r = (__pyx_v_self->_shape[0]); + goto __pyx_L0; + + /* "View.MemoryView":228 + * return memoryview(self, flags, self.dtype_is_object) + * + * def __len__(self): # <<<<<<<<<<<<<< + * return self._shape[0] + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":231 + * return self._shape[0] + * + * def __getattr__(self, attr): # <<<<<<<<<<<<<< + * return getattr(self.memview, attr) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_array___getattr__(PyObject *__pyx_v_self, PyObject *__pyx_v_attr); /*proto*/ +static PyObject *__pyx_array___getattr__(PyObject *__pyx_v_self, PyObject *__pyx_v_attr) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getattr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_attr)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_attr) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getattr__", 1); + + /* "View.MemoryView":232 + * + * def __getattr__(self, attr): + * return getattr(self.memview, attr) # <<<<<<<<<<<<<< + * + * def __getitem__(self, item): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_GetAttr(__pyx_t_1, __pyx_v_attr); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":231 + * return self._shape[0] + * + * def __getattr__(self, attr): # <<<<<<<<<<<<<< + * return getattr(self.memview, attr) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.array.__getattr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":234 + * return getattr(self.memview, attr) + * + * def __getitem__(self, item): # <<<<<<<<<<<<<< + * return self.memview[item] + * + */ + +/* Python wrapper */ +static PyObject *__pyx_array___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item); /*proto*/ +static PyObject *__pyx_array___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_item)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "View.MemoryView":235 + * + * def __getitem__(self, item): + * return self.memview[item] # <<<<<<<<<<<<<< + * + * def __setitem__(self, item, value): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 235, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_t_1, __pyx_v_item); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 235, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":234 + * return getattr(self.memview, attr) + * + * def __getitem__(self, item): # <<<<<<<<<<<<<< + * return self.memview[item] + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.array.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":237 + * return self.memview[item] + * + * def __setitem__(self, item, value): # <<<<<<<<<<<<<< + * self.memview[item] = value + * + */ + +/* Python wrapper */ +static int __pyx_array___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value); /*proto*/ +static int __pyx_array___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(((struct __pyx_array_obj *)__pyx_v_self), ((PyObject *)__pyx_v_item), ((PyObject *)__pyx_v_value)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setitem__", 1); + + /* "View.MemoryView":238 + * + * def __setitem__(self, item, value): + * self.memview[item] = value # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_memview); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 238, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (unlikely((PyObject_SetItem(__pyx_t_1, __pyx_v_item, __pyx_v_value) < 0))) __PYX_ERR(1, 238, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "View.MemoryView":237 + * return self.memview[item] + * + * def __setitem__(self, item, value): # <<<<<<<<<<<<<< + * self.memview[item] = value + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.array.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_array_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_array_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_array___reduce_cython__(((struct __pyx_array_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_array___reduce_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_array_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_array_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.array.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_array_2__setstate_cython__(((struct __pyx_array_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_array_2__setstate_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.array.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":248 + * + * @cname("__pyx_array_allocate_buffer") + * cdef int _allocate_buffer(array self) except -1: # <<<<<<<<<<<<<< + * + * + */ + +static int __pyx_array_allocate_buffer(struct __pyx_array_obj *__pyx_v_self) { + Py_ssize_t __pyx_v_i; + PyObject **__pyx_v_p; + int __pyx_r; + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "View.MemoryView":254 + * cdef PyObject **p + * + * self.free_data = True # <<<<<<<<<<<<<< + * self.data = malloc(self.len) + * if not self.data: + */ + __pyx_v_self->free_data = 1; + + /* "View.MemoryView":255 + * + * self.free_data = True + * self.data = malloc(self.len) # <<<<<<<<<<<<<< + * if not self.data: + * raise MemoryError, "unable to allocate array data." + */ + __pyx_v_self->data = ((char *)malloc(__pyx_v_self->len)); + + /* "View.MemoryView":256 + * self.free_data = True + * self.data = malloc(self.len) + * if not self.data: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate array data." + * + */ + __pyx_t_1 = (!(__pyx_v_self->data != 0)); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":257 + * self.data = malloc(self.len) + * if not self.data: + * raise MemoryError, "unable to allocate array data." # <<<<<<<<<<<<<< + * + * if self.dtype_is_object: + */ + __Pyx_Raise(__pyx_builtin_MemoryError, __pyx_kp_s_unable_to_allocate_array_data, 0, 0); + __PYX_ERR(1, 257, __pyx_L1_error) + + /* "View.MemoryView":256 + * self.free_data = True + * self.data = malloc(self.len) + * if not self.data: # <<<<<<<<<<<<<< + * raise MemoryError, "unable to allocate array data." + * + */ + } + + /* "View.MemoryView":259 + * raise MemoryError, "unable to allocate array data." + * + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * p = self.data + * for i in range(self.len // self.itemsize): + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":260 + * + * if self.dtype_is_object: + * p = self.data # <<<<<<<<<<<<<< + * for i in range(self.len // self.itemsize): + * p[i] = Py_None + */ + __pyx_v_p = ((PyObject **)__pyx_v_self->data); + + /* "View.MemoryView":261 + * if self.dtype_is_object: + * p = self.data + * for i in range(self.len // self.itemsize): # <<<<<<<<<<<<<< + * p[i] = Py_None + * Py_INCREF(Py_None) + */ + if (unlikely(__pyx_v_self->itemsize == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 261, __pyx_L1_error) + } + else if (sizeof(Py_ssize_t) == sizeof(long) && (!(((Py_ssize_t)-1) > 0)) && unlikely(__pyx_v_self->itemsize == (Py_ssize_t)-1) && unlikely(__Pyx_UNARY_NEG_WOULD_OVERFLOW(__pyx_v_self->len))) { + PyErr_SetString(PyExc_OverflowError, "value too large to perform division"); + __PYX_ERR(1, 261, __pyx_L1_error) + } + __pyx_t_2 = __Pyx_div_Py_ssize_t(__pyx_v_self->len, __pyx_v_self->itemsize); + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":262 + * p = self.data + * for i in range(self.len // self.itemsize): + * p[i] = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * return 0 + */ + (__pyx_v_p[__pyx_v_i]) = Py_None; + + /* "View.MemoryView":263 + * for i in range(self.len // self.itemsize): + * p[i] = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * return 0 + * + */ + Py_INCREF(Py_None); + } + + /* "View.MemoryView":259 + * raise MemoryError, "unable to allocate array data." + * + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * p = self.data + * for i in range(self.len // self.itemsize): + */ + } + + /* "View.MemoryView":264 + * p[i] = Py_None + * Py_INCREF(Py_None) + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":248 + * + * @cname("__pyx_array_allocate_buffer") + * cdef int _allocate_buffer(array self) except -1: # <<<<<<<<<<<<<< + * + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._allocate_buffer", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":268 + * + * @cname("__pyx_array_new") + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): # <<<<<<<<<<<<<< + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + */ + +static struct __pyx_array_obj *__pyx_array_new(PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, char *__pyx_v_format, char *__pyx_v_c_mode, char *__pyx_v_buf) { + struct __pyx_array_obj *__pyx_v_result = 0; + PyObject *__pyx_v_mode = 0; + struct __pyx_array_obj *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("array_cwrapper", 1); + + /* "View.MemoryView":270 + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. # <<<<<<<<<<<<<< + * + * if buf is NULL: + */ + __pyx_t_2 = ((__pyx_v_c_mode[0]) == 'f'); + if (__pyx_t_2) { + __Pyx_INCREF(__pyx_n_s_fortran); + __pyx_t_1 = __pyx_n_s_fortran; + } else { + __Pyx_INCREF(__pyx_n_s_c); + __pyx_t_1 = __pyx_n_s_c; + } + __pyx_v_mode = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":272 + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + * + * if buf is NULL: # <<<<<<<<<<<<<< + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + */ + __pyx_t_2 = (__pyx_v_buf == NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":273 + * + * if buf is NULL: + * result = array.__new__(array, shape, itemsize, format, mode) # <<<<<<<<<<<<<< + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) + */ + __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_itemsize); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_format); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_shape)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_mode); + __Pyx_GIVEREF(__pyx_v_mode); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 3, __pyx_v_mode)) __PYX_ERR(1, 273, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_3 = 0; + __pyx_t_3 = ((PyObject *)__pyx_tp_new_array(((PyTypeObject *)__pyx_array_type), __pyx_t_4, NULL)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 273, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_result = ((struct __pyx_array_obj *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":272 + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + * + * if buf is NULL: # <<<<<<<<<<<<<< + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":275 + * result = array.__new__(array, shape, itemsize, format, mode) + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) # <<<<<<<<<<<<<< + * result.data = buf + * + */ + /*else*/ { + __pyx_t_3 = PyInt_FromSsize_t(__pyx_v_itemsize); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyBytes_FromString(__pyx_v_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_shape)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_mode); + __Pyx_GIVEREF(__pyx_v_mode); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_v_mode)) __PYX_ERR(1, 275, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_allocate_buffer, Py_False) < 0) __PYX_ERR(1, 275, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_tp_new_array(((PyTypeObject *)__pyx_array_type), __pyx_t_1, __pyx_t_4)); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 275, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_result = ((struct __pyx_array_obj *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":276 + * else: + * result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False) + * result.data = buf # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->data = __pyx_v_buf; + } + __pyx_L3:; + + /* "View.MemoryView":278 + * result.data = buf + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "View.MemoryView":268 + * + * @cname("__pyx_array_new") + * cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf): # <<<<<<<<<<<<<< + * cdef array result + * cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.array_cwrapper", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XDECREF(__pyx_v_mode); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":304 + * cdef class Enum(object): + * cdef object name + * def __init__(self, name): # <<<<<<<<<<<<<< + * self.name = name + * def __repr__(self): + */ + +/* Python wrapper */ +static int __pyx_MemviewEnum___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_MemviewEnum___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_name = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_name)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 304, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__init__") < 0)) __PYX_ERR(1, 304, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + } + __pyx_v_name = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 304, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.Enum.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self), __pyx_v_name); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v_name) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__", 1); + + /* "View.MemoryView":305 + * cdef object name + * def __init__(self, name): + * self.name = name # <<<<<<<<<<<<<< + * def __repr__(self): + * return self.name + */ + __Pyx_INCREF(__pyx_v_name); + __Pyx_GIVEREF(__pyx_v_name); + __Pyx_GOTREF(__pyx_v_self->name); + __Pyx_DECREF(__pyx_v_self->name); + __pyx_v_self->name = __pyx_v_name; + + /* "View.MemoryView":304 + * cdef class Enum(object): + * cdef object name + * def __init__(self, name): # <<<<<<<<<<<<<< + * self.name = name + * def __repr__(self): + */ + + /* function exit code */ + __pyx_r = 0; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":306 + * def __init__(self, name): + * self.name = name + * def __repr__(self): # <<<<<<<<<<<<<< + * return self.name + * + */ + +/* Python wrapper */ +static PyObject *__pyx_MemviewEnum___repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_MemviewEnum___repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(struct __pyx_MemviewEnum_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "View.MemoryView":307 + * self.name = name + * def __repr__(self): + * return self.name # <<<<<<<<<<<<<< + * + * cdef generic = Enum("") + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->name); + __pyx_r = __pyx_v_self->name; + goto __pyx_L0; + + /* "View.MemoryView":306 + * def __init__(self, name): + * self.name = name + * def __repr__(self): # <<<<<<<<<<<<<< + * return self.name + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_MemviewEnum_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_MemviewEnum_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_MemviewEnum___reduce_cython__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_MemviewEnum___reduce_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self) { + PyObject *__pyx_v_state = 0; + PyObject *__pyx_v__dict = 0; + int __pyx_v_use_setstate; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":5 + * cdef object _dict + * cdef bint use_setstate + * state = (self.name,) # <<<<<<<<<<<<<< + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_self->name); + __Pyx_GIVEREF(__pyx_v_self->name); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_self->name)) __PYX_ERR(1, 5, __pyx_L1_error); + __pyx_v_state = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "(tree fragment)":6 + * cdef bint use_setstate + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< + * if _dict is not None: + * state += (_dict,) + */ + __pyx_t_1 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__dict = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":7 + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + __pyx_t_2 = (__pyx_v__dict != Py_None); + if (__pyx_t_2) { + + /* "(tree fragment)":8 + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + * state += (_dict,) # <<<<<<<<<<<<<< + * use_setstate = True + * else: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v__dict); + __Pyx_GIVEREF(__pyx_v__dict); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v__dict)) __PYX_ERR(1, 8, __pyx_L1_error); + __pyx_t_3 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "(tree fragment)":9 + * if _dict is not None: + * state += (_dict,) + * use_setstate = True # <<<<<<<<<<<<<< + * else: + * use_setstate = self.name is not None + */ + __pyx_v_use_setstate = 1; + + /* "(tree fragment)":7 + * state = (self.name,) + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + goto __pyx_L3; + } + + /* "(tree fragment)":11 + * use_setstate = True + * else: + * use_setstate = self.name is not None # <<<<<<<<<<<<<< + * if use_setstate: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + */ + /*else*/ { + __pyx_t_2 = (__pyx_v_self->name != Py_None); + __pyx_v_use_setstate = __pyx_t_2; + } + __pyx_L3:; + + /* "(tree fragment)":12 + * else: + * use_setstate = self.name is not None + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + */ + if (__pyx_v_use_setstate) { + + /* "(tree fragment)":13 + * use_setstate = self.name is not None + * if use_setstate: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state # <<<<<<<<<<<<<< + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_pyx_unpickle_Enum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))))) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_136983863); + __Pyx_GIVEREF(__pyx_int_136983863); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_136983863)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, Py_None)) __PYX_ERR(1, 13, __pyx_L1_error); + __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_state)) __PYX_ERR(1, 13, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "(tree fragment)":12 + * else: + * use_setstate = self.name is not None + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + */ + } + + /* "(tree fragment)":15 + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, None), state + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pyx_unpickle_Enum); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))))) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_136983863); + __Pyx_GIVEREF(__pyx_int_136983863); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_136983863)) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_state)) __PYX_ERR(1, 15, __pyx_L1_error); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error); + __pyx_t_4 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + } + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.Enum.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_state); + __Pyx_XDECREF(__pyx_v__dict); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":16 + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_MemviewEnum_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_MemviewEnum_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 16, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 16, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 16, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.Enum.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_MemviewEnum_2__setstate_cython__(((struct __pyx_MemviewEnum_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_MemviewEnum_2__setstate_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":17 + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle_Enum__set_state(self, __pyx_state) # <<<<<<<<<<<<<< + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None) || __Pyx_RaiseUnexpectedTypeError("tuple", __pyx_v___pyx_state))) __PYX_ERR(1, 17, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle_Enum__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":16 + * else: + * return __pyx_unpickle_Enum, (type(self), 0x82a3537, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state(self, __pyx_state) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.Enum.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":349 + * cdef __Pyx_TypeInfo *typeinfo + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): # <<<<<<<<<<<<<< + * self.obj = obj + * self.flags = flags + */ + +/* Python wrapper */ +static int __pyx_memoryview___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_memoryview___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_obj = 0; + int __pyx_v_flags; + int __pyx_v_dtype_is_object; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_obj,&__pyx_n_s_flags,&__pyx_n_s_dtype_is_object,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_obj)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_flags)) != 0)) { + (void)__Pyx_Arg_NewRef_VARARGS(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 3, 1); __PYX_ERR(1, 349, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dtype_is_object); + if (value) { values[2] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__cinit__") < 0)) __PYX_ERR(1, 349, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1); + values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_obj = values[0]; + __pyx_v_flags = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + if (values[2]) { + __pyx_v_dtype_is_object = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_dtype_is_object == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L3_error) + } else { + __pyx_v_dtype_is_object = ((int)0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 3, __pyx_nargs); __PYX_ERR(1, 349, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.memoryview.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_obj, __pyx_v_flags, __pyx_v_dtype_is_object); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj, int __pyx_v_flags, int __pyx_v_dtype_is_object) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + Py_intptr_t __pyx_t_4; + size_t __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 1); + + /* "View.MemoryView":350 + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): + * self.obj = obj # <<<<<<<<<<<<<< + * self.flags = flags + * if type(self) is memoryview or obj is not None: + */ + __Pyx_INCREF(__pyx_v_obj); + __Pyx_GIVEREF(__pyx_v_obj); + __Pyx_GOTREF(__pyx_v_self->obj); + __Pyx_DECREF(__pyx_v_self->obj); + __pyx_v_self->obj = __pyx_v_obj; + + /* "View.MemoryView":351 + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): + * self.obj = obj + * self.flags = flags # <<<<<<<<<<<<<< + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + */ + __pyx_v_self->flags = __pyx_v_flags; + + /* "View.MemoryView":352 + * self.obj = obj + * self.flags = flags + * if type(self) is memoryview or obj is not None: # <<<<<<<<<<<<<< + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + */ + __pyx_t_2 = (((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self))) == ((PyObject *)__pyx_memoryview_type)); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_obj != Py_None); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "View.MemoryView":353 + * self.flags = flags + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) # <<<<<<<<<<<<<< + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None + */ + __pyx_t_3 = __Pyx_GetBuffer(__pyx_v_obj, (&__pyx_v_self->view), __pyx_v_flags); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 353, __pyx_L1_error) + + /* "View.MemoryView":354 + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) + */ + __pyx_t_1 = (((PyObject *)__pyx_v_self->view.obj) == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":355 + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_self->view))->obj = Py_None; + + /* "View.MemoryView":356 + * if self.view.obj == NULL: + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + */ + Py_INCREF(Py_None); + + /* "View.MemoryView":354 + * if type(self) is memoryview or obj is not None: + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &self.view).obj = Py_None + * Py_INCREF(Py_None) + */ + } + + /* "View.MemoryView":352 + * self.obj = obj + * self.flags = flags + * if type(self) is memoryview or obj is not None: # <<<<<<<<<<<<<< + * __Pyx_GetBuffer(obj, &self.view, flags) + * if self.view.obj == NULL: + */ + } + + /* "View.MemoryView":358 + * Py_INCREF(Py_None) + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): # <<<<<<<<<<<<<< + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + */ + __pyx_t_1 = (!__PYX_CYTHON_ATOMICS_ENABLED()); + if (__pyx_t_1) { + + /* "View.MemoryView":360 + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: # <<<<<<<<<<<<<< + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + */ + __pyx_t_1 = (__pyx_memoryview_thread_locks_used < 8); + if (__pyx_t_1) { + + /* "View.MemoryView":361 + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: + */ + __pyx_v_self->lock = (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]); + + /* "View.MemoryView":362 + * if __pyx_memoryview_thread_locks_used < 8: + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 # <<<<<<<<<<<<<< + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + */ + __pyx_memoryview_thread_locks_used = (__pyx_memoryview_thread_locks_used + 1); + + /* "View.MemoryView":360 + * if not __PYX_CYTHON_ATOMICS_ENABLED(): + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: # <<<<<<<<<<<<<< + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + */ + } + + /* "View.MemoryView":363 + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: # <<<<<<<<<<<<<< + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + */ + __pyx_t_1 = (__pyx_v_self->lock == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":364 + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() # <<<<<<<<<<<<<< + * if self.lock is NULL: + * raise MemoryError + */ + __pyx_v_self->lock = PyThread_allocate_lock(); + + /* "View.MemoryView":365 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + __pyx_t_1 = (__pyx_v_self->lock == NULL); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":366 + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + * raise MemoryError # <<<<<<<<<<<<<< + * + * if flags & PyBUF_FORMAT: + */ + PyErr_NoMemory(); __PYX_ERR(1, 366, __pyx_L1_error) + + /* "View.MemoryView":365 + * if self.lock is NULL: + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + } + + /* "View.MemoryView":363 + * self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] + * __pyx_memoryview_thread_locks_used += 1 + * if self.lock is NULL: # <<<<<<<<<<<<<< + * self.lock = PyThread_allocate_lock() + * if self.lock is NULL: + */ + } + + /* "View.MemoryView":358 + * Py_INCREF(Py_None) + * + * if not __PYX_CYTHON_ATOMICS_ENABLED(): # <<<<<<<<<<<<<< + * global __pyx_memoryview_thread_locks_used + * if __pyx_memoryview_thread_locks_used < 8: + */ + } + + /* "View.MemoryView":368 + * raise MemoryError + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":369 + * + * if flags & PyBUF_FORMAT: + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') # <<<<<<<<<<<<<< + * else: + * self.dtype_is_object = dtype_is_object + */ + __pyx_t_2 = ((__pyx_v_self->view.format[0]) == 'O'); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_2 = ((__pyx_v_self->view.format[1]) == '\x00'); + __pyx_t_1 = __pyx_t_2; + __pyx_L12_bool_binop_done:; + __pyx_v_self->dtype_is_object = __pyx_t_1; + + /* "View.MemoryView":368 + * raise MemoryError + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + */ + goto __pyx_L11; + } + + /* "View.MemoryView":371 + * self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') + * else: + * self.dtype_is_object = dtype_is_object # <<<<<<<<<<<<<< + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 + */ + /*else*/ { + __pyx_v_self->dtype_is_object = __pyx_v_dtype_is_object; + } + __pyx_L11:; + + /* "View.MemoryView":373 + * self.dtype_is_object = dtype_is_object + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 # <<<<<<<<<<<<<< + * self.typeinfo = NULL + * + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_4 = ((Py_intptr_t)((void *)(&__pyx_v_self->acquisition_count))); + __pyx_t_5 = (sizeof(__pyx_atomic_int_type)); + if (unlikely(__pyx_t_5 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 373, __pyx_L1_error) + } + __pyx_t_1 = ((__pyx_t_4 % __pyx_t_5) == 0); + if (unlikely(!__pyx_t_1)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(1, 373, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(1, 373, __pyx_L1_error) + #endif + + /* "View.MemoryView":374 + * + * assert (&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0 + * self.typeinfo = NULL # <<<<<<<<<<<<<< + * + * def __dealloc__(memoryview self): + */ + __pyx_v_self->typeinfo = NULL; + + /* "View.MemoryView":349 + * cdef __Pyx_TypeInfo *typeinfo + * + * def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): # <<<<<<<<<<<<<< + * self.obj = obj + * self.flags = flags + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":376 + * self.typeinfo = NULL + * + * def __dealloc__(memoryview self): # <<<<<<<<<<<<<< + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + */ + +/* Python wrapper */ +static void __pyx_memoryview___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_memoryview___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(struct __pyx_memoryview_obj *__pyx_v_self) { + int __pyx_v_i; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyThread_type_lock __pyx_t_5; + PyThread_type_lock __pyx_t_6; + + /* "View.MemoryView":377 + * + * def __dealloc__(memoryview self): + * if self.obj is not None: # <<<<<<<<<<<<<< + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + */ + __pyx_t_1 = (__pyx_v_self->obj != Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":378 + * def __dealloc__(memoryview self): + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) # <<<<<<<<<<<<<< + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + * + */ + __Pyx_ReleaseBuffer((&__pyx_v_self->view)); + + /* "View.MemoryView":377 + * + * def __dealloc__(memoryview self): + * if self.obj is not None: # <<<<<<<<<<<<<< + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":379 + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: # <<<<<<<<<<<<<< + * + * (<__pyx_buffer *> &self.view).obj = NULL + */ + __pyx_t_1 = (((Py_buffer *)(&__pyx_v_self->view))->obj == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":381 + * elif (<__pyx_buffer *> &self.view).obj == Py_None: + * + * (<__pyx_buffer *> &self.view).obj = NULL # <<<<<<<<<<<<<< + * Py_DECREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_self->view))->obj = NULL; + + /* "View.MemoryView":382 + * + * (<__pyx_buffer *> &self.view).obj = NULL + * Py_DECREF(Py_None) # <<<<<<<<<<<<<< + * + * cdef int i + */ + Py_DECREF(Py_None); + + /* "View.MemoryView":379 + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + * elif (<__pyx_buffer *> &self.view).obj == Py_None: # <<<<<<<<<<<<<< + * + * (<__pyx_buffer *> &self.view).obj = NULL + */ + } + __pyx_L3:; + + /* "View.MemoryView":386 + * cdef int i + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: # <<<<<<<<<<<<<< + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + */ + __pyx_t_1 = (__pyx_v_self->lock != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":387 + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): # <<<<<<<<<<<<<< + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + */ + __pyx_t_2 = __pyx_memoryview_thread_locks_used; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":388 + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + */ + __pyx_t_1 = ((__pyx_memoryview_thread_locks[__pyx_v_i]) == __pyx_v_self->lock); + if (__pyx_t_1) { + + /* "View.MemoryView":389 + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 # <<<<<<<<<<<<<< + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + */ + __pyx_memoryview_thread_locks_used = (__pyx_memoryview_thread_locks_used - 1); + + /* "View.MemoryView":390 + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + */ + __pyx_t_1 = (__pyx_v_i != __pyx_memoryview_thread_locks_used); + if (__pyx_t_1) { + + /* "View.MemoryView":392 + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) # <<<<<<<<<<<<<< + * break + * else: + */ + __pyx_t_5 = (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]); + __pyx_t_6 = (__pyx_memoryview_thread_locks[__pyx_v_i]); + + /* "View.MemoryView":391 + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + * break + */ + (__pyx_memoryview_thread_locks[__pyx_v_i]) = __pyx_t_5; + (__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]) = __pyx_t_6; + + /* "View.MemoryView":390 + * if __pyx_memoryview_thread_locks[i] is self.lock: + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + */ + } + + /* "View.MemoryView":393 + * __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( + * __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) + * break # <<<<<<<<<<<<<< + * else: + * PyThread_free_lock(self.lock) + */ + goto __pyx_L6_break; + + /* "View.MemoryView":388 + * if self.lock != NULL: + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: # <<<<<<<<<<<<<< + * __pyx_memoryview_thread_locks_used -= 1 + * if i != __pyx_memoryview_thread_locks_used: + */ + } + } + /*else*/ { + + /* "View.MemoryView":395 + * break + * else: + * PyThread_free_lock(self.lock) # <<<<<<<<<<<<<< + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: + */ + PyThread_free_lock(__pyx_v_self->lock); + } + __pyx_L6_break:; + + /* "View.MemoryView":386 + * cdef int i + * global __pyx_memoryview_thread_locks_used + * if self.lock != NULL: # <<<<<<<<<<<<<< + * for i in range(__pyx_memoryview_thread_locks_used): + * if __pyx_memoryview_thread_locks[i] is self.lock: + */ + } + + /* "View.MemoryView":376 + * self.typeinfo = NULL + * + * def __dealloc__(memoryview self): # <<<<<<<<<<<<<< + * if self.obj is not None: + * __Pyx_ReleaseBuffer(&self.view) + */ + + /* function exit code */ +} + +/* "View.MemoryView":397 + * PyThread_free_lock(self.lock) + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: # <<<<<<<<<<<<<< + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf + */ + +static char *__pyx_memoryview_get_item_pointer(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index) { + Py_ssize_t __pyx_v_dim; + char *__pyx_v_itemp; + PyObject *__pyx_v_idx = NULL; + char *__pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + Py_ssize_t __pyx_t_6; + char *__pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_item_pointer", 1); + + /* "View.MemoryView":399 + * cdef char *get_item_pointer(memoryview self, object index) except NULL: + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf # <<<<<<<<<<<<<< + * + * for dim, idx in enumerate(index): + */ + __pyx_v_itemp = ((char *)__pyx_v_self->view.buf); + + /* "View.MemoryView":401 + * cdef char *itemp = self.view.buf + * + * for dim, idx in enumerate(index): # <<<<<<<<<<<<<< + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + */ + __pyx_t_1 = 0; + if (likely(PyList_CheckExact(__pyx_v_index)) || PyTuple_CheckExact(__pyx_v_index)) { + __pyx_t_2 = __pyx_v_index; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_index); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 401, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_5); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(1, 401, __pyx_L1_error) + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 401, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + #endif + } + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 401, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_5); + } + __Pyx_XDECREF_SET(__pyx_v_idx, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_v_dim = __pyx_t_1; + __pyx_t_1 = (__pyx_t_1 + 1); + + /* "View.MemoryView":402 + * + * for dim, idx in enumerate(index): + * itemp = pybuffer_index(&self.view, itemp, idx, dim) # <<<<<<<<<<<<<< + * + * return itemp + */ + __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_v_idx); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 402, __pyx_L1_error) + __pyx_t_7 = __pyx_pybuffer_index((&__pyx_v_self->view), __pyx_v_itemp, __pyx_t_6, __pyx_v_dim); if (unlikely(__pyx_t_7 == ((char *)NULL))) __PYX_ERR(1, 402, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_7; + + /* "View.MemoryView":401 + * cdef char *itemp = self.view.buf + * + * for dim, idx in enumerate(index): # <<<<<<<<<<<<<< + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":404 + * itemp = pybuffer_index(&self.view, itemp, idx, dim) + * + * return itemp # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_itemp; + goto __pyx_L0; + + /* "View.MemoryView":397 + * PyThread_free_lock(self.lock) + * + * cdef char *get_item_pointer(memoryview self, object index) except NULL: # <<<<<<<<<<<<<< + * cdef Py_ssize_t dim + * cdef char *itemp = self.view.buf + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.get_item_pointer", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_idx); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":407 + * + * + * def __getitem__(memoryview self, object index): # <<<<<<<<<<<<<< + * if index is Ellipsis: + * return self + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index); /*proto*/ +static PyObject *__pyx_memoryview___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((PyObject *)__pyx_v_index)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index) { + PyObject *__pyx_v_have_slices = NULL; + PyObject *__pyx_v_indices = NULL; + char *__pyx_v_itemp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + char *__pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "View.MemoryView":408 + * + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: # <<<<<<<<<<<<<< + * return self + * + */ + __pyx_t_1 = (__pyx_v_index == __pyx_builtin_Ellipsis); + if (__pyx_t_1) { + + /* "View.MemoryView":409 + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: + * return self # <<<<<<<<<<<<<< + * + * have_slices, indices = _unellipsify(index, self.view.ndim) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = ((PyObject *)__pyx_v_self); + goto __pyx_L0; + + /* "View.MemoryView":408 + * + * def __getitem__(memoryview self, object index): + * if index is Ellipsis: # <<<<<<<<<<<<<< + * return self + * + */ + } + + /* "View.MemoryView":411 + * return self + * + * have_slices, indices = _unellipsify(index, self.view.ndim) # <<<<<<<<<<<<<< + * + * cdef char *itemp + */ + __pyx_t_2 = _unellipsify(__pyx_v_index, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (likely(__pyx_t_2 != Py_None)) { + PyObject* sequence = __pyx_t_2; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(1, 411, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else { + __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 411, __pyx_L1_error) + } + __pyx_v_have_slices = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_indices = __pyx_t_4; + __pyx_t_4 = 0; + + /* "View.MemoryView":414 + * + * cdef char *itemp + * if have_slices: # <<<<<<<<<<<<<< + * return memview_slice(self, indices) + * else: + */ + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_have_slices); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 414, __pyx_L1_error) + if (__pyx_t_1) { + + /* "View.MemoryView":415 + * cdef char *itemp + * if have_slices: + * return memview_slice(self, indices) # <<<<<<<<<<<<<< + * else: + * itemp = self.get_item_pointer(indices) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = ((PyObject *)__pyx_memview_slice(__pyx_v_self, __pyx_v_indices)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 415, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":414 + * + * cdef char *itemp + * if have_slices: # <<<<<<<<<<<<<< + * return memview_slice(self, indices) + * else: + */ + } + + /* "View.MemoryView":417 + * return memview_slice(self, indices) + * else: + * itemp = self.get_item_pointer(indices) # <<<<<<<<<<<<<< + * return self.convert_item_to_object(itemp) + * + */ + /*else*/ { + __pyx_t_5 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->get_item_pointer(__pyx_v_self, __pyx_v_indices); if (unlikely(__pyx_t_5 == ((char *)NULL))) __PYX_ERR(1, 417, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_5; + + /* "View.MemoryView":418 + * else: + * itemp = self.get_item_pointer(indices) + * return self.convert_item_to_object(itemp) # <<<<<<<<<<<<<< + * + * def __setitem__(memoryview self, object index, object value): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->convert_item_to_object(__pyx_v_self, __pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 418, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":407 + * + * + * def __getitem__(memoryview self, object index): # <<<<<<<<<<<<<< + * if index is Ellipsis: + * return self + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.memoryview.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_have_slices); + __Pyx_XDECREF(__pyx_v_indices); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":420 + * return self.convert_item_to_object(itemp) + * + * def __setitem__(memoryview self, object index, object value): # <<<<<<<<<<<<<< + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" + */ + +/* Python wrapper */ +static int __pyx_memoryview___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /*proto*/ +static int __pyx_memoryview___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((PyObject *)__pyx_v_index), ((PyObject *)__pyx_v_value)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + PyObject *__pyx_v_have_slices = NULL; + PyObject *__pyx_v_obj = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setitem__", 0); + __Pyx_INCREF(__pyx_v_index); + + /* "View.MemoryView":421 + * + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: # <<<<<<<<<<<<<< + * raise TypeError, "Cannot assign to read-only memoryview" + * + */ + if (unlikely(__pyx_v_self->view.readonly)) { + + /* "View.MemoryView":422 + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" # <<<<<<<<<<<<<< + * + * have_slices, index = _unellipsify(index, self.view.ndim) + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_Cannot_assign_to_read_only_memor, 0, 0); + __PYX_ERR(1, 422, __pyx_L1_error) + + /* "View.MemoryView":421 + * + * def __setitem__(memoryview self, object index, object value): + * if self.view.readonly: # <<<<<<<<<<<<<< + * raise TypeError, "Cannot assign to read-only memoryview" + * + */ + } + + /* "View.MemoryView":424 + * raise TypeError, "Cannot assign to read-only memoryview" + * + * have_slices, index = _unellipsify(index, self.view.ndim) # <<<<<<<<<<<<<< + * + * if have_slices: + */ + __pyx_t_1 = _unellipsify(__pyx_v_index, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(__pyx_t_1 != Py_None)) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(1, 424, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + #else + __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 424, __pyx_L1_error) + } + __pyx_v_have_slices = __pyx_t_2; + __pyx_t_2 = 0; + __Pyx_DECREF_SET(__pyx_v_index, __pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":426 + * have_slices, index = _unellipsify(index, self.view.ndim) + * + * if have_slices: # <<<<<<<<<<<<<< + * obj = self.is_slice(value) + * if obj is not None: + */ + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_have_slices); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(1, 426, __pyx_L1_error) + if (__pyx_t_4) { + + /* "View.MemoryView":427 + * + * if have_slices: + * obj = self.is_slice(value) # <<<<<<<<<<<<<< + * if obj is not None: + * self.setitem_slice_assignment(self[index], obj) + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->is_slice(__pyx_v_self, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_obj = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":428 + * if have_slices: + * obj = self.is_slice(value) + * if obj is not None: # <<<<<<<<<<<<<< + * self.setitem_slice_assignment(self[index], obj) + * else: + */ + __pyx_t_4 = (__pyx_v_obj != Py_None); + if (__pyx_t_4) { + + /* "View.MemoryView":429 + * obj = self.is_slice(value) + * if obj is not None: + * self.setitem_slice_assignment(self[index], obj) # <<<<<<<<<<<<<< + * else: + * self.setitem_slice_assign_scalar(self[index], value) + */ + __pyx_t_1 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_self), __pyx_v_index); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_slice_assignment(__pyx_v_self, __pyx_t_1, __pyx_v_obj); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "View.MemoryView":428 + * if have_slices: + * obj = self.is_slice(value) + * if obj is not None: # <<<<<<<<<<<<<< + * self.setitem_slice_assignment(self[index], obj) + * else: + */ + goto __pyx_L5; + } + + /* "View.MemoryView":431 + * self.setitem_slice_assignment(self[index], obj) + * else: + * self.setitem_slice_assign_scalar(self[index], value) # <<<<<<<<<<<<<< + * else: + * self.setitem_indexed(index, value) + */ + /*else*/ { + __pyx_t_3 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_self), __pyx_v_index); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_memoryview_type))))) __PYX_ERR(1, 431, __pyx_L1_error) + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_slice_assign_scalar(__pyx_v_self, ((struct __pyx_memoryview_obj *)__pyx_t_3), __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_L5:; + + /* "View.MemoryView":426 + * have_slices, index = _unellipsify(index, self.view.ndim) + * + * if have_slices: # <<<<<<<<<<<<<< + * obj = self.is_slice(value) + * if obj is not None: + */ + goto __pyx_L4; + } + + /* "View.MemoryView":433 + * self.setitem_slice_assign_scalar(self[index], value) + * else: + * self.setitem_indexed(index, value) # <<<<<<<<<<<<<< + * + * cdef is_slice(self, obj): + */ + /*else*/ { + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->setitem_indexed(__pyx_v_self, __pyx_v_index, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + __pyx_L4:; + + /* "View.MemoryView":420 + * return self.convert_item_to_object(itemp) + * + * def __setitem__(memoryview self, object index, object value): # <<<<<<<<<<<<<< + * if self.view.readonly: + * raise TypeError, "Cannot assign to read-only memoryview" + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_have_slices); + __Pyx_XDECREF(__pyx_v_obj); + __Pyx_XDECREF(__pyx_v_index); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":435 + * self.setitem_indexed(index, value) + * + * cdef is_slice(self, obj): # <<<<<<<<<<<<<< + * if not isinstance(obj, memoryview): + * try: + */ + +static PyObject *__pyx_memoryview_is_slice(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_slice", 0); + __Pyx_INCREF(__pyx_v_obj); + + /* "View.MemoryView":436 + * + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): # <<<<<<<<<<<<<< + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_obj, __pyx_memoryview_type); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_4, &__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_5); + /*try:*/ { + + /* "View.MemoryView":438 + * if not isinstance(obj, memoryview): + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, # <<<<<<<<<<<<<< + * self.dtype_is_object) + * except TypeError: + */ + __pyx_t_6 = __Pyx_PyInt_From_int(((__pyx_v_self->flags & (~PyBUF_WRITABLE)) | PyBUF_ANY_CONTIGUOUS)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "View.MemoryView":439 + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) # <<<<<<<<<<<<<< + * except TypeError: + * return None + */ + __pyx_t_7 = __Pyx_PyBool_FromLong(__pyx_v_self->dtype_is_object); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 439, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_7); + + /* "View.MemoryView":438 + * if not isinstance(obj, memoryview): + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, # <<<<<<<<<<<<<< + * self.dtype_is_object) + * except TypeError: + */ + __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_INCREF(__pyx_v_obj); + __Pyx_GIVEREF(__pyx_v_obj); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_v_obj)) __PYX_ERR(1, 438, __pyx_L4_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_6)) __PYX_ERR(1, 438, __pyx_L4_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_7)) __PYX_ERR(1, 438, __pyx_L4_error); + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_8, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 438, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF_SET(__pyx_v_obj, __pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L9_try_end; + __pyx_L4_error:; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "View.MemoryView":440 + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + * except TypeError: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_9 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_9) { + __Pyx_AddTraceback("View.MemoryView.memoryview.is_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_6) < 0) __PYX_ERR(1, 440, __pyx_L6_except_error) + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_6); + + /* "View.MemoryView":441 + * self.dtype_is_object) + * except TypeError: + * return None # <<<<<<<<<<<<<< + * + * return obj + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L7_except_return; + } + goto __pyx_L6_except_error; + + /* "View.MemoryView":437 + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): + * try: # <<<<<<<<<<<<<< + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + * self.dtype_is_object) + */ + __pyx_L6_except_error:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + goto __pyx_L1_error; + __pyx_L7_except_return:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + goto __pyx_L0; + __pyx_L9_try_end:; + } + + /* "View.MemoryView":436 + * + * cdef is_slice(self, obj): + * if not isinstance(obj, memoryview): # <<<<<<<<<<<<<< + * try: + * obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, + */ + } + + /* "View.MemoryView":443 + * return None + * + * return obj # <<<<<<<<<<<<<< + * + * cdef setitem_slice_assignment(self, dst, src): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_obj); + __pyx_r = __pyx_v_obj; + goto __pyx_L0; + + /* "View.MemoryView":435 + * self.setitem_indexed(index, value) + * + * cdef is_slice(self, obj): # <<<<<<<<<<<<<< + * if not isinstance(obj, memoryview): + * try: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_obj); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":445 + * return obj + * + * cdef setitem_slice_assignment(self, dst, src): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + */ + +static PyObject *__pyx_memoryview_setitem_slice_assignment(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_dst, PyObject *__pyx_v_src) { + __Pyx_memviewslice __pyx_v_dst_slice; + __Pyx_memviewslice __pyx_v_src_slice; + __Pyx_memviewslice __pyx_v_msrc; + __Pyx_memviewslice __pyx_v_mdst; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_slice_assignment", 1); + + /* "View.MemoryView":448 + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + * cdef __Pyx_memviewslice msrc = get_slice_from_memview(src, &src_slice)[0] # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] + * + */ + if (!(likely(((__pyx_v_src) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_src, __pyx_memoryview_type))))) __PYX_ERR(1, 448, __pyx_L1_error) + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(((struct __pyx_memoryview_obj *)__pyx_v_src), (&__pyx_v_src_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 448, __pyx_L1_error) + __pyx_v_msrc = (__pyx_t_1[0]); + + /* "View.MemoryView":449 + * cdef __Pyx_memviewslice src_slice + * cdef __Pyx_memviewslice msrc = get_slice_from_memview(src, &src_slice)[0] + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] # <<<<<<<<<<<<<< + * + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + */ + if (!(likely(((__pyx_v_dst) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_dst, __pyx_memoryview_type))))) __PYX_ERR(1, 449, __pyx_L1_error) + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(((struct __pyx_memoryview_obj *)__pyx_v_dst), (&__pyx_v_dst_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 449, __pyx_L1_error) + __pyx_v_mdst = (__pyx_t_1[0]); + + /* "View.MemoryView":451 + * cdef __Pyx_memviewslice mdst = get_slice_from_memview(dst, &dst_slice)[0] + * + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) # <<<<<<<<<<<<<< + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_src, __pyx_n_s_ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_dst, __pyx_n_s_ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_t_2); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 451, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __pyx_memoryview_copy_contents(__pyx_v_msrc, __pyx_v_mdst, __pyx_t_3, __pyx_t_4, __pyx_v_self->dtype_is_object); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 451, __pyx_L1_error) + + /* "View.MemoryView":445 + * return obj + * + * cdef setitem_slice_assignment(self, dst, src): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice dst_slice + * cdef __Pyx_memviewslice src_slice + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_slice_assignment", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":453 + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): # <<<<<<<<<<<<<< + * cdef int array[128] + * cdef void *tmp = NULL + */ + +static PyObject *__pyx_memoryview_setitem_slice_assign_scalar(struct __pyx_memoryview_obj *__pyx_v_self, struct __pyx_memoryview_obj *__pyx_v_dst, PyObject *__pyx_v_value) { + int __pyx_v_array[0x80]; + void *__pyx_v_tmp; + void *__pyx_v_item; + __Pyx_memviewslice *__pyx_v_dst_slice; + __Pyx_memviewslice __pyx_v_tmp_slice; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + char const *__pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_slice_assign_scalar", 1); + + /* "View.MemoryView":455 + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): + * cdef int array[128] + * cdef void *tmp = NULL # <<<<<<<<<<<<<< + * cdef void *item + * + */ + __pyx_v_tmp = NULL; + + /* "View.MemoryView":460 + * cdef __Pyx_memviewslice *dst_slice + * cdef __Pyx_memviewslice tmp_slice + * dst_slice = get_slice_from_memview(dst, &tmp_slice) # <<<<<<<<<<<<<< + * + * if self.view.itemsize > sizeof(array): + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_dst, (&__pyx_v_tmp_slice)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 460, __pyx_L1_error) + __pyx_v_dst_slice = __pyx_t_1; + + /* "View.MemoryView":462 + * dst_slice = get_slice_from_memview(dst, &tmp_slice) + * + * if self.view.itemsize > sizeof(array): # <<<<<<<<<<<<<< + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + */ + __pyx_t_2 = (((size_t)__pyx_v_self->view.itemsize) > (sizeof(__pyx_v_array))); + if (__pyx_t_2) { + + /* "View.MemoryView":463 + * + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) # <<<<<<<<<<<<<< + * if tmp == NULL: + * raise MemoryError + */ + __pyx_v_tmp = PyMem_Malloc(__pyx_v_self->view.itemsize); + + /* "View.MemoryView":464 + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * item = tmp + */ + __pyx_t_2 = (__pyx_v_tmp == NULL); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":465 + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + * raise MemoryError # <<<<<<<<<<<<<< + * item = tmp + * else: + */ + PyErr_NoMemory(); __PYX_ERR(1, 465, __pyx_L1_error) + + /* "View.MemoryView":464 + * if self.view.itemsize > sizeof(array): + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: # <<<<<<<<<<<<<< + * raise MemoryError + * item = tmp + */ + } + + /* "View.MemoryView":466 + * if tmp == NULL: + * raise MemoryError + * item = tmp # <<<<<<<<<<<<<< + * else: + * item = array + */ + __pyx_v_item = __pyx_v_tmp; + + /* "View.MemoryView":462 + * dst_slice = get_slice_from_memview(dst, &tmp_slice) + * + * if self.view.itemsize > sizeof(array): # <<<<<<<<<<<<<< + * tmp = PyMem_Malloc(self.view.itemsize) + * if tmp == NULL: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":468 + * item = tmp + * else: + * item = array # <<<<<<<<<<<<<< + * + * try: + */ + /*else*/ { + __pyx_v_item = ((void *)__pyx_v_array); + } + __pyx_L3:; + + /* "View.MemoryView":470 + * item = array + * + * try: # <<<<<<<<<<<<<< + * if self.dtype_is_object: + * ( item)[0] = value + */ + /*try:*/ { + + /* "View.MemoryView":471 + * + * try: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * ( item)[0] = value + * else: + */ + if (__pyx_v_self->dtype_is_object) { + + /* "View.MemoryView":472 + * try: + * if self.dtype_is_object: + * ( item)[0] = value # <<<<<<<<<<<<<< + * else: + * self.assign_item_from_object( item, value) + */ + (((PyObject **)__pyx_v_item)[0]) = ((PyObject *)__pyx_v_value); + + /* "View.MemoryView":471 + * + * try: + * if self.dtype_is_object: # <<<<<<<<<<<<<< + * ( item)[0] = value + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":474 + * ( item)[0] = value + * else: + * self.assign_item_from_object( item, value) # <<<<<<<<<<<<<< + * + * + */ + /*else*/ { + __pyx_t_3 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->assign_item_from_object(__pyx_v_self, ((char *)__pyx_v_item), __pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 474, __pyx_L6_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L8:; + + /* "View.MemoryView":478 + * + * + * if self.view.suboffsets != NULL: # <<<<<<<<<<<<<< + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + */ + __pyx_t_2 = (__pyx_v_self->view.suboffsets != NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":479 + * + * if self.view.suboffsets != NULL: + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) # <<<<<<<<<<<<<< + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + * item, self.dtype_is_object) + */ + __pyx_t_4 = assert_direct_dimensions(__pyx_v_self->view.suboffsets, __pyx_v_self->view.ndim); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 479, __pyx_L6_error) + + /* "View.MemoryView":478 + * + * + * if self.view.suboffsets != NULL: # <<<<<<<<<<<<<< + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, + */ + } + + /* "View.MemoryView":480 + * if self.view.suboffsets != NULL: + * assert_direct_dimensions(self.view.suboffsets, self.view.ndim) + * slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, # <<<<<<<<<<<<<< + * item, self.dtype_is_object) + * finally: + */ + __pyx_memoryview_slice_assign_scalar(__pyx_v_dst_slice, __pyx_v_dst->view.ndim, __pyx_v_self->view.itemsize, __pyx_v_item, __pyx_v_self->dtype_is_object); + } + + /* "View.MemoryView":483 + * item, self.dtype_is_object) + * finally: + * PyMem_Free(tmp) # <<<<<<<<<<<<<< + * + * cdef setitem_indexed(self, index, value): + */ + /*finally:*/ { + /*normal exit:*/{ + PyMem_Free(__pyx_v_tmp); + goto __pyx_L7; + } + __pyx_L6_error:; + /*exception exit:*/{ + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_10, &__pyx_t_11, &__pyx_t_12); + if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9) < 0)) __Pyx_ErrFetch(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + __pyx_t_4 = __pyx_lineno; __pyx_t_5 = __pyx_clineno; __pyx_t_6 = __pyx_filename; + { + PyMem_Free(__pyx_v_tmp); + } + if (PY_MAJOR_VERSION >= 3) { + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); + } + __Pyx_XGIVEREF(__pyx_t_7); + __Pyx_XGIVEREF(__pyx_t_8); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_ErrRestore(__pyx_t_7, __pyx_t_8, __pyx_t_9); + __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; + __pyx_lineno = __pyx_t_4; __pyx_clineno = __pyx_t_5; __pyx_filename = __pyx_t_6; + goto __pyx_L1_error; + } + __pyx_L7:; + } + + /* "View.MemoryView":453 + * memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object) + * + * cdef setitem_slice_assign_scalar(self, memoryview dst, value): # <<<<<<<<<<<<<< + * cdef int array[128] + * cdef void *tmp = NULL + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_slice_assign_scalar", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":485 + * PyMem_Free(tmp) + * + * cdef setitem_indexed(self, index, value): # <<<<<<<<<<<<<< + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) + */ + +static PyObject *__pyx_memoryview_setitem_indexed(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value) { + char *__pyx_v_itemp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + char *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("setitem_indexed", 1); + + /* "View.MemoryView":486 + * + * cdef setitem_indexed(self, index, value): + * cdef char *itemp = self.get_item_pointer(index) # <<<<<<<<<<<<<< + * self.assign_item_from_object(itemp, value) + * + */ + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->get_item_pointer(__pyx_v_self, __pyx_v_index); if (unlikely(__pyx_t_1 == ((char *)NULL))) __PYX_ERR(1, 486, __pyx_L1_error) + __pyx_v_itemp = __pyx_t_1; + + /* "View.MemoryView":487 + * cdef setitem_indexed(self, index, value): + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) # <<<<<<<<<<<<<< + * + * cdef convert_item_to_object(self, char *itemp): + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->assign_item_from_object(__pyx_v_self, __pyx_v_itemp, __pyx_v_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":485 + * PyMem_Free(tmp) + * + * cdef setitem_indexed(self, index, value): # <<<<<<<<<<<<<< + * cdef char *itemp = self.get_item_pointer(index) + * self.assign_item_from_object(itemp, value) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.setitem_indexed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":489 + * self.assign_item_from_object(itemp, value) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + +static PyObject *__pyx_memoryview_convert_item_to_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp) { + PyObject *__pyx_v_struct = NULL; + PyObject *__pyx_v_bytesitem = 0; + PyObject *__pyx_v_result = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + unsigned int __pyx_t_8; + Py_ssize_t __pyx_t_9; + int __pyx_t_10; + int __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("convert_item_to_object", 1); + + /* "View.MemoryView":492 + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + * import struct # <<<<<<<<<<<<<< + * cdef bytes bytesitem + * + */ + __pyx_t_1 = __Pyx_ImportDottedModule(__pyx_n_s_struct, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 492, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_struct = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":495 + * cdef bytes bytesitem + * + * bytesitem = itemp[:self.view.itemsize] # <<<<<<<<<<<<<< + * try: + * result = struct.unpack(self.view.format, bytesitem) + */ + __pyx_t_1 = __Pyx_PyBytes_FromStringAndSize(__pyx_v_itemp + 0, __pyx_v_self->view.itemsize - 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 495, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_bytesitem = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_2, &__pyx_t_3, &__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_4); + /*try:*/ { + + /* "View.MemoryView":497 + * bytesitem = itemp[:self.view.itemsize] + * try: + * result = struct.unpack(self.view.format, bytesitem) # <<<<<<<<<<<<<< + * except struct.error: + * raise ValueError, "Unable to convert item to object" + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_unpack); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_8 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_7, __pyx_t_6, __pyx_v_bytesitem}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_8, 2+__pyx_t_8); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 497, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __pyx_v_result = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + } + + /* "View.MemoryView":501 + * raise ValueError, "Unable to convert item to object" + * else: + * if len(self.view.format) == 1: # <<<<<<<<<<<<<< + * return result[0] + * return result + */ + /*else:*/ { + __pyx_t_9 = __Pyx_ssize_strlen(__pyx_v_self->view.format); if (unlikely(__pyx_t_9 == ((Py_ssize_t)-1))) __PYX_ERR(1, 501, __pyx_L5_except_error) + __pyx_t_10 = (__pyx_t_9 == 1); + if (__pyx_t_10) { + + /* "View.MemoryView":502 + * else: + * if len(self.view.format) == 1: + * return result[0] # <<<<<<<<<<<<<< + * return result + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_result, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 502, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L6_except_return; + + /* "View.MemoryView":501 + * raise ValueError, "Unable to convert item to object" + * else: + * if len(self.view.format) == 1: # <<<<<<<<<<<<<< + * return result[0] + * return result + */ + } + + /* "View.MemoryView":503 + * if len(self.view.format) == 1: + * return result[0] + * return result # <<<<<<<<<<<<<< + * + * cdef assign_item_from_object(self, char *itemp, object value): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_result); + __pyx_r = __pyx_v_result; + goto __pyx_L6_except_return; + } + __pyx_L3_error:; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":498 + * try: + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: # <<<<<<<<<<<<<< + * raise ValueError, "Unable to convert item to object" + * else: + */ + __Pyx_ErrFetch(&__pyx_t_1, &__pyx_t_5, &__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_error); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 498, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_11 = __Pyx_PyErr_GivenExceptionMatches(__pyx_t_1, __pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_ErrRestore(__pyx_t_1, __pyx_t_5, __pyx_t_6); + __pyx_t_1 = 0; __pyx_t_5 = 0; __pyx_t_6 = 0; + if (__pyx_t_11) { + __Pyx_AddTraceback("View.MemoryView.memoryview.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_5, &__pyx_t_1) < 0) __PYX_ERR(1, 498, __pyx_L5_except_error) + __Pyx_XGOTREF(__pyx_t_6); + __Pyx_XGOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_1); + + /* "View.MemoryView":499 + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + * raise ValueError, "Unable to convert item to object" # <<<<<<<<<<<<<< + * else: + * if len(self.view.format) == 1: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Unable_to_convert_item_to_object, 0, 0); + __PYX_ERR(1, 499, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + + /* "View.MemoryView":496 + * + * bytesitem = itemp[:self.view.itemsize] + * try: # <<<<<<<<<<<<<< + * result = struct.unpack(self.view.format, bytesitem) + * except struct.error: + */ + __pyx_L5_except_error:; + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_ExceptionReset(__pyx_t_2, __pyx_t_3, __pyx_t_4); + goto __pyx_L1_error; + __pyx_L6_except_return:; + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_ExceptionReset(__pyx_t_2, __pyx_t_3, __pyx_t_4); + goto __pyx_L0; + } + + /* "View.MemoryView":489 + * self.assign_item_from_object(itemp, value) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView.memoryview.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_struct); + __Pyx_XDECREF(__pyx_v_bytesitem); + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":505 + * return result + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + +static PyObject *__pyx_memoryview_assign_item_from_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value) { + PyObject *__pyx_v_struct = NULL; + char __pyx_v_c; + PyObject *__pyx_v_bytesvalue = 0; + Py_ssize_t __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + Py_ssize_t __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + char *__pyx_t_9; + char *__pyx_t_10; + char *__pyx_t_11; + char *__pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("assign_item_from_object", 1); + + /* "View.MemoryView":508 + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + * import struct # <<<<<<<<<<<<<< + * cdef char c + * cdef bytes bytesvalue + */ + __pyx_t_1 = __Pyx_ImportDottedModule(__pyx_n_s_struct, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_struct = __pyx_t_1; + __pyx_t_1 = 0; + + /* "View.MemoryView":513 + * cdef Py_ssize_t i + * + * if isinstance(value, tuple): # <<<<<<<<<<<<<< + * bytesvalue = struct.pack(self.view.format, *value) + * else: + */ + __pyx_t_2 = PyTuple_Check(__pyx_v_value); + if (__pyx_t_2) { + + /* "View.MemoryView":514 + * + * if isinstance(value, tuple): + * bytesvalue = struct.pack(self.view.format, *value) # <<<<<<<<<<<<<< + * else: + * bytesvalue = struct.pack(self.view.format, value) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_pack); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PySequence_Tuple(__pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = PyNumber_Add(__pyx_t_4, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_3))) __PYX_ERR(1, 514, __pyx_L1_error) + __pyx_v_bytesvalue = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":513 + * cdef Py_ssize_t i + * + * if isinstance(value, tuple): # <<<<<<<<<<<<<< + * bytesvalue = struct.pack(self.view.format, *value) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":516 + * bytesvalue = struct.pack(self.view.format, *value) + * else: + * bytesvalue = struct.pack(self.view.format, value) # <<<<<<<<<<<<<< + * + * for i, c in enumerate(bytesvalue): + */ + /*else*/ { + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_struct, __pyx_n_s_pack); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __Pyx_PyBytes_FromString(__pyx_v_self->view.format); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_1, __pyx_v_value}; + __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_3))) __PYX_ERR(1, 516, __pyx_L1_error) + __pyx_v_bytesvalue = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "View.MemoryView":518 + * bytesvalue = struct.pack(self.view.format, value) + * + * for i, c in enumerate(bytesvalue): # <<<<<<<<<<<<<< + * itemp[i] = c + * + */ + __pyx_t_7 = 0; + if (unlikely(__pyx_v_bytesvalue == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' is not iterable"); + __PYX_ERR(1, 518, __pyx_L1_error) + } + __Pyx_INCREF(__pyx_v_bytesvalue); + __pyx_t_8 = __pyx_v_bytesvalue; + __pyx_t_10 = PyBytes_AS_STRING(__pyx_t_8); + __pyx_t_11 = (__pyx_t_10 + PyBytes_GET_SIZE(__pyx_t_8)); + for (__pyx_t_12 = __pyx_t_10; __pyx_t_12 < __pyx_t_11; __pyx_t_12++) { + __pyx_t_9 = __pyx_t_12; + __pyx_v_c = (__pyx_t_9[0]); + + /* "View.MemoryView":519 + * + * for i, c in enumerate(bytesvalue): + * itemp[i] = c # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + __pyx_v_i = __pyx_t_7; + + /* "View.MemoryView":518 + * bytesvalue = struct.pack(self.view.format, value) + * + * for i, c in enumerate(bytesvalue): # <<<<<<<<<<<<<< + * itemp[i] = c + * + */ + __pyx_t_7 = (__pyx_t_7 + 1); + + /* "View.MemoryView":519 + * + * for i, c in enumerate(bytesvalue): + * itemp[i] = c # <<<<<<<<<<<<<< + * + * @cname('getbuffer') + */ + (__pyx_v_itemp[__pyx_v_i]) = __pyx_v_c; + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "View.MemoryView":505 + * return result + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * """Only used if instantiated manually by the user, or if Cython doesn't + * know how to convert the type""" + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memoryview.assign_item_from_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_struct); + __Pyx_XDECREF(__pyx_v_bytesvalue); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":521 + * itemp[i] = c + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + */ + +/* Python wrapper */ +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +CYTHON_UNUSED static int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(((struct __pyx_memoryview_obj *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(struct __pyx_memoryview_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + Py_ssize_t *__pyx_t_3; + char *__pyx_t_4; + void *__pyx_t_5; + int __pyx_t_6; + Py_ssize_t __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + if (unlikely(__pyx_v_info == NULL)) { + PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); + return -1; + } + __Pyx_RefNannySetupContext("__getbuffer__", 0); + __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(__pyx_v_info->obj); + + /* "View.MemoryView":523 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: # <<<<<<<<<<<<<< + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + */ + __pyx_t_2 = ((__pyx_v_flags & PyBUF_WRITABLE) != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_1 = __pyx_v_self->view.readonly; + __pyx_L4_bool_binop_done:; + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":524 + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + * raise ValueError, "Cannot create writable memory view from read-only memoryview" # <<<<<<<<<<<<<< + * + * if flags & PyBUF_ND: + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Cannot_create_writable_memory_vi, 0, 0); + __PYX_ERR(1, 524, __pyx_L1_error) + + /* "View.MemoryView":523 + * @cname('getbuffer') + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: # <<<<<<<<<<<<<< + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + */ + } + + /* "View.MemoryView":526 + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + * if flags & PyBUF_ND: # <<<<<<<<<<<<<< + * info.shape = self.view.shape + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_ND) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":527 + * + * if flags & PyBUF_ND: + * info.shape = self.view.shape # <<<<<<<<<<<<<< + * else: + * info.shape = NULL + */ + __pyx_t_3 = __pyx_v_self->view.shape; + __pyx_v_info->shape = __pyx_t_3; + + /* "View.MemoryView":526 + * raise ValueError, "Cannot create writable memory view from read-only memoryview" + * + * if flags & PyBUF_ND: # <<<<<<<<<<<<<< + * info.shape = self.view.shape + * else: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":529 + * info.shape = self.view.shape + * else: + * info.shape = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_STRIDES: + */ + /*else*/ { + __pyx_v_info->shape = NULL; + } + __pyx_L6:; + + /* "View.MemoryView":531 + * info.shape = NULL + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.strides = self.view.strides + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_STRIDES) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":532 + * + * if flags & PyBUF_STRIDES: + * info.strides = self.view.strides # <<<<<<<<<<<<<< + * else: + * info.strides = NULL + */ + __pyx_t_3 = __pyx_v_self->view.strides; + __pyx_v_info->strides = __pyx_t_3; + + /* "View.MemoryView":531 + * info.shape = NULL + * + * if flags & PyBUF_STRIDES: # <<<<<<<<<<<<<< + * info.strides = self.view.strides + * else: + */ + goto __pyx_L7; + } + + /* "View.MemoryView":534 + * info.strides = self.view.strides + * else: + * info.strides = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_INDIRECT: + */ + /*else*/ { + __pyx_v_info->strides = NULL; + } + __pyx_L7:; + + /* "View.MemoryView":536 + * info.strides = NULL + * + * if flags & PyBUF_INDIRECT: # <<<<<<<<<<<<<< + * info.suboffsets = self.view.suboffsets + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_INDIRECT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":537 + * + * if flags & PyBUF_INDIRECT: + * info.suboffsets = self.view.suboffsets # <<<<<<<<<<<<<< + * else: + * info.suboffsets = NULL + */ + __pyx_t_3 = __pyx_v_self->view.suboffsets; + __pyx_v_info->suboffsets = __pyx_t_3; + + /* "View.MemoryView":536 + * info.strides = NULL + * + * if flags & PyBUF_INDIRECT: # <<<<<<<<<<<<<< + * info.suboffsets = self.view.suboffsets + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":539 + * info.suboffsets = self.view.suboffsets + * else: + * info.suboffsets = NULL # <<<<<<<<<<<<<< + * + * if flags & PyBUF_FORMAT: + */ + /*else*/ { + __pyx_v_info->suboffsets = NULL; + } + __pyx_L8:; + + /* "View.MemoryView":541 + * info.suboffsets = NULL + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * info.format = self.view.format + * else: + */ + __pyx_t_1 = ((__pyx_v_flags & PyBUF_FORMAT) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":542 + * + * if flags & PyBUF_FORMAT: + * info.format = self.view.format # <<<<<<<<<<<<<< + * else: + * info.format = NULL + */ + __pyx_t_4 = __pyx_v_self->view.format; + __pyx_v_info->format = __pyx_t_4; + + /* "View.MemoryView":541 + * info.suboffsets = NULL + * + * if flags & PyBUF_FORMAT: # <<<<<<<<<<<<<< + * info.format = self.view.format + * else: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":544 + * info.format = self.view.format + * else: + * info.format = NULL # <<<<<<<<<<<<<< + * + * info.buf = self.view.buf + */ + /*else*/ { + __pyx_v_info->format = NULL; + } + __pyx_L9:; + + /* "View.MemoryView":546 + * info.format = NULL + * + * info.buf = self.view.buf # <<<<<<<<<<<<<< + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize + */ + __pyx_t_5 = __pyx_v_self->view.buf; + __pyx_v_info->buf = __pyx_t_5; + + /* "View.MemoryView":547 + * + * info.buf = self.view.buf + * info.ndim = self.view.ndim # <<<<<<<<<<<<<< + * info.itemsize = self.view.itemsize + * info.len = self.view.len + */ + __pyx_t_6 = __pyx_v_self->view.ndim; + __pyx_v_info->ndim = __pyx_t_6; + + /* "View.MemoryView":548 + * info.buf = self.view.buf + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize # <<<<<<<<<<<<<< + * info.len = self.view.len + * info.readonly = self.view.readonly + */ + __pyx_t_7 = __pyx_v_self->view.itemsize; + __pyx_v_info->itemsize = __pyx_t_7; + + /* "View.MemoryView":549 + * info.ndim = self.view.ndim + * info.itemsize = self.view.itemsize + * info.len = self.view.len # <<<<<<<<<<<<<< + * info.readonly = self.view.readonly + * info.obj = self + */ + __pyx_t_7 = __pyx_v_self->view.len; + __pyx_v_info->len = __pyx_t_7; + + /* "View.MemoryView":550 + * info.itemsize = self.view.itemsize + * info.len = self.view.len + * info.readonly = self.view.readonly # <<<<<<<<<<<<<< + * info.obj = self + * + */ + __pyx_t_1 = __pyx_v_self->view.readonly; + __pyx_v_info->readonly = __pyx_t_1; + + /* "View.MemoryView":551 + * info.len = self.view.len + * info.readonly = self.view.readonly + * info.obj = self # <<<<<<<<<<<<<< + * + * + */ + __Pyx_INCREF((PyObject *)__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_v_self); + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); + __pyx_v_info->obj = ((PyObject *)__pyx_v_self); + + /* "View.MemoryView":521 + * itemp[i] = c + * + * @cname('getbuffer') # <<<<<<<<<<<<<< + * def __getbuffer__(self, Py_buffer *info, int flags): + * if flags & PyBUF_WRITABLE and self.view.readonly: + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + if (__pyx_v_info->obj != NULL) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + goto __pyx_L2; + __pyx_L0:; + if (__pyx_v_info->obj == Py_None) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + __pyx_L2:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":554 + * + * + * @property # <<<<<<<<<<<<<< + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + struct __pyx_memoryviewslice_obj *__pyx_v_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":556 + * @property + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) # <<<<<<<<<<<<<< + * transpose_memslice(&result.from_slice) + * return result + */ + __pyx_t_1 = __pyx_memoryview_copy_object(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 556, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_memoryviewslice_type))))) __PYX_ERR(1, 556, __pyx_L1_error) + __pyx_v_result = ((struct __pyx_memoryviewslice_obj *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":557 + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + * transpose_memslice(&result.from_slice) # <<<<<<<<<<<<<< + * return result + * + */ + __pyx_t_2 = __pyx_memslice_transpose((&__pyx_v_result->from_slice)); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(1, 557, __pyx_L1_error) + + /* "View.MemoryView":558 + * cdef _memoryviewslice result = memoryview_copy(self) + * transpose_memslice(&result.from_slice) + * return result # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":554 + * + * + * @property # <<<<<<<<<<<<<< + * def T(self): + * cdef _memoryviewslice result = memoryview_copy(self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.T.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":560 + * return result + * + * @property # <<<<<<<<<<<<<< + * def base(self): + * return self._get_base() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":562 + * @property + * def base(self): + * return self._get_base() # <<<<<<<<<<<<<< + * + * cdef _get_base(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((struct __pyx_vtabstruct_memoryview *)__pyx_v_self->__pyx_vtab)->_get_base(__pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 562, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":560 + * return result + * + * @property # <<<<<<<<<<<<<< + * def base(self): + * return self._get_base() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.base.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":564 + * return self._get_base() + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.obj + * + */ + +static PyObject *__pyx_memoryview__get_base(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_get_base", 1); + + /* "View.MemoryView":565 + * + * cdef _get_base(self): + * return self.obj # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->obj); + __pyx_r = __pyx_v_self->obj; + goto __pyx_L0; + + /* "View.MemoryView":564 + * return self._get_base() + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.obj + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":567 + * return self.obj + * + * @property # <<<<<<<<<<<<<< + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_7genexpr__pyx_v_length; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":569 + * @property + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = (__pyx_v_self->view.shape + __pyx_v_self->view.ndim); + for (__pyx_t_4 = __pyx_v_self->view.shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_7genexpr__pyx_v_length = (__pyx_t_2[0]); + __pyx_t_5 = PyInt_FromSsize_t(__pyx_7genexpr__pyx_v_length); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + } /* exit inner scope */ + __pyx_t_5 = PyList_AsTuple(((PyObject*)__pyx_t_1)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 569, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "View.MemoryView":567 + * return self.obj + * + * @property # <<<<<<<<<<<<<< + * def shape(self): + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.shape.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":571 + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def strides(self): + * if self.view.strides == NULL: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_8genexpr1__pyx_v_stride; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + Py_ssize_t *__pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":573 + * @property + * def strides(self): + * if self.view.strides == NULL: # <<<<<<<<<<<<<< + * + * raise ValueError, "Buffer view does not expose strides" + */ + __pyx_t_1 = (__pyx_v_self->view.strides == NULL); + if (unlikely(__pyx_t_1)) { + + /* "View.MemoryView":575 + * if self.view.strides == NULL: + * + * raise ValueError, "Buffer view does not expose strides" # <<<<<<<<<<<<<< + * + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Buffer_view_does_not_expose_stri, 0, 0); + __PYX_ERR(1, 575, __pyx_L1_error) + + /* "View.MemoryView":573 + * @property + * def strides(self): + * if self.view.strides == NULL: # <<<<<<<<<<<<<< + * + * raise ValueError, "Buffer view does not expose strides" + */ + } + + /* "View.MemoryView":577 + * raise ValueError, "Buffer view does not expose strides" + * + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (__pyx_v_self->view.strides + __pyx_v_self->view.ndim); + for (__pyx_t_5 = __pyx_v_self->view.strides; __pyx_t_5 < __pyx_t_4; __pyx_t_5++) { + __pyx_t_3 = __pyx_t_5; + __pyx_8genexpr1__pyx_v_stride = (__pyx_t_3[0]); + __pyx_t_6 = PyInt_FromSsize_t(__pyx_8genexpr1__pyx_v_stride); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } /* exit inner scope */ + __pyx_t_6 = PyList_AsTuple(((PyObject*)__pyx_t_2)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "View.MemoryView":571 + * return tuple([length for length in self.view.shape[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def strides(self): + * if self.view.strides == NULL: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.memoryview.strides.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":579 + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def suboffsets(self): + * if self.view.suboffsets == NULL: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_8genexpr2__pyx_v_suboffset; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + Py_ssize_t *__pyx_t_5; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":581 + * @property + * def suboffsets(self): + * if self.view.suboffsets == NULL: # <<<<<<<<<<<<<< + * return (-1,) * self.view.ndim + * + */ + __pyx_t_1 = (__pyx_v_self->view.suboffsets == NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":582 + * def suboffsets(self): + * if self.view.suboffsets == NULL: + * return (-1,) * self.view.ndim # <<<<<<<<<<<<<< + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PySequence_Multiply(__pyx_tuple__4, __pyx_v_self->view.ndim); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":581 + * @property + * def suboffsets(self): + * if self.view.suboffsets == NULL: # <<<<<<<<<<<<<< + * return (-1,) * self.view.ndim + * + */ + } + + /* "View.MemoryView":584 + * return (-1,) * self.view.ndim + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (__pyx_v_self->view.suboffsets + __pyx_v_self->view.ndim); + for (__pyx_t_5 = __pyx_v_self->view.suboffsets; __pyx_t_5 < __pyx_t_4; __pyx_t_5++) { + __pyx_t_3 = __pyx_t_5; + __pyx_8genexpr2__pyx_v_suboffset = (__pyx_t_3[0]); + __pyx_t_6 = PyInt_FromSsize_t(__pyx_8genexpr2__pyx_v_suboffset); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } /* exit inner scope */ + __pyx_t_6 = PyList_AsTuple(((PyObject*)__pyx_t_2)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "View.MemoryView":579 + * return tuple([stride for stride in self.view.strides[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def suboffsets(self): + * if self.view.suboffsets == NULL: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("View.MemoryView.memoryview.suboffsets.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":586 + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def ndim(self): + * return self.view.ndim + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":588 + * @property + * def ndim(self): + * return self.view.ndim # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->view.ndim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 588, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":586 + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + * + * @property # <<<<<<<<<<<<<< + * def ndim(self): + * return self.view.ndim + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.ndim.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":590 + * return self.view.ndim + * + * @property # <<<<<<<<<<<<<< + * def itemsize(self): + * return self.view.itemsize + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":592 + * @property + * def itemsize(self): + * return self.view.itemsize # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_self->view.itemsize); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":590 + * return self.view.ndim + * + * @property # <<<<<<<<<<<<<< + * def itemsize(self): + * return self.view.itemsize + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview.itemsize.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":594 + * return self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def nbytes(self): + * return self.size * self.view.itemsize + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":596 + * @property + * def nbytes(self): + * return self.size * self.view.itemsize # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_self->view.itemsize); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "View.MemoryView":594 + * return self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def nbytes(self): + * return self.size * self.view.itemsize + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.nbytes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":598 + * return self.size * self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def size(self): + * if self._size is None: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_v_result = NULL; + PyObject *__pyx_v_length = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "View.MemoryView":600 + * @property + * def size(self): + * if self._size is None: # <<<<<<<<<<<<<< + * result = 1 + * + */ + __pyx_t_1 = (__pyx_v_self->_size == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":601 + * def size(self): + * if self._size is None: + * result = 1 # <<<<<<<<<<<<<< + * + * for length in self.view.shape[:self.view.ndim]: + */ + __Pyx_INCREF(__pyx_int_1); + __pyx_v_result = __pyx_int_1; + + /* "View.MemoryView":603 + * result = 1 + * + * for length in self.view.shape[:self.view.ndim]: # <<<<<<<<<<<<<< + * result *= length + * + */ + __pyx_t_3 = (__pyx_v_self->view.shape + __pyx_v_self->view.ndim); + for (__pyx_t_4 = __pyx_v_self->view.shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_t_5 = PyInt_FromSsize_t((__pyx_t_2[0])); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 603, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_5); + __pyx_t_5 = 0; + + /* "View.MemoryView":604 + * + * for length in self.view.shape[:self.view.ndim]: + * result *= length # <<<<<<<<<<<<<< + * + * self._size = result + */ + __pyx_t_5 = PyNumber_InPlaceMultiply(__pyx_v_result, __pyx_v_length); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 604, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF_SET(__pyx_v_result, __pyx_t_5); + __pyx_t_5 = 0; + } + + /* "View.MemoryView":606 + * result *= length + * + * self._size = result # <<<<<<<<<<<<<< + * + * return self._size + */ + __Pyx_INCREF(__pyx_v_result); + __Pyx_GIVEREF(__pyx_v_result); + __Pyx_GOTREF(__pyx_v_self->_size); + __Pyx_DECREF(__pyx_v_self->_size); + __pyx_v_self->_size = __pyx_v_result; + + /* "View.MemoryView":600 + * @property + * def size(self): + * if self._size is None: # <<<<<<<<<<<<<< + * result = 1 + * + */ + } + + /* "View.MemoryView":608 + * self._size = result + * + * return self._size # <<<<<<<<<<<<<< + * + * def __len__(self): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->_size); + __pyx_r = __pyx_v_self->_size; + goto __pyx_L0; + + /* "View.MemoryView":598 + * return self.size * self.view.itemsize + * + * @property # <<<<<<<<<<<<<< + * def size(self): + * if self._size is None: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.memoryview.size.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_v_length); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":610 + * return self._size + * + * def __len__(self): # <<<<<<<<<<<<<< + * if self.view.ndim >= 1: + * return self.view.shape[0] + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_memoryview___len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_memoryview___len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(struct __pyx_memoryview_obj *__pyx_v_self) { + Py_ssize_t __pyx_r; + int __pyx_t_1; + + /* "View.MemoryView":611 + * + * def __len__(self): + * if self.view.ndim >= 1: # <<<<<<<<<<<<<< + * return self.view.shape[0] + * + */ + __pyx_t_1 = (__pyx_v_self->view.ndim >= 1); + if (__pyx_t_1) { + + /* "View.MemoryView":612 + * def __len__(self): + * if self.view.ndim >= 1: + * return self.view.shape[0] # <<<<<<<<<<<<<< + * + * return 0 + */ + __pyx_r = (__pyx_v_self->view.shape[0]); + goto __pyx_L0; + + /* "View.MemoryView":611 + * + * def __len__(self): + * if self.view.ndim >= 1: # <<<<<<<<<<<<<< + * return self.view.shape[0] + * + */ + } + + /* "View.MemoryView":614 + * return self.view.shape[0] + * + * return 0 # <<<<<<<<<<<<<< + * + * def __repr__(self): + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":610 + * return self._size + * + * def __len__(self): # <<<<<<<<<<<<<< + * if self.view.ndim >= 1: + * return self.view.shape[0] + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":616 + * return 0 + * + * def __repr__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__, + * id(self)) + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_memoryview___repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "View.MemoryView":617 + * + * def __repr__(self): + * return "" % (self.base.__class__.__name__, # <<<<<<<<<<<<<< + * id(self)) + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_base); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_name_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":618 + * def __repr__(self): + * return "" % (self.base.__class__.__name__, + * id(self)) # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_id, ((PyObject *)__pyx_v_self)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 618, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "View.MemoryView":617 + * + * def __repr__(self): + * return "" % (self.base.__class__.__name__, # <<<<<<<<<<<<<< + * id(self)) + * + */ + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(1, 617, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyString_Format(__pyx_kp_s_MemoryView_of_r_at_0x_x, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 617, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":616 + * return 0 + * + * def __repr__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__, + * id(self)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":620 + * id(self)) + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__,) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview___str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_memoryview___str__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 1); + + /* "View.MemoryView":621 + * + * def __str__(self): + * return "" % (self.base.__class__.__name__,) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_base); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_name_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_MemoryView_of_r_object, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":620 + * id(self)) + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "" % (self.base.__class__.__name__,) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":624 + * + * + * def is_c_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_is_c_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_is_c_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_c_contig (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("is_c_contig", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "is_c_contig", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice *__pyx_v_mslice; + __Pyx_memviewslice __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_c_contig", 1); + + /* "View.MemoryView":627 + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) # <<<<<<<<<<<<<< + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_self, (&__pyx_v_tmp)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 627, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":628 + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) + * return slice_is_contig(mslice[0], 'C', self.view.ndim) # <<<<<<<<<<<<<< + * + * def is_f_contig(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_memviewslice_is_contig((__pyx_v_mslice[0]), 'C', __pyx_v_self->view.ndim)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 628, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":624 + * + * + * def is_c_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_c_contig", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":630 + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + * def is_f_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_is_f_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_is_f_contig(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_f_contig (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("is_f_contig", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "is_f_contig", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice *__pyx_v_mslice; + __Pyx_memviewslice __pyx_v_tmp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_f_contig", 1); + + /* "View.MemoryView":633 + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) # <<<<<<<<<<<<<< + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + */ + __pyx_t_1 = __pyx_memoryview_get_slice_from_memoryview(__pyx_v_self, (&__pyx_v_tmp)); if (unlikely(__pyx_t_1 == ((__Pyx_memviewslice *)NULL))) __PYX_ERR(1, 633, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":634 + * cdef __Pyx_memviewslice tmp + * mslice = get_slice_from_memview(self, &tmp) + * return slice_is_contig(mslice[0], 'F', self.view.ndim) # <<<<<<<<<<<<<< + * + * def copy(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_memviewslice_is_contig((__pyx_v_mslice[0]), 'F', __pyx_v_self->view.ndim)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":630 + * return slice_is_contig(mslice[0], 'C', self.view.ndim) + * + * def is_f_contig(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice *mslice + * cdef __Pyx_memviewslice tmp + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.is_f_contig", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":636 + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + * def copy(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice __pyx_v_mslice; + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("copy", 1); + + /* "View.MemoryView":638 + * def copy(self): + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS # <<<<<<<<<<<<<< + * + * slice_copy(self, &mslice) + */ + __pyx_v_flags = (__pyx_v_self->flags & (~PyBUF_F_CONTIGUOUS)); + + /* "View.MemoryView":640 + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + * + * slice_copy(self, &mslice) # <<<<<<<<<<<<<< + * mslice = slice_copy_contig(&mslice, "c", self.view.ndim, + * self.view.itemsize, + */ + __pyx_memoryview_slice_copy(__pyx_v_self, (&__pyx_v_mslice)); + + /* "View.MemoryView":641 + * + * slice_copy(self, &mslice) + * mslice = slice_copy_contig(&mslice, "c", self.view.ndim, # <<<<<<<<<<<<<< + * self.view.itemsize, + * flags|PyBUF_C_CONTIGUOUS, + */ + __pyx_t_1 = __pyx_memoryview_copy_new_contig((&__pyx_v_mslice), ((char *)"c"), __pyx_v_self->view.ndim, __pyx_v_self->view.itemsize, (__pyx_v_flags | PyBUF_C_CONTIGUOUS), __pyx_v_self->dtype_is_object); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 641, __pyx_L1_error) + __pyx_v_mslice = __pyx_t_1; + + /* "View.MemoryView":646 + * self.dtype_is_object) + * + * return memoryview_copy_from_slice(self, &mslice) # <<<<<<<<<<<<<< + * + * def copy_fortran(self): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_copy_object_from_slice(__pyx_v_self, (&__pyx_v_mslice)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":636 + * return slice_is_contig(mslice[0], 'F', self.view.ndim) + * + * def copy(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice mslice + * cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.copy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":648 + * return memoryview_copy_from_slice(self, &mslice) + * + * def copy_fortran(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + */ + +/* Python wrapper */ +static PyObject *__pyx_memoryview_copy_fortran(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_memoryview_copy_fortran(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy_fortran (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy_fortran", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy_fortran", 0))) return NULL; + __pyx_r = __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(struct __pyx_memoryview_obj *__pyx_v_self) { + __Pyx_memviewslice __pyx_v_src; + __Pyx_memviewslice __pyx_v_dst; + int __pyx_v_flags; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_memviewslice __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("copy_fortran", 1); + + /* "View.MemoryView":650 + * def copy_fortran(self): + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS # <<<<<<<<<<<<<< + * + * slice_copy(self, &src) + */ + __pyx_v_flags = (__pyx_v_self->flags & (~PyBUF_C_CONTIGUOUS)); + + /* "View.MemoryView":652 + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + * + * slice_copy(self, &src) # <<<<<<<<<<<<<< + * dst = slice_copy_contig(&src, "fortran", self.view.ndim, + * self.view.itemsize, + */ + __pyx_memoryview_slice_copy(__pyx_v_self, (&__pyx_v_src)); + + /* "View.MemoryView":653 + * + * slice_copy(self, &src) + * dst = slice_copy_contig(&src, "fortran", self.view.ndim, # <<<<<<<<<<<<<< + * self.view.itemsize, + * flags|PyBUF_F_CONTIGUOUS, + */ + __pyx_t_1 = __pyx_memoryview_copy_new_contig((&__pyx_v_src), ((char *)"fortran"), __pyx_v_self->view.ndim, __pyx_v_self->view.itemsize, (__pyx_v_flags | PyBUF_F_CONTIGUOUS), __pyx_v_self->dtype_is_object); if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 653, __pyx_L1_error) + __pyx_v_dst = __pyx_t_1; + + /* "View.MemoryView":658 + * self.dtype_is_object) + * + * return memoryview_copy_from_slice(self, &dst) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_copy_object_from_slice(__pyx_v_self, (&__pyx_v_dst)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":648 + * return memoryview_copy_from_slice(self, &mslice) + * + * def copy_fortran(self): # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice src, dst + * cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.memoryview.copy_fortran", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryview_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryview_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_memoryview___reduce_cython__(((struct __pyx_memoryview_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryview___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryview_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryview_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.memoryview.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_memoryview_2__setstate_cython__(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryview_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.memoryview.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":662 + * + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): # <<<<<<<<<<<<<< + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + */ + +static PyObject *__pyx_memoryview_new(PyObject *__pyx_v_o, int __pyx_v_flags, int __pyx_v_dtype_is_object, __Pyx_TypeInfo *__pyx_v_typeinfo) { + struct __pyx_memoryview_obj *__pyx_v_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_cwrapper", 1); + + /* "View.MemoryView":663 + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): + * cdef memoryview result = memoryview(o, flags, dtype_is_object) # <<<<<<<<<<<<<< + * result.typeinfo = typeinfo + * return result + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_o); + __Pyx_GIVEREF(__pyx_v_o); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_o)) __PYX_ERR(1, 663, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1)) __PYX_ERR(1, 663, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_memoryview_type), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":664 + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo # <<<<<<<<<<<<<< + * return result + * + */ + __pyx_v_result->typeinfo = __pyx_v_typeinfo; + + /* "View.MemoryView":665 + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + * return result # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_check') + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":662 + * + * @cname('__pyx_memoryview_new') + * cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): # <<<<<<<<<<<<<< + * cdef memoryview result = memoryview(o, flags, dtype_is_object) + * result.typeinfo = typeinfo + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview_cwrapper", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":668 + * + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: # <<<<<<<<<<<<<< + * return isinstance(o, memoryview) + * + */ + +static CYTHON_INLINE int __pyx_memoryview_check(PyObject *__pyx_v_o) { + int __pyx_r; + int __pyx_t_1; + + /* "View.MemoryView":669 + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: + * return isinstance(o, memoryview) # <<<<<<<<<<<<<< + * + * cdef tuple _unellipsify(object index, int ndim): + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_o, __pyx_memoryview_type); + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "View.MemoryView":668 + * + * @cname('__pyx_memoryview_check') + * cdef inline bint memoryview_check(object o) noexcept: # <<<<<<<<<<<<<< + * return isinstance(o, memoryview) + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":671 + * return isinstance(o, memoryview) + * + * cdef tuple _unellipsify(object index, int ndim): # <<<<<<<<<<<<<< + * """ + * Replace all ellipses with full slices and fill incomplete indices with + */ + +static PyObject *_unellipsify(PyObject *__pyx_v_index, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_idx; + PyObject *__pyx_v_tup = NULL; + PyObject *__pyx_v_result = NULL; + int __pyx_v_have_slices; + int __pyx_v_seen_ellipsis; + PyObject *__pyx_v_item = NULL; + Py_ssize_t __pyx_v_nslices; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + Py_UCS4 __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_unellipsify", 1); + + /* "View.MemoryView":677 + * """ + * cdef Py_ssize_t idx + * tup = index if isinstance(index, tuple) else (index,) # <<<<<<<<<<<<<< + * + * result = [slice(None)] * ndim + */ + __pyx_t_2 = PyTuple_Check(__pyx_v_index); + if (__pyx_t_2) { + __Pyx_INCREF(((PyObject*)__pyx_v_index)); + __pyx_t_1 = __pyx_v_index; + } else { + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 677, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_index); + __Pyx_GIVEREF(__pyx_v_index); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_index)) __PYX_ERR(1, 677, __pyx_L1_error); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + } + __pyx_v_tup = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":679 + * tup = index if isinstance(index, tuple) else (index,) + * + * result = [slice(None)] * ndim # <<<<<<<<<<<<<< + * have_slices = False + * seen_ellipsis = False + */ + __pyx_t_1 = PyList_New(1 * ((__pyx_v_ndim<0) ? 0:__pyx_v_ndim)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + { Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < __pyx_v_ndim; __pyx_temp++) { + __Pyx_INCREF(__pyx_slice__5); + __Pyx_GIVEREF(__pyx_slice__5); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, __pyx_temp, __pyx_slice__5)) __PYX_ERR(1, 679, __pyx_L1_error); + } + } + __pyx_v_result = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "View.MemoryView":680 + * + * result = [slice(None)] * ndim + * have_slices = False # <<<<<<<<<<<<<< + * seen_ellipsis = False + * idx = 0 + */ + __pyx_v_have_slices = 0; + + /* "View.MemoryView":681 + * result = [slice(None)] * ndim + * have_slices = False + * seen_ellipsis = False # <<<<<<<<<<<<<< + * idx = 0 + * for item in tup: + */ + __pyx_v_seen_ellipsis = 0; + + /* "View.MemoryView":682 + * have_slices = False + * seen_ellipsis = False + * idx = 0 # <<<<<<<<<<<<<< + * for item in tup: + * if item is Ellipsis: + */ + __pyx_v_idx = 0; + + /* "View.MemoryView":683 + * seen_ellipsis = False + * idx = 0 + * for item in tup: # <<<<<<<<<<<<<< + * if item is Ellipsis: + * if not seen_ellipsis: + */ + if (unlikely(__pyx_v_tup == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 683, __pyx_L1_error) + } + __pyx_t_1 = __pyx_v_tup; __Pyx_INCREF(__pyx_t_1); + __pyx_t_4 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 683, __pyx_L1_error) + #endif + if (__pyx_t_4 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++; if (unlikely((0 < 0))) __PYX_ERR(1, 683, __pyx_L1_error) + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 683, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_item, __pyx_t_3); + __pyx_t_3 = 0; + + /* "View.MemoryView":684 + * idx = 0 + * for item in tup: + * if item is Ellipsis: # <<<<<<<<<<<<<< + * if not seen_ellipsis: + * idx += ndim - len(tup) + */ + __pyx_t_2 = (__pyx_v_item == __pyx_builtin_Ellipsis); + if (__pyx_t_2) { + + /* "View.MemoryView":685 + * for item in tup: + * if item is Ellipsis: + * if not seen_ellipsis: # <<<<<<<<<<<<<< + * idx += ndim - len(tup) + * seen_ellipsis = True + */ + __pyx_t_2 = (!__pyx_v_seen_ellipsis); + if (__pyx_t_2) { + + /* "View.MemoryView":686 + * if item is Ellipsis: + * if not seen_ellipsis: + * idx += ndim - len(tup) # <<<<<<<<<<<<<< + * seen_ellipsis = True + * have_slices = True + */ + if (unlikely(__pyx_v_tup == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 686, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_PyTuple_GET_SIZE(__pyx_v_tup); if (unlikely(__pyx_t_5 == ((Py_ssize_t)-1))) __PYX_ERR(1, 686, __pyx_L1_error) + __pyx_v_idx = (__pyx_v_idx + (__pyx_v_ndim - __pyx_t_5)); + + /* "View.MemoryView":687 + * if not seen_ellipsis: + * idx += ndim - len(tup) + * seen_ellipsis = True # <<<<<<<<<<<<<< + * have_slices = True + * else: + */ + __pyx_v_seen_ellipsis = 1; + + /* "View.MemoryView":685 + * for item in tup: + * if item is Ellipsis: + * if not seen_ellipsis: # <<<<<<<<<<<<<< + * idx += ndim - len(tup) + * seen_ellipsis = True + */ + } + + /* "View.MemoryView":688 + * idx += ndim - len(tup) + * seen_ellipsis = True + * have_slices = True # <<<<<<<<<<<<<< + * else: + * if isinstance(item, slice): + */ + __pyx_v_have_slices = 1; + + /* "View.MemoryView":684 + * idx = 0 + * for item in tup: + * if item is Ellipsis: # <<<<<<<<<<<<<< + * if not seen_ellipsis: + * idx += ndim - len(tup) + */ + goto __pyx_L5; + } + + /* "View.MemoryView":690 + * have_slices = True + * else: + * if isinstance(item, slice): # <<<<<<<<<<<<<< + * have_slices = True + * elif not PyIndex_Check(item): + */ + /*else*/ { + __pyx_t_2 = PySlice_Check(__pyx_v_item); + if (__pyx_t_2) { + + /* "View.MemoryView":691 + * else: + * if isinstance(item, slice): + * have_slices = True # <<<<<<<<<<<<<< + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" + */ + __pyx_v_have_slices = 1; + + /* "View.MemoryView":690 + * have_slices = True + * else: + * if isinstance(item, slice): # <<<<<<<<<<<<<< + * have_slices = True + * elif not PyIndex_Check(item): + */ + goto __pyx_L7; + } + + /* "View.MemoryView":692 + * if isinstance(item, slice): + * have_slices = True + * elif not PyIndex_Check(item): # <<<<<<<<<<<<<< + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + */ + __pyx_t_2 = (!(PyIndex_Check(__pyx_v_item) != 0)); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":693 + * have_slices = True + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" # <<<<<<<<<<<<<< + * result[idx] = item + * idx += 1 + */ + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = 0; + __pyx_t_6 = 127; + __Pyx_INCREF(__pyx_kp_u_Cannot_index_with_type); + __pyx_t_5 += 24; + __Pyx_GIVEREF(__pyx_kp_u_Cannot_index_with_type); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_kp_u_Cannot_index_with_type); + __pyx_t_7 = __Pyx_PyObject_FormatSimple(((PyObject *)Py_TYPE(__pyx_v_item)), __pyx_empty_unicode); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_7) > __pyx_t_6) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_7) : __pyx_t_6; + __pyx_t_5 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_7); + __pyx_t_7 = 0; + __Pyx_INCREF(__pyx_kp_u__6); + __pyx_t_5 += 1; + __Pyx_GIVEREF(__pyx_kp_u__6); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_kp_u__6); + __pyx_t_7 = __Pyx_PyUnicode_Join(__pyx_t_3, 3, __pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_t_7, 0, 0); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __PYX_ERR(1, 693, __pyx_L1_error) + + /* "View.MemoryView":692 + * if isinstance(item, slice): + * have_slices = True + * elif not PyIndex_Check(item): # <<<<<<<<<<<<<< + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + */ + } + __pyx_L7:; + + /* "View.MemoryView":694 + * elif not PyIndex_Check(item): + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item # <<<<<<<<<<<<<< + * idx += 1 + * + */ + if (unlikely((__Pyx_SetItemInt(__pyx_v_result, __pyx_v_idx, __pyx_v_item, Py_ssize_t, 1, PyInt_FromSsize_t, 1, 1, 1) < 0))) __PYX_ERR(1, 694, __pyx_L1_error) + } + __pyx_L5:; + + /* "View.MemoryView":695 + * raise TypeError, f"Cannot index with type '{type(item)}'" + * result[idx] = item + * idx += 1 # <<<<<<<<<<<<<< + * + * nslices = ndim - idx + */ + __pyx_v_idx = (__pyx_v_idx + 1); + + /* "View.MemoryView":683 + * seen_ellipsis = False + * idx = 0 + * for item in tup: # <<<<<<<<<<<<<< + * if item is Ellipsis: + * if not seen_ellipsis: + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "View.MemoryView":697 + * idx += 1 + * + * nslices = ndim - idx # <<<<<<<<<<<<<< + * return have_slices or nslices, tuple(result) + * + */ + __pyx_v_nslices = (__pyx_v_ndim - __pyx_v_idx); + + /* "View.MemoryView":698 + * + * nslices = ndim - idx + * return have_slices or nslices, tuple(result) # <<<<<<<<<<<<<< + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + */ + __Pyx_XDECREF(__pyx_r); + if (!__pyx_v_have_slices) { + } else { + __pyx_t_7 = __Pyx_PyBool_FromLong(__pyx_v_have_slices); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_7 = PyInt_FromSsize_t(__pyx_v_nslices); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __pyx_t_7; + __pyx_t_7 = 0; + __pyx_L9_bool_binop_done:; + __pyx_t_7 = PyList_AsTuple(__pyx_v_result); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(1, 698, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_7)) __PYX_ERR(1, 698, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_7 = 0; + __pyx_r = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "View.MemoryView":671 + * return isinstance(o, memoryview) + * + * cdef tuple _unellipsify(object index, int ndim): # <<<<<<<<<<<<<< + * """ + * Replace all ellipses with full slices and fill incomplete indices with + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView._unellipsify", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_tup); + __Pyx_XDECREF(__pyx_v_result); + __Pyx_XDECREF(__pyx_v_item); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":700 + * return have_slices or nslices, tuple(result) + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: # <<<<<<<<<<<<<< + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + */ + +static int assert_direct_dimensions(Py_ssize_t *__pyx_v_suboffsets, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_suboffset; + int __pyx_r; + Py_ssize_t *__pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "View.MemoryView":701 + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: # <<<<<<<<<<<<<< + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" + */ + __pyx_t_2 = (__pyx_v_suboffsets + __pyx_v_ndim); + for (__pyx_t_3 = __pyx_v_suboffsets; __pyx_t_3 < __pyx_t_2; __pyx_t_3++) { + __pyx_t_1 = __pyx_t_3; + __pyx_v_suboffset = (__pyx_t_1[0]); + + /* "View.MemoryView":702 + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag + */ + __pyx_t_4 = (__pyx_v_suboffset >= 0); + if (unlikely(__pyx_t_4)) { + + /* "View.MemoryView":703 + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" # <<<<<<<<<<<<<< + * return 0 # return type just used as an error flag + * + */ + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_kp_s_Indirect_dimensions_not_supporte, 0, 0); + __PYX_ERR(1, 703, __pyx_L1_error) + + /* "View.MemoryView":702 + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag + */ + } + } + + /* "View.MemoryView":704 + * if suboffset >= 0: + * raise ValueError, "Indirect dimensions not supported" + * return 0 # return type just used as an error flag # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":700 + * return have_slices or nslices, tuple(result) + * + * cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1: # <<<<<<<<<<<<<< + * for suboffset in suboffsets[:ndim]: + * if suboffset >= 0: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView.assert_direct_dimensions", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":711 + * + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): # <<<<<<<<<<<<<< + * cdef int new_ndim = 0, suboffset_dim = -1, dim + * cdef bint negative_step + */ + +static struct __pyx_memoryview_obj *__pyx_memview_slice(struct __pyx_memoryview_obj *__pyx_v_memview, PyObject *__pyx_v_indices) { + int __pyx_v_new_ndim; + int __pyx_v_suboffset_dim; + int __pyx_v_dim; + __Pyx_memviewslice __pyx_v_src; + __Pyx_memviewslice __pyx_v_dst; + __Pyx_memviewslice *__pyx_v_p_src; + struct __pyx_memoryviewslice_obj *__pyx_v_memviewsliceobj = 0; + __Pyx_memviewslice *__pyx_v_p_dst; + int *__pyx_v_p_suboffset_dim; + Py_ssize_t __pyx_v_start; + Py_ssize_t __pyx_v_stop; + Py_ssize_t __pyx_v_step; + Py_ssize_t __pyx_v_cindex; + int __pyx_v_have_start; + int __pyx_v_have_stop; + int __pyx_v_have_step; + PyObject *__pyx_v_index = NULL; + struct __pyx_memoryview_obj *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + struct __pyx_memoryview_obj *__pyx_t_3; + char *__pyx_t_4; + int __pyx_t_5; + Py_ssize_t __pyx_t_6; + PyObject *(*__pyx_t_7)(PyObject *); + PyObject *__pyx_t_8 = NULL; + Py_ssize_t __pyx_t_9; + int __pyx_t_10; + Py_ssize_t __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memview_slice", 1); + + /* "View.MemoryView":712 + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): + * cdef int new_ndim = 0, suboffset_dim = -1, dim # <<<<<<<<<<<<<< + * cdef bint negative_step + * cdef __Pyx_memviewslice src, dst + */ + __pyx_v_new_ndim = 0; + __pyx_v_suboffset_dim = -1; + + /* "View.MemoryView":719 + * + * + * memset(&dst, 0, sizeof(dst)) # <<<<<<<<<<<<<< + * + * cdef _memoryviewslice memviewsliceobj + */ + (void)(memset((&__pyx_v_dst), 0, (sizeof(__pyx_v_dst)))); + + /* "View.MemoryView":723 + * cdef _memoryviewslice memviewsliceobj + * + * assert memview.view.ndim > 0 # <<<<<<<<<<<<<< + * + * if isinstance(memview, _memoryviewslice): + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_1 = (__pyx_v_memview->view.ndim > 0); + if (unlikely(!__pyx_t_1)) { + __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); + __PYX_ERR(1, 723, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(1, 723, __pyx_L1_error) + #endif + + /* "View.MemoryView":725 + * assert memview.view.ndim > 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":726 + * + * if isinstance(memview, _memoryviewslice): + * memviewsliceobj = memview # <<<<<<<<<<<<<< + * p_src = &memviewsliceobj.from_slice + * else: + */ + if (!(likely(((((PyObject *)__pyx_v_memview)) == Py_None) || likely(__Pyx_TypeTest(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type))))) __PYX_ERR(1, 726, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_v_memview); + __Pyx_INCREF(__pyx_t_2); + __pyx_v_memviewsliceobj = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":727 + * if isinstance(memview, _memoryviewslice): + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice # <<<<<<<<<<<<<< + * else: + * slice_copy(memview, &src) + */ + __pyx_v_p_src = (&__pyx_v_memviewsliceobj->from_slice); + + /* "View.MemoryView":725 + * assert memview.view.ndim > 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * memviewsliceobj = memview + * p_src = &memviewsliceobj.from_slice + */ + goto __pyx_L3; + } + + /* "View.MemoryView":729 + * p_src = &memviewsliceobj.from_slice + * else: + * slice_copy(memview, &src) # <<<<<<<<<<<<<< + * p_src = &src + * + */ + /*else*/ { + __pyx_memoryview_slice_copy(__pyx_v_memview, (&__pyx_v_src)); + + /* "View.MemoryView":730 + * else: + * slice_copy(memview, &src) + * p_src = &src # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_p_src = (&__pyx_v_src); + } + __pyx_L3:; + + /* "View.MemoryView":736 + * + * + * dst.memview = p_src.memview # <<<<<<<<<<<<<< + * dst.data = p_src.data + * + */ + __pyx_t_3 = __pyx_v_p_src->memview; + __pyx_v_dst.memview = __pyx_t_3; + + /* "View.MemoryView":737 + * + * dst.memview = p_src.memview + * dst.data = p_src.data # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_4 = __pyx_v_p_src->data; + __pyx_v_dst.data = __pyx_t_4; + + /* "View.MemoryView":742 + * + * + * cdef __Pyx_memviewslice *p_dst = &dst # <<<<<<<<<<<<<< + * cdef int *p_suboffset_dim = &suboffset_dim + * cdef Py_ssize_t start, stop, step, cindex + */ + __pyx_v_p_dst = (&__pyx_v_dst); + + /* "View.MemoryView":743 + * + * cdef __Pyx_memviewslice *p_dst = &dst + * cdef int *p_suboffset_dim = &suboffset_dim # <<<<<<<<<<<<<< + * cdef Py_ssize_t start, stop, step, cindex + * cdef bint have_start, have_stop, have_step + */ + __pyx_v_p_suboffset_dim = (&__pyx_v_suboffset_dim); + + /* "View.MemoryView":747 + * cdef bint have_start, have_stop, have_step + * + * for dim, index in enumerate(indices): # <<<<<<<<<<<<<< + * if PyIndex_Check(index): + * cindex = index + */ + __pyx_t_5 = 0; + if (likely(PyList_CheckExact(__pyx_v_indices)) || PyTuple_CheckExact(__pyx_v_indices)) { + __pyx_t_2 = __pyx_v_indices; __Pyx_INCREF(__pyx_t_2); + __pyx_t_6 = 0; + __pyx_t_7 = NULL; + } else { + __pyx_t_6 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_indices); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 747, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_7)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_8 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_8); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #else + __pyx_t_8 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #endif + if (__pyx_t_6 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_8 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_8); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(1, 747, __pyx_L1_error) + #else + __pyx_t_8 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 747, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + #endif + } + } else { + __pyx_t_8 = __pyx_t_7(__pyx_t_2); + if (unlikely(!__pyx_t_8)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 747, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_8); + } + __Pyx_XDECREF_SET(__pyx_v_index, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_v_dim = __pyx_t_5; + __pyx_t_5 = (__pyx_t_5 + 1); + + /* "View.MemoryView":748 + * + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): # <<<<<<<<<<<<<< + * cindex = index + * slice_memviewslice( + */ + __pyx_t_1 = (PyIndex_Check(__pyx_v_index) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":749 + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): + * cindex = index # <<<<<<<<<<<<<< + * slice_memviewslice( + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + */ + __pyx_t_9 = __Pyx_PyIndex_AsSsize_t(__pyx_v_index); if (unlikely((__pyx_t_9 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 749, __pyx_L1_error) + __pyx_v_cindex = __pyx_t_9; + + /* "View.MemoryView":750 + * if PyIndex_Check(index): + * cindex = index + * slice_memviewslice( # <<<<<<<<<<<<<< + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + * dim, new_ndim, p_suboffset_dim, + */ + __pyx_t_10 = __pyx_memoryview_slice_memviewslice(__pyx_v_p_dst, (__pyx_v_p_src->shape[__pyx_v_dim]), (__pyx_v_p_src->strides[__pyx_v_dim]), (__pyx_v_p_src->suboffsets[__pyx_v_dim]), __pyx_v_dim, __pyx_v_new_ndim, __pyx_v_p_suboffset_dim, __pyx_v_cindex, 0, 0, 0, 0, 0, 0); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 750, __pyx_L1_error) + + /* "View.MemoryView":748 + * + * for dim, index in enumerate(indices): + * if PyIndex_Check(index): # <<<<<<<<<<<<<< + * cindex = index + * slice_memviewslice( + */ + goto __pyx_L6; + } + + /* "View.MemoryView":756 + * 0, 0, 0, # have_{start,stop,step} + * False) + * elif index is None: # <<<<<<<<<<<<<< + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + */ + __pyx_t_1 = (__pyx_v_index == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":757 + * False) + * elif index is None: + * p_dst.shape[new_ndim] = 1 # <<<<<<<<<<<<<< + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 + */ + (__pyx_v_p_dst->shape[__pyx_v_new_ndim]) = 1; + + /* "View.MemoryView":758 + * elif index is None: + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 # <<<<<<<<<<<<<< + * p_dst.suboffsets[new_ndim] = -1 + * new_ndim += 1 + */ + (__pyx_v_p_dst->strides[__pyx_v_new_ndim]) = 0; + + /* "View.MemoryView":759 + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 # <<<<<<<<<<<<<< + * new_ndim += 1 + * else: + */ + (__pyx_v_p_dst->suboffsets[__pyx_v_new_ndim]) = -1L; + + /* "View.MemoryView":760 + * p_dst.strides[new_ndim] = 0 + * p_dst.suboffsets[new_ndim] = -1 + * new_ndim += 1 # <<<<<<<<<<<<<< + * else: + * start = index.start or 0 + */ + __pyx_v_new_ndim = (__pyx_v_new_ndim + 1); + + /* "View.MemoryView":756 + * 0, 0, 0, # have_{start,stop,step} + * False) + * elif index is None: # <<<<<<<<<<<<<< + * p_dst.shape[new_ndim] = 1 + * p_dst.strides[new_ndim] = 0 + */ + goto __pyx_L6; + } + + /* "View.MemoryView":762 + * new_ndim += 1 + * else: + * start = index.start or 0 # <<<<<<<<<<<<<< + * stop = index.stop or 0 + * step = index.step or 0 + */ + /*else*/ { + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_start); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 762, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 762, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 762, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L7_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L7_bool_binop_done:; + __pyx_v_start = __pyx_t_9; + + /* "View.MemoryView":763 + * else: + * start = index.start or 0 + * stop = index.stop or 0 # <<<<<<<<<<<<<< + * step = index.step or 0 + * + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_stop); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 763, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 763, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L9_bool_binop_done:; + __pyx_v_stop = __pyx_t_9; + + /* "View.MemoryView":764 + * start = index.start or 0 + * stop = index.stop or 0 + * step = index.step or 0 # <<<<<<<<<<<<<< + * + * have_start = index.start is not None + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_step); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(1, 764, __pyx_L1_error) + if (!__pyx_t_1) { + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else { + __pyx_t_11 = __Pyx_PyIndex_AsSsize_t(__pyx_t_8); if (unlikely((__pyx_t_11 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 764, __pyx_L1_error) + __pyx_t_9 = __pyx_t_11; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L11_bool_binop_done; + } + __pyx_t_9 = 0; + __pyx_L11_bool_binop_done:; + __pyx_v_step = __pyx_t_9; + + /* "View.MemoryView":766 + * step = index.step or 0 + * + * have_start = index.start is not None # <<<<<<<<<<<<<< + * have_stop = index.stop is not None + * have_step = index.step is not None + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_start); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_start = __pyx_t_1; + + /* "View.MemoryView":767 + * + * have_start = index.start is not None + * have_stop = index.stop is not None # <<<<<<<<<<<<<< + * have_step = index.step is not None + * + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_stop); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 767, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_stop = __pyx_t_1; + + /* "View.MemoryView":768 + * have_start = index.start is not None + * have_stop = index.stop is not None + * have_step = index.step is not None # <<<<<<<<<<<<<< + * + * slice_memviewslice( + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_n_s_step); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 768, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_1 = (__pyx_t_8 != Py_None); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_have_step = __pyx_t_1; + + /* "View.MemoryView":770 + * have_step = index.step is not None + * + * slice_memviewslice( # <<<<<<<<<<<<<< + * p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], + * dim, new_ndim, p_suboffset_dim, + */ + __pyx_t_10 = __pyx_memoryview_slice_memviewslice(__pyx_v_p_dst, (__pyx_v_p_src->shape[__pyx_v_dim]), (__pyx_v_p_src->strides[__pyx_v_dim]), (__pyx_v_p_src->suboffsets[__pyx_v_dim]), __pyx_v_dim, __pyx_v_new_ndim, __pyx_v_p_suboffset_dim, __pyx_v_start, __pyx_v_stop, __pyx_v_step, __pyx_v_have_start, __pyx_v_have_stop, __pyx_v_have_step, 1); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 770, __pyx_L1_error) + + /* "View.MemoryView":776 + * have_start, have_stop, have_step, + * True) + * new_ndim += 1 # <<<<<<<<<<<<<< + * + * if isinstance(memview, _memoryviewslice): + */ + __pyx_v_new_ndim = (__pyx_v_new_ndim + 1); + } + __pyx_L6:; + + /* "View.MemoryView":747 + * cdef bint have_start, have_stop, have_step + * + * for dim, index in enumerate(indices): # <<<<<<<<<<<<<< + * if PyIndex_Check(index): + * cindex = index + */ + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "View.MemoryView":778 + * new_ndim += 1 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":779 + * + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, # <<<<<<<<<<<<<< + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + + /* "View.MemoryView":780 + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, # <<<<<<<<<<<<<< + * memviewsliceobj.to_dtype_func, + * memview.dtype_is_object) + */ + if (unlikely(!__pyx_v_memviewsliceobj)) { __Pyx_RaiseUnboundLocalError("memviewsliceobj"); __PYX_ERR(1, 780, __pyx_L1_error) } + + /* "View.MemoryView":781 + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * else: + */ + if (unlikely(!__pyx_v_memviewsliceobj)) { __Pyx_RaiseUnboundLocalError("memviewsliceobj"); __PYX_ERR(1, 781, __pyx_L1_error) } + + /* "View.MemoryView":779 + * + * if isinstance(memview, _memoryviewslice): + * return memoryview_fromslice(dst, new_ndim, # <<<<<<<<<<<<<< + * memviewsliceobj.to_object_func, + * memviewsliceobj.to_dtype_func, + */ + __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_dst, __pyx_v_new_ndim, __pyx_v_memviewsliceobj->to_object_func, __pyx_v_memviewsliceobj->to_dtype_func, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_memoryview_type))))) __PYX_ERR(1, 779, __pyx_L1_error) + __pyx_r = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":778 + * new_ndim += 1 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * return memoryview_fromslice(dst, new_ndim, + * memviewsliceobj.to_object_func, + */ + } + + /* "View.MemoryView":784 + * memview.dtype_is_object) + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * + */ + /*else*/ { + __Pyx_XDECREF((PyObject *)__pyx_r); + + /* "View.MemoryView":785 + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, + * memview.dtype_is_object) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_memoryview_fromslice(__pyx_v_dst, __pyx_v_new_ndim, NULL, NULL, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 784, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "View.MemoryView":784 + * memview.dtype_is_object) + * else: + * return memoryview_fromslice(dst, new_ndim, NULL, NULL, # <<<<<<<<<<<<<< + * memview.dtype_is_object) + * + */ + if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_memoryview_type))))) __PYX_ERR(1, 784, __pyx_L1_error) + __pyx_r = ((struct __pyx_memoryview_obj *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":711 + * + * @cname('__pyx_memview_slice') + * cdef memoryview memview_slice(memoryview memview, object indices): # <<<<<<<<<<<<<< + * cdef int new_ndim = 0, suboffset_dim = -1, dim + * cdef bint negative_step + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("View.MemoryView.memview_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_memviewsliceobj); + __Pyx_XDECREF(__pyx_v_index); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":793 + * + * @cname('__pyx_memoryview_slice_memviewslice') + * cdef int slice_memviewslice( # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, + */ + +static int __pyx_memoryview_slice_memviewslice(__Pyx_memviewslice *__pyx_v_dst, Py_ssize_t __pyx_v_shape, Py_ssize_t __pyx_v_stride, Py_ssize_t __pyx_v_suboffset, int __pyx_v_dim, int __pyx_v_new_ndim, int *__pyx_v_suboffset_dim, Py_ssize_t __pyx_v_start, Py_ssize_t __pyx_v_stop, Py_ssize_t __pyx_v_step, int __pyx_v_have_start, int __pyx_v_have_stop, int __pyx_v_have_step, int __pyx_v_is_slice) { + Py_ssize_t __pyx_v_new_shape; + int __pyx_v_negative_step; + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":813 + * cdef bint negative_step + * + * if not is_slice: # <<<<<<<<<<<<<< + * + * if start < 0: + */ + __pyx_t_1 = (!__pyx_v_is_slice); + if (__pyx_t_1) { + + /* "View.MemoryView":815 + * if not is_slice: + * + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if not 0 <= start < shape: + */ + __pyx_t_1 = (__pyx_v_start < 0); + if (__pyx_t_1) { + + /* "View.MemoryView":816 + * + * if start < 0: + * start += shape # <<<<<<<<<<<<<< + * if not 0 <= start < shape: + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + */ + __pyx_v_start = (__pyx_v_start + __pyx_v_shape); + + /* "View.MemoryView":815 + * if not is_slice: + * + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if not 0 <= start < shape: + */ + } + + /* "View.MemoryView":817 + * if start < 0: + * start += shape + * if not 0 <= start < shape: # <<<<<<<<<<<<<< + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + * else: + */ + __pyx_t_1 = (0 <= __pyx_v_start); + if (__pyx_t_1) { + __pyx_t_1 = (__pyx_v_start < __pyx_v_shape); + } + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "View.MemoryView":818 + * start += shape + * if not 0 <= start < shape: + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) # <<<<<<<<<<<<<< + * else: + * + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_IndexError, __pyx_kp_s_Index_out_of_bounds_axis_d, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 818, __pyx_L1_error) + + /* "View.MemoryView":817 + * if start < 0: + * start += shape + * if not 0 <= start < shape: # <<<<<<<<<<<<<< + * _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim) + * else: + */ + } + + /* "View.MemoryView":813 + * cdef bint negative_step + * + * if not is_slice: # <<<<<<<<<<<<<< + * + * if start < 0: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":821 + * else: + * + * if have_step: # <<<<<<<<<<<<<< + * negative_step = step < 0 + * if step == 0: + */ + /*else*/ { + __pyx_t_2 = (__pyx_v_have_step != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":822 + * + * if have_step: + * negative_step = step < 0 # <<<<<<<<<<<<<< + * if step == 0: + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + */ + __pyx_v_negative_step = (__pyx_v_step < 0); + + /* "View.MemoryView":823 + * if have_step: + * negative_step = step < 0 + * if step == 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + */ + __pyx_t_2 = (__pyx_v_step == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":824 + * negative_step = step < 0 + * if step == 0: + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) # <<<<<<<<<<<<<< + * else: + * negative_step = False + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_ValueError, __pyx_kp_s_Step_may_not_be_zero_axis_d, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 824, __pyx_L1_error) + + /* "View.MemoryView":823 + * if have_step: + * negative_step = step < 0 + * if step == 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + */ + } + + /* "View.MemoryView":821 + * else: + * + * if have_step: # <<<<<<<<<<<<<< + * negative_step = step < 0 + * if step == 0: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":826 + * _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim) + * else: + * negative_step = False # <<<<<<<<<<<<<< + * step = 1 + * + */ + /*else*/ { + __pyx_v_negative_step = 0; + + /* "View.MemoryView":827 + * else: + * negative_step = False + * step = 1 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_step = 1; + } + __pyx_L6:; + + /* "View.MemoryView":830 + * + * + * if have_start: # <<<<<<<<<<<<<< + * if start < 0: + * start += shape + */ + __pyx_t_2 = (__pyx_v_have_start != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":831 + * + * if have_start: + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if start < 0: + */ + __pyx_t_2 = (__pyx_v_start < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":832 + * if have_start: + * if start < 0: + * start += shape # <<<<<<<<<<<<<< + * if start < 0: + * start = 0 + */ + __pyx_v_start = (__pyx_v_start + __pyx_v_shape); + + /* "View.MemoryView":833 + * if start < 0: + * start += shape + * if start < 0: # <<<<<<<<<<<<<< + * start = 0 + * elif start >= shape: + */ + __pyx_t_2 = (__pyx_v_start < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":834 + * start += shape + * if start < 0: + * start = 0 # <<<<<<<<<<<<<< + * elif start >= shape: + * if negative_step: + */ + __pyx_v_start = 0; + + /* "View.MemoryView":833 + * if start < 0: + * start += shape + * if start < 0: # <<<<<<<<<<<<<< + * start = 0 + * elif start >= shape: + */ + } + + /* "View.MemoryView":831 + * + * if have_start: + * if start < 0: # <<<<<<<<<<<<<< + * start += shape + * if start < 0: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":835 + * if start < 0: + * start = 0 + * elif start >= shape: # <<<<<<<<<<<<<< + * if negative_step: + * start = shape - 1 + */ + __pyx_t_2 = (__pyx_v_start >= __pyx_v_shape); + if (__pyx_t_2) { + + /* "View.MemoryView":836 + * start = 0 + * elif start >= shape: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + if (__pyx_v_negative_step) { + + /* "View.MemoryView":837 + * elif start >= shape: + * if negative_step: + * start = shape - 1 # <<<<<<<<<<<<<< + * else: + * start = shape + */ + __pyx_v_start = (__pyx_v_shape - 1); + + /* "View.MemoryView":836 + * start = 0 + * elif start >= shape: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + goto __pyx_L11; + } + + /* "View.MemoryView":839 + * start = shape - 1 + * else: + * start = shape # <<<<<<<<<<<<<< + * else: + * if negative_step: + */ + /*else*/ { + __pyx_v_start = __pyx_v_shape; + } + __pyx_L11:; + + /* "View.MemoryView":835 + * if start < 0: + * start = 0 + * elif start >= shape: # <<<<<<<<<<<<<< + * if negative_step: + * start = shape - 1 + */ + } + __pyx_L9:; + + /* "View.MemoryView":830 + * + * + * if have_start: # <<<<<<<<<<<<<< + * if start < 0: + * start += shape + */ + goto __pyx_L8; + } + + /* "View.MemoryView":841 + * start = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + /*else*/ { + if (__pyx_v_negative_step) { + + /* "View.MemoryView":842 + * else: + * if negative_step: + * start = shape - 1 # <<<<<<<<<<<<<< + * else: + * start = 0 + */ + __pyx_v_start = (__pyx_v_shape - 1); + + /* "View.MemoryView":841 + * start = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * start = shape - 1 + * else: + */ + goto __pyx_L12; + } + + /* "View.MemoryView":844 + * start = shape - 1 + * else: + * start = 0 # <<<<<<<<<<<<<< + * + * if have_stop: + */ + /*else*/ { + __pyx_v_start = 0; + } + __pyx_L12:; + } + __pyx_L8:; + + /* "View.MemoryView":846 + * start = 0 + * + * if have_stop: # <<<<<<<<<<<<<< + * if stop < 0: + * stop += shape + */ + __pyx_t_2 = (__pyx_v_have_stop != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":847 + * + * if have_stop: + * if stop < 0: # <<<<<<<<<<<<<< + * stop += shape + * if stop < 0: + */ + __pyx_t_2 = (__pyx_v_stop < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":848 + * if have_stop: + * if stop < 0: + * stop += shape # <<<<<<<<<<<<<< + * if stop < 0: + * stop = 0 + */ + __pyx_v_stop = (__pyx_v_stop + __pyx_v_shape); + + /* "View.MemoryView":849 + * if stop < 0: + * stop += shape + * if stop < 0: # <<<<<<<<<<<<<< + * stop = 0 + * elif stop > shape: + */ + __pyx_t_2 = (__pyx_v_stop < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":850 + * stop += shape + * if stop < 0: + * stop = 0 # <<<<<<<<<<<<<< + * elif stop > shape: + * stop = shape + */ + __pyx_v_stop = 0; + + /* "View.MemoryView":849 + * if stop < 0: + * stop += shape + * if stop < 0: # <<<<<<<<<<<<<< + * stop = 0 + * elif stop > shape: + */ + } + + /* "View.MemoryView":847 + * + * if have_stop: + * if stop < 0: # <<<<<<<<<<<<<< + * stop += shape + * if stop < 0: + */ + goto __pyx_L14; + } + + /* "View.MemoryView":851 + * if stop < 0: + * stop = 0 + * elif stop > shape: # <<<<<<<<<<<<<< + * stop = shape + * else: + */ + __pyx_t_2 = (__pyx_v_stop > __pyx_v_shape); + if (__pyx_t_2) { + + /* "View.MemoryView":852 + * stop = 0 + * elif stop > shape: + * stop = shape # <<<<<<<<<<<<<< + * else: + * if negative_step: + */ + __pyx_v_stop = __pyx_v_shape; + + /* "View.MemoryView":851 + * if stop < 0: + * stop = 0 + * elif stop > shape: # <<<<<<<<<<<<<< + * stop = shape + * else: + */ + } + __pyx_L14:; + + /* "View.MemoryView":846 + * start = 0 + * + * if have_stop: # <<<<<<<<<<<<<< + * if stop < 0: + * stop += shape + */ + goto __pyx_L13; + } + + /* "View.MemoryView":854 + * stop = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * stop = -1 + * else: + */ + /*else*/ { + if (__pyx_v_negative_step) { + + /* "View.MemoryView":855 + * else: + * if negative_step: + * stop = -1 # <<<<<<<<<<<<<< + * else: + * stop = shape + */ + __pyx_v_stop = -1L; + + /* "View.MemoryView":854 + * stop = shape + * else: + * if negative_step: # <<<<<<<<<<<<<< + * stop = -1 + * else: + */ + goto __pyx_L16; + } + + /* "View.MemoryView":857 + * stop = -1 + * else: + * stop = shape # <<<<<<<<<<<<<< + * + * + */ + /*else*/ { + __pyx_v_stop = __pyx_v_shape; + } + __pyx_L16:; + } + __pyx_L13:; + + /* "View.MemoryView":861 + * + * with cython.cdivision(True): + * new_shape = (stop - start) // step # <<<<<<<<<<<<<< + * + * if (stop - start) - step * new_shape: + */ + __pyx_v_new_shape = ((__pyx_v_stop - __pyx_v_start) / __pyx_v_step); + + /* "View.MemoryView":863 + * new_shape = (stop - start) // step + * + * if (stop - start) - step * new_shape: # <<<<<<<<<<<<<< + * new_shape += 1 + * + */ + __pyx_t_2 = (((__pyx_v_stop - __pyx_v_start) - (__pyx_v_step * __pyx_v_new_shape)) != 0); + if (__pyx_t_2) { + + /* "View.MemoryView":864 + * + * if (stop - start) - step * new_shape: + * new_shape += 1 # <<<<<<<<<<<<<< + * + * if new_shape < 0: + */ + __pyx_v_new_shape = (__pyx_v_new_shape + 1); + + /* "View.MemoryView":863 + * new_shape = (stop - start) // step + * + * if (stop - start) - step * new_shape: # <<<<<<<<<<<<<< + * new_shape += 1 + * + */ + } + + /* "View.MemoryView":866 + * new_shape += 1 + * + * if new_shape < 0: # <<<<<<<<<<<<<< + * new_shape = 0 + * + */ + __pyx_t_2 = (__pyx_v_new_shape < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":867 + * + * if new_shape < 0: + * new_shape = 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_new_shape = 0; + + /* "View.MemoryView":866 + * new_shape += 1 + * + * if new_shape < 0: # <<<<<<<<<<<<<< + * new_shape = 0 + * + */ + } + + /* "View.MemoryView":870 + * + * + * dst.strides[new_ndim] = stride * step # <<<<<<<<<<<<<< + * dst.shape[new_ndim] = new_shape + * dst.suboffsets[new_ndim] = suboffset + */ + (__pyx_v_dst->strides[__pyx_v_new_ndim]) = (__pyx_v_stride * __pyx_v_step); + + /* "View.MemoryView":871 + * + * dst.strides[new_ndim] = stride * step + * dst.shape[new_ndim] = new_shape # <<<<<<<<<<<<<< + * dst.suboffsets[new_ndim] = suboffset + * + */ + (__pyx_v_dst->shape[__pyx_v_new_ndim]) = __pyx_v_new_shape; + + /* "View.MemoryView":872 + * dst.strides[new_ndim] = stride * step + * dst.shape[new_ndim] = new_shape + * dst.suboffsets[new_ndim] = suboffset # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_dst->suboffsets[__pyx_v_new_ndim]) = __pyx_v_suboffset; + } + __pyx_L3:; + + /* "View.MemoryView":875 + * + * + * if suboffset_dim[0] < 0: # <<<<<<<<<<<<<< + * dst.data += start * stride + * else: + */ + __pyx_t_2 = ((__pyx_v_suboffset_dim[0]) < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":876 + * + * if suboffset_dim[0] < 0: + * dst.data += start * stride # <<<<<<<<<<<<<< + * else: + * dst.suboffsets[suboffset_dim[0]] += start * stride + */ + __pyx_v_dst->data = (__pyx_v_dst->data + (__pyx_v_start * __pyx_v_stride)); + + /* "View.MemoryView":875 + * + * + * if suboffset_dim[0] < 0: # <<<<<<<<<<<<<< + * dst.data += start * stride + * else: + */ + goto __pyx_L19; + } + + /* "View.MemoryView":878 + * dst.data += start * stride + * else: + * dst.suboffsets[suboffset_dim[0]] += start * stride # <<<<<<<<<<<<<< + * + * if suboffset >= 0: + */ + /*else*/ { + __pyx_t_3 = (__pyx_v_suboffset_dim[0]); + (__pyx_v_dst->suboffsets[__pyx_t_3]) = ((__pyx_v_dst->suboffsets[__pyx_t_3]) + (__pyx_v_start * __pyx_v_stride)); + } + __pyx_L19:; + + /* "View.MemoryView":880 + * dst.suboffsets[suboffset_dim[0]] += start * stride + * + * if suboffset >= 0: # <<<<<<<<<<<<<< + * if not is_slice: + * if new_ndim == 0: + */ + __pyx_t_2 = (__pyx_v_suboffset >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":881 + * + * if suboffset >= 0: + * if not is_slice: # <<<<<<<<<<<<<< + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset + */ + __pyx_t_2 = (!__pyx_v_is_slice); + if (__pyx_t_2) { + + /* "View.MemoryView":882 + * if suboffset >= 0: + * if not is_slice: + * if new_ndim == 0: # <<<<<<<<<<<<<< + * dst.data = ( dst.data)[0] + suboffset + * else: + */ + __pyx_t_2 = (__pyx_v_new_ndim == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":883 + * if not is_slice: + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset # <<<<<<<<<<<<<< + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " + */ + __pyx_v_dst->data = ((((char **)__pyx_v_dst->data)[0]) + __pyx_v_suboffset); + + /* "View.MemoryView":882 + * if suboffset >= 0: + * if not is_slice: + * if new_ndim == 0: # <<<<<<<<<<<<<< + * dst.data = ( dst.data)[0] + suboffset + * else: + */ + goto __pyx_L22; + } + + /* "View.MemoryView":885 + * dst.data = ( dst.data)[0] + suboffset + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " # <<<<<<<<<<<<<< + * "must be indexed and not sliced", dim) + * else: + */ + /*else*/ { + + /* "View.MemoryView":886 + * else: + * _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d " + * "must be indexed and not sliced", dim) # <<<<<<<<<<<<<< + * else: + * suboffset_dim[0] = new_ndim + */ + __pyx_t_3 = __pyx_memoryview_err_dim(PyExc_IndexError, __pyx_kp_s_All_dimensions_preceding_dimensi, __pyx_v_dim); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 885, __pyx_L1_error) + } + __pyx_L22:; + + /* "View.MemoryView":881 + * + * if suboffset >= 0: + * if not is_slice: # <<<<<<<<<<<<<< + * if new_ndim == 0: + * dst.data = ( dst.data)[0] + suboffset + */ + goto __pyx_L21; + } + + /* "View.MemoryView":888 + * "must be indexed and not sliced", dim) + * else: + * suboffset_dim[0] = new_ndim # <<<<<<<<<<<<<< + * + * return 0 + */ + /*else*/ { + (__pyx_v_suboffset_dim[0]) = __pyx_v_new_ndim; + } + __pyx_L21:; + + /* "View.MemoryView":880 + * dst.suboffsets[suboffset_dim[0]] += start * stride + * + * if suboffset >= 0: # <<<<<<<<<<<<<< + * if not is_slice: + * if new_ndim == 0: + */ + } + + /* "View.MemoryView":890 + * suboffset_dim[0] = new_ndim + * + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":793 + * + * @cname('__pyx_memoryview_slice_memviewslice') + * cdef int slice_memviewslice( # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.slice_memviewslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":896 + * + * @cname('__pyx_pybuffer_index') + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, # <<<<<<<<<<<<<< + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + */ + +static char *__pyx_pybuffer_index(Py_buffer *__pyx_v_view, char *__pyx_v_bufp, Py_ssize_t __pyx_v_index, Py_ssize_t __pyx_v_dim) { + Py_ssize_t __pyx_v_shape; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_v_suboffset; + Py_ssize_t __pyx_v_itemsize; + char *__pyx_v_resultp; + char *__pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_UCS4 __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("pybuffer_index", 1); + + /* "View.MemoryView":898 + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 # <<<<<<<<<<<<<< + * cdef Py_ssize_t itemsize = view.itemsize + * cdef char *resultp + */ + __pyx_v_suboffset = -1L; + + /* "View.MemoryView":899 + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + * cdef Py_ssize_t itemsize = view.itemsize # <<<<<<<<<<<<<< + * cdef char *resultp + * + */ + __pyx_t_1 = __pyx_v_view->itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":902 + * cdef char *resultp + * + * if view.ndim == 0: # <<<<<<<<<<<<<< + * shape = view.len // itemsize + * stride = itemsize + */ + __pyx_t_2 = (__pyx_v_view->ndim == 0); + if (__pyx_t_2) { + + /* "View.MemoryView":903 + * + * if view.ndim == 0: + * shape = view.len // itemsize # <<<<<<<<<<<<<< + * stride = itemsize + * else: + */ + if (unlikely(__pyx_v_itemsize == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(1, 903, __pyx_L1_error) + } + else if (sizeof(Py_ssize_t) == sizeof(long) && (!(((Py_ssize_t)-1) > 0)) && unlikely(__pyx_v_itemsize == (Py_ssize_t)-1) && unlikely(__Pyx_UNARY_NEG_WOULD_OVERFLOW(__pyx_v_view->len))) { + PyErr_SetString(PyExc_OverflowError, "value too large to perform division"); + __PYX_ERR(1, 903, __pyx_L1_error) + } + __pyx_v_shape = __Pyx_div_Py_ssize_t(__pyx_v_view->len, __pyx_v_itemsize); + + /* "View.MemoryView":904 + * if view.ndim == 0: + * shape = view.len // itemsize + * stride = itemsize # <<<<<<<<<<<<<< + * else: + * shape = view.shape[dim] + */ + __pyx_v_stride = __pyx_v_itemsize; + + /* "View.MemoryView":902 + * cdef char *resultp + * + * if view.ndim == 0: # <<<<<<<<<<<<<< + * shape = view.len // itemsize + * stride = itemsize + */ + goto __pyx_L3; + } + + /* "View.MemoryView":906 + * stride = itemsize + * else: + * shape = view.shape[dim] # <<<<<<<<<<<<<< + * stride = view.strides[dim] + * if view.suboffsets != NULL: + */ + /*else*/ { + __pyx_v_shape = (__pyx_v_view->shape[__pyx_v_dim]); + + /* "View.MemoryView":907 + * else: + * shape = view.shape[dim] + * stride = view.strides[dim] # <<<<<<<<<<<<<< + * if view.suboffsets != NULL: + * suboffset = view.suboffsets[dim] + */ + __pyx_v_stride = (__pyx_v_view->strides[__pyx_v_dim]); + + /* "View.MemoryView":908 + * shape = view.shape[dim] + * stride = view.strides[dim] + * if view.suboffsets != NULL: # <<<<<<<<<<<<<< + * suboffset = view.suboffsets[dim] + * + */ + __pyx_t_2 = (__pyx_v_view->suboffsets != NULL); + if (__pyx_t_2) { + + /* "View.MemoryView":909 + * stride = view.strides[dim] + * if view.suboffsets != NULL: + * suboffset = view.suboffsets[dim] # <<<<<<<<<<<<<< + * + * if index < 0: + */ + __pyx_v_suboffset = (__pyx_v_view->suboffsets[__pyx_v_dim]); + + /* "View.MemoryView":908 + * shape = view.shape[dim] + * stride = view.strides[dim] + * if view.suboffsets != NULL: # <<<<<<<<<<<<<< + * suboffset = view.suboffsets[dim] + * + */ + } + } + __pyx_L3:; + + /* "View.MemoryView":911 + * suboffset = view.suboffsets[dim] + * + * if index < 0: # <<<<<<<<<<<<<< + * index += view.shape[dim] + * if index < 0: + */ + __pyx_t_2 = (__pyx_v_index < 0); + if (__pyx_t_2) { + + /* "View.MemoryView":912 + * + * if index < 0: + * index += view.shape[dim] # <<<<<<<<<<<<<< + * if index < 0: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + */ + __pyx_v_index = (__pyx_v_index + (__pyx_v_view->shape[__pyx_v_dim])); + + /* "View.MemoryView":913 + * if index < 0: + * index += view.shape[dim] + * if index < 0: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + __pyx_t_2 = (__pyx_v_index < 0); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":914 + * index += view.shape[dim] + * if index < 0: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" # <<<<<<<<<<<<<< + * + * if index >= shape: + */ + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = 0; + __pyx_t_4 = 127; + __Pyx_INCREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_1 += 37; + __Pyx_GIVEREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_5 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_1 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_kp_u__7); + __pyx_t_5 = __Pyx_PyUnicode_Join(__pyx_t_3, 3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_5, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(1, 914, __pyx_L1_error) + + /* "View.MemoryView":913 + * if index < 0: + * index += view.shape[dim] + * if index < 0: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + } + + /* "View.MemoryView":911 + * suboffset = view.suboffsets[dim] + * + * if index < 0: # <<<<<<<<<<<<<< + * index += view.shape[dim] + * if index < 0: + */ + } + + /* "View.MemoryView":916 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * if index >= shape: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + __pyx_t_2 = (__pyx_v_index >= __pyx_v_shape); + if (unlikely(__pyx_t_2)) { + + /* "View.MemoryView":917 + * + * if index >= shape: + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" # <<<<<<<<<<<<<< + * + * resultp = bufp + index * stride + */ + __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = 0; + __pyx_t_4 = 127; + __Pyx_INCREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_1 += 37; + __Pyx_GIVEREF(__pyx_kp_u_Out_of_bounds_on_buffer_access_a); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_kp_u_Out_of_bounds_on_buffer_access_a); + __pyx_t_3 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_dim, 0, ' ', 'd'); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3); + __pyx_t_3 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_1 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_kp_u__7); + __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_5, 3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_3, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 917, __pyx_L1_error) + + /* "View.MemoryView":916 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * if index >= shape: # <<<<<<<<<<<<<< + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + */ + } + + /* "View.MemoryView":919 + * raise IndexError, f"Out of bounds on buffer access (axis {dim})" + * + * resultp = bufp + index * stride # <<<<<<<<<<<<<< + * if suboffset >= 0: + * resultp = ( resultp)[0] + suboffset + */ + __pyx_v_resultp = (__pyx_v_bufp + (__pyx_v_index * __pyx_v_stride)); + + /* "View.MemoryView":920 + * + * resultp = bufp + index * stride + * if suboffset >= 0: # <<<<<<<<<<<<<< + * resultp = ( resultp)[0] + suboffset + * + */ + __pyx_t_2 = (__pyx_v_suboffset >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":921 + * resultp = bufp + index * stride + * if suboffset >= 0: + * resultp = ( resultp)[0] + suboffset # <<<<<<<<<<<<<< + * + * return resultp + */ + __pyx_v_resultp = ((((char **)__pyx_v_resultp)[0]) + __pyx_v_suboffset); + + /* "View.MemoryView":920 + * + * resultp = bufp + index * stride + * if suboffset >= 0: # <<<<<<<<<<<<<< + * resultp = ( resultp)[0] + suboffset + * + */ + } + + /* "View.MemoryView":923 + * resultp = ( resultp)[0] + suboffset + * + * return resultp # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_resultp; + goto __pyx_L0; + + /* "View.MemoryView":896 + * + * @cname('__pyx_pybuffer_index') + * cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, # <<<<<<<<<<<<<< + * Py_ssize_t dim) except NULL: + * cdef Py_ssize_t shape, stride, suboffset = -1 + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("View.MemoryView.pybuffer_index", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":929 + * + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: # <<<<<<<<<<<<<< + * cdef int ndim = memslice.memview.view.ndim + * + */ + +static int __pyx_memslice_transpose(__Pyx_memviewslice *__pyx_v_memslice) { + int __pyx_v_ndim; + Py_ssize_t *__pyx_v_shape; + Py_ssize_t *__pyx_v_strides; + int __pyx_v_i; + int __pyx_v_j; + int __pyx_r; + int __pyx_t_1; + Py_ssize_t *__pyx_t_2; + long __pyx_t_3; + long __pyx_t_4; + Py_ssize_t __pyx_t_5; + Py_ssize_t __pyx_t_6; + int __pyx_t_7; + int __pyx_t_8; + int __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":930 + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: + * cdef int ndim = memslice.memview.view.ndim # <<<<<<<<<<<<<< + * + * cdef Py_ssize_t *shape = memslice.shape + */ + __pyx_t_1 = __pyx_v_memslice->memview->view.ndim; + __pyx_v_ndim = __pyx_t_1; + + /* "View.MemoryView":932 + * cdef int ndim = memslice.memview.view.ndim + * + * cdef Py_ssize_t *shape = memslice.shape # <<<<<<<<<<<<<< + * cdef Py_ssize_t *strides = memslice.strides + * + */ + __pyx_t_2 = __pyx_v_memslice->shape; + __pyx_v_shape = __pyx_t_2; + + /* "View.MemoryView":933 + * + * cdef Py_ssize_t *shape = memslice.shape + * cdef Py_ssize_t *strides = memslice.strides # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_v_memslice->strides; + __pyx_v_strides = __pyx_t_2; + + /* "View.MemoryView":937 + * + * cdef int i, j + * for i in range(ndim // 2): # <<<<<<<<<<<<<< + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] + */ + __pyx_t_3 = __Pyx_div_long(__pyx_v_ndim, 2); + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_4; __pyx_t_1+=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":938 + * cdef int i, j + * for i in range(ndim // 2): + * j = ndim - 1 - i # <<<<<<<<<<<<<< + * strides[i], strides[j] = strides[j], strides[i] + * shape[i], shape[j] = shape[j], shape[i] + */ + __pyx_v_j = ((__pyx_v_ndim - 1) - __pyx_v_i); + + /* "View.MemoryView":939 + * for i in range(ndim // 2): + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] # <<<<<<<<<<<<<< + * shape[i], shape[j] = shape[j], shape[i] + * + */ + __pyx_t_5 = (__pyx_v_strides[__pyx_v_j]); + __pyx_t_6 = (__pyx_v_strides[__pyx_v_i]); + (__pyx_v_strides[__pyx_v_i]) = __pyx_t_5; + (__pyx_v_strides[__pyx_v_j]) = __pyx_t_6; + + /* "View.MemoryView":940 + * j = ndim - 1 - i + * strides[i], strides[j] = strides[j], strides[i] + * shape[i], shape[j] = shape[j], shape[i] # <<<<<<<<<<<<<< + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: + */ + __pyx_t_6 = (__pyx_v_shape[__pyx_v_j]); + __pyx_t_5 = (__pyx_v_shape[__pyx_v_i]); + (__pyx_v_shape[__pyx_v_i]) = __pyx_t_6; + (__pyx_v_shape[__pyx_v_j]) = __pyx_t_5; + + /* "View.MemoryView":942 + * shape[i], shape[j] = shape[j], shape[i] + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: # <<<<<<<<<<<<<< + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + */ + __pyx_t_8 = ((__pyx_v_memslice->suboffsets[__pyx_v_i]) >= 0); + if (!__pyx_t_8) { + } else { + __pyx_t_7 = __pyx_t_8; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_8 = ((__pyx_v_memslice->suboffsets[__pyx_v_j]) >= 0); + __pyx_t_7 = __pyx_t_8; + __pyx_L6_bool_binop_done:; + if (__pyx_t_7) { + + /* "View.MemoryView":943 + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") # <<<<<<<<<<<<<< + * + * return 0 + */ + __pyx_t_9 = __pyx_memoryview_err(PyExc_ValueError, __pyx_kp_s_Cannot_transpose_memoryview_with); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(1, 943, __pyx_L1_error) + + /* "View.MemoryView":942 + * shape[i], shape[j] = shape[j], shape[i] + * + * if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: # <<<<<<<<<<<<<< + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + */ + } + } + + /* "View.MemoryView":945 + * _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions") + * + * return 0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":929 + * + * @cname('__pyx_memslice_transpose') + * cdef int transpose_memslice(__Pyx_memviewslice *memslice) except -1 nogil: # <<<<<<<<<<<<<< + * cdef int ndim = memslice.memview.view.ndim + * + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.transpose_memslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":963 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + */ + +/* Python wrapper */ +static void __pyx_memoryviewslice___dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_memoryviewslice___dealloc__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(struct __pyx_memoryviewslice_obj *__pyx_v_self) { + + /* "View.MemoryView":964 + * + * def __dealloc__(self): + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) # <<<<<<<<<<<<<< + * + * cdef convert_item_to_object(self, char *itemp): + */ + __PYX_XCLEAR_MEMVIEW((&__pyx_v_self->from_slice), 1); + + /* "View.MemoryView":963 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + */ + + /* function exit code */ +} + +/* "View.MemoryView":966 + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) + */ + +static PyObject *__pyx_memoryviewslice_convert_item_to_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("convert_item_to_object", 1); + + /* "View.MemoryView":967 + * + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: # <<<<<<<<<<<<<< + * return self.to_object_func(itemp) + * else: + */ + __pyx_t_1 = (__pyx_v_self->to_object_func != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":968 + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) # <<<<<<<<<<<<<< + * else: + * return memoryview.convert_item_to_object(self, itemp) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_v_self->to_object_func(__pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 968, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "View.MemoryView":967 + * + * cdef convert_item_to_object(self, char *itemp): + * if self.to_object_func != NULL: # <<<<<<<<<<<<<< + * return self.to_object_func(itemp) + * else: + */ + } + + /* "View.MemoryView":970 + * return self.to_object_func(itemp) + * else: + * return memoryview.convert_item_to_object(self, itemp) # <<<<<<<<<<<<<< + * + * cdef assign_item_from_object(self, char *itemp, object value): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_memoryview_convert_item_to_object(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_itemp); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 970, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + } + + /* "View.MemoryView":966 + * __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1) + * + * cdef convert_item_to_object(self, char *itemp): # <<<<<<<<<<<<<< + * if self.to_object_func != NULL: + * return self.to_object_func(itemp) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.convert_item_to_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":972 + * return memoryview.convert_item_to_object(self, itemp) + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) + */ + +static PyObject *__pyx_memoryviewslice_assign_item_from_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("assign_item_from_object", 1); + + /* "View.MemoryView":973 + * + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: # <<<<<<<<<<<<<< + * self.to_dtype_func(itemp, value) + * else: + */ + __pyx_t_1 = (__pyx_v_self->to_dtype_func != NULL); + if (__pyx_t_1) { + + /* "View.MemoryView":974 + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) # <<<<<<<<<<<<<< + * else: + * memoryview.assign_item_from_object(self, itemp, value) + */ + __pyx_t_2 = __pyx_v_self->to_dtype_func(__pyx_v_itemp, __pyx_v_value); if (unlikely(__pyx_t_2 == ((int)0))) __PYX_ERR(1, 974, __pyx_L1_error) + + /* "View.MemoryView":973 + * + * cdef assign_item_from_object(self, char *itemp, object value): + * if self.to_dtype_func != NULL: # <<<<<<<<<<<<<< + * self.to_dtype_func(itemp, value) + * else: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":976 + * self.to_dtype_func(itemp, value) + * else: + * memoryview.assign_item_from_object(self, itemp, value) # <<<<<<<<<<<<<< + * + * cdef _get_base(self): + */ + /*else*/ { + __pyx_t_3 = __pyx_memoryview_assign_item_from_object(((struct __pyx_memoryview_obj *)__pyx_v_self), __pyx_v_itemp, __pyx_v_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 976, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "View.MemoryView":972 + * return memoryview.convert_item_to_object(self, itemp) + * + * cdef assign_item_from_object(self, char *itemp, object value): # <<<<<<<<<<<<<< + * if self.to_dtype_func != NULL: + * self.to_dtype_func(itemp, value) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.assign_item_from_object", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":978 + * memoryview.assign_item_from_object(self, itemp, value) + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.from_object + * + */ + +static PyObject *__pyx_memoryviewslice__get_base(struct __pyx_memoryviewslice_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_get_base", 1); + + /* "View.MemoryView":979 + * + * cdef _get_base(self): + * return self.from_object # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_self->from_object); + __pyx_r = __pyx_v_self->from_object; + goto __pyx_L0; + + /* "View.MemoryView":978 + * memoryview.assign_item_from_object(self, itemp, value) + * + * cdef _get_base(self): # <<<<<<<<<<<<<< + * return self.from_object + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryviewslice_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryviewslice_1__reduce_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce_cython__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce_cython__", 0))) return NULL; + __pyx_r = __pyx_pf___pyx_memoryviewslice___reduce_cython__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryviewslice___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 1); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + +/* Python wrapper */ +static PyObject *__pyx_pw___pyx_memoryviewslice_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyObject *__pyx_pw___pyx_memoryviewslice_3__setstate_cython__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 3, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__setstate_cython__") < 0)) __PYX_ERR(1, 3, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v___pyx_state = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__setstate_cython__", 1, 1, 1, __pyx_nargs); __PYX_ERR(1, 3, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf___pyx_memoryviewslice_2__setstate_cython__(((struct __pyx_memoryviewslice_obj *)__pyx_v_self), __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf___pyx_memoryviewslice_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 1); + + /* "(tree fragment)":4 + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" # <<<<<<<<<<<<<< + */ + __Pyx_Raise(__pyx_builtin_TypeError, __pyx_kp_s_no_default___reduce___due_to_non, 0, 0); + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError, "no default __reduce__ due to non-trivial __cinit__" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._memoryviewslice.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":999 + * + * @cname('__pyx_memoryview_fromslice') + * cdef memoryview_fromslice(__Pyx_memviewslice memviewslice, # <<<<<<<<<<<<<< + * int ndim, + * object (*to_object_func)(char *), + */ + +static PyObject *__pyx_memoryview_fromslice(__Pyx_memviewslice __pyx_v_memviewslice, int __pyx_v_ndim, PyObject *(*__pyx_v_to_object_func)(char *), int (*__pyx_v_to_dtype_func)(char *, PyObject *), int __pyx_v_dtype_is_object) { + struct __pyx_memoryviewslice_obj *__pyx_v_result = 0; + Py_ssize_t __pyx_v_suboffset; + PyObject *__pyx_v_length = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + __Pyx_TypeInfo *__pyx_t_4; + Py_buffer __pyx_t_5; + Py_ssize_t *__pyx_t_6; + Py_ssize_t *__pyx_t_7; + Py_ssize_t *__pyx_t_8; + Py_ssize_t __pyx_t_9; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_fromslice", 1); + + /* "View.MemoryView":1007 + * cdef _memoryviewslice result + * + * if memviewslice.memview == Py_None: # <<<<<<<<<<<<<< + * return None + * + */ + __pyx_t_1 = (((PyObject *)__pyx_v_memviewslice.memview) == Py_None); + if (__pyx_t_1) { + + /* "View.MemoryView":1008 + * + * if memviewslice.memview == Py_None: + * return None # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "View.MemoryView":1007 + * cdef _memoryviewslice result + * + * if memviewslice.memview == Py_None: # <<<<<<<<<<<<<< + * return None + * + */ + } + + /* "View.MemoryView":1013 + * + * + * result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object) # <<<<<<<<<<<<<< + * + * result.from_slice = memviewslice + */ + __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_dtype_is_object); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, Py_None)) __PYX_ERR(1, 1013, __pyx_L1_error); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_int_0)) __PYX_ERR(1, 1013, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_2 = ((PyObject *)__pyx_tp_new__memoryviewslice(((PyTypeObject *)__pyx_memoryviewslice_type), __pyx_t_3, NULL)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1013, __pyx_L1_error) + __Pyx_GOTREF((PyObject *)__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1015 + * result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object) + * + * result.from_slice = memviewslice # <<<<<<<<<<<<<< + * __PYX_INC_MEMVIEW(&memviewslice, 1) + * + */ + __pyx_v_result->from_slice = __pyx_v_memviewslice; + + /* "View.MemoryView":1016 + * + * result.from_slice = memviewslice + * __PYX_INC_MEMVIEW(&memviewslice, 1) # <<<<<<<<<<<<<< + * + * result.from_object = ( memviewslice.memview)._get_base() + */ + __PYX_INC_MEMVIEW((&__pyx_v_memviewslice), 1); + + /* "View.MemoryView":1018 + * __PYX_INC_MEMVIEW(&memviewslice, 1) + * + * result.from_object = ( memviewslice.memview)._get_base() # <<<<<<<<<<<<<< + * result.typeinfo = memviewslice.memview.typeinfo + * + */ + __pyx_t_2 = ((struct __pyx_vtabstruct_memoryview *)((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)->__pyx_vtab)->_get_base(((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1018, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_2); + __Pyx_GOTREF(__pyx_v_result->from_object); + __Pyx_DECREF(__pyx_v_result->from_object); + __pyx_v_result->from_object = __pyx_t_2; + __pyx_t_2 = 0; + + /* "View.MemoryView":1019 + * + * result.from_object = ( memviewslice.memview)._get_base() + * result.typeinfo = memviewslice.memview.typeinfo # <<<<<<<<<<<<<< + * + * result.view = memviewslice.memview.view + */ + __pyx_t_4 = __pyx_v_memviewslice.memview->typeinfo; + __pyx_v_result->__pyx_base.typeinfo = __pyx_t_4; + + /* "View.MemoryView":1021 + * result.typeinfo = memviewslice.memview.typeinfo + * + * result.view = memviewslice.memview.view # <<<<<<<<<<<<<< + * result.view.buf = memviewslice.data + * result.view.ndim = ndim + */ + __pyx_t_5 = __pyx_v_memviewslice.memview->view; + __pyx_v_result->__pyx_base.view = __pyx_t_5; + + /* "View.MemoryView":1022 + * + * result.view = memviewslice.memview.view + * result.view.buf = memviewslice.data # <<<<<<<<<<<<<< + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None + */ + __pyx_v_result->__pyx_base.view.buf = ((void *)__pyx_v_memviewslice.data); + + /* "View.MemoryView":1023 + * result.view = memviewslice.memview.view + * result.view.buf = memviewslice.data + * result.view.ndim = ndim # <<<<<<<<<<<<<< + * (<__pyx_buffer *> &result.view).obj = Py_None + * Py_INCREF(Py_None) + */ + __pyx_v_result->__pyx_base.view.ndim = __pyx_v_ndim; + + /* "View.MemoryView":1024 + * result.view.buf = memviewslice.data + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None # <<<<<<<<<<<<<< + * Py_INCREF(Py_None) + * + */ + ((Py_buffer *)(&__pyx_v_result->__pyx_base.view))->obj = Py_None; + + /* "View.MemoryView":1025 + * result.view.ndim = ndim + * (<__pyx_buffer *> &result.view).obj = Py_None + * Py_INCREF(Py_None) # <<<<<<<<<<<<<< + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: + */ + Py_INCREF(Py_None); + + /* "View.MemoryView":1027 + * Py_INCREF(Py_None) + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: # <<<<<<<<<<<<<< + * result.flags = PyBUF_RECORDS + * else: + */ + __pyx_t_1 = ((((struct __pyx_memoryview_obj *)__pyx_v_memviewslice.memview)->flags & PyBUF_WRITABLE) != 0); + if (__pyx_t_1) { + + /* "View.MemoryView":1028 + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: + * result.flags = PyBUF_RECORDS # <<<<<<<<<<<<<< + * else: + * result.flags = PyBUF_RECORDS_RO + */ + __pyx_v_result->__pyx_base.flags = PyBUF_RECORDS; + + /* "View.MemoryView":1027 + * Py_INCREF(Py_None) + * + * if (memviewslice.memview).flags & PyBUF_WRITABLE: # <<<<<<<<<<<<<< + * result.flags = PyBUF_RECORDS + * else: + */ + goto __pyx_L4; + } + + /* "View.MemoryView":1030 + * result.flags = PyBUF_RECORDS + * else: + * result.flags = PyBUF_RECORDS_RO # <<<<<<<<<<<<<< + * + * result.view.shape = result.from_slice.shape + */ + /*else*/ { + __pyx_v_result->__pyx_base.flags = PyBUF_RECORDS_RO; + } + __pyx_L4:; + + /* "View.MemoryView":1032 + * result.flags = PyBUF_RECORDS_RO + * + * result.view.shape = result.from_slice.shape # <<<<<<<<<<<<<< + * result.view.strides = result.from_slice.strides + * + */ + __pyx_v_result->__pyx_base.view.shape = ((Py_ssize_t *)__pyx_v_result->from_slice.shape); + + /* "View.MemoryView":1033 + * + * result.view.shape = result.from_slice.shape + * result.view.strides = result.from_slice.strides # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_result->__pyx_base.view.strides = ((Py_ssize_t *)__pyx_v_result->from_slice.strides); + + /* "View.MemoryView":1036 + * + * + * result.view.suboffsets = NULL # <<<<<<<<<<<<<< + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: + */ + __pyx_v_result->__pyx_base.view.suboffsets = NULL; + + /* "View.MemoryView":1037 + * + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: # <<<<<<<<<<<<<< + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets + */ + __pyx_t_7 = (__pyx_v_result->from_slice.suboffsets + __pyx_v_ndim); + for (__pyx_t_8 = __pyx_v_result->from_slice.suboffsets; __pyx_t_8 < __pyx_t_7; __pyx_t_8++) { + __pyx_t_6 = __pyx_t_8; + __pyx_v_suboffset = (__pyx_t_6[0]); + + /* "View.MemoryView":1038 + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * result.view.suboffsets = result.from_slice.suboffsets + * break + */ + __pyx_t_1 = (__pyx_v_suboffset >= 0); + if (__pyx_t_1) { + + /* "View.MemoryView":1039 + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_result->__pyx_base.view.suboffsets = ((Py_ssize_t *)__pyx_v_result->from_slice.suboffsets); + + /* "View.MemoryView":1040 + * if suboffset >= 0: + * result.view.suboffsets = result.from_slice.suboffsets + * break # <<<<<<<<<<<<<< + * + * result.view.len = result.view.itemsize + */ + goto __pyx_L6_break; + + /* "View.MemoryView":1038 + * result.view.suboffsets = NULL + * for suboffset in result.from_slice.suboffsets[:ndim]: + * if suboffset >= 0: # <<<<<<<<<<<<<< + * result.view.suboffsets = result.from_slice.suboffsets + * break + */ + } + } + __pyx_L6_break:; + + /* "View.MemoryView":1042 + * break + * + * result.view.len = result.view.itemsize # <<<<<<<<<<<<<< + * for length in result.view.shape[:ndim]: + * result.view.len *= length + */ + __pyx_t_9 = __pyx_v_result->__pyx_base.view.itemsize; + __pyx_v_result->__pyx_base.view.len = __pyx_t_9; + + /* "View.MemoryView":1043 + * + * result.view.len = result.view.itemsize + * for length in result.view.shape[:ndim]: # <<<<<<<<<<<<<< + * result.view.len *= length + * + */ + __pyx_t_7 = (__pyx_v_result->__pyx_base.view.shape + __pyx_v_ndim); + for (__pyx_t_8 = __pyx_v_result->__pyx_base.view.shape; __pyx_t_8 < __pyx_t_7; __pyx_t_8++) { + __pyx_t_6 = __pyx_t_8; + __pyx_t_2 = PyInt_FromSsize_t((__pyx_t_6[0])); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1043, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1044 + * result.view.len = result.view.itemsize + * for length in result.view.shape[:ndim]: + * result.view.len *= length # <<<<<<<<<<<<<< + * + * result.to_object_func = to_object_func + */ + __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_result->__pyx_base.view.len); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_InPlaceMultiply(__pyx_t_2, __pyx_v_length); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyIndex_AsSsize_t(__pyx_t_3); if (unlikely((__pyx_t_9 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_result->__pyx_base.view.len = __pyx_t_9; + } + + /* "View.MemoryView":1046 + * result.view.len *= length + * + * result.to_object_func = to_object_func # <<<<<<<<<<<<<< + * result.to_dtype_func = to_dtype_func + * + */ + __pyx_v_result->to_object_func = __pyx_v_to_object_func; + + /* "View.MemoryView":1047 + * + * result.to_object_func = to_object_func + * result.to_dtype_func = to_dtype_func # <<<<<<<<<<<<<< + * + * return result + */ + __pyx_v_result->to_dtype_func = __pyx_v_to_dtype_func; + + /* "View.MemoryView":1049 + * result.to_dtype_func = to_dtype_func + * + * return result # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_result); + __pyx_r = ((PyObject *)__pyx_v_result); + goto __pyx_L0; + + /* "View.MemoryView":999 + * + * @cname('__pyx_memoryview_fromslice') + * cdef memoryview_fromslice(__Pyx_memviewslice memviewslice, # <<<<<<<<<<<<<< + * int ndim, + * object (*to_object_func)(char *), + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("View.MemoryView.memoryview_fromslice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_result); + __Pyx_XDECREF(__pyx_v_length); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1052 + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + * cdef __Pyx_memviewslice *get_slice_from_memview(memoryview memview, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + */ + +static __Pyx_memviewslice *__pyx_memoryview_get_slice_from_memoryview(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_mslice) { + struct __pyx_memoryviewslice_obj *__pyx_v_obj = 0; + __Pyx_memviewslice *__pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get_slice_from_memview", 1); + + /* "View.MemoryView":1055 + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * obj = memview + * return &obj.from_slice + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":1056 + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): + * obj = memview # <<<<<<<<<<<<<< + * return &obj.from_slice + * else: + */ + if (!(likely(((((PyObject *)__pyx_v_memview)) == Py_None) || likely(__Pyx_TypeTest(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type))))) __PYX_ERR(1, 1056, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_v_memview); + __Pyx_INCREF(__pyx_t_2); + __pyx_v_obj = ((struct __pyx_memoryviewslice_obj *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "View.MemoryView":1057 + * if isinstance(memview, _memoryviewslice): + * obj = memview + * return &obj.from_slice # <<<<<<<<<<<<<< + * else: + * slice_copy(memview, mslice) + */ + __pyx_r = (&__pyx_v_obj->from_slice); + goto __pyx_L0; + + /* "View.MemoryView":1055 + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * obj = memview + * return &obj.from_slice + */ + } + + /* "View.MemoryView":1059 + * return &obj.from_slice + * else: + * slice_copy(memview, mslice) # <<<<<<<<<<<<<< + * return mslice + * + */ + /*else*/ { + __pyx_memoryview_slice_copy(__pyx_v_memview, __pyx_v_mslice); + + /* "View.MemoryView":1060 + * else: + * slice_copy(memview, mslice) + * return mslice # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_slice_copy') + */ + __pyx_r = __pyx_v_mslice; + goto __pyx_L0; + } + + /* "View.MemoryView":1052 + * + * @cname('__pyx_memoryview_get_slice_from_memoryview') + * cdef __Pyx_memviewslice *get_slice_from_memview(memoryview memview, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *mslice) except NULL: + * cdef _memoryviewslice obj + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView.get_slice_from_memview", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_obj); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1063 + * + * @cname('__pyx_memoryview_slice_copy') + * cdef void slice_copy(memoryview memview, __Pyx_memviewslice *dst) noexcept: # <<<<<<<<<<<<<< + * cdef int dim + * cdef (Py_ssize_t*) shape, strides, suboffsets + */ + +static void __pyx_memoryview_slice_copy(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_dst) { + int __pyx_v_dim; + Py_ssize_t *__pyx_v_shape; + Py_ssize_t *__pyx_v_strides; + Py_ssize_t *__pyx_v_suboffsets; + Py_ssize_t *__pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + Py_ssize_t __pyx_t_5; + int __pyx_t_6; + + /* "View.MemoryView":1067 + * cdef (Py_ssize_t*) shape, strides, suboffsets + * + * shape = memview.view.shape # <<<<<<<<<<<<<< + * strides = memview.view.strides + * suboffsets = memview.view.suboffsets + */ + __pyx_t_1 = __pyx_v_memview->view.shape; + __pyx_v_shape = __pyx_t_1; + + /* "View.MemoryView":1068 + * + * shape = memview.view.shape + * strides = memview.view.strides # <<<<<<<<<<<<<< + * suboffsets = memview.view.suboffsets + * + */ + __pyx_t_1 = __pyx_v_memview->view.strides; + __pyx_v_strides = __pyx_t_1; + + /* "View.MemoryView":1069 + * shape = memview.view.shape + * strides = memview.view.strides + * suboffsets = memview.view.suboffsets # <<<<<<<<<<<<<< + * + * dst.memview = <__pyx_memoryview *> memview + */ + __pyx_t_1 = __pyx_v_memview->view.suboffsets; + __pyx_v_suboffsets = __pyx_t_1; + + /* "View.MemoryView":1071 + * suboffsets = memview.view.suboffsets + * + * dst.memview = <__pyx_memoryview *> memview # <<<<<<<<<<<<<< + * dst.data = memview.view.buf + * + */ + __pyx_v_dst->memview = ((struct __pyx_memoryview_obj *)__pyx_v_memview); + + /* "View.MemoryView":1072 + * + * dst.memview = <__pyx_memoryview *> memview + * dst.data = memview.view.buf # <<<<<<<<<<<<<< + * + * for dim in range(memview.view.ndim): + */ + __pyx_v_dst->data = ((char *)__pyx_v_memview->view.buf); + + /* "View.MemoryView":1074 + * dst.data = memview.view.buf + * + * for dim in range(memview.view.ndim): # <<<<<<<<<<<<<< + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] + */ + __pyx_t_2 = __pyx_v_memview->view.ndim; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_dim = __pyx_t_4; + + /* "View.MemoryView":1075 + * + * for dim in range(memview.view.ndim): + * dst.shape[dim] = shape[dim] # <<<<<<<<<<<<<< + * dst.strides[dim] = strides[dim] + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 + */ + (__pyx_v_dst->shape[__pyx_v_dim]) = (__pyx_v_shape[__pyx_v_dim]); + + /* "View.MemoryView":1076 + * for dim in range(memview.view.ndim): + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] # <<<<<<<<<<<<<< + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 + * + */ + (__pyx_v_dst->strides[__pyx_v_dim]) = (__pyx_v_strides[__pyx_v_dim]); + + /* "View.MemoryView":1077 + * dst.shape[dim] = shape[dim] + * dst.strides[dim] = strides[dim] + * dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_object') + */ + __pyx_t_6 = (__pyx_v_suboffsets != 0); + if (__pyx_t_6) { + __pyx_t_5 = (__pyx_v_suboffsets[__pyx_v_dim]); + } else { + __pyx_t_5 = -1L; + } + (__pyx_v_dst->suboffsets[__pyx_v_dim]) = __pyx_t_5; + } + + /* "View.MemoryView":1063 + * + * @cname('__pyx_memoryview_slice_copy') + * cdef void slice_copy(memoryview memview, __Pyx_memviewslice *dst) noexcept: # <<<<<<<<<<<<<< + * cdef int dim + * cdef (Py_ssize_t*) shape, strides, suboffsets + */ + + /* function exit code */ +} + +/* "View.MemoryView":1080 + * + * @cname('__pyx_memoryview_copy_object') + * cdef memoryview_copy(memoryview memview): # <<<<<<<<<<<<<< + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + */ + +static PyObject *__pyx_memoryview_copy_object(struct __pyx_memoryview_obj *__pyx_v_memview) { + __Pyx_memviewslice __pyx_v_memviewslice; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_copy", 1); + + /* "View.MemoryView":1083 + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + * slice_copy(memview, &memviewslice) # <<<<<<<<<<<<<< + * return memoryview_copy_from_slice(memview, &memviewslice) + * + */ + __pyx_memoryview_slice_copy(__pyx_v_memview, (&__pyx_v_memviewslice)); + + /* "View.MemoryView":1084 + * cdef __Pyx_memviewslice memviewslice + * slice_copy(memview, &memviewslice) + * return memoryview_copy_from_slice(memview, &memviewslice) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_object_from_slice') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_memoryview_copy_object_from_slice(__pyx_v_memview, (&__pyx_v_memviewslice)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "View.MemoryView":1080 + * + * @cname('__pyx_memoryview_copy_object') + * cdef memoryview_copy(memoryview memview): # <<<<<<<<<<<<<< + * "Create a new memoryview object" + * cdef __Pyx_memviewslice memviewslice + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("View.MemoryView.memoryview_copy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1087 + * + * @cname('__pyx_memoryview_copy_object_from_slice') + * cdef memoryview_copy_from_slice(memoryview memview, __Pyx_memviewslice *memviewslice): # <<<<<<<<<<<<<< + * """ + * Create a new memoryview object from a given memoryview object and slice. + */ + +static PyObject *__pyx_memoryview_copy_object_from_slice(struct __pyx_memoryview_obj *__pyx_v_memview, __Pyx_memviewslice *__pyx_v_memviewslice) { + PyObject *(*__pyx_v_to_object_func)(char *); + int (*__pyx_v_to_dtype_func)(char *, PyObject *); + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *(*__pyx_t_2)(char *); + int (*__pyx_t_3)(char *, PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("memoryview_copy_from_slice", 1); + + /* "View.MemoryView":1094 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + */ + __pyx_t_1 = __Pyx_TypeCheck(((PyObject *)__pyx_v_memview), __pyx_memoryviewslice_type); + if (__pyx_t_1) { + + /* "View.MemoryView":1095 + * + * if isinstance(memview, _memoryviewslice): + * to_object_func = (<_memoryviewslice> memview).to_object_func # <<<<<<<<<<<<<< + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + * else: + */ + __pyx_t_2 = ((struct __pyx_memoryviewslice_obj *)__pyx_v_memview)->to_object_func; + __pyx_v_to_object_func = __pyx_t_2; + + /* "View.MemoryView":1096 + * if isinstance(memview, _memoryviewslice): + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func # <<<<<<<<<<<<<< + * else: + * to_object_func = NULL + */ + __pyx_t_3 = ((struct __pyx_memoryviewslice_obj *)__pyx_v_memview)->to_dtype_func; + __pyx_v_to_dtype_func = __pyx_t_3; + + /* "View.MemoryView":1094 + * cdef int (*to_dtype_func)(char *, object) except 0 + * + * if isinstance(memview, _memoryviewslice): # <<<<<<<<<<<<<< + * to_object_func = (<_memoryviewslice> memview).to_object_func + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1098 + * to_dtype_func = (<_memoryviewslice> memview).to_dtype_func + * else: + * to_object_func = NULL # <<<<<<<<<<<<<< + * to_dtype_func = NULL + * + */ + /*else*/ { + __pyx_v_to_object_func = NULL; + + /* "View.MemoryView":1099 + * else: + * to_object_func = NULL + * to_dtype_func = NULL # <<<<<<<<<<<<<< + * + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, + */ + __pyx_v_to_dtype_func = NULL; + } + __pyx_L3:; + + /* "View.MemoryView":1101 + * to_dtype_func = NULL + * + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, # <<<<<<<<<<<<<< + * to_object_func, to_dtype_func, + * memview.dtype_is_object) + */ + __Pyx_XDECREF(__pyx_r); + + /* "View.MemoryView":1103 + * return memoryview_fromslice(memviewslice[0], memview.view.ndim, + * to_object_func, to_dtype_func, + * memview.dtype_is_object) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_4 = __pyx_memoryview_fromslice((__pyx_v_memviewslice[0]), __pyx_v_memview->view.ndim, __pyx_v_to_object_func, __pyx_v_to_dtype_func, __pyx_v_memview->dtype_is_object); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "View.MemoryView":1087 + * + * @cname('__pyx_memoryview_copy_object_from_slice') + * cdef memoryview_copy_from_slice(memoryview memview, __Pyx_memviewslice *memviewslice): # <<<<<<<<<<<<<< + * """ + * Create a new memoryview object from a given memoryview object and slice. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.memoryview_copy_from_slice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "View.MemoryView":1109 + * + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: # <<<<<<<<<<<<<< + * return -arg if arg < 0 else arg + * + */ + +static Py_ssize_t abs_py_ssize_t(Py_ssize_t __pyx_v_arg) { + Py_ssize_t __pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + + /* "View.MemoryView":1110 + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: + * return -arg if arg < 0 else arg # <<<<<<<<<<<<<< + * + * @cname('__pyx_get_best_slice_order') + */ + __pyx_t_2 = (__pyx_v_arg < 0); + if (__pyx_t_2) { + __pyx_t_1 = (-__pyx_v_arg); + } else { + __pyx_t_1 = __pyx_v_arg; + } + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "View.MemoryView":1109 + * + * + * cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil: # <<<<<<<<<<<<<< + * return -arg if arg < 0 else arg + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1113 + * + * @cname('__pyx_get_best_slice_order') + * cdef char get_best_order(__Pyx_memviewslice *mslice, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * """ + * Figure out the best memory access order for a given slice. + */ + +static char __pyx_get_best_slice_order(__Pyx_memviewslice *__pyx_v_mslice, int __pyx_v_ndim) { + int __pyx_v_i; + Py_ssize_t __pyx_v_c_stride; + Py_ssize_t __pyx_v_f_stride; + char __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1118 + * """ + * cdef int i + * cdef Py_ssize_t c_stride = 0 # <<<<<<<<<<<<<< + * cdef Py_ssize_t f_stride = 0 + * + */ + __pyx_v_c_stride = 0; + + /* "View.MemoryView":1119 + * cdef int i + * cdef Py_ssize_t c_stride = 0 + * cdef Py_ssize_t f_stride = 0 # <<<<<<<<<<<<<< + * + * for i in range(ndim - 1, -1, -1): + */ + __pyx_v_f_stride = 0; + + /* "View.MemoryView":1121 + * cdef Py_ssize_t f_stride = 0 + * + * for i in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] + */ + for (__pyx_t_1 = (__pyx_v_ndim - 1); __pyx_t_1 > -1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":1122 + * + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * c_stride = mslice.strides[i] + * break + */ + __pyx_t_2 = ((__pyx_v_mslice->shape[__pyx_v_i]) > 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1123 + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_c_stride = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1124 + * if mslice.shape[i] > 1: + * c_stride = mslice.strides[i] + * break # <<<<<<<<<<<<<< + * + * for i in range(ndim): + */ + goto __pyx_L4_break; + + /* "View.MemoryView":1122 + * + * for i in range(ndim - 1, -1, -1): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * c_stride = mslice.strides[i] + * break + */ + } + } + __pyx_L4_break:; + + /* "View.MemoryView":1126 + * break + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] + */ + __pyx_t_1 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_1; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1127 + * + * for i in range(ndim): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * f_stride = mslice.strides[i] + * break + */ + __pyx_t_2 = ((__pyx_v_mslice->shape[__pyx_v_i]) > 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1128 + * for i in range(ndim): + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] # <<<<<<<<<<<<<< + * break + * + */ + __pyx_v_f_stride = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1129 + * if mslice.shape[i] > 1: + * f_stride = mslice.strides[i] + * break # <<<<<<<<<<<<<< + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): + */ + goto __pyx_L7_break; + + /* "View.MemoryView":1127 + * + * for i in range(ndim): + * if mslice.shape[i] > 1: # <<<<<<<<<<<<<< + * f_stride = mslice.strides[i] + * break + */ + } + } + __pyx_L7_break:; + + /* "View.MemoryView":1131 + * break + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): # <<<<<<<<<<<<<< + * return 'C' + * else: + */ + __pyx_t_2 = (abs_py_ssize_t(__pyx_v_c_stride) <= abs_py_ssize_t(__pyx_v_f_stride)); + if (__pyx_t_2) { + + /* "View.MemoryView":1132 + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): + * return 'C' # <<<<<<<<<<<<<< + * else: + * return 'F' + */ + __pyx_r = 'C'; + goto __pyx_L0; + + /* "View.MemoryView":1131 + * break + * + * if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): # <<<<<<<<<<<<<< + * return 'C' + * else: + */ + } + + /* "View.MemoryView":1134 + * return 'C' + * else: + * return 'F' # <<<<<<<<<<<<<< + * + * @cython.cdivision(True) + */ + /*else*/ { + __pyx_r = 'F'; + goto __pyx_L0; + } + + /* "View.MemoryView":1113 + * + * @cname('__pyx_get_best_slice_order') + * cdef char get_best_order(__Pyx_memviewslice *mslice, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * """ + * Figure out the best memory access order for a given slice. + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1137 + * + * @cython.cdivision(True) + * cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, # <<<<<<<<<<<<<< + * char *dst_data, Py_ssize_t *dst_strides, + * Py_ssize_t *src_shape, Py_ssize_t *dst_shape, + */ + +static void _copy_strided_to_strided(char *__pyx_v_src_data, Py_ssize_t *__pyx_v_src_strides, char *__pyx_v_dst_data, Py_ssize_t *__pyx_v_dst_strides, Py_ssize_t *__pyx_v_src_shape, Py_ssize_t *__pyx_v_dst_shape, int __pyx_v_ndim, size_t __pyx_v_itemsize) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + CYTHON_UNUSED Py_ssize_t __pyx_v_src_extent; + Py_ssize_t __pyx_v_dst_extent; + Py_ssize_t __pyx_v_src_stride; + Py_ssize_t __pyx_v_dst_stride; + int __pyx_t_1; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + + /* "View.MemoryView":1144 + * + * cdef Py_ssize_t i + * cdef Py_ssize_t src_extent = src_shape[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] + */ + __pyx_v_src_extent = (__pyx_v_src_shape[0]); + + /* "View.MemoryView":1145 + * cdef Py_ssize_t i + * cdef Py_ssize_t src_extent = src_shape[0] + * cdef Py_ssize_t dst_extent = dst_shape[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t src_stride = src_strides[0] + * cdef Py_ssize_t dst_stride = dst_strides[0] + */ + __pyx_v_dst_extent = (__pyx_v_dst_shape[0]); + + /* "View.MemoryView":1146 + * cdef Py_ssize_t src_extent = src_shape[0] + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + */ + __pyx_v_src_stride = (__pyx_v_src_strides[0]); + + /* "View.MemoryView":1147 + * cdef Py_ssize_t dst_extent = dst_shape[0] + * cdef Py_ssize_t src_stride = src_strides[0] + * cdef Py_ssize_t dst_stride = dst_strides[0] # <<<<<<<<<<<<<< + * + * if ndim == 1: + */ + __pyx_v_dst_stride = (__pyx_v_dst_strides[0]); + + /* "View.MemoryView":1149 + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + */ + __pyx_t_1 = (__pyx_v_ndim == 1); + if (__pyx_t_1) { + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + __pyx_t_2 = (__pyx_v_src_stride > 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_dst_stride > 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L5_bool_binop_done; + } + + /* "View.MemoryView":1151 + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): # <<<<<<<<<<<<<< + * memcpy(dst_data, src_data, itemsize * dst_extent) + * else: + */ + __pyx_t_2 = (((size_t)__pyx_v_src_stride) == __pyx_v_itemsize); + if (__pyx_t_2) { + __pyx_t_2 = (__pyx_v_itemsize == ((size_t)__pyx_v_dst_stride)); + } + __pyx_t_1 = __pyx_t_2; + __pyx_L5_bool_binop_done:; + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + if (__pyx_t_1) { + + /* "View.MemoryView":1152 + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) # <<<<<<<<<<<<<< + * else: + * for i in range(dst_extent): + */ + (void)(memcpy(__pyx_v_dst_data, __pyx_v_src_data, (__pyx_v_itemsize * __pyx_v_dst_extent))); + + /* "View.MemoryView":1150 + * + * if ndim == 1: + * if (src_stride > 0 and dst_stride > 0 and # <<<<<<<<<<<<<< + * src_stride == itemsize == dst_stride): + * memcpy(dst_data, src_data, itemsize * dst_extent) + */ + goto __pyx_L4; + } + + /* "View.MemoryView":1154 + * memcpy(dst_data, src_data, itemsize * dst_extent) + * else: + * for i in range(dst_extent): # <<<<<<<<<<<<<< + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride + */ + /*else*/ { + __pyx_t_3 = __pyx_v_dst_extent; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "View.MemoryView":1155 + * else: + * for i in range(dst_extent): + * memcpy(dst_data, src_data, itemsize) # <<<<<<<<<<<<<< + * src_data += src_stride + * dst_data += dst_stride + */ + (void)(memcpy(__pyx_v_dst_data, __pyx_v_src_data, __pyx_v_itemsize)); + + /* "View.MemoryView":1156 + * for i in range(dst_extent): + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride # <<<<<<<<<<<<<< + * dst_data += dst_stride + * else: + */ + __pyx_v_src_data = (__pyx_v_src_data + __pyx_v_src_stride); + + /* "View.MemoryView":1157 + * memcpy(dst_data, src_data, itemsize) + * src_data += src_stride + * dst_data += dst_stride # <<<<<<<<<<<<<< + * else: + * for i in range(dst_extent): + */ + __pyx_v_dst_data = (__pyx_v_dst_data + __pyx_v_dst_stride); + } + } + __pyx_L4:; + + /* "View.MemoryView":1149 + * cdef Py_ssize_t dst_stride = dst_strides[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * if (src_stride > 0 and dst_stride > 0 and + * src_stride == itemsize == dst_stride): + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1159 + * dst_data += dst_stride + * else: + * for i in range(dst_extent): # <<<<<<<<<<<<<< + * _copy_strided_to_strided(src_data, src_strides + 1, + * dst_data, dst_strides + 1, + */ + /*else*/ { + __pyx_t_3 = __pyx_v_dst_extent; + __pyx_t_4 = __pyx_t_3; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "View.MemoryView":1160 + * else: + * for i in range(dst_extent): + * _copy_strided_to_strided(src_data, src_strides + 1, # <<<<<<<<<<<<<< + * dst_data, dst_strides + 1, + * src_shape + 1, dst_shape + 1, + */ + _copy_strided_to_strided(__pyx_v_src_data, (__pyx_v_src_strides + 1), __pyx_v_dst_data, (__pyx_v_dst_strides + 1), (__pyx_v_src_shape + 1), (__pyx_v_dst_shape + 1), (__pyx_v_ndim - 1), __pyx_v_itemsize); + + /* "View.MemoryView":1164 + * src_shape + 1, dst_shape + 1, + * ndim - 1, itemsize) + * src_data += src_stride # <<<<<<<<<<<<<< + * dst_data += dst_stride + * + */ + __pyx_v_src_data = (__pyx_v_src_data + __pyx_v_src_stride); + + /* "View.MemoryView":1165 + * ndim - 1, itemsize) + * src_data += src_stride + * dst_data += dst_stride # <<<<<<<<<<<<<< + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, + */ + __pyx_v_dst_data = (__pyx_v_dst_data + __pyx_v_dst_stride); + } + } + __pyx_L3:; + + /* "View.MemoryView":1137 + * + * @cython.cdivision(True) + * cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, # <<<<<<<<<<<<<< + * char *dst_data, Py_ssize_t *dst_strides, + * Py_ssize_t *src_shape, Py_ssize_t *dst_shape, + */ + + /* function exit code */ +} + +/* "View.MemoryView":1167 + * dst_data += dst_stride + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + */ + +static void copy_strided_to_strided(__Pyx_memviewslice *__pyx_v_src, __Pyx_memviewslice *__pyx_v_dst, int __pyx_v_ndim, size_t __pyx_v_itemsize) { + + /* "View.MemoryView":1170 + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + * _copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides, # <<<<<<<<<<<<<< + * src.shape, dst.shape, ndim, itemsize) + * + */ + _copy_strided_to_strided(__pyx_v_src->data, __pyx_v_src->strides, __pyx_v_dst->data, __pyx_v_dst->strides, __pyx_v_src->shape, __pyx_v_dst->shape, __pyx_v_ndim, __pyx_v_itemsize); + + /* "View.MemoryView":1167 + * dst_data += dst_stride + * + * cdef void copy_strided_to_strided(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *dst, + * int ndim, size_t itemsize) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1174 + * + * @cname('__pyx_memoryview_slice_get_size') + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + */ + +static Py_ssize_t __pyx_memoryview_slice_get_size(__Pyx_memviewslice *__pyx_v_src, int __pyx_v_ndim) { + Py_ssize_t __pyx_v_shape; + Py_ssize_t __pyx_v_size; + Py_ssize_t __pyx_r; + Py_ssize_t __pyx_t_1; + Py_ssize_t *__pyx_t_2; + Py_ssize_t *__pyx_t_3; + Py_ssize_t *__pyx_t_4; + + /* "View.MemoryView":1176 + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize # <<<<<<<<<<<<<< + * + * for shape in src.shape[:ndim]: + */ + __pyx_t_1 = __pyx_v_src->memview->view.itemsize; + __pyx_v_size = __pyx_t_1; + + /* "View.MemoryView":1178 + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + * + * for shape in src.shape[:ndim]: # <<<<<<<<<<<<<< + * size *= shape + * + */ + __pyx_t_3 = (__pyx_v_src->shape + __pyx_v_ndim); + for (__pyx_t_4 = __pyx_v_src->shape; __pyx_t_4 < __pyx_t_3; __pyx_t_4++) { + __pyx_t_2 = __pyx_t_4; + __pyx_v_shape = (__pyx_t_2[0]); + + /* "View.MemoryView":1179 + * + * for shape in src.shape[:ndim]: + * size *= shape # <<<<<<<<<<<<<< + * + * return size + */ + __pyx_v_size = (__pyx_v_size * __pyx_v_shape); + } + + /* "View.MemoryView":1181 + * size *= shape + * + * return size # <<<<<<<<<<<<<< + * + * @cname('__pyx_fill_contig_strides_array') + */ + __pyx_r = __pyx_v_size; + goto __pyx_L0; + + /* "View.MemoryView":1174 + * + * @cname('__pyx_memoryview_slice_get_size') + * cdef Py_ssize_t slice_get_size(__Pyx_memviewslice *src, int ndim) noexcept nogil: # <<<<<<<<<<<<<< + * "Return the size of the memory occupied by the slice in number of bytes" + * cdef Py_ssize_t shape, size = src.memview.view.itemsize + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1184 + * + * @cname('__pyx_fill_contig_strides_array') + * cdef Py_ssize_t fill_contig_strides_array( # <<<<<<<<<<<<<< + * Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, + * int ndim, char order) noexcept nogil: + */ + +static Py_ssize_t __pyx_fill_contig_strides_array(Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, Py_ssize_t __pyx_v_stride, int __pyx_v_ndim, char __pyx_v_order) { + int __pyx_v_idx; + Py_ssize_t __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1193 + * cdef int idx + * + * if order == 'F': # <<<<<<<<<<<<<< + * for idx in range(ndim): + * strides[idx] = stride + */ + __pyx_t_1 = (__pyx_v_order == 'F'); + if (__pyx_t_1) { + + /* "View.MemoryView":1194 + * + * if order == 'F': + * for idx in range(ndim): # <<<<<<<<<<<<<< + * strides[idx] = stride + * stride *= shape[idx] + */ + __pyx_t_2 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_idx = __pyx_t_4; + + /* "View.MemoryView":1195 + * if order == 'F': + * for idx in range(ndim): + * strides[idx] = stride # <<<<<<<<<<<<<< + * stride *= shape[idx] + * else: + */ + (__pyx_v_strides[__pyx_v_idx]) = __pyx_v_stride; + + /* "View.MemoryView":1196 + * for idx in range(ndim): + * strides[idx] = stride + * stride *= shape[idx] # <<<<<<<<<<<<<< + * else: + * for idx in range(ndim - 1, -1, -1): + */ + __pyx_v_stride = (__pyx_v_stride * (__pyx_v_shape[__pyx_v_idx])); + } + + /* "View.MemoryView":1193 + * cdef int idx + * + * if order == 'F': # <<<<<<<<<<<<<< + * for idx in range(ndim): + * strides[idx] = stride + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1198 + * stride *= shape[idx] + * else: + * for idx in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * strides[idx] = stride + * stride *= shape[idx] + */ + /*else*/ { + for (__pyx_t_2 = (__pyx_v_ndim - 1); __pyx_t_2 > -1; __pyx_t_2-=1) { + __pyx_v_idx = __pyx_t_2; + + /* "View.MemoryView":1199 + * else: + * for idx in range(ndim - 1, -1, -1): + * strides[idx] = stride # <<<<<<<<<<<<<< + * stride *= shape[idx] + * + */ + (__pyx_v_strides[__pyx_v_idx]) = __pyx_v_stride; + + /* "View.MemoryView":1200 + * for idx in range(ndim - 1, -1, -1): + * strides[idx] = stride + * stride *= shape[idx] # <<<<<<<<<<<<<< + * + * return stride + */ + __pyx_v_stride = (__pyx_v_stride * (__pyx_v_shape[__pyx_v_idx])); + } + } + __pyx_L3:; + + /* "View.MemoryView":1202 + * stride *= shape[idx] + * + * return stride # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_copy_data_to_temp') + */ + __pyx_r = __pyx_v_stride; + goto __pyx_L0; + + /* "View.MemoryView":1184 + * + * @cname('__pyx_fill_contig_strides_array') + * cdef Py_ssize_t fill_contig_strides_array( # <<<<<<<<<<<<<< + * Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, + * int ndim, char order) noexcept nogil: + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1205 + * + * @cname('__pyx_memoryview_copy_data_to_temp') + * cdef void *copy_data_to_temp(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *tmpslice, + * char order, + */ + +static void *__pyx_memoryview_copy_data_to_temp(__Pyx_memviewslice *__pyx_v_src, __Pyx_memviewslice *__pyx_v_tmpslice, char __pyx_v_order, int __pyx_v_ndim) { + int __pyx_v_i; + void *__pyx_v_result; + size_t __pyx_v_itemsize; + size_t __pyx_v_size; + void *__pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + struct __pyx_memoryview_obj *__pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":1216 + * cdef void *result + * + * cdef size_t itemsize = src.memview.view.itemsize # <<<<<<<<<<<<<< + * cdef size_t size = slice_get_size(src, ndim) + * + */ + __pyx_t_1 = __pyx_v_src->memview->view.itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":1217 + * + * cdef size_t itemsize = src.memview.view.itemsize + * cdef size_t size = slice_get_size(src, ndim) # <<<<<<<<<<<<<< + * + * result = malloc(size) + */ + __pyx_v_size = __pyx_memoryview_slice_get_size(__pyx_v_src, __pyx_v_ndim); + + /* "View.MemoryView":1219 + * cdef size_t size = slice_get_size(src, ndim) + * + * result = malloc(size) # <<<<<<<<<<<<<< + * if not result: + * _err_no_memory() + */ + __pyx_v_result = malloc(__pyx_v_size); + + /* "View.MemoryView":1220 + * + * result = malloc(size) + * if not result: # <<<<<<<<<<<<<< + * _err_no_memory() + * + */ + __pyx_t_2 = (!(__pyx_v_result != 0)); + if (__pyx_t_2) { + + /* "View.MemoryView":1221 + * result = malloc(size) + * if not result: + * _err_no_memory() # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_3 = __pyx_memoryview_err_no_memory(); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 1221, __pyx_L1_error) + + /* "View.MemoryView":1220 + * + * result = malloc(size) + * if not result: # <<<<<<<<<<<<<< + * _err_no_memory() + * + */ + } + + /* "View.MemoryView":1224 + * + * + * tmpslice.data = result # <<<<<<<<<<<<<< + * tmpslice.memview = src.memview + * for i in range(ndim): + */ + __pyx_v_tmpslice->data = ((char *)__pyx_v_result); + + /* "View.MemoryView":1225 + * + * tmpslice.data = result + * tmpslice.memview = src.memview # <<<<<<<<<<<<<< + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] + */ + __pyx_t_4 = __pyx_v_src->memview; + __pyx_v_tmpslice->memview = __pyx_t_4; + + /* "View.MemoryView":1226 + * tmpslice.data = result + * tmpslice.memview = src.memview + * for i in range(ndim): # <<<<<<<<<<<<<< + * tmpslice.shape[i] = src.shape[i] + * tmpslice.suboffsets[i] = -1 + */ + __pyx_t_3 = __pyx_v_ndim; + __pyx_t_5 = __pyx_t_3; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "View.MemoryView":1227 + * tmpslice.memview = src.memview + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] # <<<<<<<<<<<<<< + * tmpslice.suboffsets[i] = -1 + * + */ + (__pyx_v_tmpslice->shape[__pyx_v_i]) = (__pyx_v_src->shape[__pyx_v_i]); + + /* "View.MemoryView":1228 + * for i in range(ndim): + * tmpslice.shape[i] = src.shape[i] + * tmpslice.suboffsets[i] = -1 # <<<<<<<<<<<<<< + * + * fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order) + */ + (__pyx_v_tmpslice->suboffsets[__pyx_v_i]) = -1L; + } + + /* "View.MemoryView":1230 + * tmpslice.suboffsets[i] = -1 + * + * fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order) # <<<<<<<<<<<<<< + * + * + */ + (void)(__pyx_fill_contig_strides_array((&(__pyx_v_tmpslice->shape[0])), (&(__pyx_v_tmpslice->strides[0])), __pyx_v_itemsize, __pyx_v_ndim, __pyx_v_order)); + + /* "View.MemoryView":1233 + * + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if tmpslice.shape[i] == 1: + * tmpslice.strides[i] = 0 + */ + __pyx_t_3 = __pyx_v_ndim; + __pyx_t_5 = __pyx_t_3; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "View.MemoryView":1234 + * + * for i in range(ndim): + * if tmpslice.shape[i] == 1: # <<<<<<<<<<<<<< + * tmpslice.strides[i] = 0 + * + */ + __pyx_t_2 = ((__pyx_v_tmpslice->shape[__pyx_v_i]) == 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1235 + * for i in range(ndim): + * if tmpslice.shape[i] == 1: + * tmpslice.strides[i] = 0 # <<<<<<<<<<<<<< + * + * if slice_is_contig(src[0], order, ndim): + */ + (__pyx_v_tmpslice->strides[__pyx_v_i]) = 0; + + /* "View.MemoryView":1234 + * + * for i in range(ndim): + * if tmpslice.shape[i] == 1: # <<<<<<<<<<<<<< + * tmpslice.strides[i] = 0 + * + */ + } + } + + /* "View.MemoryView":1237 + * tmpslice.strides[i] = 0 + * + * if slice_is_contig(src[0], order, ndim): # <<<<<<<<<<<<<< + * memcpy(result, src.data, size) + * else: + */ + __pyx_t_2 = __pyx_memviewslice_is_contig((__pyx_v_src[0]), __pyx_v_order, __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1238 + * + * if slice_is_contig(src[0], order, ndim): + * memcpy(result, src.data, size) # <<<<<<<<<<<<<< + * else: + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) + */ + (void)(memcpy(__pyx_v_result, __pyx_v_src->data, __pyx_v_size)); + + /* "View.MemoryView":1237 + * tmpslice.strides[i] = 0 + * + * if slice_is_contig(src[0], order, ndim): # <<<<<<<<<<<<<< + * memcpy(result, src.data, size) + * else: + */ + goto __pyx_L9; + } + + /* "View.MemoryView":1240 + * memcpy(result, src.data, size) + * else: + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) # <<<<<<<<<<<<<< + * + * return result + */ + /*else*/ { + copy_strided_to_strided(__pyx_v_src, __pyx_v_tmpslice, __pyx_v_ndim, __pyx_v_itemsize); + } + __pyx_L9:; + + /* "View.MemoryView":1242 + * copy_strided_to_strided(src, tmpslice, ndim, itemsize) + * + * return result # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "View.MemoryView":1205 + * + * @cname('__pyx_memoryview_copy_data_to_temp') + * cdef void *copy_data_to_temp(__Pyx_memviewslice *src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice *tmpslice, + * char order, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.copy_data_to_temp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1247 + * + * @cname('__pyx_memoryview_err_extents') + * cdef int _err_extents(int i, Py_ssize_t extent1, # <<<<<<<<<<<<<< + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" + */ + +static int __pyx_memoryview_err_extents(int __pyx_v_i, Py_ssize_t __pyx_v_extent1, Py_ssize_t __pyx_v_extent2) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + Py_UCS4 __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err_extents", 0); + + /* "View.MemoryView":1249 + * cdef int _err_extents(int i, Py_ssize_t extent1, + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err_dim') + */ + __pyx_t_1 = PyTuple_New(7); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = 127; + __Pyx_INCREF(__pyx_kp_u_got_differing_extents_in_dimensi); + __pyx_t_2 += 35; + __Pyx_GIVEREF(__pyx_kp_u_got_differing_extents_in_dimensi); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_kp_u_got_differing_extents_in_dimensi); + __pyx_t_4 = __Pyx_PyUnicode_From_int(__pyx_v_i, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u_got); + __pyx_t_2 += 6; + __Pyx_GIVEREF(__pyx_kp_u_got); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_kp_u_got); + __pyx_t_4 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_extent1, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u_and); + __pyx_t_2 += 5; + __Pyx_GIVEREF(__pyx_kp_u_and); + PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_kp_u_and); + __pyx_t_4 = __Pyx_PyUnicode_From_Py_ssize_t(__pyx_v_extent2, 0, ' ', 'd'); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u__7); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__7); + PyTuple_SET_ITEM(__pyx_t_1, 6, __pyx_kp_u__7); + __pyx_t_4 = __Pyx_PyUnicode_Join(__pyx_t_1, 7, __pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 1249, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, __pyx_t_4, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 1249, __pyx_L1_error) + + /* "View.MemoryView":1247 + * + * @cname('__pyx_memoryview_err_extents') + * cdef int _err_extents(int i, Py_ssize_t extent1, # <<<<<<<<<<<<<< + * Py_ssize_t extent2) except -1 with gil: + * raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView._err_extents", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1252 + * + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg % dim + * + */ + +static int __pyx_memoryview_err_dim(PyObject *__pyx_v_error, PyObject *__pyx_v_msg, int __pyx_v_dim) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err_dim", 0); + __Pyx_INCREF(__pyx_v_msg); + + /* "View.MemoryView":1253 + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: + * raise error, msg % dim # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err') + */ + __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_dim); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyString_FormatSafe(__pyx_v_msg, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 1253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(((PyObject *)__pyx_v_error), __pyx_t_2, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(1, 1253, __pyx_L1_error) + + /* "View.MemoryView":1252 + * + * @cname('__pyx_memoryview_err_dim') + * cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg % dim + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("View.MemoryView._err_dim", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_XDECREF(__pyx_v_msg); + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1256 + * + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg + * + */ + +static int __pyx_memoryview_err(PyObject *__pyx_v_error, PyObject *__pyx_v_msg) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_RefNannySetupContext("_err", 0); + __Pyx_INCREF(__pyx_v_msg); + + /* "View.MemoryView":1257 + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: + * raise error, msg # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_err_no_memory') + */ + __Pyx_Raise(((PyObject *)__pyx_v_error), __pyx_v_msg, 0, 0); + __PYX_ERR(1, 1257, __pyx_L1_error) + + /* "View.MemoryView":1256 + * + * @cname('__pyx_memoryview_err') + * cdef int _err(PyObject *error, str msg) except -1 with gil: # <<<<<<<<<<<<<< + * raise error, msg + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._err", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __Pyx_XDECREF(__pyx_v_msg); + __Pyx_RefNannyFinishContext(); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1260 + * + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + +static int __pyx_memoryview_err_no_memory(void) { + int __pyx_r; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + + /* "View.MemoryView":1261 + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: + * raise MemoryError # <<<<<<<<<<<<<< + * + * + */ + PyErr_NoMemory(); __PYX_ERR(1, 1261, __pyx_L1_error) + + /* "View.MemoryView":1260 + * + * @cname('__pyx_memoryview_err_no_memory') + * cdef int _err_no_memory() except -1 with gil: # <<<<<<<<<<<<<< + * raise MemoryError + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("View.MemoryView._err_no_memory", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + return __pyx_r; +} + +/* "View.MemoryView":1265 + * + * @cname('__pyx_memoryview_copy_contents') + * cdef int memoryview_copy_contents(__Pyx_memviewslice src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice dst, + * int src_ndim, int dst_ndim, + */ + +static int __pyx_memoryview_copy_contents(__Pyx_memviewslice __pyx_v_src, __Pyx_memviewslice __pyx_v_dst, int __pyx_v_src_ndim, int __pyx_v_dst_ndim, int __pyx_v_dtype_is_object) { + void *__pyx_v_tmpdata; + size_t __pyx_v_itemsize; + int __pyx_v_i; + char __pyx_v_order; + int __pyx_v_broadcasting; + int __pyx_v_direct_copy; + __Pyx_memviewslice __pyx_v_tmp; + int __pyx_v_ndim; + int __pyx_r; + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + void *__pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save; + #endif + + /* "View.MemoryView":1273 + * Check for overlapping memory and verify the shapes. + * """ + * cdef void *tmpdata = NULL # <<<<<<<<<<<<<< + * cdef size_t itemsize = src.memview.view.itemsize + * cdef int i + */ + __pyx_v_tmpdata = NULL; + + /* "View.MemoryView":1274 + * """ + * cdef void *tmpdata = NULL + * cdef size_t itemsize = src.memview.view.itemsize # <<<<<<<<<<<<<< + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) + */ + __pyx_t_1 = __pyx_v_src.memview->view.itemsize; + __pyx_v_itemsize = __pyx_t_1; + + /* "View.MemoryView":1276 + * cdef size_t itemsize = src.memview.view.itemsize + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) # <<<<<<<<<<<<<< + * cdef bint broadcasting = False + * cdef bint direct_copy = False + */ + __pyx_v_order = __pyx_get_best_slice_order((&__pyx_v_src), __pyx_v_src_ndim); + + /* "View.MemoryView":1277 + * cdef int i + * cdef char order = get_best_order(&src, src_ndim) + * cdef bint broadcasting = False # <<<<<<<<<<<<<< + * cdef bint direct_copy = False + * cdef __Pyx_memviewslice tmp + */ + __pyx_v_broadcasting = 0; + + /* "View.MemoryView":1278 + * cdef char order = get_best_order(&src, src_ndim) + * cdef bint broadcasting = False + * cdef bint direct_copy = False # <<<<<<<<<<<<<< + * cdef __Pyx_memviewslice tmp + * + */ + __pyx_v_direct_copy = 0; + + /* "View.MemoryView":1281 + * cdef __Pyx_memviewslice tmp + * + * if src_ndim < dst_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + */ + __pyx_t_2 = (__pyx_v_src_ndim < __pyx_v_dst_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1282 + * + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) # <<<<<<<<<<<<<< + * elif dst_ndim < src_ndim: + * broadcast_leading(&dst, dst_ndim, src_ndim) + */ + __pyx_memoryview_broadcast_leading((&__pyx_v_src), __pyx_v_src_ndim, __pyx_v_dst_ndim); + + /* "View.MemoryView":1281 + * cdef __Pyx_memviewslice tmp + * + * if src_ndim < dst_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1283 + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + */ + __pyx_t_2 = (__pyx_v_dst_ndim < __pyx_v_src_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1284 + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: + * broadcast_leading(&dst, dst_ndim, src_ndim) # <<<<<<<<<<<<<< + * + * cdef int ndim = max(src_ndim, dst_ndim) + */ + __pyx_memoryview_broadcast_leading((&__pyx_v_dst), __pyx_v_dst_ndim, __pyx_v_src_ndim); + + /* "View.MemoryView":1283 + * if src_ndim < dst_ndim: + * broadcast_leading(&src, src_ndim, dst_ndim) + * elif dst_ndim < src_ndim: # <<<<<<<<<<<<<< + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + */ + } + __pyx_L3:; + + /* "View.MemoryView":1286 + * broadcast_leading(&dst, dst_ndim, src_ndim) + * + * cdef int ndim = max(src_ndim, dst_ndim) # <<<<<<<<<<<<<< + * + * for i in range(ndim): + */ + __pyx_t_3 = __pyx_v_dst_ndim; + __pyx_t_4 = __pyx_v_src_ndim; + __pyx_t_2 = (__pyx_t_3 > __pyx_t_4); + if (__pyx_t_2) { + __pyx_t_5 = __pyx_t_3; + } else { + __pyx_t_5 = __pyx_t_4; + } + __pyx_v_ndim = __pyx_t_5; + + /* "View.MemoryView":1288 + * cdef int ndim = max(src_ndim, dst_ndim) + * + * for i in range(ndim): # <<<<<<<<<<<<<< + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: + */ + __pyx_t_5 = __pyx_v_ndim; + __pyx_t_3 = __pyx_t_5; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1289 + * + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: # <<<<<<<<<<<<<< + * if src.shape[i] == 1: + * broadcasting = True + */ + __pyx_t_2 = ((__pyx_v_src.shape[__pyx_v_i]) != (__pyx_v_dst.shape[__pyx_v_i])); + if (__pyx_t_2) { + + /* "View.MemoryView":1290 + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: # <<<<<<<<<<<<<< + * broadcasting = True + * src.strides[i] = 0 + */ + __pyx_t_2 = ((__pyx_v_src.shape[__pyx_v_i]) == 1); + if (__pyx_t_2) { + + /* "View.MemoryView":1291 + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: + * broadcasting = True # <<<<<<<<<<<<<< + * src.strides[i] = 0 + * else: + */ + __pyx_v_broadcasting = 1; + + /* "View.MemoryView":1292 + * if src.shape[i] == 1: + * broadcasting = True + * src.strides[i] = 0 # <<<<<<<<<<<<<< + * else: + * _err_extents(i, dst.shape[i], src.shape[i]) + */ + (__pyx_v_src.strides[__pyx_v_i]) = 0; + + /* "View.MemoryView":1290 + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: + * if src.shape[i] == 1: # <<<<<<<<<<<<<< + * broadcasting = True + * src.strides[i] = 0 + */ + goto __pyx_L7; + } + + /* "View.MemoryView":1294 + * src.strides[i] = 0 + * else: + * _err_extents(i, dst.shape[i], src.shape[i]) # <<<<<<<<<<<<<< + * + * if src.suboffsets[i] >= 0: + */ + /*else*/ { + __pyx_t_6 = __pyx_memoryview_err_extents(__pyx_v_i, (__pyx_v_dst.shape[__pyx_v_i]), (__pyx_v_src.shape[__pyx_v_i])); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(1, 1294, __pyx_L1_error) + } + __pyx_L7:; + + /* "View.MemoryView":1289 + * + * for i in range(ndim): + * if src.shape[i] != dst.shape[i]: # <<<<<<<<<<<<<< + * if src.shape[i] == 1: + * broadcasting = True + */ + } + + /* "View.MemoryView":1296 + * _err_extents(i, dst.shape[i], src.shape[i]) + * + * if src.suboffsets[i] >= 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + */ + __pyx_t_2 = ((__pyx_v_src.suboffsets[__pyx_v_i]) >= 0); + if (__pyx_t_2) { + + /* "View.MemoryView":1297 + * + * if src.suboffsets[i] >= 0: + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) # <<<<<<<<<<<<<< + * + * if slices_overlap(&src, &dst, ndim, itemsize): + */ + __pyx_t_6 = __pyx_memoryview_err_dim(PyExc_ValueError, __pyx_kp_s_Dimension_d_is_not_direct, __pyx_v_i); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(1, 1297, __pyx_L1_error) + + /* "View.MemoryView":1296 + * _err_extents(i, dst.shape[i], src.shape[i]) + * + * if src.suboffsets[i] >= 0: # <<<<<<<<<<<<<< + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + */ + } + } + + /* "View.MemoryView":1299 + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + * if slices_overlap(&src, &dst, ndim, itemsize): # <<<<<<<<<<<<<< + * + * if not slice_is_contig(src, order, ndim): + */ + __pyx_t_2 = __pyx_slices_overlap((&__pyx_v_src), (&__pyx_v_dst), __pyx_v_ndim, __pyx_v_itemsize); + if (__pyx_t_2) { + + /* "View.MemoryView":1301 + * if slices_overlap(&src, &dst, ndim, itemsize): + * + * if not slice_is_contig(src, order, ndim): # <<<<<<<<<<<<<< + * order = get_best_order(&dst, ndim) + * + */ + __pyx_t_2 = (!__pyx_memviewslice_is_contig(__pyx_v_src, __pyx_v_order, __pyx_v_ndim)); + if (__pyx_t_2) { + + /* "View.MemoryView":1302 + * + * if not slice_is_contig(src, order, ndim): + * order = get_best_order(&dst, ndim) # <<<<<<<<<<<<<< + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) + */ + __pyx_v_order = __pyx_get_best_slice_order((&__pyx_v_dst), __pyx_v_ndim); + + /* "View.MemoryView":1301 + * if slices_overlap(&src, &dst, ndim, itemsize): + * + * if not slice_is_contig(src, order, ndim): # <<<<<<<<<<<<<< + * order = get_best_order(&dst, ndim) + * + */ + } + + /* "View.MemoryView":1304 + * order = get_best_order(&dst, ndim) + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) # <<<<<<<<<<<<<< + * src = tmp + * + */ + __pyx_t_7 = __pyx_memoryview_copy_data_to_temp((&__pyx_v_src), (&__pyx_v_tmp), __pyx_v_order, __pyx_v_ndim); if (unlikely(__pyx_t_7 == ((void *)NULL))) __PYX_ERR(1, 1304, __pyx_L1_error) + __pyx_v_tmpdata = __pyx_t_7; + + /* "View.MemoryView":1305 + * + * tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) + * src = tmp # <<<<<<<<<<<<<< + * + * if not broadcasting: + */ + __pyx_v_src = __pyx_v_tmp; + + /* "View.MemoryView":1299 + * _err_dim(PyExc_ValueError, "Dimension %d is not direct", i) + * + * if slices_overlap(&src, &dst, ndim, itemsize): # <<<<<<<<<<<<<< + * + * if not slice_is_contig(src, order, ndim): + */ + } + + /* "View.MemoryView":1307 + * src = tmp + * + * if not broadcasting: # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (!__pyx_v_broadcasting); + if (__pyx_t_2) { + + /* "View.MemoryView":1310 + * + * + * if slice_is_contig(src, 'C', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + */ + __pyx_t_2 = __pyx_memviewslice_is_contig(__pyx_v_src, 'C', __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1311 + * + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) # <<<<<<<<<<<<<< + * elif slice_is_contig(src, 'F', ndim): + * direct_copy = slice_is_contig(dst, 'F', ndim) + */ + __pyx_v_direct_copy = __pyx_memviewslice_is_contig(__pyx_v_dst, 'C', __pyx_v_ndim); + + /* "View.MemoryView":1310 + * + * + * if slice_is_contig(src, 'C', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + */ + goto __pyx_L12; + } + + /* "View.MemoryView":1312 + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + */ + __pyx_t_2 = __pyx_memviewslice_is_contig(__pyx_v_src, 'F', __pyx_v_ndim); + if (__pyx_t_2) { + + /* "View.MemoryView":1313 + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): + * direct_copy = slice_is_contig(dst, 'F', ndim) # <<<<<<<<<<<<<< + * + * if direct_copy: + */ + __pyx_v_direct_copy = __pyx_memviewslice_is_contig(__pyx_v_dst, 'F', __pyx_v_ndim); + + /* "View.MemoryView":1312 + * if slice_is_contig(src, 'C', ndim): + * direct_copy = slice_is_contig(dst, 'C', ndim) + * elif slice_is_contig(src, 'F', ndim): # <<<<<<<<<<<<<< + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + */ + } + __pyx_L12:; + + /* "View.MemoryView":1315 + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + * if direct_copy: # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + if (__pyx_v_direct_copy) { + + /* "View.MemoryView":1317 + * if direct_copy: + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1318 + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) # <<<<<<<<<<<<<< + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) + */ + (void)(memcpy(__pyx_v_dst.data, __pyx_v_src.data, __pyx_memoryview_slice_get_size((&__pyx_v_src), __pyx_v_ndim))); + + /* "View.MemoryView":1319 + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * free(tmpdata) + * return 0 + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1320 + * memcpy(dst.data, src.data, slice_get_size(&src, ndim)) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) # <<<<<<<<<<<<<< + * return 0 + * + */ + free(__pyx_v_tmpdata); + + /* "View.MemoryView":1321 + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * free(tmpdata) + * return 0 # <<<<<<<<<<<<<< + * + * if order == 'F' == get_best_order(&dst, ndim): + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":1315 + * direct_copy = slice_is_contig(dst, 'F', ndim) + * + * if direct_copy: # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + } + + /* "View.MemoryView":1307 + * src = tmp + * + * if not broadcasting: # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":1323 + * return 0 + * + * if order == 'F' == get_best_order(&dst, ndim): # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (__pyx_v_order == 'F'); + if (__pyx_t_2) { + __pyx_t_2 = ('F' == __pyx_get_best_slice_order((&__pyx_v_dst), __pyx_v_ndim)); + } + if (__pyx_t_2) { + + /* "View.MemoryView":1326 + * + * + * transpose_memslice(&src) # <<<<<<<<<<<<<< + * transpose_memslice(&dst) + * + */ + __pyx_t_5 = __pyx_memslice_transpose((&__pyx_v_src)); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 1326, __pyx_L1_error) + + /* "View.MemoryView":1327 + * + * transpose_memslice(&src) + * transpose_memslice(&dst) # <<<<<<<<<<<<<< + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + */ + __pyx_t_5 = __pyx_memslice_transpose((&__pyx_v_dst)); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 1327, __pyx_L1_error) + + /* "View.MemoryView":1323 + * return 0 + * + * if order == 'F' == get_best_order(&dst, ndim): # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":1329 + * transpose_memslice(&dst) + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * copy_strided_to_strided(&src, &dst, ndim, itemsize) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1330 + * + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * copy_strided_to_strided(&src, &dst, ndim, itemsize) # <<<<<<<<<<<<<< + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * + */ + copy_strided_to_strided((&__pyx_v_src), (&__pyx_v_dst), __pyx_v_ndim, __pyx_v_itemsize); + + /* "View.MemoryView":1331 + * refcount_copying(&dst, dtype_is_object, ndim, inc=False) + * copy_strided_to_strided(&src, &dst, ndim, itemsize) + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * + * free(tmpdata) + */ + __pyx_memoryview_refcount_copying((&__pyx_v_dst), __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1333 + * refcount_copying(&dst, dtype_is_object, ndim, inc=True) + * + * free(tmpdata) # <<<<<<<<<<<<<< + * return 0 + * + */ + free(__pyx_v_tmpdata); + + /* "View.MemoryView":1334 + * + * free(tmpdata) + * return 0 # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_broadcast_leading') + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "View.MemoryView":1265 + * + * @cname('__pyx_memoryview_copy_contents') + * cdef int memoryview_copy_contents(__Pyx_memviewslice src, # <<<<<<<<<<<<<< + * __Pyx_memviewslice dst, + * int src_ndim, int dst_ndim, + */ + + /* function exit code */ + __pyx_L1_error:; + #ifdef WITH_THREAD + __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + __Pyx_AddTraceback("View.MemoryView.memoryview_copy_contents", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __pyx_L0:; + return __pyx_r; +} + +/* "View.MemoryView":1337 + * + * @cname('__pyx_memoryview_broadcast_leading') + * cdef void broadcast_leading(__Pyx_memviewslice *mslice, # <<<<<<<<<<<<<< + * int ndim, + * int ndim_other) noexcept nogil: + */ + +static void __pyx_memoryview_broadcast_leading(__Pyx_memviewslice *__pyx_v_mslice, int __pyx_v_ndim, int __pyx_v_ndim_other) { + int __pyx_v_i; + int __pyx_v_offset; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + + /* "View.MemoryView":1341 + * int ndim_other) noexcept nogil: + * cdef int i + * cdef int offset = ndim_other - ndim # <<<<<<<<<<<<<< + * + * for i in range(ndim - 1, -1, -1): + */ + __pyx_v_offset = (__pyx_v_ndim_other - __pyx_v_ndim); + + /* "View.MemoryView":1343 + * cdef int offset = ndim_other - ndim + * + * for i in range(ndim - 1, -1, -1): # <<<<<<<<<<<<<< + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] + */ + for (__pyx_t_1 = (__pyx_v_ndim - 1); __pyx_t_1 > -1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "View.MemoryView":1344 + * + * for i in range(ndim - 1, -1, -1): + * mslice.shape[i + offset] = mslice.shape[i] # <<<<<<<<<<<<<< + * mslice.strides[i + offset] = mslice.strides[i] + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + */ + (__pyx_v_mslice->shape[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->shape[__pyx_v_i]); + + /* "View.MemoryView":1345 + * for i in range(ndim - 1, -1, -1): + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] # <<<<<<<<<<<<<< + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + * + */ + (__pyx_v_mslice->strides[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->strides[__pyx_v_i]); + + /* "View.MemoryView":1346 + * mslice.shape[i + offset] = mslice.shape[i] + * mslice.strides[i + offset] = mslice.strides[i] + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] # <<<<<<<<<<<<<< + * + * for i in range(offset): + */ + (__pyx_v_mslice->suboffsets[(__pyx_v_i + __pyx_v_offset)]) = (__pyx_v_mslice->suboffsets[__pyx_v_i]); + } + + /* "View.MemoryView":1348 + * mslice.suboffsets[i + offset] = mslice.suboffsets[i] + * + * for i in range(offset): # <<<<<<<<<<<<<< + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] + */ + __pyx_t_1 = __pyx_v_offset; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "View.MemoryView":1349 + * + * for i in range(offset): + * mslice.shape[i] = 1 # <<<<<<<<<<<<<< + * mslice.strides[i] = mslice.strides[0] + * mslice.suboffsets[i] = -1 + */ + (__pyx_v_mslice->shape[__pyx_v_i]) = 1; + + /* "View.MemoryView":1350 + * for i in range(offset): + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] # <<<<<<<<<<<<<< + * mslice.suboffsets[i] = -1 + * + */ + (__pyx_v_mslice->strides[__pyx_v_i]) = (__pyx_v_mslice->strides[0]); + + /* "View.MemoryView":1351 + * mslice.shape[i] = 1 + * mslice.strides[i] = mslice.strides[0] + * mslice.suboffsets[i] = -1 # <<<<<<<<<<<<<< + * + * + */ + (__pyx_v_mslice->suboffsets[__pyx_v_i]) = -1L; + } + + /* "View.MemoryView":1337 + * + * @cname('__pyx_memoryview_broadcast_leading') + * cdef void broadcast_leading(__Pyx_memviewslice *mslice, # <<<<<<<<<<<<<< + * int ndim, + * int ndim_other) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1359 + * + * @cname('__pyx_memoryview_refcount_copying') + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: # <<<<<<<<<<<<<< + * + * if dtype_is_object: + */ + +static void __pyx_memoryview_refcount_copying(__Pyx_memviewslice *__pyx_v_dst, int __pyx_v_dtype_is_object, int __pyx_v_ndim, int __pyx_v_inc) { + + /* "View.MemoryView":1361 + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: + * + * if dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) + * + */ + if (__pyx_v_dtype_is_object) { + + /* "View.MemoryView":1362 + * + * if dtype_is_object: + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + */ + __pyx_memoryview_refcount_objects_in_slice_with_gil(__pyx_v_dst->data, __pyx_v_dst->shape, __pyx_v_dst->strides, __pyx_v_ndim, __pyx_v_inc); + + /* "View.MemoryView":1361 + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: + * + * if dtype_is_object: # <<<<<<<<<<<<<< + * refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) + * + */ + } + + /* "View.MemoryView":1359 + * + * @cname('__pyx_memoryview_refcount_copying') + * cdef void refcount_copying(__Pyx_memviewslice *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil: # <<<<<<<<<<<<<< + * + * if dtype_is_object: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1365 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + * cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + */ + +static void __pyx_memoryview_refcount_objects_in_slice_with_gil(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, int __pyx_v_inc) { + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + + /* "View.MemoryView":1368 + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + * refcount_objects_in_slice(data, shape, strides, ndim, inc) # <<<<<<<<<<<<<< + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + */ + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_data, __pyx_v_shape, __pyx_v_strides, __pyx_v_ndim, __pyx_v_inc); + + /* "View.MemoryView":1365 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') + * cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * bint inc) noexcept with gil: + */ + + /* function exit code */ + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif +} + +/* "View.MemoryView":1371 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + * cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + */ + +static void __pyx_memoryview_refcount_objects_in_slice(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, int __pyx_v_inc) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + + /* "View.MemoryView":1374 + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] # <<<<<<<<<<<<<< + * + * for i in range(shape[0]): + */ + __pyx_v_stride = (__pyx_v_strides[0]); + + /* "View.MemoryView":1376 + * cdef Py_ssize_t stride = strides[0] + * + * for i in range(shape[0]): # <<<<<<<<<<<<<< + * if ndim == 1: + * if inc: + */ + __pyx_t_1 = (__pyx_v_shape[0]); + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "View.MemoryView":1377 + * + * for i in range(shape[0]): + * if ndim == 1: # <<<<<<<<<<<<<< + * if inc: + * Py_INCREF(( data)[0]) + */ + __pyx_t_4 = (__pyx_v_ndim == 1); + if (__pyx_t_4) { + + /* "View.MemoryView":1378 + * for i in range(shape[0]): + * if ndim == 1: + * if inc: # <<<<<<<<<<<<<< + * Py_INCREF(( data)[0]) + * else: + */ + if (__pyx_v_inc) { + + /* "View.MemoryView":1379 + * if ndim == 1: + * if inc: + * Py_INCREF(( data)[0]) # <<<<<<<<<<<<<< + * else: + * Py_DECREF(( data)[0]) + */ + Py_INCREF((((PyObject **)__pyx_v_data)[0])); + + /* "View.MemoryView":1378 + * for i in range(shape[0]): + * if ndim == 1: + * if inc: # <<<<<<<<<<<<<< + * Py_INCREF(( data)[0]) + * else: + */ + goto __pyx_L6; + } + + /* "View.MemoryView":1381 + * Py_INCREF(( data)[0]) + * else: + * Py_DECREF(( data)[0]) # <<<<<<<<<<<<<< + * else: + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) + */ + /*else*/ { + Py_DECREF((((PyObject **)__pyx_v_data)[0])); + } + __pyx_L6:; + + /* "View.MemoryView":1377 + * + * for i in range(shape[0]): + * if ndim == 1: # <<<<<<<<<<<<<< + * if inc: + * Py_INCREF(( data)[0]) + */ + goto __pyx_L5; + } + + /* "View.MemoryView":1383 + * Py_DECREF(( data)[0]) + * else: + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) # <<<<<<<<<<<<<< + * + * data += stride + */ + /*else*/ { + __pyx_memoryview_refcount_objects_in_slice(__pyx_v_data, (__pyx_v_shape + 1), (__pyx_v_strides + 1), (__pyx_v_ndim - 1), __pyx_v_inc); + } + __pyx_L5:; + + /* "View.MemoryView":1385 + * refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) + * + * data += stride # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + + /* "View.MemoryView":1371 + * + * @cname('__pyx_memoryview_refcount_objects_in_slice') + * cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, bint inc) noexcept: + * cdef Py_ssize_t i + */ + + /* function exit code */ +} + +/* "View.MemoryView":1391 + * + * @cname('__pyx_memoryview_slice_assign_scalar') + * cdef void slice_assign_scalar(__Pyx_memviewslice *dst, int ndim, # <<<<<<<<<<<<<< + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + */ + +static void __pyx_memoryview_slice_assign_scalar(__Pyx_memviewslice *__pyx_v_dst, int __pyx_v_ndim, size_t __pyx_v_itemsize, void *__pyx_v_item, int __pyx_v_dtype_is_object) { + + /* "View.MemoryView":1394 + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + * refcount_copying(dst, dtype_is_object, ndim, inc=False) # <<<<<<<<<<<<<< + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) + * refcount_copying(dst, dtype_is_object, ndim, inc=True) + */ + __pyx_memoryview_refcount_copying(__pyx_v_dst, __pyx_v_dtype_is_object, __pyx_v_ndim, 0); + + /* "View.MemoryView":1395 + * bint dtype_is_object) noexcept nogil: + * refcount_copying(dst, dtype_is_object, ndim, inc=False) + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) # <<<<<<<<<<<<<< + * refcount_copying(dst, dtype_is_object, ndim, inc=True) + * + */ + __pyx_memoryview__slice_assign_scalar(__pyx_v_dst->data, __pyx_v_dst->shape, __pyx_v_dst->strides, __pyx_v_ndim, __pyx_v_itemsize, __pyx_v_item); + + /* "View.MemoryView":1396 + * refcount_copying(dst, dtype_is_object, ndim, inc=False) + * _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) + * refcount_copying(dst, dtype_is_object, ndim, inc=True) # <<<<<<<<<<<<<< + * + * + */ + __pyx_memoryview_refcount_copying(__pyx_v_dst, __pyx_v_dtype_is_object, __pyx_v_ndim, 1); + + /* "View.MemoryView":1391 + * + * @cname('__pyx_memoryview_slice_assign_scalar') + * cdef void slice_assign_scalar(__Pyx_memviewslice *dst, int ndim, # <<<<<<<<<<<<<< + * size_t itemsize, void *item, + * bint dtype_is_object) noexcept nogil: + */ + + /* function exit code */ +} + +/* "View.MemoryView":1400 + * + * @cname('__pyx_memoryview__slice_assign_scalar') + * cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * size_t itemsize, void *item) noexcept nogil: + */ + +static void __pyx_memoryview__slice_assign_scalar(char *__pyx_v_data, Py_ssize_t *__pyx_v_shape, Py_ssize_t *__pyx_v_strides, int __pyx_v_ndim, size_t __pyx_v_itemsize, void *__pyx_v_item) { + CYTHON_UNUSED Py_ssize_t __pyx_v_i; + Py_ssize_t __pyx_v_stride; + Py_ssize_t __pyx_v_extent; + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + Py_ssize_t __pyx_t_3; + Py_ssize_t __pyx_t_4; + + /* "View.MemoryView":1404 + * size_t itemsize, void *item) noexcept nogil: + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] # <<<<<<<<<<<<<< + * cdef Py_ssize_t extent = shape[0] + * + */ + __pyx_v_stride = (__pyx_v_strides[0]); + + /* "View.MemoryView":1405 + * cdef Py_ssize_t i + * cdef Py_ssize_t stride = strides[0] + * cdef Py_ssize_t extent = shape[0] # <<<<<<<<<<<<<< + * + * if ndim == 1: + */ + __pyx_v_extent = (__pyx_v_shape[0]); + + /* "View.MemoryView":1407 + * cdef Py_ssize_t extent = shape[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * for i in range(extent): + * memcpy(data, item, itemsize) + */ + __pyx_t_1 = (__pyx_v_ndim == 1); + if (__pyx_t_1) { + + /* "View.MemoryView":1408 + * + * if ndim == 1: + * for i in range(extent): # <<<<<<<<<<<<<< + * memcpy(data, item, itemsize) + * data += stride + */ + __pyx_t_2 = __pyx_v_extent; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1409 + * if ndim == 1: + * for i in range(extent): + * memcpy(data, item, itemsize) # <<<<<<<<<<<<<< + * data += stride + * else: + */ + (void)(memcpy(__pyx_v_data, __pyx_v_item, __pyx_v_itemsize)); + + /* "View.MemoryView":1410 + * for i in range(extent): + * memcpy(data, item, itemsize) + * data += stride # <<<<<<<<<<<<<< + * else: + * for i in range(extent): + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + + /* "View.MemoryView":1407 + * cdef Py_ssize_t extent = shape[0] + * + * if ndim == 1: # <<<<<<<<<<<<<< + * for i in range(extent): + * memcpy(data, item, itemsize) + */ + goto __pyx_L3; + } + + /* "View.MemoryView":1412 + * data += stride + * else: + * for i in range(extent): # <<<<<<<<<<<<<< + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) + * data += stride + */ + /*else*/ { + __pyx_t_2 = __pyx_v_extent; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_3; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "View.MemoryView":1413 + * else: + * for i in range(extent): + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) # <<<<<<<<<<<<<< + * data += stride + * + */ + __pyx_memoryview__slice_assign_scalar(__pyx_v_data, (__pyx_v_shape + 1), (__pyx_v_strides + 1), (__pyx_v_ndim - 1), __pyx_v_itemsize, __pyx_v_item); + + /* "View.MemoryView":1414 + * for i in range(extent): + * _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) + * data += stride # <<<<<<<<<<<<<< + * + * + */ + __pyx_v_data = (__pyx_v_data + __pyx_v_stride); + } + } + __pyx_L3:; + + /* "View.MemoryView":1400 + * + * @cname('__pyx_memoryview__slice_assign_scalar') + * cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, # <<<<<<<<<<<<<< + * Py_ssize_t *strides, int ndim, + * size_t itemsize, void *item) noexcept nogil: + */ + + /* function exit code */ +} + +/* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_15View_dot_MemoryView_1__pyx_unpickle_Enum = {"__pyx_unpickle_Enum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_15View_dot_MemoryView_1__pyx_unpickle_Enum(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v___pyx_type = 0; + long __pyx_v___pyx_checksum; + PyObject *__pyx_v___pyx_state = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_type)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_checksum)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_pyx_state)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__pyx_unpickle_Enum") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v___pyx_type = values[0]; + __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_v___pyx_state = values[2]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle_Enum", 1, 3, 3, __pyx_nargs); __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_v___pyx_PickleError = 0; + PyObject *__pyx_v___pyx_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum", 1); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__8, Py_NE)); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_2) { + + /* "(tree fragment)":5 + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): + * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_PickleError); + __Pyx_GIVEREF(__pyx_n_s_PickleError); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError)) __PYX_ERR(1, 5, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __pyx_v___pyx_PickleError = __pyx_t_1; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "(tree fragment)":6 + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum # <<<<<<<<<<<<<< + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: + */ + __pyx_t_3 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_v___pyx_PickleError, __pyx_t_1, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 6, __pyx_L1_error) + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + } + + /* "(tree fragment)":7 + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) # <<<<<<<<<<<<<< + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_MemviewEnum_type), __pyx_n_s_new); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v___pyx_type}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_v___pyx_result = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + */ + __pyx_t_2 = (__pyx_v___pyx_state != Py_None); + if (__pyx_t_2) { + + /* "(tree fragment)":9 + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) # <<<<<<<<<<<<<< + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None) || __Pyx_RaiseUnexpectedTypeError("tuple", __pyx_v___pyx_state))) __PYX_ERR(1, 9, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle_Enum__set_state(((struct __pyx_MemviewEnum_obj *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + * __pyx_result = Enum.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + */ + } + + /* "(tree fragment)":10 + * if __pyx_state is not None: + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result # <<<<<<<<<<<<<< + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v___pyx_result); + __pyx_r = __pyx_v___pyx_result; + goto __pyx_L0; + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v___pyx_PickleError); + __Pyx_XDECREF(__pyx_v___pyx_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":11 + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + */ + +static PyObject *__pyx_unpickle_Enum__set_state(struct __pyx_MemviewEnum_obj *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + Py_ssize_t __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + unsigned int __pyx_t_8; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle_Enum__set_state", 1); + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] # <<<<<<<<<<<<<< + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 12, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v___pyx_result->name); + __Pyx_DECREF(__pyx_v___pyx_result->name); + __pyx_v___pyx_result->name = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":13 + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 13, __pyx_L1_error) + } + __pyx_t_3 = __Pyx_PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(1, 13, __pyx_L1_error) + __pyx_t_4 = (__pyx_t_3 > 1); + if (__pyx_t_4) { + } else { + __pyx_t_2 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 13, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (__pyx_t_2) { + + /* "(tree fragment)":14 + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[1]) # <<<<<<<<<<<<<< + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_update); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 14, __pyx_L1_error) + } + __pyx_t_5 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_8 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+1-__pyx_t_8, 1+__pyx_t_8); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 14, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":13 + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[1]) + */ + } + + /* "(tree fragment)":11 + * __pyx_unpickle_Enum__set_state( __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle_Enum__set_state(Enum __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * __pyx_result.name = __pyx_state[0] + * if len(__pyx_state) > 1 and hasattr(__pyx_result, '__dict__'): + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("View.MemoryView.__pyx_unpickle_Enum__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":19 + * + * + * def has_clockwise_orientation(vertices: np.ndarray) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_1has_clockwise_orientation(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_5ezdxf_3acc_10np_support_has_clockwise_orientation, " Returns True if 2D `vertices` have clockwise orientation. Ignores\n z-axis of all vertices.\n\n Args:\n vertices: numpy array\n\n Raises:\n ValueError: less than 3 vertices\n\n "); +static PyMethodDef __pyx_mdef_5ezdxf_3acc_10np_support_1has_clockwise_orientation = {"has_clockwise_orientation", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_10np_support_1has_clockwise_orientation, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5ezdxf_3acc_10np_support_has_clockwise_orientation}; +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_1has_clockwise_orientation(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_vertices = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("has_clockwise_orientation (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_vertices,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_vertices)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 19, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "has_clockwise_orientation") < 0)) __PYX_ERR(0, 19, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_vertices = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("has_clockwise_orientation", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 19, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.np_support.has_clockwise_orientation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_10np_support_has_clockwise_orientation(__pyx_self, __pyx_v_vertices); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_has_clockwise_orientation(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_vertices) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + __Pyx_memviewslice __pyx_t_4 = { 0, 0, { 0 }, { 0 }, { 0 } }; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("has_clockwise_orientation", 1); + + /* "ezdxf/acc/np_support.pyx":30 + * + * """ + * if len(vertices) < 3: # <<<<<<<<<<<<<< + * raise ValueError('At least 3 vertices required.') + * + */ + __pyx_t_1 = PyObject_Length(__pyx_v_vertices); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 30, __pyx_L1_error) + __pyx_t_2 = (__pyx_t_1 < 3); + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/np_support.pyx":31 + * """ + * if len(vertices) < 3: + * raise ValueError('At least 3 vertices required.') # <<<<<<<<<<<<<< + * + * return _has_clockwise_orientation(vertices, vertices.shape[0]) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 31, __pyx_L1_error) + + /* "ezdxf/acc/np_support.pyx":30 + * + * """ + * if len(vertices) < 3: # <<<<<<<<<<<<<< + * raise ValueError('At least 3 vertices required.') + * + */ + } + + /* "ezdxf/acc/np_support.pyx":33 + * raise ValueError('At least 3 vertices required.') + * + * return _has_clockwise_orientation(vertices, vertices.shape[0]) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_vertices, PyBUF_WRITABLE); if (unlikely(!__pyx_t_4.memview)) __PYX_ERR(0, 33, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_vertices, __pyx_n_s_shape); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyIndex_AsSsize_t(__pyx_t_5); if (unlikely((__pyx_t_1 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_2 = __pyx_f_5ezdxf_3acc_10np_support__has_clockwise_orientation(__pyx_t_4, __pyx_t_1); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 33, __pyx_L1_error) + __PYX_XCLEAR_MEMVIEW(&__pyx_t_4, 1); + __pyx_t_4.memview = NULL; __pyx_t_4.data = NULL; + __pyx_t_5 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/np_support.pyx":19 + * + * + * def has_clockwise_orientation(vertices: np.ndarray) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_4, 1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.np_support.has_clockwise_orientation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":38 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef bint _has_clockwise_orientation(double [:, ::1] vertices, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef Py_ssize_t index + * cdef Py_ssize_t start + */ + +static int __pyx_f_5ezdxf_3acc_10np_support__has_clockwise_orientation(__Pyx_memviewslice __pyx_v_vertices, Py_ssize_t __pyx_v_size) { + Py_ssize_t __pyx_v_index; + Py_ssize_t __pyx_v_start; + Py_ssize_t __pyx_v_last; + double __pyx_v_s; + double __pyx_v_p1x; + double __pyx_v_p1y; + double __pyx_v_p2x; + double __pyx_v_p2y; + int __pyx_v_x_is_close; + int __pyx_v_y_is_close; + int __pyx_r; + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + int __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + Py_ssize_t __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "ezdxf/acc/np_support.pyx":41 + * cdef Py_ssize_t index + * cdef Py_ssize_t start + * cdef Py_ssize_t last = size - 1 # <<<<<<<<<<<<<< + * cdef double s = 0.0 + * cdef double p1x = vertices[0][0] + */ + __pyx_v_last = (__pyx_v_size - 1); + + /* "ezdxf/acc/np_support.pyx":42 + * cdef Py_ssize_t start + * cdef Py_ssize_t last = size - 1 + * cdef double s = 0.0 # <<<<<<<<<<<<<< + * cdef double p1x = vertices[0][0] + * cdef double p1y = vertices[0][1] + */ + __pyx_v_s = 0.0; + + /* "ezdxf/acc/np_support.pyx":43 + * cdef Py_ssize_t last = size - 1 + * cdef double s = 0.0 + * cdef double p1x = vertices[0][0] # <<<<<<<<<<<<<< + * cdef double p1y = vertices[0][1] + * cdef double p2x = vertices[last][0] + */ + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_v_p1x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_1 * __pyx_v_vertices.strides[0]) )) + __pyx_t_2)) ))); + + /* "ezdxf/acc/np_support.pyx":44 + * cdef double s = 0.0 + * cdef double p1x = vertices[0][0] + * cdef double p1y = vertices[0][1] # <<<<<<<<<<<<<< + * cdef double p2x = vertices[last][0] + * cdef double p2y = vertices[last][1] + */ + __pyx_t_2 = 0; + __pyx_t_1 = 1; + __pyx_v_p1y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_2 * __pyx_v_vertices.strides[0]) )) + __pyx_t_1)) ))); + + /* "ezdxf/acc/np_support.pyx":45 + * cdef double p1x = vertices[0][0] + * cdef double p1y = vertices[0][1] + * cdef double p2x = vertices[last][0] # <<<<<<<<<<<<<< + * cdef double p2y = vertices[last][1] + * + */ + __pyx_t_1 = __pyx_v_last; + __pyx_t_2 = 0; + __pyx_v_p2x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_1 * __pyx_v_vertices.strides[0]) )) + __pyx_t_2)) ))); + + /* "ezdxf/acc/np_support.pyx":46 + * cdef double p1y = vertices[0][1] + * cdef double p2x = vertices[last][0] + * cdef double p2y = vertices[last][1] # <<<<<<<<<<<<<< + * + * # Using the same tolerance as the Python implementation: + */ + __pyx_t_2 = __pyx_v_last; + __pyx_t_1 = 1; + __pyx_v_p2y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_2 * __pyx_v_vertices.strides[0]) )) + __pyx_t_1)) ))); + + /* "ezdxf/acc/np_support.pyx":49 + * + * # Using the same tolerance as the Python implementation: + * cdef bint x_is_close = isclose(p1x, p2x, REL_TOL, ABS_TOL) # <<<<<<<<<<<<<< + * cdef bint y_is_close = isclose(p1y, p2y, REL_TOL, ABS_TOL) + * + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_p1x, __pyx_v_p2x, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 49, __pyx_L1_error) + __pyx_v_x_is_close = __pyx_t_3; + + /* "ezdxf/acc/np_support.pyx":50 + * # Using the same tolerance as the Python implementation: + * cdef bint x_is_close = isclose(p1x, p2x, REL_TOL, ABS_TOL) + * cdef bint y_is_close = isclose(p1y, p2y, REL_TOL, ABS_TOL) # <<<<<<<<<<<<<< + * + * if x_is_close and y_is_close: + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_p1y, __pyx_v_p2y, REL_TOL, ABS_TOL); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_v_y_is_close = __pyx_t_3; + + /* "ezdxf/acc/np_support.pyx":52 + * cdef bint y_is_close = isclose(p1y, p2y, REL_TOL, ABS_TOL) + * + * if x_is_close and y_is_close: # <<<<<<<<<<<<<< + * p1x = vertices[0][0] + * p1y = vertices[0][1] + */ + if (__pyx_v_x_is_close) { + } else { + __pyx_t_3 = __pyx_v_x_is_close; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __pyx_v_y_is_close; + __pyx_L4_bool_binop_done:; + if (__pyx_t_3) { + + /* "ezdxf/acc/np_support.pyx":53 + * + * if x_is_close and y_is_close: + * p1x = vertices[0][0] # <<<<<<<<<<<<<< + * p1y = vertices[0][1] + * start = 1 + */ + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_v_p1x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_1 * __pyx_v_vertices.strides[0]) )) + __pyx_t_2)) ))); + + /* "ezdxf/acc/np_support.pyx":54 + * if x_is_close and y_is_close: + * p1x = vertices[0][0] + * p1y = vertices[0][1] # <<<<<<<<<<<<<< + * start = 1 + * else: + */ + __pyx_t_2 = 0; + __pyx_t_1 = 1; + __pyx_v_p1y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_2 * __pyx_v_vertices.strides[0]) )) + __pyx_t_1)) ))); + + /* "ezdxf/acc/np_support.pyx":55 + * p1x = vertices[0][0] + * p1y = vertices[0][1] + * start = 1 # <<<<<<<<<<<<<< + * else: + * p1x = vertices[last][0] + */ + __pyx_v_start = 1; + + /* "ezdxf/acc/np_support.pyx":52 + * cdef bint y_is_close = isclose(p1y, p2y, REL_TOL, ABS_TOL) + * + * if x_is_close and y_is_close: # <<<<<<<<<<<<<< + * p1x = vertices[0][0] + * p1y = vertices[0][1] + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/np_support.pyx":57 + * start = 1 + * else: + * p1x = vertices[last][0] # <<<<<<<<<<<<<< + * p1y = vertices[last][1] + * start = 0 + */ + /*else*/ { + __pyx_t_1 = __pyx_v_last; + __pyx_t_2 = 0; + __pyx_v_p1x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_1 * __pyx_v_vertices.strides[0]) )) + __pyx_t_2)) ))); + + /* "ezdxf/acc/np_support.pyx":58 + * else: + * p1x = vertices[last][0] + * p1y = vertices[last][1] # <<<<<<<<<<<<<< + * start = 0 + * + */ + __pyx_t_2 = __pyx_v_last; + __pyx_t_1 = 1; + __pyx_v_p1y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_2 * __pyx_v_vertices.strides[0]) )) + __pyx_t_1)) ))); + + /* "ezdxf/acc/np_support.pyx":59 + * p1x = vertices[last][0] + * p1y = vertices[last][1] + * start = 0 # <<<<<<<<<<<<<< + * + * for index in range(start, size): + */ + __pyx_v_start = 0; + } + __pyx_L3:; + + /* "ezdxf/acc/np_support.pyx":61 + * start = 0 + * + * for index in range(start, size): # <<<<<<<<<<<<<< + * p2x = vertices[index][0] + * p2y = vertices[index][1] + */ + __pyx_t_4 = __pyx_v_size; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = __pyx_v_start; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_index = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":62 + * + * for index in range(start, size): + * p2x = vertices[index][0] # <<<<<<<<<<<<<< + * p2y = vertices[index][1] + * s += (p2x - p1x) * (p2y + p1y) + */ + __pyx_t_1 = __pyx_v_index; + __pyx_t_2 = 0; + __pyx_v_p2x = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_1 * __pyx_v_vertices.strides[0]) )) + __pyx_t_2)) ))); + + /* "ezdxf/acc/np_support.pyx":63 + * for index in range(start, size): + * p2x = vertices[index][0] + * p2y = vertices[index][1] # <<<<<<<<<<<<<< + * s += (p2x - p1x) * (p2y + p1y) + * p1x = p2x + */ + __pyx_t_2 = __pyx_v_index; + __pyx_t_1 = 1; + __pyx_v_p2y = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vertices.data + __pyx_t_2 * __pyx_v_vertices.strides[0]) )) + __pyx_t_1)) ))); + + /* "ezdxf/acc/np_support.pyx":64 + * p2x = vertices[index][0] + * p2y = vertices[index][1] + * s += (p2x - p1x) * (p2y + p1y) # <<<<<<<<<<<<<< + * p1x = p2x + * p1y = p2y + */ + __pyx_v_s = (__pyx_v_s + ((__pyx_v_p2x - __pyx_v_p1x) * (__pyx_v_p2y + __pyx_v_p1y))); + + /* "ezdxf/acc/np_support.pyx":65 + * p2y = vertices[index][1] + * s += (p2x - p1x) * (p2y + p1y) + * p1x = p2x # <<<<<<<<<<<<<< + * p1y = p2y + * return s > 0.0 + */ + __pyx_v_p1x = __pyx_v_p2x; + + /* "ezdxf/acc/np_support.pyx":66 + * s += (p2x - p1x) * (p2y + p1y) + * p1x = p2x + * p1y = p2y # <<<<<<<<<<<<<< + * return s > 0.0 + * + */ + __pyx_v_p1y = __pyx_v_p2y; + } + + /* "ezdxf/acc/np_support.pyx":67 + * p1x = p2x + * p1y = p2y + * return s > 0.0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = (__pyx_v_s > 0.0); + goto __pyx_L0; + + /* "ezdxf/acc/np_support.pyx":38 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef bint _has_clockwise_orientation(double [:, ::1] vertices, Py_ssize_t size): # <<<<<<<<<<<<<< + * cdef Py_ssize_t index + * cdef Py_ssize_t start + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.np_support._has_clockwise_orientation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":70 + * + * + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: # <<<<<<<<<<<<<< + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_3lu_decompose(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_10np_support_3lu_decompose = {"lu_decompose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_10np_support_3lu_decompose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_3lu_decompose(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_A = 0; + PyObject *__pyx_v_m1 = 0; + PyObject *__pyx_v_m2 = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("lu_decompose (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_A,&__pyx_n_s_m1,&__pyx_n_s_m2,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_A)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 70, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 70, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("lu_decompose", 1, 3, 3, 1); __PYX_ERR(0, 70, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 70, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("lu_decompose", 1, 3, 3, 2); __PYX_ERR(0, 70, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lu_decompose") < 0)) __PYX_ERR(0, 70, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 3)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + } + __pyx_v_A = values[0]; + __pyx_v_m1 = ((PyObject*)values[1]); + __pyx_v_m2 = ((PyObject*)values[2]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("lu_decompose", 1, 3, 3, __pyx_nargs); __PYX_ERR(0, 70, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.np_support.lu_decompose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m1), (&PyInt_Type), 0, "m1", 1))) __PYX_ERR(0, 70, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m2), (&PyInt_Type), 0, "m2", 1))) __PYX_ERR(0, 70, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_10np_support_2lu_decompose(__pyx_self, __pyx_v_A, __pyx_v_m1, __pyx_v_m2); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_2lu_decompose(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_A, PyObject *__pyx_v_m1, PyObject *__pyx_v_m2) { + PyObject *__pyx_v_upper = NULL; + PyObject *__pyx_v_n = 0; + PyObject *__pyx_v_lower = NULL; + PyObject *__pyx_v_index = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + __Pyx_memviewslice __pyx_t_6 = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_memviewslice __pyx_t_7 = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_memviewslice __pyx_t_8 = { 0, 0, { 0 }, { 0 }, { 0 } }; + int __pyx_t_9; + int __pyx_t_10; + int __pyx_t_11; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("lu_decompose", 1); + + /* "ezdxf/acc/np_support.pyx":71 + * + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: + * upper: np.ndarray = np.array(A, dtype=np.float64) # <<<<<<<<<<<<<< + * n: int = upper.shape[0] + * lower: np.ndarray = np.zeros((n, m1), dtype=np.float64) + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_array); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_A); + __Pyx_GIVEREF(__pyx_v_A); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_A)) __PYX_ERR(0, 71, __pyx_L1_error); + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_upper = __pyx_t_5; + __pyx_t_5 = 0; + + /* "ezdxf/acc/np_support.pyx":72 + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] # <<<<<<<<<<<<<< + * lower: np.ndarray = np.zeros((n, m1), dtype=np.float64) + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_upper, __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_5, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_t_3))) __PYX_ERR(0, 72, __pyx_L1_error) + __pyx_v_n = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/np_support.pyx":73 + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] + * lower: np.ndarray = np.zeros((n, m1), dtype=np.float64) # <<<<<<<<<<<<<< + * + * # Is better to match on all platforms? + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_zeros); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_n); + __Pyx_GIVEREF(__pyx_v_n); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_n)) __PYX_ERR(0, 73, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_m1); + __Pyx_GIVEREF(__pyx_v_m1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_m1)) __PYX_ERR(0, 73, __pyx_L1_error); + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_float64); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_lower = __pyx_t_4; + __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":76 + * + * # Is better to match on all platforms? + * index: np.ndarray = np.zeros((n,), dtype=np.int32) # <<<<<<<<<<<<<< + * _lu_decompose_cext(upper, lower, index, n, m1, m2) + * return upper, lower, index + */ + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_n); + __Pyx_GIVEREF(__pyx_v_n); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_n)) __PYX_ERR(0, 76, __pyx_L1_error); + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_int32); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_dtype, __pyx_t_2) < 0) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_index = __pyx_t_2; + __pyx_t_2 = 0; + + /* "ezdxf/acc/np_support.pyx":77 + * # Is better to match on all platforms? + * index: np.ndarray = np.zeros((n,), dtype=np.int32) + * _lu_decompose_cext(upper, lower, index, n, m1, m2) # <<<<<<<<<<<<<< + * return upper, lower, index + * + */ + __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_upper, PyBUF_WRITABLE); if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_lower, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_dc_int(__pyx_v_index, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_9 = __Pyx_PyInt_As_int(__pyx_v_n); if (unlikely((__pyx_t_9 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_10 = __Pyx_PyInt_As_int(__pyx_v_m1); if (unlikely((__pyx_t_10 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_11 = __Pyx_PyInt_As_int(__pyx_v_m2); if (unlikely((__pyx_t_11 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 77, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_10np_support__lu_decompose_cext(__pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10, __pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_6, 1); + __pyx_t_6.memview = NULL; __pyx_t_6.data = NULL; + __PYX_XCLEAR_MEMVIEW(&__pyx_t_7, 1); + __pyx_t_7.memview = NULL; __pyx_t_7.data = NULL; + __PYX_XCLEAR_MEMVIEW(&__pyx_t_8, 1); + __pyx_t_8.memview = NULL; __pyx_t_8.data = NULL; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/np_support.pyx":78 + * index: np.ndarray = np.zeros((n,), dtype=np.int32) + * _lu_decompose_cext(upper, lower, index, n, m1, m2) + * return upper, lower, index # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_v_upper); + __Pyx_GIVEREF(__pyx_v_upper); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_upper)) __PYX_ERR(0, 78, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_lower); + __Pyx_GIVEREF(__pyx_v_lower); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_lower)) __PYX_ERR(0, 78, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_index); + __Pyx_GIVEREF(__pyx_v_index); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_v_index)) __PYX_ERR(0, 78, __pyx_L1_error); + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/np_support.pyx":70 + * + * + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: # <<<<<<<<<<<<<< + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_6, 1); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_7, 1); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_8, 1); + __Pyx_AddTraceback("ezdxf.acc.np_support.lu_decompose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_upper); + __Pyx_XDECREF(__pyx_v_n); + __Pyx_XDECREF(__pyx_v_lower); + __Pyx_XDECREF(__pyx_v_index); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":83 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef _lu_decompose_cext( # <<<<<<<<<<<<<< + * double [:, ::1] upper, + * double [:, ::1] lower, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_10np_support__lu_decompose_cext(__Pyx_memviewslice __pyx_v_upper, __Pyx_memviewslice __pyx_v_lower, __Pyx_memviewslice __pyx_v_index, int __pyx_v_n, int __pyx_v_m1, int __pyx_v_m2) { + int __pyx_v_mm; + int __pyx_v_l; + int __pyx_v_i; + int __pyx_v_j; + int __pyx_v_k; + double __pyx_v_dum; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + Py_ssize_t __pyx_t_7; + Py_ssize_t __pyx_t_8; + Py_ssize_t __pyx_t_9; + Py_ssize_t __pyx_t_10; + int __pyx_t_11; + double __pyx_t_12; + double __pyx_t_13; + int __pyx_t_14; + int __pyx_t_15; + int __pyx_t_16; + Py_ssize_t __pyx_t_17; + Py_ssize_t __pyx_t_18; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_lu_decompose_cext", 1); + + /* "ezdxf/acc/np_support.pyx":91 + * int m2 + * ): + * cdef int mm = m1 + m2 + 1 # <<<<<<<<<<<<<< + * cdef int l = m1 + * cdef int i, j, k + */ + __pyx_v_mm = ((__pyx_v_m1 + __pyx_v_m2) + 1); + + /* "ezdxf/acc/np_support.pyx":92 + * ): + * cdef int mm = m1 + m2 + 1 + * cdef int l = m1 # <<<<<<<<<<<<<< + * cdef int i, j, k + * cdef double dum + */ + __pyx_v_l = __pyx_v_m1; + + /* "ezdxf/acc/np_support.pyx":96 + * cdef double dum + * + * for i in range(m1): # <<<<<<<<<<<<<< + * for j in range(m1 - i, mm): + * upper[i][j - l] = upper[i][j] + */ + __pyx_t_1 = __pyx_v_m1; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "ezdxf/acc/np_support.pyx":97 + * + * for i in range(m1): + * for j in range(m1 - i, mm): # <<<<<<<<<<<<<< + * upper[i][j - l] = upper[i][j] + * l -= 1 + */ + __pyx_t_4 = __pyx_v_mm; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = (__pyx_v_m1 - __pyx_v_i); __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_j = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":98 + * for i in range(m1): + * for j in range(m1 - i, mm): + * upper[i][j - l] = upper[i][j] # <<<<<<<<<<<<<< + * l -= 1 + * for j in range(mm - l - 1, mm): + */ + __pyx_t_7 = __pyx_v_i; + __pyx_t_8 = __pyx_v_j; + __pyx_t_9 = __pyx_v_i; + __pyx_t_10 = (__pyx_v_j - __pyx_v_l); + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_9 * __pyx_v_upper.strides[0]) )) + __pyx_t_10)) )) = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))); + } + + /* "ezdxf/acc/np_support.pyx":99 + * for j in range(m1 - i, mm): + * upper[i][j - l] = upper[i][j] + * l -= 1 # <<<<<<<<<<<<<< + * for j in range(mm - l - 1, mm): + * upper[i][j] = 0.0 + */ + __pyx_v_l = (__pyx_v_l - 1); + + /* "ezdxf/acc/np_support.pyx":100 + * upper[i][j - l] = upper[i][j] + * l -= 1 + * for j in range(mm - l - 1, mm): # <<<<<<<<<<<<<< + * upper[i][j] = 0.0 + * + */ + __pyx_t_4 = __pyx_v_mm; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = ((__pyx_v_mm - __pyx_v_l) - 1); __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_j = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":101 + * l -= 1 + * for j in range(mm - l - 1, mm): + * upper[i][j] = 0.0 # <<<<<<<<<<<<<< + * + * l = m1 + */ + __pyx_t_8 = __pyx_v_i; + __pyx_t_7 = __pyx_v_j; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_8 * __pyx_v_upper.strides[0]) )) + __pyx_t_7)) )) = 0.0; + } + } + + /* "ezdxf/acc/np_support.pyx":103 + * upper[i][j] = 0.0 + * + * l = m1 # <<<<<<<<<<<<<< + * for k in range(n): + * dum = upper[k][0] + */ + __pyx_v_l = __pyx_v_m1; + + /* "ezdxf/acc/np_support.pyx":104 + * + * l = m1 + * for k in range(n): # <<<<<<<<<<<<<< + * dum = upper[k][0] + * i = k + */ + __pyx_t_1 = __pyx_v_n; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_k = __pyx_t_3; + + /* "ezdxf/acc/np_support.pyx":105 + * l = m1 + * for k in range(n): + * dum = upper[k][0] # <<<<<<<<<<<<<< + * i = k + * if l < n: + */ + __pyx_t_7 = __pyx_v_k; + __pyx_t_8 = 0; + __pyx_v_dum = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))); + + /* "ezdxf/acc/np_support.pyx":106 + * for k in range(n): + * dum = upper[k][0] + * i = k # <<<<<<<<<<<<<< + * if l < n: + * l += 1 + */ + __pyx_v_i = __pyx_v_k; + + /* "ezdxf/acc/np_support.pyx":107 + * dum = upper[k][0] + * i = k + * if l < n: # <<<<<<<<<<<<<< + * l += 1 + * for j in range(k + 1, l): + */ + __pyx_t_11 = (__pyx_v_l < __pyx_v_n); + if (__pyx_t_11) { + + /* "ezdxf/acc/np_support.pyx":108 + * i = k + * if l < n: + * l += 1 # <<<<<<<<<<<<<< + * for j in range(k + 1, l): + * if abs(upper[j][0]) > abs(dum): + */ + __pyx_v_l = (__pyx_v_l + 1); + + /* "ezdxf/acc/np_support.pyx":107 + * dum = upper[k][0] + * i = k + * if l < n: # <<<<<<<<<<<<<< + * l += 1 + * for j in range(k + 1, l): + */ + } + + /* "ezdxf/acc/np_support.pyx":109 + * if l < n: + * l += 1 + * for j in range(k + 1, l): # <<<<<<<<<<<<<< + * if abs(upper[j][0]) > abs(dum): + * dum = upper[j][0] + */ + __pyx_t_4 = __pyx_v_l; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = (__pyx_v_k + 1); __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_j = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":110 + * l += 1 + * for j in range(k + 1, l): + * if abs(upper[j][0]) > abs(dum): # <<<<<<<<<<<<<< + * dum = upper[j][0] + * i = j + */ + __pyx_t_8 = __pyx_v_j; + __pyx_t_7 = 0; + __pyx_t_11 = (fabs((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_8 * __pyx_v_upper.strides[0]) )) + __pyx_t_7)) )))) > fabs(__pyx_v_dum)); + if (__pyx_t_11) { + + /* "ezdxf/acc/np_support.pyx":111 + * for j in range(k + 1, l): + * if abs(upper[j][0]) > abs(dum): + * dum = upper[j][0] # <<<<<<<<<<<<<< + * i = j + * index[k] = i + 1 + */ + __pyx_t_7 = __pyx_v_j; + __pyx_t_8 = 0; + __pyx_v_dum = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))); + + /* "ezdxf/acc/np_support.pyx":112 + * if abs(upper[j][0]) > abs(dum): + * dum = upper[j][0] + * i = j # <<<<<<<<<<<<<< + * index[k] = i + 1 + * if i != k: + */ + __pyx_v_i = __pyx_v_j; + + /* "ezdxf/acc/np_support.pyx":110 + * l += 1 + * for j in range(k + 1, l): + * if abs(upper[j][0]) > abs(dum): # <<<<<<<<<<<<<< + * dum = upper[j][0] + * i = j + */ + } + } + + /* "ezdxf/acc/np_support.pyx":113 + * dum = upper[j][0] + * i = j + * index[k] = i + 1 # <<<<<<<<<<<<<< + * if i != k: + * for j in range(mm): + */ + __pyx_t_8 = __pyx_v_k; + *((int *) ( /* dim=0 */ ((char *) (((int *) __pyx_v_index.data) + __pyx_t_8)) )) = (__pyx_v_i + 1); + + /* "ezdxf/acc/np_support.pyx":114 + * i = j + * index[k] = i + 1 + * if i != k: # <<<<<<<<<<<<<< + * for j in range(mm): + * upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + */ + __pyx_t_11 = (__pyx_v_i != __pyx_v_k); + if (__pyx_t_11) { + + /* "ezdxf/acc/np_support.pyx":115 + * index[k] = i + 1 + * if i != k: + * for j in range(mm): # <<<<<<<<<<<<<< + * upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + * + */ + __pyx_t_4 = __pyx_v_mm; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_j = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":116 + * if i != k: + * for j in range(mm): + * upper[k][j], upper[i][j] = upper[i][j], upper[k][j] # <<<<<<<<<<<<<< + * + * for i in range(k + 1, l): + */ + __pyx_t_8 = __pyx_v_i; + __pyx_t_7 = __pyx_v_j; + __pyx_t_12 = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_8 * __pyx_v_upper.strides[0]) )) + __pyx_t_7)) ))); + __pyx_t_7 = __pyx_v_k; + __pyx_t_8 = __pyx_v_j; + __pyx_t_13 = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))); + __pyx_t_8 = __pyx_v_k; + __pyx_t_7 = __pyx_v_j; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_8 * __pyx_v_upper.strides[0]) )) + __pyx_t_7)) )) = __pyx_t_12; + __pyx_t_7 = __pyx_v_i; + __pyx_t_8 = __pyx_v_j; + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) )) = __pyx_t_13; + } + + /* "ezdxf/acc/np_support.pyx":114 + * i = j + * index[k] = i + 1 + * if i != k: # <<<<<<<<<<<<<< + * for j in range(mm): + * upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + */ + } + + /* "ezdxf/acc/np_support.pyx":118 + * upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + * + * for i in range(k + 1, l): # <<<<<<<<<<<<<< + * dum = upper[i][0] / upper[k][0] + * lower[k][i - k - 1] = dum + */ + __pyx_t_4 = __pyx_v_l; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = (__pyx_v_k + 1); __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "ezdxf/acc/np_support.pyx":119 + * + * for i in range(k + 1, l): + * dum = upper[i][0] / upper[k][0] # <<<<<<<<<<<<<< + * lower[k][i - k - 1] = dum + * for j in range(1, mm): + */ + __pyx_t_8 = __pyx_v_i; + __pyx_t_7 = 0; + __pyx_t_13 = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_8 * __pyx_v_upper.strides[0]) )) + __pyx_t_7)) ))); + __pyx_t_7 = __pyx_v_k; + __pyx_t_8 = 0; + __pyx_t_12 = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))); + if (unlikely(__pyx_t_12 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 119, __pyx_L1_error) + } + __pyx_v_dum = (__pyx_t_13 / __pyx_t_12); + + /* "ezdxf/acc/np_support.pyx":120 + * for i in range(k + 1, l): + * dum = upper[i][0] / upper[k][0] + * lower[k][i - k - 1] = dum # <<<<<<<<<<<<<< + * for j in range(1, mm): + * upper[i][j - 1] = upper[i][j] - dum * upper[k][j] + */ + __pyx_t_8 = __pyx_v_k; + __pyx_t_7 = ((__pyx_v_i - __pyx_v_k) - 1); + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_lower.data + __pyx_t_8 * __pyx_v_lower.strides[0]) )) + __pyx_t_7)) )) = __pyx_v_dum; + + /* "ezdxf/acc/np_support.pyx":121 + * dum = upper[i][0] / upper[k][0] + * lower[k][i - k - 1] = dum + * for j in range(1, mm): # <<<<<<<<<<<<<< + * upper[i][j - 1] = upper[i][j] - dum * upper[k][j] + * upper[i][mm - 1] = 0.0 + */ + __pyx_t_14 = __pyx_v_mm; + __pyx_t_15 = __pyx_t_14; + for (__pyx_t_16 = 1; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) { + __pyx_v_j = __pyx_t_16; + + /* "ezdxf/acc/np_support.pyx":122 + * lower[k][i - k - 1] = dum + * for j in range(1, mm): + * upper[i][j - 1] = upper[i][j] - dum * upper[k][j] # <<<<<<<<<<<<<< + * upper[i][mm - 1] = 0.0 + * + */ + __pyx_t_7 = __pyx_v_i; + __pyx_t_8 = __pyx_v_j; + __pyx_t_10 = __pyx_v_k; + __pyx_t_9 = __pyx_v_j; + __pyx_t_17 = __pyx_v_i; + __pyx_t_18 = (__pyx_v_j - 1); + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_17 * __pyx_v_upper.strides[0]) )) + __pyx_t_18)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_7 * __pyx_v_upper.strides[0]) )) + __pyx_t_8)) ))) - (__pyx_v_dum * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_10 * __pyx_v_upper.strides[0]) )) + __pyx_t_9)) ))))); + } + + /* "ezdxf/acc/np_support.pyx":123 + * for j in range(1, mm): + * upper[i][j - 1] = upper[i][j] - dum * upper[k][j] + * upper[i][mm - 1] = 0.0 # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_9 = __pyx_v_i; + __pyx_t_10 = (__pyx_v_mm - 1); + *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_upper.data + __pyx_t_9 * __pyx_v_upper.strides[0]) )) + __pyx_t_10)) )) = 0.0; + } + } + + /* "ezdxf/acc/np_support.pyx":83 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef _lu_decompose_cext( # <<<<<<<<<<<<<< + * double [:, ::1] upper, + * double [:, ::1] lower, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.np_support._lu_decompose_cext", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":126 + * + * + * def solve_vector_banded_matrix( # <<<<<<<<<<<<<< + * x: NDArray, + * upper: NDArray, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_5solve_vector_banded_matrix(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_10np_support_5solve_vector_banded_matrix = {"solve_vector_banded_matrix", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_10np_support_5solve_vector_banded_matrix, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_10np_support_5solve_vector_banded_matrix(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_upper = 0; + PyObject *__pyx_v_lower = 0; + PyObject *__pyx_v_index = 0; + PyObject *__pyx_v_m1 = 0; + PyObject *__pyx_v_m2 = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[6] = {0,0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("solve_vector_banded_matrix (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_upper,&__pyx_n_s_lower,&__pyx_n_s_index,&__pyx_n_s_m1,&__pyx_n_s_m2,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 6: values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5); + CYTHON_FALLTHROUGH; + case 5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_x)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_upper)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, 1); __PYX_ERR(0, 126, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_lower)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[2]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, 2); __PYX_ERR(0, 126, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_index)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[3]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, 3); __PYX_ERR(0, 126, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (likely((values[4] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[4]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, 4); __PYX_ERR(0, 126, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 5: + if (likely((values[5] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_m2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[5]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, 5); __PYX_ERR(0, 126, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "solve_vector_banded_matrix") < 0)) __PYX_ERR(0, 126, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 6)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3); + values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4); + values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5); + } + __pyx_v_x = values[0]; + __pyx_v_upper = values[1]; + __pyx_v_lower = values[2]; + __pyx_v_index = values[3]; + __pyx_v_m1 = ((PyObject*)values[4]); + __pyx_v_m2 = ((PyObject*)values[5]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("solve_vector_banded_matrix", 1, 6, 6, __pyx_nargs); __PYX_ERR(0, 126, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.np_support.solve_vector_banded_matrix", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m1), (&PyInt_Type), 0, "m1", 1))) __PYX_ERR(0, 131, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_m2), (&PyInt_Type), 0, "m2", 1))) __PYX_ERR(0, 132, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_10np_support_4solve_vector_banded_matrix(__pyx_self, __pyx_v_x, __pyx_v_upper, __pyx_v_lower, __pyx_v_index, __pyx_v_m1, __pyx_v_m2); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_10np_support_4solve_vector_banded_matrix(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_x, PyObject *__pyx_v_upper, PyObject *__pyx_v_lower, PyObject *__pyx_v_index, PyObject *__pyx_v_m1, PyObject *__pyx_v_m2) { + PyObject *__pyx_v_n = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_t_5; + __Pyx_memviewslice __pyx_t_6 = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_memviewslice __pyx_t_7 = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_memviewslice __pyx_t_8 = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_memviewslice __pyx_t_9 = { 0, 0, { 0 }, { 0 }, { 0 } }; + int __pyx_t_10; + int __pyx_t_11; + int __pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("solve_vector_banded_matrix", 0); + __Pyx_INCREF(__pyx_v_x); + + /* "ezdxf/acc/np_support.pyx":134 + * m2: int, + * ) -> NDArray: + * n: int = upper.shape[0] # <<<<<<<<<<<<<< + * x = np.array(x) # copy x because array x gets modified + * if x.shape[0] != n: + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_upper, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (!(likely(__Pyx_Py3Int_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_t_2))) __PYX_ERR(0, 134, __pyx_L1_error) + __pyx_v_n = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/np_support.pyx":135 + * ) -> NDArray: + * n: int = upper.shape[0] + * x = np.array(x) # copy x because array x gets modified # <<<<<<<<<<<<<< + * if x.shape[0] != n: + * raise ValueError( + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_array); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_v_x}; + __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF_SET(__pyx_v_x, __pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/np_support.pyx":136 + * n: int = upper.shape[0] + * x = np.array(x) # copy x because array x gets modified + * if x.shape[0] != n: # <<<<<<<<<<<<<< + * raise ValueError( + * "Item count of vector has to match the row count of matrix ." + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyObject_RichCompare(__pyx_t_3, __pyx_v_n, Py_NE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_5)) { + + /* "ezdxf/acc/np_support.pyx":137 + * x = np.array(x) # copy x because array x gets modified + * if x.shape[0] != n: + * raise ValueError( # <<<<<<<<<<<<<< + * "Item count of vector has to match the row count of matrix ." + * ) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 137, __pyx_L1_error) + + /* "ezdxf/acc/np_support.pyx":136 + * n: int = upper.shape[0] + * x = np.array(x) # copy x because array x gets modified + * if x.shape[0] != n: # <<<<<<<<<<<<<< + * raise ValueError( + * "Item count of vector has to match the row count of matrix ." + */ + } + + /* "ezdxf/acc/np_support.pyx":140 + * "Item count of vector has to match the row count of matrix ." + * ) + * _solve_vector_banded_matrix_cext(x, upper, lower, index, n, m1, m2) # <<<<<<<<<<<<<< + * return x + * + */ + __pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dc_double(__pyx_v_x, PyBUF_WRITABLE); if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_upper, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(__pyx_v_lower, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_dc_int(__pyx_v_index, PyBUF_WRITABLE); if (unlikely(!__pyx_t_9.memview)) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_10 = __Pyx_PyInt_As_int(__pyx_v_n); if (unlikely((__pyx_t_10 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_11 = __Pyx_PyInt_As_int(__pyx_v_m1); if (unlikely((__pyx_t_11 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_12 = __Pyx_PyInt_As_int(__pyx_v_m2); if (unlikely((__pyx_t_12 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 140, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5ezdxf_3acc_10np_support__solve_vector_banded_matrix_cext(__pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10, __pyx_t_11, __pyx_t_12); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 140, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_6, 1); + __pyx_t_6.memview = NULL; __pyx_t_6.data = NULL; + __PYX_XCLEAR_MEMVIEW(&__pyx_t_7, 1); + __pyx_t_7.memview = NULL; __pyx_t_7.data = NULL; + __PYX_XCLEAR_MEMVIEW(&__pyx_t_8, 1); + __pyx_t_8.memview = NULL; __pyx_t_8.data = NULL; + __PYX_XCLEAR_MEMVIEW(&__pyx_t_9, 1); + __pyx_t_9.memview = NULL; __pyx_t_9.data = NULL; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/np_support.pyx":141 + * ) + * _solve_vector_banded_matrix_cext(x, upper, lower, index, n, m1, m2) + * return x # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_x); + __pyx_r = __pyx_v_x; + goto __pyx_L0; + + /* "ezdxf/acc/np_support.pyx":126 + * + * + * def solve_vector_banded_matrix( # <<<<<<<<<<<<<< + * x: NDArray, + * upper: NDArray, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_6, 1); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_7, 1); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_8, 1); + __PYX_XCLEAR_MEMVIEW(&__pyx_t_9, 1); + __Pyx_AddTraceback("ezdxf.acc.np_support.solve_vector_banded_matrix", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_n); + __Pyx_XDECREF(__pyx_v_x); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/np_support.pyx":146 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef _solve_vector_banded_matrix_cext( # <<<<<<<<<<<<<< + * double [::1] x, + * double [:, ::1] au, + */ + +static PyObject *__pyx_f_5ezdxf_3acc_10np_support__solve_vector_banded_matrix_cext(__Pyx_memviewslice __pyx_v_x, __Pyx_memviewslice __pyx_v_au, __Pyx_memviewslice __pyx_v_al, __Pyx_memviewslice __pyx_v_index, int __pyx_v_n, int __pyx_v_m1, int __pyx_v_m2) { + int __pyx_v_mm; + int __pyx_v_l; + int __pyx_v_i; + int __pyx_v_j; + int __pyx_v_k; + double __pyx_v_dum; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + Py_ssize_t __pyx_t_4; + int __pyx_t_5; + double __pyx_t_6; + double __pyx_t_7; + int __pyx_t_8; + int __pyx_t_9; + int __pyx_t_10; + Py_ssize_t __pyx_t_11; + Py_ssize_t __pyx_t_12; + Py_ssize_t __pyx_t_13; + PyObject *__pyx_t_14 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_solve_vector_banded_matrix_cext", 1); + + /* "ezdxf/acc/np_support.pyx":155 + * int m2, + * ): + * cdef int mm = m1 + m2 + 1 # <<<<<<<<<<<<<< + * cdef int l = m1 + * cdef int i, j, k + */ + __pyx_v_mm = ((__pyx_v_m1 + __pyx_v_m2) + 1); + + /* "ezdxf/acc/np_support.pyx":156 + * ): + * cdef int mm = m1 + m2 + 1 + * cdef int l = m1 # <<<<<<<<<<<<<< + * cdef int i, j, k + * cdef double dum + */ + __pyx_v_l = __pyx_v_m1; + + /* "ezdxf/acc/np_support.pyx":160 + * cdef double dum + * + * for k in range(n): # <<<<<<<<<<<<<< + * j = index[k] - 1 + * if j != k: + */ + __pyx_t_1 = __pyx_v_n; + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_k = __pyx_t_3; + + /* "ezdxf/acc/np_support.pyx":161 + * + * for k in range(n): + * j = index[k] - 1 # <<<<<<<<<<<<<< + * if j != k: + * x[k], x[j] = x[j], x[k] + */ + __pyx_t_4 = __pyx_v_k; + __pyx_v_j = ((*((int *) ( /* dim=0 */ ((char *) (((int *) __pyx_v_index.data) + __pyx_t_4)) ))) - 1); + + /* "ezdxf/acc/np_support.pyx":162 + * for k in range(n): + * j = index[k] - 1 + * if j != k: # <<<<<<<<<<<<<< + * x[k], x[j] = x[j], x[k] + * if l < n: + */ + __pyx_t_5 = (__pyx_v_j != __pyx_v_k); + if (__pyx_t_5) { + + /* "ezdxf/acc/np_support.pyx":163 + * j = index[k] - 1 + * if j != k: + * x[k], x[j] = x[j], x[k] # <<<<<<<<<<<<<< + * if l < n: + * l += 1 + */ + __pyx_t_4 = __pyx_v_j; + __pyx_t_6 = (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_4)) ))); + __pyx_t_4 = __pyx_v_k; + __pyx_t_7 = (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_4)) ))); + __pyx_t_4 = __pyx_v_k; + *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_4)) )) = __pyx_t_6; + __pyx_t_4 = __pyx_v_j; + *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_4)) )) = __pyx_t_7; + + /* "ezdxf/acc/np_support.pyx":162 + * for k in range(n): + * j = index[k] - 1 + * if j != k: # <<<<<<<<<<<<<< + * x[k], x[j] = x[j], x[k] + * if l < n: + */ + } + + /* "ezdxf/acc/np_support.pyx":164 + * if j != k: + * x[k], x[j] = x[j], x[k] + * if l < n: # <<<<<<<<<<<<<< + * l += 1 + * for j in range(k + 1, l): + */ + __pyx_t_5 = (__pyx_v_l < __pyx_v_n); + if (__pyx_t_5) { + + /* "ezdxf/acc/np_support.pyx":165 + * x[k], x[j] = x[j], x[k] + * if l < n: + * l += 1 # <<<<<<<<<<<<<< + * for j in range(k + 1, l): + * x[j] -= al[k][j - k - 1] * x[k] + */ + __pyx_v_l = (__pyx_v_l + 1); + + /* "ezdxf/acc/np_support.pyx":164 + * if j != k: + * x[k], x[j] = x[j], x[k] + * if l < n: # <<<<<<<<<<<<<< + * l += 1 + * for j in range(k + 1, l): + */ + } + + /* "ezdxf/acc/np_support.pyx":166 + * if l < n: + * l += 1 + * for j in range(k + 1, l): # <<<<<<<<<<<<<< + * x[j] -= al[k][j - k - 1] * x[k] + * + */ + __pyx_t_8 = __pyx_v_l; + __pyx_t_9 = __pyx_t_8; + for (__pyx_t_10 = (__pyx_v_k + 1); __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) { + __pyx_v_j = __pyx_t_10; + + /* "ezdxf/acc/np_support.pyx":167 + * l += 1 + * for j in range(k + 1, l): + * x[j] -= al[k][j - k - 1] * x[k] # <<<<<<<<<<<<<< + * + * l = 1 + */ + __pyx_t_4 = __pyx_v_k; + __pyx_t_11 = ((__pyx_v_j - __pyx_v_k) - 1); + __pyx_t_12 = __pyx_v_k; + __pyx_t_13 = __pyx_v_j; + *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_13)) )) -= ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_al.data + __pyx_t_4 * __pyx_v_al.strides[0]) )) + __pyx_t_11)) ))) * (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_12)) )))); + } + } + + /* "ezdxf/acc/np_support.pyx":169 + * x[j] -= al[k][j - k - 1] * x[k] + * + * l = 1 # <<<<<<<<<<<<<< + * for i in range(n - 1, -1, -1): + * dum = x[i] + */ + __pyx_v_l = 1; + + /* "ezdxf/acc/np_support.pyx":170 + * + * l = 1 + * for i in range(n - 1, -1, -1): # <<<<<<<<<<<<<< + * dum = x[i] + * for k in range(1, l): + */ + for (__pyx_t_1 = (__pyx_v_n - 1); __pyx_t_1 > -1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "ezdxf/acc/np_support.pyx":171 + * l = 1 + * for i in range(n - 1, -1, -1): + * dum = x[i] # <<<<<<<<<<<<<< + * for k in range(1, l): + * dum -= au[i][k] * x[k + i] + */ + __pyx_t_12 = __pyx_v_i; + __pyx_v_dum = (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_12)) ))); + + /* "ezdxf/acc/np_support.pyx":172 + * for i in range(n - 1, -1, -1): + * dum = x[i] + * for k in range(1, l): # <<<<<<<<<<<<<< + * dum -= au[i][k] * x[k + i] + * x[i] = dum / au[i][0] + */ + __pyx_t_2 = __pyx_v_l; + __pyx_t_3 = __pyx_t_2; + for (__pyx_t_8 = 1; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) { + __pyx_v_k = __pyx_t_8; + + /* "ezdxf/acc/np_support.pyx":173 + * dum = x[i] + * for k in range(1, l): + * dum -= au[i][k] * x[k + i] # <<<<<<<<<<<<<< + * x[i] = dum / au[i][0] + * if l < mm: + */ + __pyx_t_12 = __pyx_v_i; + __pyx_t_11 = __pyx_v_k; + __pyx_t_4 = (__pyx_v_k + __pyx_v_i); + __pyx_v_dum = (__pyx_v_dum - ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_au.data + __pyx_t_12 * __pyx_v_au.strides[0]) )) + __pyx_t_11)) ))) * (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_4)) ))))); + } + + /* "ezdxf/acc/np_support.pyx":174 + * for k in range(1, l): + * dum -= au[i][k] * x[k + i] + * x[i] = dum / au[i][0] # <<<<<<<<<<<<<< + * if l < mm: + * l += 1 + */ + __pyx_t_4 = __pyx_v_i; + __pyx_t_11 = 0; + __pyx_t_7 = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_au.data + __pyx_t_4 * __pyx_v_au.strides[0]) )) + __pyx_t_11)) ))); + if (unlikely(__pyx_t_7 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 174, __pyx_L1_error) + } + __pyx_t_11 = __pyx_v_i; + *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_x.data) + __pyx_t_11)) )) = (__pyx_v_dum / __pyx_t_7); + + /* "ezdxf/acc/np_support.pyx":175 + * dum -= au[i][k] * x[k + i] + * x[i] = dum / au[i][0] + * if l < mm: # <<<<<<<<<<<<<< + * l += 1 + * return x + */ + __pyx_t_5 = (__pyx_v_l < __pyx_v_mm); + if (__pyx_t_5) { + + /* "ezdxf/acc/np_support.pyx":176 + * x[i] = dum / au[i][0] + * if l < mm: + * l += 1 # <<<<<<<<<<<<<< + * return x + */ + __pyx_v_l = (__pyx_v_l + 1); + + /* "ezdxf/acc/np_support.pyx":175 + * dum -= au[i][k] * x[k + i] + * x[i] = dum / au[i][0] + * if l < mm: # <<<<<<<<<<<<<< + * l += 1 + * return x + */ + } + } + + /* "ezdxf/acc/np_support.pyx":177 + * if l < mm: + * l += 1 + * return x # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_14 = __pyx_memoryview_fromslice(__pyx_v_x, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_r = __pyx_t_14; + __pyx_t_14 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/np_support.pyx":146 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * cdef _solve_vector_banded_matrix_cext( # <<<<<<<<<<<<<< + * double [::1] x, + * double [:, ::1] au, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_14); + __Pyx_AddTraceback("ezdxf.acc.np_support._solve_vector_banded_matrix_cext", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static struct __pyx_vtabstruct_array __pyx_vtable_array; + +static PyObject *__pyx_tp_new_array(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_array_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_array_obj *)o); + p->__pyx_vtab = __pyx_vtabptr_array; + p->mode = ((PyObject*)Py_None); Py_INCREF(Py_None); + p->_format = ((PyObject*)Py_None); Py_INCREF(Py_None); + if (unlikely(__pyx_array___cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_array(PyObject *o) { + struct __pyx_array_obj *p = (struct __pyx_array_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_array) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_array___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->mode); + Py_CLEAR(p->_format); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} +static PyObject *__pyx_sq_item_array(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static int __pyx_mp_ass_subscript_array(PyObject *o, PyObject *i, PyObject *v) { + if (v) { + return __pyx_array___setitem__(o, i, v); + } + else { + __Pyx_TypeName o_type_name; + o_type_name = __Pyx_PyType_GetName(Py_TYPE(o)); + PyErr_Format(PyExc_NotImplementedError, + "Subscript deletion not supported by " __Pyx_FMT_TYPENAME, o_type_name); + __Pyx_DECREF_TypeName(o_type_name); + return -1; + } +} + +static PyObject *__pyx_tp_getattro_array(PyObject *o, PyObject *n) { + PyObject *v = __Pyx_PyObject_GenericGetAttr(o, n); + if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + v = __pyx_array___getattr__(o, n); + } + return v; +} + +static PyObject *__pyx_getprop___pyx_array_memview(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_5array_7memview_1__get__(o); +} + +static PyMethodDef __pyx_methods_array[] = { + {"__getattr__", (PyCFunction)__pyx_array___getattr__, METH_O|METH_COEXIST, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_array_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_array_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_array[] = { + {(char *)"memview", __pyx_getprop___pyx_array_memview, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +#if !CYTHON_COMPILING_IN_LIMITED_API + +static PyBufferProcs __pyx_tp_as_buffer_array = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_array_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; +#endif +static PyType_Slot __pyx_type___pyx_array_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_array}, + {Py_sq_length, (void *)__pyx_array___len__}, + {Py_sq_item, (void *)__pyx_sq_item_array}, + {Py_mp_length, (void *)__pyx_array___len__}, + {Py_mp_subscript, (void *)__pyx_array___getitem__}, + {Py_mp_ass_subscript, (void *)__pyx_mp_ass_subscript_array}, + {Py_tp_getattro, (void *)__pyx_tp_getattro_array}, + #if defined(Py_bf_getbuffer) + {Py_bf_getbuffer, (void *)__pyx_array_getbuffer}, + #endif + {Py_tp_methods, (void *)__pyx_methods_array}, + {Py_tp_getset, (void *)__pyx_getsets_array}, + {Py_tp_new, (void *)__pyx_tp_new_array}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_array_spec = { + "ezdxf.acc.np_support.array", + sizeof(struct __pyx_array_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_SEQUENCE, + __pyx_type___pyx_array_slots, +}; +#else + +static PySequenceMethods __pyx_tp_as_sequence_array = { + __pyx_array___len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_array, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_array = { + __pyx_array___len__, /*mp_length*/ + __pyx_array___getitem__, /*mp_subscript*/ + __pyx_mp_ass_subscript_array, /*mp_ass_subscript*/ +}; + +static PyBufferProcs __pyx_tp_as_buffer_array = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_array_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; + +static PyTypeObject __pyx_type___pyx_array = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.np_support.""array", /*tp_name*/ + sizeof(struct __pyx_array_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_array, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence_array, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_array, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + __pyx_tp_getattro_array, /*tp_getattro*/ + 0, /*tp_setattro*/ + &__pyx_tp_as_buffer_array, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_SEQUENCE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_array, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_array, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_array, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + struct __pyx_MemviewEnum_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_MemviewEnum_obj *)o); + p->name = Py_None; Py_INCREF(Py_None); + return o; +} + +static void __pyx_tp_dealloc_Enum(PyObject *o) { + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_Enum) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->name); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_Enum(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + if (p->name) { + e = (*v)(p->name, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_Enum(PyObject *o) { + PyObject* tmp; + struct __pyx_MemviewEnum_obj *p = (struct __pyx_MemviewEnum_obj *)o; + tmp = ((PyObject*)p->name); + p->name = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyObject *__pyx_specialmethod___pyx_MemviewEnum___repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_MemviewEnum___repr__(self); +} + +static PyMethodDef __pyx_methods_Enum[] = { + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_MemviewEnum___repr__, METH_NOARGS|METH_COEXIST, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_MemviewEnum_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_MemviewEnum_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type___pyx_MemviewEnum_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_Enum}, + {Py_tp_repr, (void *)__pyx_MemviewEnum___repr__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_Enum}, + {Py_tp_clear, (void *)__pyx_tp_clear_Enum}, + {Py_tp_methods, (void *)__pyx_methods_Enum}, + {Py_tp_init, (void *)__pyx_MemviewEnum___init__}, + {Py_tp_new, (void *)__pyx_tp_new_Enum}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_MemviewEnum_spec = { + "ezdxf.acc.np_support.Enum", + sizeof(struct __pyx_MemviewEnum_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type___pyx_MemviewEnum_slots, +}; +#else + +static PyTypeObject __pyx_type___pyx_MemviewEnum = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.np_support.""Enum", /*tp_name*/ + sizeof(struct __pyx_MemviewEnum_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_Enum, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_MemviewEnum___repr__, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_Enum, /*tp_traverse*/ + __pyx_tp_clear_Enum, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_Enum, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + __pyx_MemviewEnum___init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_Enum, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct_memoryview __pyx_vtable_memoryview; + +static PyObject *__pyx_tp_new_memoryview(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_memoryview_obj *p; + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + p = ((struct __pyx_memoryview_obj *)o); + p->__pyx_vtab = __pyx_vtabptr_memoryview; + p->obj = Py_None; Py_INCREF(Py_None); + p->_size = Py_None; Py_INCREF(Py_None); + p->_array_interface = Py_None; Py_INCREF(Py_None); + p->view.obj = NULL; + if (unlikely(__pyx_memoryview___cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_memoryview(PyObject *o) { + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_memoryview) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_memoryview___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->obj); + Py_CLEAR(p->_size); + Py_CLEAR(p->_array_interface); + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} + +static int __pyx_tp_traverse_memoryview(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + if (p->obj) { + e = (*v)(p->obj, a); if (e) return e; + } + if (p->_size) { + e = (*v)(p->_size, a); if (e) return e; + } + if (p->_array_interface) { + e = (*v)(p->_array_interface, a); if (e) return e; + } + if (p->view.obj) { + e = (*v)(p->view.obj, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_memoryview(PyObject *o) { + PyObject* tmp; + struct __pyx_memoryview_obj *p = (struct __pyx_memoryview_obj *)o; + tmp = ((PyObject*)p->obj); + p->obj = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->_size); + p->_size = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->_array_interface); + p->_array_interface = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + Py_CLEAR(p->view.obj); + return 0; +} +static PyObject *__pyx_sq_item_memoryview(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static int __pyx_mp_ass_subscript_memoryview(PyObject *o, PyObject *i, PyObject *v) { + if (v) { + return __pyx_memoryview___setitem__(o, i, v); + } + else { + __Pyx_TypeName o_type_name; + o_type_name = __Pyx_PyType_GetName(Py_TYPE(o)); + PyErr_Format(PyExc_NotImplementedError, + "Subscript deletion not supported by " __Pyx_FMT_TYPENAME, o_type_name); + __Pyx_DECREF_TypeName(o_type_name); + return -1; + } +} + +static PyObject *__pyx_getprop___pyx_memoryview_T(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_1T_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_base(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4base_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_shape(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_5shape_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_strides(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_7strides_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_suboffsets(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_10suboffsets_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_ndim(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4ndim_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_itemsize(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_8itemsize_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_nbytes(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_6nbytes_1__get__(o); +} + +static PyObject *__pyx_getprop___pyx_memoryview_size(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_15View_dot_MemoryView_10memoryview_4size_1__get__(o); +} + +static PyObject *__pyx_specialmethod___pyx_memoryview___repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_memoryview___repr__(self); +} + +static PyMethodDef __pyx_methods_memoryview[] = { + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_memoryview___repr__, METH_NOARGS|METH_COEXIST, 0}, + {"is_c_contig", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_is_c_contig, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"is_f_contig", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_is_f_contig, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"copy_fortran", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_memoryview_copy_fortran, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryview_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryview_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_memoryview[] = { + {(char *)"T", __pyx_getprop___pyx_memoryview_T, 0, (char *)0, 0}, + {(char *)"base", __pyx_getprop___pyx_memoryview_base, 0, (char *)0, 0}, + {(char *)"shape", __pyx_getprop___pyx_memoryview_shape, 0, (char *)0, 0}, + {(char *)"strides", __pyx_getprop___pyx_memoryview_strides, 0, (char *)0, 0}, + {(char *)"suboffsets", __pyx_getprop___pyx_memoryview_suboffsets, 0, (char *)0, 0}, + {(char *)"ndim", __pyx_getprop___pyx_memoryview_ndim, 0, (char *)0, 0}, + {(char *)"itemsize", __pyx_getprop___pyx_memoryview_itemsize, 0, (char *)0, 0}, + {(char *)"nbytes", __pyx_getprop___pyx_memoryview_nbytes, 0, (char *)0, 0}, + {(char *)"size", __pyx_getprop___pyx_memoryview_size, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +#if !CYTHON_COMPILING_IN_LIMITED_API + +static PyBufferProcs __pyx_tp_as_buffer_memoryview = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_memoryview_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; +#endif +static PyType_Slot __pyx_type___pyx_memoryview_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_memoryview}, + {Py_tp_repr, (void *)__pyx_memoryview___repr__}, + {Py_sq_length, (void *)__pyx_memoryview___len__}, + {Py_sq_item, (void *)__pyx_sq_item_memoryview}, + {Py_mp_length, (void *)__pyx_memoryview___len__}, + {Py_mp_subscript, (void *)__pyx_memoryview___getitem__}, + {Py_mp_ass_subscript, (void *)__pyx_mp_ass_subscript_memoryview}, + {Py_tp_str, (void *)__pyx_memoryview___str__}, + #if defined(Py_bf_getbuffer) + {Py_bf_getbuffer, (void *)__pyx_memoryview_getbuffer}, + #endif + {Py_tp_traverse, (void *)__pyx_tp_traverse_memoryview}, + {Py_tp_clear, (void *)__pyx_tp_clear_memoryview}, + {Py_tp_methods, (void *)__pyx_methods_memoryview}, + {Py_tp_getset, (void *)__pyx_getsets_memoryview}, + {Py_tp_new, (void *)__pyx_tp_new_memoryview}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_memoryview_spec = { + "ezdxf.acc.np_support.memoryview", + sizeof(struct __pyx_memoryview_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + __pyx_type___pyx_memoryview_slots, +}; +#else + +static PySequenceMethods __pyx_tp_as_sequence_memoryview = { + __pyx_memoryview___len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_memoryview, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_memoryview = { + __pyx_memoryview___len__, /*mp_length*/ + __pyx_memoryview___getitem__, /*mp_subscript*/ + __pyx_mp_ass_subscript_memoryview, /*mp_ass_subscript*/ +}; + +static PyBufferProcs __pyx_tp_as_buffer_memoryview = { + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getreadbuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getwritebuffer*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getsegcount*/ + #endif + #if PY_MAJOR_VERSION < 3 + 0, /*bf_getcharbuffer*/ + #endif + __pyx_memoryview_getbuffer, /*bf_getbuffer*/ + 0, /*bf_releasebuffer*/ +}; + +static PyTypeObject __pyx_type___pyx_memoryview = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.np_support.""memoryview", /*tp_name*/ + sizeof(struct __pyx_memoryview_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_memoryview, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_memoryview___repr__, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence_memoryview, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_memoryview, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_memoryview___str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &__pyx_tp_as_buffer_memoryview, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_memoryview, /*tp_traverse*/ + __pyx_tp_clear_memoryview, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_memoryview, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_memoryview, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_memoryview, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif +static struct __pyx_vtabstruct__memoryviewslice __pyx_vtable__memoryviewslice; + +static PyObject *__pyx_tp_new__memoryviewslice(PyTypeObject *t, PyObject *a, PyObject *k) { + struct __pyx_memoryviewslice_obj *p; + PyObject *o = __pyx_tp_new_memoryview(t, a, k); + if (unlikely(!o)) return 0; + p = ((struct __pyx_memoryviewslice_obj *)o); + p->__pyx_base.__pyx_vtab = (struct __pyx_vtabstruct_memoryview*)__pyx_vtabptr__memoryviewslice; + p->from_object = Py_None; Py_INCREF(Py_None); + p->from_slice.memview = NULL; + return o; +} + +static void __pyx_tp_dealloc__memoryviewslice(PyObject *o) { + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc__memoryviewslice) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_memoryviewslice___dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->from_object); + PyObject_GC_Track(o); + __pyx_tp_dealloc_memoryview(o); +} + +static int __pyx_tp_traverse__memoryviewslice(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + e = __pyx_tp_traverse_memoryview(o, v, a); if (e) return e; + if (p->from_object) { + e = (*v)(p->from_object, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear__memoryviewslice(PyObject *o) { + PyObject* tmp; + struct __pyx_memoryviewslice_obj *p = (struct __pyx_memoryviewslice_obj *)o; + __pyx_tp_clear_memoryview(o); + tmp = ((PyObject*)p->from_object); + p->from_object = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + __PYX_XCLEAR_MEMVIEW(&p->from_slice, 1); + return 0; +} + +static PyMethodDef __pyx_methods__memoryviewslice[] = { + {"__reduce_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryviewslice_1__reduce_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__setstate_cython__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw___pyx_memoryviewslice_3__setstate_cython__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type___pyx_memoryviewslice_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc__memoryviewslice}, + {Py_tp_doc, (void *)PyDoc_STR("Internal class for passing memoryview slices to Python")}, + {Py_tp_traverse, (void *)__pyx_tp_traverse__memoryviewslice}, + {Py_tp_clear, (void *)__pyx_tp_clear__memoryviewslice}, + {Py_tp_methods, (void *)__pyx_methods__memoryviewslice}, + {Py_tp_new, (void *)__pyx_tp_new__memoryviewslice}, + {0, 0}, +}; +static PyType_Spec __pyx_type___pyx_memoryviewslice_spec = { + "ezdxf.acc.np_support._memoryviewslice", + sizeof(struct __pyx_memoryviewslice_obj), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_SEQUENCE, + __pyx_type___pyx_memoryviewslice_slots, +}; +#else + +static PyTypeObject __pyx_type___pyx_memoryviewslice = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.np_support.""_memoryviewslice", /*tp_name*/ + sizeof(struct __pyx_memoryviewslice_obj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc__memoryviewslice, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + #if CYTHON_COMPILING_IN_PYPY || 0 + __pyx_memoryview___repr__, /*tp_repr*/ + #else + 0, /*tp_repr*/ + #endif + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + #if CYTHON_COMPILING_IN_PYPY || 0 + __pyx_memoryview___str__, /*tp_str*/ + #else + 0, /*tp_str*/ + #endif + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_SEQUENCE, /*tp_flags*/ + PyDoc_STR("Internal class for passing memoryview slices to Python"), /*tp_doc*/ + __pyx_tp_traverse__memoryviewslice, /*tp_traverse*/ + __pyx_tp_clear__memoryviewslice, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods__memoryviewslice, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new__memoryviewslice, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_u_, __pyx_k_, sizeof(__pyx_k_), 0, 1, 0, 0}, + {&__pyx_n_s_A, __pyx_k_A, sizeof(__pyx_k_A), 0, 0, 1, 1}, + {&__pyx_n_s_ASCII, __pyx_k_ASCII, sizeof(__pyx_k_ASCII), 0, 0, 1, 1}, + {&__pyx_kp_s_All_dimensions_preceding_dimensi, __pyx_k_All_dimensions_preceding_dimensi, sizeof(__pyx_k_All_dimensions_preceding_dimensi), 0, 0, 1, 0}, + {&__pyx_n_s_AssertionError, __pyx_k_AssertionError, sizeof(__pyx_k_AssertionError), 0, 0, 1, 1}, + {&__pyx_kp_u_At_least_3_vertices_required, __pyx_k_At_least_3_vertices_required, sizeof(__pyx_k_At_least_3_vertices_required), 0, 1, 0, 0}, + {&__pyx_kp_s_Buffer_view_does_not_expose_stri, __pyx_k_Buffer_view_does_not_expose_stri, sizeof(__pyx_k_Buffer_view_does_not_expose_stri), 0, 0, 1, 0}, + {&__pyx_kp_s_Can_only_create_a_buffer_that_is, __pyx_k_Can_only_create_a_buffer_that_is, sizeof(__pyx_k_Can_only_create_a_buffer_that_is), 0, 0, 1, 0}, + {&__pyx_kp_s_Cannot_assign_to_read_only_memor, __pyx_k_Cannot_assign_to_read_only_memor, sizeof(__pyx_k_Cannot_assign_to_read_only_memor), 0, 0, 1, 0}, + {&__pyx_kp_s_Cannot_create_writable_memory_vi, __pyx_k_Cannot_create_writable_memory_vi, sizeof(__pyx_k_Cannot_create_writable_memory_vi), 0, 0, 1, 0}, + {&__pyx_kp_u_Cannot_index_with_type, __pyx_k_Cannot_index_with_type, sizeof(__pyx_k_Cannot_index_with_type), 0, 1, 0, 0}, + {&__pyx_kp_s_Cannot_transpose_memoryview_with, __pyx_k_Cannot_transpose_memoryview_with, sizeof(__pyx_k_Cannot_transpose_memoryview_with), 0, 0, 1, 0}, + {&__pyx_kp_s_Dimension_d_is_not_direct, __pyx_k_Dimension_d_is_not_direct, sizeof(__pyx_k_Dimension_d_is_not_direct), 0, 0, 1, 0}, + {&__pyx_n_s_Ellipsis, __pyx_k_Ellipsis, sizeof(__pyx_k_Ellipsis), 0, 0, 1, 1}, + {&__pyx_kp_s_Empty_shape_tuple_for_cython_arr, __pyx_k_Empty_shape_tuple_for_cython_arr, sizeof(__pyx_k_Empty_shape_tuple_for_cython_arr), 0, 0, 1, 0}, + {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_k_Incompatible_checksums_0x_x_vs_0, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0), 0, 0, 1, 0}, + {&__pyx_n_s_IndexError, __pyx_k_IndexError, sizeof(__pyx_k_IndexError), 0, 0, 1, 1}, + {&__pyx_kp_s_Index_out_of_bounds_axis_d, __pyx_k_Index_out_of_bounds_axis_d, sizeof(__pyx_k_Index_out_of_bounds_axis_d), 0, 0, 1, 0}, + {&__pyx_kp_s_Indirect_dimensions_not_supporte, __pyx_k_Indirect_dimensions_not_supporte, sizeof(__pyx_k_Indirect_dimensions_not_supporte), 0, 0, 1, 0}, + {&__pyx_kp_u_Invalid_mode_expected_c_or_fortr, __pyx_k_Invalid_mode_expected_c_or_fortr, sizeof(__pyx_k_Invalid_mode_expected_c_or_fortr), 0, 1, 0, 0}, + {&__pyx_kp_u_Invalid_shape_in_axis, __pyx_k_Invalid_shape_in_axis, sizeof(__pyx_k_Invalid_shape_in_axis), 0, 1, 0, 0}, + {&__pyx_kp_u_Item_count_of_vector_x_has_to_ma, __pyx_k_Item_count_of_vector_x_has_to_ma, sizeof(__pyx_k_Item_count_of_vector_x_has_to_ma), 0, 1, 0, 0}, + {&__pyx_n_s_MemoryError, __pyx_k_MemoryError, sizeof(__pyx_k_MemoryError), 0, 0, 1, 1}, + {&__pyx_kp_s_MemoryView_of_r_at_0x_x, __pyx_k_MemoryView_of_r_at_0x_x, sizeof(__pyx_k_MemoryView_of_r_at_0x_x), 0, 0, 1, 0}, + {&__pyx_kp_s_MemoryView_of_r_object, __pyx_k_MemoryView_of_r_object, sizeof(__pyx_k_MemoryView_of_r_object), 0, 0, 1, 0}, + {&__pyx_n_s_NDArray, __pyx_k_NDArray, sizeof(__pyx_k_NDArray), 0, 0, 1, 1}, + {&__pyx_n_b_O, __pyx_k_O, sizeof(__pyx_k_O), 0, 0, 0, 1}, + {&__pyx_kp_u_Out_of_bounds_on_buffer_access_a, __pyx_k_Out_of_bounds_on_buffer_access_a, sizeof(__pyx_k_Out_of_bounds_on_buffer_access_a), 0, 1, 0, 0}, + {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_kp_s_Step_may_not_be_zero_axis_d, __pyx_k_Step_may_not_be_zero_axis_d, sizeof(__pyx_k_Step_may_not_be_zero_axis_d), 0, 0, 1, 0}, + {&__pyx_n_s_TypeAlias, __pyx_k_TypeAlias, sizeof(__pyx_k_TypeAlias), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_kp_s_Unable_to_convert_item_to_object, __pyx_k_Unable_to_convert_item_to_object, sizeof(__pyx_k_Unable_to_convert_item_to_object), 0, 0, 1, 0}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_View_MemoryView, __pyx_k_View_MemoryView, sizeof(__pyx_k_View_MemoryView), 0, 0, 1, 1}, + {&__pyx_kp_u__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0, 0}, + {&__pyx_n_s__29, __pyx_k__29, sizeof(__pyx_k__29), 0, 0, 1, 1}, + {&__pyx_n_s__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 0, 1, 1}, + {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0}, + {&__pyx_kp_u__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 1, 0, 0}, + {&__pyx_n_s_abc, __pyx_k_abc, sizeof(__pyx_k_abc), 0, 0, 1, 1}, + {&__pyx_n_s_allocate_buffer, __pyx_k_allocate_buffer, sizeof(__pyx_k_allocate_buffer), 0, 0, 1, 1}, + {&__pyx_kp_u_and, __pyx_k_and, sizeof(__pyx_k_and), 0, 1, 0, 0}, + {&__pyx_n_s_array, __pyx_k_array, sizeof(__pyx_k_array), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_base, __pyx_k_base, sizeof(__pyx_k_base), 0, 0, 1, 1}, + {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1}, + {&__pyx_n_s_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 0, 1, 1}, + {&__pyx_n_u_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 1, 0, 1}, + {&__pyx_n_s_class, __pyx_k_class, sizeof(__pyx_k_class), 0, 0, 1, 1}, + {&__pyx_n_s_class_getitem, __pyx_k_class_getitem, sizeof(__pyx_k_class_getitem), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_collections, __pyx_k_collections, sizeof(__pyx_k_collections), 0, 0, 1, 1}, + {&__pyx_kp_s_collections_abc, __pyx_k_collections_abc, sizeof(__pyx_k_collections_abc), 0, 0, 1, 0}, + {&__pyx_kp_s_contiguous_and_direct, __pyx_k_contiguous_and_direct, sizeof(__pyx_k_contiguous_and_direct), 0, 0, 1, 0}, + {&__pyx_kp_s_contiguous_and_indirect, __pyx_k_contiguous_and_indirect, sizeof(__pyx_k_contiguous_and_indirect), 0, 0, 1, 0}, + {&__pyx_n_s_count, __pyx_k_count, sizeof(__pyx_k_count), 0, 0, 1, 1}, + {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1}, + {&__pyx_n_s_dtype_is_object, __pyx_k_dtype_is_object, sizeof(__pyx_k_dtype_is_object), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1}, + {&__pyx_n_s_enumerate, __pyx_k_enumerate, sizeof(__pyx_k_enumerate), 0, 0, 1, 1}, + {&__pyx_n_s_error, __pyx_k_error, sizeof(__pyx_k_error), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_acc_np_support, __pyx_k_ezdxf_acc_np_support, sizeof(__pyx_k_ezdxf_acc_np_support), 0, 0, 1, 1}, + {&__pyx_n_s_flags, __pyx_k_flags, sizeof(__pyx_k_flags), 0, 0, 1, 1}, + {&__pyx_n_s_float64, __pyx_k_float64, sizeof(__pyx_k_float64), 0, 0, 1, 1}, + {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1}, + {&__pyx_n_s_fortran, __pyx_k_fortran, sizeof(__pyx_k_fortran), 0, 0, 1, 1}, + {&__pyx_n_u_fortran, __pyx_k_fortran, sizeof(__pyx_k_fortran), 0, 1, 0, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_kp_u_got, __pyx_k_got, sizeof(__pyx_k_got), 0, 1, 0, 0}, + {&__pyx_kp_u_got_differing_extents_in_dimensi, __pyx_k_got_differing_extents_in_dimensi, sizeof(__pyx_k_got_differing_extents_in_dimensi), 0, 1, 0, 0}, + {&__pyx_n_s_has_clockwise_orientation, __pyx_k_has_clockwise_orientation, sizeof(__pyx_k_has_clockwise_orientation), 0, 0, 1, 1}, + {&__pyx_n_s_id, __pyx_k_id, sizeof(__pyx_k_id), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_index, __pyx_k_index, sizeof(__pyx_k_index), 0, 0, 1, 1}, + {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_n_s_int32, __pyx_k_int32, sizeof(__pyx_k_int32), 0, 0, 1, 1}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_itemsize, __pyx_k_itemsize, sizeof(__pyx_k_itemsize), 0, 0, 1, 1}, + {&__pyx_kp_s_itemsize_0_for_cython_array, __pyx_k_itemsize_0_for_cython_array, sizeof(__pyx_k_itemsize_0_for_cython_array), 0, 0, 1, 0}, + {&__pyx_n_s_lower, __pyx_k_lower, sizeof(__pyx_k_lower), 0, 0, 1, 1}, + {&__pyx_n_s_lu_decompose, __pyx_k_lu_decompose, sizeof(__pyx_k_lu_decompose), 0, 0, 1, 1}, + {&__pyx_n_s_m1, __pyx_k_m1, sizeof(__pyx_k_m1), 0, 0, 1, 1}, + {&__pyx_n_s_m2, __pyx_k_m2, sizeof(__pyx_k_m2), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_memview, __pyx_k_memview, sizeof(__pyx_k_memview), 0, 0, 1, 1}, + {&__pyx_n_s_mode, __pyx_k_mode, sizeof(__pyx_k_mode), 0, 0, 1, 1}, + {&__pyx_n_s_n, __pyx_k_n, sizeof(__pyx_k_n), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, + {&__pyx_n_s_ndim, __pyx_k_ndim, sizeof(__pyx_k_ndim), 0, 0, 1, 1}, + {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, + {&__pyx_kp_s_np_ndarray, __pyx_k_np_ndarray, sizeof(__pyx_k_np_ndarray), 0, 0, 1, 0}, + {&__pyx_n_s_npt, __pyx_k_npt, sizeof(__pyx_k_npt), 0, 0, 1, 1}, + {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, + {&__pyx_n_s_numpy_typing, __pyx_k_numpy_typing, sizeof(__pyx_k_numpy_typing), 0, 0, 1, 1}, + {&__pyx_n_s_obj, __pyx_k_obj, sizeof(__pyx_k_obj), 0, 0, 1, 1}, + {&__pyx_n_s_pack, __pyx_k_pack, sizeof(__pyx_k_pack), 0, 0, 1, 1}, + {&__pyx_n_s_pickle, __pyx_k_pickle, sizeof(__pyx_k_pickle), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_PickleError, __pyx_k_pyx_PickleError, sizeof(__pyx_k_pyx_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_checksum, __pyx_k_pyx_checksum, sizeof(__pyx_k_pyx_checksum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_result, __pyx_k_pyx_result, sizeof(__pyx_k_pyx_result), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_type, __pyx_k_pyx_type, sizeof(__pyx_k_pyx_type), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_unpickle_Enum, __pyx_k_pyx_unpickle_Enum, sizeof(__pyx_k_pyx_unpickle_Enum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_register, __pyx_k_register, sizeof(__pyx_k_register), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1}, + {&__pyx_n_s_size, __pyx_k_size, sizeof(__pyx_k_size), 0, 0, 1, 1}, + {&__pyx_n_s_solve_vector_banded_matrix, __pyx_k_solve_vector_banded_matrix, sizeof(__pyx_k_solve_vector_banded_matrix), 0, 0, 1, 1}, + {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_np_support_pyx, __pyx_k_src_ezdxf_acc_np_support_pyx, sizeof(__pyx_k_src_ezdxf_acc_np_support_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1}, + {&__pyx_n_s_step, __pyx_k_step, sizeof(__pyx_k_step), 0, 0, 1, 1}, + {&__pyx_n_s_stop, __pyx_k_stop, sizeof(__pyx_k_stop), 0, 0, 1, 1}, + {&__pyx_kp_s_strided_and_direct, __pyx_k_strided_and_direct, sizeof(__pyx_k_strided_and_direct), 0, 0, 1, 0}, + {&__pyx_kp_s_strided_and_direct_or_indirect, __pyx_k_strided_and_direct_or_indirect, sizeof(__pyx_k_strided_and_direct_or_indirect), 0, 0, 1, 0}, + {&__pyx_kp_s_strided_and_indirect, __pyx_k_strided_and_indirect, sizeof(__pyx_k_strided_and_indirect), 0, 0, 1, 0}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_struct, __pyx_k_struct, sizeof(__pyx_k_struct), 0, 0, 1, 1}, + {&__pyx_n_s_sys, __pyx_k_sys, sizeof(__pyx_k_sys), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_kp_s_tuple_NDArray_NDArray_NDArray, __pyx_k_tuple_NDArray_NDArray_NDArray, sizeof(__pyx_k_tuple_NDArray_NDArray_NDArray), 0, 0, 1, 0}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_typing_extensions, __pyx_k_typing_extensions, sizeof(__pyx_k_typing_extensions), 0, 0, 1, 1}, + {&__pyx_kp_s_unable_to_allocate_array_data, __pyx_k_unable_to_allocate_array_data, sizeof(__pyx_k_unable_to_allocate_array_data), 0, 0, 1, 0}, + {&__pyx_kp_s_unable_to_allocate_shape_and_str, __pyx_k_unable_to_allocate_shape_and_str, sizeof(__pyx_k_unable_to_allocate_shape_and_str), 0, 0, 1, 0}, + {&__pyx_n_s_unpack, __pyx_k_unpack, sizeof(__pyx_k_unpack), 0, 0, 1, 1}, + {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, + {&__pyx_n_s_upper, __pyx_k_upper, sizeof(__pyx_k_upper), 0, 0, 1, 1}, + {&__pyx_n_s_version_info, __pyx_k_version_info, sizeof(__pyx_k_version_info), 0, 0, 1, 1}, + {&__pyx_n_s_vertices, __pyx_k_vertices, sizeof(__pyx_k_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_zeros, __pyx_k_zeros, sizeof(__pyx_k_zeros), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 31, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 61, __pyx_L1_error) + __pyx_builtin___import__ = __Pyx_GetBuiltinName(__pyx_n_s_import); if (!__pyx_builtin___import__) __PYX_ERR(1, 100, __pyx_L1_error) + __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(1, 156, __pyx_L1_error) + __pyx_builtin_enumerate = __Pyx_GetBuiltinName(__pyx_n_s_enumerate); if (!__pyx_builtin_enumerate) __PYX_ERR(1, 159, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + __pyx_builtin_AssertionError = __Pyx_GetBuiltinName(__pyx_n_s_AssertionError); if (!__pyx_builtin_AssertionError) __PYX_ERR(1, 373, __pyx_L1_error) + __pyx_builtin_Ellipsis = __Pyx_GetBuiltinName(__pyx_n_s_Ellipsis); if (!__pyx_builtin_Ellipsis) __PYX_ERR(1, 408, __pyx_L1_error) + __pyx_builtin_id = __Pyx_GetBuiltinName(__pyx_n_s_id); if (!__pyx_builtin_id) __PYX_ERR(1, 618, __pyx_L1_error) + __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) __PYX_ERR(1, 914, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "View.MemoryView":582 + * def suboffsets(self): + * if self.view.suboffsets == NULL: + * return (-1,) * self.view.ndim # <<<<<<<<<<<<<< + * + * return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) + */ + __pyx_tuple__4 = PyTuple_New(1); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_INCREF(__pyx_int_neg_1); + __Pyx_GIVEREF(__pyx_int_neg_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_tuple__4, 0, __pyx_int_neg_1)) __PYX_ERR(1, 582, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "View.MemoryView":679 + * tup = index if isinstance(index, tuple) else (index,) + * + * result = [slice(None)] * ndim # <<<<<<<<<<<<<< + * have_slices = False + * seen_ellipsis = False + */ + __pyx_slice__5 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__5)) __PYX_ERR(1, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__5); + __Pyx_GIVEREF(__pyx_slice__5); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0x82a3537, 0x6ae9995, 0xb068931): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError, "Incompatible checksums (0x%x vs (0x82a3537, 0x6ae9995, 0xb068931) = (name))" % __pyx_checksum + */ + __pyx_tuple__8 = PyTuple_Pack(3, __pyx_int_136983863, __pyx_int_112105877, __pyx_int_184977713); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "ezdxf/acc/np_support.pyx":31 + * """ + * if len(vertices) < 3: + * raise ValueError('At least 3 vertices required.') # <<<<<<<<<<<<<< + * + * return _has_clockwise_orientation(vertices, vertices.shape[0]) + */ + __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_u_At_least_3_vertices_required); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 31, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + + /* "ezdxf/acc/np_support.pyx":137 + * x = np.array(x) # copy x because array x gets modified + * if x.shape[0] != n: + * raise ValueError( # <<<<<<<<<<<<<< + * "Item count of vector has to match the row count of matrix ." + * ) + */ + __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_u_Item_count_of_vector_x_has_to_ma); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + __pyx_tuple__11 = PyTuple_Pack(1, __pyx_n_s_sys); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__11); + __Pyx_GIVEREF(__pyx_tuple__11); + __pyx_tuple__12 = PyTuple_Pack(2, __pyx_int_3, __pyx_int_3); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + + /* "View.MemoryView":101 + * try: + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence # <<<<<<<<<<<<<< + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + */ + __pyx_tuple__13 = PyTuple_Pack(1, __pyx_kp_s_collections_abc); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(1, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__13); + __Pyx_GIVEREF(__pyx_tuple__13); + + /* "View.MemoryView":103 + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence # <<<<<<<<<<<<<< + * except: + * + */ + __pyx_tuple__14 = PyTuple_Pack(1, __pyx_n_s_collections); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(1, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + + /* "View.MemoryView":309 + * return self.name + * + * cdef generic = Enum("") # <<<<<<<<<<<<<< + * cdef strided = Enum("") # default + * cdef indirect = Enum("") + */ + __pyx_tuple__15 = PyTuple_Pack(1, __pyx_kp_s_strided_and_direct_or_indirect); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(1, 309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + + /* "View.MemoryView":310 + * + * cdef generic = Enum("") + * cdef strided = Enum("") # default # <<<<<<<<<<<<<< + * cdef indirect = Enum("") + * + */ + __pyx_tuple__16 = PyTuple_Pack(1, __pyx_kp_s_strided_and_direct); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(1, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__16); + __Pyx_GIVEREF(__pyx_tuple__16); + + /* "View.MemoryView":311 + * cdef generic = Enum("") + * cdef strided = Enum("") # default + * cdef indirect = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_tuple__17 = PyTuple_Pack(1, __pyx_kp_s_strided_and_indirect); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + + /* "View.MemoryView":314 + * + * + * cdef contiguous = Enum("") # <<<<<<<<<<<<<< + * cdef indirect_contiguous = Enum("") + * + */ + __pyx_tuple__18 = PyTuple_Pack(1, __pyx_kp_s_contiguous_and_direct); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(1, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + + /* "View.MemoryView":315 + * + * cdef contiguous = Enum("") + * cdef indirect_contiguous = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_tuple__19 = PyTuple_Pack(1, __pyx_kp_s_contiguous_and_indirect); if (unlikely(!__pyx_tuple__19)) __PYX_ERR(1, 315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__19); + __Pyx_GIVEREF(__pyx_tuple__19); + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_tuple__20 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__20); + __Pyx_GIVEREF(__pyx_tuple__20); + __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle_Enum, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(1, 1, __pyx_L1_error) + + /* "ezdxf/acc/np_support.pyx":6 + * from typing_extensions import TypeAlias + * import numpy as np + * import numpy.typing as npt # <<<<<<<<<<<<<< + * + * import cython + */ + __pyx_tuple__22 = PyTuple_Pack(2, __pyx_n_s_numpy, __pyx_n_s_typing); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + + /* "ezdxf/acc/np_support.pyx":19 + * + * + * def has_clockwise_orientation(vertices: np.ndarray) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + __pyx_tuple__23 = PyTuple_Pack(1, __pyx_n_s_vertices); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 19, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__23); + __Pyx_GIVEREF(__pyx_tuple__23); + __pyx_codeobj__24 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__23, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_np_support_pyx, __pyx_n_s_has_clockwise_orientation, 19, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__24)) __PYX_ERR(0, 19, __pyx_L1_error) + + /* "ezdxf/acc/np_support.pyx":70 + * + * + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: # <<<<<<<<<<<<<< + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] + */ + __pyx_tuple__25 = PyTuple_Pack(7, __pyx_n_s_A, __pyx_n_s_m1, __pyx_n_s_m2, __pyx_n_s_upper, __pyx_n_s_n, __pyx_n_s_lower, __pyx_n_s_index); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__25); + __Pyx_GIVEREF(__pyx_tuple__25); + __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_np_support_pyx, __pyx_n_s_lu_decompose, 70, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 70, __pyx_L1_error) + + /* "ezdxf/acc/np_support.pyx":126 + * + * + * def solve_vector_banded_matrix( # <<<<<<<<<<<<<< + * x: NDArray, + * upper: NDArray, + */ + __pyx_tuple__27 = PyTuple_Pack(7, __pyx_n_s_x, __pyx_n_s_upper, __pyx_n_s_lower, __pyx_n_s_index, __pyx_n_s_m1, __pyx_n_s_m2, __pyx_n_s_n); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(6, 0, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_np_support_pyx, __pyx_n_s_solve_vector_banded_matrix, 126, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_112105877 = PyInt_FromLong(112105877L); if (unlikely(!__pyx_int_112105877)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_136983863 = PyInt_FromLong(136983863L); if (unlikely(!__pyx_int_136983863)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_184977713 = PyInt_FromLong(184977713L); if (unlikely(!__pyx_int_184977713)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + /* AssertionsEnabled.init */ + if (likely(__Pyx_init_assertions_enabled() == 0)); else + +if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __pyx_collections_abc_Sequence = Py_None; Py_INCREF(Py_None); + generic = Py_None; Py_INCREF(Py_None); + strided = Py_None; Py_INCREF(Py_None); + indirect = Py_None; Py_INCREF(Py_None); + contiguous = Py_None; Py_INCREF(Py_None); + indirect_contiguous = Py_None; Py_INCREF(Py_None); + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_vtabptr_array = &__pyx_vtable_array; + __pyx_vtable_array.get_memview = (PyObject *(*)(struct __pyx_array_obj *))__pyx_array_get_memview; + #if CYTHON_USE_TYPE_SPECS + __pyx_array_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_array_spec, NULL); if (unlikely(!__pyx_array_type)) __PYX_ERR(1, 114, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_array_type->tp_as_buffer = &__pyx_tp_as_buffer_array; + if (!__pyx_array_type->tp_as_buffer->bf_releasebuffer && __pyx_array_type->tp_base->tp_as_buffer && __pyx_array_type->tp_base->tp_as_buffer->bf_releasebuffer) { + __pyx_array_type->tp_as_buffer->bf_releasebuffer = __pyx_array_type->tp_base->tp_as_buffer->bf_releasebuffer; + } + #elif defined(Py_bf_getbuffer) && defined(Py_bf_releasebuffer) + /* PY_VERSION_HEX >= 0x03090000 || Py_LIMITED_API >= 0x030B0000 */ + #elif defined(_MSC_VER) + #pragma message ("The buffer protocol is not supported in the Limited C-API < 3.11.") + #else + #warning "The buffer protocol is not supported in the Limited C-API < 3.11." + #endif + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_array_spec, __pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #else + __pyx_array_type = &__pyx_type___pyx_array; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_array_type->tp_print = 0; + #endif + if (__Pyx_SetVtable(__pyx_array_type, __pyx_vtabptr_array) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_array_type) < 0) __PYX_ERR(1, 114, __pyx_L1_error) + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_MemviewEnum_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_MemviewEnum_spec, NULL); if (unlikely(!__pyx_MemviewEnum_type)) __PYX_ERR(1, 302, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_MemviewEnum_spec, __pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #else + __pyx_MemviewEnum_type = &__pyx_type___pyx_MemviewEnum; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_MemviewEnum_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_MemviewEnum_type->tp_dictoffset && __pyx_MemviewEnum_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_MemviewEnum_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_MemviewEnum_type) < 0) __PYX_ERR(1, 302, __pyx_L1_error) + #endif + __pyx_vtabptr_memoryview = &__pyx_vtable_memoryview; + __pyx_vtable_memoryview.get_item_pointer = (char *(*)(struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_get_item_pointer; + __pyx_vtable_memoryview.is_slice = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_is_slice; + __pyx_vtable_memoryview.setitem_slice_assignment = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *, PyObject *))__pyx_memoryview_setitem_slice_assignment; + __pyx_vtable_memoryview.setitem_slice_assign_scalar = (PyObject *(*)(struct __pyx_memoryview_obj *, struct __pyx_memoryview_obj *, PyObject *))__pyx_memoryview_setitem_slice_assign_scalar; + __pyx_vtable_memoryview.setitem_indexed = (PyObject *(*)(struct __pyx_memoryview_obj *, PyObject *, PyObject *))__pyx_memoryview_setitem_indexed; + __pyx_vtable_memoryview.convert_item_to_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *))__pyx_memoryview_convert_item_to_object; + __pyx_vtable_memoryview.assign_item_from_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *, PyObject *))__pyx_memoryview_assign_item_from_object; + __pyx_vtable_memoryview._get_base = (PyObject *(*)(struct __pyx_memoryview_obj *))__pyx_memoryview__get_base; + #if CYTHON_USE_TYPE_SPECS + __pyx_memoryview_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_memoryview_spec, NULL); if (unlikely(!__pyx_memoryview_type)) __PYX_ERR(1, 337, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_memoryview_type->tp_as_buffer = &__pyx_tp_as_buffer_memoryview; + if (!__pyx_memoryview_type->tp_as_buffer->bf_releasebuffer && __pyx_memoryview_type->tp_base->tp_as_buffer && __pyx_memoryview_type->tp_base->tp_as_buffer->bf_releasebuffer) { + __pyx_memoryview_type->tp_as_buffer->bf_releasebuffer = __pyx_memoryview_type->tp_base->tp_as_buffer->bf_releasebuffer; + } + #elif defined(Py_bf_getbuffer) && defined(Py_bf_releasebuffer) + /* PY_VERSION_HEX >= 0x03090000 || Py_LIMITED_API >= 0x030B0000 */ + #elif defined(_MSC_VER) + #pragma message ("The buffer protocol is not supported in the Limited C-API < 3.11.") + #else + #warning "The buffer protocol is not supported in the Limited C-API < 3.11." + #endif + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_memoryview_spec, __pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #else + __pyx_memoryview_type = &__pyx_type___pyx_memoryview; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_memoryview_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_memoryview_type->tp_dictoffset && __pyx_memoryview_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_memoryview_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_memoryview_type, __pyx_vtabptr_memoryview) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_memoryview_type) < 0) __PYX_ERR(1, 337, __pyx_L1_error) + #endif + __pyx_vtabptr__memoryviewslice = &__pyx_vtable__memoryviewslice; + __pyx_vtable__memoryviewslice.__pyx_base = *__pyx_vtabptr_memoryview; + __pyx_vtable__memoryviewslice.__pyx_base.convert_item_to_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *))__pyx_memoryviewslice_convert_item_to_object; + __pyx_vtable__memoryviewslice.__pyx_base.assign_item_from_object = (PyObject *(*)(struct __pyx_memoryview_obj *, char *, PyObject *))__pyx_memoryviewslice_assign_item_from_object; + __pyx_vtable__memoryviewslice.__pyx_base._get_base = (PyObject *(*)(struct __pyx_memoryview_obj *))__pyx_memoryviewslice__get_base; + #if CYTHON_USE_TYPE_SPECS + __pyx_t_1 = PyTuple_Pack(1, (PyObject *)__pyx_memoryview_type); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 952, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_memoryviewslice_type = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type___pyx_memoryviewslice_spec, __pyx_t_1); + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(!__pyx_memoryviewslice_type)) __PYX_ERR(1, 952, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type___pyx_memoryviewslice_spec, __pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #else + __pyx_memoryviewslice_type = &__pyx_type___pyx_memoryviewslice; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + __pyx_memoryviewslice_type->tp_base = __pyx_memoryview_type; + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_memoryviewslice_type->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_memoryviewslice_type->tp_dictoffset && __pyx_memoryviewslice_type->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_memoryviewslice_type->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (__Pyx_SetVtable(__pyx_memoryviewslice_type, __pyx_vtabptr__memoryviewslice) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_MergeVtables(__pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if (__Pyx_setup_reduce((PyObject *) __pyx_memoryviewslice_type) < 0) __PYX_ERR(1, 952, __pyx_L1_error) + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec2", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec2) __PYX_ERR(2, 9, __pyx_L1_error) + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = __Pyx_ImportType_3_0_11(__pyx_t_1, "ezdxf.acc.vector", "Vec3", sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), __PYX_GET_STRUCT_ALIGNMENT_3_0_11(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3),__Pyx_ImportType_CheckSize_Warn_3_0_11); if (!__pyx_ptype_5ezdxf_3acc_6vector_Vec3) __PYX_ERR(2, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __pyx_t_1 = PyImport_ImportModule("ezdxf.acc.vector"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_ImportFunction_3_0_11(__pyx_t_1, "isclose", (void (**)(void))&__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_np_support(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_np_support}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "np_support", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initnp_support(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initnp_support(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_np_support(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_np_support(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_np_support(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + static PyThread_type_lock __pyx_t_8[8]; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'np_support' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("np_support", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "np_support" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_np_support(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__np_support) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name_2, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.np_support")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.np_support", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_variable_import_code(); + if (unlikely((__Pyx_modinit_function_import_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_version_info); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyObject_RichCompare(__pyx_t_5, __pyx_tuple__12, Py_GE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 100, __pyx_L2_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + + /* "View.MemoryView":101 + * try: + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence # <<<<<<<<<<<<<< + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__13, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_abc); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 101, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + + /* "View.MemoryView":100 + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: + * if __import__("sys").version_info >= (3, 3): # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + */ + goto __pyx_L8; + } + + /* "View.MemoryView":103 + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence # <<<<<<<<<<<<<< + * except: + * + */ + /*else*/ { + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin___import__, __pyx_tuple__14, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 103, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 103, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + } + __pyx_L8:; + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L7_try_end; + __pyx_L2_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "View.MemoryView":104 + * else: + * __pyx_collections_abc_Sequence = __import__("collections").Sequence + * except: # <<<<<<<<<<<<<< + * + * __pyx_collections_abc_Sequence = None + */ + /*except:*/ { + __Pyx_AddTraceback("View.MemoryView", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_4, &__pyx_t_7) < 0) __PYX_ERR(1, 104, __pyx_L4_except_error) + __Pyx_XGOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_7); + + /* "View.MemoryView":106 + * except: + * + * __pyx_collections_abc_Sequence = None # <<<<<<<<<<<<<< + * + * + */ + __Pyx_INCREF(Py_None); + __Pyx_XGOTREF(__pyx_collections_abc_Sequence); + __Pyx_DECREF_SET(__pyx_collections_abc_Sequence, Py_None); + __Pyx_GIVEREF(Py_None); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L3_exception_handled; + } + + /* "View.MemoryView":99 + * + * cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence" + * try: # <<<<<<<<<<<<<< + * if __import__("sys").version_info >= (3, 3): + * __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence + */ + __pyx_L4_except_error:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L3_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + __pyx_L7_try_end:; + } + + /* "View.MemoryView":241 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_2, &__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_1); + /*try:*/ { + + /* "View.MemoryView":242 + * + * try: + * count = __pyx_collections_abc_Sequence.count # <<<<<<<<<<<<<< + * index = __pyx_collections_abc_Sequence.index + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_count); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 242, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_array_type, __pyx_n_s_count, __pyx_t_7) < 0) __PYX_ERR(1, 242, __pyx_L11_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_array_type); + + /* "View.MemoryView":243 + * try: + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index # <<<<<<<<<<<<<< + * except: + * pass + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_index); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 243, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_array_type, __pyx_n_s_index, __pyx_t_7) < 0) __PYX_ERR(1, 243, __pyx_L11_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_array_type); + + /* "View.MemoryView":241 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L16_try_end; + __pyx_L11_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":244 + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + * except: # <<<<<<<<<<<<<< + * pass + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L12_exception_handled; + } + __pyx_L12_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_2, __pyx_t_1); + __pyx_L16_try_end:; + } + + /* "View.MemoryView":309 + * return self.name + * + * cdef generic = Enum("") # <<<<<<<<<<<<<< + * cdef strided = Enum("") # default + * cdef indirect = Enum("") + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__15, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(generic); + __Pyx_DECREF_SET(generic, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":310 + * + * cdef generic = Enum("") + * cdef strided = Enum("") # default # <<<<<<<<<<<<<< + * cdef indirect = Enum("") + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__16, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(strided); + __Pyx_DECREF_SET(strided, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":311 + * cdef generic = Enum("") + * cdef strided = Enum("") # default + * cdef indirect = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__17, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(indirect); + __Pyx_DECREF_SET(indirect, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":314 + * + * + * cdef contiguous = Enum("") # <<<<<<<<<<<<<< + * cdef indirect_contiguous = Enum("") + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__18, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(contiguous); + __Pyx_DECREF_SET(contiguous, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":315 + * + * cdef contiguous = Enum("") + * cdef indirect_contiguous = Enum("") # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_7 = __Pyx_PyObject_Call(((PyObject *)__pyx_MemviewEnum_type), __pyx_tuple__19, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_XGOTREF(indirect_contiguous); + __Pyx_DECREF_SET(indirect_contiguous, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_7); + __pyx_t_7 = 0; + + /* "View.MemoryView":323 + * + * + * cdef int __pyx_memoryview_thread_locks_used = 0 # <<<<<<<<<<<<<< + * cdef PyThread_type_lock[8] __pyx_memoryview_thread_locks = [ + * PyThread_allocate_lock(), + */ + __pyx_memoryview_thread_locks_used = 0; + + /* "View.MemoryView":324 + * + * cdef int __pyx_memoryview_thread_locks_used = 0 + * cdef PyThread_type_lock[8] __pyx_memoryview_thread_locks = [ # <<<<<<<<<<<<<< + * PyThread_allocate_lock(), + * PyThread_allocate_lock(), + */ + __pyx_t_8[0] = PyThread_allocate_lock(); + __pyx_t_8[1] = PyThread_allocate_lock(); + __pyx_t_8[2] = PyThread_allocate_lock(); + __pyx_t_8[3] = PyThread_allocate_lock(); + __pyx_t_8[4] = PyThread_allocate_lock(); + __pyx_t_8[5] = PyThread_allocate_lock(); + __pyx_t_8[6] = PyThread_allocate_lock(); + __pyx_t_8[7] = PyThread_allocate_lock(); + memcpy(&(__pyx_memoryview_thread_locks[0]), __pyx_t_8, sizeof(__pyx_memoryview_thread_locks[0]) * (8)); + + /* "View.MemoryView":982 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "View.MemoryView":983 + * + * try: + * count = __pyx_collections_abc_Sequence.count # <<<<<<<<<<<<<< + * index = __pyx_collections_abc_Sequence.index + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_count); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 983, __pyx_L17_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_memoryviewslice_type, __pyx_n_s_count, __pyx_t_7) < 0) __PYX_ERR(1, 983, __pyx_L17_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_memoryviewslice_type); + + /* "View.MemoryView":984 + * try: + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index # <<<<<<<<<<<<<< + * except: + * pass + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_index); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 984, __pyx_L17_error) + __Pyx_GOTREF(__pyx_t_7); + if (__Pyx_SetItemOnTypeDict(__pyx_memoryviewslice_type, __pyx_n_s_index, __pyx_t_7) < 0) __PYX_ERR(1, 984, __pyx_L17_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_memoryviewslice_type); + + /* "View.MemoryView":982 + * + * + * try: # <<<<<<<<<<<<<< + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L22_try_end; + __pyx_L17_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":985 + * count = __pyx_collections_abc_Sequence.count + * index = __pyx_collections_abc_Sequence.index + * except: # <<<<<<<<<<<<<< + * pass + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L18_exception_handled; + } + __pyx_L18_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + __pyx_L22_try_end:; + } + + /* "View.MemoryView":988 + * pass + * + * try: # <<<<<<<<<<<<<< + * if __pyx_collections_abc_Sequence: + * + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_2, &__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_1); + /*try:*/ { + + /* "View.MemoryView":989 + * + * try: + * if __pyx_collections_abc_Sequence: # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_collections_abc_Sequence); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(1, 989, __pyx_L23_error) + if (__pyx_t_6) { + + /* "View.MemoryView":993 + * + * + * __pyx_collections_abc_Sequence.register(_memoryviewslice) # <<<<<<<<<<<<<< + * __pyx_collections_abc_Sequence.register(array) + * except: + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_register); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 993, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, ((PyObject *)__pyx_memoryviewslice_type)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 993, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "View.MemoryView":994 + * + * __pyx_collections_abc_Sequence.register(_memoryviewslice) + * __pyx_collections_abc_Sequence.register(array) # <<<<<<<<<<<<<< + * except: + * pass # ignore failure, it's a minor issue + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_collections_abc_Sequence, __pyx_n_s_register); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 994, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_4, ((PyObject *)__pyx_array_type)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 994, __pyx_L23_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":989 + * + * try: + * if __pyx_collections_abc_Sequence: # <<<<<<<<<<<<<< + * + * + */ + } + + /* "View.MemoryView":988 + * pass + * + * try: # <<<<<<<<<<<<<< + * if __pyx_collections_abc_Sequence: + * + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L28_try_end; + __pyx_L23_error:; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "View.MemoryView":995 + * __pyx_collections_abc_Sequence.register(_memoryviewslice) + * __pyx_collections_abc_Sequence.register(array) + * except: # <<<<<<<<<<<<<< + * pass # ignore failure, it's a minor issue + * + */ + /*except:*/ { + __Pyx_ErrRestore(0,0,0); + goto __pyx_L24_exception_handled; + } + __pyx_L24_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_2, __pyx_t_1); + __pyx_L28_try_end:; + } + + /* "(tree fragment)":1 + * def __pyx_unpickle_Enum(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_t_7 = PyCFunction_NewEx(&__pyx_mdef_15View_dot_MemoryView_1__pyx_unpickle_Enum, NULL, __pyx_n_s_View_MemoryView); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle_Enum, __pyx_t_7) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "ezdxf/acc/np_support.pyx":4 + * # Copyright (c) 2023-2024, Manfred Moitzi + * # License: MIT License + * from typing_extensions import TypeAlias # <<<<<<<<<<<<<< + * import numpy as np + * import numpy.typing as npt + */ + __pyx_t_7 = PyList_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(__pyx_n_s_TypeAlias); + __Pyx_GIVEREF(__pyx_n_s_TypeAlias); + if (__Pyx_PyList_SET_ITEM(__pyx_t_7, 0, __pyx_n_s_TypeAlias)) __PYX_ERR(0, 4, __pyx_L1_error); + __pyx_t_4 = __Pyx_Import(__pyx_n_s_typing_extensions, __pyx_t_7, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_TypeAlias); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TypeAlias, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":5 + * # License: MIT License + * from typing_extensions import TypeAlias + * import numpy as np # <<<<<<<<<<<<<< + * import numpy.typing as npt + * + */ + __pyx_t_4 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_4) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":6 + * from typing_extensions import TypeAlias + * import numpy as np + * import numpy.typing as npt # <<<<<<<<<<<<<< + * + * import cython + */ + __pyx_t_4 = __Pyx_ImportDottedModule(__pyx_n_s_numpy_typing, __pyx_tuple__22); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_npt, __pyx_t_4) < 0) __PYX_ERR(0, 6, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":16 + * + * + * NDArray: TypeAlias = npt.NDArray[np.float64] # <<<<<<<<<<<<<< + * + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_npt); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_NDArray); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_GetItem(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_NDArray, __pyx_t_4) < 0) __PYX_ERR(0, 16, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":19 + * + * + * def has_clockwise_orientation(vertices: np.ndarray) -> bool: # <<<<<<<<<<<<<< + * """ Returns True if 2D `vertices` have clockwise orientation. Ignores + * z-axis of all vertices. + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 19, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_vertices, __pyx_kp_s_np_ndarray) < 0) __PYX_ERR(0, 19, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 19, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_10np_support_1has_clockwise_orientation, 0, __pyx_n_s_has_clockwise_orientation, NULL, __pyx_n_s_ezdxf_acc_np_support, __pyx_d, ((PyObject *)__pyx_codeobj__24)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 19, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_has_clockwise_orientation, __pyx_t_5) < 0) __PYX_ERR(0, 19, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/np_support.pyx":70 + * + * + * def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: # <<<<<<<<<<<<<< + * upper: np.ndarray = np.array(A, dtype=np.float64) + * n: int = upper.shape[0] + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_A, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 70, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_m1, __pyx_n_s_int) < 0) __PYX_ERR(0, 70, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_m2, __pyx_n_s_int) < 0) __PYX_ERR(0, 70, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_tuple_NDArray_NDArray_NDArray) < 0) __PYX_ERR(0, 70, __pyx_L1_error) + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_10np_support_3lu_decompose, 0, __pyx_n_s_lu_decompose, NULL, __pyx_n_s_ezdxf_acc_np_support, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_4, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_lu_decompose, __pyx_t_4) < 0) __PYX_ERR(0, 70, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/np_support.pyx":126 + * + * + * def solve_vector_banded_matrix( # <<<<<<<<<<<<<< + * x: NDArray, + * upper: NDArray, + */ + __pyx_t_4 = __Pyx_PyDict_NewPresized(7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_x, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_upper, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_lower, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_index, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_m1, __pyx_n_s_int) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_m2, __pyx_n_s_int) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_return, __pyx_n_s_NDArray) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_10np_support_5solve_vector_banded_matrix, 0, __pyx_n_s_solve_vector_banded_matrix, NULL, __pyx_n_s_ezdxf_acc_np_support, __pyx_d, ((PyObject *)__pyx_codeobj__28)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_solve_vector_banded_matrix, __pyx_t_5) < 0) __PYX_ERR(0, 126, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/np_support.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # Copyright (c) 2023-2024, Manfred Moitzi + * # License: MIT License + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_5) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.np_support", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.np_support"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* RaiseUnexpectedTypeError */ +static int +__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) +{ + __Pyx_TypeName obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, + expected, obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* CIntToDigits */ +static const char DIGIT_PAIRS_10[2*10*10+1] = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; +static const char DIGIT_PAIRS_8[2*8*8+1] = { + "0001020304050607" + "1011121314151617" + "2021222324252627" + "3031323334353637" + "4041424344454647" + "5051525354555657" + "6061626364656667" + "7071727374757677" +}; +static const char DIGITS_HEX[2*16+1] = { + "0123456789abcdef" + "0123456789ABCDEF" +}; + +/* BuildPyUnicode */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char) { + PyObject *uval; + Py_ssize_t uoffset = ulength - clength; +#if CYTHON_USE_UNICODE_INTERNALS + Py_ssize_t i; +#if CYTHON_PEP393_ENABLED + void *udata; + uval = PyUnicode_New(ulength, 127); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_DATA(uval); +#else + Py_UNICODE *udata; + uval = PyUnicode_FromUnicode(NULL, ulength); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_AS_UNICODE(uval); +#endif + if (uoffset > 0) { + i = 0; + if (prepend_sign) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, 0, '-'); + i++; + } + for (; i < uoffset; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, i, padding_char); + } + } + for (i=0; i < clength; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, uoffset+i, chars[i]); + } +#else + { + PyObject *sign = NULL, *padding = NULL; + uval = NULL; + if (uoffset > 0) { + prepend_sign = !!prepend_sign; + if (uoffset > prepend_sign) { + padding = PyUnicode_FromOrdinal(padding_char); + if (likely(padding) && uoffset > prepend_sign + 1) { + PyObject *tmp; + PyObject *repeat = PyInt_FromSsize_t(uoffset - prepend_sign); + if (unlikely(!repeat)) goto done_or_error; + tmp = PyNumber_Multiply(padding, repeat); + Py_DECREF(repeat); + Py_DECREF(padding); + padding = tmp; + } + if (unlikely(!padding)) goto done_or_error; + } + if (prepend_sign) { + sign = PyUnicode_FromOrdinal('-'); + if (unlikely(!sign)) goto done_or_error; + } + } + uval = PyUnicode_DecodeASCII(chars, clength, NULL); + if (likely(uval) && padding) { + PyObject *tmp = PyNumber_Add(padding, uval); + Py_DECREF(uval); + uval = tmp; + } + if (likely(uval) && sign) { + PyObject *tmp = PyNumber_Add(sign, uval); + Py_DECREF(uval); + uval = tmp; + } +done_or_error: + Py_XDECREF(padding); + Py_XDECREF(sign); + } +#endif + return uval; +} + +/* CIntToPyUnicode */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char) { + char digits[sizeof(int)*3+2]; + char *dpos, *end = digits + sizeof(int)*3+2; + const char *hex_digits = DIGITS_HEX; + Py_ssize_t length, ulength; + int prepend_sign, last_one_off; + int remaining; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (format_char == 'X') { + hex_digits += 16; + format_char = 'x'; + } + remaining = value; + last_one_off = 0; + dpos = end; + do { + int digit_pos; + switch (format_char) { + case 'o': + digit_pos = abs((int)(remaining % (8*8))); + remaining = (int) (remaining / (8*8)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2); + last_one_off = (digit_pos < 8); + break; + case 'd': + digit_pos = abs((int)(remaining % (10*10))); + remaining = (int) (remaining / (10*10)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2); + last_one_off = (digit_pos < 10); + break; + case 'x': + *(--dpos) = hex_digits[abs((int)(remaining % 16))]; + remaining = (int) (remaining / 16); + break; + default: + assert(0); + break; + } + } while (unlikely(remaining != 0)); + assert(!last_one_off || *dpos == '0'); + dpos += last_one_off; + length = end - dpos; + ulength = length; + prepend_sign = 0; + if (!is_unsigned && value <= neg_one) { + if (padding_char == ' ' || width <= length + 1) { + *(--dpos) = '-'; + ++length; + } else { + prepend_sign = 1; + } + ++ulength; + } + if (width > ulength) { + ulength = width; + } + if (ulength == 1) { + return PyUnicode_FromOrdinal(*dpos); + } + return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char); +} + +/* CIntToPyUnicode */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_Py_ssize_t(Py_ssize_t value, Py_ssize_t width, char padding_char, char format_char) { + char digits[sizeof(Py_ssize_t)*3+2]; + char *dpos, *end = digits + sizeof(Py_ssize_t)*3+2; + const char *hex_digits = DIGITS_HEX; + Py_ssize_t length, ulength; + int prepend_sign, last_one_off; + Py_ssize_t remaining; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const Py_ssize_t neg_one = (Py_ssize_t) -1, const_zero = (Py_ssize_t) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (format_char == 'X') { + hex_digits += 16; + format_char = 'x'; + } + remaining = value; + last_one_off = 0; + dpos = end; + do { + int digit_pos; + switch (format_char) { + case 'o': + digit_pos = abs((int)(remaining % (8*8))); + remaining = (Py_ssize_t) (remaining / (8*8)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2); + last_one_off = (digit_pos < 8); + break; + case 'd': + digit_pos = abs((int)(remaining % (10*10))); + remaining = (Py_ssize_t) (remaining / (10*10)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2); + last_one_off = (digit_pos < 10); + break; + case 'x': + *(--dpos) = hex_digits[abs((int)(remaining % 16))]; + remaining = (Py_ssize_t) (remaining / 16); + break; + default: + assert(0); + break; + } + } while (unlikely(remaining != 0)); + assert(!last_one_off || *dpos == '0'); + dpos += last_one_off; + length = end - dpos; + ulength = length; + prepend_sign = 0; + if (!is_unsigned && value <= neg_one) { + if (padding_char == ' ' || width <= length + 1) { + *(--dpos) = '-'; + ++length; + } else { + prepend_sign = 1; + } + ++ulength; + } + if (width > ulength) { + ulength = width; + } + if (ulength == 1) { + return PyUnicode_FromOrdinal(*dpos); + } + return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char); +} + +/* JoinPyUnicode */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char) { +#if CYTHON_USE_UNICODE_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + PyObject *result_uval; + int result_ukind, kind_shift; + Py_ssize_t i, char_pos; + void *result_udata; + CYTHON_MAYBE_UNUSED_VAR(max_char); +#if CYTHON_PEP393_ENABLED + result_uval = PyUnicode_New(result_ulength, max_char); + if (unlikely(!result_uval)) return NULL; + result_ukind = (max_char <= 255) ? PyUnicode_1BYTE_KIND : (max_char <= 65535) ? PyUnicode_2BYTE_KIND : PyUnicode_4BYTE_KIND; + kind_shift = (result_ukind == PyUnicode_4BYTE_KIND) ? 2 : result_ukind - 1; + result_udata = PyUnicode_DATA(result_uval); +#else + result_uval = PyUnicode_FromUnicode(NULL, result_ulength); + if (unlikely(!result_uval)) return NULL; + result_ukind = sizeof(Py_UNICODE); + kind_shift = (result_ukind == 4) ? 2 : result_ukind - 1; + result_udata = PyUnicode_AS_UNICODE(result_uval); +#endif + assert(kind_shift == 2 || kind_shift == 1 || kind_shift == 0); + char_pos = 0; + for (i=0; i < value_count; i++) { + int ukind; + Py_ssize_t ulength; + void *udata; + PyObject *uval = PyTuple_GET_ITEM(value_tuple, i); + if (unlikely(__Pyx_PyUnicode_READY(uval))) + goto bad; + ulength = __Pyx_PyUnicode_GET_LENGTH(uval); + if (unlikely(!ulength)) + continue; + if (unlikely((PY_SSIZE_T_MAX >> kind_shift) - ulength < char_pos)) + goto overflow; + ukind = __Pyx_PyUnicode_KIND(uval); + udata = __Pyx_PyUnicode_DATA(uval); + if (!CYTHON_PEP393_ENABLED || ukind == result_ukind) { + memcpy((char *)result_udata + (char_pos << kind_shift), udata, (size_t) (ulength << kind_shift)); + } else { + #if PY_VERSION_HEX >= 0x030d0000 + if (unlikely(PyUnicode_CopyCharacters(result_uval, char_pos, uval, 0, ulength) < 0)) goto bad; + #elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030300F0 || defined(_PyUnicode_FastCopyCharacters) + _PyUnicode_FastCopyCharacters(result_uval, char_pos, uval, 0, ulength); + #else + Py_ssize_t j; + for (j=0; j < ulength; j++) { + Py_UCS4 uchar = __Pyx_PyUnicode_READ(ukind, udata, j); + __Pyx_PyUnicode_WRITE(result_ukind, result_udata, char_pos+j, uchar); + } + #endif + } + char_pos += ulength; + } + return result_uval; +overflow: + PyErr_SetString(PyExc_OverflowError, "join() result is too long for a Python string"); +bad: + Py_DECREF(result_uval); + return NULL; +#else + CYTHON_UNUSED_VAR(max_char); + CYTHON_UNUSED_VAR(result_ulength); + CYTHON_UNUSED_VAR(value_count); + return PyUnicode_Join(__pyx_empty_unicode, value_tuple); +#endif +} + +/* GetAttr */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { +#if CYTHON_USE_TYPE_SLOTS +#if PY_MAJOR_VERSION >= 3 + if (likely(PyUnicode_Check(n))) +#else + if (likely(PyString_Check(n))) +#endif + return __Pyx_PyObject_GetAttrStr(o, n); +#endif + return PyObject_GetAttr(o, n); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* ObjectGetItem */ +#if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject *index) { + PyObject *runerr = NULL; + Py_ssize_t key_value; + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + __Pyx_TypeName index_type_name = __Pyx_PyType_GetName(Py_TYPE(index)); + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, + "cannot fit '" __Pyx_FMT_TYPENAME "' into an index-sized integer", index_type_name); + __Pyx_DECREF_TypeName(index_type_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem_Slow(PyObject *obj, PyObject *key) { + __Pyx_TypeName obj_type_name; + if (likely(PyType_Check(obj))) { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(obj, __pyx_n_s_class_getitem); + if (!meth) { + PyErr_Clear(); + } else { + PyObject *result = __Pyx_PyObject_CallOneArg(meth, key); + Py_DECREF(meth); + return result; + } + } + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "'" __Pyx_FMT_TYPENAME "' object is not subscriptable", obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key) { + PyTypeObject *tp = Py_TYPE(obj); + PyMappingMethods *mm = tp->tp_as_mapping; + PySequenceMethods *sm = tp->tp_as_sequence; + if (likely(mm && mm->mp_subscript)) { + return mm->mp_subscript(obj, key); + } + if (likely(sm && sm->sq_item)) { + return __Pyx_PyObject_GetIndex(obj, key); + } + return __Pyx_PyObject_GetItem_Slow(obj, key); +} +#endif + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* DivInt[Py_ssize_t] */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t a, Py_ssize_t b) { + Py_ssize_t q = a / b; + Py_ssize_t r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* GetAttr3 */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static PyObject *__Pyx_GetAttr3Default(PyObject *d) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (unlikely(!__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + __Pyx_PyErr_Clear(); + Py_INCREF(d); + return d; +} +#endif +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { + PyObject *r; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + int res = PyObject_GetOptionalAttr(o, n, &r); + return (res != 0) ? r : __Pyx_NewRef(d); +#else + #if CYTHON_USE_TYPE_SLOTS + if (likely(PyString_Check(n))) { + r = __Pyx_PyObject_GetAttrStrNoError(o, n); + if (unlikely(!r) && likely(!PyErr_Occurred())) { + r = __Pyx_NewRef(d); + } + return r; + } + #endif + r = PyObject_GetAttr(o, n); + return (likely(r)) ? r : __Pyx_GetAttr3Default(d); +#endif +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* RaiseTooManyValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* RaiseNoneIterError */ +static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* GetTopmostException */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportDottedModule */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { + PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; + if (unlikely(PyErr_Occurred())) { + PyErr_Clear(); + } + if (likely(PyTuple_GET_SIZE(parts_tuple) == count)) { + partial_name = name; + } else { + slice = PySequence_GetSlice(parts_tuple, 0, count); + if (unlikely(!slice)) + goto bad; + sep = PyUnicode_FromStringAndSize(".", 1); + if (unlikely(!sep)) + goto bad; + partial_name = PyUnicode_Join(sep, slice); + } + PyErr_Format( +#if PY_MAJOR_VERSION < 3 + PyExc_ImportError, + "No module named '%s'", PyString_AS_STRING(partial_name)); +#else +#if PY_VERSION_HEX >= 0x030600B1 + PyExc_ModuleNotFoundError, +#else + PyExc_ImportError, +#endif + "No module named '%U'", partial_name); +#endif +bad: + Py_XDECREF(sep); + Py_XDECREF(slice); + Py_XDECREF(partial_name); + return NULL; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { + PyObject *imported_module; +#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + return NULL; + imported_module = __Pyx_PyDict_GetItemStr(modules, name); + Py_XINCREF(imported_module); +#else + imported_module = PyImport_GetModule(name); +#endif + return imported_module; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { + Py_ssize_t i, nparts; + nparts = PyTuple_GET_SIZE(parts_tuple); + for (i=1; i < nparts && module; i++) { + PyObject *part, *submodule; +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + part = PyTuple_GET_ITEM(parts_tuple, i); +#else + part = PySequence_ITEM(parts_tuple, i); +#endif + submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); +#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(part); +#endif + Py_DECREF(module); + module = submodule; + } + if (unlikely(!module)) { + return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); + } + return module; +} +#endif +static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if PY_MAJOR_VERSION < 3 + PyObject *module, *from_list, *star = __pyx_n_s__3; + CYTHON_UNUSED_VAR(parts_tuple); + from_list = PyList_New(1); + if (unlikely(!from_list)) + return NULL; + Py_INCREF(star); + PyList_SET_ITEM(from_list, 0, star); + module = __Pyx_Import(name, from_list, 0); + Py_DECREF(from_list); + return module; +#else + PyObject *imported_module; + PyObject *module = __Pyx_Import(name, NULL, 0); + if (!parts_tuple || unlikely(!module)) + return module; + imported_module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(imported_module)) { + Py_DECREF(module); + return imported_module; + } + PyErr_Clear(); + return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); +#endif +} +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1 + PyObject *module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(module)) { + PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_n_s_spec); + if (likely(spec)) { + PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_n_s_initializing); + if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { + Py_DECREF(spec); + spec = NULL; + } + Py_XDECREF(unsafe); + } + if (likely(!spec)) { + PyErr_Clear(); + return module; + } + Py_DECREF(spec); + Py_DECREF(module); + } else if (PyErr_Occurred()) { + PyErr_Clear(); + } +#endif + return __Pyx__ImportDottedModule(name, parts_tuple); +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; itp_as_sequence && type->tp_as_sequence->sq_repeat)) { + return type->tp_as_sequence->sq_repeat(seq, mul); + } else +#endif + { + return __Pyx_PySequence_Multiply_Generic(seq, mul); + } +} + +/* SetItemInt */ +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { + int r; + if (unlikely(!j)) return -1; + r = PyObject_SetItem(o, j, v); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, + CYTHON_NCP_UNUSED int wraparound, CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o)); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o)))) { + PyObject* old = PyList_GET_ITEM(o, n); + Py_INCREF(v); + PyList_SET_ITEM(o, n, v); + Py_DECREF(old); + return 1; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_ass_subscript) { + int r; + PyObject *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return -1; + r = mm->mp_ass_subscript(o, key, v); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_ass_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return -1; + PyErr_Clear(); + } + } + return sm->sq_ass_item(o, i, v); + } + } +#else + if (is_list || !PyMapping_Check(o)) + { + return PySequence_SetItem(o, i, v); + } +#endif + return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v); +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* DivInt[long] */ +static CYTHON_INLINE long __Pyx_div_long(long a, long b) { + long q = a / b; + long r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__2); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* HasAttr */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *r; + if (unlikely(!__Pyx_PyBaseString_Check(n))) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return -1; + } + r = __Pyx_GetAttr(o, n); + if (!r) { + PyErr_Clear(); + return 0; + } else { + Py_DECREF(r); + return 1; + } +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* SetVTable */ +static int __Pyx_SetVtable(PyTypeObject *type, void *vtable) { + PyObject *ob = PyCapsule_New(vtable, 0, 0); + if (unlikely(!ob)) + goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(PyObject_SetAttr((PyObject *) type, __pyx_n_s_pyx_vtable, ob) < 0)) +#else + if (unlikely(PyDict_SetItem(type->tp_dict, __pyx_n_s_pyx_vtable, ob) < 0)) +#endif + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* GetVTable */ +static void* __Pyx_GetVtable(PyTypeObject *type) { + void* ptr; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *ob = PyObject_GetAttr((PyObject *)type, __pyx_n_s_pyx_vtable); +#else + PyObject *ob = PyObject_GetItem(type->tp_dict, __pyx_n_s_pyx_vtable); +#endif + if (!ob) + goto bad; + ptr = PyCapsule_GetPointer(ob, 0); + if (!ptr && !PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); + Py_DECREF(ob); + return ptr; +bad: + Py_XDECREF(ob); + return NULL; +} + +/* MergeVTables */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_MergeVtables(PyTypeObject *type) { + int i; + void** base_vtables; + __Pyx_TypeName tp_base_name; + __Pyx_TypeName base_name; + void* unknown = (void*)-1; + PyObject* bases = type->tp_bases; + int base_depth = 0; + { + PyTypeObject* base = type->tp_base; + while (base) { + base_depth += 1; + base = base->tp_base; + } + } + base_vtables = (void**) malloc(sizeof(void*) * (size_t)(base_depth + 1)); + base_vtables[0] = unknown; + for (i = 1; i < PyTuple_GET_SIZE(bases); i++) { + void* base_vtable = __Pyx_GetVtable(((PyTypeObject*)PyTuple_GET_ITEM(bases, i))); + if (base_vtable != NULL) { + int j; + PyTypeObject* base = type->tp_base; + for (j = 0; j < base_depth; j++) { + if (base_vtables[j] == unknown) { + base_vtables[j] = __Pyx_GetVtable(base); + base_vtables[j + 1] = unknown; + } + if (base_vtables[j] == base_vtable) { + break; + } else if (base_vtables[j] == NULL) { + goto bad; + } + base = base->tp_base; + } + } + } + PyErr_Clear(); + free(base_vtables); + return 0; +bad: + tp_base_name = __Pyx_PyType_GetName(type->tp_base); + base_name = __Pyx_PyType_GetName((PyTypeObject*)PyTuple_GET_ITEM(bases, i)); + PyErr_Format(PyExc_TypeError, + "multiple bases have vtable conflict: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", tp_base_name, base_name); + __Pyx_DECREF_TypeName(tp_base_name); + __Pyx_DECREF_TypeName(base_name); + free(base_vtables); + return -1; +} +#endif + +/* SetupReduce */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStrNoError(meth, __pyx_n_s_name_2); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) { + __Pyx_TypeName type_obj_name = + __Pyx_PyType_GetName((PyTypeObject*)type_obj); + PyErr_Format(PyExc_RuntimeError, + "Unable to initialize pickling for " __Pyx_FMT_TYPENAME, type_obj_name); + __Pyx_DECREF_TypeName(type_obj_name); + } + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} +#endif + +/* TypeImport */ +#ifndef __PYX_HAVE_RT_ImportType_3_0_11 +#define __PYX_HAVE_RT_ImportType_3_0_11 +static PyTypeObject *__Pyx_ImportType_3_0_11(PyObject *module, const char *module_name, const char *class_name, + size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize_3_0_11 check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; + Py_ssize_t itemsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + PyObject *py_itemsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#if !CYTHON_COMPILING_IN_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; + itemsize = ((PyTypeObject *)result)->tp_itemsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; + py_itemsize = PyObject_GetAttrString(result, "__itemsize__"); + if (!py_itemsize) + goto bad; + itemsize = PyLong_AsSsize_t(py_itemsize); + Py_DECREF(py_itemsize); + py_itemsize = 0; + if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (itemsize) { + if (size % alignment) { + alignment = size % alignment; + } + if (itemsize < (Py_ssize_t)alignment) + itemsize = (Py_ssize_t)alignment; + } + if ((size_t)(basicsize + itemsize) < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize+itemsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error_3_0_11 && + ((size_t)basicsize > size || (size_t)(basicsize + itemsize) < size)) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd-%zd from PyObject", + module_name, class_name, size, basicsize, basicsize+itemsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn_3_0_11 && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +#if PY_MAJOR_VERSION < 3 +static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { + __Pyx_TypeName obj_type_name; + if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); + if (__Pyx_TypeCheck(obj, __pyx_array_type)) return __pyx_array_getbuffer(obj, view, flags); + if (__Pyx_TypeCheck(obj, __pyx_memoryview_type)) return __pyx_memoryview_getbuffer(obj, view, flags); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "'" __Pyx_FMT_TYPENAME "' does not have the buffer interface", + obj_type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return -1; +} +static void __Pyx_ReleaseBuffer(Py_buffer *view) { + PyObject *obj = view->obj; + if (!obj) return; + if (PyObject_CheckBuffer(obj)) { + PyBuffer_Release(view); + return; + } + if ((0)) {} + view->obj = NULL; + Py_DECREF(obj); +} +#endif + + +/* MemviewSliceIsContig */ +static int +__pyx_memviewslice_is_contig(const __Pyx_memviewslice mvs, char order, int ndim) +{ + int i, index, step, start; + Py_ssize_t itemsize = mvs.memview->view.itemsize; + if (order == 'F') { + step = 1; + start = 0; + } else { + step = -1; + start = ndim - 1; + } + for (i = 0; i < ndim; i++) { + index = start + step * i; + if (mvs.suboffsets[index] >= 0 || mvs.strides[index] != itemsize) + return 0; + itemsize *= mvs.shape[index]; + } + return 1; +} + +/* OverlappingSlices */ +static void +__pyx_get_array_memory_extents(__Pyx_memviewslice *slice, + void **out_start, void **out_end, + int ndim, size_t itemsize) +{ + char *start, *end; + int i; + start = end = slice->data; + for (i = 0; i < ndim; i++) { + Py_ssize_t stride = slice->strides[i]; + Py_ssize_t extent = slice->shape[i]; + if (extent == 0) { + *out_start = *out_end = start; + return; + } else { + if (stride > 0) + end += stride * (extent - 1); + else + start += stride * (extent - 1); + } + } + *out_start = start; + *out_end = end + itemsize; +} +static int +__pyx_slices_overlap(__Pyx_memviewslice *slice1, + __Pyx_memviewslice *slice2, + int ndim, size_t itemsize) +{ + void *start1, *end1, *start2, *end2; + __pyx_get_array_memory_extents(slice1, &start1, &end1, ndim, itemsize); + __pyx_get_array_memory_extents(slice2, &start2, &end2, ndim, itemsize); + return (start1 < end2) && (start2 < end1); +} + +/* IsLittleEndian */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } S; + S.u32 = 0x01020304; + return S.u8[0] == 4; +} + +/* BufferFormatCheck */ +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type) { + stack[0].field = &ctx->root; + stack[0].parent_offset = 0; + ctx->root.type = type; + ctx->root.name = "buffer dtype"; + ctx->root.offset = 0; + ctx->head = stack; + ctx->head->field = &ctx->root; + ctx->fmt_offset = 0; + ctx->head->parent_offset = 0; + ctx->new_packmode = '@'; + ctx->enc_packmode = '@'; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->is_complex = 0; + ctx->is_valid_array = 0; + ctx->struct_alignment = 0; + while (type->typegroup == 'S') { + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = 0; + type = type->fields->type; + } +} +static int __Pyx_BufFmt_ParseNumber(const char** ts) { + int count; + const char* t = *ts; + if (*t < '0' || *t > '9') { + return -1; + } else { + count = *t++ - '0'; + while (*t >= '0' && *t <= '9') { + count *= 10; + count += *t++ - '0'; + } + } + *ts = t; + return count; +} +static int __Pyx_BufFmt_ExpectNumber(const char **ts) { + int number = __Pyx_BufFmt_ParseNumber(ts); + if (number == -1) + PyErr_Format(PyExc_ValueError,\ + "Does not understand character buffer dtype format string ('%c')", **ts); + return number; +} +static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { + PyErr_Format(PyExc_ValueError, + "Unexpected format string character: '%c'", ch); +} +static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { + switch (ch) { + case '?': return "'bool'"; + case 'c': return "'char'"; + case 'b': return "'signed char'"; + case 'B': return "'unsigned char'"; + case 'h': return "'short'"; + case 'H': return "'unsigned short'"; + case 'i': return "'int'"; + case 'I': return "'unsigned int'"; + case 'l': return "'long'"; + case 'L': return "'unsigned long'"; + case 'q': return "'long long'"; + case 'Q': return "'unsigned long long'"; + case 'f': return (is_complex ? "'complex float'" : "'float'"); + case 'd': return (is_complex ? "'complex double'" : "'double'"); + case 'g': return (is_complex ? "'complex long double'" : "'long double'"); + case 'T': return "a struct"; + case 'O': return "Python object"; + case 'P': return "a pointer"; + case 's': case 'p': return "a string"; + case 0: return "end"; + default: return "unparsable format string"; + } +} +static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return 2; + case 'i': case 'I': case 'l': case 'L': return 4; + case 'q': case 'Q': return 8; + case 'f': return (is_complex ? 8 : 4); + case 'd': return (is_complex ? 16 : 8); + case 'g': { + PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g').."); + return 0; + } + case 'O': case 'P': return sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(short); + case 'i': case 'I': return sizeof(int); + case 'l': case 'L': return sizeof(long); + #ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(PY_LONG_LONG); + #endif + case 'f': return sizeof(float) * (is_complex ? 2 : 1); + case 'd': return sizeof(double) * (is_complex ? 2 : 1); + case 'g': return sizeof(long double) * (is_complex ? 2 : 1); + case 'O': case 'P': return sizeof(void*); + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +typedef struct { char c; short x; } __Pyx_st_short; +typedef struct { char c; int x; } __Pyx_st_int; +typedef struct { char c; long x; } __Pyx_st_long; +typedef struct { char c; float x; } __Pyx_st_float; +typedef struct { char c; double x; } __Pyx_st_double; +typedef struct { char c; long double x; } __Pyx_st_longdouble; +typedef struct { char c; void *x; } __Pyx_st_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { char c; PY_LONG_LONG x; } __Pyx_st_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, int is_complex) { + CYTHON_UNUSED_VAR(is_complex); + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_st_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_st_float) - sizeof(float); + case 'd': return sizeof(__Pyx_st_double) - sizeof(double); + case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +/* These are for computing the padding at the end of the struct to align + on the first member of the struct. This will probably the same as above, + but we don't have any guarantees. + */ +typedef struct { short x; char c; } __Pyx_pad_short; +typedef struct { int x; char c; } __Pyx_pad_int; +typedef struct { long x; char c; } __Pyx_pad_long; +typedef struct { float x; char c; } __Pyx_pad_float; +typedef struct { double x; char c; } __Pyx_pad_double; +typedef struct { long double x; char c; } __Pyx_pad_longdouble; +typedef struct { void *x; char c; } __Pyx_pad_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { PY_LONG_LONG x; char c; } __Pyx_pad_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToPadding(char ch, int is_complex) { + CYTHON_UNUSED_VAR(is_complex); + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_pad_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_pad_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_pad_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_pad_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_pad_float) - sizeof(float); + case 'd': return sizeof(__Pyx_pad_double) - sizeof(double); + case 'g': return sizeof(__Pyx_pad_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_pad_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { + switch (ch) { + case 'c': + return 'H'; + case 'b': case 'h': case 'i': + case 'l': case 'q': case 's': case 'p': + return 'I'; + case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': + return 'U'; + case 'f': case 'd': case 'g': + return (is_complex ? 'C' : 'R'); + case 'O': + return 'O'; + case 'P': + return 'P'; + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) { + if (ctx->head == NULL || ctx->head->field == &ctx->root) { + const char* expected; + const char* quote; + if (ctx->head == NULL) { + expected = "end"; + quote = ""; + } else { + expected = ctx->head->field->type->name; + quote = "'"; + } + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected %s%s%s but got %s", + quote, expected, quote, + __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex)); + } else { + __Pyx_StructField* field = ctx->head->field; + __Pyx_StructField* parent = (ctx->head - 1)->field; + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'", + field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex), + parent->type->name, field->name); + } +} +static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) { + char group; + size_t size, offset, arraysize = 1; + if (ctx->enc_type == 0) return 0; + if (ctx->head->field->type->arraysize[0]) { + int i, ndim = 0; + if (ctx->enc_type == 's' || ctx->enc_type == 'p') { + ctx->is_valid_array = ctx->head->field->type->ndim == 1; + ndim = 1; + if (ctx->enc_count != ctx->head->field->type->arraysize[0]) { + PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %zu", + ctx->head->field->type->arraysize[0], ctx->enc_count); + return -1; + } + } + if (!ctx->is_valid_array) { + PyErr_Format(PyExc_ValueError, "Expected %d dimensions, got %d", + ctx->head->field->type->ndim, ndim); + return -1; + } + for (i = 0; i < ctx->head->field->type->ndim; i++) { + arraysize *= ctx->head->field->type->arraysize[i]; + } + ctx->is_valid_array = 0; + ctx->enc_count = 1; + } + group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex); + do { + __Pyx_StructField* field = ctx->head->field; + __Pyx_TypeInfo* type = field->type; + if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') { + size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex); + } else { + size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex); + } + if (ctx->enc_packmode == '@') { + size_t align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex); + size_t align_mod_offset; + if (align_at == 0) return -1; + align_mod_offset = ctx->fmt_offset % align_at; + if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset; + if (ctx->struct_alignment == 0) + ctx->struct_alignment = __Pyx_BufFmt_TypeCharToPadding(ctx->enc_type, + ctx->is_complex); + } + if (type->size != size || type->typegroup != group) { + if (type->typegroup == 'C' && type->fields != NULL) { + size_t parent_offset = ctx->head->parent_offset + field->offset; + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = parent_offset; + continue; + } + if ((type->typegroup == 'H' || group == 'H') && type->size == size) { + } else { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + } + offset = ctx->head->parent_offset + field->offset; + if (ctx->fmt_offset != offset) { + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch; next field is at offset %" CYTHON_FORMAT_SSIZE_T "d but %" CYTHON_FORMAT_SSIZE_T "d expected", + (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset); + return -1; + } + ctx->fmt_offset += size; + if (arraysize) + ctx->fmt_offset += (arraysize - 1) * size; + --ctx->enc_count; + while (1) { + if (field == &ctx->root) { + ctx->head = NULL; + if (ctx->enc_count != 0) { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + break; + } + ctx->head->field = ++field; + if (field->type == NULL) { + --ctx->head; + field = ctx->head->field; + continue; + } else if (field->type->typegroup == 'S') { + size_t parent_offset = ctx->head->parent_offset + field->offset; + if (field->type->fields->type == NULL) continue; + field = field->type->fields; + ++ctx->head; + ctx->head->field = field; + ctx->head->parent_offset = parent_offset; + break; + } else { + break; + } + } + } while (ctx->enc_count); + ctx->enc_type = 0; + ctx->is_complex = 0; + return 0; +} +static int +__pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) +{ + const char *ts = *tsp; + int i = 0, number, ndim; + ++ts; + if (ctx->new_count != 1) { + PyErr_SetString(PyExc_ValueError, + "Cannot handle repeated arrays in format string"); + return -1; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return -1; + ndim = ctx->head->field->type->ndim; + while (*ts && *ts != ')') { + switch (*ts) { + case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; + default: break; + } + number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return -1; + if (i < ndim && (size_t) number != ctx->head->field->type->arraysize[i]) { + PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %d", + ctx->head->field->type->arraysize[i], number); + return -1; + } + if (*ts != ',' && *ts != ')') { + PyErr_Format(PyExc_ValueError, + "Expected a comma in format string, got '%c'", *ts); + return -1; + } + if (*ts == ',') ts++; + i++; + } + if (i != ndim) { + PyErr_Format(PyExc_ValueError, "Expected %d dimension(s), got %d", + ctx->head->field->type->ndim, i); + return -1; + } + if (!*ts) { + PyErr_SetString(PyExc_ValueError, + "Unexpected end of format string, expected ')'"); + return -1; + } + ctx->is_valid_array = 1; + ctx->new_count = 1; + *tsp = ++ts; + return 0; +} +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) { + int got_Z = 0; + while (1) { + switch(*ts) { + case 0: + if (ctx->enc_type != 0 && ctx->head == NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + if (ctx->head != NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + return ts; + case ' ': + case '\r': + case '\n': + ++ts; + break; + case '<': + if (!__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '>': + case '!': + if (__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '=': + case '@': + case '^': + ctx->new_packmode = *ts++; + break; + case 'T': + { + const char* ts_after_sub; + size_t i, struct_count = ctx->new_count; + size_t struct_alignment = ctx->struct_alignment; + ctx->new_count = 1; + ++ts; + if (*ts != '{') { + PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'"); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + ctx->enc_count = 0; + ctx->struct_alignment = 0; + ++ts; + ts_after_sub = ts; + for (i = 0; i != struct_count; ++i) { + ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts); + if (!ts_after_sub) return NULL; + } + ts = ts_after_sub; + if (struct_alignment) ctx->struct_alignment = struct_alignment; + } + break; + case '}': + { + size_t alignment = ctx->struct_alignment; + ++ts; + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + if (alignment && ctx->fmt_offset % alignment) { + ctx->fmt_offset += alignment - (ctx->fmt_offset % alignment); + } + } + return ts; + case 'x': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->fmt_offset += ctx->new_count; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->enc_packmode = ctx->new_packmode; + ++ts; + break; + case 'Z': + got_Z = 1; + ++ts; + if (*ts != 'f' && *ts != 'd' && *ts != 'g') { + __Pyx_BufFmt_RaiseUnexpectedChar('Z'); + return NULL; + } + CYTHON_FALLTHROUGH; + case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': + case 'l': case 'L': case 'q': case 'Q': + case 'f': case 'd': case 'g': + case 'O': case 'p': + if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && + (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { + ctx->enc_count += ctx->new_count; + ctx->new_count = 1; + got_Z = 0; + ++ts; + break; + } + CYTHON_FALLTHROUGH; + case 's': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_count = ctx->new_count; + ctx->enc_packmode = ctx->new_packmode; + ctx->enc_type = *ts; + ctx->is_complex = got_Z; + ++ts; + ctx->new_count = 1; + got_Z = 0; + break; + case ':': + ++ts; + while(*ts != ':') ++ts; + ++ts; + break; + case '(': + if (__pyx_buffmt_parse_array(ctx, &ts) < 0) return NULL; + break; + default: + { + int number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return NULL; + ctx->new_count = (size_t)number; + } + } + } +} + +/* TypeInfoCompare */ + static int +__pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b) +{ + int i; + if (!a || !b) + return 0; + if (a == b) + return 1; + if (a->size != b->size || a->typegroup != b->typegroup || + a->is_unsigned != b->is_unsigned || a->ndim != b->ndim) { + if (a->typegroup == 'H' || b->typegroup == 'H') { + return a->size == b->size; + } else { + return 0; + } + } + if (a->ndim) { + for (i = 0; i < a->ndim; i++) + if (a->arraysize[i] != b->arraysize[i]) + return 0; + } + if (a->typegroup == 'S') { + if (a->flags != b->flags) + return 0; + if (a->fields || b->fields) { + if (!(a->fields && b->fields)) + return 0; + for (i = 0; a->fields[i].type && b->fields[i].type; i++) { + __Pyx_StructField *field_a = a->fields + i; + __Pyx_StructField *field_b = b->fields + i; + if (field_a->offset != field_b->offset || + !__pyx_typeinfo_cmp(field_a->type, field_b->type)) + return 0; + } + return !a->fields[i].type && !b->fields[i].type; + } + } + return 1; +} + +/* MemviewSliceValidateAndInit */ + static int +__pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec) +{ + if (buf->shape[dim] <= 1) + return 1; + if (buf->strides) { + if (spec & __Pyx_MEMVIEW_CONTIG) { + if (spec & (__Pyx_MEMVIEW_PTR|__Pyx_MEMVIEW_FULL)) { + if (unlikely(buf->strides[dim] != sizeof(void *))) { + PyErr_Format(PyExc_ValueError, + "Buffer is not indirectly contiguous " + "in dimension %d.", dim); + goto fail; + } + } else if (unlikely(buf->strides[dim] != buf->itemsize)) { + PyErr_SetString(PyExc_ValueError, + "Buffer and memoryview are not contiguous " + "in the same dimension."); + goto fail; + } + } + if (spec & __Pyx_MEMVIEW_FOLLOW) { + Py_ssize_t stride = buf->strides[dim]; + if (stride < 0) + stride = -stride; + if (unlikely(stride < buf->itemsize)) { + PyErr_SetString(PyExc_ValueError, + "Buffer and memoryview are not contiguous " + "in the same dimension."); + goto fail; + } + } + } else { + if (unlikely(spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1)) { + PyErr_Format(PyExc_ValueError, + "C-contiguous buffer is not contiguous in " + "dimension %d", dim); + goto fail; + } else if (unlikely(spec & (__Pyx_MEMVIEW_PTR))) { + PyErr_Format(PyExc_ValueError, + "C-contiguous buffer is not indirect in " + "dimension %d", dim); + goto fail; + } else if (unlikely(buf->suboffsets)) { + PyErr_SetString(PyExc_ValueError, + "Buffer exposes suboffsets but no strides"); + goto fail; + } + } + return 1; +fail: + return 0; +} +static int +__pyx_check_suboffsets(Py_buffer *buf, int dim, int ndim, int spec) +{ + CYTHON_UNUSED_VAR(ndim); + if (spec & __Pyx_MEMVIEW_DIRECT) { + if (unlikely(buf->suboffsets && buf->suboffsets[dim] >= 0)) { + PyErr_Format(PyExc_ValueError, + "Buffer not compatible with direct access " + "in dimension %d.", dim); + goto fail; + } + } + if (spec & __Pyx_MEMVIEW_PTR) { + if (unlikely(!buf->suboffsets || (buf->suboffsets[dim] < 0))) { + PyErr_Format(PyExc_ValueError, + "Buffer is not indirectly accessible " + "in dimension %d.", dim); + goto fail; + } + } + return 1; +fail: + return 0; +} +static int +__pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag) +{ + int i; + if (c_or_f_flag & __Pyx_IS_F_CONTIG) { + Py_ssize_t stride = 1; + for (i = 0; i < ndim; i++) { + if (unlikely(stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1)) { + PyErr_SetString(PyExc_ValueError, + "Buffer not fortran contiguous."); + goto fail; + } + stride = stride * buf->shape[i]; + } + } else if (c_or_f_flag & __Pyx_IS_C_CONTIG) { + Py_ssize_t stride = 1; + for (i = ndim - 1; i >- 1; i--) { + if (unlikely(stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1)) { + PyErr_SetString(PyExc_ValueError, + "Buffer not C contiguous."); + goto fail; + } + stride = stride * buf->shape[i]; + } + } + return 1; +fail: + return 0; +} +static int __Pyx_ValidateAndInit_memviewslice( + int *axes_specs, + int c_or_f_flag, + int buf_flags, + int ndim, + __Pyx_TypeInfo *dtype, + __Pyx_BufFmt_StackElem stack[], + __Pyx_memviewslice *memviewslice, + PyObject *original_obj) +{ + struct __pyx_memoryview_obj *memview, *new_memview; + __Pyx_RefNannyDeclarations + Py_buffer *buf; + int i, spec = 0, retval = -1; + __Pyx_BufFmt_Context ctx; + int from_memoryview = __pyx_memoryview_check(original_obj); + __Pyx_RefNannySetupContext("ValidateAndInit_memviewslice", 0); + if (from_memoryview && __pyx_typeinfo_cmp(dtype, ((struct __pyx_memoryview_obj *) + original_obj)->typeinfo)) { + memview = (struct __pyx_memoryview_obj *) original_obj; + new_memview = NULL; + } else { + memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( + original_obj, buf_flags, 0, dtype); + new_memview = memview; + if (unlikely(!memview)) + goto fail; + } + buf = &memview->view; + if (unlikely(buf->ndim != ndim)) { + PyErr_Format(PyExc_ValueError, + "Buffer has wrong number of dimensions (expected %d, got %d)", + ndim, buf->ndim); + goto fail; + } + if (new_memview) { + __Pyx_BufFmt_Init(&ctx, stack, dtype); + if (unlikely(!__Pyx_BufFmt_CheckString(&ctx, buf->format))) goto fail; + } + if (unlikely((unsigned) buf->itemsize != dtype->size)) { + PyErr_Format(PyExc_ValueError, + "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "u byte%s) " + "does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "u byte%s)", + buf->itemsize, + (buf->itemsize > 1) ? "s" : "", + dtype->name, + dtype->size, + (dtype->size > 1) ? "s" : ""); + goto fail; + } + if (buf->len > 0) { + for (i = 0; i < ndim; i++) { + spec = axes_specs[i]; + if (unlikely(!__pyx_check_strides(buf, i, ndim, spec))) + goto fail; + if (unlikely(!__pyx_check_suboffsets(buf, i, ndim, spec))) + goto fail; + } + if (unlikely(buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))) + goto fail; + } + if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice, + new_memview != NULL) == -1)) { + goto fail; + } + retval = 0; + goto no_fail; +fail: + Py_XDECREF(new_memview); + retval = -1; +no_fail: + __Pyx_RefNannyFinishContext(); + return retval; +} + +/* ObjectToMemviewSlice */ + static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(PyObject *obj, int writable_flag) { + __Pyx_memviewslice result = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_BufFmt_StackElem stack[1]; + int axes_specs[] = { (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_FOLLOW), (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_CONTIG) }; + int retcode; + if (obj == Py_None) { + result.memview = (struct __pyx_memoryview_obj *) Py_None; + return result; + } + retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, __Pyx_IS_C_CONTIG, + (PyBUF_C_CONTIGUOUS | PyBUF_FORMAT) | writable_flag, 2, + &__Pyx_TypeInfo_double, stack, + &result, obj); + if (unlikely(retcode == -1)) + goto __pyx_fail; + return result; +__pyx_fail: + result.memview = NULL; + result.data = NULL; + return result; +} + +/* ObjectToMemviewSlice */ + static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_dc_int(PyObject *obj, int writable_flag) { + __Pyx_memviewslice result = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_BufFmt_StackElem stack[1]; + int axes_specs[] = { (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_CONTIG) }; + int retcode; + if (obj == Py_None) { + result.memview = (struct __pyx_memoryview_obj *) Py_None; + return result; + } + retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, __Pyx_IS_C_CONTIG, + (PyBUF_C_CONTIGUOUS | PyBUF_FORMAT) | writable_flag, 1, + &__Pyx_TypeInfo_int, stack, + &result, obj); + if (unlikely(retcode == -1)) + goto __pyx_fail; + return result; +__pyx_fail: + result.memview = NULL; + result.data = NULL; + return result; +} + +/* CIntFromPyVerify */ + #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* ObjectToMemviewSlice */ + static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_dc_double(PyObject *obj, int writable_flag) { + __Pyx_memviewslice result = { 0, 0, { 0 }, { 0 }, { 0 } }; + __Pyx_BufFmt_StackElem stack[1]; + int axes_specs[] = { (__Pyx_MEMVIEW_DIRECT | __Pyx_MEMVIEW_CONTIG) }; + int retcode; + if (obj == Py_None) { + result.memview = (struct __pyx_memoryview_obj *) Py_None; + return result; + } + retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, __Pyx_IS_C_CONTIG, + (PyBUF_C_CONTIGUOUS | PyBUF_FORMAT) | writable_flag, 1, + &__Pyx_TypeInfo_double, stack, + &result, obj); + if (unlikely(retcode == -1)) + goto __pyx_fail; + return result; +__pyx_fail: + result.memview = NULL; + result.data = NULL; + return result; +} + +/* MemviewDtypeToObject */ + static CYTHON_INLINE PyObject *__pyx_memview_get_double(const char *itemp) { + return (PyObject *) PyFloat_FromDouble(*(double *) itemp); +} +static CYTHON_INLINE int __pyx_memview_set_double(const char *itemp, PyObject *obj) { + double value = __pyx_PyFloat_AsDouble(obj); + if (unlikely((value == (double)-1) && PyErr_Occurred())) + return 0; + *(double *) itemp = value; + return 1; +} + +/* MemviewSliceCopyTemplate */ + static __Pyx_memviewslice +__pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, + const char *mode, int ndim, + size_t sizeof_dtype, int contig_flag, + int dtype_is_object) +{ + __Pyx_RefNannyDeclarations + int i; + __Pyx_memviewslice new_mvs = { 0, 0, { 0 }, { 0 }, { 0 } }; + struct __pyx_memoryview_obj *from_memview = from_mvs->memview; + Py_buffer *buf = &from_memview->view; + PyObject *shape_tuple = NULL; + PyObject *temp_int = NULL; + struct __pyx_array_obj *array_obj = NULL; + struct __pyx_memoryview_obj *memview_obj = NULL; + __Pyx_RefNannySetupContext("__pyx_memoryview_copy_new_contig", 0); + for (i = 0; i < ndim; i++) { + if (unlikely(from_mvs->suboffsets[i] >= 0)) { + PyErr_Format(PyExc_ValueError, "Cannot copy memoryview slice with " + "indirect dimensions (axis %d)", i); + goto fail; + } + } + shape_tuple = PyTuple_New(ndim); + if (unlikely(!shape_tuple)) { + goto fail; + } + __Pyx_GOTREF(shape_tuple); + for(i = 0; i < ndim; i++) { + temp_int = PyInt_FromSsize_t(from_mvs->shape[i]); + if(unlikely(!temp_int)) { + goto fail; + } else { + PyTuple_SET_ITEM(shape_tuple, i, temp_int); + temp_int = NULL; + } + } + array_obj = __pyx_array_new(shape_tuple, sizeof_dtype, buf->format, (char *) mode, NULL); + if (unlikely(!array_obj)) { + goto fail; + } + __Pyx_GOTREF(array_obj); + memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( + (PyObject *) array_obj, contig_flag, + dtype_is_object, + from_mvs->memview->typeinfo); + if (unlikely(!memview_obj)) + goto fail; + if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs, 1) < 0)) + goto fail; + if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim, + dtype_is_object) < 0)) + goto fail; + goto no_fail; +fail: + __Pyx_XDECREF(new_mvs.memview); + new_mvs.memview = NULL; + new_mvs.data = NULL; +no_fail: + __Pyx_XDECREF(shape_tuple); + __Pyx_XDECREF(temp_int); + __Pyx_XDECREF(array_obj); + __Pyx_RefNannyFinishContext(); + return new_mvs; +} + +/* MemviewSliceInit */ + static int +__Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview, + int ndim, + __Pyx_memviewslice *memviewslice, + int memview_is_new_reference) +{ + __Pyx_RefNannyDeclarations + int i, retval=-1; + Py_buffer *buf = &memview->view; + __Pyx_RefNannySetupContext("init_memviewslice", 0); + if (unlikely(memviewslice->memview || memviewslice->data)) { + PyErr_SetString(PyExc_ValueError, + "memviewslice is already initialized!"); + goto fail; + } + if (buf->strides) { + for (i = 0; i < ndim; i++) { + memviewslice->strides[i] = buf->strides[i]; + } + } else { + Py_ssize_t stride = buf->itemsize; + for (i = ndim - 1; i >= 0; i--) { + memviewslice->strides[i] = stride; + stride *= buf->shape[i]; + } + } + for (i = 0; i < ndim; i++) { + memviewslice->shape[i] = buf->shape[i]; + if (buf->suboffsets) { + memviewslice->suboffsets[i] = buf->suboffsets[i]; + } else { + memviewslice->suboffsets[i] = -1; + } + } + memviewslice->memview = memview; + memviewslice->data = (char *)buf->buf; + if (__pyx_add_acquisition_count(memview) == 0 && !memview_is_new_reference) { + Py_INCREF(memview); + } + retval = 0; + goto no_fail; +fail: + memviewslice->memview = 0; + memviewslice->data = 0; + retval = -1; +no_fail: + __Pyx_RefNannyFinishContext(); + return retval; +} +#ifndef Py_NO_RETURN +#define Py_NO_RETURN +#endif +static void __pyx_fatalerror(const char *fmt, ...) Py_NO_RETURN { + va_list vargs; + char msg[200]; +#if PY_VERSION_HEX >= 0x030A0000 || defined(HAVE_STDARG_PROTOTYPES) + va_start(vargs, fmt); +#else + va_start(vargs); +#endif + vsnprintf(msg, 200, fmt, vargs); + va_end(vargs); + Py_FatalError(msg); +} +static CYTHON_INLINE int +__pyx_add_acquisition_count_locked(__pyx_atomic_int_type *acquisition_count, + PyThread_type_lock lock) +{ + int result; + PyThread_acquire_lock(lock, 1); + result = (*acquisition_count)++; + PyThread_release_lock(lock); + return result; +} +static CYTHON_INLINE int +__pyx_sub_acquisition_count_locked(__pyx_atomic_int_type *acquisition_count, + PyThread_type_lock lock) +{ + int result; + PyThread_acquire_lock(lock, 1); + result = (*acquisition_count)--; + PyThread_release_lock(lock); + return result; +} +static CYTHON_INLINE void +__Pyx_INC_MEMVIEW(__Pyx_memviewslice *memslice, int have_gil, int lineno) +{ + __pyx_nonatomic_int_type old_acquisition_count; + struct __pyx_memoryview_obj *memview = memslice->memview; + if (unlikely(!memview || (PyObject *) memview == Py_None)) { + return; + } + old_acquisition_count = __pyx_add_acquisition_count(memview); + if (unlikely(old_acquisition_count <= 0)) { + if (likely(old_acquisition_count == 0)) { + if (have_gil) { + Py_INCREF((PyObject *) memview); + } else { + PyGILState_STATE _gilstate = PyGILState_Ensure(); + Py_INCREF((PyObject *) memview); + PyGILState_Release(_gilstate); + } + } else { + __pyx_fatalerror("Acquisition count is %d (line %d)", + old_acquisition_count+1, lineno); + } + } +} +static CYTHON_INLINE void __Pyx_XCLEAR_MEMVIEW(__Pyx_memviewslice *memslice, + int have_gil, int lineno) { + __pyx_nonatomic_int_type old_acquisition_count; + struct __pyx_memoryview_obj *memview = memslice->memview; + if (unlikely(!memview || (PyObject *) memview == Py_None)) { + memslice->memview = NULL; + return; + } + old_acquisition_count = __pyx_sub_acquisition_count(memview); + memslice->data = NULL; + if (likely(old_acquisition_count > 1)) { + memslice->memview = NULL; + } else if (likely(old_acquisition_count == 1)) { + if (have_gil) { + Py_CLEAR(memslice->memview); + } else { + PyGILState_STATE _gilstate = PyGILState_Ensure(); + Py_CLEAR(memslice->memview); + PyGILState_Release(_gilstate); + } + } else { + __pyx_fatalerror("Acquisition count is %d (line %d)", + old_acquisition_count-1, lineno); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ + static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntFromPy */ + static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE char __Pyx_PyInt_As_char(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const char neg_one = (char) -1, const_zero = (char) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(char) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(char, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (char) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + char val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (char) -1; + val = __Pyx_PyInt_As_char(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(char, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(char) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 2 * PyLong_SHIFT)) { + return (char) (((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(char) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 3 * PyLong_SHIFT)) { + return (char) (((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(char) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) >= 4 * PyLong_SHIFT)) { + return (char) (((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (char) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(char) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(char, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(char) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(char, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(char, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(char) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(char) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + return (char) ((((((char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(char) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(char) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + return (char) ((((((((char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(char) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 4 * PyLong_SHIFT)) { + return (char) (((char)-1)*(((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(char) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(char, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(char) - 1 > 4 * PyLong_SHIFT)) { + return (char) ((((((((((char)digits[3]) << PyLong_SHIFT) | (char)digits[2]) << PyLong_SHIFT) | (char)digits[1]) << PyLong_SHIFT) | (char)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(char) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(char, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(char) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(char, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + char val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (char) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (char) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (char) -1; + } else { + stepval = v; + } + v = NULL; + val = (char) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(char) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((char) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(char) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((char) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((char) 1) << (sizeof(char) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (char) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to char"); + return (char) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to char"); + return (char) -1; +} + +/* FormatTypeName */ + #if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name_2); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__29); + } + return name; +} +#endif + +/* CheckBinaryVersion */ + static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionImport */ + #ifndef __PYX_HAVE_RT_ImportFunction_3_0_11 +#define __PYX_HAVE_RT_ImportFunction_3_0_11 +static int __Pyx_ImportFunction_3_0_11(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!d) + goto bad; + cobj = PyDict_GetItemString(d, funcname); + if (!cobj) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), funcname); + goto bad; + } + if (!PyCapsule_IsValid(cobj, sig)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", + PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); + goto bad; + } + tmp.p = PyCapsule_GetPointer(cobj, sig); + *f = tmp.fp; + if (!(*f)) + goto bad; + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(d); + return -1; +} +#endif + +/* InitStrings */ + #if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.cpython-312-darwin.so new file mode 100755 index 0000000..e887bed Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.pyx new file mode 100644 index 0000000..e74650b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/np_support.pyx @@ -0,0 +1,177 @@ +# cython: language_level=3 +# Copyright (c) 2023-2024, Manfred Moitzi +# License: MIT License +from typing_extensions import TypeAlias +import numpy as np +import numpy.typing as npt + +import cython +from .vector cimport isclose + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + + +NDArray: TypeAlias = npt.NDArray[np.float64] + + +def has_clockwise_orientation(vertices: np.ndarray) -> bool: + """ Returns True if 2D `vertices` have clockwise orientation. Ignores + z-axis of all vertices. + + Args: + vertices: numpy array + + Raises: + ValueError: less than 3 vertices + + """ + if len(vertices) < 3: + raise ValueError('At least 3 vertices required.') + + return _has_clockwise_orientation(vertices, vertices.shape[0]) + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef bint _has_clockwise_orientation(double [:, ::1] vertices, Py_ssize_t size): + cdef Py_ssize_t index + cdef Py_ssize_t start + cdef Py_ssize_t last = size - 1 + cdef double s = 0.0 + cdef double p1x = vertices[0][0] + cdef double p1y = vertices[0][1] + cdef double p2x = vertices[last][0] + cdef double p2y = vertices[last][1] + + # Using the same tolerance as the Python implementation: + cdef bint x_is_close = isclose(p1x, p2x, REL_TOL, ABS_TOL) + cdef bint y_is_close = isclose(p1y, p2y, REL_TOL, ABS_TOL) + + if x_is_close and y_is_close: + p1x = vertices[0][0] + p1y = vertices[0][1] + start = 1 + else: + p1x = vertices[last][0] + p1y = vertices[last][1] + start = 0 + + for index in range(start, size): + p2x = vertices[index][0] + p2y = vertices[index][1] + s += (p2x - p1x) * (p2y + p1y) + p1x = p2x + p1y = p2y + return s > 0.0 + + +def lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: + upper: np.ndarray = np.array(A, dtype=np.float64) + n: int = upper.shape[0] + lower: np.ndarray = np.zeros((n, m1), dtype=np.float64) + + # Is better to match on all platforms? + index: np.ndarray = np.zeros((n,), dtype=np.int32) + _lu_decompose_cext(upper, lower, index, n, m1, m2) + return upper, lower, index + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef _lu_decompose_cext( + double [:, ::1] upper, + double [:, ::1] lower, + int [::1] index, + int n, + int m1, + int m2 +): + cdef int mm = m1 + m2 + 1 + cdef int l = m1 + cdef int i, j, k + cdef double dum + + for i in range(m1): + for j in range(m1 - i, mm): + upper[i][j - l] = upper[i][j] + l -= 1 + for j in range(mm - l - 1, mm): + upper[i][j] = 0.0 + + l = m1 + for k in range(n): + dum = upper[k][0] + i = k + if l < n: + l += 1 + for j in range(k + 1, l): + if abs(upper[j][0]) > abs(dum): + dum = upper[j][0] + i = j + index[k] = i + 1 + if i != k: + for j in range(mm): + upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + + for i in range(k + 1, l): + dum = upper[i][0] / upper[k][0] + lower[k][i - k - 1] = dum + for j in range(1, mm): + upper[i][j - 1] = upper[i][j] - dum * upper[k][j] + upper[i][mm - 1] = 0.0 + + +def solve_vector_banded_matrix( + x: NDArray, + upper: NDArray, + lower: NDArray, + index: NDArray, + m1: int, + m2: int, +) -> NDArray: + n: int = upper.shape[0] + x = np.array(x) # copy x because array x gets modified + if x.shape[0] != n: + raise ValueError( + "Item count of vector has to match the row count of matrix ." + ) + _solve_vector_banded_matrix_cext(x, upper, lower, index, n, m1, m2) + return x + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef _solve_vector_banded_matrix_cext( + double [::1] x, + double [:, ::1] au, + double [:, ::1] al, + int [::1] index, + int n, + int m1, + int m2, +): + cdef int mm = m1 + m2 + 1 + cdef int l = m1 + cdef int i, j, k + cdef double dum + + for k in range(n): + j = index[k] - 1 + if j != k: + x[k], x[j] = x[j], x[k] + if l < n: + l += 1 + for j in range(k + 1, l): + x[j] -= al[k][j - k - 1] * x[k] + + l = 1 + for i in range(n - 1, -1, -1): + dum = x[i] + for k in range(1, l): + dum -= au[i][k] * x[k + i] + x[i] = dum / au[i][0] + if l < mm: + l += 1 + return x diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.c b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.c new file mode 100644 index 0000000..c87a48a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.c @@ -0,0 +1,32048 @@ +/* Generated by Cython 3.0.11 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/ezdxf/acc/constants.h" + ], + "include_dirs": [ + "src/ezdxf/acc" + ], + "name": "ezdxf.acc.vector", + "sources": [ + "src/ezdxf/acc/vector.pyx" + ] + }, + "module_name": "ezdxf.acc.vector" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#if defined(CYTHON_LIMITED_API) && 0 + #ifndef Py_LIMITED_API + #if CYTHON_LIMITED_API+0 > 0x03030000 + #define Py_LIMITED_API CYTHON_LIMITED_API + #else + #define Py_LIMITED_API 0x03030000 + #endif + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02070000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.7+ or Python 3.3+. +#else +#if defined(CYTHON_LIMITED_API) && CYTHON_LIMITED_API +#define __PYX_EXTRA_ABI_MODULE_NAME "limited" +#else +#define __PYX_EXTRA_ABI_MODULE_NAME "" +#endif +#define CYTHON_ABI "3_0_11" __PYX_EXTRA_ABI_MODULE_NAME +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." +#define CYTHON_HEX_VERSION 0x03000BF0 +#define CYTHON_FUTURE_DIVISION 1 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #define HAVE_LONG_LONG +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS (PY_MAJOR_VERSION >= 3) + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1 && PYPY_VERSION_NUM >= 0x07030C00) + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_CLINE_IN_TRACEBACK + #define CYTHON_CLINE_IN_TRACEBACK 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 1 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 +#elif defined(Py_GIL_DISABLED) || defined(Py_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #endif +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL (PY_MAJOR_VERSION < 3 || PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (PY_VERSION_HEX >= 0x030700A1) + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #if PY_VERSION_HEX < 0x030400a1 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #elif !defined(CYTHON_USE_TP_FINALIZE) + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #if PY_VERSION_HEX < 0x030600B1 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5) + #endif + #if PY_VERSION_HEX < 0x030700A3 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if !defined(CYTHON_VECTORCALL) +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) +#endif +#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + #endif + #endif + #if _MSC_VER < 1300 + #ifdef _WIN64 + typedef unsigned long long __pyx_uintptr_t; + #else + typedef unsigned int __pyx_uintptr_t; + #endif + #else + #ifdef _WIN64 + typedef unsigned __int64 __pyx_uintptr_t; + #else + typedef unsigned __int32 __pyx_uintptr_t; + #endif + #endif +#else + #include + typedef uintptr_t __pyx_uintptr_t; +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_DefaultClassType PyClass_Type + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030B0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030B0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } + #ifndef CO_OPTIMIZED + #define CO_OPTIMIZED 0x0001 + #endif + #ifndef CO_NEWLOCALS + #define CO_NEWLOCALS 0x0002 + #endif + #ifndef CO_VARARGS + #define CO_VARARGS 0x0004 + #endif + #ifndef CO_VARKEYWORDS + #define CO_VARKEYWORDS 0x0008 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x0200 + #endif + #ifndef CO_GENERATOR + #define CO_GENERATOR 0x0020 + #endif + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x0080 + #endif +#elif PY_VERSION_HEX >= 0x030B0000 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + PyObject *empty_bytes = PyBytes_FromStringAndSize("", 0); + if (!empty_bytes) return NULL; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, empty_bytes); + Py_DECREF(empty_bytes); + return result; + } +#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +#endif +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 +#endif +#ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#elif CYTHON_BACKPORT_VECTORCALL + typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames); + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_MAJOR_VERSION >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if __PYX_LIMITED_VERSION_HEX < 0x030900B1 + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void *__Pyx_PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE(obj), name, func_ctype) +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if PY_MAJOR_VERSION < 3 + #if CYTHON_COMPILING_IN_PYPY + #if PYPY_VERSION_NUM < 0x07030600 + #if defined(__cplusplus) && __cplusplus >= 201402L + [[deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")]] + #elif defined(__GNUC__) || defined(__clang__) + __attribute__ ((__deprecated__("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6"))) + #elif defined(_MSC_VER) + __declspec(deprecated("`with nogil:` inside a nogil function will not release the GIL in PyPy2 < 7.3.6")) + #endif + static CYTHON_INLINE int PyGILState_Check(void) { + return 0; + } + #else // PYPY_VERSION_NUM < 0x07030600 + #endif // PYPY_VERSION_NUM < 0x07030600 + #else + static CYTHON_INLINE int PyGILState_Check(void) { + PyThreadState * tstate = _PyThreadState_Current; + return tstate && (tstate == PyGILState_GetThisThreadState()); + } + #endif +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B4 && PY_VERSION_HEX < 0x030d0000 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif PY_MAJOR_VERSION >= 3 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000) +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) + #define __Pyx_PyObject_GetIterNextFunc(obj) (Py_TYPE(obj)->tp_iternext) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) + #define __Pyx_PyObject_GetIterNextFunc(obj) PyIter_Next +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyObject_GenericSetAttr((PyObject*)tp, k, v) +#else + #define __Pyx_SetItemOnTypeDict(tp, k, v) PyDict_SetItem(tp->tp_dict, k, v) +#endif +#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GetLength(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#elif PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535U : 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((int)sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = (Py_UNICODE) ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) || (PY_MAJOR_VERSION == 2 && PYPY_VERSION_NUM < 0x07030500) + #undef PyUnicode_Contains + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#if CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define __Pyx_Py3Int_Check(op) PyLong_Check(op) + #define __Pyx_Py3Int_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#else + #define __Pyx_Py3Int_Check(op) (PyLong_Check(op) || PyInt_Check(op)) + #define __Pyx_Py3Int_CheckExact(op) (PyLong_CheckExact(op) || PyInt_CheckExact(op)) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__ezdxf__acc__vector +#define __PYX_HAVE_API__ezdxf__acc__vector +/* Early includes */ +#include +#include "constants.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +#include +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = (char) c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#include +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* #### Code section: filename_table ### */ + +static const char *__pyx_f[] = { + "src/ezdxf/acc/vector.pyx", + "src/ezdxf/acc/vector.pxd", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2; +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3; +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr; +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__; +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr; +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__; + +/* "ezdxf/acc/vector.pxd":9 + * cdef double normalize_deg_angle(double a) + * + * cdef class Vec2: # <<<<<<<<<<<<<< + * cdef readonly double x, y + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 { + PyObject_HEAD + double x; + double y; +}; + + +/* "ezdxf/acc/vector.pxd":28 + * + * + * cdef class Vec3: # <<<<<<<<<<<<<< + * cdef readonly double x, y, z + * + */ +struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 { + PyObject_HEAD + double x; + double y; + double z; +}; + + +/* "ezdxf/acc/vector.pyx":116 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr { + PyObject_HEAD + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_item; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/vector.pyx":155 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self; +}; + + +/* "ezdxf/acc/vector.pyx":468 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr { + PyObject_HEAD + PyObject *__pyx_genexpr_arg_0; + PyObject *__pyx_v_item; + PyObject *__pyx_t_0; + Py_ssize_t __pyx_t_1; + PyObject *(*__pyx_t_2)(PyObject *); +}; + + +/* "ezdxf/acc/vector.pyx":517 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ +struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ { + PyObject_HEAD + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self; +}; + +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__)) + #define __Pyx_RefNannyFinishContextNogil() __Pyx_RefNannyFinishContext() +#endif + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* TupleAndListFromArray.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_VARARGS(args, i) PySequence_GetItem(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i) +#else + #define __Pyx_Arg_VARARGS(args, i) PyTuple_GetItem(args, i) +#endif +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_Arg_NewRef_VARARGS(arg) __Pyx_NewRef(arg) + #define __Pyx_Arg_XDECREF_VARARGS(arg) Py_XDECREF(arg) +#else + #define __Pyx_Arg_NewRef_VARARGS(arg) arg + #define __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_Arg_FASTCALL(args, i) args[i] + #define __Pyx_NumKwargs_FASTCALL(kwds) PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif + #define __Pyx_Arg_NewRef_FASTCALL(arg) arg /* no-op, __Pyx_Arg_FASTCALL is direct and this needs + to have the same reference counting */ + #define __Pyx_Arg_XDECREF_FASTCALL(arg) +#else + #define __Pyx_Arg_FASTCALL __Pyx_Arg_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS + #define __Pyx_Arg_NewRef_FASTCALL(arg) __Pyx_Arg_NewRef_VARARGS(arg) + #define __Pyx_Arg_XDECREF_FASTCALL(arg) __Pyx_Arg_XDECREF_VARARGS(arg) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_VARARGS(args, start), stop - start) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(&__Pyx_Arg_FASTCALL(args, start), stop - start) +#else +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, + const char* function_name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kw, const char* function_name, int kw_allowed); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#if !CYTHON_VECTORCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if !CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03080000 + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets() + #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) +#else + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif +#endif +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs); + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* RaiseUnboundLocalError.proto */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* PyObjectFormatSimple.proto */ +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#elif PY_MAJOR_VERSION < 3 + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyString_CheckExact(s)) ? PyUnicode_FromEncodedObject(s, NULL, "strict") :\ + PyObject_Format(s, f)) +#elif CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + likely(PyLong_CheckExact(s)) ? PyLong_Type.tp_repr(s) :\ + likely(PyFloat_CheckExact(s)) ? PyFloat_Type.tp_repr(s) :\ + PyObject_Format(s, f)) +#else + #define __Pyx_PyObject_FormatSimple(s, f) (\ + likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ + PyObject_Format(s, f)) +#endif + +/* JoinPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* BuildPyUnicode.proto */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char); + +/* CIntToPyUnicode.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char); + +/* PyObjectCallNoArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* IncludeStructmemberH.proto */ +#include + +/* FixUpExtensionType.proto */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); +#endif + +/* PyObjectGetMethod.proto */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); + +/* PyObjectCallMethod0.proto */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* ImportDottedModule.proto */ +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); +#endif + +/* FetchSharedCythonModule.proto */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto */ +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); +#else +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); +#endif + +/* PyMethodNew.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *typesModule=NULL, *methodType=NULL, *result=NULL; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + typesModule = PyImport_ImportModule("types"); + if (!typesModule) return NULL; + methodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + if (!methodType) return NULL; + result = PyObject_CallFunctionObjArgs(methodType, func, self, NULL); + Py_DECREF(methodType); + return result; +} +#elif PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#else + #define __Pyx_PyMethod_New PyMethod_New +#endif + +/* PyVectorcallFastCallDict.proto */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_BACKPORT_VECTORCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + void *defaults; + int defaults_pyobjects; + size_t defaults_size; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_BACKPORT_VECTORCALL +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* GetNameInClass.proto */ +#define __Pyx_GetNameInClass(var, nmspace, name) (var) = __Pyx__GetNameInClass(nmspace, name) +static PyObject *__Pyx__GetNameInClass(PyObject *nmspace, PyObject *name); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +#if !CYTHON_COMPILING_IN_LIMITED_API +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); +#endif + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +static __Pyx_TypeName __Pyx_PyType_GetName(PyTypeObject* tp); +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#else +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyObjectCall2Args.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* CoroutineBase.proto */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; + PyObject *gi_weakreflist; + PyObject *classobj; + PyObject *yieldfrom; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static PyObject *__Pyx_Coroutine_Close(PyObject *self); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); + +/* PatchModuleWithCoroutine.proto */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code); + +/* PatchGeneratorABC.proto */ +static int __Pyx_patch_abc(void); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); + +/* CheckBinaryVersion.proto */ +static unsigned long __Pyx_get_runtime_version(void); +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* FunctionExport.proto */ +static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +/* #### Code section: module_declarations ### */ + +/* Module declarations from "libc.math" */ + +/* Module declarations from "ezdxf.acc.vector" */ +static double __pyx_v_5ezdxf_3acc_6vector_RAD2DEG; +static double __pyx_v_5ezdxf_3acc_6vector_DEG2RAD; +static int __pyx_f_5ezdxf_3acc_6vector_isclose(double, double, double, double); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle(double); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_normalize_deg_angle(double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_add(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_sub(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v2_dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v2_det(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v2_dist(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_from_angle(double, double); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v2_angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_ortho(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, int); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_add(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_sub(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_reverse(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v3_dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_cross(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static CYTHON_INLINE double __pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static CYTHON_INLINE double __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v3_dist(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_from_angle(double, double); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v3_angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static double __pyx_f_5ezdxf_3acc_6vector_v3_angle_about(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_ortho(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, int); /*proto*/ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *); /*proto*/ +static int __pyx_f_5ezdxf_3acc_6vector_v3_isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "ezdxf.acc.vector" +extern int __pyx_module_is_main_ezdxf__acc__vector; +int __pyx_module_is_main_ezdxf__acc__vector = 0; + +/* Implementation of "ezdxf.acc.vector" */ +/* #### Code section: global_var ### */ +static PyObject *__pyx_builtin_staticmethod; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_round; +static PyObject *__pyx_builtin_IndexError; +static PyObject *__pyx_builtin_NotImplemented; +/* #### Code section: string_decls ### */ +static const char __pyx_k_a[] = "a"; +static const char __pyx_k_b[] = "b"; +static const char __pyx_k_o[] = "o"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k_v[] = "v"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k_z[] = "z"; +static const char __pyx_k__2[] = "("; +static const char __pyx_k__3[] = ", "; +static const char __pyx_k__4[] = ")"; +static const char __pyx_k_gc[] = "gc"; +static const char __pyx_k_p1[] = "p1"; +static const char __pyx_k_p2[] = "p2"; +static const char __pyx_k_v1[] = "v1"; +static const char __pyx_k_v2[] = "v2"; +static const char __pyx_k__12[] = "."; +static const char __pyx_k__13[] = "*"; +static const char __pyx_k_add[] = "__add__"; +static const char __pyx_k_ccw[] = "ccw"; +static const char __pyx_k_det[] = "det"; +static const char __pyx_k_dot[] = "dot"; +static const char __pyx_k_mul[] = "__mul__"; +static const char __pyx_k_neg[] = "__neg__"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_str[] = "__str__"; +static const char __pyx_k_sub[] = "__sub__"; +static const char __pyx_k_sum[] = "sum"; +static const char __pyx_k_tmp[] = "tmp"; +static const char __pyx_k_xyz[] = "xyz"; +static const char __pyx_k_List[] = "List"; +static const char __pyx_k_UVec[] = "UVec"; +static const char __pyx_k_Vec2[] = "Vec2"; +static const char __pyx_k_Vec3[] = "Vec3"; +static const char __pyx_k__100[] = "?"; +static const char __pyx_k_args[] = "args"; +static const char __pyx_k_base[] = "base"; +static const char __pyx_k_bool[] = "bool"; +static const char __pyx_k_copy[] = "copy"; +static const char __pyx_k_dict[] = "__dict__"; +static const char __pyx_k_iadd[] = "__iadd__"; +static const char __pyx_k_imul[] = "__imul__"; +static const char __pyx_k_isub[] = "__isub__"; +static const char __pyx_k_iter[] = "__iter__"; +static const char __pyx_k_lerp[] = "lerp"; +static const char __pyx_k_list[] = "list"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_radd[] = "__radd__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_send[] = "send"; +static const char __pyx_k_spec[] = "__spec__"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_Tuple[] = "Tuple"; +static const char __pyx_k_angle[] = "angle"; +static const char __pyx_k_close[] = "close"; +static const char __pyx_k_cross[] = "cross"; +static const char __pyx_k_float[] = "float"; +static const char __pyx_k_items[] = "items"; +static const char __pyx_k_other[] = "other"; +static const char __pyx_k_round[] = "round"; +static const char __pyx_k_throw[] = "throw"; +static const char __pyx_k_tuple[] = "tuple"; +static const char __pyx_k_AnyVec[] = "AnyVec"; +static const char __pyx_k_X_AXIS[] = "X_AXIS"; +static const char __pyx_k_Y_AXIS[] = "Y_AXIS"; +static const char __pyx_k_Z_AXIS[] = "Z_AXIS"; +static const char __pyx_k_copy_2[] = "__copy__"; +static const char __pyx_k_dict_2[] = "dict"; +static const char __pyx_k_enable[] = "enable"; +static const char __pyx_k_factor[] = "factor"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_length[] = "length"; +static const char __pyx_k_neg_v2[] = "neg_v2"; +static const char __pyx_k_random[] = "random"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_return[] = "return"; +static const char __pyx_k_rotate[] = "rotate"; +static const char __pyx_k_target[] = "target"; +static const char __pyx_k_typing[] = "typing"; +static const char __pyx_k_NULLVEC[] = "NULLVEC"; +static const char __pyx_k_abs_tol[] = "abs_tol"; +static const char __pyx_k_angle_2[] = "angle_"; +static const char __pyx_k_disable[] = "disable"; +static const char __pyx_k_genexpr[] = "genexpr"; +static const char __pyx_k_is_null[] = "is_null"; +static const char __pyx_k_isclose[] = "isclose"; +static const char __pyx_k_ndigits[] = "ndigits"; +static const char __pyx_k_project[] = "project"; +static const char __pyx_k_rel_tol[] = "rel_tol"; +static const char __pyx_k_replace[] = "replace"; +static const char __pyx_k_uniform[] = "uniform"; +static const char __pyx_k_AnyVec_2[] = "'AnyVec'"; +static const char __pyx_k_Iterable[] = "Iterable"; +static const char __pyx_k_Iterator[] = "Iterator"; +static const char __pyx_k_Sequence[] = "Sequence"; +static const char __pyx_k_Vec2_det[] = "Vec2.det"; +static const char __pyx_k_Vec2_dot[] = "Vec2.dot"; +static const char __pyx_k_Vec2_sum[] = "Vec2.sum"; +static const char __pyx_k_Vec3_dot[] = "Vec3.dot"; +static const char __pyx_k_Vec3_sum[] = "Vec3.sum"; +static const char __pyx_k_deepcopy[] = "__deepcopy__"; +static const char __pyx_k_distance[] = "distance"; +static const char __pyx_k_generate[] = "generate"; +static const char __pyx_k_int_None[] = "int | None"; +static const char __pyx_k_memodict[] = "memodict"; +static const char __pyx_k_reversed[] = "reversed"; +static const char __pyx_k_List_Vec2[] = "List[Vec2]"; +static const char __pyx_k_List_Vec3[] = "List[Vec3]"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_Vec2_copy[] = "Vec2.copy"; +static const char __pyx_k_Vec2_lerp[] = "Vec2.lerp"; +static const char __pyx_k_Vec2_list[] = "Vec2.list"; +static const char __pyx_k_Vec3_copy[] = "Vec3.copy"; +static const char __pyx_k_Vec3_lerp[] = "Vec3.lerp"; +static const char __pyx_k_Vec3_list[] = "Vec3.list"; +static const char __pyx_k_isenabled[] = "isenabled"; +static const char __pyx_k_magnitude[] = "magnitude"; +static const char __pyx_k_normalize[] = "normalize"; +static const char __pyx_k_IndexError[] = "IndexError"; +static const char __pyx_k_Vec2_round[] = "Vec2.round"; +static const char __pyx_k_Vec2_tuple[] = "Vec2.tuple"; +static const char __pyx_k_Vec3_cross[] = "Vec3.cross"; +static const char __pyx_k_Vec3_round[] = "Vec3.round"; +static const char __pyx_k_Vec3_tuple[] = "Vec3.tuple"; +static const char __pyx_k_ezdxf_math[] = "ezdxf.math"; +static const char __pyx_k_from_angle[] = "from_angle"; +static const char __pyx_k_orthogonal[] = "orthogonal"; +static const char __pyx_k_rotate_deg[] = "rotate_deg"; +static const char __pyx_k_self_angle[] = "self_angle"; +static const char __pyx_k_Vec2___copy[] = "Vec2.__copy__"; +static const char __pyx_k_Vec2___iter[] = "Vec2.__iter__"; +static const char __pyx_k_Vec2_rotate[] = "Vec2.rotate"; +static const char __pyx_k_Vec3___iter[] = "Vec3.__iter__"; +static const char __pyx_k_Vec3_random[] = "Vec3.random"; +static const char __pyx_k_Vec3_rotate[] = "Vec3.rotate"; +static const char __pyx_k_angle_about[] = "angle_about"; +static const char __pyx_k_is_parallel[] = "is_parallel"; +static const char __pyx_k_magnitude_2[] = "magnitude_"; +static const char __pyx_k_Vec2_isclose[] = "Vec2.isclose"; +static const char __pyx_k_Vec2_project[] = "Vec2.project"; +static const char __pyx_k_Vec3_isclose[] = "Vec3.isclose"; +static const char __pyx_k_Vec3_project[] = "Vec3.project"; +static const char __pyx_k_Vec3_replace[] = "Vec3.replace"; +static const char __pyx_k_initializing[] = "_initializing"; +static const char __pyx_k_is_coroutine[] = "_is_coroutine"; +static const char __pyx_k_staticmethod[] = "staticmethod"; +static const char __pyx_k_Iterable_UVec[] = "Iterable[UVec]"; +static const char __pyx_k_Iterable_Vec2[] = "Iterable[Vec2]"; +static const char __pyx_k_Iterator_Vec2[] = "Iterator[Vec2]"; +static const char __pyx_k_Iterator_Vec3[] = "Iterator[Vec3]"; +static const char __pyx_k_Sequence_Vec2[] = "Sequence[Vec2]"; +static const char __pyx_k_Sequence_Vec3[] = "Sequence[Vec3]"; +static const char __pyx_k_TYPE_CHECKING[] = "TYPE_CHECKING"; +static const char __pyx_k_Vec2___reduce[] = "Vec2.__reduce__"; +static const char __pyx_k_Vec2_distance[] = "Vec2.distance"; +static const char __pyx_k_Vec2_generate[] = "Vec2.generate"; +static const char __pyx_k_Vec3___reduce[] = "Vec3.__reduce__"; +static const char __pyx_k_Vec3_distance[] = "Vec3.distance"; +static const char __pyx_k_Vec3_generate[] = "Vec3.generate"; +static const char __pyx_k_Vec3_reversed[] = "Vec3.reversed"; +static const char __pyx_k_angle_between[] = "angle_between"; +static const char __pyx_k_invalid_index[] = "invalid index "; +static const char __pyx_k_spatial_angle[] = "spatial_angle"; +static const char __pyx_k_NotImplemented[] = "NotImplemented"; +static const char __pyx_k_Vec2_normalize[] = "Vec2.normalize"; +static const char __pyx_k_Vec3_normalize[] = "Vec3.normalize"; +static const char __pyx_k_from_deg_angle[] = "from_deg_angle"; +static const char __pyx_k_Vec2___deepcopy[] = "Vec2.__deepcopy__"; +static const char __pyx_k_Vec2_from_angle[] = "Vec2.from_angle"; +static const char __pyx_k_Vec2_orthogonal[] = "Vec2.orthogonal"; +static const char __pyx_k_Vec2_rotate_deg[] = "Vec2.rotate_deg"; +static const char __pyx_k_Vec3___deepcopy[] = "Vec3.__deepcopy__"; +static const char __pyx_k_Vec3_from_angle[] = "Vec3.from_angle"; +static const char __pyx_k_Vec3_orthogonal[] = "Vec3.orthogonal"; +static const char __pyx_k_Vec3_rotate_deg[] = "Vec3.rotate_deg"; +static const char __pyx_k_Vec3_angle_about[] = "Vec3.angle_about"; +static const char __pyx_k_Vec3_is_parallel[] = "Vec3.is_parallel"; +static const char __pyx_k_ezdxf_acc_vector[] = "ezdxf.acc.vector"; +static const char __pyx_k_Vec2_angle_between[] = "Vec2.angle_between"; +static const char __pyx_k_Vec3_angle_between[] = "Vec3.angle_between"; +static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_Vec2_from_deg_angle[] = "Vec2.from_deg_angle"; +static const char __pyx_k_Vec3_from_deg_angle[] = "Vec3.from_deg_angle"; +static const char __pyx_k_normalize_deg_angle[] = "_normalize_deg_angle"; +static const char __pyx_k_normalize_rad_angle[] = "_normalize_rad_angle"; +static const char __pyx_k_invalid_argument_count[] = "invalid argument count"; +static const char __pyx_k_generate_locals_genexpr[] = "generate..genexpr"; +static const char __pyx_k_src_ezdxf_acc_vector_pyx[] = "src/ezdxf/acc/vector.pyx"; +/* #### Code section: decls ### */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector__normalize_rad_angle(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_angle); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_2_normalize_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_angle); /* proto */ +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec2___cinit__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_args); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_2__reduce__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_4vec3___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_4round(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_ndigits); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_6list(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_8tuple(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_8generate_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_10generate(PyObject *__pyx_v_items); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_12from_angle(double __pyx_v_angle, double __pyx_v_length); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_14from_deg_angle(double __pyx_v_angle, double __pyx_v_length); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_16__str__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_18__repr__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_pf_5ezdxf_3acc_6vector_4Vec2_20__len__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static Py_hash_t __pyx_pf_5ezdxf_3acc_6vector_4Vec2_22__hash__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_24copy(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_26__copy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_28__deepcopy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_memodict); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_30__getitem__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, int __pyx_v_index); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_32__iter__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_35__abs__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_9magnitude___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_7is_null___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_5angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_9angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_37orthogonal(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_ccw); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_39lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_factor); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_41normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_length); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_43project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_45__neg__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec2_47__bool__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_49isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_51__eq__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_53__lt__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_55__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_57__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_59__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_61__rmul__(PyObject *__pyx_v_self, double __pyx_v_factor); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_63__truediv__(PyObject *__pyx_v_self, double __pyx_v_factor); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_65dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_67det(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_69distance(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_71angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_73rotate(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_75rotate_deg(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_77sum(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_1x___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_1y___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec3___cinit__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_args); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_2__reduce__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_2xy___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_3xyz___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_4vec2___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_4replace(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_z); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_6round(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_ndigits); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_8list(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_10tuple(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_8generate_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_12generate(PyObject *__pyx_v_items); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_14from_angle(double __pyx_v_angle, double __pyx_v_length); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_16from_deg_angle(double __pyx_v_angle, double __pyx_v_length); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_18random(double __pyx_v_length); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_20__str__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_22__repr__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static Py_ssize_t __pyx_pf_5ezdxf_3acc_6vector_4Vec3_24__len__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static Py_hash_t __pyx_pf_5ezdxf_3acc_6vector_4Vec3_26__hash__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_28copy(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_30__deepcopy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_memodict); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_32__getitem__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, int __pyx_v_index); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_34__iter__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_37__abs__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_9magnitude___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_16magnitude_square___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_7is_null___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_39is_parallel(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_13spatial_angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_5angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_9angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_41orthogonal(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_ccw); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_43lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_factor); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_45project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_47normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_length); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_49reversed(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_51__neg__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec3_53__bool__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_55isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_57__eq__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_59__lt__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_61__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_63__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_65__rsub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_67__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_69__rmul__(PyObject *__pyx_v_self, double __pyx_v_factor); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_71__truediv__(PyObject *__pyx_v_self, double __pyx_v_factor); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_73sum(PyObject *__pyx_v_items); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_75dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_77cross(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_79distance(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_81angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_83angle_about(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_base, PyObject *__pyx_v_target); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_85rotate(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_angle); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_87rotate_deg(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_angle); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1x___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1y___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1z___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4distance(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_p1, PyObject *__pyx_v_p2); /* proto */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_6lerp(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_p1, PyObject *__pyx_v_p2, double __pyx_v_factor); /* proto */ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector_Vec2(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector_Vec3(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + #ifdef __Pyx_CyFunction_USED + PyTypeObject *__pyx_CyFunctionType; + #endif + #ifdef __Pyx_FusedFunction_USED + PyTypeObject *__pyx_FusedFunctionType; + #endif + #ifdef __Pyx_Generator_USED + PyTypeObject *__pyx_GeneratorType; + #endif + #ifdef __Pyx_IterableCoroutine_USED + PyTypeObject *__pyx_IterableCoroutineType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineAwaitType; + #endif + #ifdef __Pyx_Coroutine_USED + PyTypeObject *__pyx_CoroutineType; + #endif + #if CYTHON_USE_MODULE_STATE + #endif + #if CYTHON_USE_MODULE_STATE + PyObject *__pyx_type_5ezdxf_3acc_6vector_Vec2; + PyObject *__pyx_type_5ezdxf_3acc_6vector_Vec3; + PyObject *__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr; + PyObject *__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__; + PyObject *__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr; + PyObject *__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__; + #endif + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec2; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector_Vec3; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr; + PyTypeObject *__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__; + PyObject *__pyx_n_s_AnyVec; + PyObject *__pyx_kp_s_AnyVec_2; + PyObject *__pyx_n_s_IndexError; + PyObject *__pyx_n_s_Iterable; + PyObject *__pyx_kp_s_Iterable_UVec; + PyObject *__pyx_kp_s_Iterable_Vec2; + PyObject *__pyx_n_s_Iterator; + PyObject *__pyx_kp_s_Iterator_Vec2; + PyObject *__pyx_kp_s_Iterator_Vec3; + PyObject *__pyx_n_s_List; + PyObject *__pyx_kp_s_List_Vec2; + PyObject *__pyx_kp_s_List_Vec3; + PyObject *__pyx_n_s_NULLVEC; + PyObject *__pyx_n_s_NotImplemented; + PyObject *__pyx_n_s_Sequence; + PyObject *__pyx_kp_s_Sequence_Vec2; + PyObject *__pyx_kp_s_Sequence_Vec3; + PyObject *__pyx_n_s_TYPE_CHECKING; + PyObject *__pyx_n_s_Tuple; + PyObject *__pyx_n_s_TypeError; + PyObject *__pyx_n_s_UVec; + PyObject *__pyx_n_s_Vec2; + PyObject *__pyx_n_u_Vec2; + PyObject *__pyx_n_s_Vec2___copy; + PyObject *__pyx_n_s_Vec2___deepcopy; + PyObject *__pyx_n_s_Vec2___iter; + PyObject *__pyx_n_s_Vec2___reduce; + PyObject *__pyx_n_s_Vec2_angle_between; + PyObject *__pyx_n_s_Vec2_copy; + PyObject *__pyx_n_s_Vec2_det; + PyObject *__pyx_n_s_Vec2_distance; + PyObject *__pyx_n_s_Vec2_dot; + PyObject *__pyx_n_s_Vec2_from_angle; + PyObject *__pyx_n_s_Vec2_from_deg_angle; + PyObject *__pyx_n_s_Vec2_generate; + PyObject *__pyx_n_s_Vec2_isclose; + PyObject *__pyx_n_s_Vec2_lerp; + PyObject *__pyx_n_s_Vec2_list; + PyObject *__pyx_n_s_Vec2_normalize; + PyObject *__pyx_n_s_Vec2_orthogonal; + PyObject *__pyx_n_s_Vec2_project; + PyObject *__pyx_n_s_Vec2_rotate; + PyObject *__pyx_n_s_Vec2_rotate_deg; + PyObject *__pyx_n_s_Vec2_round; + PyObject *__pyx_n_s_Vec2_sum; + PyObject *__pyx_n_s_Vec2_tuple; + PyObject *__pyx_n_s_Vec3; + PyObject *__pyx_n_u_Vec3; + PyObject *__pyx_n_s_Vec3___deepcopy; + PyObject *__pyx_n_s_Vec3___iter; + PyObject *__pyx_n_s_Vec3___reduce; + PyObject *__pyx_n_s_Vec3_angle_about; + PyObject *__pyx_n_s_Vec3_angle_between; + PyObject *__pyx_n_s_Vec3_copy; + PyObject *__pyx_n_s_Vec3_cross; + PyObject *__pyx_n_s_Vec3_distance; + PyObject *__pyx_n_s_Vec3_dot; + PyObject *__pyx_n_s_Vec3_from_angle; + PyObject *__pyx_n_s_Vec3_from_deg_angle; + PyObject *__pyx_n_s_Vec3_generate; + PyObject *__pyx_n_s_Vec3_is_parallel; + PyObject *__pyx_n_s_Vec3_isclose; + PyObject *__pyx_n_s_Vec3_lerp; + PyObject *__pyx_n_s_Vec3_list; + PyObject *__pyx_n_s_Vec3_normalize; + PyObject *__pyx_n_s_Vec3_orthogonal; + PyObject *__pyx_n_s_Vec3_project; + PyObject *__pyx_n_s_Vec3_random; + PyObject *__pyx_n_s_Vec3_replace; + PyObject *__pyx_n_s_Vec3_reversed; + PyObject *__pyx_n_s_Vec3_rotate; + PyObject *__pyx_n_s_Vec3_rotate_deg; + PyObject *__pyx_n_s_Vec3_round; + PyObject *__pyx_n_s_Vec3_sum; + PyObject *__pyx_n_s_Vec3_tuple; + PyObject *__pyx_n_s_X_AXIS; + PyObject *__pyx_n_s_Y_AXIS; + PyObject *__pyx_n_s_Z_AXIS; + PyObject *__pyx_n_s__100; + PyObject *__pyx_kp_u__12; + PyObject *__pyx_n_s__13; + PyObject *__pyx_kp_u__2; + PyObject *__pyx_kp_u__3; + PyObject *__pyx_kp_u__4; + PyObject *__pyx_n_s_a; + PyObject *__pyx_n_s_abs_tol; + PyObject *__pyx_n_s_add; + PyObject *__pyx_n_s_angle; + PyObject *__pyx_n_s_angle_2; + PyObject *__pyx_n_s_angle_about; + PyObject *__pyx_n_s_angle_between; + PyObject *__pyx_n_s_args; + PyObject *__pyx_n_s_asyncio_coroutines; + PyObject *__pyx_n_s_b; + PyObject *__pyx_n_s_base; + PyObject *__pyx_n_s_bool; + PyObject *__pyx_n_s_ccw; + PyObject *__pyx_n_s_cline_in_traceback; + PyObject *__pyx_n_s_close; + PyObject *__pyx_n_s_copy; + PyObject *__pyx_n_s_copy_2; + PyObject *__pyx_n_s_cross; + PyObject *__pyx_n_s_deepcopy; + PyObject *__pyx_n_s_det; + PyObject *__pyx_n_s_dict; + PyObject *__pyx_n_s_dict_2; + PyObject *__pyx_kp_u_disable; + PyObject *__pyx_n_s_distance; + PyObject *__pyx_n_s_dot; + PyObject *__pyx_kp_u_enable; + PyObject *__pyx_n_s_ezdxf_acc_vector; + PyObject *__pyx_n_s_ezdxf_math; + PyObject *__pyx_n_s_factor; + PyObject *__pyx_n_s_float; + PyObject *__pyx_n_s_from_angle; + PyObject *__pyx_n_s_from_deg_angle; + PyObject *__pyx_kp_u_gc; + PyObject *__pyx_n_s_generate; + PyObject *__pyx_n_s_generate_locals_genexpr; + PyObject *__pyx_n_s_genexpr; + PyObject *__pyx_n_s_iadd; + PyObject *__pyx_n_s_import; + PyObject *__pyx_n_s_imul; + PyObject *__pyx_n_s_initializing; + PyObject *__pyx_kp_s_int_None; + PyObject *__pyx_kp_u_invalid_argument_count; + PyObject *__pyx_kp_u_invalid_index; + PyObject *__pyx_n_s_is_coroutine; + PyObject *__pyx_n_s_is_null; + PyObject *__pyx_n_s_is_parallel; + PyObject *__pyx_n_s_isclose; + PyObject *__pyx_kp_u_isenabled; + PyObject *__pyx_n_s_isub; + PyObject *__pyx_n_s_items; + PyObject *__pyx_n_s_iter; + PyObject *__pyx_n_s_length; + PyObject *__pyx_n_s_lerp; + PyObject *__pyx_n_s_list; + PyObject *__pyx_n_s_magnitude; + PyObject *__pyx_n_s_magnitude_2; + PyObject *__pyx_n_s_main; + PyObject *__pyx_n_s_memodict; + PyObject *__pyx_n_s_mul; + PyObject *__pyx_n_s_name; + PyObject *__pyx_n_s_ndigits; + PyObject *__pyx_n_s_neg; + PyObject *__pyx_n_s_neg_v2; + PyObject *__pyx_n_s_normalize; + PyObject *__pyx_n_s_normalize_deg_angle; + PyObject *__pyx_n_s_normalize_rad_angle; + PyObject *__pyx_n_s_o; + PyObject *__pyx_n_s_orthogonal; + PyObject *__pyx_n_s_other; + PyObject *__pyx_n_s_p1; + PyObject *__pyx_n_s_p2; + PyObject *__pyx_n_s_project; + PyObject *__pyx_n_s_radd; + PyObject *__pyx_n_s_random; + PyObject *__pyx_n_s_reduce; + PyObject *__pyx_n_s_rel_tol; + PyObject *__pyx_n_s_replace; + PyObject *__pyx_n_s_res; + PyObject *__pyx_n_s_return; + PyObject *__pyx_n_s_reversed; + PyObject *__pyx_n_s_rotate; + PyObject *__pyx_n_s_rotate_deg; + PyObject *__pyx_n_s_round; + PyObject *__pyx_n_s_self; + PyObject *__pyx_n_s_self_angle; + PyObject *__pyx_n_s_send; + PyObject *__pyx_n_s_spatial_angle; + PyObject *__pyx_n_s_spec; + PyObject *__pyx_kp_s_src_ezdxf_acc_vector_pyx; + PyObject *__pyx_n_s_staticmethod; + PyObject *__pyx_n_s_str; + PyObject *__pyx_n_s_sub; + PyObject *__pyx_n_s_sum; + PyObject *__pyx_n_s_t; + PyObject *__pyx_n_s_target; + PyObject *__pyx_n_s_test; + PyObject *__pyx_n_s_throw; + PyObject *__pyx_n_s_tmp; + PyObject *__pyx_n_s_tuple; + PyObject *__pyx_n_s_typing; + PyObject *__pyx_n_s_uniform; + PyObject *__pyx_n_s_v; + PyObject *__pyx_n_s_v1; + PyObject *__pyx_n_s_v2; + PyObject *__pyx_n_s_x; + PyObject *__pyx_n_s_xyz; + PyObject *__pyx_n_s_y; + PyObject *__pyx_n_s_z; + PyObject *__pyx_float_1_; + PyObject *__pyx_float_0_5; + PyObject *__pyx_float_1_0; + PyObject *__pyx_int_0; + PyObject *__pyx_int_1; + PyObject *__pyx_int_neg_1; + double __pyx_k__5; + double __pyx_k__6; + double __pyx_k__8; + double __pyx_k__9; + double __pyx_k__10; + double __pyx_k__11; + PyObject *__pyx_tuple_; + PyObject *__pyx_tuple__7; + PyObject *__pyx_tuple__14; + PyObject *__pyx_tuple__17; + PyObject *__pyx_tuple__19; + PyObject *__pyx_tuple__21; + PyObject *__pyx_tuple__22; + PyObject *__pyx_tuple__25; + PyObject *__pyx_tuple__27; + PyObject *__pyx_tuple__29; + PyObject *__pyx_tuple__33; + PyObject *__pyx_tuple__35; + PyObject *__pyx_tuple__37; + PyObject *__pyx_tuple__38; + PyObject *__pyx_tuple__40; + PyObject *__pyx_tuple__41; + PyObject *__pyx_tuple__43; + PyObject *__pyx_tuple__45; + PyObject *__pyx_tuple__51; + PyObject *__pyx_tuple__53; + PyObject *__pyx_tuple__55; + PyObject *__pyx_tuple__58; + PyObject *__pyx_tuple__60; + PyObject *__pyx_tuple__67; + PyObject *__pyx_tuple__71; + PyObject *__pyx_tuple__74; + PyObject *__pyx_tuple__76; + PyObject *__pyx_tuple__80; + PyObject *__pyx_tuple__87; + PyObject *__pyx_tuple__89; + PyObject *__pyx_tuple__92; + PyObject *__pyx_tuple__93; + PyObject *__pyx_tuple__94; + PyObject *__pyx_tuple__95; + PyObject *__pyx_tuple__96; + PyObject *__pyx_tuple__98; + PyObject *__pyx_codeobj__15; + PyObject *__pyx_codeobj__16; + PyObject *__pyx_codeobj__18; + PyObject *__pyx_codeobj__20; + PyObject *__pyx_codeobj__23; + PyObject *__pyx_codeobj__24; + PyObject *__pyx_codeobj__26; + PyObject *__pyx_codeobj__28; + PyObject *__pyx_codeobj__30; + PyObject *__pyx_codeobj__31; + PyObject *__pyx_codeobj__32; + PyObject *__pyx_codeobj__34; + PyObject *__pyx_codeobj__36; + PyObject *__pyx_codeobj__39; + PyObject *__pyx_codeobj__42; + PyObject *__pyx_codeobj__44; + PyObject *__pyx_codeobj__46; + PyObject *__pyx_codeobj__47; + PyObject *__pyx_codeobj__48; + PyObject *__pyx_codeobj__49; + PyObject *__pyx_codeobj__50; + PyObject *__pyx_codeobj__52; + PyObject *__pyx_codeobj__54; + PyObject *__pyx_codeobj__56; + PyObject *__pyx_codeobj__57; + PyObject *__pyx_codeobj__59; + PyObject *__pyx_codeobj__61; + PyObject *__pyx_codeobj__62; + PyObject *__pyx_codeobj__63; + PyObject *__pyx_codeobj__64; + PyObject *__pyx_codeobj__65; + PyObject *__pyx_codeobj__66; + PyObject *__pyx_codeobj__68; + PyObject *__pyx_codeobj__69; + PyObject *__pyx_codeobj__70; + PyObject *__pyx_codeobj__72; + PyObject *__pyx_codeobj__73; + PyObject *__pyx_codeobj__75; + PyObject *__pyx_codeobj__77; + PyObject *__pyx_codeobj__78; + PyObject *__pyx_codeobj__79; + PyObject *__pyx_codeobj__81; + PyObject *__pyx_codeobj__82; + PyObject *__pyx_codeobj__83; + PyObject *__pyx_codeobj__84; + PyObject *__pyx_codeobj__85; + PyObject *__pyx_codeobj__86; + PyObject *__pyx_codeobj__88; + PyObject *__pyx_codeobj__90; + PyObject *__pyx_codeobj__91; + PyObject *__pyx_codeobj__97; + PyObject *__pyx_codeobj__99; +} __pyx_mstate; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { + extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate(o) ((__pyx_mstate *)__Pyx_PyModule_GetState(o)) + +#define __pyx_mstate_global (__pyx_mstate(PyState_FindModule(&__pyx_moduledef))) + +#define __pyx_m (PyState_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstate __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstate *__pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_clear(PyObject *m) { + __pyx_mstate *clear_module_state = __pyx_mstate(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector_Vec2); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector_Vec3); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr); + Py_CLEAR(clear_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__); + Py_CLEAR(clear_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__); + Py_CLEAR(clear_module_state->__pyx_n_s_AnyVec); + Py_CLEAR(clear_module_state->__pyx_kp_s_AnyVec_2); + Py_CLEAR(clear_module_state->__pyx_n_s_IndexError); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterable); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_UVec); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterable_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_s_Iterator); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Vec2); + Py_CLEAR(clear_module_state->__pyx_kp_s_Iterator_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_List); + Py_CLEAR(clear_module_state->__pyx_kp_s_List_Vec2); + Py_CLEAR(clear_module_state->__pyx_kp_s_List_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_NULLVEC); + Py_CLEAR(clear_module_state->__pyx_n_s_NotImplemented); + Py_CLEAR(clear_module_state->__pyx_n_s_Sequence); + Py_CLEAR(clear_module_state->__pyx_kp_s_Sequence_Vec2); + Py_CLEAR(clear_module_state->__pyx_kp_s_Sequence_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_TYPE_CHECKING); + Py_CLEAR(clear_module_state->__pyx_n_s_Tuple); + Py_CLEAR(clear_module_state->__pyx_n_s_TypeError); + Py_CLEAR(clear_module_state->__pyx_n_s_UVec); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_u_Vec2); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2___copy); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2___deepcopy); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2___iter); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2___reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_angle_between); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_copy); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_det); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_distance); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_dot); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_from_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_from_deg_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_generate); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_isclose); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_lerp); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_list); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_normalize); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_orthogonal); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_project); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_rotate_deg); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_round); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_sum); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec2_tuple); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_u_Vec3); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3___deepcopy); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3___iter); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3___reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_angle_about); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_angle_between); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_copy); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_cross); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_distance); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_dot); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_from_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_from_deg_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_generate); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_is_parallel); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_isclose); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_lerp); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_list); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_normalize); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_orthogonal); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_project); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_random); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_replace); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_reversed); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_rotate_deg); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_round); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_sum); + Py_CLEAR(clear_module_state->__pyx_n_s_Vec3_tuple); + Py_CLEAR(clear_module_state->__pyx_n_s_X_AXIS); + Py_CLEAR(clear_module_state->__pyx_n_s_Y_AXIS); + Py_CLEAR(clear_module_state->__pyx_n_s_Z_AXIS); + Py_CLEAR(clear_module_state->__pyx_n_s__100); + Py_CLEAR(clear_module_state->__pyx_kp_u__12); + Py_CLEAR(clear_module_state->__pyx_n_s__13); + Py_CLEAR(clear_module_state->__pyx_kp_u__2); + Py_CLEAR(clear_module_state->__pyx_kp_u__3); + Py_CLEAR(clear_module_state->__pyx_kp_u__4); + Py_CLEAR(clear_module_state->__pyx_n_s_a); + Py_CLEAR(clear_module_state->__pyx_n_s_abs_tol); + Py_CLEAR(clear_module_state->__pyx_n_s_add); + Py_CLEAR(clear_module_state->__pyx_n_s_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_2); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_about); + Py_CLEAR(clear_module_state->__pyx_n_s_angle_between); + Py_CLEAR(clear_module_state->__pyx_n_s_args); + Py_CLEAR(clear_module_state->__pyx_n_s_asyncio_coroutines); + Py_CLEAR(clear_module_state->__pyx_n_s_b); + Py_CLEAR(clear_module_state->__pyx_n_s_base); + Py_CLEAR(clear_module_state->__pyx_n_s_bool); + Py_CLEAR(clear_module_state->__pyx_n_s_ccw); + Py_CLEAR(clear_module_state->__pyx_n_s_cline_in_traceback); + Py_CLEAR(clear_module_state->__pyx_n_s_close); + Py_CLEAR(clear_module_state->__pyx_n_s_copy); + Py_CLEAR(clear_module_state->__pyx_n_s_copy_2); + Py_CLEAR(clear_module_state->__pyx_n_s_cross); + Py_CLEAR(clear_module_state->__pyx_n_s_deepcopy); + Py_CLEAR(clear_module_state->__pyx_n_s_det); + Py_CLEAR(clear_module_state->__pyx_n_s_dict); + Py_CLEAR(clear_module_state->__pyx_n_s_dict_2); + Py_CLEAR(clear_module_state->__pyx_kp_u_disable); + Py_CLEAR(clear_module_state->__pyx_n_s_distance); + Py_CLEAR(clear_module_state->__pyx_n_s_dot); + Py_CLEAR(clear_module_state->__pyx_kp_u_enable); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_acc_vector); + Py_CLEAR(clear_module_state->__pyx_n_s_ezdxf_math); + Py_CLEAR(clear_module_state->__pyx_n_s_factor); + Py_CLEAR(clear_module_state->__pyx_n_s_float); + Py_CLEAR(clear_module_state->__pyx_n_s_from_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_from_deg_angle); + Py_CLEAR(clear_module_state->__pyx_kp_u_gc); + Py_CLEAR(clear_module_state->__pyx_n_s_generate); + Py_CLEAR(clear_module_state->__pyx_n_s_generate_locals_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_genexpr); + Py_CLEAR(clear_module_state->__pyx_n_s_iadd); + Py_CLEAR(clear_module_state->__pyx_n_s_import); + Py_CLEAR(clear_module_state->__pyx_n_s_imul); + Py_CLEAR(clear_module_state->__pyx_n_s_initializing); + Py_CLEAR(clear_module_state->__pyx_kp_s_int_None); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_argument_count); + Py_CLEAR(clear_module_state->__pyx_kp_u_invalid_index); + Py_CLEAR(clear_module_state->__pyx_n_s_is_coroutine); + Py_CLEAR(clear_module_state->__pyx_n_s_is_null); + Py_CLEAR(clear_module_state->__pyx_n_s_is_parallel); + Py_CLEAR(clear_module_state->__pyx_n_s_isclose); + Py_CLEAR(clear_module_state->__pyx_kp_u_isenabled); + Py_CLEAR(clear_module_state->__pyx_n_s_isub); + Py_CLEAR(clear_module_state->__pyx_n_s_items); + Py_CLEAR(clear_module_state->__pyx_n_s_iter); + Py_CLEAR(clear_module_state->__pyx_n_s_length); + Py_CLEAR(clear_module_state->__pyx_n_s_lerp); + Py_CLEAR(clear_module_state->__pyx_n_s_list); + Py_CLEAR(clear_module_state->__pyx_n_s_magnitude); + Py_CLEAR(clear_module_state->__pyx_n_s_magnitude_2); + Py_CLEAR(clear_module_state->__pyx_n_s_main); + Py_CLEAR(clear_module_state->__pyx_n_s_memodict); + Py_CLEAR(clear_module_state->__pyx_n_s_mul); + Py_CLEAR(clear_module_state->__pyx_n_s_name); + Py_CLEAR(clear_module_state->__pyx_n_s_ndigits); + Py_CLEAR(clear_module_state->__pyx_n_s_neg); + Py_CLEAR(clear_module_state->__pyx_n_s_neg_v2); + Py_CLEAR(clear_module_state->__pyx_n_s_normalize); + Py_CLEAR(clear_module_state->__pyx_n_s_normalize_deg_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_normalize_rad_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_o); + Py_CLEAR(clear_module_state->__pyx_n_s_orthogonal); + Py_CLEAR(clear_module_state->__pyx_n_s_other); + Py_CLEAR(clear_module_state->__pyx_n_s_p1); + Py_CLEAR(clear_module_state->__pyx_n_s_p2); + Py_CLEAR(clear_module_state->__pyx_n_s_project); + Py_CLEAR(clear_module_state->__pyx_n_s_radd); + Py_CLEAR(clear_module_state->__pyx_n_s_random); + Py_CLEAR(clear_module_state->__pyx_n_s_reduce); + Py_CLEAR(clear_module_state->__pyx_n_s_rel_tol); + Py_CLEAR(clear_module_state->__pyx_n_s_replace); + Py_CLEAR(clear_module_state->__pyx_n_s_res); + Py_CLEAR(clear_module_state->__pyx_n_s_return); + Py_CLEAR(clear_module_state->__pyx_n_s_reversed); + Py_CLEAR(clear_module_state->__pyx_n_s_rotate); + Py_CLEAR(clear_module_state->__pyx_n_s_rotate_deg); + Py_CLEAR(clear_module_state->__pyx_n_s_round); + Py_CLEAR(clear_module_state->__pyx_n_s_self); + Py_CLEAR(clear_module_state->__pyx_n_s_self_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_send); + Py_CLEAR(clear_module_state->__pyx_n_s_spatial_angle); + Py_CLEAR(clear_module_state->__pyx_n_s_spec); + Py_CLEAR(clear_module_state->__pyx_kp_s_src_ezdxf_acc_vector_pyx); + Py_CLEAR(clear_module_state->__pyx_n_s_staticmethod); + Py_CLEAR(clear_module_state->__pyx_n_s_str); + Py_CLEAR(clear_module_state->__pyx_n_s_sub); + Py_CLEAR(clear_module_state->__pyx_n_s_sum); + Py_CLEAR(clear_module_state->__pyx_n_s_t); + Py_CLEAR(clear_module_state->__pyx_n_s_target); + Py_CLEAR(clear_module_state->__pyx_n_s_test); + Py_CLEAR(clear_module_state->__pyx_n_s_throw); + Py_CLEAR(clear_module_state->__pyx_n_s_tmp); + Py_CLEAR(clear_module_state->__pyx_n_s_tuple); + Py_CLEAR(clear_module_state->__pyx_n_s_typing); + Py_CLEAR(clear_module_state->__pyx_n_s_uniform); + Py_CLEAR(clear_module_state->__pyx_n_s_v); + Py_CLEAR(clear_module_state->__pyx_n_s_v1); + Py_CLEAR(clear_module_state->__pyx_n_s_v2); + Py_CLEAR(clear_module_state->__pyx_n_s_x); + Py_CLEAR(clear_module_state->__pyx_n_s_xyz); + Py_CLEAR(clear_module_state->__pyx_n_s_y); + Py_CLEAR(clear_module_state->__pyx_n_s_z); + Py_CLEAR(clear_module_state->__pyx_float_1_); + Py_CLEAR(clear_module_state->__pyx_float_0_5); + Py_CLEAR(clear_module_state->__pyx_float_1_0); + Py_CLEAR(clear_module_state->__pyx_int_0); + Py_CLEAR(clear_module_state->__pyx_int_1); + Py_CLEAR(clear_module_state->__pyx_int_neg_1); + Py_CLEAR(clear_module_state->__pyx_tuple_); + Py_CLEAR(clear_module_state->__pyx_tuple__7); + Py_CLEAR(clear_module_state->__pyx_tuple__14); + Py_CLEAR(clear_module_state->__pyx_tuple__17); + Py_CLEAR(clear_module_state->__pyx_tuple__19); + Py_CLEAR(clear_module_state->__pyx_tuple__21); + Py_CLEAR(clear_module_state->__pyx_tuple__22); + Py_CLEAR(clear_module_state->__pyx_tuple__25); + Py_CLEAR(clear_module_state->__pyx_tuple__27); + Py_CLEAR(clear_module_state->__pyx_tuple__29); + Py_CLEAR(clear_module_state->__pyx_tuple__33); + Py_CLEAR(clear_module_state->__pyx_tuple__35); + Py_CLEAR(clear_module_state->__pyx_tuple__37); + Py_CLEAR(clear_module_state->__pyx_tuple__38); + Py_CLEAR(clear_module_state->__pyx_tuple__40); + Py_CLEAR(clear_module_state->__pyx_tuple__41); + Py_CLEAR(clear_module_state->__pyx_tuple__43); + Py_CLEAR(clear_module_state->__pyx_tuple__45); + Py_CLEAR(clear_module_state->__pyx_tuple__51); + Py_CLEAR(clear_module_state->__pyx_tuple__53); + Py_CLEAR(clear_module_state->__pyx_tuple__55); + Py_CLEAR(clear_module_state->__pyx_tuple__58); + Py_CLEAR(clear_module_state->__pyx_tuple__60); + Py_CLEAR(clear_module_state->__pyx_tuple__67); + Py_CLEAR(clear_module_state->__pyx_tuple__71); + Py_CLEAR(clear_module_state->__pyx_tuple__74); + Py_CLEAR(clear_module_state->__pyx_tuple__76); + Py_CLEAR(clear_module_state->__pyx_tuple__80); + Py_CLEAR(clear_module_state->__pyx_tuple__87); + Py_CLEAR(clear_module_state->__pyx_tuple__89); + Py_CLEAR(clear_module_state->__pyx_tuple__92); + Py_CLEAR(clear_module_state->__pyx_tuple__93); + Py_CLEAR(clear_module_state->__pyx_tuple__94); + Py_CLEAR(clear_module_state->__pyx_tuple__95); + Py_CLEAR(clear_module_state->__pyx_tuple__96); + Py_CLEAR(clear_module_state->__pyx_tuple__98); + Py_CLEAR(clear_module_state->__pyx_codeobj__15); + Py_CLEAR(clear_module_state->__pyx_codeobj__16); + Py_CLEAR(clear_module_state->__pyx_codeobj__18); + Py_CLEAR(clear_module_state->__pyx_codeobj__20); + Py_CLEAR(clear_module_state->__pyx_codeobj__23); + Py_CLEAR(clear_module_state->__pyx_codeobj__24); + Py_CLEAR(clear_module_state->__pyx_codeobj__26); + Py_CLEAR(clear_module_state->__pyx_codeobj__28); + Py_CLEAR(clear_module_state->__pyx_codeobj__30); + Py_CLEAR(clear_module_state->__pyx_codeobj__31); + Py_CLEAR(clear_module_state->__pyx_codeobj__32); + Py_CLEAR(clear_module_state->__pyx_codeobj__34); + Py_CLEAR(clear_module_state->__pyx_codeobj__36); + Py_CLEAR(clear_module_state->__pyx_codeobj__39); + Py_CLEAR(clear_module_state->__pyx_codeobj__42); + Py_CLEAR(clear_module_state->__pyx_codeobj__44); + Py_CLEAR(clear_module_state->__pyx_codeobj__46); + Py_CLEAR(clear_module_state->__pyx_codeobj__47); + Py_CLEAR(clear_module_state->__pyx_codeobj__48); + Py_CLEAR(clear_module_state->__pyx_codeobj__49); + Py_CLEAR(clear_module_state->__pyx_codeobj__50); + Py_CLEAR(clear_module_state->__pyx_codeobj__52); + Py_CLEAR(clear_module_state->__pyx_codeobj__54); + Py_CLEAR(clear_module_state->__pyx_codeobj__56); + Py_CLEAR(clear_module_state->__pyx_codeobj__57); + Py_CLEAR(clear_module_state->__pyx_codeobj__59); + Py_CLEAR(clear_module_state->__pyx_codeobj__61); + Py_CLEAR(clear_module_state->__pyx_codeobj__62); + Py_CLEAR(clear_module_state->__pyx_codeobj__63); + Py_CLEAR(clear_module_state->__pyx_codeobj__64); + Py_CLEAR(clear_module_state->__pyx_codeobj__65); + Py_CLEAR(clear_module_state->__pyx_codeobj__66); + Py_CLEAR(clear_module_state->__pyx_codeobj__68); + Py_CLEAR(clear_module_state->__pyx_codeobj__69); + Py_CLEAR(clear_module_state->__pyx_codeobj__70); + Py_CLEAR(clear_module_state->__pyx_codeobj__72); + Py_CLEAR(clear_module_state->__pyx_codeobj__73); + Py_CLEAR(clear_module_state->__pyx_codeobj__75); + Py_CLEAR(clear_module_state->__pyx_codeobj__77); + Py_CLEAR(clear_module_state->__pyx_codeobj__78); + Py_CLEAR(clear_module_state->__pyx_codeobj__79); + Py_CLEAR(clear_module_state->__pyx_codeobj__81); + Py_CLEAR(clear_module_state->__pyx_codeobj__82); + Py_CLEAR(clear_module_state->__pyx_codeobj__83); + Py_CLEAR(clear_module_state->__pyx_codeobj__84); + Py_CLEAR(clear_module_state->__pyx_codeobj__85); + Py_CLEAR(clear_module_state->__pyx_codeobj__86); + Py_CLEAR(clear_module_state->__pyx_codeobj__88); + Py_CLEAR(clear_module_state->__pyx_codeobj__90); + Py_CLEAR(clear_module_state->__pyx_codeobj__91); + Py_CLEAR(clear_module_state->__pyx_codeobj__97); + Py_CLEAR(clear_module_state->__pyx_codeobj__99); + return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstate *traverse_module_state = __pyx_mstate(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + Py_VISIT(traverse_module_state->__pyx_empty_tuple); + Py_VISIT(traverse_module_state->__pyx_empty_bytes); + Py_VISIT(traverse_module_state->__pyx_empty_unicode); + #ifdef __Pyx_CyFunction_USED + Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + #endif + #ifdef __Pyx_FusedFunction_USED + Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); + #endif + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector_Vec2); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector_Vec3); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr); + Py_VISIT(traverse_module_state->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__); + Py_VISIT(traverse_module_state->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__); + Py_VISIT(traverse_module_state->__pyx_n_s_AnyVec); + Py_VISIT(traverse_module_state->__pyx_kp_s_AnyVec_2); + Py_VISIT(traverse_module_state->__pyx_n_s_IndexError); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterable); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_UVec); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterable_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_s_Iterator); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Vec2); + Py_VISIT(traverse_module_state->__pyx_kp_s_Iterator_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_List); + Py_VISIT(traverse_module_state->__pyx_kp_s_List_Vec2); + Py_VISIT(traverse_module_state->__pyx_kp_s_List_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_NULLVEC); + Py_VISIT(traverse_module_state->__pyx_n_s_NotImplemented); + Py_VISIT(traverse_module_state->__pyx_n_s_Sequence); + Py_VISIT(traverse_module_state->__pyx_kp_s_Sequence_Vec2); + Py_VISIT(traverse_module_state->__pyx_kp_s_Sequence_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_TYPE_CHECKING); + Py_VISIT(traverse_module_state->__pyx_n_s_Tuple); + Py_VISIT(traverse_module_state->__pyx_n_s_TypeError); + Py_VISIT(traverse_module_state->__pyx_n_s_UVec); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_u_Vec2); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2___copy); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2___deepcopy); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2___iter); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2___reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_angle_between); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_copy); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_det); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_distance); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_dot); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_from_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_from_deg_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_generate); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_isclose); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_lerp); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_list); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_normalize); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_orthogonal); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_project); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_rotate_deg); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_round); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_sum); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec2_tuple); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_u_Vec3); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3___deepcopy); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3___iter); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3___reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_angle_about); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_angle_between); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_copy); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_cross); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_distance); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_dot); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_from_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_from_deg_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_generate); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_is_parallel); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_isclose); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_lerp); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_list); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_normalize); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_orthogonal); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_project); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_random); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_replace); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_reversed); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_rotate_deg); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_round); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_sum); + Py_VISIT(traverse_module_state->__pyx_n_s_Vec3_tuple); + Py_VISIT(traverse_module_state->__pyx_n_s_X_AXIS); + Py_VISIT(traverse_module_state->__pyx_n_s_Y_AXIS); + Py_VISIT(traverse_module_state->__pyx_n_s_Z_AXIS); + Py_VISIT(traverse_module_state->__pyx_n_s__100); + Py_VISIT(traverse_module_state->__pyx_kp_u__12); + Py_VISIT(traverse_module_state->__pyx_n_s__13); + Py_VISIT(traverse_module_state->__pyx_kp_u__2); + Py_VISIT(traverse_module_state->__pyx_kp_u__3); + Py_VISIT(traverse_module_state->__pyx_kp_u__4); + Py_VISIT(traverse_module_state->__pyx_n_s_a); + Py_VISIT(traverse_module_state->__pyx_n_s_abs_tol); + Py_VISIT(traverse_module_state->__pyx_n_s_add); + Py_VISIT(traverse_module_state->__pyx_n_s_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_2); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_about); + Py_VISIT(traverse_module_state->__pyx_n_s_angle_between); + Py_VISIT(traverse_module_state->__pyx_n_s_args); + Py_VISIT(traverse_module_state->__pyx_n_s_asyncio_coroutines); + Py_VISIT(traverse_module_state->__pyx_n_s_b); + Py_VISIT(traverse_module_state->__pyx_n_s_base); + Py_VISIT(traverse_module_state->__pyx_n_s_bool); + Py_VISIT(traverse_module_state->__pyx_n_s_ccw); + Py_VISIT(traverse_module_state->__pyx_n_s_cline_in_traceback); + Py_VISIT(traverse_module_state->__pyx_n_s_close); + Py_VISIT(traverse_module_state->__pyx_n_s_copy); + Py_VISIT(traverse_module_state->__pyx_n_s_copy_2); + Py_VISIT(traverse_module_state->__pyx_n_s_cross); + Py_VISIT(traverse_module_state->__pyx_n_s_deepcopy); + Py_VISIT(traverse_module_state->__pyx_n_s_det); + Py_VISIT(traverse_module_state->__pyx_n_s_dict); + Py_VISIT(traverse_module_state->__pyx_n_s_dict_2); + Py_VISIT(traverse_module_state->__pyx_kp_u_disable); + Py_VISIT(traverse_module_state->__pyx_n_s_distance); + Py_VISIT(traverse_module_state->__pyx_n_s_dot); + Py_VISIT(traverse_module_state->__pyx_kp_u_enable); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_acc_vector); + Py_VISIT(traverse_module_state->__pyx_n_s_ezdxf_math); + Py_VISIT(traverse_module_state->__pyx_n_s_factor); + Py_VISIT(traverse_module_state->__pyx_n_s_float); + Py_VISIT(traverse_module_state->__pyx_n_s_from_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_from_deg_angle); + Py_VISIT(traverse_module_state->__pyx_kp_u_gc); + Py_VISIT(traverse_module_state->__pyx_n_s_generate); + Py_VISIT(traverse_module_state->__pyx_n_s_generate_locals_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_genexpr); + Py_VISIT(traverse_module_state->__pyx_n_s_iadd); + Py_VISIT(traverse_module_state->__pyx_n_s_import); + Py_VISIT(traverse_module_state->__pyx_n_s_imul); + Py_VISIT(traverse_module_state->__pyx_n_s_initializing); + Py_VISIT(traverse_module_state->__pyx_kp_s_int_None); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_argument_count); + Py_VISIT(traverse_module_state->__pyx_kp_u_invalid_index); + Py_VISIT(traverse_module_state->__pyx_n_s_is_coroutine); + Py_VISIT(traverse_module_state->__pyx_n_s_is_null); + Py_VISIT(traverse_module_state->__pyx_n_s_is_parallel); + Py_VISIT(traverse_module_state->__pyx_n_s_isclose); + Py_VISIT(traverse_module_state->__pyx_kp_u_isenabled); + Py_VISIT(traverse_module_state->__pyx_n_s_isub); + Py_VISIT(traverse_module_state->__pyx_n_s_items); + Py_VISIT(traverse_module_state->__pyx_n_s_iter); + Py_VISIT(traverse_module_state->__pyx_n_s_length); + Py_VISIT(traverse_module_state->__pyx_n_s_lerp); + Py_VISIT(traverse_module_state->__pyx_n_s_list); + Py_VISIT(traverse_module_state->__pyx_n_s_magnitude); + Py_VISIT(traverse_module_state->__pyx_n_s_magnitude_2); + Py_VISIT(traverse_module_state->__pyx_n_s_main); + Py_VISIT(traverse_module_state->__pyx_n_s_memodict); + Py_VISIT(traverse_module_state->__pyx_n_s_mul); + Py_VISIT(traverse_module_state->__pyx_n_s_name); + Py_VISIT(traverse_module_state->__pyx_n_s_ndigits); + Py_VISIT(traverse_module_state->__pyx_n_s_neg); + Py_VISIT(traverse_module_state->__pyx_n_s_neg_v2); + Py_VISIT(traverse_module_state->__pyx_n_s_normalize); + Py_VISIT(traverse_module_state->__pyx_n_s_normalize_deg_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_normalize_rad_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_o); + Py_VISIT(traverse_module_state->__pyx_n_s_orthogonal); + Py_VISIT(traverse_module_state->__pyx_n_s_other); + Py_VISIT(traverse_module_state->__pyx_n_s_p1); + Py_VISIT(traverse_module_state->__pyx_n_s_p2); + Py_VISIT(traverse_module_state->__pyx_n_s_project); + Py_VISIT(traverse_module_state->__pyx_n_s_radd); + Py_VISIT(traverse_module_state->__pyx_n_s_random); + Py_VISIT(traverse_module_state->__pyx_n_s_reduce); + Py_VISIT(traverse_module_state->__pyx_n_s_rel_tol); + Py_VISIT(traverse_module_state->__pyx_n_s_replace); + Py_VISIT(traverse_module_state->__pyx_n_s_res); + Py_VISIT(traverse_module_state->__pyx_n_s_return); + Py_VISIT(traverse_module_state->__pyx_n_s_reversed); + Py_VISIT(traverse_module_state->__pyx_n_s_rotate); + Py_VISIT(traverse_module_state->__pyx_n_s_rotate_deg); + Py_VISIT(traverse_module_state->__pyx_n_s_round); + Py_VISIT(traverse_module_state->__pyx_n_s_self); + Py_VISIT(traverse_module_state->__pyx_n_s_self_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_send); + Py_VISIT(traverse_module_state->__pyx_n_s_spatial_angle); + Py_VISIT(traverse_module_state->__pyx_n_s_spec); + Py_VISIT(traverse_module_state->__pyx_kp_s_src_ezdxf_acc_vector_pyx); + Py_VISIT(traverse_module_state->__pyx_n_s_staticmethod); + Py_VISIT(traverse_module_state->__pyx_n_s_str); + Py_VISIT(traverse_module_state->__pyx_n_s_sub); + Py_VISIT(traverse_module_state->__pyx_n_s_sum); + Py_VISIT(traverse_module_state->__pyx_n_s_t); + Py_VISIT(traverse_module_state->__pyx_n_s_target); + Py_VISIT(traverse_module_state->__pyx_n_s_test); + Py_VISIT(traverse_module_state->__pyx_n_s_throw); + Py_VISIT(traverse_module_state->__pyx_n_s_tmp); + Py_VISIT(traverse_module_state->__pyx_n_s_tuple); + Py_VISIT(traverse_module_state->__pyx_n_s_typing); + Py_VISIT(traverse_module_state->__pyx_n_s_uniform); + Py_VISIT(traverse_module_state->__pyx_n_s_v); + Py_VISIT(traverse_module_state->__pyx_n_s_v1); + Py_VISIT(traverse_module_state->__pyx_n_s_v2); + Py_VISIT(traverse_module_state->__pyx_n_s_x); + Py_VISIT(traverse_module_state->__pyx_n_s_xyz); + Py_VISIT(traverse_module_state->__pyx_n_s_y); + Py_VISIT(traverse_module_state->__pyx_n_s_z); + Py_VISIT(traverse_module_state->__pyx_float_1_); + Py_VISIT(traverse_module_state->__pyx_float_0_5); + Py_VISIT(traverse_module_state->__pyx_float_1_0); + Py_VISIT(traverse_module_state->__pyx_int_0); + Py_VISIT(traverse_module_state->__pyx_int_1); + Py_VISIT(traverse_module_state->__pyx_int_neg_1); + Py_VISIT(traverse_module_state->__pyx_tuple_); + Py_VISIT(traverse_module_state->__pyx_tuple__7); + Py_VISIT(traverse_module_state->__pyx_tuple__14); + Py_VISIT(traverse_module_state->__pyx_tuple__17); + Py_VISIT(traverse_module_state->__pyx_tuple__19); + Py_VISIT(traverse_module_state->__pyx_tuple__21); + Py_VISIT(traverse_module_state->__pyx_tuple__22); + Py_VISIT(traverse_module_state->__pyx_tuple__25); + Py_VISIT(traverse_module_state->__pyx_tuple__27); + Py_VISIT(traverse_module_state->__pyx_tuple__29); + Py_VISIT(traverse_module_state->__pyx_tuple__33); + Py_VISIT(traverse_module_state->__pyx_tuple__35); + Py_VISIT(traverse_module_state->__pyx_tuple__37); + Py_VISIT(traverse_module_state->__pyx_tuple__38); + Py_VISIT(traverse_module_state->__pyx_tuple__40); + Py_VISIT(traverse_module_state->__pyx_tuple__41); + Py_VISIT(traverse_module_state->__pyx_tuple__43); + Py_VISIT(traverse_module_state->__pyx_tuple__45); + Py_VISIT(traverse_module_state->__pyx_tuple__51); + Py_VISIT(traverse_module_state->__pyx_tuple__53); + Py_VISIT(traverse_module_state->__pyx_tuple__55); + Py_VISIT(traverse_module_state->__pyx_tuple__58); + Py_VISIT(traverse_module_state->__pyx_tuple__60); + Py_VISIT(traverse_module_state->__pyx_tuple__67); + Py_VISIT(traverse_module_state->__pyx_tuple__71); + Py_VISIT(traverse_module_state->__pyx_tuple__74); + Py_VISIT(traverse_module_state->__pyx_tuple__76); + Py_VISIT(traverse_module_state->__pyx_tuple__80); + Py_VISIT(traverse_module_state->__pyx_tuple__87); + Py_VISIT(traverse_module_state->__pyx_tuple__89); + Py_VISIT(traverse_module_state->__pyx_tuple__92); + Py_VISIT(traverse_module_state->__pyx_tuple__93); + Py_VISIT(traverse_module_state->__pyx_tuple__94); + Py_VISIT(traverse_module_state->__pyx_tuple__95); + Py_VISIT(traverse_module_state->__pyx_tuple__96); + Py_VISIT(traverse_module_state->__pyx_tuple__98); + Py_VISIT(traverse_module_state->__pyx_codeobj__15); + Py_VISIT(traverse_module_state->__pyx_codeobj__16); + Py_VISIT(traverse_module_state->__pyx_codeobj__18); + Py_VISIT(traverse_module_state->__pyx_codeobj__20); + Py_VISIT(traverse_module_state->__pyx_codeobj__23); + Py_VISIT(traverse_module_state->__pyx_codeobj__24); + Py_VISIT(traverse_module_state->__pyx_codeobj__26); + Py_VISIT(traverse_module_state->__pyx_codeobj__28); + Py_VISIT(traverse_module_state->__pyx_codeobj__30); + Py_VISIT(traverse_module_state->__pyx_codeobj__31); + Py_VISIT(traverse_module_state->__pyx_codeobj__32); + Py_VISIT(traverse_module_state->__pyx_codeobj__34); + Py_VISIT(traverse_module_state->__pyx_codeobj__36); + Py_VISIT(traverse_module_state->__pyx_codeobj__39); + Py_VISIT(traverse_module_state->__pyx_codeobj__42); + Py_VISIT(traverse_module_state->__pyx_codeobj__44); + Py_VISIT(traverse_module_state->__pyx_codeobj__46); + Py_VISIT(traverse_module_state->__pyx_codeobj__47); + Py_VISIT(traverse_module_state->__pyx_codeobj__48); + Py_VISIT(traverse_module_state->__pyx_codeobj__49); + Py_VISIT(traverse_module_state->__pyx_codeobj__50); + Py_VISIT(traverse_module_state->__pyx_codeobj__52); + Py_VISIT(traverse_module_state->__pyx_codeobj__54); + Py_VISIT(traverse_module_state->__pyx_codeobj__56); + Py_VISIT(traverse_module_state->__pyx_codeobj__57); + Py_VISIT(traverse_module_state->__pyx_codeobj__59); + Py_VISIT(traverse_module_state->__pyx_codeobj__61); + Py_VISIT(traverse_module_state->__pyx_codeobj__62); + Py_VISIT(traverse_module_state->__pyx_codeobj__63); + Py_VISIT(traverse_module_state->__pyx_codeobj__64); + Py_VISIT(traverse_module_state->__pyx_codeobj__65); + Py_VISIT(traverse_module_state->__pyx_codeobj__66); + Py_VISIT(traverse_module_state->__pyx_codeobj__68); + Py_VISIT(traverse_module_state->__pyx_codeobj__69); + Py_VISIT(traverse_module_state->__pyx_codeobj__70); + Py_VISIT(traverse_module_state->__pyx_codeobj__72); + Py_VISIT(traverse_module_state->__pyx_codeobj__73); + Py_VISIT(traverse_module_state->__pyx_codeobj__75); + Py_VISIT(traverse_module_state->__pyx_codeobj__77); + Py_VISIT(traverse_module_state->__pyx_codeobj__78); + Py_VISIT(traverse_module_state->__pyx_codeobj__79); + Py_VISIT(traverse_module_state->__pyx_codeobj__81); + Py_VISIT(traverse_module_state->__pyx_codeobj__82); + Py_VISIT(traverse_module_state->__pyx_codeobj__83); + Py_VISIT(traverse_module_state->__pyx_codeobj__84); + Py_VISIT(traverse_module_state->__pyx_codeobj__85); + Py_VISIT(traverse_module_state->__pyx_codeobj__86); + Py_VISIT(traverse_module_state->__pyx_codeobj__88); + Py_VISIT(traverse_module_state->__pyx_codeobj__90); + Py_VISIT(traverse_module_state->__pyx_codeobj__91); + Py_VISIT(traverse_module_state->__pyx_codeobj__97); + Py_VISIT(traverse_module_state->__pyx_codeobj__99); + return 0; +} +#endif +/* #### Code section: module_state_defines ### */ +#define __pyx_d __pyx_mstate_global->__pyx_d +#define __pyx_b __pyx_mstate_global->__pyx_b +#define __pyx_cython_runtime __pyx_mstate_global->__pyx_cython_runtime +#define __pyx_empty_tuple __pyx_mstate_global->__pyx_empty_tuple +#define __pyx_empty_bytes __pyx_mstate_global->__pyx_empty_bytes +#define __pyx_empty_unicode __pyx_mstate_global->__pyx_empty_unicode +#ifdef __Pyx_CyFunction_USED +#define __pyx_CyFunctionType __pyx_mstate_global->__pyx_CyFunctionType +#endif +#ifdef __Pyx_FusedFunction_USED +#define __pyx_FusedFunctionType __pyx_mstate_global->__pyx_FusedFunctionType +#endif +#ifdef __Pyx_Generator_USED +#define __pyx_GeneratorType __pyx_mstate_global->__pyx_GeneratorType +#endif +#ifdef __Pyx_IterableCoroutine_USED +#define __pyx_IterableCoroutineType __pyx_mstate_global->__pyx_IterableCoroutineType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineAwaitType __pyx_mstate_global->__pyx_CoroutineAwaitType +#endif +#ifdef __Pyx_Coroutine_USED +#define __pyx_CoroutineType __pyx_mstate_global->__pyx_CoroutineType +#endif +#if CYTHON_USE_MODULE_STATE +#endif +#if CYTHON_USE_MODULE_STATE +#define __pyx_type_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector_Vec2 +#define __pyx_type_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector_Vec3 +#define __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr +#define __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ +#define __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr +#define __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ __pyx_mstate_global->__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ +#endif +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec2 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec2 +#define __pyx_ptype_5ezdxf_3acc_6vector_Vec3 __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector_Vec3 +#define __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr +#define __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ +#define __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr +#define __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ __pyx_mstate_global->__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ +#define __pyx_n_s_AnyVec __pyx_mstate_global->__pyx_n_s_AnyVec +#define __pyx_kp_s_AnyVec_2 __pyx_mstate_global->__pyx_kp_s_AnyVec_2 +#define __pyx_n_s_IndexError __pyx_mstate_global->__pyx_n_s_IndexError +#define __pyx_n_s_Iterable __pyx_mstate_global->__pyx_n_s_Iterable +#define __pyx_kp_s_Iterable_UVec __pyx_mstate_global->__pyx_kp_s_Iterable_UVec +#define __pyx_kp_s_Iterable_Vec2 __pyx_mstate_global->__pyx_kp_s_Iterable_Vec2 +#define __pyx_n_s_Iterator __pyx_mstate_global->__pyx_n_s_Iterator +#define __pyx_kp_s_Iterator_Vec2 __pyx_mstate_global->__pyx_kp_s_Iterator_Vec2 +#define __pyx_kp_s_Iterator_Vec3 __pyx_mstate_global->__pyx_kp_s_Iterator_Vec3 +#define __pyx_n_s_List __pyx_mstate_global->__pyx_n_s_List +#define __pyx_kp_s_List_Vec2 __pyx_mstate_global->__pyx_kp_s_List_Vec2 +#define __pyx_kp_s_List_Vec3 __pyx_mstate_global->__pyx_kp_s_List_Vec3 +#define __pyx_n_s_NULLVEC __pyx_mstate_global->__pyx_n_s_NULLVEC +#define __pyx_n_s_NotImplemented __pyx_mstate_global->__pyx_n_s_NotImplemented +#define __pyx_n_s_Sequence __pyx_mstate_global->__pyx_n_s_Sequence +#define __pyx_kp_s_Sequence_Vec2 __pyx_mstate_global->__pyx_kp_s_Sequence_Vec2 +#define __pyx_kp_s_Sequence_Vec3 __pyx_mstate_global->__pyx_kp_s_Sequence_Vec3 +#define __pyx_n_s_TYPE_CHECKING __pyx_mstate_global->__pyx_n_s_TYPE_CHECKING +#define __pyx_n_s_Tuple __pyx_mstate_global->__pyx_n_s_Tuple +#define __pyx_n_s_TypeError __pyx_mstate_global->__pyx_n_s_TypeError +#define __pyx_n_s_UVec __pyx_mstate_global->__pyx_n_s_UVec +#define __pyx_n_s_Vec2 __pyx_mstate_global->__pyx_n_s_Vec2 +#define __pyx_n_u_Vec2 __pyx_mstate_global->__pyx_n_u_Vec2 +#define __pyx_n_s_Vec2___copy __pyx_mstate_global->__pyx_n_s_Vec2___copy +#define __pyx_n_s_Vec2___deepcopy __pyx_mstate_global->__pyx_n_s_Vec2___deepcopy +#define __pyx_n_s_Vec2___iter __pyx_mstate_global->__pyx_n_s_Vec2___iter +#define __pyx_n_s_Vec2___reduce __pyx_mstate_global->__pyx_n_s_Vec2___reduce +#define __pyx_n_s_Vec2_angle_between __pyx_mstate_global->__pyx_n_s_Vec2_angle_between +#define __pyx_n_s_Vec2_copy __pyx_mstate_global->__pyx_n_s_Vec2_copy +#define __pyx_n_s_Vec2_det __pyx_mstate_global->__pyx_n_s_Vec2_det +#define __pyx_n_s_Vec2_distance __pyx_mstate_global->__pyx_n_s_Vec2_distance +#define __pyx_n_s_Vec2_dot __pyx_mstate_global->__pyx_n_s_Vec2_dot +#define __pyx_n_s_Vec2_from_angle __pyx_mstate_global->__pyx_n_s_Vec2_from_angle +#define __pyx_n_s_Vec2_from_deg_angle __pyx_mstate_global->__pyx_n_s_Vec2_from_deg_angle +#define __pyx_n_s_Vec2_generate __pyx_mstate_global->__pyx_n_s_Vec2_generate +#define __pyx_n_s_Vec2_isclose __pyx_mstate_global->__pyx_n_s_Vec2_isclose +#define __pyx_n_s_Vec2_lerp __pyx_mstate_global->__pyx_n_s_Vec2_lerp +#define __pyx_n_s_Vec2_list __pyx_mstate_global->__pyx_n_s_Vec2_list +#define __pyx_n_s_Vec2_normalize __pyx_mstate_global->__pyx_n_s_Vec2_normalize +#define __pyx_n_s_Vec2_orthogonal __pyx_mstate_global->__pyx_n_s_Vec2_orthogonal +#define __pyx_n_s_Vec2_project __pyx_mstate_global->__pyx_n_s_Vec2_project +#define __pyx_n_s_Vec2_rotate __pyx_mstate_global->__pyx_n_s_Vec2_rotate +#define __pyx_n_s_Vec2_rotate_deg __pyx_mstate_global->__pyx_n_s_Vec2_rotate_deg +#define __pyx_n_s_Vec2_round __pyx_mstate_global->__pyx_n_s_Vec2_round +#define __pyx_n_s_Vec2_sum __pyx_mstate_global->__pyx_n_s_Vec2_sum +#define __pyx_n_s_Vec2_tuple __pyx_mstate_global->__pyx_n_s_Vec2_tuple +#define __pyx_n_s_Vec3 __pyx_mstate_global->__pyx_n_s_Vec3 +#define __pyx_n_u_Vec3 __pyx_mstate_global->__pyx_n_u_Vec3 +#define __pyx_n_s_Vec3___deepcopy __pyx_mstate_global->__pyx_n_s_Vec3___deepcopy +#define __pyx_n_s_Vec3___iter __pyx_mstate_global->__pyx_n_s_Vec3___iter +#define __pyx_n_s_Vec3___reduce __pyx_mstate_global->__pyx_n_s_Vec3___reduce +#define __pyx_n_s_Vec3_angle_about __pyx_mstate_global->__pyx_n_s_Vec3_angle_about +#define __pyx_n_s_Vec3_angle_between __pyx_mstate_global->__pyx_n_s_Vec3_angle_between +#define __pyx_n_s_Vec3_copy __pyx_mstate_global->__pyx_n_s_Vec3_copy +#define __pyx_n_s_Vec3_cross __pyx_mstate_global->__pyx_n_s_Vec3_cross +#define __pyx_n_s_Vec3_distance __pyx_mstate_global->__pyx_n_s_Vec3_distance +#define __pyx_n_s_Vec3_dot __pyx_mstate_global->__pyx_n_s_Vec3_dot +#define __pyx_n_s_Vec3_from_angle __pyx_mstate_global->__pyx_n_s_Vec3_from_angle +#define __pyx_n_s_Vec3_from_deg_angle __pyx_mstate_global->__pyx_n_s_Vec3_from_deg_angle +#define __pyx_n_s_Vec3_generate __pyx_mstate_global->__pyx_n_s_Vec3_generate +#define __pyx_n_s_Vec3_is_parallel __pyx_mstate_global->__pyx_n_s_Vec3_is_parallel +#define __pyx_n_s_Vec3_isclose __pyx_mstate_global->__pyx_n_s_Vec3_isclose +#define __pyx_n_s_Vec3_lerp __pyx_mstate_global->__pyx_n_s_Vec3_lerp +#define __pyx_n_s_Vec3_list __pyx_mstate_global->__pyx_n_s_Vec3_list +#define __pyx_n_s_Vec3_normalize __pyx_mstate_global->__pyx_n_s_Vec3_normalize +#define __pyx_n_s_Vec3_orthogonal __pyx_mstate_global->__pyx_n_s_Vec3_orthogonal +#define __pyx_n_s_Vec3_project __pyx_mstate_global->__pyx_n_s_Vec3_project +#define __pyx_n_s_Vec3_random __pyx_mstate_global->__pyx_n_s_Vec3_random +#define __pyx_n_s_Vec3_replace __pyx_mstate_global->__pyx_n_s_Vec3_replace +#define __pyx_n_s_Vec3_reversed __pyx_mstate_global->__pyx_n_s_Vec3_reversed +#define __pyx_n_s_Vec3_rotate __pyx_mstate_global->__pyx_n_s_Vec3_rotate +#define __pyx_n_s_Vec3_rotate_deg __pyx_mstate_global->__pyx_n_s_Vec3_rotate_deg +#define __pyx_n_s_Vec3_round __pyx_mstate_global->__pyx_n_s_Vec3_round +#define __pyx_n_s_Vec3_sum __pyx_mstate_global->__pyx_n_s_Vec3_sum +#define __pyx_n_s_Vec3_tuple __pyx_mstate_global->__pyx_n_s_Vec3_tuple +#define __pyx_n_s_X_AXIS __pyx_mstate_global->__pyx_n_s_X_AXIS +#define __pyx_n_s_Y_AXIS __pyx_mstate_global->__pyx_n_s_Y_AXIS +#define __pyx_n_s_Z_AXIS __pyx_mstate_global->__pyx_n_s_Z_AXIS +#define __pyx_n_s__100 __pyx_mstate_global->__pyx_n_s__100 +#define __pyx_kp_u__12 __pyx_mstate_global->__pyx_kp_u__12 +#define __pyx_n_s__13 __pyx_mstate_global->__pyx_n_s__13 +#define __pyx_kp_u__2 __pyx_mstate_global->__pyx_kp_u__2 +#define __pyx_kp_u__3 __pyx_mstate_global->__pyx_kp_u__3 +#define __pyx_kp_u__4 __pyx_mstate_global->__pyx_kp_u__4 +#define __pyx_n_s_a __pyx_mstate_global->__pyx_n_s_a +#define __pyx_n_s_abs_tol __pyx_mstate_global->__pyx_n_s_abs_tol +#define __pyx_n_s_add __pyx_mstate_global->__pyx_n_s_add +#define __pyx_n_s_angle __pyx_mstate_global->__pyx_n_s_angle +#define __pyx_n_s_angle_2 __pyx_mstate_global->__pyx_n_s_angle_2 +#define __pyx_n_s_angle_about __pyx_mstate_global->__pyx_n_s_angle_about +#define __pyx_n_s_angle_between __pyx_mstate_global->__pyx_n_s_angle_between +#define __pyx_n_s_args __pyx_mstate_global->__pyx_n_s_args +#define __pyx_n_s_asyncio_coroutines __pyx_mstate_global->__pyx_n_s_asyncio_coroutines +#define __pyx_n_s_b __pyx_mstate_global->__pyx_n_s_b +#define __pyx_n_s_base __pyx_mstate_global->__pyx_n_s_base +#define __pyx_n_s_bool __pyx_mstate_global->__pyx_n_s_bool +#define __pyx_n_s_ccw __pyx_mstate_global->__pyx_n_s_ccw +#define __pyx_n_s_cline_in_traceback __pyx_mstate_global->__pyx_n_s_cline_in_traceback +#define __pyx_n_s_close __pyx_mstate_global->__pyx_n_s_close +#define __pyx_n_s_copy __pyx_mstate_global->__pyx_n_s_copy +#define __pyx_n_s_copy_2 __pyx_mstate_global->__pyx_n_s_copy_2 +#define __pyx_n_s_cross __pyx_mstate_global->__pyx_n_s_cross +#define __pyx_n_s_deepcopy __pyx_mstate_global->__pyx_n_s_deepcopy +#define __pyx_n_s_det __pyx_mstate_global->__pyx_n_s_det +#define __pyx_n_s_dict __pyx_mstate_global->__pyx_n_s_dict +#define __pyx_n_s_dict_2 __pyx_mstate_global->__pyx_n_s_dict_2 +#define __pyx_kp_u_disable __pyx_mstate_global->__pyx_kp_u_disable +#define __pyx_n_s_distance __pyx_mstate_global->__pyx_n_s_distance +#define __pyx_n_s_dot __pyx_mstate_global->__pyx_n_s_dot +#define __pyx_kp_u_enable __pyx_mstate_global->__pyx_kp_u_enable +#define __pyx_n_s_ezdxf_acc_vector __pyx_mstate_global->__pyx_n_s_ezdxf_acc_vector +#define __pyx_n_s_ezdxf_math __pyx_mstate_global->__pyx_n_s_ezdxf_math +#define __pyx_n_s_factor __pyx_mstate_global->__pyx_n_s_factor +#define __pyx_n_s_float __pyx_mstate_global->__pyx_n_s_float +#define __pyx_n_s_from_angle __pyx_mstate_global->__pyx_n_s_from_angle +#define __pyx_n_s_from_deg_angle __pyx_mstate_global->__pyx_n_s_from_deg_angle +#define __pyx_kp_u_gc __pyx_mstate_global->__pyx_kp_u_gc +#define __pyx_n_s_generate __pyx_mstate_global->__pyx_n_s_generate +#define __pyx_n_s_generate_locals_genexpr __pyx_mstate_global->__pyx_n_s_generate_locals_genexpr +#define __pyx_n_s_genexpr __pyx_mstate_global->__pyx_n_s_genexpr +#define __pyx_n_s_iadd __pyx_mstate_global->__pyx_n_s_iadd +#define __pyx_n_s_import __pyx_mstate_global->__pyx_n_s_import +#define __pyx_n_s_imul __pyx_mstate_global->__pyx_n_s_imul +#define __pyx_n_s_initializing __pyx_mstate_global->__pyx_n_s_initializing +#define __pyx_kp_s_int_None __pyx_mstate_global->__pyx_kp_s_int_None +#define __pyx_kp_u_invalid_argument_count __pyx_mstate_global->__pyx_kp_u_invalid_argument_count +#define __pyx_kp_u_invalid_index __pyx_mstate_global->__pyx_kp_u_invalid_index +#define __pyx_n_s_is_coroutine __pyx_mstate_global->__pyx_n_s_is_coroutine +#define __pyx_n_s_is_null __pyx_mstate_global->__pyx_n_s_is_null +#define __pyx_n_s_is_parallel __pyx_mstate_global->__pyx_n_s_is_parallel +#define __pyx_n_s_isclose __pyx_mstate_global->__pyx_n_s_isclose +#define __pyx_kp_u_isenabled __pyx_mstate_global->__pyx_kp_u_isenabled +#define __pyx_n_s_isub __pyx_mstate_global->__pyx_n_s_isub +#define __pyx_n_s_items __pyx_mstate_global->__pyx_n_s_items +#define __pyx_n_s_iter __pyx_mstate_global->__pyx_n_s_iter +#define __pyx_n_s_length __pyx_mstate_global->__pyx_n_s_length +#define __pyx_n_s_lerp __pyx_mstate_global->__pyx_n_s_lerp +#define __pyx_n_s_list __pyx_mstate_global->__pyx_n_s_list +#define __pyx_n_s_magnitude __pyx_mstate_global->__pyx_n_s_magnitude +#define __pyx_n_s_magnitude_2 __pyx_mstate_global->__pyx_n_s_magnitude_2 +#define __pyx_n_s_main __pyx_mstate_global->__pyx_n_s_main +#define __pyx_n_s_memodict __pyx_mstate_global->__pyx_n_s_memodict +#define __pyx_n_s_mul __pyx_mstate_global->__pyx_n_s_mul +#define __pyx_n_s_name __pyx_mstate_global->__pyx_n_s_name +#define __pyx_n_s_ndigits __pyx_mstate_global->__pyx_n_s_ndigits +#define __pyx_n_s_neg __pyx_mstate_global->__pyx_n_s_neg +#define __pyx_n_s_neg_v2 __pyx_mstate_global->__pyx_n_s_neg_v2 +#define __pyx_n_s_normalize __pyx_mstate_global->__pyx_n_s_normalize +#define __pyx_n_s_normalize_deg_angle __pyx_mstate_global->__pyx_n_s_normalize_deg_angle +#define __pyx_n_s_normalize_rad_angle __pyx_mstate_global->__pyx_n_s_normalize_rad_angle +#define __pyx_n_s_o __pyx_mstate_global->__pyx_n_s_o +#define __pyx_n_s_orthogonal __pyx_mstate_global->__pyx_n_s_orthogonal +#define __pyx_n_s_other __pyx_mstate_global->__pyx_n_s_other +#define __pyx_n_s_p1 __pyx_mstate_global->__pyx_n_s_p1 +#define __pyx_n_s_p2 __pyx_mstate_global->__pyx_n_s_p2 +#define __pyx_n_s_project __pyx_mstate_global->__pyx_n_s_project +#define __pyx_n_s_radd __pyx_mstate_global->__pyx_n_s_radd +#define __pyx_n_s_random __pyx_mstate_global->__pyx_n_s_random +#define __pyx_n_s_reduce __pyx_mstate_global->__pyx_n_s_reduce +#define __pyx_n_s_rel_tol __pyx_mstate_global->__pyx_n_s_rel_tol +#define __pyx_n_s_replace __pyx_mstate_global->__pyx_n_s_replace +#define __pyx_n_s_res __pyx_mstate_global->__pyx_n_s_res +#define __pyx_n_s_return __pyx_mstate_global->__pyx_n_s_return +#define __pyx_n_s_reversed __pyx_mstate_global->__pyx_n_s_reversed +#define __pyx_n_s_rotate __pyx_mstate_global->__pyx_n_s_rotate +#define __pyx_n_s_rotate_deg __pyx_mstate_global->__pyx_n_s_rotate_deg +#define __pyx_n_s_round __pyx_mstate_global->__pyx_n_s_round +#define __pyx_n_s_self __pyx_mstate_global->__pyx_n_s_self +#define __pyx_n_s_self_angle __pyx_mstate_global->__pyx_n_s_self_angle +#define __pyx_n_s_send __pyx_mstate_global->__pyx_n_s_send +#define __pyx_n_s_spatial_angle __pyx_mstate_global->__pyx_n_s_spatial_angle +#define __pyx_n_s_spec __pyx_mstate_global->__pyx_n_s_spec +#define __pyx_kp_s_src_ezdxf_acc_vector_pyx __pyx_mstate_global->__pyx_kp_s_src_ezdxf_acc_vector_pyx +#define __pyx_n_s_staticmethod __pyx_mstate_global->__pyx_n_s_staticmethod +#define __pyx_n_s_str __pyx_mstate_global->__pyx_n_s_str +#define __pyx_n_s_sub __pyx_mstate_global->__pyx_n_s_sub +#define __pyx_n_s_sum __pyx_mstate_global->__pyx_n_s_sum +#define __pyx_n_s_t __pyx_mstate_global->__pyx_n_s_t +#define __pyx_n_s_target __pyx_mstate_global->__pyx_n_s_target +#define __pyx_n_s_test __pyx_mstate_global->__pyx_n_s_test +#define __pyx_n_s_throw __pyx_mstate_global->__pyx_n_s_throw +#define __pyx_n_s_tmp __pyx_mstate_global->__pyx_n_s_tmp +#define __pyx_n_s_tuple __pyx_mstate_global->__pyx_n_s_tuple +#define __pyx_n_s_typing __pyx_mstate_global->__pyx_n_s_typing +#define __pyx_n_s_uniform __pyx_mstate_global->__pyx_n_s_uniform +#define __pyx_n_s_v __pyx_mstate_global->__pyx_n_s_v +#define __pyx_n_s_v1 __pyx_mstate_global->__pyx_n_s_v1 +#define __pyx_n_s_v2 __pyx_mstate_global->__pyx_n_s_v2 +#define __pyx_n_s_x __pyx_mstate_global->__pyx_n_s_x +#define __pyx_n_s_xyz __pyx_mstate_global->__pyx_n_s_xyz +#define __pyx_n_s_y __pyx_mstate_global->__pyx_n_s_y +#define __pyx_n_s_z __pyx_mstate_global->__pyx_n_s_z +#define __pyx_float_1_ __pyx_mstate_global->__pyx_float_1_ +#define __pyx_float_0_5 __pyx_mstate_global->__pyx_float_0_5 +#define __pyx_float_1_0 __pyx_mstate_global->__pyx_float_1_0 +#define __pyx_int_0 __pyx_mstate_global->__pyx_int_0 +#define __pyx_int_1 __pyx_mstate_global->__pyx_int_1 +#define __pyx_int_neg_1 __pyx_mstate_global->__pyx_int_neg_1 +#define __pyx_k__5 __pyx_mstate_global->__pyx_k__5 +#define __pyx_k__6 __pyx_mstate_global->__pyx_k__6 +#define __pyx_k__8 __pyx_mstate_global->__pyx_k__8 +#define __pyx_k__9 __pyx_mstate_global->__pyx_k__9 +#define __pyx_k__10 __pyx_mstate_global->__pyx_k__10 +#define __pyx_k__11 __pyx_mstate_global->__pyx_k__11 +#define __pyx_tuple_ __pyx_mstate_global->__pyx_tuple_ +#define __pyx_tuple__7 __pyx_mstate_global->__pyx_tuple__7 +#define __pyx_tuple__14 __pyx_mstate_global->__pyx_tuple__14 +#define __pyx_tuple__17 __pyx_mstate_global->__pyx_tuple__17 +#define __pyx_tuple__19 __pyx_mstate_global->__pyx_tuple__19 +#define __pyx_tuple__21 __pyx_mstate_global->__pyx_tuple__21 +#define __pyx_tuple__22 __pyx_mstate_global->__pyx_tuple__22 +#define __pyx_tuple__25 __pyx_mstate_global->__pyx_tuple__25 +#define __pyx_tuple__27 __pyx_mstate_global->__pyx_tuple__27 +#define __pyx_tuple__29 __pyx_mstate_global->__pyx_tuple__29 +#define __pyx_tuple__33 __pyx_mstate_global->__pyx_tuple__33 +#define __pyx_tuple__35 __pyx_mstate_global->__pyx_tuple__35 +#define __pyx_tuple__37 __pyx_mstate_global->__pyx_tuple__37 +#define __pyx_tuple__38 __pyx_mstate_global->__pyx_tuple__38 +#define __pyx_tuple__40 __pyx_mstate_global->__pyx_tuple__40 +#define __pyx_tuple__41 __pyx_mstate_global->__pyx_tuple__41 +#define __pyx_tuple__43 __pyx_mstate_global->__pyx_tuple__43 +#define __pyx_tuple__45 __pyx_mstate_global->__pyx_tuple__45 +#define __pyx_tuple__51 __pyx_mstate_global->__pyx_tuple__51 +#define __pyx_tuple__53 __pyx_mstate_global->__pyx_tuple__53 +#define __pyx_tuple__55 __pyx_mstate_global->__pyx_tuple__55 +#define __pyx_tuple__58 __pyx_mstate_global->__pyx_tuple__58 +#define __pyx_tuple__60 __pyx_mstate_global->__pyx_tuple__60 +#define __pyx_tuple__67 __pyx_mstate_global->__pyx_tuple__67 +#define __pyx_tuple__71 __pyx_mstate_global->__pyx_tuple__71 +#define __pyx_tuple__74 __pyx_mstate_global->__pyx_tuple__74 +#define __pyx_tuple__76 __pyx_mstate_global->__pyx_tuple__76 +#define __pyx_tuple__80 __pyx_mstate_global->__pyx_tuple__80 +#define __pyx_tuple__87 __pyx_mstate_global->__pyx_tuple__87 +#define __pyx_tuple__89 __pyx_mstate_global->__pyx_tuple__89 +#define __pyx_tuple__92 __pyx_mstate_global->__pyx_tuple__92 +#define __pyx_tuple__93 __pyx_mstate_global->__pyx_tuple__93 +#define __pyx_tuple__94 __pyx_mstate_global->__pyx_tuple__94 +#define __pyx_tuple__95 __pyx_mstate_global->__pyx_tuple__95 +#define __pyx_tuple__96 __pyx_mstate_global->__pyx_tuple__96 +#define __pyx_tuple__98 __pyx_mstate_global->__pyx_tuple__98 +#define __pyx_codeobj__15 __pyx_mstate_global->__pyx_codeobj__15 +#define __pyx_codeobj__16 __pyx_mstate_global->__pyx_codeobj__16 +#define __pyx_codeobj__18 __pyx_mstate_global->__pyx_codeobj__18 +#define __pyx_codeobj__20 __pyx_mstate_global->__pyx_codeobj__20 +#define __pyx_codeobj__23 __pyx_mstate_global->__pyx_codeobj__23 +#define __pyx_codeobj__24 __pyx_mstate_global->__pyx_codeobj__24 +#define __pyx_codeobj__26 __pyx_mstate_global->__pyx_codeobj__26 +#define __pyx_codeobj__28 __pyx_mstate_global->__pyx_codeobj__28 +#define __pyx_codeobj__30 __pyx_mstate_global->__pyx_codeobj__30 +#define __pyx_codeobj__31 __pyx_mstate_global->__pyx_codeobj__31 +#define __pyx_codeobj__32 __pyx_mstate_global->__pyx_codeobj__32 +#define __pyx_codeobj__34 __pyx_mstate_global->__pyx_codeobj__34 +#define __pyx_codeobj__36 __pyx_mstate_global->__pyx_codeobj__36 +#define __pyx_codeobj__39 __pyx_mstate_global->__pyx_codeobj__39 +#define __pyx_codeobj__42 __pyx_mstate_global->__pyx_codeobj__42 +#define __pyx_codeobj__44 __pyx_mstate_global->__pyx_codeobj__44 +#define __pyx_codeobj__46 __pyx_mstate_global->__pyx_codeobj__46 +#define __pyx_codeobj__47 __pyx_mstate_global->__pyx_codeobj__47 +#define __pyx_codeobj__48 __pyx_mstate_global->__pyx_codeobj__48 +#define __pyx_codeobj__49 __pyx_mstate_global->__pyx_codeobj__49 +#define __pyx_codeobj__50 __pyx_mstate_global->__pyx_codeobj__50 +#define __pyx_codeobj__52 __pyx_mstate_global->__pyx_codeobj__52 +#define __pyx_codeobj__54 __pyx_mstate_global->__pyx_codeobj__54 +#define __pyx_codeobj__56 __pyx_mstate_global->__pyx_codeobj__56 +#define __pyx_codeobj__57 __pyx_mstate_global->__pyx_codeobj__57 +#define __pyx_codeobj__59 __pyx_mstate_global->__pyx_codeobj__59 +#define __pyx_codeobj__61 __pyx_mstate_global->__pyx_codeobj__61 +#define __pyx_codeobj__62 __pyx_mstate_global->__pyx_codeobj__62 +#define __pyx_codeobj__63 __pyx_mstate_global->__pyx_codeobj__63 +#define __pyx_codeobj__64 __pyx_mstate_global->__pyx_codeobj__64 +#define __pyx_codeobj__65 __pyx_mstate_global->__pyx_codeobj__65 +#define __pyx_codeobj__66 __pyx_mstate_global->__pyx_codeobj__66 +#define __pyx_codeobj__68 __pyx_mstate_global->__pyx_codeobj__68 +#define __pyx_codeobj__69 __pyx_mstate_global->__pyx_codeobj__69 +#define __pyx_codeobj__70 __pyx_mstate_global->__pyx_codeobj__70 +#define __pyx_codeobj__72 __pyx_mstate_global->__pyx_codeobj__72 +#define __pyx_codeobj__73 __pyx_mstate_global->__pyx_codeobj__73 +#define __pyx_codeobj__75 __pyx_mstate_global->__pyx_codeobj__75 +#define __pyx_codeobj__77 __pyx_mstate_global->__pyx_codeobj__77 +#define __pyx_codeobj__78 __pyx_mstate_global->__pyx_codeobj__78 +#define __pyx_codeobj__79 __pyx_mstate_global->__pyx_codeobj__79 +#define __pyx_codeobj__81 __pyx_mstate_global->__pyx_codeobj__81 +#define __pyx_codeobj__82 __pyx_mstate_global->__pyx_codeobj__82 +#define __pyx_codeobj__83 __pyx_mstate_global->__pyx_codeobj__83 +#define __pyx_codeobj__84 __pyx_mstate_global->__pyx_codeobj__84 +#define __pyx_codeobj__85 __pyx_mstate_global->__pyx_codeobj__85 +#define __pyx_codeobj__86 __pyx_mstate_global->__pyx_codeobj__86 +#define __pyx_codeobj__88 __pyx_mstate_global->__pyx_codeobj__88 +#define __pyx_codeobj__90 __pyx_mstate_global->__pyx_codeobj__90 +#define __pyx_codeobj__91 __pyx_mstate_global->__pyx_codeobj__91 +#define __pyx_codeobj__97 __pyx_mstate_global->__pyx_codeobj__97 +#define __pyx_codeobj__99 __pyx_mstate_global->__pyx_codeobj__99 +/* #### Code section: module_code ### */ + +/* "ezdxf/acc/vector.pyx":20 + * from ezdxf.math import AnyVec, UVec + * + * cdef bint isclose(double a, double b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * # Has to match the Python implementation! + * cdef double diff = fabs(b - a) + */ + +static int __pyx_f_5ezdxf_3acc_6vector_isclose(double __pyx_v_a, double __pyx_v_b, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + double __pyx_v_diff; + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":22 + * cdef bint isclose(double a, double b, double rel_tol, double abs_tol): + * # Has to match the Python implementation! + * cdef double diff = fabs(b - a) # <<<<<<<<<<<<<< + * return diff <= fabs(rel_tol * b) or \ + * diff <= fabs(rel_tol * a) or \ + */ + __pyx_v_diff = fabs((__pyx_v_b - __pyx_v_a)); + + /* "ezdxf/acc/vector.pyx":23 + * # Has to match the Python implementation! + * cdef double diff = fabs(b - a) + * return diff <= fabs(rel_tol * b) or \ # <<<<<<<<<<<<<< + * diff <= fabs(rel_tol * a) or \ + * diff <= abs_tol + */ + __pyx_t_2 = (__pyx_v_diff <= fabs((__pyx_v_rel_tol * __pyx_v_b))); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":24 + * cdef double diff = fabs(b - a) + * return diff <= fabs(rel_tol * b) or \ + * diff <= fabs(rel_tol * a) or \ # <<<<<<<<<<<<<< + * diff <= abs_tol + * + */ + __pyx_t_2 = (__pyx_v_diff <= fabs((__pyx_v_rel_tol * __pyx_v_a))); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":25 + * return diff <= fabs(rel_tol * b) or \ + * diff <= fabs(rel_tol * a) or \ + * diff <= abs_tol # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = (__pyx_v_diff <= __pyx_v_abs_tol); + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":20 + * from ezdxf.math import AnyVec, UVec + * + * cdef bint isclose(double a, double b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * # Has to match the Python implementation! + * cdef double diff = fabs(b - a) + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":28 + * + * + * cdef double normalize_rad_angle(double a): # <<<<<<<<<<<<<< + * # Emulate the Python behavior of (a % math.tau) + * cdef double res = fmod(a, M_TAU) + */ + +static double __pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle(double __pyx_v_a) { + double __pyx_v_res; + double __pyx_r; + int __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":30 + * cdef double normalize_rad_angle(double a): + * # Emulate the Python behavior of (a % math.tau) + * cdef double res = fmod(a, M_TAU) # <<<<<<<<<<<<<< + * if res < 0.0: + * res += M_TAU + */ + __pyx_v_res = fmod(__pyx_v_a, M_TAU); + + /* "ezdxf/acc/vector.pyx":31 + * # Emulate the Python behavior of (a % math.tau) + * cdef double res = fmod(a, M_TAU) + * if res < 0.0: # <<<<<<<<<<<<<< + * res += M_TAU + * return res + */ + __pyx_t_1 = (__pyx_v_res < 0.0); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":32 + * cdef double res = fmod(a, M_TAU) + * if res < 0.0: + * res += M_TAU # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res = (__pyx_v_res + M_TAU); + + /* "ezdxf/acc/vector.pyx":31 + * # Emulate the Python behavior of (a % math.tau) + * cdef double res = fmod(a, M_TAU) + * if res < 0.0: # <<<<<<<<<<<<<< + * res += M_TAU + * return res + */ + } + + /* "ezdxf/acc/vector.pyx":33 + * if res < 0.0: + * res += M_TAU + * return res # <<<<<<<<<<<<<< + * + * def _normalize_rad_angle(double angle): + */ + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":28 + * + * + * cdef double normalize_rad_angle(double a): # <<<<<<<<<<<<<< + * # Emulate the Python behavior of (a % math.tau) + * cdef double res = fmod(a, M_TAU) + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":35 + * return res + * + * def _normalize_rad_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_rad_angle(angle) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_1_normalize_rad_angle(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_1_normalize_rad_angle = {"_normalize_rad_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_1_normalize_rad_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_1_normalize_rad_angle(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_normalize_rad_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 35, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "_normalize_rad_angle") < 0)) __PYX_ERR(0, 35, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 35, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_normalize_rad_angle", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 35, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector._normalize_rad_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector__normalize_rad_angle(__pyx_self, __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector__normalize_rad_angle(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_angle) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_normalize_rad_angle", 1); + + /* "ezdxf/acc/vector.pyx":37 + * def _normalize_rad_angle(double angle): + * # just for testing + * return normalize_rad_angle(angle) # <<<<<<<<<<<<<< + * + * cdef double normalize_deg_angle(double a): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle(__pyx_v_angle); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 37, __pyx_L1_error) + __pyx_t_2 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":35 + * return res + * + * def _normalize_rad_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_rad_angle(angle) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector._normalize_rad_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":39 + * return normalize_rad_angle(angle) + * + * cdef double normalize_deg_angle(double a): # <<<<<<<<<<<<<< + * # Emulate the Python behavior of (a % 360) + * cdef double res = fmod(a, 360.0) + */ + +static double __pyx_f_5ezdxf_3acc_6vector_normalize_deg_angle(double __pyx_v_a) { + double __pyx_v_res; + double __pyx_r; + int __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":41 + * cdef double normalize_deg_angle(double a): + * # Emulate the Python behavior of (a % 360) + * cdef double res = fmod(a, 360.0) # <<<<<<<<<<<<<< + * if res < 0.0: + * res += 360.0 + */ + __pyx_v_res = fmod(__pyx_v_a, 360.0); + + /* "ezdxf/acc/vector.pyx":42 + * # Emulate the Python behavior of (a % 360) + * cdef double res = fmod(a, 360.0) + * if res < 0.0: # <<<<<<<<<<<<<< + * res += 360.0 + * return res + */ + __pyx_t_1 = (__pyx_v_res < 0.0); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":43 + * cdef double res = fmod(a, 360.0) + * if res < 0.0: + * res += 360.0 # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res = (__pyx_v_res + 360.0); + + /* "ezdxf/acc/vector.pyx":42 + * # Emulate the Python behavior of (a % 360) + * cdef double res = fmod(a, 360.0) + * if res < 0.0: # <<<<<<<<<<<<<< + * res += 360.0 + * return res + */ + } + + /* "ezdxf/acc/vector.pyx":44 + * if res < 0.0: + * res += 360.0 + * return res # <<<<<<<<<<<<<< + * + * def _normalize_deg_angle(double angle): + */ + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":39 + * return normalize_rad_angle(angle) + * + * cdef double normalize_deg_angle(double a): # <<<<<<<<<<<<<< + * # Emulate the Python behavior of (a % 360) + * cdef double res = fmod(a, 360.0) + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":46 + * return res + * + * def _normalize_deg_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_deg_angle(angle) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_3_normalize_deg_angle(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_3_normalize_deg_angle = {"_normalize_deg_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_3_normalize_deg_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_3_normalize_deg_angle(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_normalize_deg_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "_normalize_deg_angle") < 0)) __PYX_ERR(0, 46, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_normalize_deg_angle", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 46, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector._normalize_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_2_normalize_deg_angle(__pyx_self, __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_2_normalize_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_angle) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_normalize_deg_angle", 1); + + /* "ezdxf/acc/vector.pyx":48 + * def _normalize_deg_angle(double angle): + * # just for testing + * return normalize_deg_angle(angle) # <<<<<<<<<<<<<< + * + * cdef class Vec2: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_normalize_deg_angle(__pyx_v_angle); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 48, __pyx_L1_error) + __pyx_t_2 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":46 + * return res + * + * def _normalize_deg_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_deg_angle(angle) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector._normalize_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":64 + * """ + * + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len( args) + * + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec2_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec2_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_args = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_VARARGS(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __Pyx_INCREF(__pyx_args); + __pyx_v_args = __pyx_args; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2___cinit__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_args); + + /* function exit code */ + __Pyx_DECREF(__pyx_v_args); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec2___cinit__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_args) { + Py_ssize_t __pyx_v_count; + PyObject *__pyx_v_arg = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + __Pyx_INCREF(__pyx_v_args); + + /* "ezdxf/acc/vector.pyx":65 + * + * def __cinit__(self, *args): + * cdef Py_ssize_t count = len( args) # <<<<<<<<<<<<<< + * + * if count == 0: # fastest init - default constructor + */ + if (unlikely(__pyx_v_args == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(0, 65, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyTuple_GET_SIZE(((PyObject*)__pyx_v_args)); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 65, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":67 + * cdef Py_ssize_t count = len( args) + * + * if count == 0: # fastest init - default constructor # <<<<<<<<<<<<<< + * self.x = 0 + * self.y = 0 + */ + __pyx_t_2 = (__pyx_v_count == 0); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":68 + * + * if count == 0: # fastest init - default constructor + * self.x = 0 # <<<<<<<<<<<<<< + * self.y = 0 + * return + */ + __pyx_v_self->x = 0.0; + + /* "ezdxf/acc/vector.pyx":69 + * if count == 0: # fastest init - default constructor + * self.x = 0 + * self.y = 0 # <<<<<<<<<<<<<< + * return + * + */ + __pyx_v_self->y = 0.0; + + /* "ezdxf/acc/vector.pyx":70 + * self.x = 0 + * self.y = 0 + * return # <<<<<<<<<<<<<< + * + * if count == 1: + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":67 + * cdef Py_ssize_t count = len( args) + * + * if count == 0: # fastest init - default constructor # <<<<<<<<<<<<<< + * self.x = 0 + * self.y = 0 + */ + } + + /* "ezdxf/acc/vector.pyx":72 + * return + * + * if count == 1: # <<<<<<<<<<<<<< + * arg = args[0] + * if isinstance(arg, Vec2): + */ + __pyx_t_2 = (__pyx_v_count == 1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":73 + * + * if count == 1: + * arg = args[0] # <<<<<<<<<<<<<< + * if isinstance(arg, Vec2): + * # fast init by Vec2() + */ + __pyx_t_3 = __Pyx_GetItemInt_Tuple(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_v_arg = __pyx_t_3; + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":74 + * if count == 1: + * arg = args[0] + * if isinstance(arg, Vec2): # <<<<<<<<<<<<<< + * # fast init by Vec2() + * self.x = ( arg).x + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_arg, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":76 + * if isinstance(arg, Vec2): + * # fast init by Vec2() + * self.x = ( arg).x # <<<<<<<<<<<<<< + * self.y = ( arg).y + * return + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_arg)->x; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":77 + * # fast init by Vec2() + * self.x = ( arg).x + * self.y = ( arg).y # <<<<<<<<<<<<<< + * return + * if isinstance(arg, Vec3): + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_arg)->y; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":78 + * self.x = ( arg).x + * self.y = ( arg).y + * return # <<<<<<<<<<<<<< + * if isinstance(arg, Vec3): + * # fast init by Vec3() + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":74 + * if count == 1: + * arg = args[0] + * if isinstance(arg, Vec2): # <<<<<<<<<<<<<< + * # fast init by Vec2() + * self.x = ( arg).x + */ + } + + /* "ezdxf/acc/vector.pyx":79 + * self.y = ( arg).y + * return + * if isinstance(arg, Vec3): # <<<<<<<<<<<<<< + * # fast init by Vec3() + * self.x = ( arg).x + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_arg, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":81 + * if isinstance(arg, Vec3): + * # fast init by Vec3() + * self.x = ( arg).x # <<<<<<<<<<<<<< + * self.y = ( arg).y + * return + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_arg)->x; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":82 + * # fast init by Vec3() + * self.x = ( arg).x + * self.y = ( arg).y # <<<<<<<<<<<<<< + * return + * args = arg + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_arg)->y; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":83 + * self.x = ( arg).x + * self.y = ( arg).y + * return # <<<<<<<<<<<<<< + * args = arg + * count = len(args) + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":79 + * self.y = ( arg).y + * return + * if isinstance(arg, Vec3): # <<<<<<<<<<<<<< + * # fast init by Vec3() + * self.x = ( arg).x + */ + } + + /* "ezdxf/acc/vector.pyx":84 + * self.y = ( arg).y + * return + * args = arg # <<<<<<<<<<<<<< + * count = len(args) + * + */ + __Pyx_INCREF(__pyx_v_arg); + __Pyx_DECREF_SET(__pyx_v_args, __pyx_v_arg); + + /* "ezdxf/acc/vector.pyx":85 + * return + * args = arg + * count = len(args) # <<<<<<<<<<<<<< + * + * # ignore z-axis but raise error for 4 or more arguments + */ + __pyx_t_1 = PyObject_Length(__pyx_v_args); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 85, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":72 + * return + * + * if count == 1: # <<<<<<<<<<<<<< + * arg = args[0] + * if isinstance(arg, Vec2): + */ + } + + /* "ezdxf/acc/vector.pyx":88 + * + * # ignore z-axis but raise error for 4 or more arguments + * if count > 3: # <<<<<<<<<<<<<< + * raise TypeError('invalid argument count') + * + */ + __pyx_t_2 = (__pyx_v_count > 3); + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/vector.pyx":89 + * # ignore z-axis but raise error for 4 or more arguments + * if count > 3: + * raise TypeError('invalid argument count') # <<<<<<<<<<<<<< + * + * # slow init by sequence + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 89, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":88 + * + * # ignore z-axis but raise error for 4 or more arguments + * if count > 3: # <<<<<<<<<<<<<< + * raise TypeError('invalid argument count') + * + */ + } + + /* "ezdxf/acc/vector.pyx":92 + * + * # slow init by sequence + * self.x = args[0] # <<<<<<<<<<<<<< + * self.y = args[1] + * + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":93 + * # slow init by sequence + * self.x = args[0] + * self.y = args[1] # <<<<<<<<<<<<<< + * + * def __reduce__(self): + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":64 + * """ + * + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len( args) + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_args); + __Pyx_XDECREF(__pyx_v_arg); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":95 + * self.y = args[1] + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec2, (self.x, self.y) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_3__reduce__ = {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_2__reduce__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_2__reduce__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce__", 1); + + /* "ezdxf/acc/vector.pyx":96 + * + * def __reduce__(self): + * return Vec2, (self.x, self.y) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 96, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 96, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 96, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(0, 96, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(0, 96, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 96, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2))) __PYX_ERR(0, 96, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3)) __PYX_ERR(0, 96, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":95 + * self.y = args[1] + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec2, (self.x, self.y) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":98 + * return Vec2, (self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def vec3(self) -> Vec3: + * return Vec3(self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_4vec3_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_4vec3_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_4vec3___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_4vec3___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":100 + * @property + * def vec3(self) -> Vec3: + * return Vec3(self) # <<<<<<<<<<<<<< + * + * def round(self, ndigits=None) -> Vec2: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), ((PyObject *)__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":98 + * return Vec2, (self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def vec3(self) -> Vec3: + * return Vec3(self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.vec3.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":102 + * return Vec3(self) + * + * def round(self, ndigits=None) -> Vec2: # <<<<<<<<<<<<<< + * # only used for testing + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5round(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_5round = {"round", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5round, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5round(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ndigits = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("round (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ndigits,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_None)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ndigits); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 102, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "round") < 0)) __PYX_ERR(0, 102, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ndigits = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("round", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 102, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.round", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_4round(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_ndigits); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_4round(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_ndigits) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("round", 1); + + /* "ezdxf/acc/vector.pyx":104 + * def round(self, ndigits=None) -> Vec2: + * # only used for testing + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ndigits); + __Pyx_GIVEREF(__pyx_v_ndigits); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_ndigits)) __PYX_ERR(0, 104, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_round, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ndigits); + __Pyx_GIVEREF(__pyx_v_ndigits); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_ndigits)) __PYX_ERR(0, 104, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_round, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 104, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":102 + * return Vec3(self) + * + * def round(self, ndigits=None) -> Vec2: # <<<<<<<<<<<<<< + * # only used for testing + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.round", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":106 + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec2]: + * return list(Vec2.generate(items)) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7list(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_7list = {"list", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7list, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7list(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("list (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 106, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "list") < 0)) __PYX_ERR(0, 106, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("list", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 106, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.list", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_6list(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_6list(PyObject *__pyx_v_items) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("list", 1); + + /* "ezdxf/acc/vector.pyx":108 + * @staticmethod + * def list(items: Iterable[UVec]) -> List[Vec2]: + * return list(Vec2.generate(items)) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_n_s_generate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_items}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_ListKeepNew(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 108, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":106 + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec2]: + * return list(Vec2.generate(items)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.list", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":110 + * return list(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + * return tuple(Vec2.generate(items)) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9tuple(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_9tuple = {"tuple", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9tuple, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9tuple(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("tuple (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 110, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "tuple") < 0)) __PYX_ERR(0, 110, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("tuple", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 110, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.tuple", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_8tuple(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_8tuple(PyObject *__pyx_v_items) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tuple", 1); + + /* "ezdxf/acc/vector.pyx":112 + * @staticmethod + * def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + * return tuple(Vec2.generate(items)) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_n_s_generate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_items}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":110 + * return list(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + * return tuple(Vec2.generate(items)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.tuple", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":114 + * return tuple(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_11generate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_11generate = {"generate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_11generate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_11generate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("generate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 114, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "generate") < 0)) __PYX_ERR(0, 114, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("generate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 114, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.generate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_10generate(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec2_8generate_2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/vector.pyx":116 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_8generate_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 116, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_6vector_4Vec2_8generate_2generator2, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_generate_locals_genexpr, __pyx_n_s_ezdxf_acc_vector); if (unlikely(!gen)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.generate.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec2_8generate_2generator2(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 116, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 116, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 116, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 116, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 116, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 116, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 116, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 116, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_item); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_item, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_cur_scope->__pyx_v_item); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 116, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":114 + * return tuple(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_10generate(PyObject *__pyx_v_items) { + PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec2_8generate_2generator2 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("generate", 1); + + /* "ezdxf/acc/vector.pyx":116 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_8generate_genexpr(NULL, __pyx_v_items); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":114 + * return tuple(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.generate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_6vector_4Vec2_8generate_2generator2); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":118 + * return (Vec2(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle, length) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_13from_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_13from_angle = {"from_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_13from_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_13from_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("from_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 118, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 118, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "from_angle") < 0)) __PYX_ERR(0, 118, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 119, __pyx_L3_error) + if (values[1]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 119, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("from_angle", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 118, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_12from_angle(__pyx_v_angle, __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_12from_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("from_angle", 1); + + /* "ezdxf/acc/vector.pyx":120 + * @staticmethod + * def from_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle, length) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_from_angle(__pyx_v_angle, __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 120, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":118 + * return (Vec2(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle, length) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":122 + * return v2_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle * DEG2RAD, length) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle = {"from_deg_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("from_deg_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "from_deg_angle") < 0)) __PYX_ERR(0, 122, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 123, __pyx_L3_error) + if (values[1]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 123, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("from_deg_angle", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 122, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.from_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_14from_deg_angle(__pyx_v_angle, __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_14from_deg_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("from_deg_angle", 1); + + /* "ezdxf/acc/vector.pyx":124 + * @staticmethod + * def from_deg_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle * DEG2RAD, length) # <<<<<<<<<<<<<< + * + * def __str__(self) -> str: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_from_angle((__pyx_v_angle * __pyx_v_5ezdxf_3acc_6vector_DEG2RAD), __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 124, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":122 + * return v2_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle * DEG2RAD, length) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.from_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":126 + * return v2_from_angle(angle * DEG2RAD, length) + * + * def __str__(self) -> str: # <<<<<<<<<<<<<< + * return f'({self.x}, {self.y})' + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_17__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_17__str__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_16__str__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_16__str__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + Py_UCS4 __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 1); + + /* "ezdxf/acc/vector.pyx":127 + * + * def __str__(self) -> str: + * return f'({self.x}, {self.y})' # <<<<<<<<<<<<<< + * + * def __repr__(self)-> str: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = 127; + __Pyx_INCREF(__pyx_kp_u__2); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__2); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_kp_u__2); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_FormatSimple(__pyx_t_4, __pyx_empty_unicode); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) > __pyx_t_3) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) : __pyx_t_3; + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_kp_u__3); + __pyx_t_2 += 2; + __Pyx_GIVEREF(__pyx_kp_u__3); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_kp_u__3); + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_t_5, __pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4) > __pyx_t_3) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4) : __pyx_t_3; + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u__4); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__4); + PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_kp_u__4); + __pyx_t_4 = __Pyx_PyUnicode_Join(__pyx_t_1, 5, __pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":126 + * return v2_from_angle(angle * DEG2RAD, length) + * + * def __str__(self) -> str: # <<<<<<<<<<<<<< + * return f'({self.x}, {self.y})' + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":129 + * return f'({self.x}, {self.y})' + * + * def __repr__(self)-> str: # <<<<<<<<<<<<<< + * return "Vec2" + self.__str__() + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_18__repr__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_18__repr__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "ezdxf/acc/vector.pyx":130 + * + * def __repr__(self)-> str: + * return "Vec2" + self.__str__() # <<<<<<<<<<<<<< + * + * def __len__(self) -> int: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_str); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = PyNumber_Add(__pyx_n_u_Vec2, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":129 + * return f'({self.x}, {self.y})' + * + * def __repr__(self)-> str: # <<<<<<<<<<<<<< + * return "Vec2" + self.__str__() + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":132 + * return "Vec2" + self.__str__() + * + * def __len__(self) -> int: # <<<<<<<<<<<<<< + * return 2 + * + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_20__len__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_pf_5ezdxf_3acc_6vector_4Vec2_20__len__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + Py_ssize_t __pyx_r; + + /* "ezdxf/acc/vector.pyx":133 + * + * def __len__(self) -> int: + * return 2 # <<<<<<<<<<<<<< + * + * def __hash__(self) -> int: + */ + __pyx_r = 2; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":132 + * return "Vec2" + self.__str__() + * + * def __len__(self) -> int: # <<<<<<<<<<<<<< + * return 2 + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":135 + * return 2 + * + * def __hash__(self) -> int: # <<<<<<<<<<<<<< + * return hash((self.x, self.y)) + * + */ + +/* Python wrapper */ +static Py_hash_t __pyx_pw_5ezdxf_3acc_6vector_4Vec2_23__hash__(PyObject *__pyx_v_self); /*proto*/ +static Py_hash_t __pyx_pw_5ezdxf_3acc_6vector_4Vec2_23__hash__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_hash_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__hash__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_22__hash__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_hash_t __pyx_pf_5ezdxf_3acc_6vector_4Vec2_22__hash__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + Py_hash_t __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + Py_hash_t __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__hash__", 1); + + /* "ezdxf/acc/vector.pyx":136 + * + * def __hash__(self) -> int: + * return hash((self.x, self.y)) # <<<<<<<<<<<<<< + * + * def copy(self) -> Vec2: + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1)) __PYX_ERR(0, 136, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_4 = PyObject_Hash(__pyx_t_3); if (unlikely(__pyx_t_4 == ((Py_hash_t)-1))) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_4; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":135 + * return 2 + * + * def __hash__(self) -> int: # <<<<<<<<<<<<<< + * return hash((self.x, self.y)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__hash__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + if (unlikely(__pyx_r == -1) && !PyErr_Occurred()) __pyx_r = -2; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":138 + * return hash((self.x, self.y)) + * + * def copy(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_25copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_25copy = {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_25copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_25copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_24copy(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_24copy(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy", 1); + + /* "ezdxf/acc/vector.pyx":139 + * + * def copy(self) -> Vec2: + * return self # immutable # <<<<<<<<<<<<<< + * + * def __copy__(self) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = __pyx_v_self; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":138 + * return hash((self.x, self.y)) + * + * def copy(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":141 + * return self # immutable + * + * def __copy__(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_27__copy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_27__copy__ = {"__copy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_27__copy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_27__copy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__copy__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__copy__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__copy__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_26__copy__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_26__copy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__copy__", 1); + + /* "ezdxf/acc/vector.pyx":142 + * + * def __copy__(self) -> Vec2: + * return self # immutable # <<<<<<<<<<<<<< + * + * def __deepcopy__(self, memodict: dict) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = __pyx_v_self; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":141 + * return self # immutable + * + * def __copy__(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":144 + * return self # immutable + * + * def __deepcopy__(self, memodict: dict) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__ = {"__deepcopy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v_memodict = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__deepcopy__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_memodict,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_memodict)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__deepcopy__") < 0)) __PYX_ERR(0, 144, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_memodict = ((PyObject*)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__deepcopy__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 144, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__deepcopy__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_memodict), (&PyDict_Type), 0, "memodict", 1))) __PYX_ERR(0, 144, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_28__deepcopy__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_memodict); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_28__deepcopy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_memodict) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__deepcopy__", 1); + + /* "ezdxf/acc/vector.pyx":145 + * + * def __deepcopy__(self, memodict: dict) -> Vec2: + * return self # immutable # <<<<<<<<<<<<<< + * + * def __getitem__(self, int index) -> float: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = __pyx_v_self; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":144 + * return self # immutable + * + * def __deepcopy__(self, memodict: dict) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":147 + * return self # immutable + * + * def __getitem__(self, int index) -> float: # <<<<<<<<<<<<<< + * if index == 0: + * return self.x + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_31__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_31__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index) { + int __pyx_v_index; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_index); { + __pyx_v_index = __Pyx_PyInt_As_int(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 147, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_30__getitem__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), ((int)__pyx_v_index)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_30__getitem__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, int __pyx_v_index) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "ezdxf/acc/vector.pyx":148 + * + * def __getitem__(self, int index) -> float: + * if index == 0: # <<<<<<<<<<<<<< + * return self.x + * elif index == 1: + */ + switch (__pyx_v_index) { + case 0: + + /* "ezdxf/acc/vector.pyx":149 + * def __getitem__(self, int index) -> float: + * if index == 0: + * return self.x # <<<<<<<<<<<<<< + * elif index == 1: + * return self.y + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":148 + * + * def __getitem__(self, int index) -> float: + * if index == 0: # <<<<<<<<<<<<<< + * return self.x + * elif index == 1: + */ + break; + case 1: + + /* "ezdxf/acc/vector.pyx":151 + * return self.x + * elif index == 1: + * return self.y # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid index {index}') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":150 + * if index == 0: + * return self.x + * elif index == 1: # <<<<<<<<<<<<<< + * return self.y + * else: + */ + break; + default: + + /* "ezdxf/acc/vector.pyx":153 + * return self.y + * else: + * raise IndexError(f'invalid index {index}') # <<<<<<<<<<<<<< + * + * def __iter__(self) -> Iterator[float]: + */ + __pyx_t_1 = __Pyx_PyUnicode_From_int(__pyx_v_index, 0, ' ', 'd'); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_index, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 153, __pyx_L1_error) + break; + } + + /* "ezdxf/acc/vector.pyx":147 + * return self # immutable + * + * def __getitem__(self, int index) -> float: # <<<<<<<<<<<<<< + * if index == 0: + * return self.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec2_34generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/vector.pyx":155 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_33__iter__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_33__iter__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_32__iter__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_32__iter__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__iter__", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 155, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_6vector_4Vec2_34generator, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_Vec2___iter, __pyx_n_s_ezdxf_acc_vector); if (unlikely(!gen)) __PYX_ERR(0, 155, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec2_34generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L4_resume_from_yield; + case 2: goto __pyx_L5_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 155, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":156 + * + * def __iter__(self) -> Iterator[float]: + * yield self.x # <<<<<<<<<<<<<< + * yield self.y + * + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L4_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 156, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":157 + * def __iter__(self) -> Iterator[float]: + * yield self.x + * yield self.y # <<<<<<<<<<<<<< + * + * def __abs__(self) -> float: + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 2; + return __pyx_r; + __pyx_L5_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 157, __pyx_L1_error) + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/vector.pyx":155 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":159 + * yield self.y + * + * def __abs__(self) -> float: # <<<<<<<<<<<<<< + * return hypot(self.x, self.y) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_36__abs__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_36__abs__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__abs__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_35__abs__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_35__abs__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__abs__", 1); + + /* "ezdxf/acc/vector.pyx":160 + * + * def __abs__(self) -> float: + * return hypot(self.x, self.y) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(hypot(__pyx_v_self->x, __pyx_v_self->y)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":159 + * yield self.y + * + * def __abs__(self) -> float: # <<<<<<<<<<<<<< + * return hypot(self.x, self.y) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__abs__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":162 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def magnitude(self) -> float: + * return hypot(self.x, self.y) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9magnitude_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9magnitude_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_9magnitude___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_9magnitude___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":164 + * @property + * def magnitude(self) -> float: + * return hypot(self.x, self.y) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(hypot(__pyx_v_self->x, __pyx_v_self->y)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":162 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def magnitude(self) -> float: + * return hypot(self.x, self.y) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.magnitude.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":166 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7is_null_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7is_null_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_7is_null___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_7is_null___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":168 + * @property + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = (fabs(__pyx_v_self->x) <= ABS_TOL); + if (__pyx_t_2) { + } else { + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 168, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_2 = (fabs(__pyx_v_self->y) <= ABS_TOL); + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 168, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":166 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.is_null.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":170 + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL + * + * @property # <<<<<<<<<<<<<< + * def angle(self) -> float: + * return atan2(self.y, self.x) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5angle_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5angle_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_5angle___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_5angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":172 + * @property + * def angle(self) -> float: + * return atan2(self.y, self.x) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(atan2(__pyx_v_self->y, __pyx_v_self->x)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":170 + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL + * + * @property # <<<<<<<<<<<<<< + * def angle(self) -> float: + * return atan2(self.y, self.x) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.angle.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":174 + * return atan2(self.y, self.x) + * + * @property # <<<<<<<<<<<<<< + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9angle_deg_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9angle_deg_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_9angle_deg___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_9angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":176 + * @property + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG # <<<<<<<<<<<<<< + * + * def orthogonal(self, ccw: bool = True) -> Vec2: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble((atan2(__pyx_v_self->y, __pyx_v_self->x) * __pyx_v_5ezdxf_3acc_6vector_RAD2DEG)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 176, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":174 + * return atan2(self.y, self.x) + * + * @property # <<<<<<<<<<<<<< + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.angle_deg.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":178 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec2: # <<<<<<<<<<<<<< + * return v2_ortho(self, ccw) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_38orthogonal(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_38orthogonal = {"orthogonal", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_38orthogonal, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_38orthogonal(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ccw = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("orthogonal (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ccw,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_True)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ccw); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 178, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "orthogonal") < 0)) __PYX_ERR(0, 178, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ccw = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("orthogonal", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 178, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.orthogonal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_37orthogonal(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_ccw); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_37orthogonal(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_ccw) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("orthogonal", 1); + + /* "ezdxf/acc/vector.pyx":179 + * + * def orthogonal(self, ccw: bool = True) -> Vec2: + * return v2_ortho(self, ccw) # <<<<<<<<<<<<<< + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_ccw); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 179, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_ortho(__pyx_v_self, __pyx_t_1)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 179, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":178 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec2: # <<<<<<<<<<<<<< + * return v2_ortho(self, ccw) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.orthogonal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":181 + * return v2_ortho(self, ccw) + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_lerp(self, o, factor) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_40lerp(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_40lerp = {"lerp", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_40lerp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_40lerp(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + double __pyx_v_factor; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("lerp (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,&__pyx_n_s_factor,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 181, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_factor); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 181, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lerp") < 0)) __PYX_ERR(0, 181, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_other = values[0]; + if (values[1]) { + __pyx_v_factor = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 181, __pyx_L3_error) + } else { + __pyx_v_factor = ((double)0.5); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("lerp", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 181, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_39lerp(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other, __pyx_v_factor); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_39lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("lerp", 1); + + /* "ezdxf/acc/vector.pyx":182 + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_lerp(self, o, factor) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":183 + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: + * cdef Vec2 o = Vec2(other) + * return v2_lerp(self, o, factor) # <<<<<<<<<<<<<< + * + * def normalize(self, double length = 1.) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_lerp(__pyx_v_self, __pyx_v_o, __pyx_v_factor)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":181 + * return v2_ortho(self, ccw) + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_lerp(self, o, factor) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":185 + * return v2_lerp(self, o, factor) + * + * def normalize(self, double length = 1.) -> Vec2: # <<<<<<<<<<<<<< + * return v2_normalize(self, length) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_42normalize(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_42normalize = {"normalize", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_42normalize, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_42normalize(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("normalize (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 185, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "normalize") < 0)) __PYX_ERR(0, 185, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + if (values[0]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 185, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("normalize", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 185, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_41normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_41normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("normalize", 1); + + /* "ezdxf/acc/vector.pyx":186 + * + * def normalize(self, double length = 1.) -> Vec2: + * return v2_normalize(self, length) # <<<<<<<<<<<<<< + * + * def project(self, other: AnyVec) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_normalize(__pyx_v_self, __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":185 + * return v2_lerp(self, o, factor) + * + * def normalize(self, double length = 1.) -> Vec2: # <<<<<<<<<<<<<< + * return v2_normalize(self, length) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":188 + * return v2_normalize(self, length) + * + * def project(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_project(self, o) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_44project(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_44project = {"project", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_44project, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_44project(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("project (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "project") < 0)) __PYX_ERR(0, 188, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("project", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 188, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_43project(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_43project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("project", 1); + + /* "ezdxf/acc/vector.pyx":189 + * + * def project(self, other: AnyVec) -> Vec2: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_project(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 189, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":190 + * def project(self, other: AnyVec) -> Vec2: + * cdef Vec2 o = Vec2(other) + * return v2_project(self, o) # <<<<<<<<<<<<<< + * + * def __neg__(self) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_project(__pyx_v_self, __pyx_v_o)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":188 + * return v2_normalize(self, length) + * + * def project(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_project(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":192 + * return v2_project(self, o) + * + * def __neg__(self) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = -self.x + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_46__neg__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_46__neg__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__neg__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_45__neg__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_45__neg__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__neg__", 1); + + /* "ezdxf/acc/vector.pyx":193 + * + * def __neg__(self) -> Vec2: + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * res.x = -self.x + * res.y = -self.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":194 + * def __neg__(self) -> Vec2: + * cdef Vec2 res = Vec2() + * res.x = -self.x # <<<<<<<<<<<<<< + * res.y = -self.y + * return res + */ + __pyx_v_res->x = (-__pyx_v_self->x); + + /* "ezdxf/acc/vector.pyx":195 + * cdef Vec2 res = Vec2() + * res.x = -self.x + * res.y = -self.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (-__pyx_v_self->y); + + /* "ezdxf/acc/vector.pyx":196 + * res.x = -self.x + * res.y = -self.y + * return res # <<<<<<<<<<<<<< + * + * reversed = __neg__ + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = ((PyObject *)__pyx_v_res); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":192 + * return v2_project(self, o) + * + * def __neg__(self) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = -self.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__neg__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":200 + * reversed = __neg__ + * + * def __bool__(self) -> bool: # <<<<<<<<<<<<<< + * return self.x != 0 or self.y != 0 + * + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec2_48__bool__(PyObject *__pyx_v_self); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec2_48__bool__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__bool__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_47__bool__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec2_47__bool__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":201 + * + * def __bool__(self) -> bool: + * return self.x != 0 or self.y != 0 # <<<<<<<<<<<<<< + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, + */ + __pyx_t_2 = (__pyx_v_self->x != 0.0); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_2 = (__pyx_v_self->y != 0.0); + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":200 + * reversed = __neg__ + * + * def __bool__(self) -> bool: # <<<<<<<<<<<<<< + * return self.x != 0 or self.y != 0 + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_50isclose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_50isclose = {"isclose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_50isclose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_50isclose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + double __pyx_v_rel_tol; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("isclose (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,&__pyx_n_s_rel_tol,&__pyx_n_s_abs_tol,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 203, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (kw_args > 0 && likely(kw_args <= 2)) { + Py_ssize_t index; + for (index = 1; index < 3 && kw_args > 0; index++) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, *__pyx_pyargnames[index]); + if (value) { values[index] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 203, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "isclose") < 0)) __PYX_ERR(0, 203, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + if (values[1]) { + __pyx_v_rel_tol = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_rel_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 203, __pyx_L3_error) + } else { + __pyx_v_rel_tol = __pyx_k__5; + } + if (values[2]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 204, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_k__6; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("isclose", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 203, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_49isclose(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other, __pyx_v_rel_tol, __pyx_v_abs_tol); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_49isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("isclose", 1); + + /* "ezdxf/acc/vector.pyx":205 + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return isclose(self.x, o.x, rel_tol, abs_tol) and \ + * isclose(self.y, o.y, rel_tol, abs_tol) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":206 + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + * return isclose(self.x, o.x, rel_tol, abs_tol) and \ # <<<<<<<<<<<<<< + * isclose(self.y, o.y, rel_tol, abs_tol) + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_self->x, __pyx_v_o->x, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 206, __pyx_L1_error) + if (__pyx_t_2) { + } else { + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 206, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":207 + * cdef Vec2 o = Vec2(other) + * return isclose(self.x, o.x, rel_tol, abs_tol) and \ + * isclose(self.y, o.y, rel_tol, abs_tol) # <<<<<<<<<<<<<< + * + * def __eq__(self, other: UVec) -> bool: + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_self->y, __pyx_v_o->y, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 207, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":209 + * isclose(self.y, o.y, rel_tol, abs_tol) + * + * def __eq__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_52__eq__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_52__eq__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__eq__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_51__eq__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_51__eq__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__eq__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":210 + * + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return self.x == other.x and self.y == other.y + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":211 + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec2): + * other = Vec2(other) # <<<<<<<<<<<<<< + * return self.x == other.x and self.y == other.y + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 211, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":210 + * + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return self.x == other.x and self.y == other.y + */ + } + + /* "ezdxf/acc/vector.pyx":212 + * if not isinstance(other, Vec2): + * other = Vec2(other) + * return self.x == other.x and self.y == other.y # <<<<<<<<<<<<<< + * + * def __lt__(self, other) -> bool: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_x); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 212, __pyx_L1_error) + if (__pyx_t_2) { + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __Pyx_INCREF(__pyx_t_6); + __pyx_t_3 = __pyx_t_6; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_y); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_L4_bool_binop_done:; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":209 + * isclose(self.y, o.y, rel_tol, abs_tol) + * + * def __eq__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__eq__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":214 + * return self.x == other.x and self.y == other.y + * + * def __lt__(self, other) -> bool: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * if self.x == o.x: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_54__lt__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_54__lt__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__lt__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_53__lt__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_53__lt__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__lt__", 1); + + /* "ezdxf/acc/vector.pyx":215 + * + * def __lt__(self, other) -> bool: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * if self.x == o.x: + * return self.y < o.y + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":216 + * def __lt__(self, other) -> bool: + * cdef Vec2 o = Vec2(other) + * if self.x == o.x: # <<<<<<<<<<<<<< + * return self.y < o.y + * else: + */ + __pyx_t_2 = (__pyx_v_self->x == __pyx_v_o->x); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":217 + * cdef Vec2 o = Vec2(other) + * if self.x == o.x: + * return self.y < o.y # <<<<<<<<<<<<<< + * else: + * return self.x < o.x + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_self->y < __pyx_v_o->y)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":216 + * def __lt__(self, other) -> bool: + * cdef Vec2 o = Vec2(other) + * if self.x == o.x: # <<<<<<<<<<<<<< + * return self.y < o.y + * else: + */ + } + + /* "ezdxf/acc/vector.pyx":219 + * return self.y < o.y + * else: + * return self.x < o.x # <<<<<<<<<<<<<< + * + * def __add__(self, other: AnyVec) -> Vec2: + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_self->x < __pyx_v_o->x)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + } + + /* "ezdxf/acc/vector.pyx":214 + * return self.x == other.x and self.y == other.y + * + * def __lt__(self, other) -> bool: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * if self.x == o.x: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__lt__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":221 + * return self.x < o.x + * + * def __add__(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_56__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_56__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__add__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_55__add__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_55__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__add__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":222 + * + * def __add__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return v2_add(self, other) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":223 + * def __add__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): + * other = Vec2(other) # <<<<<<<<<<<<<< + * return v2_add(self, other) + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":222 + * + * def __add__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return v2_add(self, other) + */ + } + + /* "ezdxf/acc/vector.pyx":224 + * if not isinstance(other, Vec2): + * other = Vec2(other) + * return v2_add(self, other) # <<<<<<<<<<<<<< + * + * # __radd__ not supported for Vec2 + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 224, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_add(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_other))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 224, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":221 + * return self.x < o.x + * + * def __add__(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__add__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":230 + * __iadd__ = __add__ # immutable + * + * def __sub__(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_58__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_58__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__sub__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_57__sub__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_57__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__sub__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":231 + * + * def __sub__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return v2_sub(self, other) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":232 + * def __sub__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): + * other = Vec2(other) # <<<<<<<<<<<<<< + * return v2_sub(self, other) + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":231 + * + * def __sub__(self, other: AnyVec) -> Vec2: + * if not isinstance(other, Vec2): # <<<<<<<<<<<<<< + * other = Vec2(other) + * return v2_sub(self, other) + */ + } + + /* "ezdxf/acc/vector.pyx":233 + * if not isinstance(other, Vec2): + * other = Vec2(other) + * return v2_sub(self, other) # <<<<<<<<<<<<<< + * + * # __rsub__ not supported for Vec2 + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 233, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_sub(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_other))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 233, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":230 + * __iadd__ = __add__ # immutable + * + * def __sub__(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec2): + * other = Vec2(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__sub__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":239 + * __isub__ = __sub__ # immutable + * + * def __mul__(self, factor) -> Vec2: # <<<<<<<<<<<<<< + * if isinstance(self, Vec2): + * return v2_mul(self, factor) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_60__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_60__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__mul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_59__mul__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_59__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + double __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__mul__", 1); + + /* "ezdxf/acc/vector.pyx":240 + * + * def __mul__(self, factor) -> Vec2: + * if isinstance(self, Vec2): # <<<<<<<<<<<<<< + * return v2_mul(self, factor) + * elif isinstance(factor, Vec2): + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":241 + * def __mul__(self, factor) -> Vec2: + * if isinstance(self, Vec2): + * return v2_mul(self, factor) # <<<<<<<<<<<<<< + * elif isinstance(factor, Vec2): + * return v2_mul( factor, self) + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 241, __pyx_L1_error) + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_factor); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 241, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 241, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":240 + * + * def __mul__(self, factor) -> Vec2: + * if isinstance(self, Vec2): # <<<<<<<<<<<<<< + * return v2_mul(self, factor) + * elif isinstance(factor, Vec2): + */ + } + + /* "ezdxf/acc/vector.pyx":242 + * if isinstance(self, Vec2): + * return v2_mul(self, factor) + * elif isinstance(factor, Vec2): # <<<<<<<<<<<<<< + * return v2_mul( factor, self) + * else: + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_factor, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":243 + * return v2_mul(self, factor) + * elif isinstance(factor, Vec2): + * return v2_mul( factor, self) # <<<<<<<<<<<<<< + * else: + * return NotImplemented + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_self); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 243, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_factor), ((double)__pyx_t_2))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":242 + * if isinstance(self, Vec2): + * return v2_mul(self, factor) + * elif isinstance(factor, Vec2): # <<<<<<<<<<<<<< + * return v2_mul( factor, self) + * else: + */ + } + + /* "ezdxf/acc/vector.pyx":245 + * return v2_mul( factor, self) + * else: + * return NotImplemented # <<<<<<<<<<<<<< + * + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_builtin_NotImplemented); + __pyx_r = __pyx_builtin_NotImplemented; + goto __pyx_L0; + } + + /* "ezdxf/acc/vector.pyx":239 + * __isub__ = __sub__ # immutable + * + * def __mul__(self, factor) -> Vec2: # <<<<<<<<<<<<<< + * if isinstance(self, Vec2): + * return v2_mul(self, factor) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__mul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":249 + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * + * def __rmul__(self, double factor) -> Vec2: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v2_mul(self, factor) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_62__rmul__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_62__rmul__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor) { + double __pyx_v_factor; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__rmul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_factor); { + __pyx_v_factor = __pyx_PyFloat_AsDouble(__pyx_arg_factor); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 249, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__rmul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_61__rmul__(((PyObject *)__pyx_v_self), ((double)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_61__rmul__(PyObject *__pyx_v_self, double __pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__rmul__", 1); + + /* "ezdxf/acc/vector.pyx":251 + * def __rmul__(self, double factor) -> Vec2: + * # for Cython >= 3.0 + * return v2_mul(self, factor) # <<<<<<<<<<<<<< + * + * __imul__ = __mul__ # immutable + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 251, __pyx_L1_error) + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_factor)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":249 + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * + * def __rmul__(self, double factor) -> Vec2: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v2_mul(self, factor) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__rmul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":255 + * __imul__ = __mul__ # immutable + * + * def __truediv__(self, double factor) -> Vec2: # <<<<<<<<<<<<<< + * return v2_mul(self, 1.0 / factor) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_64__truediv__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_64__truediv__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor) { + double __pyx_v_factor; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__truediv__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_factor); { + __pyx_v_factor = __pyx_PyFloat_AsDouble(__pyx_arg_factor); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 255, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__truediv__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_63__truediv__(((PyObject *)__pyx_v_self), ((double)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_63__truediv__(PyObject *__pyx_v_self, double __pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__truediv__", 1); + + /* "ezdxf/acc/vector.pyx":256 + * + * def __truediv__(self, double factor) -> Vec2: + * return v2_mul(self, 1.0 / factor) # <<<<<<<<<<<<<< + * + * # __rtruediv__ not supported -> TypeError + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 256, __pyx_L1_error) + if (unlikely(__pyx_v_factor == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 256, __pyx_L1_error) + } + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), (1.0 / __pyx_v_factor))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":255 + * __imul__ = __mul__ # immutable + * + * def __truediv__(self, double factor) -> Vec2: # <<<<<<<<<<<<<< + * return v2_mul(self, 1.0 / factor) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.__truediv__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":260 + * # __rtruediv__ not supported -> TypeError + * + * def dot(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dot(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_66dot(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_66dot = {"dot", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_66dot, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_66dot(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("dot (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 260, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "dot") < 0)) __PYX_ERR(0, 260, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("dot", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 260, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.dot", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_65dot(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_65dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("dot", 1); + + /* "ezdxf/acc/vector.pyx":261 + * + * def dot(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_dot(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":262 + * def dot(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) + * return v2_dot(self, o) # <<<<<<<<<<<<<< + * + * def det(self, other: AnyVec) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_dot(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 262, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":260 + * # __rtruediv__ not supported -> TypeError + * + * def dot(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dot(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.dot", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":264 + * return v2_dot(self, o) + * + * def det(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_det(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_68det(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_68det = {"det", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_68det, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_68det(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("det (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 264, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "det") < 0)) __PYX_ERR(0, 264, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("det", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 264, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.det", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_67det(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_67det(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("det", 1); + + /* "ezdxf/acc/vector.pyx":265 + * + * def det(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_det(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":266 + * def det(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) + * return v2_det(self, o) # <<<<<<<<<<<<<< + * + * def distance(self, other: AnyVec) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_det(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 266, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 266, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":264 + * return v2_dot(self, o) + * + * def det(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_det(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.det", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":268 + * return v2_det(self, o) + * + * def distance(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dist(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_70distance(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_70distance = {"distance", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_70distance, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_70distance(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("distance (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 268, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "distance") < 0)) __PYX_ERR(0, 268, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("distance", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 268, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_69distance(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_69distance(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("distance", 1); + + /* "ezdxf/acc/vector.pyx":269 + * + * def distance(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_dist(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 269, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":270 + * def distance(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) + * return v2_dist(self, o) # <<<<<<<<<<<<<< + * + * def angle_between(self, other: AnyVec) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_dist(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 270, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":268 + * return v2_det(self, o) + * + * def distance(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dist(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":272 + * return v2_dist(self, o) + * + * def angle_between(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_angle_between(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_72angle_between(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_72angle_between = {"angle_between", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_72angle_between, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_72angle_between(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("angle_between (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 272, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "angle_between") < 0)) __PYX_ERR(0, 272, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("angle_between", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 272, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_71angle_between(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_71angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("angle_between", 1); + + /* "ezdxf/acc/vector.pyx":273 + * + * def angle_between(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) # <<<<<<<<<<<<<< + * return v2_angle_between(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":274 + * def angle_between(self, other: AnyVec) -> float: + * cdef Vec2 o = Vec2(other) + * return v2_angle_between(self, o) # <<<<<<<<<<<<<< + * + * def rotate(self, double angle) -> Vec2: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_angle_between(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1000.0))) __PYX_ERR(0, 274, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":272 + * return v2_dist(self, o) + * + * def angle_between(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_angle_between(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":276 + * return v2_angle_between(self, o) + * + * def rotate(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_74rotate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_74rotate = {"rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_74rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_74rotate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 276, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "rotate") < 0)) __PYX_ERR(0, 276, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 276, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("rotate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 276, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_73rotate(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_73rotate(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_angle) { + double __pyx_v_self_angle; + double __pyx_v_magnitude; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("rotate", 1); + + /* "ezdxf/acc/vector.pyx":277 + * + * def rotate(self, double angle) -> Vec2: + * cdef double self_angle = atan2(self.y, self.x) # <<<<<<<<<<<<<< + * cdef double magnitude = hypot(self.x, self.y) + * return v2_from_angle(self_angle + angle, magnitude) + */ + __pyx_v_self_angle = atan2(__pyx_v_self->y, __pyx_v_self->x); + + /* "ezdxf/acc/vector.pyx":278 + * def rotate(self, double angle) -> Vec2: + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) # <<<<<<<<<<<<<< + * return v2_from_angle(self_angle + angle, magnitude) + * + */ + __pyx_v_magnitude = hypot(__pyx_v_self->x, __pyx_v_self->y); + + /* "ezdxf/acc/vector.pyx":279 + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) + * return v2_from_angle(self_angle + angle, magnitude) # <<<<<<<<<<<<<< + * + * def rotate_deg(self, double angle) -> Vec2: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_from_angle((__pyx_v_self_angle + __pyx_v_angle), __pyx_v_magnitude)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 279, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":276 + * return v2_angle_between(self, o) + * + * def rotate(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":281 + * return v2_from_angle(self_angle + angle, magnitude) + * + * def rotate_deg(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_76rotate_deg(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_76rotate_deg = {"rotate_deg", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_76rotate_deg, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_76rotate_deg(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rotate_deg (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 281, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "rotate_deg") < 0)) __PYX_ERR(0, 281, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 281, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("rotate_deg", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 281, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.rotate_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_75rotate_deg(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self), __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_75rotate_deg(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self, double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("rotate_deg", 1); + + /* "ezdxf/acc/vector.pyx":282 + * + * def rotate_deg(self, double angle) -> Vec2: + * return self.rotate(angle * DEG2RAD) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_rotate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_angle * __pyx_v_5ezdxf_3acc_6vector_DEG2RAD)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 282, __pyx_L1_error) + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":281 + * return v2_from_angle(self_angle + angle, magnitude) + * + * def rotate_deg(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.rotate_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":284 + * return self.rotate(angle * DEG2RAD) + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[Vec2]) -> Vec2: + * cdef Vec2 res = Vec2() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_78sum(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec2_78sum = {"sum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_78sum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_78sum(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("sum (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 284, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sum") < 0)) __PYX_ERR(0, 284, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("sum", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 284, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.sum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_77sum(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_77sum(PyObject *__pyx_v_items) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_tmp = 0; + PyObject *__pyx_v_v = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("sum", 1); + + /* "ezdxf/acc/vector.pyx":286 + * @staticmethod + * def sum(items: Iterable[Vec2]) -> Vec2: + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * cdef Vec2 tmp + * res.x = 0.0 + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 286, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":288 + * cdef Vec2 res = Vec2() + * cdef Vec2 tmp + * res.x = 0.0 # <<<<<<<<<<<<<< + * res.y = 0.0 + * for v in items: + */ + __pyx_v_res->x = 0.0; + + /* "ezdxf/acc/vector.pyx":289 + * cdef Vec2 tmp + * res.x = 0.0 + * res.y = 0.0 # <<<<<<<<<<<<<< + * for v in items: + * tmp = v + */ + __pyx_v_res->y = 0.0; + + /* "ezdxf/acc/vector.pyx":290 + * res.x = 0.0 + * res.y = 0.0 + * for v in items: # <<<<<<<<<<<<<< + * tmp = v + * res.x += tmp.x + */ + if (likely(PyList_CheckExact(__pyx_v_items)) || PyTuple_CheckExact(__pyx_v_items)) { + __pyx_t_1 = __pyx_v_items; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_items); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 290, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 290, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 290, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 290, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 290, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 290, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 290, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 290, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":291 + * res.y = 0.0 + * for v in items: + * tmp = v # <<<<<<<<<<<<<< + * res.x += tmp.x + * res.y += tmp.y + */ + if (!(likely(((__pyx_v_v) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_v, __pyx_ptype_5ezdxf_3acc_6vector_Vec2))))) __PYX_ERR(0, 291, __pyx_L1_error) + __pyx_t_4 = __pyx_v_v; + __Pyx_INCREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_tmp, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":292 + * for v in items: + * tmp = v + * res.x += tmp.x # <<<<<<<<<<<<<< + * res.y += tmp.y + * return res + */ + __pyx_v_res->x = (__pyx_v_res->x + __pyx_v_tmp->x); + + /* "ezdxf/acc/vector.pyx":293 + * tmp = v + * res.x += tmp.x + * res.y += tmp.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_res->y + __pyx_v_tmp->y); + + /* "ezdxf/acc/vector.pyx":290 + * res.x = 0.0 + * res.y = 0.0 + * for v in items: # <<<<<<<<<<<<<< + * tmp = v + * res.x += tmp.x + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":294 + * res.x += tmp.x + * res.y += tmp.y + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":284 + * return self.rotate(angle * DEG2RAD) + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[Vec2]) -> Vec2: + * cdef Vec2 res = Vec2() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.sum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XDECREF((PyObject *)__pyx_v_tmp); + __Pyx_XDECREF(__pyx_v_v); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pxd":10 + * + * cdef class Vec2: + * cdef readonly double x, y # <<<<<<<<<<<<<< + * + * # Vec2 C-functions: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_1x_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_1x_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_1x___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_1x___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.x.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_1y_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec2_1y_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec2_1y___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec2_1y___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec2.y.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":297 + * + * + * cdef Vec2 v2_add(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x + b.x + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_add(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_add", 1); + + /* "ezdxf/acc/vector.pyx":298 + * + * cdef Vec2 v2_add(Vec2 a, Vec2 b): + * res = Vec2() # <<<<<<<<<<<<<< + * res.x = a.x + b.x + * res.y = a.y + b.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 298, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":299 + * cdef Vec2 v2_add(Vec2 a, Vec2 b): + * res = Vec2() + * res.x = a.x + b.x # <<<<<<<<<<<<<< + * res.y = a.y + b.y + * return res + */ + __pyx_v_res->x = (__pyx_v_a->x + __pyx_v_b->x); + + /* "ezdxf/acc/vector.pyx":300 + * res = Vec2() + * res.x = a.x + b.x + * res.y = a.y + b.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_a->y + __pyx_v_b->y); + + /* "ezdxf/acc/vector.pyx":301 + * res.x = a.x + b.x + * res.y = a.y + b.y + * return res # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_sub(Vec2 a, Vec2 b): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":297 + * + * + * cdef Vec2 v2_add(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x + b.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_add", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":303 + * return res + * + * cdef Vec2 v2_sub(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x - b.x + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_sub(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_sub", 1); + + /* "ezdxf/acc/vector.pyx":304 + * + * cdef Vec2 v2_sub(Vec2 a, Vec2 b): + * res = Vec2() # <<<<<<<<<<<<<< + * res.x = a.x - b.x + * res.y = a.y - b.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":305 + * cdef Vec2 v2_sub(Vec2 a, Vec2 b): + * res = Vec2() + * res.x = a.x - b.x # <<<<<<<<<<<<<< + * res.y = a.y - b.y + * return res + */ + __pyx_v_res->x = (__pyx_v_a->x - __pyx_v_b->x); + + /* "ezdxf/acc/vector.pyx":306 + * res = Vec2() + * res.x = a.x - b.x + * res.y = a.y - b.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_a->y - __pyx_v_b->y); + + /* "ezdxf/acc/vector.pyx":307 + * res.x = a.x - b.x + * res.y = a.y - b.y + * return res # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_mul(Vec2 a, double factor): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":303 + * return res + * + * cdef Vec2 v2_sub(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x - b.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_sub", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":309 + * return res + * + * cdef Vec2 v2_mul(Vec2 a, double factor): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x * factor + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_mul", 1); + + /* "ezdxf/acc/vector.pyx":310 + * + * cdef Vec2 v2_mul(Vec2 a, double factor): + * res = Vec2() # <<<<<<<<<<<<<< + * res.x = a.x * factor + * res.y = a.y * factor + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":311 + * cdef Vec2 v2_mul(Vec2 a, double factor): + * res = Vec2() + * res.x = a.x * factor # <<<<<<<<<<<<<< + * res.y = a.y * factor + * return res + */ + __pyx_v_res->x = (__pyx_v_a->x * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":312 + * res = Vec2() + * res.x = a.x * factor + * res.y = a.y * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_a->y * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":313 + * res.x = a.x * factor + * res.y = a.y * factor + * return res # <<<<<<<<<<<<<< + * + * cdef double v2_dot(Vec2 a, Vec2 b): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":309 + * return res + * + * cdef Vec2 v2_mul(Vec2 a, double factor): # <<<<<<<<<<<<<< + * res = Vec2() + * res.x = a.x * factor + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_mul", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":315 + * return res + * + * cdef double v2_dot(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return a.x * b.x + a.y * b.y + * + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v2_dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":316 + * + * cdef double v2_dot(Vec2 a, Vec2 b): + * return a.x * b.x + a.y * b.y # <<<<<<<<<<<<<< + * + * cdef double v2_det(Vec2 a, Vec2 b): + */ + __pyx_r = ((__pyx_v_a->x * __pyx_v_b->x) + (__pyx_v_a->y * __pyx_v_b->y)); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":315 + * return res + * + * cdef double v2_dot(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return a.x * b.x + a.y * b.y + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":318 + * return a.x * b.x + a.y * b.y + * + * cdef double v2_det(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return a.x * b.y - a.y * b.x + * + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v2_det(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":319 + * + * cdef double v2_det(Vec2 a, Vec2 b): + * return a.x * b.y - a.y * b.x # <<<<<<<<<<<<<< + * + * cdef double v2_dist(Vec2 a, Vec2 b): + */ + __pyx_r = ((__pyx_v_a->x * __pyx_v_b->y) - (__pyx_v_a->y * __pyx_v_b->x)); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":318 + * return a.x * b.x + a.y * b.y + * + * cdef double v2_det(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return a.x * b.y - a.y * b.x + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":321 + * return a.x * b.y - a.y * b.x + * + * cdef double v2_dist(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return hypot(a.x - b.x, a.y - b.y) + * + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v2_dist(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":322 + * + * cdef double v2_dist(Vec2 a, Vec2 b): + * return hypot(a.x - b.x, a.y - b.y) # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_from_angle(double angle, double length): + */ + __pyx_r = hypot((__pyx_v_a->x - __pyx_v_b->x), (__pyx_v_a->y - __pyx_v_b->y)); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":321 + * return a.x * b.y - a.y * b.x + * + * cdef double v2_dist(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * return hypot(a.x - b.x, a.y - b.y) + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":324 + * return hypot(a.x - b.x, a.y - b.y) + * + * cdef Vec2 v2_from_angle(double angle, double length): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = cos(angle) * length + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_from_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_from_angle", 1); + + /* "ezdxf/acc/vector.pyx":325 + * + * cdef Vec2 v2_from_angle(double angle, double length): + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * res.x = cos(angle) * length + * res.y = sin(angle) * length + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 325, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":326 + * cdef Vec2 v2_from_angle(double angle, double length): + * cdef Vec2 res = Vec2() + * res.x = cos(angle) * length # <<<<<<<<<<<<<< + * res.y = sin(angle) * length + * return res + */ + __pyx_v_res->x = (cos(__pyx_v_angle) * __pyx_v_length); + + /* "ezdxf/acc/vector.pyx":327 + * cdef Vec2 res = Vec2() + * res.x = cos(angle) * length + * res.y = sin(angle) * length # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (sin(__pyx_v_angle) * __pyx_v_length); + + /* "ezdxf/acc/vector.pyx":328 + * res.x = cos(angle) * length + * res.y = sin(angle) * length + * return res # <<<<<<<<<<<<<< + * + * cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":324 + * return hypot(a.x - b.x, a.y - b.y) + * + * cdef Vec2 v2_from_angle(double angle, double length): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = cos(angle) * length + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":330 + * return res + * + * cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000: # <<<<<<<<<<<<<< + * cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v2_angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + double __pyx_v_cos_theta; + double __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_angle_between", 1); + + /* "ezdxf/acc/vector.pyx":331 + * + * cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000: + * cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) # <<<<<<<<<<<<<< + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_normalize(__pyx_v_a, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 331, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_normalize(__pyx_v_b, 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 331, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v2_dot(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2)); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 331, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_cos_theta = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":333 + * cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: # <<<<<<<<<<<<<< + * cos_theta = -1.0 + * elif cos_theta > 1.0: + */ + __pyx_t_4 = (__pyx_v_cos_theta < -1.0); + if (__pyx_t_4) { + + /* "ezdxf/acc/vector.pyx":334 + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: + * cos_theta = -1.0 # <<<<<<<<<<<<<< + * elif cos_theta > 1.0: + * cos_theta = 1.0 + */ + __pyx_v_cos_theta = -1.0; + + /* "ezdxf/acc/vector.pyx":333 + * cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: # <<<<<<<<<<<<<< + * cos_theta = -1.0 + * elif cos_theta > 1.0: + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/vector.pyx":335 + * if cos_theta < -1.0: + * cos_theta = -1.0 + * elif cos_theta > 1.0: # <<<<<<<<<<<<<< + * cos_theta = 1.0 + * return acos(cos_theta) + */ + __pyx_t_4 = (__pyx_v_cos_theta > 1.0); + if (__pyx_t_4) { + + /* "ezdxf/acc/vector.pyx":336 + * cos_theta = -1.0 + * elif cos_theta > 1.0: + * cos_theta = 1.0 # <<<<<<<<<<<<<< + * return acos(cos_theta) + * + */ + __pyx_v_cos_theta = 1.0; + + /* "ezdxf/acc/vector.pyx":335 + * if cos_theta < -1.0: + * cos_theta = -1.0 + * elif cos_theta > 1.0: # <<<<<<<<<<<<<< + * cos_theta = 1.0 + * return acos(cos_theta) + */ + } + __pyx_L3:; + + /* "ezdxf/acc/vector.pyx":337 + * elif cos_theta > 1.0: + * cos_theta = 1.0 + * return acos(cos_theta) # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_normalize(Vec2 a, double length): + */ + __pyx_r = acos(__pyx_v_cos_theta); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":330 + * return res + * + * cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000: # <<<<<<<<<<<<<< + * cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1000.0; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":339 + * return acos(cos_theta) + * + * cdef Vec2 v2_normalize(Vec2 a, double length): # <<<<<<<<<<<<<< + * cdef double factor = length / hypot(a.x, a.y) + * cdef Vec2 res = Vec2() + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, double __pyx_v_length) { + double __pyx_v_factor; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_normalize", 1); + + /* "ezdxf/acc/vector.pyx":340 + * + * cdef Vec2 v2_normalize(Vec2 a, double length): + * cdef double factor = length / hypot(a.x, a.y) # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = a.x * factor + */ + __pyx_t_1 = hypot(__pyx_v_a->x, __pyx_v_a->y); + if (unlikely(__pyx_t_1 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 340, __pyx_L1_error) + } + __pyx_v_factor = (__pyx_v_length / __pyx_t_1); + + /* "ezdxf/acc/vector.pyx":341 + * cdef Vec2 v2_normalize(Vec2 a, double length): + * cdef double factor = length / hypot(a.x, a.y) + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * res.x = a.x * factor + * res.y = a.y * factor + */ + __pyx_t_2 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 341, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":342 + * cdef double factor = length / hypot(a.x, a.y) + * cdef Vec2 res = Vec2() + * res.x = a.x * factor # <<<<<<<<<<<<<< + * res.y = a.y * factor + * return res + */ + __pyx_v_res->x = (__pyx_v_a->x * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":343 + * cdef Vec2 res = Vec2() + * res.x = a.x * factor + * res.y = a.y * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_a->y * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":344 + * res.x = a.x * factor + * res.y = a.y * factor + * return res # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":339 + * return acos(cos_theta) + * + * cdef Vec2 v2_normalize(Vec2 a, double length): # <<<<<<<<<<<<<< + * cdef double factor = length / hypot(a.x, a.y) + * cdef Vec2 res = Vec2() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":346 + * return res + * + * cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = a.x + (b.x - a.x) * factor + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_lerp", 1); + + /* "ezdxf/acc/vector.pyx":347 + * + * cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":348 + * cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): + * cdef Vec2 res = Vec2() + * res.x = a.x + (b.x - a.x) * factor # <<<<<<<<<<<<<< + * res.y = a.y + (b.y - a.y) * factor + * return res + */ + __pyx_v_res->x = (__pyx_v_a->x + ((__pyx_v_b->x - __pyx_v_a->x) * __pyx_v_factor)); + + /* "ezdxf/acc/vector.pyx":349 + * cdef Vec2 res = Vec2() + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (__pyx_v_a->y + ((__pyx_v_b->y - __pyx_v_a->y) * __pyx_v_factor)); + + /* "ezdxf/acc/vector.pyx":350 + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor + * return res # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":346 + * return res + * + * cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * res.x = a.x + (b.x - a.x) * factor + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":352 + * return res + * + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * if ccw: + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_ortho(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, int __pyx_v_ccw) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_ortho", 1); + + /* "ezdxf/acc/vector.pyx":353 + * + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * if ccw: + * res.x = -a.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":354 + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): + * cdef Vec2 res = Vec2() + * if ccw: # <<<<<<<<<<<<<< + * res.x = -a.y + * res.y = a.x + */ + if (__pyx_v_ccw) { + + /* "ezdxf/acc/vector.pyx":355 + * cdef Vec2 res = Vec2() + * if ccw: + * res.x = -a.y # <<<<<<<<<<<<<< + * res.y = a.x + * else: + */ + __pyx_v_res->x = (-__pyx_v_a->y); + + /* "ezdxf/acc/vector.pyx":356 + * if ccw: + * res.x = -a.y + * res.y = a.x # <<<<<<<<<<<<<< + * else: + * res.x = a.y + */ + __pyx_t_2 = __pyx_v_a->x; + __pyx_v_res->y = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":354 + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): + * cdef Vec2 res = Vec2() + * if ccw: # <<<<<<<<<<<<<< + * res.x = -a.y + * res.y = a.x + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/vector.pyx":358 + * res.y = a.x + * else: + * res.x = a.y # <<<<<<<<<<<<<< + * res.y = -a.x + * return res + */ + /*else*/ { + __pyx_t_2 = __pyx_v_a->y; + __pyx_v_res->x = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":359 + * else: + * res.x = a.y + * res.y = -a.x # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (-__pyx_v_a->x); + } + __pyx_L3:; + + /* "ezdxf/acc/vector.pyx":360 + * res.x = a.y + * res.y = -a.x + * return res # <<<<<<<<<<<<<< + * + * cdef Vec2 v2_project(Vec2 a, Vec2 b): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":352 + * return res + * + * cdef Vec2 v2_ortho(Vec2 a, bint ccw): # <<<<<<<<<<<<<< + * cdef Vec2 res = Vec2() + * if ccw: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_ortho", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":362 + * return res + * + * cdef Vec2 v2_project(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * cdef Vec2 uv = v2_normalize(a, 1.0) + * return v2_mul(uv, v2_dot(uv, b)) + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_f_5ezdxf_3acc_6vector_v2_project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_uv = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v2_project", 1); + + /* "ezdxf/acc/vector.pyx":363 + * + * cdef Vec2 v2_project(Vec2 a, Vec2 b): + * cdef Vec2 uv = v2_normalize(a, 1.0) # <<<<<<<<<<<<<< + * return v2_mul(uv, v2_dot(uv, b)) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_normalize(__pyx_v_a, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 363, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_uv = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":364 + * cdef Vec2 v2_project(Vec2 a, Vec2 b): + * cdef Vec2 uv = v2_normalize(a, 1.0) + * return v2_mul(uv, v2_dot(uv, b)) # <<<<<<<<<<<<<< + * + * cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v2_dot(__pyx_v_uv, __pyx_v_b); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 364, __pyx_L1_error) + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v2_mul(__pyx_v_uv, __pyx_t_2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":362 + * return res + * + * cdef Vec2 v2_project(Vec2 a, Vec2 b): # <<<<<<<<<<<<<< + * cdef Vec2 uv = v2_normalize(a, 1.0) + * return v2_mul(uv, v2_dot(uv, b)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v2_project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_uv); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":366 + * return v2_mul(uv, v2_dot(uv, b)) + * + * cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) + */ + +static int __pyx_f_5ezdxf_3acc_6vector_v2_isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_b, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "ezdxf/acc/vector.pyx":367 + * + * cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ # <<<<<<<<<<<<<< + * isclose(a.y, b.y, rel_tol, abs_tol) + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_a->x, __pyx_v_b->x, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 367, __pyx_L1_error) + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":368 + * cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_a->y, __pyx_v_b->y, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 368, __pyx_L1_error) + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":366 + * return v2_mul(uv, v2_dot(uv, b)) + * + * cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.v2_isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":386 + * """ + * + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len( args) + * if count == 0: # fastest init - default constructor + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec3_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec3_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_args = 0; + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1; + #endif + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_VARARGS(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __Pyx_INCREF(__pyx_args); + __pyx_v_args = __pyx_args; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3___cinit__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_args); + + /* function exit code */ + __Pyx_DECREF(__pyx_v_args); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec3___cinit__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_args) { + Py_ssize_t __pyx_v_count; + PyObject *__pyx_v_arg0 = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + __Pyx_INCREF(__pyx_v_args); + + /* "ezdxf/acc/vector.pyx":387 + * + * def __cinit__(self, *args): + * cdef Py_ssize_t count = len( args) # <<<<<<<<<<<<<< + * if count == 0: # fastest init - default constructor + * self.x = 0 + */ + if (unlikely(__pyx_v_args == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(0, 387, __pyx_L1_error) + } + __pyx_t_1 = __Pyx_PyTuple_GET_SIZE(((PyObject*)__pyx_v_args)); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 387, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":388 + * def __cinit__(self, *args): + * cdef Py_ssize_t count = len( args) + * if count == 0: # fastest init - default constructor # <<<<<<<<<<<<<< + * self.x = 0 + * self.y = 0 + */ + __pyx_t_2 = (__pyx_v_count == 0); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":389 + * cdef Py_ssize_t count = len( args) + * if count == 0: # fastest init - default constructor + * self.x = 0 # <<<<<<<<<<<<<< + * self.y = 0 + * self.z = 0 + */ + __pyx_v_self->x = 0.0; + + /* "ezdxf/acc/vector.pyx":390 + * if count == 0: # fastest init - default constructor + * self.x = 0 + * self.y = 0 # <<<<<<<<<<<<<< + * self.z = 0 + * return + */ + __pyx_v_self->y = 0.0; + + /* "ezdxf/acc/vector.pyx":391 + * self.x = 0 + * self.y = 0 + * self.z = 0 # <<<<<<<<<<<<<< + * return + * + */ + __pyx_v_self->z = 0.0; + + /* "ezdxf/acc/vector.pyx":392 + * self.y = 0 + * self.z = 0 + * return # <<<<<<<<<<<<<< + * + * if count == 1: + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":388 + * def __cinit__(self, *args): + * cdef Py_ssize_t count = len( args) + * if count == 0: # fastest init - default constructor # <<<<<<<<<<<<<< + * self.x = 0 + * self.y = 0 + */ + } + + /* "ezdxf/acc/vector.pyx":394 + * return + * + * if count == 1: # <<<<<<<<<<<<<< + * arg0 = args[0] + * if isinstance(arg0, Vec3): + */ + __pyx_t_2 = (__pyx_v_count == 1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":395 + * + * if count == 1: + * arg0 = args[0] # <<<<<<<<<<<<<< + * if isinstance(arg0, Vec3): + * # fast init by Vec3() + */ + __pyx_t_3 = __Pyx_GetItemInt_Tuple(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 395, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_v_arg0 = __pyx_t_3; + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":396 + * if count == 1: + * arg0 = args[0] + * if isinstance(arg0, Vec3): # <<<<<<<<<<<<<< + * # fast init by Vec3() + * self.x = ( arg0).x + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_arg0, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":398 + * if isinstance(arg0, Vec3): + * # fast init by Vec3() + * self.x = ( arg0).x # <<<<<<<<<<<<<< + * self.y = ( arg0).y + * self.z = ( arg0).z + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_arg0)->x; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":399 + * # fast init by Vec3() + * self.x = ( arg0).x + * self.y = ( arg0).y # <<<<<<<<<<<<<< + * self.z = ( arg0).z + * return + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_arg0)->y; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":400 + * self.x = ( arg0).x + * self.y = ( arg0).y + * self.z = ( arg0).z # <<<<<<<<<<<<<< + * return + * if isinstance(arg0, Vec2): + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_arg0)->z; + __pyx_v_self->z = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":401 + * self.y = ( arg0).y + * self.z = ( arg0).z + * return # <<<<<<<<<<<<<< + * if isinstance(arg0, Vec2): + * # fast init by Vec2() + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":396 + * if count == 1: + * arg0 = args[0] + * if isinstance(arg0, Vec3): # <<<<<<<<<<<<<< + * # fast init by Vec3() + * self.x = ( arg0).x + */ + } + + /* "ezdxf/acc/vector.pyx":402 + * self.z = ( arg0).z + * return + * if isinstance(arg0, Vec2): # <<<<<<<<<<<<<< + * # fast init by Vec2() + * self.x = ( arg0).x + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_arg0, __pyx_ptype_5ezdxf_3acc_6vector_Vec2); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":404 + * if isinstance(arg0, Vec2): + * # fast init by Vec2() + * self.x = ( arg0).x # <<<<<<<<<<<<<< + * self.y = ( arg0).y + * self.z = 0 + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_arg0)->x; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":405 + * # fast init by Vec2() + * self.x = ( arg0).x + * self.y = ( arg0).y # <<<<<<<<<<<<<< + * self.z = 0 + * return + */ + __pyx_t_4 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_v_arg0)->y; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":406 + * self.x = ( arg0).x + * self.y = ( arg0).y + * self.z = 0 # <<<<<<<<<<<<<< + * return + * args = arg0 + */ + __pyx_v_self->z = 0.0; + + /* "ezdxf/acc/vector.pyx":407 + * self.y = ( arg0).y + * self.z = 0 + * return # <<<<<<<<<<<<<< + * args = arg0 + * count = len(args) + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":402 + * self.z = ( arg0).z + * return + * if isinstance(arg0, Vec2): # <<<<<<<<<<<<<< + * # fast init by Vec2() + * self.x = ( arg0).x + */ + } + + /* "ezdxf/acc/vector.pyx":408 + * self.z = 0 + * return + * args = arg0 # <<<<<<<<<<<<<< + * count = len(args) + * + */ + __Pyx_INCREF(__pyx_v_arg0); + __Pyx_DECREF_SET(__pyx_v_args, __pyx_v_arg0); + + /* "ezdxf/acc/vector.pyx":409 + * return + * args = arg0 + * count = len(args) # <<<<<<<<<<<<<< + * + * if count > 3 or count < 2: + */ + __pyx_t_1 = PyObject_Length(__pyx_v_args); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 409, __pyx_L1_error) + __pyx_v_count = __pyx_t_1; + + /* "ezdxf/acc/vector.pyx":394 + * return + * + * if count == 1: # <<<<<<<<<<<<<< + * arg0 = args[0] + * if isinstance(arg0, Vec3): + */ + } + + /* "ezdxf/acc/vector.pyx":411 + * count = len(args) + * + * if count > 3 or count < 2: # <<<<<<<<<<<<<< + * raise TypeError('invalid argument count') + * + */ + __pyx_t_5 = (__pyx_v_count > 3); + if (!__pyx_t_5) { + } else { + __pyx_t_2 = __pyx_t_5; + goto __pyx_L8_bool_binop_done; + } + __pyx_t_5 = (__pyx_v_count < 2); + __pyx_t_2 = __pyx_t_5; + __pyx_L8_bool_binop_done:; + if (unlikely(__pyx_t_2)) { + + /* "ezdxf/acc/vector.pyx":412 + * + * if count > 3 or count < 2: + * raise TypeError('invalid argument count') # <<<<<<<<<<<<<< + * + * # slow init by sequence + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 412, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 412, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":411 + * count = len(args) + * + * if count > 3 or count < 2: # <<<<<<<<<<<<<< + * raise TypeError('invalid argument count') + * + */ + } + + /* "ezdxf/acc/vector.pyx":415 + * + * # slow init by sequence + * self.x = args[0] # <<<<<<<<<<<<<< + * self.y = args[1] + * if count > 2: + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 415, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 415, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_self->x = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":416 + * # slow init by sequence + * self.x = args[0] + * self.y = args[1] # <<<<<<<<<<<<<< + * if count > 2: + * self.z = args[2] + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_self->y = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":417 + * self.x = args[0] + * self.y = args[1] + * if count > 2: # <<<<<<<<<<<<<< + * self.z = args[2] + * else: + */ + __pyx_t_2 = (__pyx_v_count > 2); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":418 + * self.y = args[1] + * if count > 2: + * self.z = args[2] # <<<<<<<<<<<<<< + * else: + * self.z = 0.0 + */ + __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_args, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 418, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_t_3); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 418, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_self->z = __pyx_t_4; + + /* "ezdxf/acc/vector.pyx":417 + * self.x = args[0] + * self.y = args[1] + * if count > 2: # <<<<<<<<<<<<<< + * self.z = args[2] + * else: + */ + goto __pyx_L10; + } + + /* "ezdxf/acc/vector.pyx":420 + * self.z = args[2] + * else: + * self.z = 0.0 # <<<<<<<<<<<<<< + * + * def __reduce__(self): + */ + /*else*/ { + __pyx_v_self->z = 0.0; + } + __pyx_L10:; + + /* "ezdxf/acc/vector.pyx":386 + * """ + * + * def __cinit__(self, *args): # <<<<<<<<<<<<<< + * cdef Py_ssize_t count = len( args) + * if count == 0: # fastest init - default constructor + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_args); + __Pyx_XDECREF(__pyx_v_arg0); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":422 + * self.z = 0.0 + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec3, self.xyz + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_3__reduce__ = {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3__reduce__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("__reduce__", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__reduce__", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_2__reduce__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_2__reduce__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce__", 1); + + /* "ezdxf/acc/vector.pyx":423 + * + * def __reduce__(self): + * return Vec3, self.xyz # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_xyz); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 423, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 423, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GIVEREF((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3))) __PYX_ERR(0, 423, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_1)) __PYX_ERR(0, 423, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":422 + * self.z = 0.0 + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec3, self.xyz + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":425 + * return Vec3, self.xyz + * + * @property # <<<<<<<<<<<<<< + * def xy(self) -> Vec3: + * cdef Vec3 res = Vec3() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_2xy_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_2xy_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_2xy___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_2xy___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":427 + * @property + * def xy(self) -> Vec3: + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = self.x + * res.y = self.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":428 + * def xy(self) -> Vec3: + * cdef Vec3 res = Vec3() + * res.x = self.x # <<<<<<<<<<<<<< + * res.y = self.y + * return res + */ + __pyx_t_2 = __pyx_v_self->x; + __pyx_v_res->x = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":429 + * cdef Vec3 res = Vec3() + * res.x = self.x + * res.y = self.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_t_2 = __pyx_v_self->y; + __pyx_v_res->y = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":430 + * res.x = self.x + * res.y = self.y + * return res # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = ((PyObject *)__pyx_v_res); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":425 + * return Vec3, self.xyz + * + * @property # <<<<<<<<<<<<<< + * def xy(self) -> Vec3: + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.xy.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":432 + * return res + * + * @property # <<<<<<<<<<<<<< + * def xyz(self) -> Tuple[float, float, float]: + * return self.x, self.y, self.z + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3xyz_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3xyz_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_3xyz___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_3xyz___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":434 + * @property + * def xyz(self) -> Tuple[float, float, float]: + * return self.x, self.y, self.z # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1)) __PYX_ERR(0, 434, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_2)) __PYX_ERR(0, 434, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_t_3)) __PYX_ERR(0, 434, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":432 + * return res + * + * @property # <<<<<<<<<<<<<< + * def xyz(self) -> Tuple[float, float, float]: + * return self.x, self.y, self.z + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.xyz.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":436 + * return self.x, self.y, self.z + * + * @property # <<<<<<<<<<<<<< + * def vec2(self) -> Vec2: + * cdef Vec2 res = Vec2() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_4vec2_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_4vec2_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_4vec2___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_4vec2___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *__pyx_v_res = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":438 + * @property + * def vec2(self) -> Vec2: + * cdef Vec2 res = Vec2() # <<<<<<<<<<<<<< + * res.x = self.x + * res.y = self.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 438, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":439 + * def vec2(self) -> Vec2: + * cdef Vec2 res = Vec2() + * res.x = self.x # <<<<<<<<<<<<<< + * res.y = self.y + * return res + */ + __pyx_t_2 = __pyx_v_self->x; + __pyx_v_res->x = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":440 + * cdef Vec2 res = Vec2() + * res.x = self.x + * res.y = self.y # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_t_2 = __pyx_v_self->y; + __pyx_v_res->y = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":441 + * res.x = self.x + * res.y = self.y + * return res # <<<<<<<<<<<<<< + * + * def replace(self, x: float = None, y: float = None, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = ((PyObject *)__pyx_v_res); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":436 + * return self.x, self.y, self.z + * + * @property # <<<<<<<<<<<<<< + * def vec2(self) -> Vec2: + * cdef Vec2 res = Vec2() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.vec2.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":443 + * return res + * + * def replace(self, x: float = None, y: float = None, # <<<<<<<<<<<<<< + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5replace(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_5replace = {"replace", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5replace, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5replace(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_y = 0; + PyObject *__pyx_v_z = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("replace (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_z,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject*)Py_None)); + values[1] = __Pyx_Arg_NewRef_FASTCALL(((PyObject*)Py_None)); + + /* "ezdxf/acc/vector.pyx":444 + * + * def replace(self, x: float = None, y: float = None, + * z: float = None) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = self.x if x is None else x + */ + values[2] = __Pyx_Arg_NewRef_FASTCALL(((PyObject*)Py_None)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_x); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 443, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_y); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 443, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_z); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 443, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "replace") < 0)) __PYX_ERR(0, 443, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_x = ((PyObject*)values[0]); + __pyx_v_y = ((PyObject*)values[1]); + __pyx_v_z = ((PyObject*)values[2]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("replace", 0, 0, 3, __pyx_nargs); __PYX_ERR(0, 443, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.replace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), (&PyFloat_Type), 1, "x", 1))) __PYX_ERR(0, 443, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), (&PyFloat_Type), 1, "y", 1))) __PYX_ERR(0, 443, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_z), (&PyFloat_Type), 1, "z", 1))) __PYX_ERR(0, 444, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_4replace(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_x, __pyx_v_y, __pyx_v_z); + + /* "ezdxf/acc/vector.pyx":443 + * return res + * + * def replace(self, x: float = None, y: float = None, # <<<<<<<<<<<<<< + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_4replace(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_z) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_t_3; + double __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("replace", 1); + + /* "ezdxf/acc/vector.pyx":445 + * def replace(self, x: float = None, y: float = None, + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = self.x if x is None else x + * res.y = self.y if y is None else y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 445, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":446 + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + * res.x = self.x if x is None else x # <<<<<<<<<<<<<< + * res.y = self.y if y is None else y + * res.z = self.z if z is None else z + */ + __pyx_t_3 = (__pyx_v_x == ((PyObject*)Py_None)); + if (__pyx_t_3) { + __pyx_t_2 = __pyx_v_self->x; + } else { + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_x); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 446, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + } + __pyx_v_res->x = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":447 + * cdef Vec3 res = Vec3() + * res.x = self.x if x is None else x + * res.y = self.y if y is None else y # <<<<<<<<<<<<<< + * res.z = self.z if z is None else z + * return res + */ + __pyx_t_3 = (__pyx_v_y == ((PyObject*)Py_None)); + if (__pyx_t_3) { + __pyx_t_2 = __pyx_v_self->y; + } else { + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_y); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 447, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + } + __pyx_v_res->y = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":448 + * res.x = self.x if x is None else x + * res.y = self.y if y is None else y + * res.z = self.z if z is None else z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_t_3 = (__pyx_v_z == ((PyObject*)Py_None)); + if (__pyx_t_3) { + __pyx_t_2 = __pyx_v_self->z; + } else { + __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_z); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 448, __pyx_L1_error) + __pyx_t_2 = __pyx_t_4; + } + __pyx_v_res->z = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":449 + * res.y = self.y if y is None else y + * res.z = self.z if z is None else z + * return res # <<<<<<<<<<<<<< + * + * def round(self, ndigits: int | None = None) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":443 + * return res + * + * def replace(self, x: float = None, y: float = None, # <<<<<<<<<<<<<< + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.replace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":451 + * return res + * + * def round(self, ndigits: int | None = None) -> Vec3: # <<<<<<<<<<<<<< + * return Vec3( + * round(self.x, ndigits), + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7round(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_7round = {"round", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7round, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7round(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ndigits = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("round (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ndigits,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_None)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ndigits); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 451, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "round") < 0)) __PYX_ERR(0, 451, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ndigits = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("round", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 451, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.round", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_6round(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_ndigits); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_6round(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_ndigits) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("round", 1); + + /* "ezdxf/acc/vector.pyx":452 + * + * def round(self, ndigits: int | None = None) -> Vec3: + * return Vec3( # <<<<<<<<<<<<<< + * round(self.x, ndigits), + * round(self.y, ndigits), + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + + /* "ezdxf/acc/vector.pyx":453 + * def round(self, ndigits: int | None = None) -> Vec3: + * return Vec3( + * round(self.x, ndigits), # <<<<<<<<<<<<<< + * round(self.y, ndigits), + * round(self.z, ndigits), + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 453, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 453, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 453, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ndigits); + __Pyx_GIVEREF(__pyx_v_ndigits); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_ndigits)) __PYX_ERR(0, 453, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_round, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 453, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":454 + * return Vec3( + * round(self.x, ndigits), + * round(self.y, ndigits), # <<<<<<<<<<<<<< + * round(self.z, ndigits), + * ) + */ + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 454, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 454, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(0, 454, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ndigits); + __Pyx_GIVEREF(__pyx_v_ndigits); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_ndigits)) __PYX_ERR(0, 454, __pyx_L1_error); + __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_round, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 454, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":455 + * round(self.x, ndigits), + * round(self.y, ndigits), + * round(self.z, ndigits), # <<<<<<<<<<<<<< + * ) + * + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3)) __PYX_ERR(0, 455, __pyx_L1_error); + __Pyx_INCREF(__pyx_v_ndigits); + __Pyx_GIVEREF(__pyx_v_ndigits); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_v_ndigits)) __PYX_ERR(0, 455, __pyx_L1_error); + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_round, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":452 + * + * def round(self, ndigits: int | None = None) -> Vec3: + * return Vec3( # <<<<<<<<<<<<<< + * round(self.x, ndigits), + * round(self.y, ndigits), + */ + __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 452, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1)) __PYX_ERR(0, 452, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_2)) __PYX_ERR(0, 452, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_t_3)) __PYX_ERR(0, 452, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 452, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3); + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":451 + * return res + * + * def round(self, ndigits: int | None = None) -> Vec3: # <<<<<<<<<<<<<< + * return Vec3( + * round(self.x, ndigits), + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.round", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":458 + * ) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec3]: + * return list(Vec3.generate(items)) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9list(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_9list = {"list", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9list, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9list(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("list (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 458, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "list") < 0)) __PYX_ERR(0, 458, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("list", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 458, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.list", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_8list(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_8list(PyObject *__pyx_v_items) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("list", 1); + + /* "ezdxf/acc/vector.pyx":460 + * @staticmethod + * def list(items: Iterable[UVec]) -> List[Vec3]: + * return list(Vec3.generate(items)) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_n_s_generate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 460, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_items}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 460, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_ListKeepNew(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 460, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":458 + * ) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec3]: + * return list(Vec3.generate(items)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.list", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":462 + * return list(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + * return tuple(Vec3.generate(items)) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_11tuple(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_11tuple = {"tuple", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_11tuple, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_11tuple(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("tuple (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 462, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "tuple") < 0)) __PYX_ERR(0, 462, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("tuple", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 462, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.tuple", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_10tuple(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_10tuple(PyObject *__pyx_v_items) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("tuple", 1); + + /* "ezdxf/acc/vector.pyx":464 + * @staticmethod + * def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + * return tuple(Vec3.generate(items)) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_n_s_generate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 464, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_items}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 1+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 464, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 464, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":462 + * return list(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + * return tuple(Vec3.generate(items)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.tuple", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":466 + * return tuple(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13generate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_13generate = {"generate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13generate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13generate(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("generate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 466, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "generate") < 0)) __PYX_ERR(0, 466, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("generate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 466, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.generate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_12generate(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec3_8generate_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/vector.pyx":468 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_8generate_genexpr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_genexpr_arg_0) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("genexpr", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 468, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_genexpr_arg_0 = __pyx_genexpr_arg_0; + __Pyx_INCREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + __Pyx_GIVEREF(__pyx_cur_scope->__pyx_genexpr_arg_0); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_6vector_4Vec3_8generate_2generator3, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_generate_locals_genexpr, __pyx_n_s_ezdxf_acc_vector); if (unlikely(!gen)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.generate.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec3_8generate_2generator3(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("genexpr", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 468, __pyx_L1_error) + if (unlikely(!__pyx_cur_scope->__pyx_genexpr_arg_0)) { __Pyx_RaiseUnboundLocalError(".0"); __PYX_ERR(0, 468, __pyx_L1_error) } + if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_genexpr_arg_0)) { + __pyx_t_1 = __pyx_cur_scope->__pyx_genexpr_arg_0; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_genexpr_arg_0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 468, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 468, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 468, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 468, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 468, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 468, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_item); + __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_item, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_cur_scope->__pyx_v_item); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + __Pyx_XGIVEREF(__pyx_t_1); + __pyx_cur_scope->__pyx_t_0 = __pyx_t_1; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_2; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_3; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L6_resume_from_yield:; + __pyx_t_1 = __pyx_cur_scope->__pyx_t_0; + __pyx_cur_scope->__pyx_t_0 = 0; + __Pyx_XGOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_3 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 468, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":466 + * return tuple(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) + */ + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_12generate(PyObject *__pyx_v_items) { + PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec3_8generate_2generator3 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("generate", 1); + + /* "ezdxf/acc/vector.pyx":468 + * @staticmethod + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_8generate_genexpr(NULL, __pyx_v_items); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":466 + * return tuple(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.generate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_gb_5ezdxf_3acc_6vector_4Vec3_8generate_2generator3); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":470 + * return (Vec3(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle, length) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_15from_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_15from_angle = {"from_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_15from_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_15from_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("from_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 470, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 470, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "from_angle") < 0)) __PYX_ERR(0, 470, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 471, __pyx_L3_error) + if (values[1]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 471, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("from_angle", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 470, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_14from_angle(__pyx_v_angle, __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_14from_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("from_angle", 1); + + /* "ezdxf/acc/vector.pyx":472 + * @staticmethod + * def from_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle, length) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_from_angle(__pyx_v_angle, __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 472, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":470 + * return (Vec3(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle, length) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":474 + * return v3_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle * DEG2RAD, length) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle = {"from_deg_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("from_deg_angle (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 474, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 474, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "from_deg_angle") < 0)) __PYX_ERR(0, 474, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 475, __pyx_L3_error) + if (values[1]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 475, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("from_deg_angle", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 474, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.from_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_16from_deg_angle(__pyx_v_angle, __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_16from_deg_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("from_deg_angle", 1); + + /* "ezdxf/acc/vector.pyx":476 + * @staticmethod + * def from_deg_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle * DEG2RAD, length) # <<<<<<<<<<<<<< + * + * @staticmethod + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_from_angle((__pyx_v_angle * __pyx_v_5ezdxf_3acc_6vector_DEG2RAD), __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 476, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":474 + * return v3_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle * DEG2RAD, length) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.from_deg_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":478 + * return v3_from_angle(angle * DEG2RAD, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_19random(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_19random = {"random", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_19random, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_19random(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("random (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 478, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "random") < 0)) __PYX_ERR(0, 478, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + if (values[0]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 479, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.0); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("random", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 478, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.random", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_18random(__pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_18random(double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + PyObject *__pyx_v_uniform = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("random", 1); + + /* "ezdxf/acc/vector.pyx":480 + * @staticmethod + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * uniform = random.uniform + * res.x = uniform(-1, 1) + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 480, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":481 + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() + * uniform = random.uniform # <<<<<<<<<<<<<< + * res.x = uniform(-1, 1) + * res.y = uniform(-1, 1) + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_random); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_uniform); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_uniform = __pyx_t_2; + __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":482 + * cdef Vec3 res = Vec3() + * uniform = random.uniform + * res.x = uniform(-1, 1) # <<<<<<<<<<<<<< + * res.y = uniform(-1, 1) + * res.z = uniform(-1, 1) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_v_uniform, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_res->x = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":483 + * uniform = random.uniform + * res.x = uniform(-1, 1) + * res.y = uniform(-1, 1) # <<<<<<<<<<<<<< + * res.z = uniform(-1, 1) + * return v3_normalize(res, length) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_v_uniform, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 483, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 483, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_res->y = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":484 + * res.x = uniform(-1, 1) + * res.y = uniform(-1, 1) + * res.z = uniform(-1, 1) # <<<<<<<<<<<<<< + * return v3_normalize(res, length) + * + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_v_uniform, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_res->z = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":485 + * res.y = uniform(-1, 1) + * res.z = uniform(-1, 1) + * return v3_normalize(res, length) # <<<<<<<<<<<<<< + * + * def __str__(self) -> str: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_res, __pyx_v_length)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":478 + * return v3_from_angle(angle * DEG2RAD, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.random", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XDECREF(__pyx_v_uniform); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":487 + * return v3_normalize(res, length) + * + * def __str__(self) -> str: # <<<<<<<<<<<<<< + * return f'({self.x}, {self.y}, {self.z})' + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_21__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_21__str__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_20__str__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_20__str__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + Py_UCS4 __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 1); + + /* "ezdxf/acc/vector.pyx":488 + * + * def __str__(self) -> str: + * return f'({self.x}, {self.y}, {self.z})' # <<<<<<<<<<<<<< + * + * def __repr__(self)-> str: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyTuple_New(7); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = 127; + __Pyx_INCREF(__pyx_kp_u__2); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__2); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_kp_u__2); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_FormatSimple(__pyx_t_4, __pyx_empty_unicode); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) > __pyx_t_3) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) : __pyx_t_3; + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_kp_u__3); + __pyx_t_2 += 2; + __Pyx_GIVEREF(__pyx_kp_u__3); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_kp_u__3); + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_t_5, __pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4) > __pyx_t_3) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4) : __pyx_t_3; + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_t_4); + __pyx_t_4 = 0; + __Pyx_INCREF(__pyx_kp_u__3); + __pyx_t_2 += 2; + __Pyx_GIVEREF(__pyx_kp_u__3); + PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_kp_u__3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_FormatSimple(__pyx_t_4, __pyx_empty_unicode); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) > __pyx_t_3) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) : __pyx_t_3; + __pyx_t_2 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_t_5); + __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_kp_u__4); + __pyx_t_2 += 1; + __Pyx_GIVEREF(__pyx_kp_u__4); + PyTuple_SET_ITEM(__pyx_t_1, 6, __pyx_kp_u__4); + __pyx_t_5 = __Pyx_PyUnicode_Join(__pyx_t_1, 7, __pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 488, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":487 + * return v3_normalize(res, length) + * + * def __str__(self) -> str: # <<<<<<<<<<<<<< + * return f'({self.x}, {self.y}, {self.z})' + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":490 + * return f'({self.x}, {self.y}, {self.z})' + * + * def __repr__(self)-> str: # <<<<<<<<<<<<<< + * return "Vec3" + self.__str__() + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_22__repr__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_22__repr__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + unsigned int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 1); + + /* "ezdxf/acc/vector.pyx":491 + * + * def __repr__(self)-> str: + * return "Vec3" + self.__str__() # <<<<<<<<<<<<<< + * + * def __len__(self) -> int: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_str); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_4, 0+__pyx_t_4); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __pyx_t_2 = PyNumber_Add(__pyx_n_u_Vec3, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":490 + * return f'({self.x}, {self.y}, {self.z})' + * + * def __repr__(self)-> str: # <<<<<<<<<<<<<< + * return "Vec3" + self.__str__() + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":493 + * return "Vec3" + self.__str__() + * + * def __len__(self) -> int: # <<<<<<<<<<<<<< + * return 3 + * + */ + +/* Python wrapper */ +static Py_ssize_t __pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__(PyObject *__pyx_v_self); /*proto*/ +static Py_ssize_t __pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_ssize_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__len__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_24__len__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_ssize_t __pyx_pf_5ezdxf_3acc_6vector_4Vec3_24__len__(CYTHON_UNUSED struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + Py_ssize_t __pyx_r; + + /* "ezdxf/acc/vector.pyx":494 + * + * def __len__(self) -> int: + * return 3 # <<<<<<<<<<<<<< + * + * def __hash__(self) -> int: + */ + __pyx_r = 3; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":493 + * return "Vec3" + self.__str__() + * + * def __len__(self) -> int: # <<<<<<<<<<<<<< + * return 3 + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":496 + * return 3 + * + * def __hash__(self) -> int: # <<<<<<<<<<<<<< + * return hash(self.xyz) + * + */ + +/* Python wrapper */ +static Py_hash_t __pyx_pw_5ezdxf_3acc_6vector_4Vec3_27__hash__(PyObject *__pyx_v_self); /*proto*/ +static Py_hash_t __pyx_pw_5ezdxf_3acc_6vector_4Vec3_27__hash__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + Py_hash_t __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__hash__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_26__hash__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static Py_hash_t __pyx_pf_5ezdxf_3acc_6vector_4Vec3_26__hash__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + Py_hash_t __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_hash_t __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__hash__", 1); + + /* "ezdxf/acc/vector.pyx":497 + * + * def __hash__(self) -> int: + * return hash(self.xyz) # <<<<<<<<<<<<<< + * + * def copy(self) -> Vec3: + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_xyz); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyObject_Hash(__pyx_t_1); if (unlikely(__pyx_t_2 == ((Py_hash_t)-1))) __PYX_ERR(0, 497, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":496 + * return 3 + * + * def __hash__(self) -> int: # <<<<<<<<<<<<<< + * return hash(self.xyz) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__hash__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + if (unlikely(__pyx_r == -1) && !PyErr_Occurred()) __pyx_r = -2; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":499 + * return hash(self.xyz) + * + * def copy(self) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_29copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_29copy = {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_29copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_29copy(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("copy", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "copy", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_28copy(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_28copy(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("copy", 1); + + /* "ezdxf/acc/vector.pyx":500 + * + * def copy(self) -> Vec3: + * return self # immutable # <<<<<<<<<<<<<< + * + * __copy__ = copy + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = __pyx_v_self; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":499 + * return hash(self.xyz) + * + * def copy(self) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":504 + * __copy__ = copy + * + * def __deepcopy__(self, memodict: dict) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable! + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__ = {"__deepcopy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + CYTHON_UNUSED PyObject *__pyx_v_memodict = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__deepcopy__ (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_memodict,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_memodict)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 504, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "__deepcopy__") < 0)) __PYX_ERR(0, 504, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_memodict = ((PyObject*)values[0]); + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__deepcopy__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 504, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__deepcopy__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_memodict), (&PyDict_Type), 0, "memodict", 1))) __PYX_ERR(0, 504, __pyx_L1_error) + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_30__deepcopy__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_memodict); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_30__deepcopy__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_memodict) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__deepcopy__", 1); + + /* "ezdxf/acc/vector.pyx":505 + * + * def __deepcopy__(self, memodict: dict) -> Vec3: + * return self # immutable! # <<<<<<<<<<<<<< + * + * def __getitem__(self, int index) -> float: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_self); + __pyx_r = __pyx_v_self; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":504 + * __copy__ = copy + * + * def __deepcopy__(self, memodict: dict) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable! + * + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":507 + * return self # immutable! + * + * def __getitem__(self, int index) -> float: # <<<<<<<<<<<<<< + * if index == 0: + * return self.x + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_33__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_33__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index) { + int __pyx_v_index; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_index); { + __pyx_v_index = __Pyx_PyInt_As_int(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 507, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_32__getitem__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), ((int)__pyx_v_index)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_32__getitem__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, int __pyx_v_index) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 1); + + /* "ezdxf/acc/vector.pyx":508 + * + * def __getitem__(self, int index) -> float: + * if index == 0: # <<<<<<<<<<<<<< + * return self.x + * elif index == 1: + */ + switch (__pyx_v_index) { + case 0: + + /* "ezdxf/acc/vector.pyx":509 + * def __getitem__(self, int index) -> float: + * if index == 0: + * return self.x # <<<<<<<<<<<<<< + * elif index == 1: + * return self.y + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 509, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":508 + * + * def __getitem__(self, int index) -> float: + * if index == 0: # <<<<<<<<<<<<<< + * return self.x + * elif index == 1: + */ + break; + case 1: + + /* "ezdxf/acc/vector.pyx":511 + * return self.x + * elif index == 1: + * return self.y # <<<<<<<<<<<<<< + * elif index == 2: + * return self.z + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":510 + * if index == 0: + * return self.x + * elif index == 1: # <<<<<<<<<<<<<< + * return self.y + * elif index == 2: + */ + break; + case 2: + + /* "ezdxf/acc/vector.pyx":513 + * return self.y + * elif index == 2: + * return self.z # <<<<<<<<<<<<<< + * else: + * raise IndexError(f'invalid index {index}') + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":512 + * elif index == 1: + * return self.y + * elif index == 2: # <<<<<<<<<<<<<< + * return self.z + * else: + */ + break; + default: + + /* "ezdxf/acc/vector.pyx":515 + * return self.z + * else: + * raise IndexError(f'invalid index {index}') # <<<<<<<<<<<<<< + * + * def __iter__(self) -> Iterator[float]: + */ + __pyx_t_1 = __Pyx_PyUnicode_From_int(__pyx_v_index, 0, ' ', 'd'); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 515, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyUnicode_Concat(__pyx_kp_u_invalid_index, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 515, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_IndexError, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 515, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 515, __pyx_L1_error) + break; + } + + /* "ezdxf/acc/vector.pyx":507 + * return self # immutable! + * + * def __getitem__(self, int index) -> float: # <<<<<<<<<<<<<< + * if index == 0: + * return self.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec3_36generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "ezdxf/acc/vector.pyx":517 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_35__iter__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_35__iter__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_34__iter__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_34__iter__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__iter__", 0); + __pyx_cur_scope = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__, __pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 517, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_self = __pyx_v_self; + __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self); + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_5ezdxf_3acc_6vector_4Vec3_36generator1, NULL, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_Vec3___iter, __pyx_n_s_ezdxf_acc_vector); if (unlikely(!gen)) __PYX_ERR(0, 517, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_5ezdxf_3acc_6vector_4Vec3_36generator1(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L4_resume_from_yield; + case 2: goto __pyx_L5_resume_from_yield; + case 3: goto __pyx_L6_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 517, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":518 + * + * def __iter__(self) -> Iterator[float]: + * yield self.x # <<<<<<<<<<<<<< + * yield self.y + * yield self.z + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 518, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L4_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 518, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":519 + * def __iter__(self) -> Iterator[float]: + * yield self.x + * yield self.y # <<<<<<<<<<<<<< + * yield self.z + * + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 519, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 2; + return __pyx_r; + __pyx_L5_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 519, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":520 + * yield self.x + * yield self.y + * yield self.z # <<<<<<<<<<<<<< + * + * def __abs__(self) -> float: + */ + __pyx_t_1 = PyFloat_FromDouble(__pyx_cur_scope->__pyx_v_self->z); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 520, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 3; + return __pyx_r; + __pyx_L6_resume_from_yield:; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 520, __pyx_L1_error) + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "ezdxf/acc/vector.pyx":517 + * raise IndexError(f'invalid index {index}') + * + * def __iter__(self) -> Iterator[float]: # <<<<<<<<<<<<<< + * yield self.x + * yield self.y + */ + + /* function exit code */ + PyErr_SetNone(PyExc_StopIteration); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_L0:; + __Pyx_XDECREF(__pyx_r); __pyx_r = 0; + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":522 + * yield self.z + * + * def __abs__(self) -> float: # <<<<<<<<<<<<<< + * return v3_magnitude(self) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_38__abs__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_38__abs__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__abs__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_37__abs__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_37__abs__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__abs__", 1); + + /* "ezdxf/acc/vector.pyx":523 + * + * def __abs__(self) -> float: + * return v3_magnitude(self) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(__pyx_v_self); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 523, __pyx_L1_error) + __pyx_t_2 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 523, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":522 + * yield self.z + * + * def __abs__(self) -> float: # <<<<<<<<<<<<<< + * return v3_magnitude(self) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__abs__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":525 + * return v3_magnitude(self) + * + * @property # <<<<<<<<<<<<<< + * def magnitude(self) -> float: + * return v3_magnitude(self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9magnitude_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9magnitude_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_9magnitude___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_9magnitude___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":527 + * @property + * def magnitude(self) -> float: + * return v3_magnitude(self) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(__pyx_v_self); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 527, __pyx_L1_error) + __pyx_t_2 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 527, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":525 + * return v3_magnitude(self) + * + * @property # <<<<<<<<<<<<<< + * def magnitude(self) -> float: + * return v3_magnitude(self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.magnitude.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":529 + * return v3_magnitude(self) + * + * @property # <<<<<<<<<<<<<< + * def magnitude_xy(self) -> float: + * return hypot(self.x, self.y) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":531 + * @property + * def magnitude_xy(self) -> float: + * return hypot(self.x, self.y) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(hypot(__pyx_v_self->x, __pyx_v_self->y)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 531, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":529 + * return v3_magnitude(self) + * + * @property # <<<<<<<<<<<<<< + * def magnitude_xy(self) -> float: + * return hypot(self.x, self.y) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.magnitude_xy.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":533 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def magnitude_square(self) -> float: + * return v3_magnitude_sqr(self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_16magnitude_square_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_16magnitude_square_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_16magnitude_square___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_16magnitude_square___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":535 + * @property + * def magnitude_square(self) -> float: + * return v3_magnitude_sqr(self) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr(__pyx_v_self); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 535, __pyx_L1_error) + __pyx_t_2 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 535, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":533 + * return hypot(self.x, self.y) + * + * @property # <<<<<<<<<<<<<< + * def magnitude_square(self) -> float: + * return v3_magnitude_sqr(self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.magnitude_square.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":537 + * return v3_magnitude_sqr(self) + * + * @property # <<<<<<<<<<<<<< + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL and \ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7is_null_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7is_null_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_7is_null___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_7is_null___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":539 + * @property + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL and \ # <<<<<<<<<<<<<< + * fabs(self.z) <= ABS_TOL + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = (fabs(__pyx_v_self->x) <= ABS_TOL); + if (__pyx_t_2) { + } else { + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L3_bool_binop_done; + } + __pyx_t_2 = (fabs(__pyx_v_self->y) <= ABS_TOL); + if (__pyx_t_2) { + } else { + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":540 + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL and \ + * fabs(self.z) <= ABS_TOL # <<<<<<<<<<<<<< + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, + */ + __pyx_t_2 = (fabs(__pyx_v_self->z) <= ABS_TOL); + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 540, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":537 + * return v3_magnitude_sqr(self) + * + * @property # <<<<<<<<<<<<<< + * def is_null(self) -> bool: + * return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL and \ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.is_null.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_40is_parallel(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_40is_parallel = {"is_parallel", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_40is_parallel, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_40is_parallel(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + double __pyx_v_rel_tol; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("is_parallel (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,&__pyx_n_s_rel_tol,&__pyx_n_s_abs_tol,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 542, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (kw_args > 0 && likely(kw_args <= 2)) { + Py_ssize_t index; + for (index = 1; index < 3 && kw_args > 0; index++) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, *__pyx_pyargnames[index]); + if (value) { values[index] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 542, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "is_parallel") < 0)) __PYX_ERR(0, 542, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + if (values[1]) { + __pyx_v_rel_tol = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_rel_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 542, __pyx_L3_error) + } else { + __pyx_v_rel_tol = __pyx_k__8; + } + if (values[2]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 543, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_k__9; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("is_parallel", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 542, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.is_parallel", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_39is_parallel(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other, __pyx_v_rel_tol, __pyx_v_abs_tol); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_39is_parallel(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v1 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_v2 = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_neg_v2 = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("is_parallel", 1); + + /* "ezdxf/acc/vector.pyx":544 + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) # <<<<<<<<<<<<<< + * cdef Vec3 v1 = v3_normalize(self, 1.0) + * cdef Vec3 v2 = v3_normalize(o, 1.0) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 544, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":545 + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + * cdef Vec3 v1 = v3_normalize(self, 1.0) # <<<<<<<<<<<<<< + * cdef Vec3 v2 = v3_normalize(o, 1.0) + * cdef Vec3 neg_v2 = v3_reverse(v2) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_self, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 545, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v1 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":546 + * cdef Vec3 o = Vec3(other) + * cdef Vec3 v1 = v3_normalize(self, 1.0) + * cdef Vec3 v2 = v3_normalize(o, 1.0) # <<<<<<<<<<<<<< + * cdef Vec3 neg_v2 = v3_reverse(v2) + * return v3_isclose(v1, v2, rel_tol, abs_tol) or \ + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_o, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 546, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_v2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":547 + * cdef Vec3 v1 = v3_normalize(self, 1.0) + * cdef Vec3 v2 = v3_normalize(o, 1.0) + * cdef Vec3 neg_v2 = v3_reverse(v2) # <<<<<<<<<<<<<< + * return v3_isclose(v1, v2, rel_tol, abs_tol) or \ + * v3_isclose(v1, neg_v2, rel_tol, abs_tol) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_reverse(__pyx_v_v2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 547, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_neg_v2 = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":548 + * cdef Vec3 v2 = v3_normalize(o, 1.0) + * cdef Vec3 neg_v2 = v3_reverse(v2) + * return v3_isclose(v1, v2, rel_tol, abs_tol) or \ # <<<<<<<<<<<<<< + * v3_isclose(v1, neg_v2, rel_tol, abs_tol) + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_v_v1, __pyx_v_v2, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 548, __pyx_L1_error) + if (!__pyx_t_2) { + } else { + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 548, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":549 + * cdef Vec3 neg_v2 = v3_reverse(v2) + * return v3_isclose(v1, v2, rel_tol, abs_tol) or \ + * v3_isclose(v1, neg_v2, rel_tol, abs_tol) # <<<<<<<<<<<<<< + * + * @property + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_v_v1, __pyx_v_neg_v2, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 549, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 549, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.is_parallel", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XDECREF((PyObject *)__pyx_v_v1); + __Pyx_XDECREF((PyObject *)__pyx_v_v2); + __Pyx_XDECREF((PyObject *)__pyx_v_neg_v2); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":551 + * v3_isclose(v1, neg_v2, rel_tol, abs_tol) + * + * @property # <<<<<<<<<<<<<< + * def spatial_angle(self) -> float: + * return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13spatial_angle_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13spatial_angle_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_13spatial_angle___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_13spatial_angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":553 + * @property + * def spatial_angle(self) -> float: + * return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_X_AXIS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 553, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_self, 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 553, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 553, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(acos(__pyx_t_3)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 553, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":551 + * v3_isclose(v1, neg_v2, rel_tol, abs_tol) + * + * @property # <<<<<<<<<<<<<< + * def spatial_angle(self) -> float: + * return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.spatial_angle.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":555 + * return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) + * + * @property # <<<<<<<<<<<<<< + * def spatial_angle_deg(self) -> float: + * return self.spatial_angle * RAD2DEG + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":557 + * @property + * def spatial_angle_deg(self) -> float: + * return self.spatial_angle * RAD2DEG # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_spatial_angle); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_5ezdxf_3acc_6vector_RAD2DEG); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_Multiply(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":555 + * return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) + * + * @property # <<<<<<<<<<<<<< + * def spatial_angle_deg(self) -> float: + * return self.spatial_angle * RAD2DEG + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.spatial_angle_deg.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":559 + * return self.spatial_angle * RAD2DEG + * + * @property # <<<<<<<<<<<<<< + * def angle(self) -> float: + * return atan2(self.y, self.x) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5angle_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5angle_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_5angle___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_5angle___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":561 + * @property + * def angle(self) -> float: + * return atan2(self.y, self.x) # <<<<<<<<<<<<<< + * + * @property + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(atan2(__pyx_v_self->y, __pyx_v_self->x)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 561, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":559 + * return self.spatial_angle * RAD2DEG + * + * @property # <<<<<<<<<<<<<< + * def angle(self) -> float: + * return atan2(self.y, self.x) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":563 + * return atan2(self.y, self.x) + * + * @property # <<<<<<<<<<<<<< + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9angle_deg_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9angle_deg_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_9angle_deg___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_9angle_deg___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + + /* "ezdxf/acc/vector.pyx":565 + * @property + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG # <<<<<<<<<<<<<< + * + * def orthogonal(self, ccw: bool = True) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble((atan2(__pyx_v_self->y, __pyx_v_self->x) * __pyx_v_5ezdxf_3acc_6vector_RAD2DEG)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 565, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":563 + * return atan2(self.y, self.x) + * + * @property # <<<<<<<<<<<<<< + * def angle_deg(self) -> float: + * return atan2(self.y, self.x) * RAD2DEG + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle_deg.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":567 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec3: # <<<<<<<<<<<<<< + * return v3_ortho(self, ccw) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_42orthogonal(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_42orthogonal = {"orthogonal", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_42orthogonal, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_42orthogonal(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_ccw = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("orthogonal (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ccw,0}; + values[0] = __Pyx_Arg_NewRef_FASTCALL(((PyObject *)Py_True)); + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_ccw); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 567, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "orthogonal") < 0)) __PYX_ERR(0, 567, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ccw = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("orthogonal", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 567, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.orthogonal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_41orthogonal(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_ccw); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_41orthogonal(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_ccw) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("orthogonal", 1); + + /* "ezdxf/acc/vector.pyx":568 + * + * def orthogonal(self, ccw: bool = True) -> Vec3: + * return v3_ortho(self, ccw) # <<<<<<<<<<<<<< + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_ccw); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 568, __pyx_L1_error) + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_ortho(__pyx_v_self, __pyx_t_1)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 568, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":567 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec3: # <<<<<<<<<<<<<< + * return v3_ortho(self, ccw) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.orthogonal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":570 + * return v3_ortho(self, ccw) + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_44lerp(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_44lerp = {"lerp", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_44lerp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_44lerp(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + double __pyx_v_factor; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("lerp (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,&__pyx_n_s_factor,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 570, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_factor); + if (value) { values[1] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 570, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lerp") < 0)) __PYX_ERR(0, 570, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_other = values[0]; + if (values[1]) { + __pyx_v_factor = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 570, __pyx_L3_error) + } else { + __pyx_v_factor = ((double)0.5); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("lerp", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 570, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_43lerp(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other, __pyx_v_factor); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_43lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("lerp", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":571 + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_lerp(self, other, factor) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":572 + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return v3_lerp(self, other, factor) + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 572, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":571 + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_lerp(self, other, factor) + */ + } + + /* "ezdxf/acc/vector.pyx":573 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return v3_lerp(self, other, factor) # <<<<<<<<<<<<<< + * + * def project(self, other: UVec) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_lerp(__pyx_v_self, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other), __pyx_v_factor)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 573, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3); + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":570 + * return v3_ortho(self, ccw) + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":575 + * return v3_lerp(self, other, factor) + * + * def project(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_46project(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_46project = {"project", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_46project, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_46project(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("project (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 575, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "project") < 0)) __PYX_ERR(0, 575, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("project", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 575, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_45project(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_45project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("project", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":576 + * + * def project(self, other: UVec) -> Vec3: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_project(self, other) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":577 + * def project(self, other: UVec) -> Vec3: + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return v3_project(self, other) + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 577, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":576 + * + * def project(self, other: UVec) -> Vec3: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_project(self, other) + */ + } + + /* "ezdxf/acc/vector.pyx":578 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return v3_project(self, other) # <<<<<<<<<<<<<< + * + * def normalize(self, double length = 1.) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_project(__pyx_v_self, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 578, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3); + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":575 + * return v3_lerp(self, other, factor) + * + * def project(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":580 + * return v3_project(self, other) + * + * def normalize(self, double length = 1.) -> Vec3: # <<<<<<<<<<<<<< + * return v3_normalize(self, length) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_48normalize(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_48normalize = {"normalize", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_48normalize, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_48normalize(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_length; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("normalize (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_length,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_length); + if (value) { values[0] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 580, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "normalize") < 0)) __PYX_ERR(0, 580, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + if (values[0]) { + __pyx_v_length = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_length == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 580, __pyx_L3_error) + } else { + __pyx_v_length = ((double)1.); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("normalize", 0, 0, 1, __pyx_nargs); __PYX_ERR(0, 580, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_47normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_length); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_47normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("normalize", 1); + + /* "ezdxf/acc/vector.pyx":581 + * + * def normalize(self, double length = 1.) -> Vec3: + * return v3_normalize(self, length) # <<<<<<<<<<<<<< + * + * def reversed(self) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_self, __pyx_v_length)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":580 + * return v3_project(self, other) + * + * def normalize(self, double length = 1.) -> Vec3: # <<<<<<<<<<<<<< + * return v3_normalize(self, length) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":583 + * return v3_normalize(self, length) + * + * def reversed(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_50reversed(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_50reversed = {"reversed", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_50reversed, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_50reversed(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("reversed (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + if (unlikely(__pyx_nargs > 0)) { + __Pyx_RaiseArgtupleInvalid("reversed", 1, 0, 0, __pyx_nargs); return NULL;} + if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "reversed", 0))) return NULL; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_49reversed(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_49reversed(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("reversed", 1); + + /* "ezdxf/acc/vector.pyx":584 + * + * def reversed(self) -> Vec3: + * return v3_reverse(self) # <<<<<<<<<<<<<< + * + * def __neg__(self) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_reverse(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":583 + * return v3_normalize(self, length) + * + * def reversed(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.reversed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":586 + * return v3_reverse(self) + * + * def __neg__(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_52__neg__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_52__neg__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__neg__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_51__neg__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_51__neg__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__neg__", 1); + + /* "ezdxf/acc/vector.pyx":587 + * + * def __neg__(self) -> Vec3: + * return v3_reverse(self) # <<<<<<<<<<<<<< + * + * def __bool__(self) -> bool: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_reverse(__pyx_v_self)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 587, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":586 + * return v3_reverse(self) + * + * def __neg__(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__neg__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":589 + * return v3_reverse(self) + * + * def __bool__(self) -> bool: # <<<<<<<<<<<<<< + * return not self.is_null + * + */ + +/* Python wrapper */ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec3_54__bool__(PyObject *__pyx_v_self); /*proto*/ +static int __pyx_pw_5ezdxf_3acc_6vector_4Vec3_54__bool__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__bool__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_53__bool__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5ezdxf_3acc_6vector_4Vec3_53__bool__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__bool__", 1); + + /* "ezdxf/acc/vector.pyx":590 + * + * def __bool__(self) -> bool: + * return not self.is_null # <<<<<<<<<<<<<< + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_is_null); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 590, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = (!__pyx_t_2); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":589 + * return v3_reverse(self) + * + * def __bool__(self) -> bool: # <<<<<<<<<<<<<< + * return not self.is_null + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__bool__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_56isclose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_56isclose = {"isclose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_56isclose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_56isclose(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + double __pyx_v_rel_tol; + double __pyx_v_abs_tol; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("isclose (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,&__pyx_n_s_rel_tol,&__pyx_n_s_abs_tol,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 592, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (kw_args > 0 && likely(kw_args <= 2)) { + Py_ssize_t index; + for (index = 1; index < 3 && kw_args > 0; index++) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, *__pyx_pyargnames[index]); + if (value) { values[index] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 592, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "isclose") < 0)) __PYX_ERR(0, 592, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + if (values[1]) { + __pyx_v_rel_tol = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_rel_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 592, __pyx_L3_error) + } else { + __pyx_v_rel_tol = __pyx_k__10; + } + if (values[2]) { + __pyx_v_abs_tol = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_abs_tol == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 593, __pyx_L3_error) + } else { + __pyx_v_abs_tol = __pyx_k__11; + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("isclose", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 592, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_55isclose(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other, __pyx_v_rel_tol, __pyx_v_abs_tol); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_55isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("isclose", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":594 + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_isclose(self, other, rel_tol, abs_tol) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":595 + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return v3_isclose(self, other, rel_tol, abs_tol) + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 595, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":594 + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_isclose(self, other, rel_tol, abs_tol) + */ + } + + /* "ezdxf/acc/vector.pyx":596 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return v3_isclose(self, other, rel_tol, abs_tol) # <<<<<<<<<<<<<< + * + * def __eq__(self, other: UVec) -> bool: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_isclose(__pyx_v_self, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other), __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 596, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":598 + * return v3_isclose(self, other, rel_tol, abs_tol) + * + * def __eq__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_58__eq__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_58__eq__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__eq__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_57__eq__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_57__eq__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__eq__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":599 + * + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return self.x == other.x and self.y == other.y and self.z == other.z + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":600 + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return self.x == other.x and self.y == other.y and self.z == other.z + * + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 600, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":599 + * + * def __eq__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return self.x == other.x and self.y == other.y and self.z == other.z + */ + } + + /* "ezdxf/acc/vector.pyx":601 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return self.x == other.x and self.y == other.y and self.z == other.z # <<<<<<<<<<<<<< + * + * def __lt__(self, other: UVec) -> bool: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_x); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 601, __pyx_L1_error) + if (__pyx_t_2) { + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __Pyx_INCREF(__pyx_t_6); + __pyx_t_3 = __pyx_t_6; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_y); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 601, __pyx_L1_error) + if (__pyx_t_2) { + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else { + __Pyx_INCREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_z); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 601, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_INCREF(__pyx_t_6); + __pyx_t_3 = __pyx_t_6; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_L4_bool_binop_done:; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":598 + * return v3_isclose(self, other, rel_tol, abs_tol) + * + * def __eq__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__eq__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":603 + * return self.x == other.x and self.y == other.y and self.z == other.z + * + * def __lt__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_60__lt__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_60__lt__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__lt__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_59__lt__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_59__lt__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__lt__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":604 + * + * def __lt__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * if self.x == ( other).x: + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":605 + * def __lt__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * if self.x == ( other).x: + * return self.y < ( other).y + */ + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 605, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_3); + __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":604 + * + * def __lt__(self, other: UVec) -> bool: + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * if self.x == ( other).x: + */ + } + + /* "ezdxf/acc/vector.pyx":606 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * if self.x == ( other).x: # <<<<<<<<<<<<<< + * return self.y < ( other).y + * else: + */ + __pyx_t_2 = (__pyx_v_self->x == ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other)->x); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":607 + * other = Vec3(other) + * if self.x == ( other).x: + * return self.y < ( other).y # <<<<<<<<<<<<<< + * else: + * return self.x < ( other).x + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyBool_FromLong((__pyx_v_self->y < ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other)->y)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 607, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":606 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * if self.x == ( other).x: # <<<<<<<<<<<<<< + * return self.y < ( other).y + * else: + */ + } + + /* "ezdxf/acc/vector.pyx":609 + * return self.y < ( other).y + * else: + * return self.x < ( other).x # <<<<<<<<<<<<<< + * + * # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyBool_FromLong((__pyx_v_self->x < ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other)->x)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 609, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + } + + /* "ezdxf/acc/vector.pyx":603 + * return self.x == other.x and self.y == other.y and self.z == other.z + * + * def __lt__(self, other: UVec) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__lt__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":612 + * + * # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + * def __add__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(self, Vec3): + * # other is the real self + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_62__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_62__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__add__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_61__add__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_61__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__add__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":613 + * # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + * def __add__(self, other) -> Vec3: + * if not isinstance(self, Vec3): # <<<<<<<<<<<<<< + * # other is the real self + * return v3_add(Vec3(self), other) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":615 + * if not isinstance(self, Vec3): + * # other is the real self + * return v3_add(Vec3(self), other) # <<<<<<<<<<<<<< + * + * if not isinstance(other, Vec3): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_self); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 615, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 615, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":613 + * # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + * def __add__(self, other) -> Vec3: + * if not isinstance(self, Vec3): # <<<<<<<<<<<<<< + * # other is the real self + * return v3_add(Vec3(self), other) + */ + } + + /* "ezdxf/acc/vector.pyx":617 + * return v3_add(Vec3(self), other) + * + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_add( self, other) + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_1 = (!__pyx_t_2); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":618 + * + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return v3_add( self, other) + * + */ + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 618, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":617 + * return v3_add(Vec3(self), other) + * + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_add( self, other) + */ + } + + /* "ezdxf/acc/vector.pyx":619 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return v3_add( self, other) # <<<<<<<<<<<<<< + * + * __radd__ = __add__ # Cython >= 3.0 + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_add(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 619, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":612 + * + * # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + * def __add__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(self, Vec3): + * # other is the real self + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__add__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":626 + * + * # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + * def __sub__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(self, Vec3): + * # other is the real self + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_64__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_64__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__sub__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_63__sub__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_63__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__sub__", 0); + __Pyx_INCREF(__pyx_v_other); + + /* "ezdxf/acc/vector.pyx":627 + * # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + * def __sub__(self, other) -> Vec3: + * if not isinstance(self, Vec3): # <<<<<<<<<<<<<< + * # other is the real self + * return v3_sub(Vec3(self), other) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_2 = (!__pyx_t_1); + if (__pyx_t_2) { + + /* "ezdxf/acc/vector.pyx":629 + * if not isinstance(self, Vec3): + * # other is the real self + * return v3_sub(Vec3(self), other) # <<<<<<<<<<<<<< + * + * if not isinstance(other, Vec3): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_self); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 629, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_3), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 629, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":627 + * # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + * def __sub__(self, other) -> Vec3: + * if not isinstance(self, Vec3): # <<<<<<<<<<<<<< + * # other is the real self + * return v3_sub(Vec3(self), other) + */ + } + + /* "ezdxf/acc/vector.pyx":631 + * return v3_sub(Vec3(self), other) + * + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_sub( self, other) + */ + __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_other, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __pyx_t_1 = (!__pyx_t_2); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":632 + * + * if not isinstance(other, Vec3): + * other = Vec3(other) # <<<<<<<<<<<<<< + * return v3_sub( self, other) + * + */ + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF_SET(__pyx_v_other, __pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":631 + * return v3_sub(Vec3(self), other) + * + * if not isinstance(other, Vec3): # <<<<<<<<<<<<<< + * other = Vec3(other) + * return v3_sub( self, other) + */ + } + + /* "ezdxf/acc/vector.pyx":633 + * if not isinstance(other, Vec3): + * other = Vec3(other) + * return v3_sub( self, other) # <<<<<<<<<<<<<< + * + * def __rsub__(self, other) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_other))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 633, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":626 + * + * # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + * def __sub__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(self, Vec3): + * # other is the real self + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__sub__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_other); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":635 + * return v3_sub( self, other) + * + * def __rsub__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v3_sub(Vec3(other), self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_66__rsub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_66__rsub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__rsub__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_65__rsub__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_65__rsub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__rsub__", 1); + + /* "ezdxf/acc/vector.pyx":637 + * def __rsub__(self, other) -> Vec3: + * # for Cython >= 3.0 + * return v3_sub(Vec3(other), self) # <<<<<<<<<<<<<< + * + * __isub__ = __sub__ # immutable + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 637, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 637, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":635 + * return v3_sub( self, other) + * + * def __rsub__(self, other) -> Vec3: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v3_sub(Vec3(other), self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__rsub__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":642 + * + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * def __mul__(self, factor) -> Vec3: # <<<<<<<<<<<<<< + * if isinstance(factor, Vec3): + * return v3_mul( factor, self) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_68__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_68__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__mul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_67__mul__(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_67__mul__(PyObject *__pyx_v_self, PyObject *__pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + double __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__mul__", 1); + + /* "ezdxf/acc/vector.pyx":643 + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * def __mul__(self, factor) -> Vec3: + * if isinstance(factor, Vec3): # <<<<<<<<<<<<<< + * return v3_mul( factor, self) + * return v3_mul( self, factor) + */ + __pyx_t_1 = __Pyx_TypeCheck(__pyx_v_factor, __pyx_ptype_5ezdxf_3acc_6vector_Vec3); + if (__pyx_t_1) { + + /* "ezdxf/acc/vector.pyx":644 + * def __mul__(self, factor) -> Vec3: + * if isinstance(factor, Vec3): + * return v3_mul( factor, self) # <<<<<<<<<<<<<< + * return v3_mul( self, factor) + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_self); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 644, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_factor), __pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":643 + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * def __mul__(self, factor) -> Vec3: + * if isinstance(factor, Vec3): # <<<<<<<<<<<<<< + * return v3_mul( factor, self) + * return v3_mul( self, factor) + */ + } + + /* "ezdxf/acc/vector.pyx":645 + * if isinstance(factor, Vec3): + * return v3_mul( factor, self) + * return v3_mul( self, factor) # <<<<<<<<<<<<<< + * + * def __rmul__(self, double factor) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_factor); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 645, __pyx_L1_error) + __pyx_t_3 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 645, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":642 + * + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + * def __mul__(self, factor) -> Vec3: # <<<<<<<<<<<<<< + * if isinstance(factor, Vec3): + * return v3_mul( factor, self) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__mul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":647 + * return v3_mul( self, factor) + * + * def __rmul__(self, double factor) -> Vec3: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v3_mul(self, factor) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_70__rmul__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_70__rmul__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor) { + double __pyx_v_factor; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__rmul__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_factor); { + __pyx_v_factor = __pyx_PyFloat_AsDouble(__pyx_arg_factor); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 647, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__rmul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_69__rmul__(((PyObject *)__pyx_v_self), ((double)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_69__rmul__(PyObject *__pyx_v_self, double __pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__rmul__", 1); + + /* "ezdxf/acc/vector.pyx":649 + * def __rmul__(self, double factor) -> Vec3: + * # for Cython >= 3.0 + * return v3_mul(self, factor) # <<<<<<<<<<<<<< + * + * __imul__ = __mul__ # immutable + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 649, __pyx_L1_error) + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_factor)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 649, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":647 + * return v3_mul( self, factor) + * + * def __rmul__(self, double factor) -> Vec3: # <<<<<<<<<<<<<< + * # for Cython >= 3.0 + * return v3_mul(self, factor) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__rmul__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":653 + * __imul__ = __mul__ # immutable + * + * def __truediv__(self, double factor) -> Vec3: # <<<<<<<<<<<<<< + * return v3_mul(self, 1.0 / factor) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_72__truediv__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_72__truediv__(PyObject *__pyx_v_self, PyObject *__pyx_arg_factor) { + double __pyx_v_factor; + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__truediv__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + assert(__pyx_arg_factor); { + __pyx_v_factor = __pyx_PyFloat_AsDouble(__pyx_arg_factor); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 653, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__truediv__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_71__truediv__(((PyObject *)__pyx_v_self), ((double)__pyx_v_factor)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_71__truediv__(PyObject *__pyx_v_self, double __pyx_v_factor) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__truediv__", 1); + + /* "ezdxf/acc/vector.pyx":654 + * + * def __truediv__(self, double factor) -> Vec3: + * return v3_mul(self, 1.0 / factor) # <<<<<<<<<<<<<< + * + * # __rtruediv__ not supported -> TypeError + */ + __Pyx_XDECREF(__pyx_r); + if (!(likely(((__pyx_v_self) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 654, __pyx_L1_error) + if (unlikely(__pyx_v_factor == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 654, __pyx_L1_error) + } + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), (1.0 / __pyx_v_factor))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 654, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":653 + * __imul__ = __mul__ # immutable + * + * def __truediv__(self, double factor) -> Vec3: # <<<<<<<<<<<<<< + * return v3_mul(self, 1.0 / factor) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.__truediv__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":658 + * # __rtruediv__ not supported -> TypeError + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[UVec]) -> Vec3: + * cdef Vec3 res = Vec3() + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_74sum(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_74sum = {"sum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_74sum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_74sum(CYTHON_UNUSED PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_items = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("sum (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_items,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_items)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 658, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "sum") < 0)) __PYX_ERR(0, 658, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_items = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("sum", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 658, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.sum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_73sum(__pyx_v_items); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_73sum(PyObject *__pyx_v_items) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_tmp = 0; + PyObject *__pyx_v_v = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("sum", 1); + + /* "ezdxf/acc/vector.pyx":660 + * @staticmethod + * def sum(items: Iterable[UVec]) -> Vec3: + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * cdef Vec3 tmp + * for v in items: + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 660, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":662 + * cdef Vec3 res = Vec3() + * cdef Vec3 tmp + * for v in items: # <<<<<<<<<<<<<< + * tmp = Vec3(v) + * res.x += tmp.x + */ + if (likely(PyList_CheckExact(__pyx_v_items)) || PyTuple_CheckExact(__pyx_v_items)) { + __pyx_t_1 = __pyx_v_items; __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_items); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 662, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 662, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 662, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 662, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 662, __pyx_L1_error) + #endif + if (__pyx_t_2 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely((0 < 0))) __PYX_ERR(0, 662, __pyx_L1_error) + #else + __pyx_t_4 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 662, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 662, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_4); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":663 + * cdef Vec3 tmp + * for v in items: + * tmp = Vec3(v) # <<<<<<<<<<<<<< + * res.x += tmp.x + * res.y += tmp.y + */ + __pyx_t_4 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_v); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 663, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_tmp, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "ezdxf/acc/vector.pyx":664 + * for v in items: + * tmp = Vec3(v) + * res.x += tmp.x # <<<<<<<<<<<<<< + * res.y += tmp.y + * res.z += tmp.z + */ + __pyx_v_res->x = (__pyx_v_res->x + __pyx_v_tmp->x); + + /* "ezdxf/acc/vector.pyx":665 + * tmp = Vec3(v) + * res.x += tmp.x + * res.y += tmp.y # <<<<<<<<<<<<<< + * res.z += tmp.z + * return res + */ + __pyx_v_res->y = (__pyx_v_res->y + __pyx_v_tmp->y); + + /* "ezdxf/acc/vector.pyx":666 + * res.x += tmp.x + * res.y += tmp.y + * res.z += tmp.z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_res->z + __pyx_v_tmp->z); + + /* "ezdxf/acc/vector.pyx":662 + * cdef Vec3 res = Vec3() + * cdef Vec3 tmp + * for v in items: # <<<<<<<<<<<<<< + * tmp = Vec3(v) + * res.x += tmp.x + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":667 + * res.y += tmp.y + * res.z += tmp.z + * return res # <<<<<<<<<<<<<< + * + * def dot(self, other: UVec) -> float: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":658 + * # __rtruediv__ not supported -> TypeError + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[UVec]) -> Vec3: + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.sum", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XDECREF((PyObject *)__pyx_v_tmp); + __Pyx_XDECREF(__pyx_v_v); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":669 + * return res + * + * def dot(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dot(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_76dot(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_76dot = {"dot", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_76dot, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_76dot(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("dot (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 669, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "dot") < 0)) __PYX_ERR(0, 669, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("dot", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 669, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.dot", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_75dot(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_75dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("dot", 1); + + /* "ezdxf/acc/vector.pyx":670 + * + * def dot(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) # <<<<<<<<<<<<<< + * return v3_dot(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 670, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":671 + * def dot(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) + * return v3_dot(self, o) # <<<<<<<<<<<<<< + * + * def cross(self, other: UVec) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 671, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 671, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":669 + * return res + * + * def dot(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dot(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.dot", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":673 + * return v3_dot(self, o) + * + * def cross(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_cross(self, o) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_78cross(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_78cross = {"cross", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_78cross, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_78cross(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cross (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 673, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "cross") < 0)) __PYX_ERR(0, 673, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("cross", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 673, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.cross", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_77cross(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_77cross(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cross", 1); + + /* "ezdxf/acc/vector.pyx":674 + * + * def cross(self, other: UVec) -> Vec3: + * cdef Vec3 o = Vec3(other) # <<<<<<<<<<<<<< + * return v3_cross(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 674, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":675 + * def cross(self, other: UVec) -> Vec3: + * cdef Vec3 o = Vec3(other) + * return v3_cross(self, o) # <<<<<<<<<<<<<< + * + * def distance(self, other: UVec) -> float: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_cross(__pyx_v_self, __pyx_v_o)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":673 + * return v3_dot(self, o) + * + * def cross(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_cross(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.cross", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":677 + * return v3_cross(self, o) + * + * def distance(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dist(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_80distance(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_80distance = {"distance", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_80distance, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_80distance(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("distance (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 677, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "distance") < 0)) __PYX_ERR(0, 677, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("distance", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 677, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_79distance(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_79distance(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("distance", 1); + + /* "ezdxf/acc/vector.pyx":678 + * + * def distance(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) # <<<<<<<<<<<<<< + * return v3_dist(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 678, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":679 + * def distance(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) + * return v3_dist(self, o) # <<<<<<<<<<<<<< + * + * def angle_between(self, other: UVec) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 679, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":677 + * return v3_cross(self, o) + * + * def distance(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dist(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":681 + * return v3_dist(self, o) + * + * def angle_between(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_angle_between(self, o) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_82angle_between(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_82angle_between = {"angle_between", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_82angle_between, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_82angle_between(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_other = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("angle_between (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_other,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_other)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 681, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "angle_between") < 0)) __PYX_ERR(0, 681, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_other = values[0]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("angle_between", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 681, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_81angle_between(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_other); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_81angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_other) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_o = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("angle_between", 1); + + /* "ezdxf/acc/vector.pyx":682 + * + * def angle_between(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) # <<<<<<<<<<<<<< + * return v3_angle_between(self, o) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_other); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 682, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_o = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":683 + * def angle_between(self, other: UVec) -> float: + * cdef Vec3 o = Vec3(other) + * return v3_angle_between(self, o) # <<<<<<<<<<<<<< + * + * def angle_about(self, base: UVec, target: UVec) -> float: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_angle_between(__pyx_v_self, __pyx_v_o); if (unlikely(__pyx_t_2 == ((double)-1000.0))) __PYX_ERR(0, 683, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 683, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":681 + * return v3_dist(self, o) + * + * def angle_between(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_angle_between(self, o) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_o); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":685 + * return v3_angle_between(self, o) + * + * def angle_about(self, base: UVec, target: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_84angle_about(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_84angle_about = {"angle_about", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_84angle_about, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_84angle_about(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_base = 0; + PyObject *__pyx_v_target = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("angle_about (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_base,&__pyx_n_s_target,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_base)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 685, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_target)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 685, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("angle_about", 1, 2, 2, 1); __PYX_ERR(0, 685, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "angle_about") < 0)) __PYX_ERR(0, 685, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_base = values[0]; + __pyx_v_target = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("angle_about", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 685, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle_about", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_83angle_about(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_base, __pyx_v_target); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_83angle_about(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, PyObject *__pyx_v_base, PyObject *__pyx_v_target) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_t = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("angle_about", 1); + + /* "ezdxf/acc/vector.pyx":686 + * + * def angle_about(self, base: UVec, target: UVec) -> float: + * cdef Vec3 b = Vec3(base) # <<<<<<<<<<<<<< + * cdef Vec3 t = Vec3(target) + * return v3_angle_about(self, b, t) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_base); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 686, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_b = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":687 + * def angle_about(self, base: UVec, target: UVec) -> float: + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) # <<<<<<<<<<<<<< + * return v3_angle_about(self, b, t) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_target); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_t = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":688 + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) + * return v3_angle_about(self, b, t) # <<<<<<<<<<<<<< + * + * def rotate(self, double angle) -> Vec3: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_angle_about(__pyx_v_self, __pyx_v_b, __pyx_v_t); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 688, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 688, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":685 + * return v3_angle_between(self, o) + * + * def angle_about(self, base: UVec, target: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.angle_about", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XDECREF((PyObject *)__pyx_v_t); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":690 + * return v3_angle_about(self, b, t) + * + * def rotate(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_86rotate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_86rotate = {"rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_86rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_86rotate(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rotate (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 690, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "rotate") < 0)) __PYX_ERR(0, 690, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 690, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("rotate", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 690, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_85rotate(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_85rotate(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_angle) { + double __pyx_v_angle_; + double __pyx_v_magnitude_; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + unsigned int __pyx_t_6; + double __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("rotate", 1); + + /* "ezdxf/acc/vector.pyx":691 + * + * def rotate(self, double angle) -> Vec3: + * cdef double angle_ = atan2(self.y, self.x) + angle # <<<<<<<<<<<<<< + * cdef double magnitude_ = hypot(self.x, self.y) + * cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) + */ + __pyx_v_angle_ = (atan2(__pyx_v_self->y, __pyx_v_self->x) + __pyx_v_angle); + + /* "ezdxf/acc/vector.pyx":692 + * def rotate(self, double angle) -> Vec3: + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) + * res.z = self.z + */ + __pyx_v_magnitude_ = hypot(__pyx_v_self->x, __pyx_v_self->y); + + /* "ezdxf/acc/vector.pyx":693 + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) + * cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) # <<<<<<<<<<<<<< + * res.z = self.z + * return res + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_n_s_from_angle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_angle_); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_magnitude_); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + __pyx_t_6 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_6 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_t_3, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_6, 2+__pyx_t_6); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 693, __pyx_L1_error) + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":694 + * cdef double magnitude_ = hypot(self.x, self.y) + * cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) + * res.z = self.z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_t_7 = __pyx_v_self->z; + __pyx_v_res->z = __pyx_t_7; + + /* "ezdxf/acc/vector.pyx":695 + * cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) + * res.z = self.z + * return res # <<<<<<<<<<<<<< + * + * def rotate_deg(self, double angle) -> Vec3: + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":690 + * return v3_angle_about(self, b, t) + * + * def rotate(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.rotate", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":697 + * return res + * + * def rotate_deg(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_88rotate_deg(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_4Vec3_88rotate_deg = {"rotate_deg", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_88rotate_deg, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_88rotate_deg(PyObject *__pyx_v_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + double __pyx_v_angle; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[1] = {0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rotate_deg (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_angle,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_angle)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 697, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "rotate_deg") < 0)) __PYX_ERR(0, 697, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 1)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + } + __pyx_v_angle = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_angle == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 697, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("rotate_deg", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 697, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.rotate_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_87rotate_deg(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self), __pyx_v_angle); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_87rotate_deg(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self, double __pyx_v_angle) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + unsigned int __pyx_t_5; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("rotate_deg", 1); + + /* "ezdxf/acc/vector.pyx":698 + * + * def rotate_deg(self, double angle) -> Vec3: + * return self.rotate(angle * DEG2RAD) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_rotate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble((__pyx_v_angle * __pyx_v_5ezdxf_3acc_6vector_DEG2RAD)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + __pyx_t_5 = 0; + #if CYTHON_UNPACK_METHODS + if (likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_5 = 1; + } + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5); + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 698, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5ezdxf_3acc_6vector_Vec3))))) __PYX_ERR(0, 698, __pyx_L1_error) + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":697 + * return res + * + * def rotate_deg(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.rotate_deg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pxd":29 + * + * cdef class Vec3: + * cdef readonly double x, y, z # <<<<<<<<<<<<<< + * + * # Vec3 C-functions: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1x_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1x_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_1x___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1x___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.x.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1y_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1y_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_1y___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1y___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->y); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.y.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1z_1__get__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1z_1__get__(PyObject *__pyx_v_self) { + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__get__ (wrapper)", 0); + __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4Vec3_1z___get__(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4Vec3_1z___get__(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__get__", 1); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->z); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.Vec3.z.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":706 + * NULLVEC = Vec3(0, 0, 0) + * + * cdef Vec3 v3_add(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x + b.x + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_add(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_add", 1); + + /* "ezdxf/acc/vector.pyx":707 + * + * cdef Vec3 v3_add(Vec3 a, Vec3 b): + * res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.x + b.x + * res.y = a.y + b.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 707, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":708 + * cdef Vec3 v3_add(Vec3 a, Vec3 b): + * res = Vec3() + * res.x = a.x + b.x # <<<<<<<<<<<<<< + * res.y = a.y + b.y + * res.z = a.z + b.z + */ + __pyx_v_res->x = (__pyx_v_a->x + __pyx_v_b->x); + + /* "ezdxf/acc/vector.pyx":709 + * res = Vec3() + * res.x = a.x + b.x + * res.y = a.y + b.y # <<<<<<<<<<<<<< + * res.z = a.z + b.z + * return res + */ + __pyx_v_res->y = (__pyx_v_a->y + __pyx_v_b->y); + + /* "ezdxf/acc/vector.pyx":710 + * res.x = a.x + b.x + * res.y = a.y + b.y + * res.z = a.z + b.z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_a->z + __pyx_v_b->z); + + /* "ezdxf/acc/vector.pyx":711 + * res.y = a.y + b.y + * res.z = a.z + b.z + * return res # <<<<<<<<<<<<<< + * + * cdef Vec3 v3_sub(Vec3 a, Vec3 b): + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":706 + * NULLVEC = Vec3(0, 0, 0) + * + * cdef Vec3 v3_add(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x + b.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_add", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":713 + * return res + * + * cdef Vec3 v3_sub(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x - b.x + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_sub(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_sub", 1); + + /* "ezdxf/acc/vector.pyx":714 + * + * cdef Vec3 v3_sub(Vec3 a, Vec3 b): + * res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.x - b.x + * res.y = a.y - b.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 714, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":715 + * cdef Vec3 v3_sub(Vec3 a, Vec3 b): + * res = Vec3() + * res.x = a.x - b.x # <<<<<<<<<<<<<< + * res.y = a.y - b.y + * res.z = a.z - b.z + */ + __pyx_v_res->x = (__pyx_v_a->x - __pyx_v_b->x); + + /* "ezdxf/acc/vector.pyx":716 + * res = Vec3() + * res.x = a.x - b.x + * res.y = a.y - b.y # <<<<<<<<<<<<<< + * res.z = a.z - b.z + * return res + */ + __pyx_v_res->y = (__pyx_v_a->y - __pyx_v_b->y); + + /* "ezdxf/acc/vector.pyx":717 + * res.x = a.x - b.x + * res.y = a.y - b.y + * res.z = a.z - b.z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_a->z - __pyx_v_b->z); + + /* "ezdxf/acc/vector.pyx":718 + * res.y = a.y - b.y + * res.z = a.z - b.z + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":713 + * return res + * + * cdef Vec3 v3_sub(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x - b.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_sub", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":721 + * + * + * cdef Vec3 v3_mul(Vec3 a, double factor): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x * factor + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_mul(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_mul", 1); + + /* "ezdxf/acc/vector.pyx":722 + * + * cdef Vec3 v3_mul(Vec3 a, double factor): + * res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.x * factor + * res.y = a.y * factor + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 722, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":723 + * cdef Vec3 v3_mul(Vec3 a, double factor): + * res = Vec3() + * res.x = a.x * factor # <<<<<<<<<<<<<< + * res.y = a.y * factor + * res.z = a.z * factor + */ + __pyx_v_res->x = (__pyx_v_a->x * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":724 + * res = Vec3() + * res.x = a.x * factor + * res.y = a.y * factor # <<<<<<<<<<<<<< + * res.z = a.z * factor + * return res + */ + __pyx_v_res->y = (__pyx_v_a->y * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":725 + * res.x = a.x * factor + * res.y = a.y * factor + * res.z = a.z * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_a->z * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":726 + * res.y = a.y * factor + * res.z = a.z * factor + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":721 + * + * + * cdef Vec3 v3_mul(Vec3 a, double factor): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.x * factor + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_mul", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":729 + * + * + * cdef Vec3 v3_reverse(Vec3 a): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = -a.x + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_reverse(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_reverse", 1); + + /* "ezdxf/acc/vector.pyx":730 + * + * cdef Vec3 v3_reverse(Vec3 a): + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = -a.x + * res.y = -a.y + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 730, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":731 + * cdef Vec3 v3_reverse(Vec3 a): + * cdef Vec3 res = Vec3() + * res.x = -a.x # <<<<<<<<<<<<<< + * res.y = -a.y + * res.z = -a.z + */ + __pyx_v_res->x = (-__pyx_v_a->x); + + /* "ezdxf/acc/vector.pyx":732 + * cdef Vec3 res = Vec3() + * res.x = -a.x + * res.y = -a.y # <<<<<<<<<<<<<< + * res.z = -a.z + * return res + */ + __pyx_v_res->y = (-__pyx_v_a->y); + + /* "ezdxf/acc/vector.pyx":733 + * res.x = -a.x + * res.y = -a.y + * res.z = -a.z # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (-__pyx_v_a->z); + + /* "ezdxf/acc/vector.pyx":734 + * res.y = -a.y + * res.z = -a.z + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":729 + * + * + * cdef Vec3 v3_reverse(Vec3 a): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = -a.x + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_reverse", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":737 + * + * + * cdef double v3_dot(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * return a.x * b.x + a.y * b.y + a.z * b.z + * + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v3_dot(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":738 + * + * cdef double v3_dot(Vec3 a, Vec3 b): + * return a.x * b.x + a.y * b.y + a.z * b.z # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = (((__pyx_v_a->x * __pyx_v_b->x) + (__pyx_v_a->y * __pyx_v_b->y)) + (__pyx_v_a->z * __pyx_v_b->z)); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":737 + * + * + * cdef double v3_dot(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * return a.x * b.x + a.y * b.y + a.z * b.z + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":741 + * + * + * cdef Vec3 v3_cross(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.y * b.z - a.z * b.y + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_cross(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = NULL; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_cross", 1); + + /* "ezdxf/acc/vector.pyx":742 + * + * cdef Vec3 v3_cross(Vec3 a, Vec3 b): + * res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.y * b.z - a.z * b.y + * res.y = a.z * b.x - a.x * b.z + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 742, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":743 + * cdef Vec3 v3_cross(Vec3 a, Vec3 b): + * res = Vec3() + * res.x = a.y * b.z - a.z * b.y # <<<<<<<<<<<<<< + * res.y = a.z * b.x - a.x * b.z + * res.z = a.x * b.y - a.y * b.x + */ + __pyx_v_res->x = ((__pyx_v_a->y * __pyx_v_b->z) - (__pyx_v_a->z * __pyx_v_b->y)); + + /* "ezdxf/acc/vector.pyx":744 + * res = Vec3() + * res.x = a.y * b.z - a.z * b.y + * res.y = a.z * b.x - a.x * b.z # <<<<<<<<<<<<<< + * res.z = a.x * b.y - a.y * b.x + * return res + */ + __pyx_v_res->y = ((__pyx_v_a->z * __pyx_v_b->x) - (__pyx_v_a->x * __pyx_v_b->z)); + + /* "ezdxf/acc/vector.pyx":745 + * res.x = a.y * b.z - a.z * b.y + * res.y = a.z * b.x - a.x * b.z + * res.z = a.x * b.y - a.y * b.x # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = ((__pyx_v_a->x * __pyx_v_b->y) - (__pyx_v_a->y * __pyx_v_b->x)); + + /* "ezdxf/acc/vector.pyx":746 + * res.y = a.z * b.x - a.x * b.z + * res.z = a.x * b.y - a.y * b.x + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":741 + * + * + * cdef Vec3 v3_cross(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * res = Vec3() + * res.x = a.y * b.z - a.z * b.y + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_cross", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":749 + * + * + * cdef inline double v3_magnitude_sqr(Vec3 a): # <<<<<<<<<<<<<< + * return a.x * a.x + a.y * a.y + a.z * a.z + * + */ + +static CYTHON_INLINE double __pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a) { + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":750 + * + * cdef inline double v3_magnitude_sqr(Vec3 a): + * return a.x * a.x + a.y * a.y + a.z * a.z # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = (((__pyx_v_a->x * __pyx_v_a->x) + (__pyx_v_a->y * __pyx_v_a->y)) + (__pyx_v_a->z * __pyx_v_a->z)); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":749 + * + * + * cdef inline double v3_magnitude_sqr(Vec3 a): # <<<<<<<<<<<<<< + * return a.x * a.x + a.y * a.y + a.z * a.z + * + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":753 + * + * + * cdef inline double v3_magnitude(Vec3 a): # <<<<<<<<<<<<<< + * return sqrt(v3_magnitude_sqr(a)) + * + */ + +static CYTHON_INLINE double __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a) { + double __pyx_r; + double __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "ezdxf/acc/vector.pyx":754 + * + * cdef inline double v3_magnitude(Vec3 a): + * return sqrt(v3_magnitude_sqr(a)) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr(__pyx_v_a); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 754, __pyx_L1_error) + __pyx_r = sqrt(__pyx_t_1); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":753 + * + * + * cdef inline double v3_magnitude(Vec3 a): # <<<<<<<<<<<<<< + * return sqrt(v3_magnitude_sqr(a)) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.v3_magnitude", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":757 + * + * + * cdef double v3_dist(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * cdef double dx = a.x - b.x + * cdef double dy = a.y - b.y + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v3_dist(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + double __pyx_v_dx; + double __pyx_v_dy; + double __pyx_v_dz; + double __pyx_r; + + /* "ezdxf/acc/vector.pyx":758 + * + * cdef double v3_dist(Vec3 a, Vec3 b): + * cdef double dx = a.x - b.x # <<<<<<<<<<<<<< + * cdef double dy = a.y - b.y + * cdef double dz = a.z - b.z + */ + __pyx_v_dx = (__pyx_v_a->x - __pyx_v_b->x); + + /* "ezdxf/acc/vector.pyx":759 + * cdef double v3_dist(Vec3 a, Vec3 b): + * cdef double dx = a.x - b.x + * cdef double dy = a.y - b.y # <<<<<<<<<<<<<< + * cdef double dz = a.z - b.z + * return sqrt(dx * dx + dy * dy + dz * dz) + */ + __pyx_v_dy = (__pyx_v_a->y - __pyx_v_b->y); + + /* "ezdxf/acc/vector.pyx":760 + * cdef double dx = a.x - b.x + * cdef double dy = a.y - b.y + * cdef double dz = a.z - b.z # <<<<<<<<<<<<<< + * return sqrt(dx * dx + dy * dy + dz * dz) + * + */ + __pyx_v_dz = (__pyx_v_a->z - __pyx_v_b->z); + + /* "ezdxf/acc/vector.pyx":761 + * cdef double dy = a.y - b.y + * cdef double dz = a.z - b.z + * return sqrt(dx * dx + dy * dy + dz * dz) # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = sqrt((((__pyx_v_dx * __pyx_v_dx) + (__pyx_v_dy * __pyx_v_dy)) + (__pyx_v_dz * __pyx_v_dz))); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":757 + * + * + * cdef double v3_dist(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * cdef double dx = a.x - b.x + * cdef double dy = a.y - b.y + */ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":764 + * + * + * cdef Vec3 v3_from_angle(double angle, double length): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = cos(angle) * length + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_from_angle(double __pyx_v_angle, double __pyx_v_length) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_from_angle", 1); + + /* "ezdxf/acc/vector.pyx":765 + * + * cdef Vec3 v3_from_angle(double angle, double length): + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = cos(angle) * length + * res.y = sin(angle) * length + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 765, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":766 + * cdef Vec3 v3_from_angle(double angle, double length): + * cdef Vec3 res = Vec3() + * res.x = cos(angle) * length # <<<<<<<<<<<<<< + * res.y = sin(angle) * length + * return res + */ + __pyx_v_res->x = (cos(__pyx_v_angle) * __pyx_v_length); + + /* "ezdxf/acc/vector.pyx":767 + * cdef Vec3 res = Vec3() + * res.x = cos(angle) * length + * res.y = sin(angle) * length # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (sin(__pyx_v_angle) * __pyx_v_length); + + /* "ezdxf/acc/vector.pyx":768 + * res.x = cos(angle) * length + * res.y = sin(angle) * length + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":764 + * + * + * cdef Vec3 v3_from_angle(double angle, double length): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = cos(angle) * length + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_from_angle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":771 + * + * + * cdef double v3_angle_between(Vec3 a, Vec3 b) except -1000: # <<<<<<<<<<<<<< + * cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v3_angle_between(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + double __pyx_v_cos_theta; + double __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_angle_between", 1); + + /* "ezdxf/acc/vector.pyx":772 + * + * cdef double v3_angle_between(Vec3 a, Vec3 b) except -1000: + * cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) # <<<<<<<<<<<<<< + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_a, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 772, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_b, 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 772, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2)); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 772, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_cos_theta = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":774 + * cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: # <<<<<<<<<<<<<< + * cos_theta = -1.0 + * elif cos_theta > 1.0: + */ + __pyx_t_4 = (__pyx_v_cos_theta < -1.0); + if (__pyx_t_4) { + + /* "ezdxf/acc/vector.pyx":775 + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: + * cos_theta = -1.0 # <<<<<<<<<<<<<< + * elif cos_theta > 1.0: + * cos_theta = 1.0 + */ + __pyx_v_cos_theta = -1.0; + + /* "ezdxf/acc/vector.pyx":774 + * cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + * if cos_theta < -1.0: # <<<<<<<<<<<<<< + * cos_theta = -1.0 + * elif cos_theta > 1.0: + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/vector.pyx":776 + * if cos_theta < -1.0: + * cos_theta = -1.0 + * elif cos_theta > 1.0: # <<<<<<<<<<<<<< + * cos_theta = 1.0 + * return acos(cos_theta) + */ + __pyx_t_4 = (__pyx_v_cos_theta > 1.0); + if (__pyx_t_4) { + + /* "ezdxf/acc/vector.pyx":777 + * cos_theta = -1.0 + * elif cos_theta > 1.0: + * cos_theta = 1.0 # <<<<<<<<<<<<<< + * return acos(cos_theta) + * + */ + __pyx_v_cos_theta = 1.0; + + /* "ezdxf/acc/vector.pyx":776 + * if cos_theta < -1.0: + * cos_theta = -1.0 + * elif cos_theta > 1.0: # <<<<<<<<<<<<<< + * cos_theta = 1.0 + * return acos(cos_theta) + */ + } + __pyx_L3:; + + /* "ezdxf/acc/vector.pyx":778 + * elif cos_theta > 1.0: + * cos_theta = 1.0 + * return acos(cos_theta) # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = acos(__pyx_v_cos_theta); + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":771 + * + * + * cdef double v3_angle_between(Vec3 a, Vec3 b) except -1000: # <<<<<<<<<<<<<< + * cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) + * # avoid domain errors caused by floating point imprecision: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_angle_between", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1000.0; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":781 + * + * + * cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target): # <<<<<<<<<<<<<< + * cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + */ + +static double __pyx_f_5ezdxf_3acc_6vector_v3_angle_about(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_base, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_target) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_x_axis = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_y_axis = 0; + double __pyx_v_target_projected_x; + double __pyx_v_target_projected_y; + double __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + double __pyx_t_3; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_angle_about", 1); + + /* "ezdxf/acc/vector.pyx":782 + * + * cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target): + * cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) # <<<<<<<<<<<<<< + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + * cdef double target_projected_x = v3_dot(x_axis, target) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_project(__pyx_v_a, __pyx_v_base)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_sub(__pyx_v_base, ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 782, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2), 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 782, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_x_axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":783 + * cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target): + * cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) # <<<<<<<<<<<<<< + * cdef double target_projected_x = v3_dot(x_axis, target) + * cdef double target_projected_y = v3_dot(y_axis, target) + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_cross(__pyx_v_a, __pyx_v_x_axis)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 783, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1), 1.0)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 783, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_y_axis = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":784 + * cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + * cdef double target_projected_x = v3_dot(x_axis, target) # <<<<<<<<<<<<<< + * cdef double target_projected_y = v3_dot(y_axis, target) + * return normalize_rad_angle(atan2(target_projected_y, target_projected_x)) + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_x_axis, __pyx_v_target); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 784, __pyx_L1_error) + __pyx_v_target_projected_x = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":785 + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + * cdef double target_projected_x = v3_dot(x_axis, target) + * cdef double target_projected_y = v3_dot(y_axis, target) # <<<<<<<<<<<<<< + * return normalize_rad_angle(atan2(target_projected_y, target_projected_x)) + * + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_y_axis, __pyx_v_target); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 785, __pyx_L1_error) + __pyx_v_target_projected_y = __pyx_t_3; + + /* "ezdxf/acc/vector.pyx":786 + * cdef double target_projected_x = v3_dot(x_axis, target) + * cdef double target_projected_y = v3_dot(y_axis, target) + * return normalize_rad_angle(atan2(target_projected_y, target_projected_x)) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_3 = __pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle(atan2(__pyx_v_target_projected_y, __pyx_v_target_projected_x)); if (unlikely(__pyx_t_3 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 786, __pyx_L1_error) + __pyx_r = __pyx_t_3; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":781 + * + * + * cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target): # <<<<<<<<<<<<<< + * cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) + * cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_angle_about", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_x_axis); + __Pyx_XDECREF((PyObject *)__pyx_v_y_axis); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":789 + * + * + * cdef Vec3 v3_normalize(Vec3 a, double length): # <<<<<<<<<<<<<< + * cdef double factor = length / v3_magnitude(a) + * cdef Vec3 res = Vec3() + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_normalize(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, double __pyx_v_length) { + double __pyx_v_factor; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_normalize", 1); + + /* "ezdxf/acc/vector.pyx":790 + * + * cdef Vec3 v3_normalize(Vec3 a, double length): + * cdef double factor = length / v3_magnitude(a) # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = a.x * factor + */ + __pyx_t_1 = __pyx_f_5ezdxf_3acc_6vector_v3_magnitude(__pyx_v_a); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 790, __pyx_L1_error) + if (unlikely(__pyx_t_1 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 790, __pyx_L1_error) + } + __pyx_v_factor = (__pyx_v_length / __pyx_t_1); + + /* "ezdxf/acc/vector.pyx":791 + * cdef Vec3 v3_normalize(Vec3 a, double length): + * cdef double factor = length / v3_magnitude(a) + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.x * factor + * res.y = a.y * factor + */ + __pyx_t_2 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 791, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":792 + * cdef double factor = length / v3_magnitude(a) + * cdef Vec3 res = Vec3() + * res.x = a.x * factor # <<<<<<<<<<<<<< + * res.y = a.y * factor + * res.z = a.z * factor + */ + __pyx_v_res->x = (__pyx_v_a->x * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":793 + * cdef Vec3 res = Vec3() + * res.x = a.x * factor + * res.y = a.y * factor # <<<<<<<<<<<<<< + * res.z = a.z * factor + * return res + */ + __pyx_v_res->y = (__pyx_v_a->y * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":794 + * res.x = a.x * factor + * res.y = a.y * factor + * res.z = a.z * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_a->z * __pyx_v_factor); + + /* "ezdxf/acc/vector.pyx":795 + * res.y = a.y * factor + * res.z = a.z * factor + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":789 + * + * + * cdef Vec3 v3_normalize(Vec3 a, double length): # <<<<<<<<<<<<<< + * cdef double factor = length / v3_magnitude(a) + * cdef Vec3 res = Vec3() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_normalize", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":798 + * + * + * cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = a.x + (b.x - a.x) * factor + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_lerp(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_lerp", 1); + + /* "ezdxf/acc/vector.pyx":799 + * + * cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor): + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":800 + * cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor): + * cdef Vec3 res = Vec3() + * res.x = a.x + (b.x - a.x) * factor # <<<<<<<<<<<<<< + * res.y = a.y + (b.y - a.y) * factor + * res.z = a.z + (b.z - a.z) * factor + */ + __pyx_v_res->x = (__pyx_v_a->x + ((__pyx_v_b->x - __pyx_v_a->x) * __pyx_v_factor)); + + /* "ezdxf/acc/vector.pyx":801 + * cdef Vec3 res = Vec3() + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor # <<<<<<<<<<<<<< + * res.z = a.z + (b.z - a.z) * factor + * return res + */ + __pyx_v_res->y = (__pyx_v_a->y + ((__pyx_v_b->y - __pyx_v_a->y) * __pyx_v_factor)); + + /* "ezdxf/acc/vector.pyx":802 + * res.x = a.x + (b.x - a.x) * factor + * res.y = a.y + (b.y - a.y) * factor + * res.z = a.z + (b.z - a.z) * factor # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->z = (__pyx_v_a->z + ((__pyx_v_b->z - __pyx_v_a->z) * __pyx_v_factor)); + + /* "ezdxf/acc/vector.pyx":803 + * res.y = a.y + (b.y - a.y) * factor + * res.z = a.z + (b.z - a.z) * factor + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":798 + * + * + * cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.x = a.x + (b.x - a.x) * factor + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":806 + * + * + * cdef Vec3 v3_ortho(Vec3 a, bint ccw): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.z = a.z + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_ortho(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, int __pyx_v_ccw) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_res = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_ortho", 1); + + /* "ezdxf/acc/vector.pyx":807 + * + * cdef Vec3 v3_ortho(Vec3 a, bint ccw): + * cdef Vec3 res = Vec3() # <<<<<<<<<<<<<< + * res.z = a.z + * if ccw: + */ + __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 807, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_res = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":808 + * cdef Vec3 v3_ortho(Vec3 a, bint ccw): + * cdef Vec3 res = Vec3() + * res.z = a.z # <<<<<<<<<<<<<< + * if ccw: + * res.x = -a.y + */ + __pyx_t_2 = __pyx_v_a->z; + __pyx_v_res->z = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":809 + * cdef Vec3 res = Vec3() + * res.z = a.z + * if ccw: # <<<<<<<<<<<<<< + * res.x = -a.y + * res.y = a.x + */ + if (__pyx_v_ccw) { + + /* "ezdxf/acc/vector.pyx":810 + * res.z = a.z + * if ccw: + * res.x = -a.y # <<<<<<<<<<<<<< + * res.y = a.x + * else: + */ + __pyx_v_res->x = (-__pyx_v_a->y); + + /* "ezdxf/acc/vector.pyx":811 + * if ccw: + * res.x = -a.y + * res.y = a.x # <<<<<<<<<<<<<< + * else: + * res.x = a.y + */ + __pyx_t_2 = __pyx_v_a->x; + __pyx_v_res->y = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":809 + * cdef Vec3 res = Vec3() + * res.z = a.z + * if ccw: # <<<<<<<<<<<<<< + * res.x = -a.y + * res.y = a.x + */ + goto __pyx_L3; + } + + /* "ezdxf/acc/vector.pyx":813 + * res.y = a.x + * else: + * res.x = a.y # <<<<<<<<<<<<<< + * res.y = -a.x + * return res + */ + /*else*/ { + __pyx_t_2 = __pyx_v_a->y; + __pyx_v_res->x = __pyx_t_2; + + /* "ezdxf/acc/vector.pyx":814 + * else: + * res.x = a.y + * res.y = -a.x # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_v_res->y = (-__pyx_v_a->x); + } + __pyx_L3:; + + /* "ezdxf/acc/vector.pyx":815 + * res.x = a.y + * res.y = -a.x + * return res # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __Pyx_INCREF((PyObject *)__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":806 + * + * + * cdef Vec3 v3_ortho(Vec3 a, bint ccw): # <<<<<<<<<<<<<< + * cdef Vec3 res = Vec3() + * res.z = a.z + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_ortho", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_res); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":818 + * + * + * cdef Vec3 v3_project(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * cdef Vec3 uv = v3_normalize(a, 1.0) + * return v3_mul(uv, v3_dot(uv, b)) + */ + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_f_5ezdxf_3acc_6vector_v3_project(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_uv = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("v3_project", 1); + + /* "ezdxf/acc/vector.pyx":819 + * + * cdef Vec3 v3_project(Vec3 a, Vec3 b): + * cdef Vec3 uv = v3_normalize(a, 1.0) # <<<<<<<<<<<<<< + * return v3_mul(uv, v3_dot(uv, b)) + * + */ + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_normalize(__pyx_v_a, 1.0)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 819, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_uv = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":820 + * cdef Vec3 v3_project(Vec3 a, Vec3 b): + * cdef Vec3 uv = v3_normalize(a, 1.0) + * return v3_mul(uv, v3_dot(uv, b)) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_dot(__pyx_v_uv, __pyx_v_b); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 820, __pyx_L1_error) + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_mul(__pyx_v_uv, __pyx_t_2)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":818 + * + * + * cdef Vec3 v3_project(Vec3 a, Vec3 b): # <<<<<<<<<<<<<< + * cdef Vec3 uv = v3_normalize(a, 1.0) + * return v3_mul(uv, v3_dot(uv, b)) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.v3_project", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_uv); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":823 + * + * + * cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) and \ + */ + +static int __pyx_f_5ezdxf_3acc_6vector_v3_isclose(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b, double __pyx_v_rel_tol, double __pyx_v_abs_tol) { + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "ezdxf/acc/vector.pyx":824 + * + * cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol): + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ # <<<<<<<<<<<<<< + * isclose(a.y, b.y, rel_tol, abs_tol) and \ + * isclose(a.z, b.z, rel_tol, abs_tol) + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_a->x, __pyx_v_b->x, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 824, __pyx_L1_error) + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":825 + * cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol): + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) and \ # <<<<<<<<<<<<<< + * isclose(a.z, b.z, rel_tol, abs_tol) + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_a->y, __pyx_v_b->y, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 825, __pyx_L1_error) + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L3_bool_binop_done; + } + + /* "ezdxf/acc/vector.pyx":826 + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) and \ + * isclose(a.z, b.z, rel_tol, abs_tol) # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_isclose(__pyx_v_a->z, __pyx_v_b->z, __pyx_v_rel_tol, __pyx_v_abs_tol); if (unlikely(__pyx_t_2 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 826, __pyx_L1_error) + __pyx_t_1 = __pyx_t_2; + __pyx_L3_bool_binop_done:; + __pyx_r = __pyx_t_1; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":823 + * + * + * cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol): # <<<<<<<<<<<<<< + * return isclose(a.x, b.x, rel_tol, abs_tol) and \ + * isclose(a.y, b.y, rel_tol, abs_tol) and \ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("ezdxf.acc.vector.v3_isclose", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":829 + * + * + * def distance(p1: UVec, p2: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_5distance(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_5distance = {"distance", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_5distance, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_5ezdxf_3acc_6vector_5distance(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_p1 = 0; + PyObject *__pyx_v_p2 = 0; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[2] = {0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("distance (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p1,&__pyx_n_s_p2,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 829, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 829, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("distance", 1, 2, 2, 1); __PYX_ERR(0, 829, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "distance") < 0)) __PYX_ERR(0, 829, __pyx_L3_error) + } + } else if (unlikely(__pyx_nargs != 2)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + } + __pyx_v_p1 = values[0]; + __pyx_v_p2 = values[1]; + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("distance", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 829, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_4distance(__pyx_self, __pyx_v_p1, __pyx_v_p2); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_5ezdxf_3acc_6vector_4distance(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_p1, PyObject *__pyx_v_p2) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + double __pyx_t_2; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("distance", 1); + + /* "ezdxf/acc/vector.pyx":830 + * + * def distance(p1: UVec, p2: UVec) -> float: + * cdef Vec3 a = Vec3(p1) # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(p2) + * return v3_dist(a, b) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_p1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 830, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_a = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":831 + * def distance(p1: UVec, p2: UVec) -> float: + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) # <<<<<<<<<<<<<< + * return v3_dist(a, b) + * + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_p2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_b = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":832 + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + * return v3_dist(a, b) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_5ezdxf_3acc_6vector_v3_dist(__pyx_v_a, __pyx_v_b); if (unlikely(__pyx_t_2 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 832, __pyx_L1_error) + __pyx_t_1 = PyFloat_FromDouble(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 832, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":829 + * + * + * def distance(p1: UVec, p2: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.distance", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "ezdxf/acc/vector.pyx":835 + * + * + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + +/* Python wrapper */ +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_7lerp(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +static PyMethodDef __pyx_mdef_5ezdxf_3acc_6vector_7lerp = {"lerp", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_7lerp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pw_5ezdxf_3acc_6vector_7lerp(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_p1 = 0; + PyObject *__pyx_v_p2 = 0; + double __pyx_v_factor; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("lerp (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_MACROS + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p1,&__pyx_n_s_p2,&__pyx_n_s_factor,0}; + if (__pyx_kwds) { + Py_ssize_t kw_args; + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds); + switch (__pyx_nargs) { + case 0: + if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p1)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[0]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 835, __pyx_L3_error) + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_p2)) != 0)) { + (void)__Pyx_Arg_NewRef_FASTCALL(values[1]); + kw_args--; + } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 835, __pyx_L3_error) + else { + __Pyx_RaiseArgtupleInvalid("lerp", 0, 2, 3, 1); __PYX_ERR(0, 835, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_factor); + if (value) { values[2] = __Pyx_Arg_NewRef_FASTCALL(value); kw_args--; } + else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 835, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "lerp") < 0)) __PYX_ERR(0, 835, __pyx_L3_error) + } + } else { + switch (__pyx_nargs) { + case 3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1); + values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_p1 = values[0]; + __pyx_v_p2 = values[1]; + if (values[2]) { + __pyx_v_factor = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_factor == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 835, __pyx_L3_error) + } else { + __pyx_v_factor = ((double)((double)0.5)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("lerp", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 835, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_AddTraceback("ezdxf.acc.vector.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_5ezdxf_3acc_6vector_6lerp(__pyx_self, __pyx_v_p1, __pyx_v_p2, __pyx_v_factor); + + /* function exit code */ + { + Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]); + } + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_pf_5ezdxf_3acc_6vector_6lerp(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_p1, PyObject *__pyx_v_p2, double __pyx_v_factor) { + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_a = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_v_b = 0; + struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("lerp", 1); + + /* "ezdxf/acc/vector.pyx":836 + * + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: + * cdef Vec3 a = Vec3(p1) # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(p2) + * return v3_lerp(a, b, factor) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_p1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 836, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_a = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":837 + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) # <<<<<<<<<<<<<< + * return v3_lerp(a, b, factor) + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_v_p2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 837, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_b = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "ezdxf/acc/vector.pyx":838 + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + * return v3_lerp(a, b, factor) # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF((PyObject *)__pyx_r); + __pyx_t_1 = ((PyObject *)__pyx_f_5ezdxf_3acc_6vector_v3_lerp(__pyx_v_a, __pyx_v_b, __pyx_v_factor)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 838, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = ((struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)__pyx_t_1); + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "ezdxf/acc/vector.pyx":835 + * + * + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("ezdxf.acc.vector.lerp", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_a); + __Pyx_XDECREF((PyObject *)__pyx_v_b); + __Pyx_XGIVEREF((PyObject *)__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector_Vec2(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + if (unlikely(__pyx_pw_5ezdxf_3acc_6vector_4Vec2_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec2(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec2) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} +static PyObject *__pyx_sq_item_5ezdxf_3acc_6vector_Vec2(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static PyObject *__pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec2(PyObject *o1, PyObject *o2, int op) { + switch (op) { + case Py_EQ: { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_52__eq__(o1, o2); + } + case Py_LT: { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_54__lt__(o1, o2); + } + case Py_NE: { + PyObject *ret; + ret = __pyx_pw_5ezdxf_3acc_6vector_4Vec2_52__eq__(o1, o2); + if (likely(ret && ret != Py_NotImplemented)) { + int b = __Pyx_PyObject_IsTrue(ret); + Py_DECREF(ret); + if (unlikely(b < 0)) return NULL; + ret = (b) ? Py_False : Py_True; + Py_INCREF(ret); + } + return ret; + } + default: { + return __Pyx_NewRef(Py_NotImplemented); + } + } +} +#define __pyx_nb_add_5ezdxf_3acc_6vector_Vec2 __pyx_pw_5ezdxf_3acc_6vector_4Vec2_56__add__ +#define __pyx_nb_subtract_5ezdxf_3acc_6vector_Vec2 __pyx_pw_5ezdxf_3acc_6vector_4Vec2_58__sub__ +#define __pyx_nb_multiply_5ezdxf_3acc_6vector_Vec2 __pyx_pw_5ezdxf_3acc_6vector_4Vec2_60__mul__ +#define __pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec2 __pyx_pw_5ezdxf_3acc_6vector_4Vec2_64__truediv__ + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_vec3(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_4vec3_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_magnitude(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_9magnitude_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_is_null(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_7is_null_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_angle(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_5angle_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_angle_deg(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_9angle_deg_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_x(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_1x_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec2_y(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_1y_1__get__(o); +} + +static PyObject *__pyx_specialmethod___pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__(self); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_6vector_Vec2[] = { + {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"round", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_5round, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"list", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_7list, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"tuple", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_9tuple, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"generate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_11generate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"from_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_13from_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"from_deg_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__, METH_NOARGS|METH_COEXIST, 0}, + {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_25copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__copy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_27__copy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__deepcopy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"orthogonal", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_38orthogonal, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"lerp", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_40lerp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"normalize", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_42normalize, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"project", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_44project, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"isclose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_50isclose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__rmul__", (PyCFunction)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_62__rmul__, METH_O|METH_COEXIST, 0}, + {"dot", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_66dot, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"det", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_68det, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"distance", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_70distance, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"angle_between", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_72angle_between, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_74rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"rotate_deg", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_76rotate_deg, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"sum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_78sum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_6vector_Vec2[] = { + {(char *)"vec3", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_vec3, 0, (char *)0, 0}, + {(char *)"magnitude", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_magnitude, 0, (char *)0, 0}, + {(char *)"is_null", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_is_null, 0, (char *)0, 0}, + {(char *)"angle", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_angle, 0, (char *)0, 0}, + {(char *)"angle_deg", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_angle_deg, 0, (char *)0, 0}, + {(char *)"x", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_x, 0, (char *)0, 0}, + {(char *)"y", __pyx_getprop_5ezdxf_3acc_6vector_4Vec2_y, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector_Vec2_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec2}, + {Py_tp_repr, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__}, + {Py_nb_add, (void *)__pyx_nb_add_5ezdxf_3acc_6vector_Vec2}, + {Py_nb_subtract, (void *)__pyx_nb_subtract_5ezdxf_3acc_6vector_Vec2}, + {Py_nb_multiply, (void *)__pyx_nb_multiply_5ezdxf_3acc_6vector_Vec2}, + {Py_nb_negative, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_46__neg__}, + {Py_nb_absolute, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_36__abs__}, + {Py_nb_bool, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_48__bool__}, + {Py_nb_true_divide, (void *)__pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec2}, + {Py_sq_length, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__}, + {Py_sq_item, (void *)__pyx_sq_item_5ezdxf_3acc_6vector_Vec2}, + {Py_mp_length, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__}, + {Py_mp_subscript, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_31__getitem__}, + {Py_tp_hash, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_23__hash__}, + {Py_tp_str, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_17__str__}, + {Py_tp_doc, (void *)PyDoc_STR(" Immutable 2D vector.\n\n Init:\n\n - Vec2(vec2)\n - Vec2(vec3)\n - Vec2((x, y))\n - Vec2((x, y, z)), ignore z-axis\n - Vec2(x, y)\n - Vec2(x, y, z), ignore z-axis\n\n ")}, + {Py_tp_richcompare, (void *)__pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec2}, + {Py_tp_iter, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec2_33__iter__}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_6vector_Vec2}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_6vector_Vec2}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector_Vec2}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector_Vec2_spec = { + "ezdxf.acc.vector.Vec2", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_6vector_Vec2_slots, +}; +#else + +static PyNumberMethods __pyx_tp_as_number_Vec2 = { + __pyx_nb_add_5ezdxf_3acc_6vector_Vec2, /*nb_add*/ + __pyx_nb_subtract_5ezdxf_3acc_6vector_Vec2, /*nb_subtract*/ + __pyx_nb_multiply_5ezdxf_3acc_6vector_Vec2, /*nb_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_divide*/ + #endif + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_46__neg__, /*nb_negative*/ + 0, /*nb_positive*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_36__abs__, /*nb_absolute*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_48__bool__, /*nb_bool*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_coerce*/ + #endif + 0, /*nb_int*/ + #if PY_MAJOR_VERSION < 3 + 0, /*nb_long*/ + #else + 0, /*reserved*/ + #endif + 0, /*nb_float*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_oct*/ + #endif + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_hex*/ + #endif + 0, /*nb_inplace_add*/ + 0, /*nb_inplace_subtract*/ + 0, /*nb_inplace_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_inplace_divide*/ + #endif + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + 0, /*nb_inplace_and*/ + 0, /*nb_inplace_xor*/ + 0, /*nb_inplace_or*/ + 0, /*nb_floor_divide*/ + __pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec2, /*nb_true_divide*/ + 0, /*nb_inplace_floor_divide*/ + 0, /*nb_inplace_true_divide*/ + 0, /*nb_index*/ + #if PY_VERSION_HEX >= 0x03050000 + 0, /*nb_matrix_multiply*/ + #endif + #if PY_VERSION_HEX >= 0x03050000 + 0, /*nb_inplace_matrix_multiply*/ + #endif +}; + +static PySequenceMethods __pyx_tp_as_sequence_Vec2 = { + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_5ezdxf_3acc_6vector_Vec2, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_Vec2 = { + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_21__len__, /*mp_length*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_31__getitem__, /*mp_subscript*/ + 0, /*mp_ass_subscript*/ +}; + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector_Vec2 = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""Vec2", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec2, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_19__repr__, /*tp_repr*/ + &__pyx_tp_as_number_Vec2, /*tp_as_number*/ + &__pyx_tp_as_sequence_Vec2, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_Vec2, /*tp_as_mapping*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_23__hash__, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_17__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + PyDoc_STR(" Immutable 2D vector.\n\n Init:\n\n - Vec2(vec2)\n - Vec2(vec3)\n - Vec2((x, y))\n - Vec2((x, y, z)), ignore z-axis\n - Vec2(x, y)\n - Vec2(x, y, z), ignore z-axis\n\n "), /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + __pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec2, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec2_33__iter__, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_6vector_Vec2, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_6vector_Vec2, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector_Vec2, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector_Vec3(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + if (likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + #endif + if (unlikely(__pyx_pw_5ezdxf_3acc_6vector_4Vec3_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec3(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec3) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif +} +static PyObject *__pyx_sq_item_5ezdxf_3acc_6vector_Vec3(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static PyObject *__pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec3(PyObject *o1, PyObject *o2, int op) { + switch (op) { + case Py_EQ: { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_58__eq__(o1, o2); + } + case Py_LT: { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_60__lt__(o1, o2); + } + case Py_NE: { + PyObject *ret; + ret = __pyx_pw_5ezdxf_3acc_6vector_4Vec3_58__eq__(o1, o2); + if (likely(ret && ret != Py_NotImplemented)) { + int b = __Pyx_PyObject_IsTrue(ret); + Py_DECREF(ret); + if (unlikely(b < 0)) return NULL; + ret = (b) ? Py_False : Py_True; + Py_INCREF(ret); + } + return ret; + } + default: { + return __Pyx_NewRef(Py_NotImplemented); + } + } +} +#define __pyx_nb_add_5ezdxf_3acc_6vector_Vec3 __pyx_pw_5ezdxf_3acc_6vector_4Vec3_62__add__ +#define __pyx_nb_subtract_5ezdxf_3acc_6vector_Vec3 __pyx_pw_5ezdxf_3acc_6vector_4Vec3_64__sub__ +#define __pyx_nb_multiply_5ezdxf_3acc_6vector_Vec3 __pyx_pw_5ezdxf_3acc_6vector_4Vec3_68__mul__ +#define __pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec3 __pyx_pw_5ezdxf_3acc_6vector_4Vec3_72__truediv__ + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_xy(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_2xy_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_xyz(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_3xyz_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_vec2(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_4vec2_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_9magnitude_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude_xy(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_12magnitude_xy_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude_square(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_16magnitude_square_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_is_null(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_7is_null_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_spatial_angle(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_13spatial_angle_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_spatial_angle_deg(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_17spatial_angle_deg_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_angle(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_5angle_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_angle_deg(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_9angle_deg_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_x(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_1x_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_y(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_1y_1__get__(o); +} + +static PyObject *__pyx_getprop_5ezdxf_3acc_6vector_4Vec3_z(PyObject *o, CYTHON_UNUSED void *x) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_1z_1__get__(o); +} + +static PyObject *__pyx_specialmethod___pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__(PyObject *self, CYTHON_UNUSED PyObject *arg) { + return __pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__(self); +} + +static PyMethodDef __pyx_methods_5ezdxf_3acc_6vector_Vec3[] = { + {"__reduce__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_3__reduce__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"replace", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_5replace, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"round", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_7round, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"list", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_9list, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"tuple", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_11tuple, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"generate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_13generate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"from_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_15from_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"from_deg_angle", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"random", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_19random, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__repr__", (PyCFunction)__pyx_specialmethod___pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__, METH_NOARGS|METH_COEXIST, 0}, + {"copy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_29copy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__deepcopy__", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"is_parallel", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_40is_parallel, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"orthogonal", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_42orthogonal, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"lerp", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_44lerp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"project", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_46project, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"normalize", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_48normalize, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"reversed", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_50reversed, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"isclose", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_56isclose, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"__rsub__", (PyCFunction)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_66__rsub__, METH_O|METH_COEXIST, 0}, + {"__rmul__", (PyCFunction)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_70__rmul__, METH_O|METH_COEXIST, 0}, + {"sum", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_74sum, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"dot", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_76dot, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"cross", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_78cross, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"distance", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_80distance, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"angle_between", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_82angle_between, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"angle_about", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_84angle_about, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"rotate", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_86rotate, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {"rotate_deg", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_88rotate_deg, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}, + {0, 0, 0, 0} +}; + +static struct PyGetSetDef __pyx_getsets_5ezdxf_3acc_6vector_Vec3[] = { + {(char *)"xy", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_xy, 0, (char *)0, 0}, + {(char *)"xyz", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_xyz, 0, (char *)0, 0}, + {(char *)"vec2", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_vec2, 0, (char *)0, 0}, + {(char *)"magnitude", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude, 0, (char *)0, 0}, + {(char *)"magnitude_xy", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude_xy, 0, (char *)0, 0}, + {(char *)"magnitude_square", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_magnitude_square, 0, (char *)0, 0}, + {(char *)"is_null", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_is_null, 0, (char *)0, 0}, + {(char *)"spatial_angle", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_spatial_angle, 0, (char *)0, 0}, + {(char *)"spatial_angle_deg", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_spatial_angle_deg, 0, (char *)0, 0}, + {(char *)"angle", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_angle, 0, (char *)0, 0}, + {(char *)"angle_deg", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_angle_deg, 0, (char *)0, 0}, + {(char *)"x", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_x, 0, (char *)0, 0}, + {(char *)"y", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_y, 0, (char *)0, 0}, + {(char *)"z", __pyx_getprop_5ezdxf_3acc_6vector_4Vec3_z, 0, (char *)0, 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector_Vec3_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec3}, + {Py_tp_repr, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__}, + {Py_nb_add, (void *)__pyx_nb_add_5ezdxf_3acc_6vector_Vec3}, + {Py_nb_subtract, (void *)__pyx_nb_subtract_5ezdxf_3acc_6vector_Vec3}, + {Py_nb_multiply, (void *)__pyx_nb_multiply_5ezdxf_3acc_6vector_Vec3}, + {Py_nb_negative, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_52__neg__}, + {Py_nb_absolute, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_38__abs__}, + {Py_nb_bool, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_54__bool__}, + {Py_nb_true_divide, (void *)__pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec3}, + {Py_sq_length, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__}, + {Py_sq_item, (void *)__pyx_sq_item_5ezdxf_3acc_6vector_Vec3}, + {Py_mp_length, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__}, + {Py_mp_subscript, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_33__getitem__}, + {Py_tp_hash, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_27__hash__}, + {Py_tp_str, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_21__str__}, + {Py_tp_doc, (void *)PyDoc_STR(" Immutable 3D vector.\n\n Init:\n\n - Vec3()\n - Vec3(vec3)\n - Vec3(vec2)\n - Vec3((x, y))\n - Vec3((x, y, z))\n - Vec3(x, y)\n - Vec3(x, y, z)\n\n ")}, + {Py_tp_richcompare, (void *)__pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec3}, + {Py_tp_iter, (void *)__pyx_pw_5ezdxf_3acc_6vector_4Vec3_35__iter__}, + {Py_tp_methods, (void *)__pyx_methods_5ezdxf_3acc_6vector_Vec3}, + {Py_tp_getset, (void *)__pyx_getsets_5ezdxf_3acc_6vector_Vec3}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector_Vec3}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector_Vec3_spec = { + "ezdxf.acc.vector.Vec3", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, + __pyx_type_5ezdxf_3acc_6vector_Vec3_slots, +}; +#else + +static PyNumberMethods __pyx_tp_as_number_Vec3 = { + __pyx_nb_add_5ezdxf_3acc_6vector_Vec3, /*nb_add*/ + __pyx_nb_subtract_5ezdxf_3acc_6vector_Vec3, /*nb_subtract*/ + __pyx_nb_multiply_5ezdxf_3acc_6vector_Vec3, /*nb_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_divide*/ + #endif + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_52__neg__, /*nb_negative*/ + 0, /*nb_positive*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_38__abs__, /*nb_absolute*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_54__bool__, /*nb_bool*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_coerce*/ + #endif + 0, /*nb_int*/ + #if PY_MAJOR_VERSION < 3 + 0, /*nb_long*/ + #else + 0, /*reserved*/ + #endif + 0, /*nb_float*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_oct*/ + #endif + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_hex*/ + #endif + 0, /*nb_inplace_add*/ + 0, /*nb_inplace_subtract*/ + 0, /*nb_inplace_multiply*/ + #if PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000) + 0, /*nb_inplace_divide*/ + #endif + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + 0, /*nb_inplace_and*/ + 0, /*nb_inplace_xor*/ + 0, /*nb_inplace_or*/ + 0, /*nb_floor_divide*/ + __pyx_nb_true_divide_5ezdxf_3acc_6vector_Vec3, /*nb_true_divide*/ + 0, /*nb_inplace_floor_divide*/ + 0, /*nb_inplace_true_divide*/ + 0, /*nb_index*/ + #if PY_VERSION_HEX >= 0x03050000 + 0, /*nb_matrix_multiply*/ + #endif + #if PY_VERSION_HEX >= 0x03050000 + 0, /*nb_inplace_matrix_multiply*/ + #endif +}; + +static PySequenceMethods __pyx_tp_as_sequence_Vec3 = { + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item_5ezdxf_3acc_6vector_Vec3, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping_Vec3 = { + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_25__len__, /*mp_length*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_33__getitem__, /*mp_subscript*/ + 0, /*mp_ass_subscript*/ +}; + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector_Vec3 = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""Vec3", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector_Vec3, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_23__repr__, /*tp_repr*/ + &__pyx_tp_as_number_Vec3, /*tp_as_number*/ + &__pyx_tp_as_sequence_Vec3, /*tp_as_sequence*/ + &__pyx_tp_as_mapping_Vec3, /*tp_as_mapping*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_27__hash__, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_21__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + PyDoc_STR(" Immutable 3D vector.\n\n Init:\n\n - Vec3()\n - Vec3(vec3)\n - Vec3(vec2)\n - Vec3((x, y))\n - Vec3((x, y, z))\n - Vec3(x, y)\n - Vec3(x, y, z)\n\n "), /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + __pyx_tp_richcompare_5ezdxf_3acc_6vector_Vec3, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + __pyx_pw_5ezdxf_3acc_6vector_4Vec3_35__iter__, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_5ezdxf_3acc_6vector_Vec3, /*tp_methods*/ + 0, /*tp_members*/ + __pyx_getsets_5ezdxf_3acc_6vector_Vec3, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector_Vec3, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr[--__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_item); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr)))) { + __pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr[__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr *)o; + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + } + if (p->__pyx_v_item) { + e = (*v)(p->__pyx_v_item, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr_spec = { + "ezdxf.acc.vector.__pyx_scope_struct__genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""__pyx_scope_struct__genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__[8]; +static int __pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__[--__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__)))) { + __pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__[__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__++] = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter___slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter___spec = { + "ezdxf.acc.vector.__pyx_scope_struct_1___iter__", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter___slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""__pyx_scope_struct_1___iter__", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr[8]; +static int __pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr[--__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_genexpr_arg_0); + Py_CLEAR(p->__pyx_v_item); + Py_CLEAR(p->__pyx_t_0); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr)))) { + __pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr[__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr++] = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr *)o; + if (p->__pyx_genexpr_arg_0) { + e = (*v)(p->__pyx_genexpr_arg_0, a); if (e) return e; + } + if (p->__pyx_v_item) { + e = (*v)(p->__pyx_v_item, a); if (e) return e; + } + if (p->__pyx_t_0) { + e = (*v)(p->__pyx_t_0, a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr_spec = { + "ezdxf.acc.vector.__pyx_scope_struct_2_genexpr", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr_slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""__pyx_scope_struct_2_genexpr", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +#if CYTHON_USE_FREELISTS +static struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__[8]; +static int __pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ = 0; +#endif + +static PyObject *__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_COMPILING_IN_LIMITED_API + allocfunc alloc_func = (allocfunc)PyType_GetSlot(t, Py_tp_alloc); + o = alloc_func(t, 0); + #else + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ > 0) & (int)(t->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__)))) { + o = (PyObject*)__pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__[--__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__]; + memset(o, 0, sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__)); + (void) PyObject_INIT(o, t); + PyObject_GC_Track(o); + } else + #endif + { + o = (*t->tp_alloc)(t, 0); + if (unlikely(!o)) return 0; + } + #endif + return o; +} + +static void __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__(PyObject *o) { + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely((PY_VERSION_HEX >= 0x03080000 || __Pyx_PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE)) && __Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && !__Pyx_PyObject_GC_IsFinalized(o)) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + PyObject_GC_UnTrack(o); + Py_CLEAR(p->__pyx_v_self); + #if CYTHON_USE_FREELISTS + if (((int)(__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ < 8) & (int)(Py_TYPE(o)->tp_basicsize == sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__)))) { + __pyx_freelist_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__[__pyx_freecount_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__++] = ((struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)o); + } else + #endif + { + #if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + (*Py_TYPE(o)->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + } +} + +static int __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *p = (struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ *)o; + if (p->__pyx_v_self) { + e = (*v)(((PyObject *)p->__pyx_v_self), a); if (e) return e; + } + return 0; +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter___slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__}, + {Py_tp_traverse, (void *)__pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__}, + {Py_tp_new, (void *)__pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__}, + {0, 0}, +}; +static PyType_Spec __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter___spec = { + "ezdxf.acc.vector.__pyx_scope_struct_3___iter__", + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, + __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter___slots, +}; +#else + +static PyTypeObject __pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ = { + PyVarObject_HEAD_INIT(0, 0) + "ezdxf.acc.vector.""__pyx_scope_struct_3___iter__", /*tp_name*/ + sizeof(struct __pyx_obj_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif +/* #### Code section: pystring_table ### */ + +static int __Pyx_CreateStringTabAndInitStrings(void) { + __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_n_s_AnyVec, __pyx_k_AnyVec, sizeof(__pyx_k_AnyVec), 0, 0, 1, 1}, + {&__pyx_kp_s_AnyVec_2, __pyx_k_AnyVec_2, sizeof(__pyx_k_AnyVec_2), 0, 0, 1, 0}, + {&__pyx_n_s_IndexError, __pyx_k_IndexError, sizeof(__pyx_k_IndexError), 0, 0, 1, 1}, + {&__pyx_n_s_Iterable, __pyx_k_Iterable, sizeof(__pyx_k_Iterable), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterable_UVec, __pyx_k_Iterable_UVec, sizeof(__pyx_k_Iterable_UVec), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterable_Vec2, __pyx_k_Iterable_Vec2, sizeof(__pyx_k_Iterable_Vec2), 0, 0, 1, 0}, + {&__pyx_n_s_Iterator, __pyx_k_Iterator, sizeof(__pyx_k_Iterator), 0, 0, 1, 1}, + {&__pyx_kp_s_Iterator_Vec2, __pyx_k_Iterator_Vec2, sizeof(__pyx_k_Iterator_Vec2), 0, 0, 1, 0}, + {&__pyx_kp_s_Iterator_Vec3, __pyx_k_Iterator_Vec3, sizeof(__pyx_k_Iterator_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_List, __pyx_k_List, sizeof(__pyx_k_List), 0, 0, 1, 1}, + {&__pyx_kp_s_List_Vec2, __pyx_k_List_Vec2, sizeof(__pyx_k_List_Vec2), 0, 0, 1, 0}, + {&__pyx_kp_s_List_Vec3, __pyx_k_List_Vec3, sizeof(__pyx_k_List_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_NULLVEC, __pyx_k_NULLVEC, sizeof(__pyx_k_NULLVEC), 0, 0, 1, 1}, + {&__pyx_n_s_NotImplemented, __pyx_k_NotImplemented, sizeof(__pyx_k_NotImplemented), 0, 0, 1, 1}, + {&__pyx_n_s_Sequence, __pyx_k_Sequence, sizeof(__pyx_k_Sequence), 0, 0, 1, 1}, + {&__pyx_kp_s_Sequence_Vec2, __pyx_k_Sequence_Vec2, sizeof(__pyx_k_Sequence_Vec2), 0, 0, 1, 0}, + {&__pyx_kp_s_Sequence_Vec3, __pyx_k_Sequence_Vec3, sizeof(__pyx_k_Sequence_Vec3), 0, 0, 1, 0}, + {&__pyx_n_s_TYPE_CHECKING, __pyx_k_TYPE_CHECKING, sizeof(__pyx_k_TYPE_CHECKING), 0, 0, 1, 1}, + {&__pyx_n_s_Tuple, __pyx_k_Tuple, sizeof(__pyx_k_Tuple), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_n_s_UVec, __pyx_k_UVec, sizeof(__pyx_k_UVec), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2, __pyx_k_Vec2, sizeof(__pyx_k_Vec2), 0, 0, 1, 1}, + {&__pyx_n_u_Vec2, __pyx_k_Vec2, sizeof(__pyx_k_Vec2), 0, 1, 0, 1}, + {&__pyx_n_s_Vec2___copy, __pyx_k_Vec2___copy, sizeof(__pyx_k_Vec2___copy), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2___deepcopy, __pyx_k_Vec2___deepcopy, sizeof(__pyx_k_Vec2___deepcopy), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2___iter, __pyx_k_Vec2___iter, sizeof(__pyx_k_Vec2___iter), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2___reduce, __pyx_k_Vec2___reduce, sizeof(__pyx_k_Vec2___reduce), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_angle_between, __pyx_k_Vec2_angle_between, sizeof(__pyx_k_Vec2_angle_between), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_copy, __pyx_k_Vec2_copy, sizeof(__pyx_k_Vec2_copy), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_det, __pyx_k_Vec2_det, sizeof(__pyx_k_Vec2_det), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_distance, __pyx_k_Vec2_distance, sizeof(__pyx_k_Vec2_distance), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_dot, __pyx_k_Vec2_dot, sizeof(__pyx_k_Vec2_dot), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_from_angle, __pyx_k_Vec2_from_angle, sizeof(__pyx_k_Vec2_from_angle), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_from_deg_angle, __pyx_k_Vec2_from_deg_angle, sizeof(__pyx_k_Vec2_from_deg_angle), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_generate, __pyx_k_Vec2_generate, sizeof(__pyx_k_Vec2_generate), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_isclose, __pyx_k_Vec2_isclose, sizeof(__pyx_k_Vec2_isclose), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_lerp, __pyx_k_Vec2_lerp, sizeof(__pyx_k_Vec2_lerp), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_list, __pyx_k_Vec2_list, sizeof(__pyx_k_Vec2_list), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_normalize, __pyx_k_Vec2_normalize, sizeof(__pyx_k_Vec2_normalize), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_orthogonal, __pyx_k_Vec2_orthogonal, sizeof(__pyx_k_Vec2_orthogonal), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_project, __pyx_k_Vec2_project, sizeof(__pyx_k_Vec2_project), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_rotate, __pyx_k_Vec2_rotate, sizeof(__pyx_k_Vec2_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_rotate_deg, __pyx_k_Vec2_rotate_deg, sizeof(__pyx_k_Vec2_rotate_deg), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_round, __pyx_k_Vec2_round, sizeof(__pyx_k_Vec2_round), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_sum, __pyx_k_Vec2_sum, sizeof(__pyx_k_Vec2_sum), 0, 0, 1, 1}, + {&__pyx_n_s_Vec2_tuple, __pyx_k_Vec2_tuple, sizeof(__pyx_k_Vec2_tuple), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3, __pyx_k_Vec3, sizeof(__pyx_k_Vec3), 0, 0, 1, 1}, + {&__pyx_n_u_Vec3, __pyx_k_Vec3, sizeof(__pyx_k_Vec3), 0, 1, 0, 1}, + {&__pyx_n_s_Vec3___deepcopy, __pyx_k_Vec3___deepcopy, sizeof(__pyx_k_Vec3___deepcopy), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3___iter, __pyx_k_Vec3___iter, sizeof(__pyx_k_Vec3___iter), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3___reduce, __pyx_k_Vec3___reduce, sizeof(__pyx_k_Vec3___reduce), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_angle_about, __pyx_k_Vec3_angle_about, sizeof(__pyx_k_Vec3_angle_about), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_angle_between, __pyx_k_Vec3_angle_between, sizeof(__pyx_k_Vec3_angle_between), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_copy, __pyx_k_Vec3_copy, sizeof(__pyx_k_Vec3_copy), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_cross, __pyx_k_Vec3_cross, sizeof(__pyx_k_Vec3_cross), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_distance, __pyx_k_Vec3_distance, sizeof(__pyx_k_Vec3_distance), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_dot, __pyx_k_Vec3_dot, sizeof(__pyx_k_Vec3_dot), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_from_angle, __pyx_k_Vec3_from_angle, sizeof(__pyx_k_Vec3_from_angle), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_from_deg_angle, __pyx_k_Vec3_from_deg_angle, sizeof(__pyx_k_Vec3_from_deg_angle), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_generate, __pyx_k_Vec3_generate, sizeof(__pyx_k_Vec3_generate), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_is_parallel, __pyx_k_Vec3_is_parallel, sizeof(__pyx_k_Vec3_is_parallel), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_isclose, __pyx_k_Vec3_isclose, sizeof(__pyx_k_Vec3_isclose), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_lerp, __pyx_k_Vec3_lerp, sizeof(__pyx_k_Vec3_lerp), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_list, __pyx_k_Vec3_list, sizeof(__pyx_k_Vec3_list), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_normalize, __pyx_k_Vec3_normalize, sizeof(__pyx_k_Vec3_normalize), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_orthogonal, __pyx_k_Vec3_orthogonal, sizeof(__pyx_k_Vec3_orthogonal), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_project, __pyx_k_Vec3_project, sizeof(__pyx_k_Vec3_project), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_random, __pyx_k_Vec3_random, sizeof(__pyx_k_Vec3_random), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_replace, __pyx_k_Vec3_replace, sizeof(__pyx_k_Vec3_replace), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_reversed, __pyx_k_Vec3_reversed, sizeof(__pyx_k_Vec3_reversed), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_rotate, __pyx_k_Vec3_rotate, sizeof(__pyx_k_Vec3_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_rotate_deg, __pyx_k_Vec3_rotate_deg, sizeof(__pyx_k_Vec3_rotate_deg), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_round, __pyx_k_Vec3_round, sizeof(__pyx_k_Vec3_round), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_sum, __pyx_k_Vec3_sum, sizeof(__pyx_k_Vec3_sum), 0, 0, 1, 1}, + {&__pyx_n_s_Vec3_tuple, __pyx_k_Vec3_tuple, sizeof(__pyx_k_Vec3_tuple), 0, 0, 1, 1}, + {&__pyx_n_s_X_AXIS, __pyx_k_X_AXIS, sizeof(__pyx_k_X_AXIS), 0, 0, 1, 1}, + {&__pyx_n_s_Y_AXIS, __pyx_k_Y_AXIS, sizeof(__pyx_k_Y_AXIS), 0, 0, 1, 1}, + {&__pyx_n_s_Z_AXIS, __pyx_k_Z_AXIS, sizeof(__pyx_k_Z_AXIS), 0, 0, 1, 1}, + {&__pyx_n_s__100, __pyx_k__100, sizeof(__pyx_k__100), 0, 0, 1, 1}, + {&__pyx_kp_u__12, __pyx_k__12, sizeof(__pyx_k__12), 0, 1, 0, 0}, + {&__pyx_n_s__13, __pyx_k__13, sizeof(__pyx_k__13), 0, 0, 1, 1}, + {&__pyx_kp_u__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0, 0}, + {&__pyx_kp_u__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 1, 0, 0}, + {&__pyx_kp_u__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0, 0}, + {&__pyx_n_s_a, __pyx_k_a, sizeof(__pyx_k_a), 0, 0, 1, 1}, + {&__pyx_n_s_abs_tol, __pyx_k_abs_tol, sizeof(__pyx_k_abs_tol), 0, 0, 1, 1}, + {&__pyx_n_s_add, __pyx_k_add, sizeof(__pyx_k_add), 0, 0, 1, 1}, + {&__pyx_n_s_angle, __pyx_k_angle, sizeof(__pyx_k_angle), 0, 0, 1, 1}, + {&__pyx_n_s_angle_2, __pyx_k_angle_2, sizeof(__pyx_k_angle_2), 0, 0, 1, 1}, + {&__pyx_n_s_angle_about, __pyx_k_angle_about, sizeof(__pyx_k_angle_about), 0, 0, 1, 1}, + {&__pyx_n_s_angle_between, __pyx_k_angle_between, sizeof(__pyx_k_angle_between), 0, 0, 1, 1}, + {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1}, + {&__pyx_n_s_asyncio_coroutines, __pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 0, 1, 1}, + {&__pyx_n_s_b, __pyx_k_b, sizeof(__pyx_k_b), 0, 0, 1, 1}, + {&__pyx_n_s_base, __pyx_k_base, sizeof(__pyx_k_base), 0, 0, 1, 1}, + {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1}, + {&__pyx_n_s_ccw, __pyx_k_ccw, sizeof(__pyx_k_ccw), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1}, + {&__pyx_n_s_copy, __pyx_k_copy, sizeof(__pyx_k_copy), 0, 0, 1, 1}, + {&__pyx_n_s_copy_2, __pyx_k_copy_2, sizeof(__pyx_k_copy_2), 0, 0, 1, 1}, + {&__pyx_n_s_cross, __pyx_k_cross, sizeof(__pyx_k_cross), 0, 0, 1, 1}, + {&__pyx_n_s_deepcopy, __pyx_k_deepcopy, sizeof(__pyx_k_deepcopy), 0, 0, 1, 1}, + {&__pyx_n_s_det, __pyx_k_det, sizeof(__pyx_k_det), 0, 0, 1, 1}, + {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, + {&__pyx_n_s_dict_2, __pyx_k_dict_2, sizeof(__pyx_k_dict_2), 0, 0, 1, 1}, + {&__pyx_kp_u_disable, __pyx_k_disable, sizeof(__pyx_k_disable), 0, 1, 0, 0}, + {&__pyx_n_s_distance, __pyx_k_distance, sizeof(__pyx_k_distance), 0, 0, 1, 1}, + {&__pyx_n_s_dot, __pyx_k_dot, sizeof(__pyx_k_dot), 0, 0, 1, 1}, + {&__pyx_kp_u_enable, __pyx_k_enable, sizeof(__pyx_k_enable), 0, 1, 0, 0}, + {&__pyx_n_s_ezdxf_acc_vector, __pyx_k_ezdxf_acc_vector, sizeof(__pyx_k_ezdxf_acc_vector), 0, 0, 1, 1}, + {&__pyx_n_s_ezdxf_math, __pyx_k_ezdxf_math, sizeof(__pyx_k_ezdxf_math), 0, 0, 1, 1}, + {&__pyx_n_s_factor, __pyx_k_factor, sizeof(__pyx_k_factor), 0, 0, 1, 1}, + {&__pyx_n_s_float, __pyx_k_float, sizeof(__pyx_k_float), 0, 0, 1, 1}, + {&__pyx_n_s_from_angle, __pyx_k_from_angle, sizeof(__pyx_k_from_angle), 0, 0, 1, 1}, + {&__pyx_n_s_from_deg_angle, __pyx_k_from_deg_angle, sizeof(__pyx_k_from_deg_angle), 0, 0, 1, 1}, + {&__pyx_kp_u_gc, __pyx_k_gc, sizeof(__pyx_k_gc), 0, 1, 0, 0}, + {&__pyx_n_s_generate, __pyx_k_generate, sizeof(__pyx_k_generate), 0, 0, 1, 1}, + {&__pyx_n_s_generate_locals_genexpr, __pyx_k_generate_locals_genexpr, sizeof(__pyx_k_generate_locals_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_genexpr, __pyx_k_genexpr, sizeof(__pyx_k_genexpr), 0, 0, 1, 1}, + {&__pyx_n_s_iadd, __pyx_k_iadd, sizeof(__pyx_k_iadd), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_imul, __pyx_k_imul, sizeof(__pyx_k_imul), 0, 0, 1, 1}, + {&__pyx_n_s_initializing, __pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 0, 1, 1}, + {&__pyx_kp_s_int_None, __pyx_k_int_None, sizeof(__pyx_k_int_None), 0, 0, 1, 0}, + {&__pyx_kp_u_invalid_argument_count, __pyx_k_invalid_argument_count, sizeof(__pyx_k_invalid_argument_count), 0, 1, 0, 0}, + {&__pyx_kp_u_invalid_index, __pyx_k_invalid_index, sizeof(__pyx_k_invalid_index), 0, 1, 0, 0}, + {&__pyx_n_s_is_coroutine, __pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 0, 1, 1}, + {&__pyx_n_s_is_null, __pyx_k_is_null, sizeof(__pyx_k_is_null), 0, 0, 1, 1}, + {&__pyx_n_s_is_parallel, __pyx_k_is_parallel, sizeof(__pyx_k_is_parallel), 0, 0, 1, 1}, + {&__pyx_n_s_isclose, __pyx_k_isclose, sizeof(__pyx_k_isclose), 0, 0, 1, 1}, + {&__pyx_kp_u_isenabled, __pyx_k_isenabled, sizeof(__pyx_k_isenabled), 0, 1, 0, 0}, + {&__pyx_n_s_isub, __pyx_k_isub, sizeof(__pyx_k_isub), 0, 0, 1, 1}, + {&__pyx_n_s_items, __pyx_k_items, sizeof(__pyx_k_items), 0, 0, 1, 1}, + {&__pyx_n_s_iter, __pyx_k_iter, sizeof(__pyx_k_iter), 0, 0, 1, 1}, + {&__pyx_n_s_length, __pyx_k_length, sizeof(__pyx_k_length), 0, 0, 1, 1}, + {&__pyx_n_s_lerp, __pyx_k_lerp, sizeof(__pyx_k_lerp), 0, 0, 1, 1}, + {&__pyx_n_s_list, __pyx_k_list, sizeof(__pyx_k_list), 0, 0, 1, 1}, + {&__pyx_n_s_magnitude, __pyx_k_magnitude, sizeof(__pyx_k_magnitude), 0, 0, 1, 1}, + {&__pyx_n_s_magnitude_2, __pyx_k_magnitude_2, sizeof(__pyx_k_magnitude_2), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_memodict, __pyx_k_memodict, sizeof(__pyx_k_memodict), 0, 0, 1, 1}, + {&__pyx_n_s_mul, __pyx_k_mul, sizeof(__pyx_k_mul), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_ndigits, __pyx_k_ndigits, sizeof(__pyx_k_ndigits), 0, 0, 1, 1}, + {&__pyx_n_s_neg, __pyx_k_neg, sizeof(__pyx_k_neg), 0, 0, 1, 1}, + {&__pyx_n_s_neg_v2, __pyx_k_neg_v2, sizeof(__pyx_k_neg_v2), 0, 0, 1, 1}, + {&__pyx_n_s_normalize, __pyx_k_normalize, sizeof(__pyx_k_normalize), 0, 0, 1, 1}, + {&__pyx_n_s_normalize_deg_angle, __pyx_k_normalize_deg_angle, sizeof(__pyx_k_normalize_deg_angle), 0, 0, 1, 1}, + {&__pyx_n_s_normalize_rad_angle, __pyx_k_normalize_rad_angle, sizeof(__pyx_k_normalize_rad_angle), 0, 0, 1, 1}, + {&__pyx_n_s_o, __pyx_k_o, sizeof(__pyx_k_o), 0, 0, 1, 1}, + {&__pyx_n_s_orthogonal, __pyx_k_orthogonal, sizeof(__pyx_k_orthogonal), 0, 0, 1, 1}, + {&__pyx_n_s_other, __pyx_k_other, sizeof(__pyx_k_other), 0, 0, 1, 1}, + {&__pyx_n_s_p1, __pyx_k_p1, sizeof(__pyx_k_p1), 0, 0, 1, 1}, + {&__pyx_n_s_p2, __pyx_k_p2, sizeof(__pyx_k_p2), 0, 0, 1, 1}, + {&__pyx_n_s_project, __pyx_k_project, sizeof(__pyx_k_project), 0, 0, 1, 1}, + {&__pyx_n_s_radd, __pyx_k_radd, sizeof(__pyx_k_radd), 0, 0, 1, 1}, + {&__pyx_n_s_random, __pyx_k_random, sizeof(__pyx_k_random), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_rel_tol, __pyx_k_rel_tol, sizeof(__pyx_k_rel_tol), 0, 0, 1, 1}, + {&__pyx_n_s_replace, __pyx_k_replace, sizeof(__pyx_k_replace), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_return, __pyx_k_return, sizeof(__pyx_k_return), 0, 0, 1, 1}, + {&__pyx_n_s_reversed, __pyx_k_reversed, sizeof(__pyx_k_reversed), 0, 0, 1, 1}, + {&__pyx_n_s_rotate, __pyx_k_rotate, sizeof(__pyx_k_rotate), 0, 0, 1, 1}, + {&__pyx_n_s_rotate_deg, __pyx_k_rotate_deg, sizeof(__pyx_k_rotate_deg), 0, 0, 1, 1}, + {&__pyx_n_s_round, __pyx_k_round, sizeof(__pyx_k_round), 0, 0, 1, 1}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_self_angle, __pyx_k_self_angle, sizeof(__pyx_k_self_angle), 0, 0, 1, 1}, + {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1}, + {&__pyx_n_s_spatial_angle, __pyx_k_spatial_angle, sizeof(__pyx_k_spatial_angle), 0, 0, 1, 1}, + {&__pyx_n_s_spec, __pyx_k_spec, sizeof(__pyx_k_spec), 0, 0, 1, 1}, + {&__pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_k_src_ezdxf_acc_vector_pyx, sizeof(__pyx_k_src_ezdxf_acc_vector_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_staticmethod, __pyx_k_staticmethod, sizeof(__pyx_k_staticmethod), 0, 0, 1, 1}, + {&__pyx_n_s_str, __pyx_k_str, sizeof(__pyx_k_str), 0, 0, 1, 1}, + {&__pyx_n_s_sub, __pyx_k_sub, sizeof(__pyx_k_sub), 0, 0, 1, 1}, + {&__pyx_n_s_sum, __pyx_k_sum, sizeof(__pyx_k_sum), 0, 0, 1, 1}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_target, __pyx_k_target, sizeof(__pyx_k_target), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1}, + {&__pyx_n_s_tmp, __pyx_k_tmp, sizeof(__pyx_k_tmp), 0, 0, 1, 1}, + {&__pyx_n_s_tuple, __pyx_k_tuple, sizeof(__pyx_k_tuple), 0, 0, 1, 1}, + {&__pyx_n_s_typing, __pyx_k_typing, sizeof(__pyx_k_typing), 0, 0, 1, 1}, + {&__pyx_n_s_uniform, __pyx_k_uniform, sizeof(__pyx_k_uniform), 0, 0, 1, 1}, + {&__pyx_n_s_v, __pyx_k_v, sizeof(__pyx_k_v), 0, 0, 1, 1}, + {&__pyx_n_s_v1, __pyx_k_v1, sizeof(__pyx_k_v1), 0, 0, 1, 1}, + {&__pyx_n_s_v2, __pyx_k_v2, sizeof(__pyx_k_v2), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_xyz, __pyx_k_xyz, sizeof(__pyx_k_xyz), 0, 0, 1, 1}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {&__pyx_n_s_z, __pyx_k_z, sizeof(__pyx_k_z), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} + }; + return __Pyx_InitStrings(__pyx_string_tab); +} +/* #### Code section: cached_builtins ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_staticmethod = __Pyx_GetBuiltinName(__pyx_n_s_staticmethod); if (!__pyx_builtin_staticmethod) __PYX_ERR(0, 106, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 89, __pyx_L1_error) + __pyx_builtin_round = __Pyx_GetBuiltinName(__pyx_n_s_round); if (!__pyx_builtin_round) __PYX_ERR(0, 104, __pyx_L1_error) + __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) __PYX_ERR(0, 153, __pyx_L1_error) + __pyx_builtin_NotImplemented = __Pyx_GetBuiltinName(__pyx_n_s_NotImplemented); if (!__pyx_builtin_NotImplemented) __PYX_ERR(0, 245, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cached_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "ezdxf/acc/vector.pyx":89 + * # ignore z-axis but raise error for 4 or more arguments + * if count > 3: + * raise TypeError('invalid argument count') # <<<<<<<<<<<<<< + * + * # slow init by sequence + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_invalid_argument_count); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "ezdxf/acc/vector.pyx":482 + * cdef Vec3 res = Vec3() + * uniform = random.uniform + * res.x = uniform(-1, 1) # <<<<<<<<<<<<<< + * res.y = uniform(-1, 1) + * res.z = uniform(-1, 1) + */ + __pyx_tuple__7 = PyTuple_Pack(2, __pyx_int_neg_1, __pyx_int_1); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + + /* "ezdxf/acc/vector.pyx":35 + * return res + * + * def _normalize_rad_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_rad_angle(angle) + */ + __pyx_tuple__14 = PyTuple_Pack(1, __pyx_n_s_angle); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_normalize_rad_angle, 35, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) __PYX_ERR(0, 35, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":46 + * return res + * + * def _normalize_deg_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_deg_angle(angle) + */ + __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_normalize_deg_angle, 46, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(0, 46, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":95 + * self.y = args[1] + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec2, (self.x, self.y) + * + */ + __pyx_tuple__17 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + __pyx_codeobj__18 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_reduce, 95, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__18)) __PYX_ERR(0, 95, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":102 + * return Vec3(self) + * + * def round(self, ndigits=None) -> Vec2: # <<<<<<<<<<<<<< + * # only used for testing + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + */ + __pyx_tuple__19 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_ndigits); if (unlikely(!__pyx_tuple__19)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__19); + __Pyx_GIVEREF(__pyx_tuple__19); + __pyx_codeobj__20 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_round, 102, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(0, 102, __pyx_L1_error) + __pyx_tuple__21 = PyTuple_Pack(1, Py_None); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__21); + __Pyx_GIVEREF(__pyx_tuple__21); + + /* "ezdxf/acc/vector.pyx":106 + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec2]: + * return list(Vec2.generate(items)) + */ + __pyx_tuple__22 = PyTuple_Pack(1, __pyx_n_s_items); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_list, 106, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 106, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":110 + * return list(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + * return tuple(Vec2.generate(items)) + */ + __pyx_codeobj__24 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_tuple, 110, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__24)) __PYX_ERR(0, 110, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":114 + * return tuple(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) + */ + __pyx_tuple__25 = PyTuple_Pack(3, __pyx_n_s_items, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__25); + __Pyx_GIVEREF(__pyx_tuple__25); + __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_generate, 114, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 114, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":118 + * return (Vec2(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle, length) + */ + __pyx_tuple__27 = PyTuple_Pack(2, __pyx_n_s_angle, __pyx_n_s_length); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_from_angle, 118, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(0, 118, __pyx_L1_error) + __pyx_tuple__29 = PyTuple_Pack(1, __pyx_float_1_0); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__29); + __Pyx_GIVEREF(__pyx_tuple__29); + + /* "ezdxf/acc/vector.pyx":122 + * return v2_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle * DEG2RAD, length) + */ + __pyx_codeobj__30 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_from_deg_angle, 122, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__30)) __PYX_ERR(0, 122, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":138 + * return hash((self.x, self.y)) + * + * def copy(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_codeobj__31 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_copy, 138, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__31)) __PYX_ERR(0, 138, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":141 + * return self # immutable + * + * def __copy__(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_codeobj__32 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_copy_2, 141, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__32)) __PYX_ERR(0, 141, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":144 + * return self # immutable + * + * def __deepcopy__(self, memodict: dict) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_tuple__33 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_memodict); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__33); + __Pyx_GIVEREF(__pyx_tuple__33); + __pyx_codeobj__34 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_deepcopy, 144, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__34)) __PYX_ERR(0, 144, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":178 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec2: # <<<<<<<<<<<<<< + * return v2_ortho(self, ccw) + * + */ + __pyx_tuple__35 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_ccw); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(0, 178, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__35); + __Pyx_GIVEREF(__pyx_tuple__35); + __pyx_codeobj__36 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_orthogonal, 178, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__36)) __PYX_ERR(0, 178, __pyx_L1_error) + __pyx_tuple__37 = PyTuple_Pack(1, Py_True); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(0, 178, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__37); + __Pyx_GIVEREF(__pyx_tuple__37); + + /* "ezdxf/acc/vector.pyx":181 + * return v2_ortho(self, ccw) + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_lerp(self, o, factor) + */ + __pyx_tuple__38 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_factor, __pyx_n_s_o); if (unlikely(!__pyx_tuple__38)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__38); + __Pyx_GIVEREF(__pyx_tuple__38); + __pyx_codeobj__39 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__38, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_lerp, 181, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__39)) __PYX_ERR(0, 181, __pyx_L1_error) + __pyx_tuple__40 = PyTuple_Pack(1, __pyx_float_0_5); if (unlikely(!__pyx_tuple__40)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__40); + __Pyx_GIVEREF(__pyx_tuple__40); + + /* "ezdxf/acc/vector.pyx":185 + * return v2_lerp(self, o, factor) + * + * def normalize(self, double length = 1.) -> Vec2: # <<<<<<<<<<<<<< + * return v2_normalize(self, length) + * + */ + __pyx_tuple__41 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_length); if (unlikely(!__pyx_tuple__41)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__41); + __Pyx_GIVEREF(__pyx_tuple__41); + __pyx_codeobj__42 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__41, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_normalize, 185, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__42)) __PYX_ERR(0, 185, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":188 + * return v2_normalize(self, length) + * + * def project(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_project(self, o) + */ + __pyx_tuple__43 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_o); if (unlikely(!__pyx_tuple__43)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__43); + __Pyx_GIVEREF(__pyx_tuple__43); + __pyx_codeobj__44 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_project, 188, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__44)) __PYX_ERR(0, 188, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + __pyx_tuple__45 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_rel_tol, __pyx_n_s_abs_tol, __pyx_n_s_o); if (unlikely(!__pyx_tuple__45)) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__45); + __Pyx_GIVEREF(__pyx_tuple__45); + __pyx_codeobj__46 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__45, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_isclose, 203, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__46)) __PYX_ERR(0, 203, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":260 + * # __rtruediv__ not supported -> TypeError + * + * def dot(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dot(self, o) + */ + __pyx_codeobj__47 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_dot, 260, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__47)) __PYX_ERR(0, 260, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":264 + * return v2_dot(self, o) + * + * def det(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_det(self, o) + */ + __pyx_codeobj__48 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_det, 264, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__48)) __PYX_ERR(0, 264, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":268 + * return v2_det(self, o) + * + * def distance(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dist(self, o) + */ + __pyx_codeobj__49 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_distance, 268, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__49)) __PYX_ERR(0, 268, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":272 + * return v2_dist(self, o) + * + * def angle_between(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_angle_between(self, o) + */ + __pyx_codeobj__50 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_angle_between, 272, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__50)) __PYX_ERR(0, 272, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":276 + * return v2_angle_between(self, o) + * + * def rotate(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) + */ + __pyx_tuple__51 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_angle, __pyx_n_s_self_angle, __pyx_n_s_magnitude); if (unlikely(!__pyx_tuple__51)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__51); + __Pyx_GIVEREF(__pyx_tuple__51); + __pyx_codeobj__52 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__51, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_rotate, 276, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__52)) __PYX_ERR(0, 276, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":281 + * return v2_from_angle(self_angle + angle, magnitude) + * + * def rotate_deg(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + __pyx_tuple__53 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_angle); if (unlikely(!__pyx_tuple__53)) __PYX_ERR(0, 281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__53); + __Pyx_GIVEREF(__pyx_tuple__53); + __pyx_codeobj__54 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__53, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_rotate_deg, 281, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__54)) __PYX_ERR(0, 281, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":284 + * return self.rotate(angle * DEG2RAD) + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[Vec2]) -> Vec2: + * cdef Vec2 res = Vec2() + */ + __pyx_tuple__55 = PyTuple_Pack(4, __pyx_n_s_items, __pyx_n_s_res, __pyx_n_s_tmp, __pyx_n_s_v); if (unlikely(!__pyx_tuple__55)) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__55); + __Pyx_GIVEREF(__pyx_tuple__55); + __pyx_codeobj__56 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__55, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_sum, 284, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__56)) __PYX_ERR(0, 284, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":422 + * self.z = 0.0 + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec3, self.xyz + * + */ + __pyx_codeobj__57 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_reduce, 422, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__57)) __PYX_ERR(0, 422, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":443 + * return res + * + * def replace(self, x: float = None, y: float = None, # <<<<<<<<<<<<<< + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_tuple__58 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z, __pyx_n_s_res); if (unlikely(!__pyx_tuple__58)) __PYX_ERR(0, 443, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__58); + __Pyx_GIVEREF(__pyx_tuple__58); + __pyx_codeobj__59 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__58, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_replace, 443, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__59)) __PYX_ERR(0, 443, __pyx_L1_error) + __pyx_tuple__60 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__60)) __PYX_ERR(0, 443, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__60); + __Pyx_GIVEREF(__pyx_tuple__60); + + /* "ezdxf/acc/vector.pyx":451 + * return res + * + * def round(self, ndigits: int | None = None) -> Vec3: # <<<<<<<<<<<<<< + * return Vec3( + * round(self.x, ndigits), + */ + __pyx_codeobj__61 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_round, 451, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__61)) __PYX_ERR(0, 451, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":458 + * ) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec3]: + * return list(Vec3.generate(items)) + */ + __pyx_codeobj__62 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_list, 458, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__62)) __PYX_ERR(0, 458, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":462 + * return list(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + * return tuple(Vec3.generate(items)) + */ + __pyx_codeobj__63 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_tuple, 462, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__63)) __PYX_ERR(0, 462, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":466 + * return tuple(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) + */ + __pyx_codeobj__64 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_generate, 466, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__64)) __PYX_ERR(0, 466, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":470 + * return (Vec3(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle, length) + */ + __pyx_codeobj__65 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_from_angle, 470, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__65)) __PYX_ERR(0, 470, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":474 + * return v3_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle * DEG2RAD, length) + */ + __pyx_codeobj__66 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__27, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_from_deg_angle, 474, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__66)) __PYX_ERR(0, 474, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":478 + * return v3_from_angle(angle * DEG2RAD, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_tuple__67 = PyTuple_Pack(3, __pyx_n_s_length, __pyx_n_s_res, __pyx_n_s_uniform); if (unlikely(!__pyx_tuple__67)) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__67); + __Pyx_GIVEREF(__pyx_tuple__67); + __pyx_codeobj__68 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__67, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_random, 478, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__68)) __PYX_ERR(0, 478, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":499 + * return hash(self.xyz) + * + * def copy(self) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_codeobj__69 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_copy, 499, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__69)) __PYX_ERR(0, 499, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":504 + * __copy__ = copy + * + * def __deepcopy__(self, memodict: dict) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable! + * + */ + __pyx_codeobj__70 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_deepcopy, 504, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__70)) __PYX_ERR(0, 504, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + __pyx_tuple__71 = PyTuple_Pack(8, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_rel_tol, __pyx_n_s_abs_tol, __pyx_n_s_o, __pyx_n_s_v1, __pyx_n_s_v2, __pyx_n_s_neg_v2); if (unlikely(!__pyx_tuple__71)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__71); + __Pyx_GIVEREF(__pyx_tuple__71); + __pyx_codeobj__72 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 8, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__71, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_is_parallel, 542, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__72)) __PYX_ERR(0, 542, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":567 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec3: # <<<<<<<<<<<<<< + * return v3_ortho(self, ccw) + * + */ + __pyx_codeobj__73 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__35, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_orthogonal, 567, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__73)) __PYX_ERR(0, 567, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":570 + * return v3_ortho(self, ccw) + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_tuple__74 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_factor); if (unlikely(!__pyx_tuple__74)) __PYX_ERR(0, 570, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__74); + __Pyx_GIVEREF(__pyx_tuple__74); + __pyx_codeobj__75 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__74, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_lerp, 570, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__75)) __PYX_ERR(0, 570, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":575 + * return v3_lerp(self, other, factor) + * + * def project(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_tuple__76 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_other); if (unlikely(!__pyx_tuple__76)) __PYX_ERR(0, 575, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__76); + __Pyx_GIVEREF(__pyx_tuple__76); + __pyx_codeobj__77 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__76, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_project, 575, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__77)) __PYX_ERR(0, 575, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":580 + * return v3_project(self, other) + * + * def normalize(self, double length = 1.) -> Vec3: # <<<<<<<<<<<<<< + * return v3_normalize(self, length) + * + */ + __pyx_codeobj__78 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__41, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_normalize, 580, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__78)) __PYX_ERR(0, 580, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":583 + * return v3_normalize(self, length) + * + * def reversed(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + __pyx_codeobj__79 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_reversed, 583, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__79)) __PYX_ERR(0, 583, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + __pyx_tuple__80 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_other, __pyx_n_s_rel_tol, __pyx_n_s_abs_tol); if (unlikely(!__pyx_tuple__80)) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__80); + __Pyx_GIVEREF(__pyx_tuple__80); + __pyx_codeobj__81 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__80, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_isclose, 592, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__81)) __PYX_ERR(0, 592, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":658 + * # __rtruediv__ not supported -> TypeError + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[UVec]) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_codeobj__82 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__55, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_sum, 658, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__82)) __PYX_ERR(0, 658, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":669 + * return res + * + * def dot(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dot(self, o) + */ + __pyx_codeobj__83 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_dot, 669, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__83)) __PYX_ERR(0, 669, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":673 + * return v3_dot(self, o) + * + * def cross(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_cross(self, o) + */ + __pyx_codeobj__84 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_cross, 673, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__84)) __PYX_ERR(0, 673, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":677 + * return v3_cross(self, o) + * + * def distance(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dist(self, o) + */ + __pyx_codeobj__85 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_distance, 677, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__85)) __PYX_ERR(0, 677, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":681 + * return v3_dist(self, o) + * + * def angle_between(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_angle_between(self, o) + */ + __pyx_codeobj__86 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_angle_between, 681, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__86)) __PYX_ERR(0, 681, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":685 + * return v3_angle_between(self, o) + * + * def angle_about(self, base: UVec, target: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) + */ + __pyx_tuple__87 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_base, __pyx_n_s_target, __pyx_n_s_b, __pyx_n_s_t); if (unlikely(!__pyx_tuple__87)) __PYX_ERR(0, 685, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__87); + __Pyx_GIVEREF(__pyx_tuple__87); + __pyx_codeobj__88 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__87, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_angle_about, 685, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__88)) __PYX_ERR(0, 685, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":690 + * return v3_angle_about(self, b, t) + * + * def rotate(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) + */ + __pyx_tuple__89 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_angle, __pyx_n_s_angle_2, __pyx_n_s_magnitude_2, __pyx_n_s_res); if (unlikely(!__pyx_tuple__89)) __PYX_ERR(0, 690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__89); + __Pyx_GIVEREF(__pyx_tuple__89); + __pyx_codeobj__90 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__89, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_rotate, 690, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__90)) __PYX_ERR(0, 690, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":697 + * return res + * + * def rotate_deg(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + __pyx_codeobj__91 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 2, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__53, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_rotate_deg, 697, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__91)) __PYX_ERR(0, 697, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":701 + * + * + * X_AXIS = Vec3(1, 0, 0) # <<<<<<<<<<<<<< + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) + */ + __pyx_tuple__92 = PyTuple_Pack(3, __pyx_int_1, __pyx_int_0, __pyx_int_0); if (unlikely(!__pyx_tuple__92)) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__92); + __Pyx_GIVEREF(__pyx_tuple__92); + + /* "ezdxf/acc/vector.pyx":702 + * + * X_AXIS = Vec3(1, 0, 0) + * Y_AXIS = Vec3(0, 1, 0) # <<<<<<<<<<<<<< + * Z_AXIS = Vec3(0, 0, 1) + * NULLVEC = Vec3(0, 0, 0) + */ + __pyx_tuple__93 = PyTuple_Pack(3, __pyx_int_0, __pyx_int_1, __pyx_int_0); if (unlikely(!__pyx_tuple__93)) __PYX_ERR(0, 702, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__93); + __Pyx_GIVEREF(__pyx_tuple__93); + + /* "ezdxf/acc/vector.pyx":703 + * X_AXIS = Vec3(1, 0, 0) + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) # <<<<<<<<<<<<<< + * NULLVEC = Vec3(0, 0, 0) + * + */ + __pyx_tuple__94 = PyTuple_Pack(3, __pyx_int_0, __pyx_int_0, __pyx_int_1); if (unlikely(!__pyx_tuple__94)) __PYX_ERR(0, 703, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__94); + __Pyx_GIVEREF(__pyx_tuple__94); + + /* "ezdxf/acc/vector.pyx":704 + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) + * NULLVEC = Vec3(0, 0, 0) # <<<<<<<<<<<<<< + * + * cdef Vec3 v3_add(Vec3 a, Vec3 b): + */ + __pyx_tuple__95 = PyTuple_Pack(3, __pyx_int_0, __pyx_int_0, __pyx_int_0); if (unlikely(!__pyx_tuple__95)) __PYX_ERR(0, 704, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__95); + __Pyx_GIVEREF(__pyx_tuple__95); + + /* "ezdxf/acc/vector.pyx":829 + * + * + * def distance(p1: UVec, p2: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + __pyx_tuple__96 = PyTuple_Pack(4, __pyx_n_s_p1, __pyx_n_s_p2, __pyx_n_s_a, __pyx_n_s_b); if (unlikely(!__pyx_tuple__96)) __PYX_ERR(0, 829, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__96); + __Pyx_GIVEREF(__pyx_tuple__96); + __pyx_codeobj__97 = (PyObject*)__Pyx_PyCode_New(2, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__96, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_distance, 829, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__97)) __PYX_ERR(0, 829, __pyx_L1_error) + + /* "ezdxf/acc/vector.pyx":835 + * + * + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + __pyx_tuple__98 = PyTuple_Pack(5, __pyx_n_s_p1, __pyx_n_s_p2, __pyx_n_s_factor, __pyx_n_s_a, __pyx_n_s_b); if (unlikely(!__pyx_tuple__98)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__98); + __Pyx_GIVEREF(__pyx_tuple__98); + __pyx_codeobj__99 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__98, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_src_ezdxf_acc_vector_pyx, __pyx_n_s_lerp, 835, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__99)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} +/* #### Code section: init_constants ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitConstants(void) { + if (__Pyx_CreateStringTabAndInitStrings() < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_float_1_ = PyFloat_FromDouble(1.); if (unlikely(!__pyx_float_1_)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_0_5 = PyFloat_FromDouble(0.5); if (unlikely(!__pyx_float_0_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_1_0 = PyFloat_FromDouble(1.0); if (unlikely(!__pyx_float_1_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_globals ### */ + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + return 0; +} +/* #### Code section: init_module ### */ + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + if (__Pyx_ExportFunction("isclose", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_isclose, "int (double, double, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("normalize_rad_angle", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_normalize_rad_angle, "double (double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("normalize_deg_angle", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_normalize_deg_angle, "double (double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_add", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_sub", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_sub, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_mul", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_normalize", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_normalize, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_dot", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_dot, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_det", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_det, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_dist", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_dist, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_from_angle", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_from_angle, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_angle_between", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_angle_between, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_lerp", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_lerp, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_ortho", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_ortho, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, int)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_project", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_project, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v2_isclose", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v2_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec2 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_add", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_add, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_sub", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_sub, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_mul", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_mul, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_reverse", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_reverse, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_dot", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_dot, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_cross", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_cross, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_magnitude_sqr", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_magnitude_sqr, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_magnitude", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_magnitude, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_dist", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_dist, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_from_angle", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_from_angle, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_angle_between", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_angle_between, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_angle_about", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_angle_about, "double (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_normalize", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_normalize, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_lerp", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_lerp, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_ortho", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_ortho, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, int)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_project", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_project, "struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *(struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_ExportFunction("v3_isclose", (void (*)(void))__pyx_f_5ezdxf_3acc_6vector_v3_isclose, "int (struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, struct __pyx_obj_5ezdxf_3acc_6vector_Vec3 *, double, double)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector_Vec2_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector_Vec2)) __PYX_ERR(0, 50, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector_Vec2_spec, __pyx_ptype_5ezdxf_3acc_6vector_Vec2) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector_Vec2 = &__pyx_type_5ezdxf_3acc_6vector_Vec2; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector_Vec2) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector_Vec2->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector_Vec2->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector_Vec2->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector_Vec2->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Vec2, (PyObject *) __pyx_ptype_5ezdxf_3acc_6vector_Vec2) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector_Vec3_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector_Vec3)) __PYX_ERR(0, 371, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector_Vec3_spec, __pyx_ptype_5ezdxf_3acc_6vector_Vec3) < 0) __PYX_ERR(0, 371, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector_Vec3 = &__pyx_type_5ezdxf_3acc_6vector_Vec3; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector_Vec3) < 0) __PYX_ERR(0, 371, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector_Vec3->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector_Vec3->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector_Vec3->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector_Vec3->tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + #endif + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Vec3, (PyObject *) __pyx_ptype_5ezdxf_3acc_6vector_Vec3) < 0) __PYX_ERR(0, 371, __pyx_L1_error) + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr)) __PYX_ERR(0, 116, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr_spec, __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr) < 0) __PYX_ERR(0, 116, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr = &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr) < 0) __PYX_ERR(0, 116, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct__genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter___spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__)) __PYX_ERR(0, 155, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter___spec, __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__) < 0) __PYX_ERR(0, 155, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__ = &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__) < 0) __PYX_ERR(0, 155, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_1___iter__->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr_spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr)) __PYX_ERR(0, 468, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr_spec, __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr) < 0) __PYX_ERR(0, 468, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr = &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr) < 0) __PYX_ERR(0, 468, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_2_genexpr->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + #if CYTHON_USE_TYPE_SPECS + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter___spec, NULL); if (unlikely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__)) __PYX_ERR(0, 517, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter___spec, __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__) < 0) __PYX_ERR(0, 517, __pyx_L1_error) + #else + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__ = &__pyx_type_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__) < 0) __PYX_ERR(0, 517, __pyx_L1_error) + #endif + #if PY_MAJOR_VERSION < 3 + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__->tp_print = 0; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__->tp_dictoffset && __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_ptype_5ezdxf_3acc_6vector___pyx_scope_struct_3___iter__->tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + } + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_vector(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_vector}, + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "vector", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #elif CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstate), /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif +#endif + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initvector(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initvector(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_vector(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_vector(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *module, const char* from_name, const char* to_name, int allow_none) +#else +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +#endif +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { +#if CYTHON_COMPILING_IN_LIMITED_API + result = PyModule_AddObject(module, to_name, value); +#else + result = PyDict_SetItemString(moddict, to_name, value); +#endif + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; +#if CYTHON_COMPILING_IN_LIMITED_API + moddict = module; +#else + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; +#endif + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_vector(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'vector' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("vector", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #elif CYTHON_USE_MODULE_STATE + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + { + int add_module_result = PyState_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "vector" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #endif + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = __Pyx_PyImport_AddModuleRef((const char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_vector(void)", 0); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_ezdxf__acc__vector) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "ezdxf.acc.vector")) { + if (unlikely((PyDict_SetItemString(modules, "ezdxf.acc.vector", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + if (unlikely((__Pyx_modinit_function_export_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + if (unlikely((__Pyx_modinit_type_init_code() < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_type_import_code(); + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "ezdxf/acc/vector.pyx":5 + * # Copyright (c) 2020-2024, Manfred Moitzi + * # License: MIT License + * from typing import Iterable, List, Sequence, TYPE_CHECKING, Tuple, Iterator # <<<<<<<<<<<<<< + * from libc.math cimport fabs, sin, cos, M_PI, hypot, atan2, acos, sqrt, fmod + * import random + */ + __pyx_t_2 = PyList_New(6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_INCREF(__pyx_n_s_Iterable); + __Pyx_GIVEREF(__pyx_n_s_Iterable); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_Iterable)) __PYX_ERR(0, 5, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_List); + __Pyx_GIVEREF(__pyx_n_s_List); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_List)) __PYX_ERR(0, 5, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Sequence); + __Pyx_GIVEREF(__pyx_n_s_Sequence); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_Sequence)) __PYX_ERR(0, 5, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_TYPE_CHECKING); + __Pyx_GIVEREF(__pyx_n_s_TYPE_CHECKING); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_n_s_TYPE_CHECKING)) __PYX_ERR(0, 5, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Tuple); + __Pyx_GIVEREF(__pyx_n_s_Tuple); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 4, __pyx_n_s_Tuple)) __PYX_ERR(0, 5, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_Iterator); + __Pyx_GIVEREF(__pyx_n_s_Iterator); + if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 5, __pyx_n_s_Iterator)) __PYX_ERR(0, 5, __pyx_L1_error); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterable); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterable, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_List); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_List, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Sequence); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Sequence, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_TYPE_CHECKING, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Tuple); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Tuple, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Iterator); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Iterator, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":7 + * from typing import Iterable, List, Sequence, TYPE_CHECKING, Tuple, Iterator + * from libc.math cimport fabs, sin, cos, M_PI, hypot, atan2, acos, sqrt, fmod + * import random # <<<<<<<<<<<<<< + * + * cdef extern from "constants.h": + */ + __pyx_t_3 = __Pyx_ImportDottedModule(__pyx_n_s_random, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_random, __pyx_t_3) < 0) __PYX_ERR(0, 7, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":14 + * const double M_TAU + * + * cdef double RAD2DEG = 180.0 / M_PI # <<<<<<<<<<<<<< + * cdef double DEG2RAD = M_PI / 180.0 + * + */ + if (unlikely(M_PI == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 14, __pyx_L1_error) + } + __pyx_v_5ezdxf_3acc_6vector_RAD2DEG = (180.0 / ((double)M_PI)); + + /* "ezdxf/acc/vector.pyx":15 + * + * cdef double RAD2DEG = 180.0 / M_PI + * cdef double DEG2RAD = M_PI / 180.0 # <<<<<<<<<<<<<< + * + * if TYPE_CHECKING: + */ + __pyx_v_5ezdxf_3acc_6vector_DEG2RAD = (((double)M_PI) / 180.0); + + /* "ezdxf/acc/vector.pyx":17 + * cdef double DEG2RAD = M_PI / 180.0 + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import AnyVec, UVec + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_TYPE_CHECKING); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 17, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "ezdxf/acc/vector.pyx":18 + * + * if TYPE_CHECKING: + * from ezdxf.math import AnyVec, UVec # <<<<<<<<<<<<<< + * + * cdef bint isclose(double a, double b, double rel_tol, double abs_tol): + */ + __pyx_t_3 = PyList_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_AnyVec); + __Pyx_GIVEREF(__pyx_n_s_AnyVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_AnyVec)) __PYX_ERR(0, 18, __pyx_L1_error); + __Pyx_INCREF(__pyx_n_s_UVec); + __Pyx_GIVEREF(__pyx_n_s_UVec); + if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_UVec)) __PYX_ERR(0, 18, __pyx_L1_error); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_ezdxf_math, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_AnyVec); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_AnyVec, __pyx_t_3) < 0) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_UVec); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_UVec, __pyx_t_3) < 0) __PYX_ERR(0, 18, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":17 + * cdef double DEG2RAD = M_PI / 180.0 + * + * if TYPE_CHECKING: # <<<<<<<<<<<<<< + * from ezdxf.math import AnyVec, UVec + * + */ + } + + /* "ezdxf/acc/vector.pyx":35 + * return res + * + * def _normalize_rad_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_rad_angle(angle) + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_1_normalize_rad_angle, 0, __pyx_n_s_normalize_rad_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_normalize_rad_angle, __pyx_t_2) < 0) __PYX_ERR(0, 35, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":46 + * return res + * + * def _normalize_deg_angle(double angle): # <<<<<<<<<<<<<< + * # just for testing + * return normalize_deg_angle(angle) + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_3_normalize_deg_angle, 0, __pyx_n_s_normalize_deg_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__16)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_normalize_deg_angle, __pyx_t_2) < 0) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":95 + * self.y = args[1] + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec2, (self.x, self.y) + * + */ + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_3__reduce__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2___reduce, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__18)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_reduce, __pyx_t_2) < 0) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":102 + * return Vec3(self) + * + * def round(self, ndigits=None) -> Vec2: # <<<<<<<<<<<<<< + * # only used for testing + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 102, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_5round, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_round, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__20)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__21); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_round, __pyx_t_3) < 0) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":106 + * return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec2]: + * return list(Vec2.generate(items)) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 106, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_List_Vec2) < 0) __PYX_ERR(0, 106, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_7list, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_list, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_list, __pyx_t_2) < 0) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_list); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_list, __pyx_t_3) < 0) __PYX_ERR(0, 106, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":110 + * return list(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + * return tuple(Vec2.generate(items)) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 110, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Sequence_Vec2) < 0) __PYX_ERR(0, 110, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_9tuple, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_tuple, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__24)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_tuple, __pyx_t_2) < 0) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_tuple); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_tuple, __pyx_t_3) < 0) __PYX_ERR(0, 110, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":114 + * return tuple(Vec2.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + * return (Vec2(item) for item in items) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec2) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_11generate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_generate, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_generate, __pyx_t_2) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_generate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_generate, __pyx_t_3) < 0) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":118 + * return (Vec2(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle, length) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 118, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_13from_angle, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_from_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__28)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_angle, __pyx_t_2) < 0) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_angle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_angle, __pyx_t_3) < 0) __PYX_ERR(0, 118, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":122 + * return v2_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec2: + * return v2_from_angle(angle * DEG2RAD, length) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 122, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_15from_deg_angle, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_from_deg_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__30)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_deg_angle, __pyx_t_2) < 0) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_deg_angle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_from_deg_angle, __pyx_t_3) < 0) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":138 + * return hash((self.x, self.y)) + * + * def copy(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 138, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_25copy, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_copy, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__31)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_copy, __pyx_t_2) < 0) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":141 + * return self # immutable + * + * def __copy__(self) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 141, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_27__copy__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2___copy, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__32)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_copy_2, __pyx_t_3) < 0) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":144 + * return self # immutable + * + * def __deepcopy__(self, memodict: dict) -> Vec2: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_memodict, __pyx_n_s_dict_2) < 0) __PYX_ERR(0, 144, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 144, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_29__deepcopy__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2___deepcopy, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__34)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_deepcopy, __pyx_t_2) < 0) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":178 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec2: # <<<<<<<<<<<<<< + * return v2_ortho(self, ccw) + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 178, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_ccw, __pyx_n_s_bool) < 0) __PYX_ERR(0, 178, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 178, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_38orthogonal, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_orthogonal, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__36)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 178, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__37); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_orthogonal, __pyx_t_3) < 0) __PYX_ERR(0, 178, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":181 + * return v2_ortho(self, ccw) + * + * def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_lerp(self, o, factor) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_kp_s_AnyVec_2) < 0) __PYX_ERR(0, 181, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 181, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_40lerp, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_lerp, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__39)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__40); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_lerp, __pyx_t_2) < 0) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":185 + * return v2_lerp(self, o, factor) + * + * def normalize(self, double length = 1.) -> Vec2: # <<<<<<<<<<<<<< + * return v2_normalize(self, length) + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 185, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_42normalize, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_normalize, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__42)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_normalize, __pyx_t_3) < 0) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":188 + * return v2_normalize(self, length) + * + * def project(self, other: AnyVec) -> Vec2: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_project(self, o) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_AnyVec) < 0) __PYX_ERR(0, 188, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 188, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_44project, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_project, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__44)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_project, __pyx_t_2) < 0) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":198 + * return res + * + * reversed = __neg__ # <<<<<<<<<<<<<< + * + * def __bool__(self) -> bool: + */ + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_neg); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_reversed, __pyx_t_2) < 0) __PYX_ERR(0, 198, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + __pyx_k__5 = REL_TOL; + + /* "ezdxf/acc/vector.pyx":204 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return isclose(self.x, o.x, rel_tol, abs_tol) and \ + */ + __pyx_k__6 = ABS_TOL; + + /* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble(REL_TOL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_rel_tol, __pyx_t_3) < 0) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":204 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return isclose(self.x, o.x, rel_tol, abs_tol) and \ + */ + __pyx_t_3 = PyFloat_FromDouble(ABS_TOL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_abs_tol, __pyx_t_3) < 0) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":203 + * return self.x != 0 or self.y != 0 + * + * def isclose(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec2 o = Vec2(other) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 203, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 203, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_50isclose, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_isclose, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__46)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsKwDict(__pyx_t_5, __pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_isclose, __pyx_t_5) < 0) __PYX_ERR(0, 203, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":228 + * # __radd__ not supported for Vec2 + * + * __iadd__ = __add__ # immutable # <<<<<<<<<<<<<< + * + * def __sub__(self, other: AnyVec) -> Vec2: + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_add); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_iadd, __pyx_t_5) < 0) __PYX_ERR(0, 228, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":237 + * # __rsub__ not supported for Vec2 + * + * __isub__ = __sub__ # immutable # <<<<<<<<<<<<<< + * + * def __mul__(self, factor) -> Vec2: + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_sub); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_isub, __pyx_t_5) < 0) __PYX_ERR(0, 237, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":253 + * return v2_mul(self, factor) + * + * __imul__ = __mul__ # immutable # <<<<<<<<<<<<<< + * + * def __truediv__(self, double factor) -> Vec2: + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_mul); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_imul, __pyx_t_5) < 0) __PYX_ERR(0, 253, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":260 + * # __rtruediv__ not supported -> TypeError + * + * def dot(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dot(self, o) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 260, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_other, __pyx_n_s_AnyVec) < 0) __PYX_ERR(0, 260, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 260, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_66dot, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_dot, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__47)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 260, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_dot, __pyx_t_3) < 0) __PYX_ERR(0, 260, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":264 + * return v2_dot(self, o) + * + * def det(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_det(self, o) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_AnyVec) < 0) __PYX_ERR(0, 264, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 264, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_68det, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_det, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__48)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_det, __pyx_t_5) < 0) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":268 + * return v2_det(self, o) + * + * def distance(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_dist(self, o) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 268, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_other, __pyx_n_s_AnyVec) < 0) __PYX_ERR(0, 268, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 268, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_70distance, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_distance, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__49)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 268, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_distance, __pyx_t_3) < 0) __PYX_ERR(0, 268, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":272 + * return v2_dist(self, o) + * + * def angle_between(self, other: AnyVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec2 o = Vec2(other) + * return v2_angle_between(self, o) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_AnyVec) < 0) __PYX_ERR(0, 272, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 272, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_72angle_between, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_angle_between, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__50)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_angle_between, __pyx_t_5) < 0) __PYX_ERR(0, 272, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":276 + * return v2_angle_between(self, o) + * + * def rotate(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * cdef double self_angle = atan2(self.y, self.x) + * cdef double magnitude = hypot(self.x, self.y) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 276, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_74rotate, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_rotate, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__52)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_rotate, __pyx_t_3) < 0) __PYX_ERR(0, 276, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":281 + * return v2_from_angle(self_angle + angle, magnitude) + * + * def rotate_deg(self, double angle) -> Vec2: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 281, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_76rotate_deg, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_rotate_deg, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__54)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_rotate_deg, __pyx_t_5) < 0) __PYX_ERR(0, 281, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":284 + * return self.rotate(angle * DEG2RAD) + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[Vec2]) -> Vec2: + * cdef Vec2 res = Vec2() + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_items, __pyx_kp_s_Iterable_Vec2) < 0) __PYX_ERR(0, 284, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec2) < 0) __PYX_ERR(0, 284, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec2_78sum, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec2_sum, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__56)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_sum, __pyx_t_3) < 0) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_sum); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec2, __pyx_n_s_sum, __pyx_t_5) < 0) __PYX_ERR(0, 284, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec2); + + /* "ezdxf/acc/vector.pyx":422 + * self.z = 0.0 + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return Vec3, self.xyz + * + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_3__reduce__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3___reduce, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__57)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 422, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_reduce, __pyx_t_5) < 0) __PYX_ERR(0, 422, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":443 + * return res + * + * def replace(self, x: float = None, y: float = None, # <<<<<<<<<<<<<< + * z: float = None) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 443, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_x, __pyx_n_s_float) < 0) __PYX_ERR(0, 443, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_y, __pyx_n_s_float) < 0) __PYX_ERR(0, 443, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_z, __pyx_n_s_float) < 0) __PYX_ERR(0, 443, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 443, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_5replace, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_replace, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__59)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 443, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__60); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_replace, __pyx_t_3) < 0) __PYX_ERR(0, 443, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":451 + * return res + * + * def round(self, ndigits: int | None = None) -> Vec3: # <<<<<<<<<<<<<< + * return Vec3( + * round(self.x, ndigits), + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_ndigits, __pyx_kp_s_int_None) < 0) __PYX_ERR(0, 451, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 451, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_7round, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_round, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__61)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 451, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_tuple__21); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_round, __pyx_t_5) < 0) __PYX_ERR(0, 451, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":458 + * ) + * + * @staticmethod # <<<<<<<<<<<<<< + * def list(items: Iterable[UVec]) -> List[Vec3]: + * return list(Vec3.generate(items)) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 458, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_List_Vec3) < 0) __PYX_ERR(0, 458, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_9list, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_list, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__62)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_list, __pyx_t_3) < 0) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_list); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_list, __pyx_t_5) < 0) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":462 + * return list(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + * return tuple(Vec3.generate(items)) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 462, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_Sequence_Vec3) < 0) __PYX_ERR(0, 462, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_11tuple, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_tuple, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__63)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_tuple, __pyx_t_3) < 0) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_tuple); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_tuple, __pyx_t_5) < 0) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":466 + * return tuple(Vec3.generate(items)) + * + * @staticmethod # <<<<<<<<<<<<<< + * def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + * return (Vec3(item) for item in items) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 466, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_kp_s_Iterator_Vec3) < 0) __PYX_ERR(0, 466, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_13generate, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_generate, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__64)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_generate, __pyx_t_3) < 0) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_generate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_generate, __pyx_t_5) < 0) __PYX_ERR(0, 466, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":470 + * return (Vec3(item) for item in items) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle, length) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 470, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_15from_angle, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_from_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__65)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_angle, __pyx_t_3) < 0) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_angle); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_angle, __pyx_t_5) < 0) __PYX_ERR(0, 470, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":474 + * return v3_from_angle(angle, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def from_deg_angle(double angle, double length = 1.0) -> Vec3: + * return v3_from_angle(angle * DEG2RAD, length) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 474, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_17from_deg_angle, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_from_deg_angle, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__66)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_deg_angle, __pyx_t_3) < 0) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_deg_angle); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_from_deg_angle, __pyx_t_5) < 0) __PYX_ERR(0, 474, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":478 + * return v3_from_angle(angle * DEG2RAD, length) + * + * @staticmethod # <<<<<<<<<<<<<< + * def random(double length = 1.0) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 478, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_19random, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_random, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__68)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_random, __pyx_t_3) < 0) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_random); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_random, __pyx_t_5) < 0) __PYX_ERR(0, 478, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":499 + * return hash(self.xyz) + * + * def copy(self) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable + * + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 499, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_29copy, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_copy, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__69)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_copy, __pyx_t_3) < 0) __PYX_ERR(0, 499, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":502 + * return self # immutable + * + * __copy__ = copy # <<<<<<<<<<<<<< + * + * def __deepcopy__(self, memodict: dict) -> Vec3: + */ + __Pyx_GetNameInClass(__pyx_t_3, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_copy); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_copy_2, __pyx_t_3) < 0) __PYX_ERR(0, 502, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":504 + * __copy__ = copy + * + * def __deepcopy__(self, memodict: dict) -> Vec3: # <<<<<<<<<<<<<< + * return self # immutable! + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_memodict, __pyx_n_s_dict_2) < 0) __PYX_ERR(0, 504, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 504, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_31__deepcopy__, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3___deepcopy, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__70)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_deepcopy, __pyx_t_5) < 0) __PYX_ERR(0, 504, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + __pyx_k__8 = REL_TOL; + + /* "ezdxf/acc/vector.pyx":543 + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * cdef Vec3 v1 = v3_normalize(self, 1.0) + */ + __pyx_k__9 = ABS_TOL; + + /* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = PyFloat_FromDouble(REL_TOL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_rel_tol, __pyx_t_3) < 0) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":543 + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * cdef Vec3 v1 = v3_normalize(self, 1.0) + */ + __pyx_t_3 = PyFloat_FromDouble(ABS_TOL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 543, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_abs_tol, __pyx_t_3) < 0) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":542 + * fabs(self.z) <= ABS_TOL + * + * def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * cdef Vec3 o = Vec3(other) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 542, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 542, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_40is_parallel, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_is_parallel, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__72)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsKwDict(__pyx_t_2, __pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_is_parallel, __pyx_t_2) < 0) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":567 + * return atan2(self.y, self.x) * RAD2DEG + * + * def orthogonal(self, ccw: bool = True) -> Vec3: # <<<<<<<<<<<<<< + * return v3_ortho(self, ccw) + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 567, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_ccw, __pyx_n_s_bool) < 0) __PYX_ERR(0, 567, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 567, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_42orthogonal, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_orthogonal, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__73)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 567, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_tuple__37); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_orthogonal, __pyx_t_3) < 0) __PYX_ERR(0, 567, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":570 + * return v3_ortho(self, ccw) + * + * def lerp(self, other: UVec, double factor=0.5) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 570, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 570, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 570, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_44lerp, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_lerp, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__75)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 570, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__40); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_lerp, __pyx_t_2) < 0) __PYX_ERR(0, 570, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":575 + * return v3_lerp(self, other, factor) + * + * def project(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 575, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 575, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 575, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_46project, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_project, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__77)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 575, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_project, __pyx_t_3) < 0) __PYX_ERR(0, 575, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":580 + * return v3_project(self, other) + * + * def normalize(self, double length = 1.) -> Vec3: # <<<<<<<<<<<<<< + * return v3_normalize(self, length) + * + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 580, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 580, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_48normalize, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_normalize, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__78)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 580, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_tuple__29); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_normalize, __pyx_t_2) < 0) __PYX_ERR(0, 580, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":583 + * return v3_normalize(self, length) + * + * def reversed(self) -> Vec3: # <<<<<<<<<<<<<< + * return v3_reverse(self) + * + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 583, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_50reversed, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_reversed, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__79)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_reversed, __pyx_t_3) < 0) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + __pyx_k__10 = REL_TOL; + + /* "ezdxf/acc/vector.pyx":593 + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_k__11 = ABS_TOL; + + /* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyFloat_FromDouble(REL_TOL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_rel_tol, __pyx_t_2) < 0) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":593 + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + * double abs_tol = ABS_TOL) -> bool: # <<<<<<<<<<<<<< + * if not isinstance(other, Vec3): + * other = Vec3(other) + */ + __pyx_t_2 = PyFloat_FromDouble(ABS_TOL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 593, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_abs_tol, __pyx_t_2) < 0) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":592 + * return not self.is_null + * + * def isclose(self, other: UVec, *, double rel_tol = REL_TOL, # <<<<<<<<<<<<<< + * double abs_tol = ABS_TOL) -> bool: + * if not isinstance(other, Vec3): + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 592, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_bool) < 0) __PYX_ERR(0, 592, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_56isclose, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_isclose, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__81)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsKwDict(__pyx_t_5, __pyx_t_3); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_isclose, __pyx_t_5) < 0) __PYX_ERR(0, 592, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":621 + * return v3_add( self, other) + * + * __radd__ = __add__ # Cython >= 3.0 # <<<<<<<<<<<<<< + * + * __iadd__ = __add__ # immutable + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_add); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 621, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_radd, __pyx_t_5) < 0) __PYX_ERR(0, 621, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":623 + * __radd__ = __add__ # Cython >= 3.0 + * + * __iadd__ = __add__ # immutable # <<<<<<<<<<<<<< + * + * # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_add); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 623, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_iadd, __pyx_t_5) < 0) __PYX_ERR(0, 623, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":639 + * return v3_sub(Vec3(other), self) + * + * __isub__ = __sub__ # immutable # <<<<<<<<<<<<<< + * + * # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_sub); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 639, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_isub, __pyx_t_5) < 0) __PYX_ERR(0, 639, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":651 + * return v3_mul(self, factor) + * + * __imul__ = __mul__ # immutable # <<<<<<<<<<<<<< + * + * def __truediv__(self, double factor) -> Vec3: + */ + __Pyx_GetNameInClass(__pyx_t_5, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_mul); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 651, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_imul, __pyx_t_5) < 0) __PYX_ERR(0, 651, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":658 + * # __rtruediv__ not supported -> TypeError + * + * @staticmethod # <<<<<<<<<<<<<< + * def sum(items: Iterable[UVec]) -> Vec3: + * cdef Vec3 res = Vec3() + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_items, __pyx_kp_s_Iterable_UVec) < 0) __PYX_ERR(0, 658, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 658, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_74sum, __Pyx_CYFUNCTION_STATICMETHOD | __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_sum, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__82)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_sum, __pyx_t_2) < 0) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + __Pyx_GetNameInClass(__pyx_t_2, (PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_sum); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_staticmethod, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_sum, __pyx_t_5) < 0) __PYX_ERR(0, 658, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":669 + * return res + * + * def dot(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dot(self, o) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 669, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 669, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 669, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_76dot, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_dot, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__83)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 669, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_dot, __pyx_t_2) < 0) __PYX_ERR(0, 669, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":673 + * return v3_dot(self, o) + * + * def cross(self, other: UVec) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_cross(self, o) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 673, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 673, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 673, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_78cross, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_cross, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__84)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 673, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_cross, __pyx_t_5) < 0) __PYX_ERR(0, 673, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":677 + * return v3_cross(self, o) + * + * def distance(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_dist(self, o) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 677, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 677, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 677, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_80distance, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_distance, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__85)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 677, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_distance, __pyx_t_2) < 0) __PYX_ERR(0, 677, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":681 + * return v3_dist(self, o) + * + * def angle_between(self, other: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 o = Vec3(other) + * return v3_angle_between(self, o) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 681, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_other, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 681, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 681, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_82angle_between, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_angle_between, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__86)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 681, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_angle_between, __pyx_t_5) < 0) __PYX_ERR(0, 681, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":685 + * return v3_angle_between(self, o) + * + * def angle_about(self, base: UVec, target: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 b = Vec3(base) + * cdef Vec3 t = Vec3(target) + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 685, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_base, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 685, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_target, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 685, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 685, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_84angle_about, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_angle_about, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__88)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 685, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_angle_about, __pyx_t_2) < 0) __PYX_ERR(0, 685, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":690 + * return v3_angle_about(self, b, t) + * + * def rotate(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * cdef double angle_ = atan2(self.y, self.x) + angle + * cdef double magnitude_ = hypot(self.x, self.y) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 690, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_86rotate, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_rotate, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__90)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_rotate, __pyx_t_5) < 0) __PYX_ERR(0, 690, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":697 + * return res + * + * def rotate_deg(self, double angle) -> Vec3: # <<<<<<<<<<<<<< + * return self.rotate(angle * DEG2RAD) + * + */ + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 697, __pyx_L1_error) + __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_4Vec3_88rotate_deg, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_Vec3_rotate_deg, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__91)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_5); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3, __pyx_n_s_rotate_deg, __pyx_t_2) < 0) __PYX_ERR(0, 697, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + PyType_Modified(__pyx_ptype_5ezdxf_3acc_6vector_Vec3); + + /* "ezdxf/acc/vector.pyx":701 + * + * + * X_AXIS = Vec3(1, 0, 0) # <<<<<<<<<<<<<< + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) + */ + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_tuple__92, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_X_AXIS, __pyx_t_2) < 0) __PYX_ERR(0, 701, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":702 + * + * X_AXIS = Vec3(1, 0, 0) + * Y_AXIS = Vec3(0, 1, 0) # <<<<<<<<<<<<<< + * Z_AXIS = Vec3(0, 0, 1) + * NULLVEC = Vec3(0, 0, 0) + */ + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_tuple__93, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 702, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Y_AXIS, __pyx_t_2) < 0) __PYX_ERR(0, 702, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":703 + * X_AXIS = Vec3(1, 0, 0) + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) # <<<<<<<<<<<<<< + * NULLVEC = Vec3(0, 0, 0) + * + */ + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_tuple__94, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 703, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Z_AXIS, __pyx_t_2) < 0) __PYX_ERR(0, 703, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":704 + * Y_AXIS = Vec3(0, 1, 0) + * Z_AXIS = Vec3(0, 0, 1) + * NULLVEC = Vec3(0, 0, 0) # <<<<<<<<<<<<<< + * + * cdef Vec3 v3_add(Vec3 a, Vec3 b): + */ + __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_5ezdxf_3acc_6vector_Vec3), __pyx_tuple__95, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 704, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_NULLVEC, __pyx_t_2) < 0) __PYX_ERR(0, 704, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "ezdxf/acc/vector.pyx":829 + * + * + * def distance(p1: UVec, p2: UVec) -> float: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + __pyx_t_2 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 829, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_p1, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 829, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_p2, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 829, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_return, __pyx_n_s_float) < 0) __PYX_ERR(0, 829, __pyx_L1_error) + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_5distance, 0, __pyx_n_s_distance, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__97)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 829, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_5, __pyx_t_2); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_distance, __pyx_t_5) < 0) __PYX_ERR(0, 829, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "ezdxf/acc/vector.pyx":835 + * + * + * def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: # <<<<<<<<<<<<<< + * cdef Vec3 a = Vec3(p1) + * cdef Vec3 b = Vec3(p2) + */ + __pyx_t_5 = PyFloat_FromDouble(((double)0.5)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_5)) __PYX_ERR(0, 835, __pyx_L1_error); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_p1, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 835, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_p2, __pyx_n_s_UVec) < 0) __PYX_ERR(0, 835, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_return, __pyx_n_s_Vec3) < 0) __PYX_ERR(0, 835, __pyx_L1_error) + __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_5ezdxf_3acc_6vector_7lerp, 0, __pyx_n_s_lerp, NULL, __pyx_n_s_ezdxf_acc_vector, __pyx_d, ((PyObject *)__pyx_codeobj__99)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_t_2); + __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_lerp, __pyx_t_3) < 0) __PYX_ERR(0, 835, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "ezdxf/acc/vector.pyx":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # cython: c_api_binop_methods=True + * # Copyright (c) 2020-2024, Manfred Moitzi + */ + __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + if (__pyx_m) { + if (__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init ezdxf.acc.vector", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init ezdxf.acc.vector"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d00A1 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d00A1 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* TupleAndListFromArray */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + Py_INCREF(__pyx_empty_tuple); + return __pyx_empty_tuple; + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = PyTuple_GET_SIZE(kwnames); + for (i = 0; i < n; i++) + { + if (s == PyTuple_GET_ITEM(kwnames, i)) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + int eq = __Pyx_PyUnicode_Equals(s, PyTuple_GET_ITEM(kwnames, i), Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs = PyTuple_GET_SIZE(kwnames); + PyObject *dict; + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; i= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject *const *kwvalues, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + int kwds_is_tuple = CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds)); + while (1) { + Py_XDECREF(key); key = NULL; + Py_XDECREF(value); value = NULL; + if (kwds_is_tuple) { + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(kwds); +#else + size = PyTuple_Size(kwds); + if (size < 0) goto bad; +#endif + if (pos >= size) break; +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); + if (!key) goto bad; +#elif CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kwds, pos); +#else + key = PyTuple_GetItem(kwds, pos); + if (!key) goto bad; +#endif + value = kwvalues[pos]; + pos++; + } + else + { + if (!PyDict_Next(kwds, &pos, &key, &value)) break; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + } + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(value); + Py_DECREF(key); +#endif + key = NULL; + value = NULL; + continue; + } +#if !CYTHON_AVOID_BORROWED_REFS + Py_INCREF(key); +#endif + Py_INCREF(value); + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = ( + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key) + ); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; +#if CYTHON_AVOID_BORROWED_REFS + value = NULL; +#endif + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + Py_XDECREF(key); + Py_XDECREF(value); + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + Py_XDECREF(key); + Py_XDECREF(value); + return -1; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kw, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kw, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kw))) { + Py_ssize_t kwsize; +#if CYTHON_ASSUME_SAFE_MACROS + kwsize = PyTuple_GET_SIZE(kw); +#else + kwsize = PyTuple_Size(kw); + if (kwsize < 0) return 0; +#endif + if (unlikely(kwsize == 0)) + return 1; + if (!kw_allowed) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, 0); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + goto invalid_keyword; + } +#if PY_VERSION_HEX < 0x03090000 + for (pos = 0; pos < kwsize; pos++) { +#if CYTHON_ASSUME_SAFE_MACROS + key = PyTuple_GET_ITEM(kw, pos); +#else + key = PyTuple_GetItem(kw, pos); + if (!key) return 0; +#endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } +#endif + return 1; + } + while (PyDict_Next(kw, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if (!kw_allowed && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + #if PY_MAJOR_VERSION < 3 + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (mm && mm->mp_subscript) { + PyObject *r, *key = PyInt_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + __Pyx_PyThreadState_declare + CYTHON_UNUSED_VAR(cause); + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { + #if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); + #elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) { + return NULL; + } + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { + return NULL; + } + #endif + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + #if PY_MAJOR_VERSION < 3 + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + #else + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + #endif + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) < 0) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject **args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + #if PY_VERSION_HEX < 0x030800B1 + #if CYTHON_FAST_PYCCALL + if (PyCFunction_Check(func)) { + if (kwargs) { + return _PyCFunction_FastCallDict(func, args, nargs, kwargs); + } else { + return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); + } + } + #if PY_VERSION_HEX >= 0x030700A1 + if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { + return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); + } + #endif + #endif + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); + } + #endif + #endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if PY_VERSION_HEX < 0x03090000 + vectorcallfunc f = _PyVectorcall_Function(func); + #else + vectorcallfunc f = PyVectorcall_Function(func); + #endif + if (f) { + return f(func, args, (size_t)nargs, NULL); + } + #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL + if (__Pyx_CyFunction_CheckExact(func)) { + __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); + if (f) return f(func, args, (size_t)nargs, NULL); + } + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyObjectCallOneArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *args[2] = {NULL, arg}; + return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* RaiseUnboundLocalError */ +static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { + PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C00A6 + local_value = tstate->current_exception; + tstate->current_exception = 0; + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE && PY_VERSION_HEX >= 0x030C00A6 + if (unlikely(tstate->current_exception)) +#elif CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc; + __Pyx_PyThreadState_declare + #ifdef __Pyx_StopAsyncIteration_USED + int is_async_stopiteration = 0; + #endif + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + cur_exc = PyErr_Occurred(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + #ifdef __Pyx_StopAsyncIteration_USED + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else + #endif + return; + } + __Pyx_PyThreadState_assign + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + PyErr_SetString(PyExc_RuntimeError, + #ifdef __Pyx_StopAsyncIteration_USED + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + #endif + "generator raised StopIteration"); +} + +/* JoinPyUnicode */ +static PyObject* __Pyx_PyUnicode_Join(PyObject* value_tuple, Py_ssize_t value_count, Py_ssize_t result_ulength, + Py_UCS4 max_char) { +#if CYTHON_USE_UNICODE_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + PyObject *result_uval; + int result_ukind, kind_shift; + Py_ssize_t i, char_pos; + void *result_udata; + CYTHON_MAYBE_UNUSED_VAR(max_char); +#if CYTHON_PEP393_ENABLED + result_uval = PyUnicode_New(result_ulength, max_char); + if (unlikely(!result_uval)) return NULL; + result_ukind = (max_char <= 255) ? PyUnicode_1BYTE_KIND : (max_char <= 65535) ? PyUnicode_2BYTE_KIND : PyUnicode_4BYTE_KIND; + kind_shift = (result_ukind == PyUnicode_4BYTE_KIND) ? 2 : result_ukind - 1; + result_udata = PyUnicode_DATA(result_uval); +#else + result_uval = PyUnicode_FromUnicode(NULL, result_ulength); + if (unlikely(!result_uval)) return NULL; + result_ukind = sizeof(Py_UNICODE); + kind_shift = (result_ukind == 4) ? 2 : result_ukind - 1; + result_udata = PyUnicode_AS_UNICODE(result_uval); +#endif + assert(kind_shift == 2 || kind_shift == 1 || kind_shift == 0); + char_pos = 0; + for (i=0; i < value_count; i++) { + int ukind; + Py_ssize_t ulength; + void *udata; + PyObject *uval = PyTuple_GET_ITEM(value_tuple, i); + if (unlikely(__Pyx_PyUnicode_READY(uval))) + goto bad; + ulength = __Pyx_PyUnicode_GET_LENGTH(uval); + if (unlikely(!ulength)) + continue; + if (unlikely((PY_SSIZE_T_MAX >> kind_shift) - ulength < char_pos)) + goto overflow; + ukind = __Pyx_PyUnicode_KIND(uval); + udata = __Pyx_PyUnicode_DATA(uval); + if (!CYTHON_PEP393_ENABLED || ukind == result_ukind) { + memcpy((char *)result_udata + (char_pos << kind_shift), udata, (size_t) (ulength << kind_shift)); + } else { + #if PY_VERSION_HEX >= 0x030d0000 + if (unlikely(PyUnicode_CopyCharacters(result_uval, char_pos, uval, 0, ulength) < 0)) goto bad; + #elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030300F0 || defined(_PyUnicode_FastCopyCharacters) + _PyUnicode_FastCopyCharacters(result_uval, char_pos, uval, 0, ulength); + #else + Py_ssize_t j; + for (j=0; j < ulength; j++) { + Py_UCS4 uchar = __Pyx_PyUnicode_READ(ukind, udata, j); + __Pyx_PyUnicode_WRITE(result_ukind, result_udata, char_pos+j, uchar); + } + #endif + } + char_pos += ulength; + } + return result_uval; +overflow: + PyErr_SetString(PyExc_OverflowError, "join() result is too long for a Python string"); +bad: + Py_DECREF(result_uval); + return NULL; +#else + CYTHON_UNUSED_VAR(max_char); + CYTHON_UNUSED_VAR(result_ulength); + CYTHON_UNUSED_VAR(value_count); + return PyUnicode_Join(__pyx_empty_unicode, value_tuple); +#endif +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + __Pyx_TypeName type_name; + __Pyx_TypeName obj_type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + type_name = __Pyx_PyType_GetName(type); + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME + ", got " __Pyx_FMT_TYPENAME ")", name, type_name, obj_type_name); + __Pyx_DECREF_TypeName(type_name); + __Pyx_DECREF_TypeName(obj_type_name); + return 0; +} + +/* CIntToDigits */ +static const char DIGIT_PAIRS_10[2*10*10+1] = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; +static const char DIGIT_PAIRS_8[2*8*8+1] = { + "0001020304050607" + "1011121314151617" + "2021222324252627" + "3031323334353637" + "4041424344454647" + "5051525354555657" + "6061626364656667" + "7071727374757677" +}; +static const char DIGITS_HEX[2*16+1] = { + "0123456789abcdef" + "0123456789ABCDEF" +}; + +/* BuildPyUnicode */ +static PyObject* __Pyx_PyUnicode_BuildFromAscii(Py_ssize_t ulength, char* chars, int clength, + int prepend_sign, char padding_char) { + PyObject *uval; + Py_ssize_t uoffset = ulength - clength; +#if CYTHON_USE_UNICODE_INTERNALS + Py_ssize_t i; +#if CYTHON_PEP393_ENABLED + void *udata; + uval = PyUnicode_New(ulength, 127); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_DATA(uval); +#else + Py_UNICODE *udata; + uval = PyUnicode_FromUnicode(NULL, ulength); + if (unlikely(!uval)) return NULL; + udata = PyUnicode_AS_UNICODE(uval); +#endif + if (uoffset > 0) { + i = 0; + if (prepend_sign) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, 0, '-'); + i++; + } + for (; i < uoffset; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, i, padding_char); + } + } + for (i=0; i < clength; i++) { + __Pyx_PyUnicode_WRITE(PyUnicode_1BYTE_KIND, udata, uoffset+i, chars[i]); + } +#else + { + PyObject *sign = NULL, *padding = NULL; + uval = NULL; + if (uoffset > 0) { + prepend_sign = !!prepend_sign; + if (uoffset > prepend_sign) { + padding = PyUnicode_FromOrdinal(padding_char); + if (likely(padding) && uoffset > prepend_sign + 1) { + PyObject *tmp; + PyObject *repeat = PyInt_FromSsize_t(uoffset - prepend_sign); + if (unlikely(!repeat)) goto done_or_error; + tmp = PyNumber_Multiply(padding, repeat); + Py_DECREF(repeat); + Py_DECREF(padding); + padding = tmp; + } + if (unlikely(!padding)) goto done_or_error; + } + if (prepend_sign) { + sign = PyUnicode_FromOrdinal('-'); + if (unlikely(!sign)) goto done_or_error; + } + } + uval = PyUnicode_DecodeASCII(chars, clength, NULL); + if (likely(uval) && padding) { + PyObject *tmp = PyNumber_Add(padding, uval); + Py_DECREF(uval); + uval = tmp; + } + if (likely(uval) && sign) { + PyObject *tmp = PyNumber_Add(sign, uval); + Py_DECREF(uval); + uval = tmp; + } +done_or_error: + Py_XDECREF(padding); + Py_XDECREF(sign); + } +#endif + return uval; +} + +/* CIntToPyUnicode */ +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_From_int(int value, Py_ssize_t width, char padding_char, char format_char) { + char digits[sizeof(int)*3+2]; + char *dpos, *end = digits + sizeof(int)*3+2; + const char *hex_digits = DIGITS_HEX; + Py_ssize_t length, ulength; + int prepend_sign, last_one_off; + int remaining; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (format_char == 'X') { + hex_digits += 16; + format_char = 'x'; + } + remaining = value; + last_one_off = 0; + dpos = end; + do { + int digit_pos; + switch (format_char) { + case 'o': + digit_pos = abs((int)(remaining % (8*8))); + remaining = (int) (remaining / (8*8)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_8 + digit_pos * 2, 2); + last_one_off = (digit_pos < 8); + break; + case 'd': + digit_pos = abs((int)(remaining % (10*10))); + remaining = (int) (remaining / (10*10)); + dpos -= 2; + memcpy(dpos, DIGIT_PAIRS_10 + digit_pos * 2, 2); + last_one_off = (digit_pos < 10); + break; + case 'x': + *(--dpos) = hex_digits[abs((int)(remaining % 16))]; + remaining = (int) (remaining / 16); + break; + default: + assert(0); + break; + } + } while (unlikely(remaining != 0)); + assert(!last_one_off || *dpos == '0'); + dpos += last_one_off; + length = end - dpos; + ulength = length; + prepend_sign = 0; + if (!is_unsigned && value <= neg_one) { + if (padding_char == ' ' || width <= length + 1) { + *(--dpos) = '-'; + ++length; + } else { + prepend_sign = 1; + } + ++ulength; + } + if (width > ulength) { + ulength = width; + } + if (ulength == 1) { + return PyUnicode_FromOrdinal(*dpos); + } + return __Pyx_PyUnicode_BuildFromAscii(ulength, dpos, (int) length, prepend_sign, padding_char); +} + +/* PyObjectCallNoArg */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* ExtTypeTest */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + __Pyx_TypeName obj_type_name; + __Pyx_TypeName type_name; + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + obj_type_name = __Pyx_PyType_GetName(Py_TYPE(obj)); + type_name = __Pyx_PyType_GetName(type); + PyErr_Format(PyExc_TypeError, + "Cannot convert " __Pyx_FMT_TYPENAME " to " __Pyx_FMT_TYPENAME, + obj_type_name, type_name); + __Pyx_DECREF_TypeName(obj_type_name); + __Pyx_DECREF_TypeName(type_name); + return 0; +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && PY_VERSION_HEX < 0x030d0000 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#elif CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* FixUpExtensionType */ +#if CYTHON_USE_TYPE_SPECS +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); +#else + const PyType_Slot *slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { + int changed = 0; +#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) + const +#endif + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { +#if PY_VERSION_HEX < 0x030900b1 + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); +#if PY_VERSION_HEX >= 0x030800b4 + type->tp_vectorcall_offset = memb->offset; +#else + type->tp_print = (printfunc) memb->offset; +#endif + changed = 1; + } +#endif +#else + if ((0)); +#endif +#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { + Py_DECREF(descr); + return -1; + } + Py_DECREF(descr); + changed = 1; + } +#endif + } + memb++; + } + if (changed) + PyType_Modified(type); + } +#endif + return 0; +} +#endif + +/* PyObjectGetMethod */ +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#elif PY_MAJOR_VERSION >= 3 + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} + +/* PyObjectCallMethod0 */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +} + +/* ValidateBasesTuple */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_MACROS + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (n < 0) return -1; +#endif + for (i = 1; i < n; i++) + { +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + PyTypeObject *b; +#if PY_MAJOR_VERSION < 3 + if (PyClass_Check(b0)) + { + PyErr_Format(PyExc_TypeError, "base class '%.200s' is an old-style class", + PyString_AS_STRING(((PyClassObject*)b0)->cl_name)); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !(CYTHON_USE_TYPE_SLOTS || CYTHON_COMPILING_IN_PYPY) + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !(CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API) || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if PY_VERSION_HEX >= 0x030700a1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) + gc = PyImport_GetModule(__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if PY_VERSION_HEX >= 0x03050000 && !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + __Pyx_TypeName type_name = __Pyx_PyType_GetName(tp); + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, attr_name); +#else + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%.400s'", + type_name, PyString_AS_STRING(attr_name)); +#endif + __Pyx_DECREF_TypeName(type_name); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *empty_list = 0; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (unlikely(!py_import)) + goto bad; + if (!from_list) { + empty_list = PyList_New(0); + if (unlikely(!empty_list)) + goto bad; + from_list = empty_list; + } + #endif + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.') != NULL) { + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, 1); + if (unlikely(!module)) { + if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (unlikely(!py_level)) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, __pyx_d, empty_dict, from_list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, __pyx_d, empty_dict, from_list, level); + #endif + } + } +bad: + Py_XDECREF(empty_dict); + Py_XDECREF(empty_list); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_kp_u__12); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* ImportDottedModule */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { + PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; + if (unlikely(PyErr_Occurred())) { + PyErr_Clear(); + } + if (likely(PyTuple_GET_SIZE(parts_tuple) == count)) { + partial_name = name; + } else { + slice = PySequence_GetSlice(parts_tuple, 0, count); + if (unlikely(!slice)) + goto bad; + sep = PyUnicode_FromStringAndSize(".", 1); + if (unlikely(!sep)) + goto bad; + partial_name = PyUnicode_Join(sep, slice); + } + PyErr_Format( +#if PY_MAJOR_VERSION < 3 + PyExc_ImportError, + "No module named '%s'", PyString_AS_STRING(partial_name)); +#else +#if PY_VERSION_HEX >= 0x030600B1 + PyExc_ModuleNotFoundError, +#else + PyExc_ImportError, +#endif + "No module named '%U'", partial_name); +#endif +bad: + Py_XDECREF(sep); + Py_XDECREF(slice); + Py_XDECREF(partial_name); + return NULL; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { + PyObject *imported_module; +#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + return NULL; + imported_module = __Pyx_PyDict_GetItemStr(modules, name); + Py_XINCREF(imported_module); +#else + imported_module = PyImport_GetModule(name); +#endif + return imported_module; +} +#endif +#if PY_MAJOR_VERSION >= 3 +static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { + Py_ssize_t i, nparts; + nparts = PyTuple_GET_SIZE(parts_tuple); + for (i=1; i < nparts && module; i++) { + PyObject *part, *submodule; +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + part = PyTuple_GET_ITEM(parts_tuple, i); +#else + part = PySequence_ITEM(parts_tuple, i); +#endif + submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); +#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(part); +#endif + Py_DECREF(module); + module = submodule; + } + if (unlikely(!module)) { + return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); + } + return module; +} +#endif +static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if PY_MAJOR_VERSION < 3 + PyObject *module, *from_list, *star = __pyx_n_s__13; + CYTHON_UNUSED_VAR(parts_tuple); + from_list = PyList_New(1); + if (unlikely(!from_list)) + return NULL; + Py_INCREF(star); + PyList_SET_ITEM(from_list, 0, star); + module = __Pyx_Import(name, from_list, 0); + Py_DECREF(from_list); + return module; +#else + PyObject *imported_module; + PyObject *module = __Pyx_Import(name, NULL, 0); + if (!parts_tuple || unlikely(!module)) + return module; + imported_module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(imported_module)) { + Py_DECREF(module); + return imported_module; + } + PyErr_Clear(); + return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); +#endif +} +static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1 + PyObject *module = __Pyx__ImportDottedModule_Lookup(name); + if (likely(module)) { + PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_n_s_spec); + if (likely(spec)) { + PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_n_s_initializing); + if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { + Py_DECREF(spec); + spec = NULL; + } + Py_XDECREF(unsafe); + } + if (likely(!spec)) { + PyErr_Clear(); + return module; + } + Py_DECREF(spec); + Py_DECREF(module); + } else if (PyErr_Occurred()) { + PyErr_Clear(); + } +#endif + return __Pyx__ImportDottedModule(name, parts_tuple); +} + +/* FetchSharedCythonModule */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef((char*) __PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType */ +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t basicsize, + Py_ssize_t expected_basicsize) { + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +#if !CYTHON_USE_TYPE_SPECS +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* abi_module; + const char* object_name; + PyTypeObject *cached_type = NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + if (__Pyx_VerifyCachedType( + (PyObject *)cached_type, + object_name, + cached_type->tp_basicsize, + type->tp_basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; +done: + Py_DECREF(abi_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#else +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module, *cached_type = NULL; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) return NULL; + cached_type = PyObject_GetAttrString(abi_module, object_name); + if (cached_type) { + Py_ssize_t basicsize; +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; +#else + basicsize = likely(PyType_Check(cached_type)) ? ((PyTypeObject*) cached_type)->tp_basicsize : -1; +#endif + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + basicsize, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + CYTHON_UNUSED_VAR(module); + cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; +done: + Py_DECREF(abi_module); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} +#endif + +/* PyVectorcallFastCallDict */ +#if CYTHON_METH_FASTCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i, pos; + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (PyDict_Next(kw, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(kwnames, i, key); + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + if (likely(kw == NULL) || PyDict_GET_SIZE(kw) == 0) { + return vc(func, args, nargs, NULL); + } + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void *cfunc) { + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) +{ + CYTHON_UNUSED_VAR(closure); + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#elif PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_name, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->func_dict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_tuple; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->defaults_kwdict; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = op->func_annotations; + CYTHON_UNUSED_VAR(context); + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + int is_coroutine; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; +#if PY_VERSION_HEX >= 0x03050000 + if (is_coroutine) { + PyObject *module, *fromlist, *marker = __pyx_n_s_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_n_s_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + op->func_is_coroutine = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(op->func_is_coroutine)) { + return __Pyx_NewRef(op->func_is_coroutine); + } +ignore: + PyErr_Clear(); + } +#endif + op->func_is_coroutine = __Pyx_PyBool_FromLong(is_coroutine); + return __Pyx_NewRef(op->func_is_coroutine); +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {(char *) "_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if CYTHON_USE_TYPE_SPECS + {(char *) "__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#if CYTHON_METH_FASTCALL +#if CYTHON_BACKPORT_VECTORCALL + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else +#if !CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#endif +#endif +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + CYTHON_UNUSED_VAR(args); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(((PyCFunctionObject*)m)->m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyObject *py_name = NULL; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_MACROS + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, + "%.200S() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, size); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); +#endif + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } +#if CYTHON_COMPILING_IN_LIMITED_API + py_name = __Pyx_CyFunction_get_name((__pyx_CyFunctionObject*)func, NULL); + if (!py_name) return NULL; + PyErr_Format(PyExc_TypeError, "%.200S() takes no keyword arguments", + py_name); + Py_DECREF(py_name); +#else + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); +#endif + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_MACROS + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(!argc) < 0) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + PyErr_Format(PyExc_TypeError, "%.200s() needs an argument", + ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(PyTuple_GET_SIZE(kwnames))) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", ((PyCFunctionObject*)cyfunc)->m_ml->ml_name); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + def->ml_name, nargs); + return NULL; + } + return def->ml_meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))def->ml_meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyMethodDef* def = ((PyCFunctionObject*)cyfunc)->m_ml; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); +#if CYTHON_BACKPORT_VECTORCALL + Py_ssize_t nargs = (Py_ssize_t)nargsf; +#else + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); +#endif + PyObject *self; + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: + self = ((PyCFunctionObject*)cyfunc)->m_self; + break; + default: + return NULL; + } + return ((__Pyx_PyCMethod)(void(*)(void))def->ml_meth)(self, cls, args, (size_t)nargs, kwnames); +} +#endif +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if (defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +#else +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, +#if !CYTHON_METH_FASTCALL + 0, +#elif CYTHON_BACKPORT_VECTORCALL + (printfunc)offsetof(__pyx_CyFunctionObject, func_vectorcall), +#else + offsetof(PyCFunctionObject, vectorcall), +#endif + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if defined(_Py_TPFLAGS_HAVE_VECTORCALL) && CYTHON_METH_FASTCALL + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_PyMethod_New, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_CyFunction_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); +#endif + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* GetNameInClass */ +static PyObject *__Pyx__GetNameInClass(PyObject *nmspace, PyObject *name) { + PyObject *result; + PyObject *dict; + assert(PyType_Check(nmspace)); +#if CYTHON_USE_TYPE_SLOTS + dict = ((PyTypeObject*)nmspace)->tp_dict; + Py_XINCREF(dict); +#else + dict = PyObject_GetAttr(nmspace, __pyx_n_s_dict); +#endif + if (likely(dict)) { + result = PyObject_GetItem(dict, name); + Py_DECREF(dict); + if (result) { + return result; + } + } + PyErr_Clear(); + __Pyx_GetModuleGlobalNameUncached(result, name); + return result; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +#if !CYTHON_COMPILING_IN_LIMITED_API +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} +#endif + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result; + result = PyObject_Call(replace, __pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + #if __PYX_LIMITED_VERSION_HEX < 0x030780000 + { + PyObject *compiled = NULL, *result = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "code", code))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "type", (PyObject*)(&PyType_Type)))) return NULL; + compiled = Py_CompileString( + "out = type(code)(\n" + " code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize,\n" + " code.co_flags, code.co_code, code.co_consts, code.co_names,\n" + " code.co_varnames, code.co_filename, co_name, co_firstlineno,\n" + " code.co_lnotab)\n", "", Py_file_input); + if (!compiled) return NULL; + result = PyEval_EvalCode(compiled, scratch_dict, scratch_dict); + Py_DECREF(compiled); + if (!result) PyErr_Print(); + Py_DECREF(result); + result = PyDict_GetItemString(scratch_dict, "out"); + if (result) Py_INCREF(result); + return result; + } + #else + return NULL; + #endif +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + (void) __pyx_cfilenm; + (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + py_funcname = PyUnicode_FromString(funcname); + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(int) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL; + PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + arg_tuple = PyTuple_Pack(2, py_bytes, order_str); + if (!arg_tuple) goto limited_bad; + if (!is_unsigned) { + kwds = PyDict_New(); + if (!kwds) goto limited_bad; + if (PyDict_SetItemString(kwds, "signed", __Pyx_NewRef(Py_True))) goto limited_bad; + } + result = PyObject_Call(from_bytes, arg_tuple, kwds); + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(arg_tuple); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API +static __Pyx_TypeName +__Pyx_PyType_GetName(PyTypeObject* tp) +{ + PyObject *name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_n_s_name); + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) { + PyErr_Clear(); + Py_XDECREF(name); + name = __Pyx_NewRef(__pyx_n_s__100); + } + return name; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if ((sizeof(long) < sizeof(long))) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } +#endif + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; iexc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* PyObjectCall2Args */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 */ +#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C00A2 + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_GetMethod; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* CoroutineBase */ +#include +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } +#if PY_VERSION_HEX >= 0x030300A0 + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); + } +#endif + else if (unlikely(PyTuple_Check(ev))) { + if (PyTuple_GET_SIZE(ev) >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#else + value = PySequence_ITEM(ev, 0); +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if PY_VERSION_HEX >= 0x030300A0 + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + Py_DECREF(ev); +#else + { + PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args); + Py_DECREF(ev); + if (likely(args)) { + value = PySequence_GetItem(args, 0); + Py_DECREF(args); + } + if (unlikely(!value)) { + __Pyx_ErrRestore(NULL, NULL, NULL); + Py_INCREF(Py_None); + value = Py_None; + } + } +#endif + *pvalue = value; + return 0; +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +#define __Pyx_Coroutine_NotStartedError(gen) (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_NotStartedError(PyObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(gen)) { + msg = "can't send non-None value to a just-started coroutine"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a just-started async generator"; + #endif + } else { + msg = "can't send non-None value to a just-started generator"; + } + PyErr_SetString(PyExc_TypeError, msg); +} +#define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing) (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(!self->is_running); + if (unlikely(self->resume_label == 0)) { + if (unlikely(value && value != Py_None)) { + return __Pyx_Coroutine_NotStartedError((PyObject*)self); + } + } + if (unlikely(self->resume_label == -1)) { + return __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + self->is_running = 1; + retval = self->body(self, tstate, value); + self->is_running = 0; +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + return retval; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_MethodReturn(PyObject* gen, PyObject *retval) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (unlikely(!retval)) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (!__Pyx_PyErr_Occurred()) { + PyObject *exc = PyExc_StopIteration; + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + exc = __Pyx_PyExc_StopAsyncIteration; + #endif + __Pyx_PyErr_SetNone(exc); + } + } + return retval; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE +PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) { + PyObject *ret; + PyObject *val = NULL; + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + ret = __Pyx_Coroutine_SendEx(gen, val, 0); + Py_XDECREF(val); + return ret; +} +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03050000 && defined(PyCoro_CheckExact) && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + { + if (value == Py_None) + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + else + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value); + } + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + retval = __Pyx_Coroutine_FinishDelegation(gen); + } else { + retval = __Pyx_Coroutine_SendEx(gen, value, 0); + } + return __Pyx_Coroutine_MethodReturn(self, retval); +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + PyObject *retval = NULL; + int err = 0; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + retval = __Pyx_Coroutine_Close(yf); + if (!retval) + return -1; + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + retval = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf, NULL); + if (!retval) + return -1; + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + } else + #endif + { + PyObject *meth; + gen->is_running = 1; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) + err = -1; + } + gen->is_running = 0; + } + Py_XDECREF(retval); + return err; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + gen->is_running = 1; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03030000 && (defined(__linux__) || PY_VERSION_HEX >= 0x030600B3) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + ret = __Pyx_PyObject_GetIterNextFunc(yf)(yf); + gen->is_running = 0; + if (likely(ret)) { + return ret; + } + return __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_SendEx(gen, Py_None, 0); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + return __Pyx_Coroutine_Close(self); +} +static PyObject *__Pyx_Coroutine_Close(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *retval, *raised_exception; + PyObject *yf = gen->yieldfrom; + int err = 0; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = __Pyx_Coroutine_SendEx(gen, NULL, 1); + if (unlikely(retval)) { + const char *msg; + Py_DECREF(retval); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { +#if PY_VERSION_HEX < 0x03060000 + msg = "async generator ignored GeneratorExit - might require Python 3.6+ finalisation (PEP 525)"; +#else + msg = "async generator ignored GeneratorExit"; +#endif + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + return NULL; + } + raised_exception = PyErr_Occurred(); + if (likely(!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration))) { + if (raised_exception) PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf = gen->yieldfrom; + if (unlikely(gen->is_running)) + return __Pyx_Coroutine_AlreadyRunningError(gen); + if (yf) { + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); + goto throw_here; + } + gen->is_running = 1; + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_n_s_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + gen->is_running = 0; + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + gen->is_running = 0; + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + gen->is_running = 0; + Py_DECREF(yf); + if (!ret) { + ret = __Pyx_Coroutine_FinishDelegation(gen); + } + return __Pyx_Coroutine_MethodReturn(self, ret); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); + return __Pyx_Coroutine_MethodReturn(self, __Pyx_Coroutine_SendEx(gen, NULL, 0)); +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + Py_CLEAR(gen->yieldfrom); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if PY_VERSION_HEX >= 0x030400a1 && CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + Py_TYPE(gen)->tp_del(self); + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } +#if !CYTHON_USE_TP_FINALIZE + assert(self->ob_refcnt == 0); + __Pyx_SET_REFCNT(self, 1); +#endif + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); +#if PY_MAJOR_VERSION >= 3 || defined(PyErr_WarnFormat) + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); +#else + {PyObject *msg; + char *cmsg; + #if CYTHON_COMPILING_IN_PYPY + msg = NULL; + cmsg = (char*) "coroutine was never awaited"; + #else + char *cname; + PyObject *qualname; + qualname = gen->gi_qualname; + cname = PyString_AS_STRING(qualname); + msg = PyString_FromFormat("coroutine '%.50s' was never awaited", cname); + if (unlikely(!msg)) { + PyErr_Clear(); + cmsg = (char*) "coroutine was never awaited"; + } else { + cmsg = PyString_AS_STRING(msg); + } + #endif + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, cmsg, 1) < 0)) + PyErr_WriteUnraisable(self); + Py_XDECREF(msg);} +#endif + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *res = __Pyx_Coroutine_Close(self); + if (unlikely(!res)) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +#if !CYTHON_USE_TP_FINALIZE + assert(Py_REFCNT(self) > 0); + if (likely(--self->ob_refcnt == 0)) { + return; + } + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReference(self); + __Pyx_SET_REFCNT(self, refcnt); + } +#if CYTHON_COMPILING_IN_CPYTHON + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + _Py_DEC_REFTOTAL; +#endif +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif +#endif +} +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) +{ + PyObject *frame = self->gi_frame; + CYTHON_UNUSED_VAR(context); + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (unlikely(!frame)) + return NULL; + self->gi_frame = frame; + } + Py_INCREF(frame); + return frame; +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif + gen->gi_weakreflist = NULL; + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} + +/* PatchModuleWithCoroutine */ +static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + int result; + PyObject *globals, *result_obj; + globals = PyDict_New(); if (unlikely(!globals)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_coroutine_type", + #ifdef __Pyx_Coroutine_USED + (PyObject*)__pyx_CoroutineType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + result = PyDict_SetItemString(globals, "_cython_generator_type", + #ifdef __Pyx_Generator_USED + (PyObject*)__pyx_GeneratorType); + #else + Py_None); + #endif + if (unlikely(result < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore; + if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore; + result_obj = PyRun_String(py_code, Py_file_input, globals, globals); + if (unlikely(!result_obj)) goto ignore; + Py_DECREF(result_obj); + Py_DECREF(globals); + return module; +ignore: + Py_XDECREF(globals); + PyErr_WriteUnraisable(module); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) { + Py_DECREF(module); + module = NULL; + } +#else + py_code++; +#endif + return module; +} + +/* PatchGeneratorABC */ +#ifndef CYTHON_REGISTER_ABCS +#define CYTHON_REGISTER_ABCS 1 +#endif +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) +static PyObject* __Pyx_patch_abc_module(PyObject *module); +static PyObject* __Pyx_patch_abc_module(PyObject *module) { + module = __Pyx_Coroutine_patch_module( + module, "" +"if _cython_generator_type is not None:\n" +" try: Generator = _module.Generator\n" +" except AttributeError: pass\n" +" else: Generator.register(_cython_generator_type)\n" +"if _cython_coroutine_type is not None:\n" +" try: Coroutine = _module.Coroutine\n" +" except AttributeError: pass\n" +" else: Coroutine.register(_cython_coroutine_type)\n" + ); + return module; +} +#endif +static int __Pyx_patch_abc(void) { +#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + static int abc_patched = 0; + if (CYTHON_REGISTER_ABCS && !abc_patched) { + PyObject *module; + module = PyImport_ImportModule((PY_MAJOR_VERSION >= 3) ? "collections.abc" : "collections"); + if (unlikely(!module)) { + PyErr_WriteUnraisable(NULL); + if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, + ((PY_MAJOR_VERSION >= 3) ? + "Cython module failed to register with collections.abc module" : + "Cython module failed to register with collections module"), 1) < 0)) { + return -1; + } + } else { + module = __Pyx_patch_abc_module(module); + abc_patched = 1; + if (unlikely(!module)) + return -1; + Py_DECREF(module); + } + module = PyImport_ImportModule("backports_abc"); + if (module) { + module = __Pyx_patch_abc_module(module); + Py_XDECREF(module); + } + if (!module) { + PyErr_Clear(); + } + } +#else + if ((0)) __Pyx_Coroutine_patch_module(NULL, NULL); +#endif + return 0; +} + +/* Generator */ +static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL}, + {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + (char*) PyDoc_STR("object being iterated by 'yield from', or None")}, + {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if CYTHON_USE_TYPE_SPECS + {(char *) "__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + (char*) PyDoc_STR("name of the generator"), 0}, + {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + (char*) PyDoc_STR("qualified name of the generator"), 0}, + {(char *) "gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + (char*) PyDoc_STR("Frame of the generator"), 0}, + {0, 0, 0, 0, 0} +}; +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) __Pyx_PyObject_GenericGetAttrNoDict}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + __pyx_GeneratorType_slots +}; +#else +static PyTypeObject __pyx_GeneratorType_type = { + PyVarObject_HEAD_INIT(0, 0) + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, + (destructor) __Pyx_Coroutine_dealloc, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, + 0, + (traverseproc) __Pyx_Coroutine_traverse, + 0, + 0, + offsetof(__pyx_CoroutineObject, gi_weakreflist), + 0, + (iternextfunc) __Pyx_Generator_Next, + __pyx_Generator_methods, + __pyx_Generator_memberlist, + __pyx_Generator_getsets, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if CYTHON_USE_TP_FINALIZE + 0, +#else + __Pyx_Coroutine_del, +#endif + 0, +#if CYTHON_USE_TP_FINALIZE + __Pyx_Coroutine_del, +#elif PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if __PYX_NEED_TP_PRINT_SLOT + 0, +#endif +#if PY_VERSION_HEX >= 0x030C0000 + 0, +#endif +#if PY_VERSION_HEX >= 0x030d00A4 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, +#endif +}; +#endif +static int __pyx_Generator_init(PyObject *module) { +#if CYTHON_USE_TYPE_SPECS + __pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_GeneratorType_spec, NULL); +#else + CYTHON_UNUSED_VAR(module); + __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict; + __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; + __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); +#endif + if (unlikely(!__pyx_GeneratorType)) { + return -1; + } + return 0; +} + +/* CheckBinaryVersion */ +static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030B00A4 + return Py_Version & ~0xFFUL; +#else + const char* rt_version = Py_GetVersion(); + unsigned long version = 0; + unsigned long factor = 0x01000000UL; + unsigned int digit = 0; + int i = 0; + while (factor) { + while ('0' <= rt_version[i] && rt_version[i] <= '9') { + digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); + ++i; + } + version += factor * digit; + if (rt_version[i] != '.') + break; + digit = 0; + factor >>= 8; + ++i; + } + return version; +#endif +} +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* FunctionExport */ +static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig) { + PyObject *d = 0; + PyObject *cobj = 0; + union { + void (*fp)(void); + void *p; + } tmp; + d = PyObject_GetAttrString(__pyx_m, (char *)"__pyx_capi__"); + if (!d) { + PyErr_Clear(); + d = PyDict_New(); + if (!d) + goto bad; + Py_INCREF(d); + if (PyModule_AddObject(__pyx_m, (char *)"__pyx_capi__", d) < 0) + goto bad; + } + tmp.fp = f; + cobj = PyCapsule_New(tmp.p, sig, 0); + if (!cobj) + goto bad; + if (PyDict_SetItemString(d, name, cobj) < 0) + goto bad; + Py_DECREF(cobj); + Py_DECREF(d); + return 0; +bad: + Py_XDECREF(cobj); + Py_XDECREF(d); + return -1; +} + +/* InitStrings */ +#if PY_MAJOR_VERSION >= 3 +static int __Pyx_InitString(__Pyx_StringTabEntry t, PyObject **str) { + if (t.is_unicode | t.is_str) { + if (t.intern) { + *str = PyUnicode_InternFromString(t.s); + } else if (t.encoding) { + *str = PyUnicode_Decode(t.s, t.n - 1, t.encoding, NULL); + } else { + *str = PyUnicode_FromStringAndSize(t.s, t.n - 1); + } + } else { + *str = PyBytes_FromStringAndSize(t.s, t.n - 1); + } + if (!*str) + return -1; + if (PyObject_Hash(*str) == -1) + return -1; + return 0; +} +#endif +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION >= 3 + __Pyx_InitString(*t, t->p); + #else + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + #endif + ++t; + } + return 0; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_LIMITED_API) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetName(Py_TYPE(result)); +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type " __Pyx_FMT_TYPENAME ")", + type_name, type_name, result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.cpython-312-darwin.so new file mode 100755 index 0000000..75aeb73 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pxd b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pxd new file mode 100644 index 0000000..bf0ea53 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pxd @@ -0,0 +1,49 @@ +# cython: language_level=3 +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License + +cdef bint isclose(double a, double b, double rel_tol, double abs_tol) +cdef double normalize_rad_angle(double a) +cdef double normalize_deg_angle(double a) + +cdef class Vec2: + cdef readonly double x, y + +# Vec2 C-functions: +cdef Vec2 v2_add(Vec2 a, Vec2 b) +cdef Vec2 v2_sub(Vec2 a, Vec2 b) +cdef Vec2 v2_mul(Vec2 a, double factor) +cdef Vec2 v2_normalize(Vec2 a, double length) +cdef double v2_dot(Vec2 a, Vec2 b) +cdef double v2_det(Vec2 a, Vec2 b) +cdef double v2_dist(Vec2 a, Vec2 b) +cdef Vec2 v2_from_angle(double angle, double length) +cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000 +cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor) +cdef Vec2 v2_ortho(Vec2 a, bint ccw) +cdef Vec2 v2_project(Vec2 a, Vec2 b) +cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol) + + +cdef class Vec3: + cdef readonly double x, y, z + +# Vec3 C-functions: +cdef Vec3 v3_add(Vec3 a, Vec3 b) +cdef Vec3 v3_sub(Vec3 a, Vec3 b) +cdef Vec3 v3_mul(Vec3 a, double factor) +cdef Vec3 v3_reverse(Vec3 a) +cdef double v3_dot(Vec3 a, Vec3 b) +cdef Vec3 v3_cross(Vec3 a, Vec3 b) +cdef double v3_magnitude_sqr(Vec3 a) +cdef double v3_magnitude(Vec3 a) +cdef double v3_dist(Vec3 a, Vec3 b) +cdef Vec3 v3_from_angle(double angle, double length) +cdef double v3_angle_between(Vec3 a, Vec3 b) except -1000 +cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target) +cdef Vec3 v3_normalize(Vec3 a, double length) +cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor) +cdef Vec3 v3_ortho(Vec3 a, bint ccw) +cdef Vec3 v3_project(Vec3 a, Vec3 b) +cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol) + diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pyx b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pyx new file mode 100644 index 0000000..962963e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acc/vector.pyx @@ -0,0 +1,838 @@ +# cython: language_level=3 +# cython: c_api_binop_methods=True +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from typing import Iterable, List, Sequence, TYPE_CHECKING, Tuple, Iterator +from libc.math cimport fabs, sin, cos, M_PI, hypot, atan2, acos, sqrt, fmod +import random + +cdef extern from "constants.h": + const double ABS_TOL + const double REL_TOL + const double M_TAU + +cdef double RAD2DEG = 180.0 / M_PI +cdef double DEG2RAD = M_PI / 180.0 + +if TYPE_CHECKING: + from ezdxf.math import AnyVec, UVec + +cdef bint isclose(double a, double b, double rel_tol, double abs_tol): + # Has to match the Python implementation! + cdef double diff = fabs(b - a) + return diff <= fabs(rel_tol * b) or \ + diff <= fabs(rel_tol * a) or \ + diff <= abs_tol + + +cdef double normalize_rad_angle(double a): + # Emulate the Python behavior of (a % math.tau) + cdef double res = fmod(a, M_TAU) + if res < 0.0: + res += M_TAU + return res + +def _normalize_rad_angle(double angle): + # just for testing + return normalize_rad_angle(angle) + +cdef double normalize_deg_angle(double a): + # Emulate the Python behavior of (a % 360) + cdef double res = fmod(a, 360.0) + if res < 0.0: + res += 360.0 + return res + +def _normalize_deg_angle(double angle): + # just for testing + return normalize_deg_angle(angle) + +cdef class Vec2: + """ Immutable 2D vector. + + Init: + + - Vec2(vec2) + - Vec2(vec3) + - Vec2((x, y)) + - Vec2((x, y, z)), ignore z-axis + - Vec2(x, y) + - Vec2(x, y, z), ignore z-axis + + """ + + def __cinit__(self, *args): + cdef Py_ssize_t count = len( args) + + if count == 0: # fastest init - default constructor + self.x = 0 + self.y = 0 + return + + if count == 1: + arg = args[0] + if isinstance(arg, Vec2): + # fast init by Vec2() + self.x = ( arg).x + self.y = ( arg).y + return + if isinstance(arg, Vec3): + # fast init by Vec3() + self.x = ( arg).x + self.y = ( arg).y + return + args = arg + count = len(args) + + # ignore z-axis but raise error for 4 or more arguments + if count > 3: + raise TypeError('invalid argument count') + + # slow init by sequence + self.x = args[0] + self.y = args[1] + + def __reduce__(self): + return Vec2, (self.x, self.y) + + @property + def vec3(self) -> Vec3: + return Vec3(self) + + def round(self, ndigits=None) -> Vec2: + # only used for testing + return Vec2(round(self.x, ndigits), round(self.y, ndigits)) + + @staticmethod + def list(items: Iterable[UVec]) -> List[Vec2]: + return list(Vec2.generate(items)) + + @staticmethod + def tuple(items: Iterable[UVec]) -> Sequence[Vec2]: + return tuple(Vec2.generate(items)) + + @staticmethod + def generate(items: Iterable[UVec]) -> Iterator[Vec2]: + return (Vec2(item) for item in items) + + @staticmethod + def from_angle(double angle, double length = 1.0) -> Vec2: + return v2_from_angle(angle, length) + + @staticmethod + def from_deg_angle(double angle, double length = 1.0) -> Vec2: + return v2_from_angle(angle * DEG2RAD, length) + + def __str__(self) -> str: + return f'({self.x}, {self.y})' + + def __repr__(self)-> str: + return "Vec2" + self.__str__() + + def __len__(self) -> int: + return 2 + + def __hash__(self) -> int: + return hash((self.x, self.y)) + + def copy(self) -> Vec2: + return self # immutable + + def __copy__(self) -> Vec2: + return self # immutable + + def __deepcopy__(self, memodict: dict) -> Vec2: + return self # immutable + + def __getitem__(self, int index) -> float: + if index == 0: + return self.x + elif index == 1: + return self.y + else: + raise IndexError(f'invalid index {index}') + + def __iter__(self) -> Iterator[float]: + yield self.x + yield self.y + + def __abs__(self) -> float: + return hypot(self.x, self.y) + + @property + def magnitude(self) -> float: + return hypot(self.x, self.y) + + @property + def is_null(self) -> bool: + return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL + + @property + def angle(self) -> float: + return atan2(self.y, self.x) + + @property + def angle_deg(self) -> float: + return atan2(self.y, self.x) * RAD2DEG + + def orthogonal(self, ccw: bool = True) -> Vec2: + return v2_ortho(self, ccw) + + def lerp(self, other: "AnyVec", double factor = 0.5) -> Vec2: + cdef Vec2 o = Vec2(other) + return v2_lerp(self, o, factor) + + def normalize(self, double length = 1.) -> Vec2: + return v2_normalize(self, length) + + def project(self, other: AnyVec) -> Vec2: + cdef Vec2 o = Vec2(other) + return v2_project(self, o) + + def __neg__(self) -> Vec2: + cdef Vec2 res = Vec2() + res.x = -self.x + res.y = -self.y + return res + + reversed = __neg__ + + def __bool__(self) -> bool: + return self.x != 0 or self.y != 0 + + def isclose(self, other: UVec, *, double rel_tol=REL_TOL, + double abs_tol = ABS_TOL) -> bool: + cdef Vec2 o = Vec2(other) + return isclose(self.x, o.x, rel_tol, abs_tol) and \ + isclose(self.y, o.y, rel_tol, abs_tol) + + def __eq__(self, other: UVec) -> bool: + if not isinstance(other, Vec2): + other = Vec2(other) + return self.x == other.x and self.y == other.y + + def __lt__(self, other) -> bool: + cdef Vec2 o = Vec2(other) + if self.x == o.x: + return self.y < o.y + else: + return self.x < o.x + + def __add__(self, other: AnyVec) -> Vec2: + if not isinstance(other, Vec2): + other = Vec2(other) + return v2_add(self, other) + + # __radd__ not supported for Vec2 + + __iadd__ = __add__ # immutable + + def __sub__(self, other: AnyVec) -> Vec2: + if not isinstance(other, Vec2): + other = Vec2(other) + return v2_sub(self, other) + + # __rsub__ not supported for Vec2 + + __isub__ = __sub__ # immutable + + def __mul__(self, factor) -> Vec2: + if isinstance(self, Vec2): + return v2_mul(self, factor) + elif isinstance(factor, Vec2): + return v2_mul( factor, self) + else: + return NotImplemented + + # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + + def __rmul__(self, double factor) -> Vec2: + # for Cython >= 3.0 + return v2_mul(self, factor) + + __imul__ = __mul__ # immutable + + def __truediv__(self, double factor) -> Vec2: + return v2_mul(self, 1.0 / factor) + + # __rtruediv__ not supported -> TypeError + + def dot(self, other: AnyVec) -> float: + cdef Vec2 o = Vec2(other) + return v2_dot(self, o) + + def det(self, other: AnyVec) -> float: + cdef Vec2 o = Vec2(other) + return v2_det(self, o) + + def distance(self, other: AnyVec) -> float: + cdef Vec2 o = Vec2(other) + return v2_dist(self, o) + + def angle_between(self, other: AnyVec) -> float: + cdef Vec2 o = Vec2(other) + return v2_angle_between(self, o) + + def rotate(self, double angle) -> Vec2: + cdef double self_angle = atan2(self.y, self.x) + cdef double magnitude = hypot(self.x, self.y) + return v2_from_angle(self_angle + angle, magnitude) + + def rotate_deg(self, double angle) -> Vec2: + return self.rotate(angle * DEG2RAD) + + @staticmethod + def sum(items: Iterable[Vec2]) -> Vec2: + cdef Vec2 res = Vec2() + cdef Vec2 tmp + res.x = 0.0 + res.y = 0.0 + for v in items: + tmp = v + res.x += tmp.x + res.y += tmp.y + return res + + +cdef Vec2 v2_add(Vec2 a, Vec2 b): + res = Vec2() + res.x = a.x + b.x + res.y = a.y + b.y + return res + +cdef Vec2 v2_sub(Vec2 a, Vec2 b): + res = Vec2() + res.x = a.x - b.x + res.y = a.y - b.y + return res + +cdef Vec2 v2_mul(Vec2 a, double factor): + res = Vec2() + res.x = a.x * factor + res.y = a.y * factor + return res + +cdef double v2_dot(Vec2 a, Vec2 b): + return a.x * b.x + a.y * b.y + +cdef double v2_det(Vec2 a, Vec2 b): + return a.x * b.y - a.y * b.x + +cdef double v2_dist(Vec2 a, Vec2 b): + return hypot(a.x - b.x, a.y - b.y) + +cdef Vec2 v2_from_angle(double angle, double length): + cdef Vec2 res = Vec2() + res.x = cos(angle) * length + res.y = sin(angle) * length + return res + +cdef double v2_angle_between(Vec2 a, Vec2 b) except -1000: + cdef double cos_theta = v2_dot(v2_normalize(a, 1.0), v2_normalize(b, 1.0)) + # avoid domain errors caused by floating point imprecision: + if cos_theta < -1.0: + cos_theta = -1.0 + elif cos_theta > 1.0: + cos_theta = 1.0 + return acos(cos_theta) + +cdef Vec2 v2_normalize(Vec2 a, double length): + cdef double factor = length / hypot(a.x, a.y) + cdef Vec2 res = Vec2() + res.x = a.x * factor + res.y = a.y * factor + return res + +cdef Vec2 v2_lerp(Vec2 a, Vec2 b, double factor): + cdef Vec2 res = Vec2() + res.x = a.x + (b.x - a.x) * factor + res.y = a.y + (b.y - a.y) * factor + return res + +cdef Vec2 v2_ortho(Vec2 a, bint ccw): + cdef Vec2 res = Vec2() + if ccw: + res.x = -a.y + res.y = a.x + else: + res.x = a.y + res.y = -a.x + return res + +cdef Vec2 v2_project(Vec2 a, Vec2 b): + cdef Vec2 uv = v2_normalize(a, 1.0) + return v2_mul(uv, v2_dot(uv, b)) + +cdef bint v2_isclose(Vec2 a, Vec2 b, double rel_tol, double abs_tol): + return isclose(a.x, b.x, rel_tol, abs_tol) and \ + isclose(a.y, b.y, rel_tol, abs_tol) + + +cdef class Vec3: + """ Immutable 3D vector. + + Init: + + - Vec3() + - Vec3(vec3) + - Vec3(vec2) + - Vec3((x, y)) + - Vec3((x, y, z)) + - Vec3(x, y) + - Vec3(x, y, z) + + """ + + def __cinit__(self, *args): + cdef Py_ssize_t count = len( args) + if count == 0: # fastest init - default constructor + self.x = 0 + self.y = 0 + self.z = 0 + return + + if count == 1: + arg0 = args[0] + if isinstance(arg0, Vec3): + # fast init by Vec3() + self.x = ( arg0).x + self.y = ( arg0).y + self.z = ( arg0).z + return + if isinstance(arg0, Vec2): + # fast init by Vec2() + self.x = ( arg0).x + self.y = ( arg0).y + self.z = 0 + return + args = arg0 + count = len(args) + + if count > 3 or count < 2: + raise TypeError('invalid argument count') + + # slow init by sequence + self.x = args[0] + self.y = args[1] + if count > 2: + self.z = args[2] + else: + self.z = 0.0 + + def __reduce__(self): + return Vec3, self.xyz + + @property + def xy(self) -> Vec3: + cdef Vec3 res = Vec3() + res.x = self.x + res.y = self.y + return res + + @property + def xyz(self) -> Tuple[float, float, float]: + return self.x, self.y, self.z + + @property + def vec2(self) -> Vec2: + cdef Vec2 res = Vec2() + res.x = self.x + res.y = self.y + return res + + def replace(self, x: float = None, y: float = None, + z: float = None) -> Vec3: + cdef Vec3 res = Vec3() + res.x = self.x if x is None else x + res.y = self.y if y is None else y + res.z = self.z if z is None else z + return res + + def round(self, ndigits: int | None = None) -> Vec3: + return Vec3( + round(self.x, ndigits), + round(self.y, ndigits), + round(self.z, ndigits), + ) + + @staticmethod + def list(items: Iterable[UVec]) -> List[Vec3]: + return list(Vec3.generate(items)) + + @staticmethod + def tuple(items: Iterable[UVec]) -> Sequence[Vec3]: + return tuple(Vec3.generate(items)) + + @staticmethod + def generate(items: Iterable[UVec]) -> Iterator[Vec3]: + return (Vec3(item) for item in items) + + @staticmethod + def from_angle(double angle, double length = 1.0) -> Vec3: + return v3_from_angle(angle, length) + + @staticmethod + def from_deg_angle(double angle, double length = 1.0) -> Vec3: + return v3_from_angle(angle * DEG2RAD, length) + + @staticmethod + def random(double length = 1.0) -> Vec3: + cdef Vec3 res = Vec3() + uniform = random.uniform + res.x = uniform(-1, 1) + res.y = uniform(-1, 1) + res.z = uniform(-1, 1) + return v3_normalize(res, length) + + def __str__(self) -> str: + return f'({self.x}, {self.y}, {self.z})' + + def __repr__(self)-> str: + return "Vec3" + self.__str__() + + def __len__(self) -> int: + return 3 + + def __hash__(self) -> int: + return hash(self.xyz) + + def copy(self) -> Vec3: + return self # immutable + + __copy__ = copy + + def __deepcopy__(self, memodict: dict) -> Vec3: + return self # immutable! + + def __getitem__(self, int index) -> float: + if index == 0: + return self.x + elif index == 1: + return self.y + elif index == 2: + return self.z + else: + raise IndexError(f'invalid index {index}') + + def __iter__(self) -> Iterator[float]: + yield self.x + yield self.y + yield self.z + + def __abs__(self) -> float: + return v3_magnitude(self) + + @property + def magnitude(self) -> float: + return v3_magnitude(self) + + @property + def magnitude_xy(self) -> float: + return hypot(self.x, self.y) + + @property + def magnitude_square(self) -> float: + return v3_magnitude_sqr(self) + + @property + def is_null(self) -> bool: + return fabs(self.x) <= ABS_TOL and fabs(self.y) <= ABS_TOL and \ + fabs(self.z) <= ABS_TOL + + def is_parallel(self, other: UVec, *, double rel_tol=REL_TOL, + double abs_tol = ABS_TOL) -> bool: + cdef Vec3 o = Vec3(other) + cdef Vec3 v1 = v3_normalize(self, 1.0) + cdef Vec3 v2 = v3_normalize(o, 1.0) + cdef Vec3 neg_v2 = v3_reverse(v2) + return v3_isclose(v1, v2, rel_tol, abs_tol) or \ + v3_isclose(v1, neg_v2, rel_tol, abs_tol) + + @property + def spatial_angle(self) -> float: + return acos(v3_dot( X_AXIS, v3_normalize(self, 1.0))) + + @property + def spatial_angle_deg(self) -> float: + return self.spatial_angle * RAD2DEG + + @property + def angle(self) -> float: + return atan2(self.y, self.x) + + @property + def angle_deg(self) -> float: + return atan2(self.y, self.x) * RAD2DEG + + def orthogonal(self, ccw: bool = True) -> Vec3: + return v3_ortho(self, ccw) + + def lerp(self, other: UVec, double factor=0.5) -> Vec3: + if not isinstance(other, Vec3): + other = Vec3(other) + return v3_lerp(self, other, factor) + + def project(self, other: UVec) -> Vec3: + if not isinstance(other, Vec3): + other = Vec3(other) + return v3_project(self, other) + + def normalize(self, double length = 1.) -> Vec3: + return v3_normalize(self, length) + + def reversed(self) -> Vec3: + return v3_reverse(self) + + def __neg__(self) -> Vec3: + return v3_reverse(self) + + def __bool__(self) -> bool: + return not self.is_null + + def isclose(self, other: UVec, *, double rel_tol = REL_TOL, + double abs_tol = ABS_TOL) -> bool: + if not isinstance(other, Vec3): + other = Vec3(other) + return v3_isclose(self, other, rel_tol, abs_tol) + + def __eq__(self, other: UVec) -> bool: + if not isinstance(other, Vec3): + other = Vec3(other) + return self.x == other.x and self.y == other.y and self.z == other.z + + def __lt__(self, other: UVec) -> bool: + if not isinstance(other, Vec3): + other = Vec3(other) + if self.x == ( other).x: + return self.y < ( other).y + else: + return self.x < ( other).x + + # Special Cython (<3.0) feature: __radd__ == __add__(other, self) + def __add__(self, other) -> Vec3: + if not isinstance(self, Vec3): + # other is the real self + return v3_add(Vec3(self), other) + + if not isinstance(other, Vec3): + other = Vec3(other) + return v3_add( self, other) + + __radd__ = __add__ # Cython >= 3.0 + + __iadd__ = __add__ # immutable + + # Special Cython (<3.0) feature: __rsub__ == __sub__(other, self) + def __sub__(self, other) -> Vec3: + if not isinstance(self, Vec3): + # other is the real self + return v3_sub(Vec3(self), other) + + if not isinstance(other, Vec3): + other = Vec3(other) + return v3_sub( self, other) + + def __rsub__(self, other) -> Vec3: + # for Cython >= 3.0 + return v3_sub(Vec3(other), self) + + __isub__ = __sub__ # immutable + + # Special Cython <(3.0) feature: __rmul__ == __mul__(factor, self) + def __mul__(self, factor) -> Vec3: + if isinstance(factor, Vec3): + return v3_mul( factor, self) + return v3_mul( self, factor) + + def __rmul__(self, double factor) -> Vec3: + # for Cython >= 3.0 + return v3_mul(self, factor) + + __imul__ = __mul__ # immutable + + def __truediv__(self, double factor) -> Vec3: + return v3_mul(self, 1.0 / factor) + + # __rtruediv__ not supported -> TypeError + + @staticmethod + def sum(items: Iterable[UVec]) -> Vec3: + cdef Vec3 res = Vec3() + cdef Vec3 tmp + for v in items: + tmp = Vec3(v) + res.x += tmp.x + res.y += tmp.y + res.z += tmp.z + return res + + def dot(self, other: UVec) -> float: + cdef Vec3 o = Vec3(other) + return v3_dot(self, o) + + def cross(self, other: UVec) -> Vec3: + cdef Vec3 o = Vec3(other) + return v3_cross(self, o) + + def distance(self, other: UVec) -> float: + cdef Vec3 o = Vec3(other) + return v3_dist(self, o) + + def angle_between(self, other: UVec) -> float: + cdef Vec3 o = Vec3(other) + return v3_angle_between(self, o) + + def angle_about(self, base: UVec, target: UVec) -> float: + cdef Vec3 b = Vec3(base) + cdef Vec3 t = Vec3(target) + return v3_angle_about(self, b, t) + + def rotate(self, double angle) -> Vec3: + cdef double angle_ = atan2(self.y, self.x) + angle + cdef double magnitude_ = hypot(self.x, self.y) + cdef Vec3 res = Vec3.from_angle(angle_, magnitude_) + res.z = self.z + return res + + def rotate_deg(self, double angle) -> Vec3: + return self.rotate(angle * DEG2RAD) + + +X_AXIS = Vec3(1, 0, 0) +Y_AXIS = Vec3(0, 1, 0) +Z_AXIS = Vec3(0, 0, 1) +NULLVEC = Vec3(0, 0, 0) + +cdef Vec3 v3_add(Vec3 a, Vec3 b): + res = Vec3() + res.x = a.x + b.x + res.y = a.y + b.y + res.z = a.z + b.z + return res + +cdef Vec3 v3_sub(Vec3 a, Vec3 b): + res = Vec3() + res.x = a.x - b.x + res.y = a.y - b.y + res.z = a.z - b.z + return res + + +cdef Vec3 v3_mul(Vec3 a, double factor): + res = Vec3() + res.x = a.x * factor + res.y = a.y * factor + res.z = a.z * factor + return res + + +cdef Vec3 v3_reverse(Vec3 a): + cdef Vec3 res = Vec3() + res.x = -a.x + res.y = -a.y + res.z = -a.z + return res + + +cdef double v3_dot(Vec3 a, Vec3 b): + return a.x * b.x + a.y * b.y + a.z * b.z + + +cdef Vec3 v3_cross(Vec3 a, Vec3 b): + res = Vec3() + res.x = a.y * b.z - a.z * b.y + res.y = a.z * b.x - a.x * b.z + res.z = a.x * b.y - a.y * b.x + return res + + +cdef inline double v3_magnitude_sqr(Vec3 a): + return a.x * a.x + a.y * a.y + a.z * a.z + + +cdef inline double v3_magnitude(Vec3 a): + return sqrt(v3_magnitude_sqr(a)) + + +cdef double v3_dist(Vec3 a, Vec3 b): + cdef double dx = a.x - b.x + cdef double dy = a.y - b.y + cdef double dz = a.z - b.z + return sqrt(dx * dx + dy * dy + dz * dz) + + +cdef Vec3 v3_from_angle(double angle, double length): + cdef Vec3 res = Vec3() + res.x = cos(angle) * length + res.y = sin(angle) * length + return res + + +cdef double v3_angle_between(Vec3 a, Vec3 b) except -1000: + cdef double cos_theta = v3_dot(v3_normalize(a, 1.0), v3_normalize(b, 1.0)) + # avoid domain errors caused by floating point imprecision: + if cos_theta < -1.0: + cos_theta = -1.0 + elif cos_theta > 1.0: + cos_theta = 1.0 + return acos(cos_theta) + + +cdef double v3_angle_about(Vec3 a, Vec3 base, Vec3 target): + cdef Vec3 x_axis = v3_normalize(v3_sub(base, v3_project(a, base)), 1.0) + cdef Vec3 y_axis = v3_normalize(v3_cross(a, x_axis), 1.0) + cdef double target_projected_x = v3_dot(x_axis, target) + cdef double target_projected_y = v3_dot(y_axis, target) + return normalize_rad_angle(atan2(target_projected_y, target_projected_x)) + + +cdef Vec3 v3_normalize(Vec3 a, double length): + cdef double factor = length / v3_magnitude(a) + cdef Vec3 res = Vec3() + res.x = a.x * factor + res.y = a.y * factor + res.z = a.z * factor + return res + + +cdef Vec3 v3_lerp(Vec3 a, Vec3 b, double factor): + cdef Vec3 res = Vec3() + res.x = a.x + (b.x - a.x) * factor + res.y = a.y + (b.y - a.y) * factor + res.z = a.z + (b.z - a.z) * factor + return res + + +cdef Vec3 v3_ortho(Vec3 a, bint ccw): + cdef Vec3 res = Vec3() + res.z = a.z + if ccw: + res.x = -a.y + res.y = a.x + else: + res.x = a.y + res.y = -a.x + return res + + +cdef Vec3 v3_project(Vec3 a, Vec3 b): + cdef Vec3 uv = v3_normalize(a, 1.0) + return v3_mul(uv, v3_dot(uv, b)) + + +cdef bint v3_isclose(Vec3 a, Vec3 b, double rel_tol, double abs_tol): + return isclose(a.x, b.x, rel_tol, abs_tol) and \ + isclose(a.y, b.y, rel_tol, abs_tol) and \ + isclose(a.z, b.z, rel_tol, abs_tol) + + +def distance(p1: UVec, p2: UVec) -> float: + cdef Vec3 a = Vec3(p1) + cdef Vec3 b = Vec3(p2) + return v3_dist(a, b) + + +def lerp(p1: UVec, p2: UVec, double factor = 0.5) -> Vec3: + cdef Vec3 a = Vec3(p1) + cdef Vec3 b = Vec3(p2) + return v3_lerp(a, b, factor) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/__init__.py new file mode 100644 index 0000000..6f356cf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +# Users should always import from ezdxf.acis.api! diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..2e5201f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/abstract.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/abstract.cpython-312.pyc new file mode 100644 index 0000000..c66e5c0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/abstract.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000..caa7d76 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/api.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/cache.cpython-312.pyc new file mode 100644 index 0000000..64128dd Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/cache.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/const.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/const.cpython-312.pyc new file mode 100644 index 0000000..8c95705 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/const.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dbg.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dbg.cpython-312.pyc new file mode 100644 index 0000000..011da1d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dbg.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dxf.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dxf.cpython-312.pyc new file mode 100644 index 0000000..a71f30c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/dxf.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/entities.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/entities.cpython-312.pyc new file mode 100644 index 0000000..416d6de Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/entities.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/hdr.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/hdr.cpython-312.pyc new file mode 100644 index 0000000..762f392 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/hdr.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/mesh.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/mesh.cpython-312.pyc new file mode 100644 index 0000000..1d2dbe5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/mesh.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sab.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sab.cpython-312.pyc new file mode 100644 index 0000000..4e0ffd0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sab.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sat.cpython-312.pyc new file mode 100644 index 0000000..cf222f6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/sat.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/type_hints.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/type_hints.cpython-312.pyc new file mode 100644 index 0000000..e140953 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/acis/__pycache__/type_hints.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/abstract.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/abstract.py new file mode 100644 index 0000000..f825c16 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/abstract.py @@ -0,0 +1,224 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TypeVar, Generic, TYPE_CHECKING, Optional +from abc import ABC, abstractmethod +from .const import NULL_PTR_NAME, MIN_EXPORT_VERSION +from .hdr import AcisHeader + +if TYPE_CHECKING: + from .entities import AcisEntity + from ezdxf.math import Vec3 + + +T = TypeVar("T", bound="AbstractEntity") + + +class AbstractEntity(ABC): + """Unified query interface for SAT and SAB data.""" + + name: str + id: int = -1 + + def __str__(self): + return f"{self.name}" + + @property + def is_null_ptr(self) -> bool: + """Returns ``True`` if this entity is the ``NULL_PTR`` entity.""" + return self.name == NULL_PTR_NAME + + +class DataLoader(ABC): + """Data loading interface to create high level AcisEntity data from low + level AbstractEntity representation. + + """ + + version: int = MIN_EXPORT_VERSION + + @abstractmethod + def has_data(self) -> bool: + pass + + @abstractmethod + def read_int(self, skip_sat: Optional[int] = None) -> int: + """There are sometimes additional int values in SAB files which are + not present in SAT files, maybe reference counters e.g. vertex, coedge. + """ + pass + + @abstractmethod + def read_double(self) -> float: + pass + + @abstractmethod + def read_interval(self) -> float: + pass + + @abstractmethod + def read_vec3(self) -> tuple[float, float, float]: + pass + + @abstractmethod + def read_bool(self, true: str, false: str) -> bool: + pass + + @abstractmethod + def read_str(self) -> str: + pass + + @abstractmethod + def read_ptr(self) -> AbstractEntity: + pass + + @abstractmethod + def read_transform(self) -> list[float]: + pass + + +class DataExporter(ABC): + version: int = MIN_EXPORT_VERSION + + @abstractmethod + def write_int(self, value: int, skip_sat=False) -> None: + """There are sometimes additional int values in SAB files which are + not present in SAT files, maybe reference counters e.g. vertex, coedge. + """ + pass + + @abstractmethod + def write_double(self, value: float) -> None: + pass + + @abstractmethod + def write_interval(self, value: float) -> None: + pass + + @abstractmethod + def write_loc_vec3(self, value: Vec3) -> None: + pass + + @abstractmethod + def write_dir_vec3(self, value: Vec3) -> None: + pass + + @abstractmethod + def write_bool(self, value: bool, true: str, false: str) -> None: + pass + + @abstractmethod + def write_str(self, value: str) -> None: + pass + + @abstractmethod + def write_literal_str(self, value: str) -> None: + pass + + @abstractmethod + def write_ptr(self, entity: AcisEntity) -> None: + pass + + @abstractmethod + def write_transform(self, data: list[str]) -> None: + pass + + +class AbstractBuilder(Generic[T]): + header: AcisHeader + bodies: list[T] + entities: list[T] + + def reorder_records(self) -> None: + if len(self.entities) == 0: + return + header: list[T] = [] + entities: list[T] = [] + for e in self.entities: + if e.name == "body": + header.append(e) + elif e.name == "asmheader": + header.insert(0, e) # has to be the first record + else: + entities.append(e) + self.entities = header + entities + + def reset_ids(self, start: int = 0) -> None: + for num, entity in enumerate(self.entities, start=start): + entity.id = num + + def clear_ids(self) -> None: + for entity in self.entities: + entity.id = -1 + + +class EntityExporter(Generic[T]): + def __init__(self, header: AcisHeader): + self.header = header + self.version = header.version + self._exported_entities: dict[int, T] = {} + if self.header.has_asm_header: + self.export(self.header.asm_header()) + + def export_records(self) -> list[T]: + return list(self._exported_entities.values()) + + @abstractmethod + def make_record(self, entity: AcisEntity) -> T: + pass + + @abstractmethod + def make_data_exporter(self, record: T) -> DataExporter: + pass + + def get_record(self, entity: AcisEntity) -> T: + assert not entity.is_none + return self._exported_entities[id(entity)] + + def export(self, entity: AcisEntity): + if entity.is_none: + raise TypeError("invalid NONE_REF entity given") + self._make_all_records(entity) + self._export_data(entity) + + def _has_record(self, entity: AcisEntity) -> bool: + return id(entity) in self._exported_entities + + def _add_record(self, entity: AcisEntity, record: T) -> None: + assert not entity.is_none + self._exported_entities[id(entity)] = record + + def _make_all_records(self, entity: AcisEntity): + def add(e: AcisEntity) -> bool: + if not e.is_none and not self._has_record(e): + self._add_record(e, self.make_record(e)) + return True + return False + + entities = [entity] + while entities: + next_entity = entities.pop(0) + add(next_entity) + for sub_entity in next_entity.entities(): + if add(sub_entity): + entities.append(sub_entity) + + def _export_data(self, entity: AcisEntity): + def _export_record(e: AcisEntity): + if id(e) not in done: + done.add(id(e)) + record = self.get_record(e) + if not e.attributes.is_none: + record.attributes = self.get_record(e.attributes) # type: ignore + e.export(self.make_data_exporter(record)) + return True + return False + + entities = [entity] + done: set[int] = set() + while entities: + next_entity = entities.pop(0) + _export_record(next_entity) + for sub_entity in next_entity.entities(): + if _export_record(sub_entity): + entities.append(sub_entity) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/api.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/api.py new file mode 100644 index 0000000..eaeecf3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/api.py @@ -0,0 +1,31 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +# Public API module (interface) +""" +The main goals of this ACIS support library is: + + 1. load and parse simple and known ACIS data structures + 2. create and export simple and known ACIS data structures + +It is NOT a goal to edit and export arbitrary existing ACIS structures. + + Don't even try it! + +This modules do not implement an ACIS kernel!!! +So tasks beyond stitching some flat polygonal faces to a polyhedron or creating +simple curves is not possible. + +To all beginners: GO AWAY! + +""" +from .const import ( + AcisException, + ParsingError, + InvalidLinkStructure, + ExportError, +) +from .mesh import mesh_from_body, body_from_mesh, vertices_from_body +from .entities import load, export_sat, export_sab, Body +from .dbg import AcisDebugger, dump_sab_as_text +from .dxf import export_dxf, load_dxf +from .cache import AcisCache diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/cache.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/cache.py new file mode 100644 index 0000000..a833a6f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/cache.py @@ -0,0 +1,59 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Sequence +from .entities import Body, load +from .type_hints import EncodedData + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + +__all__ = ["AcisCache"] +NO_BODIES: Sequence[Body] = tuple() + + +class AcisCache: + """This cache manages ACIS bodies created from SAT or SAB data stored in DXF + entities. + + Each entry is a list of ACIS bodies and is indexed by a hash calculated from the + source content of the SAT or SAB data. + + """ + def __init__(self) -> None: + self._entries: dict[int, Sequence[Body]] = {} + self.hits: int = 0 + self.misses: int = 0 + + @staticmethod + def hash_data(data: EncodedData) -> int: + if isinstance(data, list): + return hash(tuple(data)) + elif isinstance(data, bytearray): + return hash(bytes(data)) + return hash(data) + + def __len__(self) -> int: + return len(self._entries) + + def get_bodies(self, data: EncodedData) -> Sequence[Body]: + if not data: + return NO_BODIES + + hash_value = AcisCache.hash_data(data) + bodies = self._entries.get(hash_value, NO_BODIES) + if bodies is not NO_BODIES: + self.hits += 1 + return bodies + + self.misses += 1 + bodies = tuple(load(data)) + self._entries[hash_value] = bodies + return bodies + + def from_dxf_entity(self, entity: DXFEntity) -> Sequence[Body]: + from ezdxf.entities import Body as DxfBody + + if not isinstance(entity, DxfBody): + return NO_BODIES + return self.get_bodies(entity.acis_data) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/const.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/const.py new file mode 100644 index 0000000..c3033ca --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/const.py @@ -0,0 +1,183 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +import enum +from ezdxf.version import __version__ + +# SAT Export Requirements for Autodesk Products +# --------------------------------------------- +# Script to create test files: +# examples/acistools/create_3dsolid_cube.py + +# DXF R2000, R2004, R2007, R2010: OK, tested with TrueView 2022 +# ACIS version 700 +# ACIS version string: "ACIS 32.0 NT" +# record count: 0, not required +# body count: 1, required +# ASM header: no +# end-marker: "End-of-ACIS-data" + +# DXF R2004, R2007, R2010: OK, tested with TrueView 2022 +# ACIS version 20800 +# ACIS version string: "ACIS 208.00 NT" +# record count: 0, not required +# body count: n + 1 (asm-header), required +# ASM header: "208.0.4.7009" +# end-marker: "End-of-ACIS-data" + +# SAB Export Requirements for Autodesk Products +# --------------------------------------------- +# DXF R2013, R2018: OK, tested with TrueView 2022 +# ACIS version 21800 +# ACIS version string: "ACIS 208.00 NT" +# record count: 0, not required +# body count: n + 1 (asm-header), required +# ASM header: "208.0.4.7009" +# end-marker: "End-of-ASM-data" + +ACIS_VERSION = { + 400: "ACIS 4.00 NT", # DXF R2000, no asm header - only R2000 + 700: "ACIS 32.0 NT", # DXF R2000-R2010, no asm header + 20800: "ACIS 208.00 NT", # DXF R2013 with asm-header, asm-end-marker + 21800: "ACIS 218.00 NT", # DXF R2013 with asm-header, asm-end-marker + 22300: "ACIS 223.00 NT", # DXF R2018 with asm-header, asm-end-marker +} +ASM_VERSION = { + 20800: "208.0.4.7009", # DXF R2004, R2007, R2010 + 21800: "208.0.4.7009", # DXF R2013, default version for R2013 and R2018 + 22300: "222.0.0.1700", # DXF R2018 +} +EZDXF_BUILDER_ID = f"ezdxf v{__version__} ACIS Builder" +MIN_EXPORT_VERSION = 700 + +# ACIS version 700 is the default version for DXF R2000, R2004, R2007 and R2010 (SAT) +# ACIS version 21800 is the default version for DXF R2013 and R2018 (SAB) +DEFAULT_SAT_VERSION = 700 +DEFAULT_SAB_VERSION = 21800 + +DATE_FMT = "%a %b %d %H:%M:%S %Y" +END_OF_ACIS_DATA_SAT = "End-of-ACIS-data" +END_OF_ACIS_DATA_SAB = b"\x0e\x03End\x0e\x02of\x0e\x04ACIS\x0d\x04data" +END_OF_ASM_DATA_SAT = "End-of-ASM-data" +END_OF_ASM_DATA_SAB = b"\x0e\x03End\x0e\x02of\x0e\x03ASM\x0d\x04data" +BEGIN_OF_ACIS_HISTORY_DATA = "Begin-of-ACIS-History-data" +END_OF_ACIS_HISTORY_DATA = "End-of-ACIS-History-data" +DATA_END_MARKERS = ( + END_OF_ACIS_DATA_SAT, + BEGIN_OF_ACIS_HISTORY_DATA, + END_OF_ASM_DATA_SAT, +) +NULL_PTR_NAME = "null-ptr" +NONE_ENTITY_NAME = "none-entity" +NOR_TOL = 1e-10 +RES_TOL = 9.9999999999999995e-7 + +BOOL_SPECIFIER = { + "forward": True, + "forward_v": True, + "reversed": False, + "reversed_v": False, + "single": True, + "double": False, +} + +ACIS_SIGNATURE = b"ACIS BinaryFile" # DXF R2013/R2018 +ASM_SIGNATURE = b"ASM BinaryFile4" # DXF R2018 +SIGNATURES = [ACIS_SIGNATURE, ASM_SIGNATURE] + + +def is_valid_export_version(version: int): + return version >= MIN_EXPORT_VERSION and version in ACIS_VERSION + + +class Tags(enum.IntEnum): + NO_TYPE = 0x00 + BYTE = 0x01 # not used in files! + CHAR = 0x02 # not used in files! + SHORT = 0x03 # not used in files! + INT = 0x04 # 32-bit signed integer + FLOAT = 0x05 # not used in files! + DOUBLE = 0x06 # 64-bit double precision floating point value + STR = 0x07 # count is the following 8-bit uchar + STR2 = 0x08 # not used in files! + STR3 = 0x09 # not used in files! + + # bool value for reversed, double, I - depends on context + BOOL_TRUE = 0x0A + + # bool value forward, single, forward_v - depends on context + BOOL_FALSE = 0x0B + POINTER = 0x0C + ENTITY_TYPE = 0x0D + ENTITY_TYPE_EX = 0x0E + SUBTYPE_START = 0x0F + SUBTYPE_END = 0x10 + RECORD_END = 0x11 + LITERAL_STR = 0x12 # count ia a 32-bit uint, see transform entity + LOCATION_VEC = 0x13 # vector (3 doubles) + DIRECTION_VEC = 0x14 # vector (3 doubles) + + # Enumeration are stored as strings in SAT and ints in SAB. + # It's not possible to translate SAT enums (strings) to SAB enums (int) and + # vice versa without knowing the implementation details. Each enumeration + # is specific to the class where it is used. + ENUM = 0x15 + # 0x16: ??? + UNKNOWN_0x17 = 0x17 # double + + +# entity type structure: +# 0x0D 0x04 (char count of) "body" = SAT "body" +# 0x0E 0x05 "plane" 0x0D 0x07 "surface" = SAT "plane-surface" +# 0x0E 0x06 "ref_vt" 0x0E 0x03 "eye" 0x0D 0x06 "attrib" = SAT "ref_vt-eye-attrib" + + +class Flags(enum.IntFlag): + HAS_HISTORY = 1 + + +class AcisException(Exception): + pass + + +class InvalidLinkStructure(AcisException): + pass + + +class ParsingError(AcisException): + pass + + +class ExportError(AcisException): + pass + + +class EndOfAcisData(AcisException): + pass + + +class Features: + LAW_SPL = 400 + CONE_SCALING = 400 + LOFT_LAW = 400 + REF_MIN_UV_GRID = 400 + VBLEND_AUTO = 400 + BL_ENV_SF = 400 + ELLIPSE_OFFSET = 500 + TOL_MODELING = 500 + APPROX_SUMMARY = 500 + TAPER_SCALING = 500 + LAZY_B_SPLINE = 500 + DM_MULTI_SURF = 500 + GA_COPY_ACTION = 600 + DM_MULTI_SURF_COLOR = 600 + RECAL_SKIN_ERROR = 520 + TAPER_U_RULED = 600 + DM_60 = 600 + LOFT_PCURVE = 600 + EELIST_OWNER = 600 + ANNO_HOOKED = 700 + PATTERN = 700 + ENTITY_TAGS = 700 + AT = 700 + NET_LAW = 700 + STRINGLESS_HISTORY = 700 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/dbg.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/dbg.py new file mode 100644 index 0000000..753b95d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/dbg.py @@ -0,0 +1,193 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Callable, Any +from .entities import ( + AcisEntity, + NONE_REF, + Face, + Coedge, + Loop, + Vertex, +) +from . import sab + + +class AcisDebugger: + def __init__(self, root: AcisEntity = NONE_REF, start_id: int = 1): + self._next_id = start_id - 1 + self._root: AcisEntity = root + self.entities: dict[int, AcisEntity] = dict() + if not root.is_none: + self._store_entities(root) + + @property + def root(self) -> AcisEntity: + return self._root + + def _get_id(self) -> int: + self._next_id += 1 + return self._next_id + + def _store_entities(self, entity: AcisEntity) -> None: + if not entity.is_none and entity.id == -1: + entity.id = self._get_id() + self.entities[entity.id] = entity + for e in vars(entity).values(): + if isinstance(e, AcisEntity) and e.id == -1: + self._store_entities(e) + + def set_entities(self, entity: AcisEntity) -> None: + self.entities.clear() + self._root = entity + self._store_entities(entity) + + def walk(self, root: AcisEntity = NONE_REF) -> Iterator[AcisEntity]: + def _walk(entity: AcisEntity): + if entity.is_none: + return + yield entity + done.add(entity.id) + for e in vars(entity).values(): + if isinstance(e, AcisEntity) and e.id not in done: + yield from _walk(e) + + if root.is_none: + root = self._root + done: set[int] = set() + yield from _walk(root) + + def filter( + self, func: Callable[[AcisEntity], bool], entity: AcisEntity = NONE_REF + ) -> Iterator[Any]: + if entity.is_none: + entity = self._root + yield from filter(func, self.walk(entity)) + + def filter_type( + self, name: str, entity: AcisEntity = NONE_REF + ) -> Iterator[Any]: + if entity.is_none: + entity = self._root + yield from filter(lambda x: x.type == name, self.walk(entity)) + + @staticmethod + def entity_attributes(entity: AcisEntity, indent: int = 0) -> Iterator[str]: + indent_str = " " * indent + for name, data in vars(entity).items(): + if name == "id": + continue + yield f"{indent_str}{name}: {data}" + + def face_link_structure(self, face: Face, indent: int = 0) -> Iterator[str]: + indent_str = " " * indent + + while not face.is_none: + partner_faces = list(self.partner_faces(face)) + error = "" + linked_partner_faces = [] + unlinked_partner_faces = [] + for pface_id in partner_faces: + pface = self.entities.get(pface_id) + if pface is None: + error += f" face {pface_id} does not exist;" + if isinstance(pface, Face): + reverse_faces = self.partner_faces(pface) + if face.id in reverse_faces: + linked_partner_faces.append(pface_id) + else: + unlinked_partner_faces.append(pface_id) + else: + error += f" entity {pface_id} is not a face;" + if unlinked_partner_faces: + error = f"unlinked partner faces: {unlinked_partner_faces} {error}" + yield f"{indent_str}{str(face)} >> {partner_faces} {error}" + face = face.next_face + + @staticmethod + def partner_faces(face: Face) -> Iterator[int]: + coedges: list[Coedge] = [] + loop = face.loop + while not loop.is_none: + coedges.extend(co for co in loop.coedges()) + loop = loop.next_loop + for coedge in coedges: + for partner_coedge in coedge.partner_coedges(): + yield partner_coedge.loop.face.id + + @staticmethod + def coedge_structure(face: Face, ident: int = 4) -> list[str]: + lines: list[str] = [] + coedges: list[Coedge] = [] + loop = face.loop + + while not loop.is_none: + coedges.extend(co for co in loop.coedges()) + loop = loop.next_loop + for coedge in coedges: + edge1 = coedge.edge + sense1 = coedge.sense + lines.append(f"Coedge={coedge.id} edge={edge1.id} sense={sense1}") + for partner_coedge in coedge.partner_coedges(): + edge2 = partner_coedge.edge + sense2 = partner_coedge.sense + lines.append( + f" Partner Coedge={partner_coedge.id} edge={edge2.id} sense={sense2}" + ) + ident_str = " " * ident + return [ident_str + line for line in lines] + + @staticmethod + def loop_vertices(loop: Loop, indent: int = 0) -> str: + indent_str = " " * indent + return f"{indent_str}{loop} >> {list(AcisDebugger.loop_edges(loop))}" + + @staticmethod + def loop_edges(loop: Loop) -> Iterator[list[int]]: + coedge = loop.coedge + first = coedge + while not coedge.is_none: + edge = coedge.edge + sv = edge.start_vertex + ev = edge.end_vertex + if coedge.sense: + yield [ev.id, sv.id] + else: + yield [sv.id, ev.id] + coedge = coedge.next_coedge + if coedge is first: + break + + def vertex_to_edge_relation(self) -> Iterator[str]: + for vertex in ( + e for e in self.entities.values() if isinstance(e, Vertex) + ): + edge = vertex.edge + sv = edge.start_vertex + ev = edge.end_vertex + yield f"{vertex}: parent edge is {edge.id}; {sv.id} => {ev.id}; {edge.curve}" + + def is_manifold(self) -> bool: + for coedge in self.filter_type("coedge"): + if len(coedge.partner_coedges()) > 1: + return False + return True + + +def dump_sab_as_text(data: bytes) -> Iterator[str]: + def entity_data(e): + for tag, value in e: + name = sab.Tags(tag).name + yield f"{name} = {value}" + + decoder = sab.Decoder(data) + header = decoder.read_header() + yield from header.dumps() + index = 0 + try: + for record in decoder.read_records(): + yield f"--------------------- record: {index}" + yield from entity_data(record) + index += 1 + except sab.ParsingError as e: + yield str(e) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/dxf.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/dxf.py new file mode 100644 index 0000000..ab66960 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/dxf.py @@ -0,0 +1,82 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import cast, Sequence +from ezdxf.entities import DXFEntity, Body as DXFBody +from ezdxf.lldxf import const +from .entities import Body, export_sat, export_sab, load + + +def export_dxf(entity: DXFEntity, bodies: Sequence[Body]): + """Store the :term:`ACIS` bodies in the given DXF entity. This is the + recommended way to set ACIS data of DXF entities. + + The DXF entity has to be an ACIS based entity and inherit from + :class:`ezdxf.entities.Body`. The entity has to be bound to a valid DXF + document and the DXF version of the document has to be DXF R2000 or newer. + + Raises: + DXFTypeError: invalid DXF entity type + DXFValueError: invalid DXF document + DXFVersionError: invalid DXF version + + """ + if not isinstance(entity, DXFBody): + raise const.DXFTypeError(f"invalid DXF entity {entity.dxftype()}") + body = cast(DXFBody, entity) + doc = entity.doc + if doc is None: + raise const.DXFValueError("a valid DXF document is required") + dxfversion = doc.dxfversion + if dxfversion < const.DXF2000: + raise const.DXFVersionError(f"invalid DXF version {dxfversion}") + + if dxfversion < const.DXF2013: + body.sat = export_sat(bodies) + else: + body.sab = export_sab(bodies) + + +def load_dxf(entity: DXFEntity) -> list[Body]: + """Load the :term:`ACIS` bodies from the given DXF entity. This is the + recommended way to load ACIS data. + + The DXF entity has to be an ACIS based entity and inherit from + :class:`ezdxf.entities.Body`. The entity has to be bound to a valid DXF + document and the DXF version of the document has to be DXF R2000 or newer. + + Raises: + DXFTypeError: invalid DXF entity type + DXFValueError: invalid DXF document + DXFVersionError: invalid DXF version + + .. warning:: + + Only a limited count of :term:`ACIS` entities is supported, all + unsupported entities are loaded as ``NONE_ENTITY`` and their data is + lost. Exporting such ``NONE_ENTITIES`` will raise an :class:`ExportError` + exception. + + To emphasize that again: **It is not possible to load and re-export + arbitrary ACIS data!** + + """ + + if not isinstance(entity, DXFBody): + raise const.DXFTypeError(f"invalid DXF entity {entity.dxftype()}") + body = cast(DXFBody, entity) + doc = entity.doc + if doc is None: + raise const.DXFValueError("a valid DXF document is required") + dxfversion = doc.dxfversion + if dxfversion < const.DXF2000: + raise const.DXFVersionError(f"invalid DXF version {dxfversion}") + if body.has_binary_data: + binary_data = body.sab + if binary_data: + return load(binary_data) + else: + text = body.sat + if text: + return load(text) + return [] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/entities.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/entities.py new file mode 100644 index 0000000..aebdfe1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/entities.py @@ -0,0 +1,802 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Callable, Type, Any, Sequence, Iterator +import abc + +from . import sab, sat, const, hdr +from .const import Features +from .abstract import DataLoader, AbstractEntity, DataExporter +from .type_hints import EncodedData +from ezdxf.math import Matrix44, Vec3, NULLVEC + +Factory = Callable[[AbstractEntity], "AcisEntity"] + +ENTITY_TYPES: dict[str, Type[AcisEntity]] = {} +INF = float("inf") + + +def load(data: EncodedData) -> list[Body]: + """Returns a list of :class:`Body` entities from :term:`SAT` or :term:`SAB` + data. Accepts :term:`SAT` data as a single string or a sequence of strings + and :term:`SAB` data as bytes or bytearray. + + """ + if isinstance(data, (bytes, bytearray)): + return SabLoader.load(data) + return SatLoader.load(data) + + +def export_sat( + bodies: Sequence[Body], version: int = const.DEFAULT_SAT_VERSION +) -> list[str]: + """Export one or more :class:`Body` entities as text based :term:`SAT` data. + + ACIS version 700 is sufficient for DXF versions R2000, R2004, R2007 and + R2010, later DXF versions require :term:`SAB` data. + + Raises: + ExportError: ACIS structures contain unsupported entities + InvalidLinkStructure: corrupt link structure + + """ + if version < const.MIN_EXPORT_VERSION: + raise const.ExportError(f"invalid ACIS version: {version}") + exporter = sat.SatExporter(_setup_export_header(version)) + exporter.header.asm_end_marker = False + for body in bodies: + exporter.export(body) + return exporter.dump_sat() + + +def export_sab( + bodies: Sequence[Body], version: int = const.DEFAULT_SAB_VERSION +) -> bytes: + """Export one or more :class:`Body` entities as binary encoded :term:`SAB` + data. + + ACIS version 21800 is sufficient for DXF versions R2013 and R2018, earlier + DXF versions require :term:`SAT` data. + + Raises: + ExportError: ACIS structures contain unsupported entities + InvalidLinkStructure: corrupt link structure + + """ + if version < const.MIN_EXPORT_VERSION: + raise const.ExportError(f"invalid ACIS version: {version}") + exporter = sab.SabExporter(_setup_export_header(version)) + exporter.header.asm_end_marker = True + for body in bodies: + exporter.export(body) + return exporter.dump_sab() + + +def _setup_export_header(version) -> hdr.AcisHeader: + if not const.is_valid_export_version(version): + raise const.ExportError(f"invalid export version: {version}") + header = hdr.AcisHeader() + header.set_version(version) + return header + + +def register(cls): + ENTITY_TYPES[cls.type] = cls + return cls + + +class NoneEntity: + type: str = const.NONE_ENTITY_NAME + + @property + def is_none(self) -> bool: + return self.type == const.NONE_ENTITY_NAME + + +NONE_REF: Any = NoneEntity() + + +class AcisEntity(NoneEntity): + """Base ACIS entity which also represents unsupported entities. + + Unsupported entities are entities whose internal structure are not fully + known or user defined entity types. + + The content of these unsupported entities is not loaded and lost by + exporting such entities, therefore exporting unsupported entities raises + an :class:`ExportError` exception. + + """ + + type: str = "unsupported-entity" + id: int = -1 + attributes: AcisEntity = NONE_REF + + def __str__(self) -> str: + return f"{self.type}({self.id})" + + def load(self, loader: DataLoader, entity_factory: Factory) -> None: + """Load the ACIS entity content from `loader`.""" + self.restore_common(loader, entity_factory) + self.restore_data(loader) + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + """Load the common part of an ACIS entity.""" + pass + + def restore_data(self, loader: DataLoader) -> None: + """Load the data part of an ACIS entity.""" + pass + + def export(self, exporter: DataExporter) -> None: + """Write the ACIS entity content to `exporter`.""" + self.write_common(exporter) + self.write_data(exporter) + + def write_common(self, exporter: DataExporter) -> None: + """Write the common part of the ACIS entity. + + It is not possible to export :class:`Body` entities including + unsupported entities, doing so would cause data loss or worse data + corruption! + + """ + raise const.ExportError(f"unsupported entity type: {self.type}") + + def write_data(self, exporter: DataExporter) -> None: + """Write the data part of the ACIS entity.""" + pass + + def entities(self) -> Iterator[AcisEntity]: + """Yield all attributes of this entity of type AcisEntity.""" + for e in vars(self).values(): + if isinstance(e, AcisEntity): + yield e + + +def restore_entity( + expected_type: str, loader: DataLoader, entity_factory: Factory +) -> Any: + raw_entity = loader.read_ptr() + if raw_entity.is_null_ptr: + return NONE_REF + if raw_entity.name.endswith(expected_type): + return entity_factory(raw_entity) + else: + raise const.ParsingError( + f"expected entity type '{expected_type}', got '{raw_entity.name}'" + ) + + +@register +class Transform(AcisEntity): + type: str = "transform" + matrix = Matrix44() + + def restore_data(self, loader: DataLoader) -> None: + data = loader.read_transform() + # insert values of the 4th matrix column (0, 0, 0, 1) + data.insert(3, 0.0) + data.insert(7, 0.0) + data.insert(11, 0.0) + data.append(1.0) + self.matrix = Matrix44(data) + + def write_common(self, exporter: DataExporter) -> None: + def write_double(value: float): + data.append(f"{value:g}") + + data: list[str] = [] + for row in self.matrix.rows(): + write_double(row[0]) + write_double(row[1]) + write_double(row[2]) + test_vector = Vec3(1, 0, 0) + result = self.matrix.transform_direction(test_vector) + # A uniform scaling in x- y- and z-axis is assumed: + write_double(round(result.magnitude, 6)) # scale factor + is_rotated = not result.normalize().isclose(test_vector) + data.append("rotate" if is_rotated else "no_rotate") + data.append("no_reflect") + data.append("no_shear") + exporter.write_transform(data) + + +@register +class AsmHeader(AcisEntity): + type: str = "asmheader" + + def __init__(self, version: str = ""): + self.version = version + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + self.version = loader.read_str() + + def write_common(self, exporter: DataExporter) -> None: + exporter.write_str(self.version) + + +class SupportsPattern(AcisEntity): + pattern: Pattern = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + if loader.version >= Features.PATTERN: + self.pattern = restore_entity("pattern", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + exporter.write_ptr(self.pattern) + + +@register +class Body(SupportsPattern): + type: str = "body" + pattern: Pattern = NONE_REF + lump: Lump = NONE_REF + wire: Wire = NONE_REF + transform: Transform = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.lump = restore_entity("lump", loader, entity_factory) + self.wire = restore_entity("wire", loader, entity_factory) + self.transform = restore_entity("transform", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.lump) + exporter.write_ptr(self.wire) + exporter.write_ptr(self.transform) + + def append_lump(self, lump: Lump) -> None: + """Append a :class:`Lump` entity as last lump.""" + lump.body = self + if self.lump.is_none: + self.lump = lump + else: + current_lump = self.lump + while not current_lump.next_lump.is_none: + current_lump = current_lump.next_lump + current_lump.next_lump = lump + + def lumps(self) -> list[Lump]: + """Returns all linked :class:`Lump` entities as a list.""" + lumps = [] + current_lump = self.lump + while not current_lump.is_none: + lumps.append(current_lump) + current_lump = current_lump.next_lump + return lumps + + +@register +class Wire(SupportsPattern): # not implemented + type: str = "wire" + + +@register +class Pattern(AcisEntity): # not implemented + type: str = "pattern" + + +@register +class Lump(SupportsPattern): + type: str = "lump" + next_lump: Lump = NONE_REF + shell: Shell = NONE_REF + body: Body = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.next_lump = restore_entity("lump", loader, entity_factory) + self.shell = restore_entity("shell", loader, entity_factory) + self.body = restore_entity("body", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.next_lump) + exporter.write_ptr(self.shell) + exporter.write_ptr(self.body) + + def append_shell(self, shell: Shell) -> None: + """Append a :class:`Shell` entity as last shell.""" + shell.lump = self + if self.shell.is_none: + self.shell = shell + else: + current_shell = self.shell + while not current_shell.next_shell.is_none: + current_shell = current_shell.next_shell + current_shell.next_shell = shell + + def shells(self) -> list[Shell]: + """Returns all linked :class:`Shell` entities as a list.""" + shells = [] + current_shell = self.shell + while not current_shell.is_none: + shells.append(current_shell) + current_shell = current_shell.next_shell + return shells + + +@register +class Shell(SupportsPattern): + type: str = "shell" + next_shell: Shell = NONE_REF + subshell: Subshell = NONE_REF + face: Face = NONE_REF + wire: Wire = NONE_REF + lump: Lump = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.next_shell = restore_entity("next_shell", loader, entity_factory) + self.subshell = restore_entity("subshell", loader, entity_factory) + self.face = restore_entity("face", loader, entity_factory) + self.wire = restore_entity("wire", loader, entity_factory) + self.lump = restore_entity("lump", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.next_shell) + exporter.write_ptr(self.subshell) + exporter.write_ptr(self.face) + exporter.write_ptr(self.wire) + exporter.write_ptr(self.lump) + + def append_face(self, face: Face) -> None: + """Append a :class:`Face` entity as last face.""" + face.shell = self + if self.face.is_none: + self.face = face + else: + current_face = self.face + while not current_face.next_face.is_none: + current_face = current_face.next_face + current_face.next_face = face + + def faces(self) -> list[Face]: + """Returns all linked :class:`Face` entities as a list.""" + faces = [] + current_face = self.face + while not current_face.is_none: + faces.append(current_face) + current_face = current_face.next_face + return faces + + +@register +class Subshell(SupportsPattern): # not implemented + type: str = "subshell" + + +@register +class Face(SupportsPattern): + type: str = "face" + next_face: "Face" = NONE_REF + loop: Loop = NONE_REF + shell: Shell = NONE_REF + subshell: Subshell = NONE_REF + surface: Surface = NONE_REF + # sense: face normal with respect to the surface + sense = False # True = reversed; False = forward + double_sided = False # True = double (hollow body); False = single (solid body) + containment = False # if double_sided: True = in, False = out + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.next_face = restore_entity("face", loader, entity_factory) + self.loop = restore_entity("loop", loader, entity_factory) + self.shell = restore_entity("shell", loader, entity_factory) + self.subshell = restore_entity("subshell", loader, entity_factory) + self.surface = restore_entity("surface", loader, entity_factory) + self.sense = loader.read_bool("reversed", "forward") + self.double_sided = loader.read_bool("double", "single") + if self.double_sided: + self.containment = loader.read_bool("in", "out") + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.next_face) + exporter.write_ptr(self.loop) + exporter.write_ptr(self.shell) + exporter.write_ptr(self.subshell) + exporter.write_ptr(self.surface) + exporter.write_bool(self.sense, "reversed", "forward") + exporter.write_bool(self.double_sided, "double", "single") + if self.double_sided: + exporter.write_bool(self.containment, "in", "out") + + def append_loop(self, loop: Loop) -> None: + """Append a :class:`Loop` entity as last loop.""" + loop.face = self + if self.loop.is_none: + self.loop = loop + else: # order of coedges is important! (right-hand rule) + current_loop = self.loop + while not current_loop.next_loop.is_none: + current_loop = current_loop.next_loop + current_loop.next_loop = loop + + def loops(self) -> list[Loop]: + """Returns all linked :class:`Loop` entities as a list.""" + loops = [] + current_loop = self.loop + while not current_loop.is_none: + loops.append(current_loop) + current_loop = current_loop.next_loop + return loops + + +@register +class Surface(SupportsPattern): + type: str = "surface" + u_bounds = INF, INF + v_bounds = INF, INF + + def restore_data(self, loader: DataLoader) -> None: + self.u_bounds = loader.read_interval(), loader.read_interval() + self.v_bounds = loader.read_interval(), loader.read_interval() + + def write_data(self, exporter: DataExporter): + exporter.write_interval(self.u_bounds[0]) + exporter.write_interval(self.u_bounds[1]) + exporter.write_interval(self.v_bounds[0]) + exporter.write_interval(self.v_bounds[1]) + + @abc.abstractmethod + def evaluate(self, u: float, v: float) -> Vec3: + """Returns the spatial location at the parametric surface for the given + parameters `u` and `v`. + + """ + pass + + +@register +class Plane(Surface): + type: str = "plane-surface" + origin = Vec3(0, 0, 0) + normal = Vec3(0, 0, 1) # pointing outside + u_dir = Vec3(1, 0, 0) # unit vector! + v_dir = Vec3(0, 1, 0) # unit vector! + # reverse_v: + # True: "reverse_v" - the normal vector does not follow the right-hand rule + # False: "forward_v" - the normal vector follows right-hand rule + reverse_v = False + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.origin = Vec3(loader.read_vec3()) + self.normal = Vec3(loader.read_vec3()) + self.u_dir = Vec3(loader.read_vec3()) + self.reverse_v = loader.read_bool("reverse_v", "forward_v") + self.update_v_dir() + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_loc_vec3(self.origin) + exporter.write_dir_vec3(self.normal) + exporter.write_dir_vec3(self.u_dir) + exporter.write_bool(self.reverse_v, "reverse_v", "forward_v") + # v_dir is not exported + + def update_v_dir(self): + v_dir = self.normal.cross(self.u_dir) + if self.reverse_v: + v_dir = -v_dir + self.v_dir = v_dir + + def evaluate(self, u: float, v: float) -> Vec3: + return self.origin + (self.u_dir * u) + (self.v_dir * v) + + +@register +class Loop(SupportsPattern): + type: str = "loop" + next_loop: Loop = NONE_REF + coedge: Coedge = NONE_REF + face: Face = NONE_REF # parent/owner + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.next_loop = restore_entity("loop", loader, entity_factory) + self.coedge = restore_entity("coedge", loader, entity_factory) + self.face = restore_entity("face", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.next_loop) + exporter.write_ptr(self.coedge) + exporter.write_ptr(self.face) + + def set_coedges(self, coedges: list[Coedge], close=True) -> None: + """Set all coedges of a loop at once.""" + assert len(coedges) > 0 + self.coedge = coedges[0] + next_coedges = coedges[1:] + prev_coedges = coedges[:-1] + if close: + next_coedges.append(coedges[0]) + prev_coedges.insert(0, coedges[-1]) + else: + next_coedges.append(NONE_REF) + prev_coedges.insert(0, NONE_REF) + + for coedge, next, prev in zip(coedges, next_coedges, prev_coedges): + coedge.loop = self + coedge.prev_coedge = prev + coedge.next_coedge = next + + def coedges(self) -> list[Coedge]: + """Returns all linked :class:`Coedge` entities as a list.""" + coedges = [] + + current_coedge = self.coedge + while not current_coedge.is_none: # open loop if none + coedges.append(current_coedge) + current_coedge = current_coedge.next_coedge + if current_coedge is self.coedge: # circular linked list! + break # closed loop + return coedges + + +@register +class Coedge(SupportsPattern): + type: str = "coedge" + next_coedge: Coedge = NONE_REF + prev_coedge: Coedge = NONE_REF + # The partner_coedge points to the coedge of an adjacent face, in a + # manifold body each coedge has zero (open) or one (closed) partner edge. + # ACIS supports also non-manifold bodies, so there can be more than one + # partner coedges which are organized in a circular linked list. + partner_coedge: Coedge = NONE_REF + edge: Edge = NONE_REF + # sense: True = reversed; False = forward; + # coedge has the same direction as the underlying edge + sense: bool = True + loop: Loop = NONE_REF # parent/owner + unknown: int = 0 # only in SAB file!? + pcurve: PCurve = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.next_coedge = restore_entity("coedge", loader, entity_factory) + self.prev_coedge = restore_entity("coedge", loader, entity_factory) + self.partner_coedge = restore_entity("coedge", loader, entity_factory) + self.edge = restore_entity("edge", loader, entity_factory) + self.sense = loader.read_bool("reversed", "forward") + self.loop = restore_entity("loop", loader, entity_factory) + self.unknown = loader.read_int(skip_sat=0) + self.pcurve = restore_entity("pcurve", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.next_coedge) + exporter.write_ptr(self.prev_coedge) + exporter.write_ptr(self.partner_coedge) + exporter.write_ptr(self.edge) + exporter.write_bool(self.sense, "reversed", "forward") + exporter.write_ptr(self.loop) + # TODO: write_int() ? + exporter.write_int(0, skip_sat=True) + exporter.write_ptr(self.pcurve) + + def add_partner_coedge(self, coedge: Coedge) -> None: + assert coedge.partner_coedge.is_none + partner_coedge = self.partner_coedge + if partner_coedge.is_none: + partner_coedge = self + # insert new coedge as first partner coedge: + self.partner_coedge = coedge + coedge.partner_coedge = partner_coedge + self.order_partner_coedges() + + def order_partner_coedges(self) -> None: + # todo: the referenced faces of non-manifold coedges have to be ordered + # by the right-hand rule around this edge. + pass + + def partner_coedges(self) -> list[Coedge]: + """Returns all partner coedges of this coedge without `self`.""" + coedges: list[Coedge] = [] + partner_coedge = self.partner_coedge + if partner_coedge.is_none: + return coedges + while True: + coedges.append(partner_coedge) + partner_coedge = partner_coedge.partner_coedge + if partner_coedge.is_none or partner_coedge is self: + break + return coedges + + +@register +class Edge(SupportsPattern): + type: str = "edge" + + # The parent edge of the start_vertex doesn't have to be this edge! + start_vertex: Vertex = NONE_REF + start_param: float = 0.0 + + # The parent edge of the end_vertex doesn't have to be this edge! + end_vertex: Vertex = NONE_REF + end_param: float = 0.0 + coedge: Coedge = NONE_REF + curve: Curve = NONE_REF + # sense: True = reversed; False = forward; + # forward: edge has the same direction as the underlying curve + sense: bool = False + convexity: str = "unknown" + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.start_vertex = restore_entity("vertex", loader, entity_factory) + if loader.version >= Features.TOL_MODELING: + self.start_param = loader.read_double() + self.end_vertex = restore_entity("vertex", loader, entity_factory) + if loader.version >= Features.TOL_MODELING: + self.end_param = loader.read_double() + self.coedge = restore_entity("coedge", loader, entity_factory) + self.curve = restore_entity("curve", loader, entity_factory) + self.sense = loader.read_bool("reversed", "forward") + if loader.version >= Features.TOL_MODELING: + self.convexity = loader.read_str() + + def write_common(self, exporter: DataExporter) -> None: + # write support >= version 700 only + super().write_common(exporter) + exporter.write_ptr(self.start_vertex) + exporter.write_double(self.start_param) + exporter.write_ptr(self.end_vertex) + exporter.write_double(self.end_param) + exporter.write_ptr(self.coedge) + exporter.write_ptr(self.curve) + exporter.write_bool(self.sense, "reversed", "forward") + exporter.write_str(self.convexity) + + +@register +class PCurve(SupportsPattern): # not implemented + type: str = "pcurve" + + +@register +class Vertex(SupportsPattern): + type: str = "vertex" + edge: Edge = NONE_REF + ref_count: int = 0 # only in SAB files + point: Point = NONE_REF + + def restore_common(self, loader: DataLoader, entity_factory: Factory) -> None: + super().restore_common(loader, entity_factory) + self.edge = restore_entity("edge", loader, entity_factory) + self.ref_count = loader.read_int(skip_sat=0) + self.point = restore_entity("point", loader, entity_factory) + + def write_common(self, exporter: DataExporter) -> None: + super().write_common(exporter) + exporter.write_ptr(self.edge) + exporter.write_int(self.ref_count, skip_sat=True) + exporter.write_ptr(self.point) + + +@register +class Curve(SupportsPattern): + type: str = "curve" + bounds = INF, INF + + def restore_data(self, loader: DataLoader) -> None: + self.bounds = loader.read_interval(), loader.read_interval() + + def write_data(self, exporter: DataExporter) -> None: + exporter.write_interval(self.bounds[0]) + exporter.write_interval(self.bounds[1]) + + @abc.abstractmethod + def evaluate(self, param: float) -> Vec3: + """Returns the spatial location at the parametric curve for the given + parameter. + + """ + pass + + +@register +class StraightCurve(Curve): + type: str = "straight-curve" + origin = Vec3(0, 0, 0) + direction = Vec3(1, 0, 0) + + def restore_data(self, loader: DataLoader) -> None: + self.origin = Vec3(loader.read_vec3()) + self.direction = Vec3(loader.read_vec3()) + super().restore_data(loader) + + def write_data(self, exporter: DataExporter) -> None: + exporter.write_loc_vec3(self.origin) + exporter.write_dir_vec3(self.direction) + super().write_data(exporter) + + def evaluate(self, param: float) -> Vec3: + return self.origin + (self.direction * param) + + +@register +class Point(SupportsPattern): + type: str = "point" + location: Vec3 = NULLVEC + + def restore_data(self, loader: DataLoader) -> None: + self.location = Vec3(loader.read_vec3()) + + def write_data(self, exporter: DataExporter) -> None: + exporter.write_loc_vec3(self.location) + + +class FileLoader(abc.ABC): + records: Sequence[sat.SatEntity | sab.SabEntity] + + def __init__(self, version: int): + self.entities: dict[int, AcisEntity] = {} + self.version: int = version + + def entity_factory(self, raw_entity: AbstractEntity) -> AcisEntity: + uid = id(raw_entity) + try: + return self.entities[uid] + except KeyError: # create a new entity + entity = ENTITY_TYPES.get(raw_entity.name, AcisEntity)() + self.entities[uid] = entity + return entity + + def bodies(self) -> list[Body]: + # noinspection PyTypeChecker + return [e for e in self.entities.values() if isinstance(e, Body)] + + def load_entities(self): + entity_factory = self.entity_factory + + for raw_entity in self.records: + entity = entity_factory(raw_entity) + entity.id = raw_entity.id + attributes = raw_entity.attributes + if not attributes.is_null_ptr: + entity.attributes = entity_factory(attributes) + data_loader = self.make_data_loader(raw_entity.data) + entity.load(data_loader, entity_factory) + + @abc.abstractmethod + def make_data_loader(self, data: list[Any]) -> DataLoader: + pass + + +class SabLoader(FileLoader): + def __init__(self, data: bytes | bytearray): + builder = sab.parse_sab(data) + super().__init__(builder.header.version) + self.records = builder.entities + + def make_data_loader(self, data: list[Any]) -> DataLoader: + return sab.SabDataLoader(data, self.version) + + @classmethod + def load(cls, data: bytes | bytearray) -> list[Body]: + loader = cls(data) + loader.load_entities() + return loader.bodies() + + +class SatLoader(FileLoader): + def __init__(self, data: str | Sequence[str]): + builder = sat.parse_sat(data) + super().__init__(builder.header.version) + self.records = builder.entities + + def make_data_loader(self, data: list[Any]) -> DataLoader: + return sat.SatDataLoader(data, self.version) + + @classmethod + def load(cls, data: str | Sequence[str]) -> list[Body]: + loader = cls(data) + loader.load_entities() + return loader.bodies() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/hdr.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/hdr.py new file mode 100644 index 0000000..47528ca --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/hdr.py @@ -0,0 +1,110 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from dataclasses import dataclass, field +from datetime import datetime +import struct +from . import const + +# ACIS versions exported by BricsCAD: +# R2000/AC1015: 400, "ACIS 4.00 NT", text length has no prefix "@" +# R2004/AC1018: 20800 @ "ACIS 208.00 NT", text length has "@" prefix ??? weird +# R2007/AC1021: 700 @ "ACIS 32.0 NT", text length has "@" prefix +# R2010/AC1024: 700 @ "ACIS 32.0 NT", text length has "@" prefix + +# A test showed that R2000 files that contains ACIS v700/32.0 or v20800/208.0 +# data can be opened by Autodesk TrueView, BricsCAD and Allplan, so exporting +# only v700/32.0 for all DXF versions should be OK! +# test script: exploration/acis/transplant_acis_data.py + + +def encode_str(s: str) -> bytes: + b = s.encode("utf8", errors="ignore") + return struct.pack(" bytes: + return struct.pack(" bool: + return self.asm_version != "" + + def dumps(self) -> list[str]: + """Returns the SAT file header as list of strings.""" + return [ + f"{self.version} {self.n_records} {self.n_entities} {self.flags} ", + self._header_str(), + f"{self.units_in_mm:g} 9.9999999999999995e-007 1e-010 ", + ] + + def dumpb(self) -> bytes: + """Returns the SAB file header as bytes.""" + buffer: list[bytes] = [] + if self.version > 21800: + buffer.append(const.ASM_SIGNATURE) + else: + buffer.append(const.ACIS_SIGNATURE) + data = struct.pack( + " str: + p_len = len(self.product_id) + a_len = len(self.acis_version) + date = self.creation_date.ctime() + if self.version > 400: + return f"@{p_len} {self.product_id} @{a_len} {self.acis_version} @{len(date)} {date} " + else: + return f"{p_len} {self.product_id} {a_len} {self.acis_version} {len(date)} {date} " + + def set_version(self, version: int) -> None: + """Sets the ACIS version as an integer value and updates the version + string accordingly. + """ + try: + self.acis_version = const.ACIS_VERSION[version] + self.version = version + except KeyError: + raise ValueError(f"invalid ACIS version number {version}") + self.asm_version = const.ASM_VERSION.get(version, "") + + def asm_header(self): + from .entities import AsmHeader + return AsmHeader(self.asm_version) + + def sat_end_marker(self) -> str: + if self.asm_end_marker: + return const.END_OF_ASM_DATA_SAT + " " + else: + return const.END_OF_ACIS_DATA_SAT + " " + + def sab_end_marker(self) -> bytes: + if self.asm_end_marker: + return const.END_OF_ASM_DATA_SAB + else: + return const.END_OF_ACIS_DATA_SAB diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/mesh.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/mesh.py new file mode 100644 index 0000000..077eecf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/mesh.py @@ -0,0 +1,415 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Sequence, Optional, Iterable +from ezdxf.render import MeshVertexMerger, MeshTransformer, MeshBuilder +from ezdxf.math import Matrix44, Vec3, NULLVEC, BoundingBox +from . import entities +from .entities import Body, Lump, NONE_REF, Face, Shell + + +def mesh_from_body(body: Body, merge_lumps=True) -> list[MeshTransformer]: + """Returns a list of :class:`~ezdxf.render.MeshTransformer` instances from + the given ACIS :class:`Body` entity. + The list contains multiple meshes if `merge_lumps` is ``False`` or just a + single mesh if `merge_lumps` is ``True``. + + The ACIS format stores the faces in counter-clockwise orientation where the + face-normal points outwards (away) from the solid body (material). + + .. note:: + + This function returns meshes build up only from flat polygonal + :class:`Face` entities, for a tessellation of more complex ACIS + entities (spline surfaces, tori, cones, ...) is an ACIS kernel + required which `ezdxf` does not provide. + + Args: + body: ACIS entity of type :class:`Body` + merge_lumps: returns all :class:`Lump` entities + from a body as a single mesh if ``True`` otherwise each :class:`Lump` + entity is a separated mesh + + Raises: + TypeError: given `body` entity has invalid type + + """ + if not isinstance(body, Body): + raise TypeError(f"expected a body entity, got: {type(body)}") + + meshes: list[MeshTransformer] = [] + builder = MeshVertexMerger() + for faces in flat_polygon_faces_from_body(body): + for face in faces: + builder.add_face(face) + if not merge_lumps: + meshes.append(MeshTransformer.from_builder(builder)) + builder = MeshVertexMerger() + if merge_lumps: + meshes.append(MeshTransformer.from_builder(builder)) + return meshes + + +def flat_polygon_faces_from_body( + body: Body, +) -> Iterator[list[Sequence[Vec3]]]: + """Yields all flat polygon faces from all lumps in the given + :class:`Body` entity. + Yields a separated list of faces for each linked :class:`Lump` entity. + + Args: + body: ACIS entity of type :class:`Body` + + Raises: + TypeError: given `body` entity has invalid type + + """ + + if not isinstance(body, Body): + raise TypeError(f"expected a body entity, got: {type(body)}") + lump = body.lump + transform = body.transform + + m: Optional[Matrix44] = None + if not transform.is_none: + m = transform.matrix + while not lump.is_none: + yield list(flat_polygon_faces_from_lump(lump, m)) + lump = lump.next_lump + + +def flat_polygon_faces_from_lump( + lump: Lump, m: Matrix44 | None = None +) -> Iterator[Sequence[Vec3]]: + """Yields all flat polygon faces from the given :class:`Lump` entity as + sequence of :class:`~ezdxf.math.Vec3` instances. Applies the transformation + :class:`~ezdxf.math.Matrix44` `m` to all vertices if not ``None``. + + Args: + lump: :class:`Lump` entity + m: optional transformation matrix + + Raises: + TypeError: `lump` has invalid ACIS type + + """ + if not isinstance(lump, Lump): + raise TypeError(f"expected a lump entity, got: {type(lump)}") + + shell = lump.shell + if shell.is_none: + return # not a shell + vertices: list[Vec3] = [] + face = shell.face + while not face.is_none: + first_coedge = NONE_REF + vertices.clear() + if face.surface.type == "plane-surface": + try: + first_coedge = face.loop.coedge + except AttributeError: # loop is a none-entity + pass + coedge = first_coedge + while not coedge.is_none: # invalid coedge or face is not closed + # the edge entity contains the vertices and the curve type + edge = coedge.edge + try: + # only straight lines as face edges supported: + if edge.curve.type != "straight-curve": + break + # add the first edge vertex to the face vertices + if coedge.sense: # reversed sense of the underlying edge + vertices.append(edge.end_vertex.point.location) + else: # same sense as the underlying edge + vertices.append(edge.start_vertex.point.location) + except AttributeError: + # one of the involved entities is a none-entity or an + # incompatible entity type -> ignore this face! + break + coedge = coedge.next_coedge + if coedge is first_coedge: # a valid closed face + if m is not None: + yield tuple(m.transform_vertices(vertices)) + else: + yield tuple(vertices) + break + face = face.next_face + + +def body_from_mesh(mesh: MeshBuilder, precision: int = 6) -> Body: + """Returns a :term:`ACIS` :class:`~ezdxf.acis.entities.Body` entity from a + :class:`~ezdxf.render.MeshBuilder` instance. + + This entity can be assigned to a :class:`~ezdxf.entities.Solid3d` DXF entity + as :term:`SAT` or :term:`SAB` data according to the version your DXF + document uses (SAT for DXF R2000 to R2010 and SAB for DXF R2013 and later). + + If the `mesh` contains multiple separated meshes, each mesh will be a + separated :class:`~ezdxf.acis.entities.Lump` node. + If each mesh should get its own :class:`~ezdxf.acis.entities.Body` entity, + separate the meshes beforehand by the method + :meth:`~ezdxf.render.MeshBuilder.separate_meshes`. + + A closed mesh creates a solid body and an open mesh creates an open (hollow) + shell. The detection if the mesh is open or closed is based on the edges + of the mesh: if **all** edges of mesh have two adjacent faces the mesh is + closed. + + The current implementation applies automatically a vertex optimization, + which merges coincident vertices into a single vertex. + + """ + mesh = mesh.optimize_vertices(precision) + body = Body() + bbox = BoundingBox(mesh.vertices) + if not bbox.center.is_null: + mesh.translate(-bbox.center) + transform = entities.Transform() + transform.matrix = Matrix44.translate(*bbox.center) + body.transform = transform + + for mesh in mesh.separate_meshes(): + lump = lump_from_mesh(mesh) + body.append_lump(lump) + return body + + +def lump_from_mesh(mesh: MeshBuilder) -> Lump: + """Returns a :class:`~ezdxf.acis.entities.Lump` entity from a + :class:`~ezdxf.render.MeshBuilder` instance. The `mesh` has to be a single + body or shell! + """ + lump = Lump() + shell = Shell() + lump.append_shell(shell) + face_builder = PolyhedronFaceBuilder(mesh) + for face in face_builder.acis_faces(): + shell.append_face(face) + return lump + + +class PolyhedronFaceBuilder: + def __init__(self, mesh: MeshBuilder): + mesh_copy = mesh.copy() + mesh_copy.normalize_faces() # open faces without duplicates! + self.vertices: list[Vec3] = mesh_copy.vertices + self.faces: list[Sequence[int]] = mesh_copy.faces + self.normals = list(mesh_copy.face_normals()) + self.acis_vertices: list[entities.Vertex] = [] + + # double_sided: + # If every edge belongs to two faces the body is for sure a closed + # surface. But the "is_edge_balance_broken" property can not detect + # non-manifold meshes! + # - True: the body is an open shell, each side of the face is outside + # (environment side) + # - False: the body is a closed solid body, one side points outwards of + # the body (environment side) and one side points inwards (material + # side) + self.double_sided = mesh_copy.diagnose().is_edge_balance_broken + + # coedges and edges ledger, where index1 <= index2 + self.partner_coedges: dict[tuple[int, int], entities.Coedge] = dict() + self.edges: dict[tuple[int, int], entities.Edge] = dict() + + def reset(self): + self.acis_vertices = list(make_vertices(self.vertices)) + self.partner_coedges.clear() + self.edges.clear() + + def acis_faces(self) -> list[Face]: + self.reset() + faces: list[Face] = [] + for face, face_normal in zip(self.faces, self.normals): + if face_normal.is_null: + continue + acis_face = Face() + plane = self.make_plane(face) + if plane is None: + continue + plane.normal = face_normal + loop = self.make_loop(face) + if loop is None: + continue + acis_face.append_loop(loop) + acis_face.surface = plane + acis_face.sense = False # face normal is plane normal + acis_face.double_sided = self.double_sided + faces.append(acis_face) + # The link structure of all entities is only completed at the end of + # the building process. Do not yield faces from the body of the loop! + return faces + + def make_plane(self, face: Sequence[int]) -> Optional[entities.Plane]: + assert len(face) > 1, "face requires least 2 vertices" + plane = entities.Plane() + # normal is always calculated by the right-hand rule: + plane.reverse_v = False + plane.origin = self.vertices[face[0]] + try: + plane.u_dir = (self.vertices[face[1]] - plane.origin).normalize() + except ZeroDivisionError: + return None # vertices are too close together + return plane + + def make_loop(self, face: Sequence[int]) -> Optional[entities.Loop]: + coedges: list[entities.Coedge] = [] + face2 = list(face[1:]) + if face[0] != face[-1]: + face2.append(face[0]) + + for i1, i2 in zip(face, face2): + coedge = self.make_coedge(i1, i2) + coedge.edge, coedge.sense = self.make_edge(i1, i2, coedge) + coedges.append(coedge) + loop = entities.Loop() + loop.set_coedges(coedges, close=True) + return loop + + def make_coedge(self, index1: int, index2: int) -> entities.Coedge: + if index1 > index2: + key = index2, index1 + else: + key = index1, index2 + coedge = entities.Coedge() + try: + partner_coedge = self.partner_coedges[key] + except KeyError: + self.partner_coedges[key] = coedge + else: + partner_coedge.add_partner_coedge(coedge) + return coedge + + def make_edge( + self, index1: int, index2: int, parent: entities.Coedge + ) -> tuple[entities.Edge, bool]: + def make_vertex(index: int): + vertex = self.acis_vertices[index] + vertex.ref_count += 1 + # assign first edge which references the vertex as parent edge (?): + if vertex.edge.is_none: + vertex.edge = edge + return vertex + + sense = False + ex1 = index1 # vertex index of unified edges + ex2 = index2 # vertex index of unified edges + if ex1 > ex2: + sense = True + ex1, ex2 = ex2, ex1 + try: + return self.edges[ex1, ex2], sense + except KeyError: + pass + # The edge has always the same direction as the underlying + # straight curve: + edge = entities.Edge() + edge.coedge = parent # first coedge which references this edge + edge.sense = False + edge.start_vertex = make_vertex(ex1) + edge.start_param = 0.0 + edge.end_vertex = make_vertex(ex2) + edge.end_param = self.vertices[ex1].distance(self.vertices[ex2]) + edge.curve = self.make_ray(ex1, ex2) + self.edges[ex1, ex2] = edge + return edge, sense + + def make_ray(self, index1: int, index2: int) -> entities.StraightCurve: + v1 = self.vertices[index1] + v2 = self.vertices[index2] + ray = entities.StraightCurve() + ray.origin = v1 + try: + ray.direction = (v2 - v1).normalize() + except ZeroDivisionError: # avoided by normalize_faces() + ray.direction = NULLVEC + return ray + + +def make_vertices(vertices: Iterable[Vec3]) -> Iterator[entities.Vertex]: + for v in vertices: + point = entities.Point() + point.location = v + vertex = entities.Vertex() + vertex.point = point + yield vertex + + +def vertices_from_body(body: Body) -> list[Vec3]: + """Returns all stored vertices in the given :class:`Body` entity. + The result is not optimized, meaning the vertices are in no particular order and + there are duplicates. + + This function can be useful to determining the approximate bounding box of an + :term:`ACIS` entity. The result is exact for polyhedra with flat faces with + straight edges, but not for bodies with curved edges and faces. + + Args: + body: ACIS entity of type :class:`Body` + + Raises: + TypeError: given `body` entity has invalid type + + """ + + if not isinstance(body, Body): + raise TypeError(f"expected a body entity, got: {type(body)}") + lump = body.lump + transform = body.transform + vertices: list[Vec3] = [] + + m: Optional[Matrix44] = None + if not transform.is_none: + m = transform.matrix + while not lump.is_none: + vertices.extend(vertices_from_lump(lump, m)) + lump = lump.next_lump + return vertices + + +def vertices_from_lump(lump: Lump, m: Matrix44 | None = None) -> list[Vec3]: + """Returns all stored vertices from a given :class:`Lump` entity. + Applies the transformation :class:`~ezdxf.math.Matrix44` `m` to all vertices if not + ``None``. + + Args: + lump: :class:`Lump` entity + m: optional transformation matrix + + Raises: + TypeError: `lump` has invalid ACIS type + + """ + if not isinstance(lump, Lump): + raise TypeError(f"expected a lump entity, got: {type(lump)}") + + vertices: list[Vec3] = [] + shell = lump.shell + if shell.is_none: + return vertices # not a shell + + face = shell.face + while not face.is_none: + first_coedge = NONE_REF + try: + first_coedge = face.loop.coedge + except AttributeError: # loop is a none-entity + pass + coedge = first_coedge + while not coedge.is_none: # invalid coedge or face is not closed + # the edge entity contains the vertices and the curve type + edge = coedge.edge + try: + vertices.append(edge.start_vertex.point.location) + vertices.append(edge.end_vertex.point.location) + except AttributeError: + # one of the involved entities is a none-entity or an + # incompatible entity type -> ignore this face! + break + coedge = coedge.next_coedge + if coedge is first_coedge: # a valid closed face + break + face = face.next_face + if m is not None: + return list(m.transform_vertices(vertices)) + return vertices diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/sab.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/sab.py new file mode 100644 index 0000000..5141b47 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/sab.py @@ -0,0 +1,527 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + NamedTuple, + Any, + Sequence, + Iterator, + Union, + Iterable, + cast, + TYPE_CHECKING, + List, + Tuple, + Optional, +) +from typing_extensions import TypeAlias +import math +import struct +from datetime import datetime + +from ezdxf.math import Vec3 +from . import const +from .const import ParsingError, Tags, InvalidLinkStructure +from .hdr import AcisHeader +from .abstract import ( + AbstractEntity, + DataLoader, + AbstractBuilder, + DataExporter, + EntityExporter, +) + +if TYPE_CHECKING: + from .entities import AcisEntity + + +class Token(NamedTuple): + """Named tuple to store tagged value tokens of the SAB format.""" + + tag: int + value: Any + + def __str__(self): + return f"(0x{self.tag:02x}, {str(self.value)})" + + +SabRecord: TypeAlias = List[Token] + + +class Decoder: + def __init__(self, data: bytes): + self.data = data + self.index: int = 0 + + @property + def has_data(self) -> bool: + return self.index < len(self.data) + + def read_header(self) -> AcisHeader: + header = AcisHeader() + for signature in const.SIGNATURES: + if self.data.startswith(signature): + self.index = len(signature) + break + else: + raise ParsingError("not a SAB file") + header.version = self.read_int() + header.n_records = self.read_int() + header.n_entities = self.read_int() + header.flags = self.read_int() + header.product_id = self.read_str_tag() + header.acis_version = self.read_str_tag() + date = self.read_str_tag() + header.creation_date = datetime.strptime(date, const.DATE_FMT) + header.units_in_mm = self.read_double_tag() + # tolerances are ignored + _ = self.read_double_tag() # res_tol + _ = self.read_double_tag() # nor_tol + return header + + def forward(self, count: int): + pos = self.index + self.index += count + return pos + + def read_byte(self) -> int: + pos = self.forward(1) + return self.data[pos] + + def read_bytes(self, count: int) -> bytes: + pos = self.forward(count) + return self.data[pos : pos + count] + + def read_int(self) -> int: + pos = self.forward(4) + values = struct.unpack_from(" float: + pos = self.forward(8) + return struct.unpack_from(" Sequence[float]: + pos = self.forward(8 * count) + return struct.unpack_from(f"<{count}d", self.data, pos) + + def read_str(self, length) -> str: + text = self.read_bytes(length) + return text.decode() + + def read_str_tag(self) -> str: + tag = self.read_byte() + if tag != Tags.STR: + raise ParsingError("string tag (7) not found") + return self.read_str(self.read_byte()) + + def read_double_tag(self) -> float: + tag = self.read_byte() + if tag != Tags.DOUBLE: + raise ParsingError("double tag (6) not found") + return self.read_float() + + def read_record(self) -> SabRecord: + def entity_name(): + return "-".join(entity_type) + + values: SabRecord = [] + entity_type: list[str] = [] + subtype_level: int = 0 + while True: + if not self.has_data: + if values: + token = values[0] + if token.value in const.DATA_END_MARKERS: + return values + raise ParsingError("pre-mature end of data") + tag = self.read_byte() + if tag == Tags.INT: + values.append(Token(tag, self.read_int())) + elif tag == Tags.DOUBLE: + values.append(Token(tag, self.read_float())) + elif tag == Tags.STR: + values.append(Token(tag, self.read_str(self.read_byte()))) + elif tag == Tags.POINTER: + values.append(Token(tag, self.read_int())) + elif tag == Tags.BOOL_TRUE: + values.append(Token(tag, True)) + elif tag == Tags.BOOL_FALSE: + values.append(Token(tag, False)) + elif tag == Tags.LITERAL_STR: + values.append(Token(tag, self.read_str(self.read_int()))) + elif tag == Tags.ENTITY_TYPE_EX: + entity_type.append(self.read_str(self.read_byte())) + elif tag == Tags.ENTITY_TYPE: + entity_type.append(self.read_str(self.read_byte())) + values.append(Token(tag, entity_name())) + entity_type.clear() + elif tag == Tags.LOCATION_VEC: + values.append(Token(tag, self.read_floats(3))) + elif tag == Tags.DIRECTION_VEC: + values.append(Token(tag, self.read_floats(3))) + elif tag == Tags.ENUM: + values.append(Token(tag, self.read_int())) + elif tag == Tags.UNKNOWN_0x17: + values.append(Token(tag, self.read_float())) + elif tag == Tags.SUBTYPE_START: + subtype_level += 1 + values.append(Token(tag, subtype_level)) + elif tag == Tags.SUBTYPE_END: + values.append(Token(tag, subtype_level)) + subtype_level -= 1 + elif tag == Tags.RECORD_END: + return values + else: + raise ParsingError( + f"unknown SAB tag: 0x{tag:x} ({tag}) in entity '{values[0].value}'" + ) + + def read_records(self) -> Iterator[SabRecord]: + while True: + try: + if self.has_data: + yield self.read_record() + else: + return + except IndexError: + return + + +class SabEntity(AbstractEntity): + """Low level representation of an ACIS entity (node).""" + + def __init__( + self, + name: str, + attr_ptr: int = -1, + id: int = -1, + data: Optional[SabRecord] = None, + ): + self.name = name + self.attr_ptr = attr_ptr + self.id = id + self.data: SabRecord = data if data is not None else [] + self.attributes: "SabEntity" = None # type: ignore + + def __str__(self): + return f"{self.name}({self.id})" + + +NULL_PTR = SabEntity(const.NULL_PTR_NAME, -1, -1, tuple()) # type: ignore + + +class SabDataLoader(DataLoader): + def __init__(self, data: SabRecord, version: int): + self.version = version + self.data = data + self.index = 0 + + def has_data(self) -> bool: + return self.index <= len(self.data) + + def read_int(self, skip_sat: Optional[int] = None) -> int: + token = self.data[self.index] + if token.tag == Tags.INT: + self.index += 1 + return cast(int, token.value) + raise ParsingError(f"expected int token, got {token}") + + def read_double(self) -> float: + token = self.data[self.index] + if token.tag == Tags.DOUBLE: + self.index += 1 + return cast(float, token.value) + raise ParsingError(f"expected double token, got {token}") + + def read_interval(self) -> float: + finite = self.read_bool("F", "I") + if finite: + return self.read_double() + return math.inf + + def read_vec3(self) -> tuple[float, float, float]: + token = self.data[self.index] + if token.tag in (Tags.LOCATION_VEC, Tags.DIRECTION_VEC): + self.index += 1 + return cast(Tuple[float, float, float], token.value) + raise ParsingError(f"expected vector token, got {token}") + + def read_bool(self, true: str, false: str) -> bool: + token = self.data[self.index] + if token.tag == Tags.BOOL_TRUE: + self.index += 1 + return True + elif token.tag == Tags.BOOL_FALSE: + self.index += 1 + return False + raise ParsingError(f"expected bool token, got {token}") + + def read_str(self) -> str: + token = self.data[self.index] + if token.tag in (Tags.STR, Tags.LITERAL_STR): + self.index += 1 + return cast(str, token.value) + raise ParsingError(f"expected str token, got {token}") + + def read_ptr(self) -> AbstractEntity: + token = self.data[self.index] + if token.tag == Tags.POINTER: + self.index += 1 + return cast(AbstractEntity, token.value) + raise ParsingError(f"expected pointer token, got {token}") + + def read_transform(self) -> list[float]: + # Transform matrix is stored as literal string like in the SAT format! + # 4th column is not stored + # Read only the matrix values which contain all information needed, + # the additional data are only hints for the kernel how to process + # the data (rotation, reflection, scaling, shearing). + values = self.read_str().split(" ") + return [float(v) for v in values[:12]] + + +class SabBuilder(AbstractBuilder): + """Low level data structure to manage ACIS SAB data files.""" + + def __init__(self) -> None: + self.header = AcisHeader() + self.bodies: list[SabEntity] = [] + self.entities: list[SabEntity] = [] + + def dump_sab(self) -> bytes: + """Returns the SAB representation of the ACIS file as bytes.""" + self.reorder_records() + self.header.n_entities = len(self.bodies) + int( + self.header.has_asm_header + ) + self.header.n_records = 0 # is always 0 + self.header.flags = 12 # important for 21800 - meaning unknown + data: list[bytes] = [self.header.dumpb()] + encoder = Encoder() + for record in build_sab_records(self.entities): + encoder.write_record(record) + data.extend(encoder.buffer) + data.append(self.header.sab_end_marker()) + return b"".join(data) + + def set_entities(self, entities: list[SabEntity]) -> None: + """Reset entities and bodies list. (internal API)""" + self.bodies = [e for e in entities if e.name == "body"] + self.entities = entities + + +class SabExporter(EntityExporter[SabEntity]): + def make_record(self, entity: AcisEntity) -> SabEntity: + record = SabEntity(entity.type, id=entity.id) + record.attributes = NULL_PTR + return record + + def make_data_exporter(self, record: SabEntity) -> DataExporter: + return SabDataExporter(self, record.data) + + def dump_sab(self) -> bytes: + builder = SabBuilder() + builder.header = self.header + builder.set_entities(self.export_records()) + return builder.dump_sab() + + +def build_entities( + records: Iterable[SabRecord], version: int +) -> Iterator[SabEntity]: + for record in records: + assert record[0].tag == Tags.ENTITY_TYPE, "invalid entity-name tag" + name = record[0].value # 1. entity-name + if name in const.DATA_END_MARKERS: + yield SabEntity(name) + return + assert record[1].tag == Tags.POINTER, "invalid attribute pointer tag" + attr = record[1].value # 2. attribute record pointer + id_ = -1 + if version >= 700: + assert record[2].tag == Tags.INT, "invalid id tag" + id_ = record[2].value # 3. int id + data = record[3:] + else: + data = record[2:] + yield SabEntity(name, attr, id_, data) + + +def resolve_pointers(entities: list[SabEntity]) -> list[SabEntity]: + def ptr(num: int) -> SabEntity: + if num == -1: + return NULL_PTR + return entities[num] + + for entity in entities: + entity.attributes = ptr(entity.attr_ptr) + entity.attr_ptr = -1 + for index, token in enumerate(entity.data): + if token.tag == Tags.POINTER: + entity.data[index] = Token(token.tag, ptr(token.value)) + return entities + + +def parse_sab(data: Union[bytes, bytearray]) -> SabBuilder: + """Returns the :class:`SabBuilder` for the ACIS :term:`SAB` file content + given as string or list of strings. + + Raises: + ParsingError: invalid or unsupported ACIS data structure + + """ + if not isinstance(data, (bytes, bytearray)): + raise TypeError("expected bytes, bytearray") + builder = SabBuilder() + decoder = Decoder(data) + builder.header = decoder.read_header() + entities = list( + build_entities(decoder.read_records(), builder.header.version) + ) + builder.set_entities(resolve_pointers(entities)) + return builder + + +class SabDataExporter(DataExporter): + def __init__(self, exporter: SabExporter, data: list[Token]): + self.version = exporter.version + self.exporter = exporter + self.data = data + + def write_int(self, value: int, skip_sat=False) -> None: + """There are sometimes additional int values in SAB files which are + not present in SAT files, maybe reference counters e.g. vertex, coedge. + """ + self.data.append(Token(Tags.INT, value)) + + def write_double(self, value: float) -> None: + self.data.append(Token(Tags.DOUBLE, value)) + + def write_interval(self, value: float) -> None: + if math.isinf(value): + self.data.append(Token(Tags.BOOL_FALSE, False)) # infinite "I" + else: + self.data.append(Token(Tags.BOOL_TRUE, True)) # finite "F" + self.write_double(value) + + def write_loc_vec3(self, value: Vec3) -> None: + self.data.append(Token(Tags.LOCATION_VEC, value)) + + def write_dir_vec3(self, value: Vec3) -> None: + self.data.append(Token(Tags.DIRECTION_VEC, value)) + + def write_bool(self, value: bool, true: str, false: str) -> None: + if value: + self.data.append(Token(Tags.BOOL_TRUE, True)) + else: + self.data.append(Token(Tags.BOOL_FALSE, False)) + + def write_str(self, value: str) -> None: + self.data.append(Token(Tags.STR, value)) + + def write_literal_str(self, value: str) -> None: + self.data.append(Token(Tags.LITERAL_STR, value)) + + def write_ptr(self, entity: AcisEntity) -> None: + record = NULL_PTR + if not entity.is_none: + record = self.exporter.get_record(entity) + self.data.append(Token(Tags.POINTER, record)) + + def write_transform(self, data: list[str]) -> None: + # The last space is important! + self.write_literal_str(" ".join(data) + " ") + + +def encode_entity_type(name: str) -> list[Token]: + if name == const.NULL_PTR_NAME: + raise InvalidLinkStructure( + f"invalid record type: {const.NULL_PTR_NAME}" + ) + parts = name.split("-") + tokens = [Token(Tags.ENTITY_TYPE_EX, part) for part in parts[:-1]] + tokens.append(Token(Tags.ENTITY_TYPE, parts[-1])) + return tokens + + +def encode_entity_ptr(entity: SabEntity, entities: list[SabEntity]) -> Token: + if entity.is_null_ptr: + return Token(Tags.POINTER, -1) + try: + return Token(Tags.POINTER, entities.index(entity)) + except ValueError: + raise InvalidLinkStructure( + f"entity {str(entity)} not in record storage" + ) + + +def build_sab_records(entities: list[SabEntity]) -> Iterator[SabRecord]: + for entity in entities: + record: list[Token] = [] + record.extend(encode_entity_type(entity.name)) + # 1. attribute record pointer + record.append(encode_entity_ptr(entity.attributes, entities)) + # 2. int id + record.append(Token(Tags.INT, entity.id)) + for token in entity.data: + if token.tag == Tags.POINTER: + record.append(encode_entity_ptr(token.value, entities)) + elif token.tag == Tags.ENTITY_TYPE: + record.extend(encode_entity_type(token.value)) + else: + record.append(token) + yield record + + +END_OF_RECORD = bytes([Tags.RECORD_END.value]) +TRUE_RECORD = bytes([Tags.BOOL_TRUE.value]) +FALSE_RECORD = bytes([Tags.BOOL_FALSE.value]) +SUBTYPE_START_RECORD = bytes([Tags.SUBTYPE_START.value]) +SUBTYPE_END_RECORD = bytes([Tags.SUBTYPE_END.value]) +SAB_ENCODING = "utf8" + + +class Encoder: + def __init__(self) -> None: + self.buffer: list[bytes] = [] + + def write_record(self, record: SabRecord) -> None: + for token in record: + self.write_token(token) + self.buffer.append(END_OF_RECORD) + + def write_token(self, token: Token) -> None: + tag = token.tag + if tag in (Tags.INT, Tags.POINTER, Tags.ENUM): + assert isinstance(token.value, int) + self.buffer.append(struct.pack(" SatEntity: + """Factory to create new ACIS entities. + + Args: + name: entity type + attributes: reference to the entity attributes or :attr:`NULL_PTR`. + id: unique entity id as integer or -1 + data: generic data container as list + + """ + e = SatEntity(name, "$-1", id, data) + e.attributes = attributes + return e + + +def is_ptr(s: str) -> bool: + """Returns ``True`` if the string `s` represents an entity pointer.""" + return len(s) > 0 and s[0] == "$" + + +def resolve_str_pointers(entities: list[SatEntity]) -> list[SatEntity]: + def ptr(s: str) -> SatEntity: + num = int(s[1:]) + if num == -1: + return NULL_PTR + return entities[num] + + for entity in entities: + entity.attributes = ptr(entity.attr_ptr) + entity.attr_ptr = "$-1" + data = [] + for token in entity.data: + if is_ptr(token): + data.append(ptr(token)) + else: + data.append(token) + entity.data = data + return entities + + +class SatDataLoader(DataLoader): + def __init__(self, data: list[Any], version: int): + self.version = version + self.data = data + self.index = 0 + + def has_data(self) -> bool: + return self.index <= len(self.data) + + def read_int(self, skip_sat: Optional[int] = None) -> int: + if skip_sat is not None: + return skip_sat + + entry = self.data[self.index] + try: + value = int(entry) + except ValueError: + raise ParsingError(f"expected integer, got {entry}") + self.index += 1 + return value + + def read_double(self) -> float: + entry = self.data[self.index] + try: + value = float(entry) + except ValueError: + raise ParsingError(f"expected double, got {entry}") + self.index += 1 + return value + + def read_interval(self) -> float: + finite = self.read_bool("F", "I") + if finite: + return self.read_double() + return math.inf + + def read_vec3(self) -> tuple[float, float, float]: + x = self.read_double() + y = self.read_double() + z = self.read_double() + return x, y, z + + def read_bool(self, true: str, false: str) -> bool: + value = self.data[self.index] + if value == true: + self.index += 1 + return True + elif value == false: + self.index += 1 + return False + raise ParsingError( + f"expected bool string '{true}' or '{false}', got {value}" + ) + + def read_str(self) -> str: + value = self.data[self.index] + if self.version < const.Features.AT or value.startswith("@"): + self.index += 2 + return self.data[self.index - 1] + raise ParsingError(f"expected string, got {value}") + + def read_ptr(self) -> AbstractEntity: + entity = self.data[self.index] + if isinstance(entity, AbstractEntity): + self.index += 1 + return entity + raise ParsingError(f"expected pointer, got {type(entity)}") + + def read_transform(self) -> list[float]: + # 4th column is not stored + # Read only the matrix values which contain all information needed, + # the additional data are only hints for the kernel how to process + # the data (rotation, reflection, scaling, shearing). + return [self.read_double() for _ in range(12)] + + +class SatBuilder(AbstractBuilder): + """Low level data structure to manage ACIS SAT data files.""" + + def __init__(self) -> None: + self.header = AcisHeader() + self.bodies: list[SatEntity] = [] + self.entities: list[SatEntity] = [] + self._export_mapping: dict[int, SatEntity] = {} + + def dump_sat(self) -> list[str]: + """Returns the text representation of the ACIS file as list of strings + without line endings. + + Raise: + InvalidLinkStructure: referenced ACIS entity is not stored in + the :attr:`entities` storage + + """ + self.reorder_records() + self.header.n_entities = len(self.bodies) + int( + self.header.has_asm_header + ) + if self.header.version == 700: + self.header.n_records = 0 # ignored for old versions + else: + self.header.n_records = len(self.entities) + data = self.header.dumps() + data.extend(build_str_records(self.entities, self.header.version)) + data.append(self.header.sat_end_marker()) + return data + + def set_entities(self, entities: list[SatEntity]) -> None: + """Reset entities and bodies list. (internal API)""" + self.bodies = [e for e in entities if e.name == "body"] + self.entities = entities + + +class SatExporter(EntityExporter[SatEntity]): + def make_record(self, entity: AcisEntity) -> SatEntity: + record = SatEntity(entity.type, id=entity.id) + record.attributes = NULL_PTR + return record + + def make_data_exporter(self, record: SatEntity) -> DataExporter: + return SatDataExporter(self, record.data) + + def dump_sat(self) -> list[str]: + builder = SatBuilder() + builder.header = self.header + builder.set_entities(self.export_records()) + return builder.dump_sat() + + +def build_str_records(entities: list[SatEntity], version: int) -> Iterator[str]: + def ptr_str(e: SatEntity) -> str: + if e is NULL_PTR: + return "$-1" + try: + return f"${entities.index(e)}" + except ValueError: + raise InvalidLinkStructure(f"entity {str(e)} not in record storage") + + for entity in entities: + tokens = [entity.name] + tokens.append(ptr_str(entity.attributes)) + if version >= 700: + tokens.append(str(entity.id)) + for data in entity.data: + if isinstance(data, SatEntity): + tokens.append(ptr_str(data)) + else: + tokens.append(str(data)) + tokens.append("#") + yield " ".join(tokens) + + +def parse_header_str(s: str) -> Iterator[str]: + num = "" + collect = 0 + token = "" + for c in s.rstrip(): + if collect > 0: + token += c + collect -= 1 + if collect == 0: + yield token + token = "" + elif c == "@": + continue + elif c in "0123456789": + num += c + elif c == " " and num: + collect = int(num) + num = "" + + +def parse_header(data: Sequence[str]) -> tuple[AcisHeader, Sequence[str]]: + header = AcisHeader() + tokens = data[0].split() + header.version = int(tokens[0]) + try: + header.n_records = int(tokens[1]) + header.n_entities = int(tokens[2]) + header.flags = int(tokens[3]) + except (IndexError, ValueError): + pass + tokens = list(parse_header_str(data[1])) + try: + header.product_id = tokens[0] + header.acis_version = tokens[1] + except IndexError: + pass + + if len(tokens) > 2: + try: # Sat Jan 1 10:00:00 2022 + header.creation_date = datetime.strptime(tokens[2], const.DATE_FMT) + except ValueError: + pass + tokens = data[2].split() + try: + header.units_in_mm = float(tokens[0]) + except (IndexError, ValueError): + pass + return header, data[3:] + + +def _filter_records(data: Sequence[str]) -> Iterator[str]: + for line in data: + if line.startswith(const.END_OF_ACIS_DATA_SAT) or line.startswith( + const.BEGIN_OF_ACIS_HISTORY_DATA + ): + return + yield line + + +def merge_record_strings(data: Sequence[str]) -> Iterator[str]: + merged_data = " ".join(_filter_records(data)) + for record in merged_data.split("#"): + record = record.strip() + if record: + yield record + + +def parse_records(data: Sequence[str]) -> list[SatRecord]: + expected_seq_num = 0 + records: list[SatRecord] = [] + for line in merge_record_strings(data): + tokens: SatRecord = line.split() + first_token = tokens[0].strip() + if first_token.startswith("-"): + num = -int(first_token) + if num != expected_seq_num: + raise ParsingError( + "non-continuous sequence numbers not supported" + ) + tokens.pop(0) + records.append(tokens) + expected_seq_num += 1 + return records + + +def build_entities( + records: Sequence[SatRecord], version: int +) -> list[SatEntity]: + entities: list[SatEntity] = [] + for record in records: + name = record[0] + attr = record[1] + id_ = -1 + if version >= 700: + id_ = int(record[2]) + data = record[3:] + else: + data = record[2:] + entities.append(SatEntity(name, attr, id_, data)) + return entities + + +def parse_sat(s: Union[str, Sequence[str]]) -> SatBuilder: + """Returns the :class:`SatBuilder` for the ACIS :term:`SAT` file content + given as string or list of strings. + + Raises: + ParsingError: invalid or unsupported ACIS data structure + + """ + data: Sequence[str] + if isinstance(s, str): + data = s.splitlines() + else: + data = s + if not isinstance(data, Sequence): + raise TypeError("expected as string or a sequence of strings") + builder = SatBuilder() + header, data = parse_header(data) + builder.header = header + records = parse_records(data) + entities = build_entities(records, header.version) + builder.set_entities(resolve_str_pointers(entities)) + return builder + + +class SatDataExporter(DataExporter): + def __init__(self, exporter: SatExporter, data: list[Any]): + self.version = exporter.version + self.exporter = exporter + self.data = data + + def write_int(self, value: int, skip_sat=False) -> None: + """There are sometimes additional int values in SAB files which are + not present in SAT files, maybe reference counters e.g. vertex, coedge. + """ + if not skip_sat: + self.data.append(str(value)) + + def write_double(self, value: float) -> None: + self.data.append(f"{value:g}") + + def write_interval(self, value: float) -> None: + if math.isinf(value): + self.data.append("I") # infinite + else: + self.data.append("F") # finite + self.write_double(value) + + def write_loc_vec3(self, value: Vec3) -> None: + self.write_double(value.x) + self.write_double(value.y) + self.write_double(value.z) + + def write_dir_vec3(self, value: Vec3) -> None: + self.write_double(value.x) + self.write_double(value.y) + self.write_double(value.z) + + def write_bool(self, value: bool, true: str, false: str) -> None: + self.data.append(true if value else false) + + def write_str(self, value: str) -> None: + self.data.append(f"@{len(value)}") + self.data.append(str(value)) + + def write_literal_str(self, value: str) -> None: + self.write_str(value) # just for SAB files important + + def write_ptr(self, entity: AcisEntity) -> None: + record = NULL_PTR + if not entity.is_none: + record = self.exporter.get_record(entity) + self.data.append(record) + + def write_transform(self, data: list[str]) -> None: + self.data.extend(data) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/acis/type_hints.py b/.venv/lib/python3.12/site-packages/ezdxf/acis/type_hints.py new file mode 100644 index 0000000..976d770 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/acis/type_hints.py @@ -0,0 +1,7 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Union +from typing_extensions import TypeAlias + +EncodedData: TypeAlias = Union[str, Sequence[str], bytes, bytearray] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/__init__.py new file mode 100644 index 0000000..9219163 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/__init__.py @@ -0,0 +1,10 @@ +# Copyright (C) 2011-2022, Manfred Moitzi +# License: MIT License +from .mtextsurrogate import MTextSurrogate +from .tablepainter import TablePainter, CustomCell +from .menger_sponge import MengerSponge +from .sierpinski_pyramid import SierpinskyPyramid +from .dimlines import LinearDimension, AngularDimension, ArcDimension, RadialDimension, dimstyles +from .importer import Importer +from .r12writer import r12writer +from .mtxpl import MTextExplode diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..aff683b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/acadctb.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/acadctb.cpython-312.pyc new file mode 100644 index 0000000..aabd399 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/acadctb.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/binpacking.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/binpacking.cpython-312.pyc new file mode 100644 index 0000000..873e001 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/binpacking.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dimlines.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dimlines.cpython-312.pyc new file mode 100644 index 0000000..e9618e5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dimlines.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dxf2code.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dxf2code.cpython-312.pyc new file mode 100644 index 0000000..243aec1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/dxf2code.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/genetic_algorithm.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/genetic_algorithm.cpython-312.pyc new file mode 100644 index 0000000..7def618 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/genetic_algorithm.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/geo.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/geo.cpython-312.pyc new file mode 100644 index 0000000..9f1400e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/geo.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/gerber_D6673.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/gerber_D6673.cpython-312.pyc new file mode 100644 index 0000000..31a0d7a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/gerber_D6673.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/importer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/importer.cpython-312.pyc new file mode 100644 index 0000000..712ebd7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/importer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/iterdxf.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/iterdxf.cpython-312.pyc new file mode 100644 index 0000000..08ca110 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/iterdxf.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/menger_sponge.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/menger_sponge.cpython-312.pyc new file mode 100644 index 0000000..1e35ad9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/menger_sponge.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/meshex.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/meshex.cpython-312.pyc new file mode 100644 index 0000000..d403ab1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/meshex.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mixins.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mixins.cpython-312.pyc new file mode 100644 index 0000000..8dccc27 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mixins.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtextsurrogate.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtextsurrogate.cpython-312.pyc new file mode 100644 index 0000000..97b0297 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtextsurrogate.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtxpl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtxpl.cpython-312.pyc new file mode 100644 index 0000000..4c8d083 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/mtxpl.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/odafc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/odafc.cpython-312.pyc new file mode 100644 index 0000000..3a193a8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/odafc.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/openscad.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/openscad.cpython-312.pyc new file mode 100644 index 0000000..59d3bb5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/openscad.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/pycsg.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/pycsg.cpython-312.pyc new file mode 100644 index 0000000..c7ffa87 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/pycsg.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12export.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12export.cpython-312.pyc new file mode 100644 index 0000000..7ee4e80 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12export.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12writer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12writer.cpython-312.pyc new file mode 100644 index 0000000..033157c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/r12writer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/sierpinski_pyramid.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/sierpinski_pyramid.cpython-312.pyc new file mode 100644 index 0000000..462cf7a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/sierpinski_pyramid.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/tablepainter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/tablepainter.cpython-312.pyc new file mode 100644 index 0000000..4b772c2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/tablepainter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/text2path.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/text2path.cpython-312.pyc new file mode 100644 index 0000000..83ecf5f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/text2path.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xplayer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xplayer.cpython-312.pyc new file mode 100644 index 0000000..905e0f6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xplayer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xqt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xqt.cpython-312.pyc new file mode 100644 index 0000000..b8c2042 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/__pycache__/xqt.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acadctb.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/acadctb.py new file mode 100644 index 0000000..d5eb183 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/acadctb.py @@ -0,0 +1,779 @@ +# Purpose: read and write AutoCAD CTB files +# Copyright (c) 2010-2023, Manfred Moitzi +# License: MIT License +# IMPORTANT: use only standard 7-Bit ascii code +from __future__ import annotations +from typing import ( + Union, + Optional, + BinaryIO, + TextIO, + Iterable, + Iterator, + Any, +) +import os +from abc import abstractmethod +from io import StringIO +from array import array +from struct import pack +import zlib + +END_STYLE_BUTT = 0 +END_STYLE_SQUARE = 1 +END_STYLE_ROUND = 2 +END_STYLE_DIAMOND = 3 +END_STYLE_OBJECT = 4 + +JOIN_STYLE_MITER = 0 +JOIN_STYLE_BEVEL = 1 +JOIN_STYLE_ROUND = 2 +JOIN_STYLE_DIAMOND = 3 +JOIN_STYLE_OBJECT = 5 + +FILL_STYLE_SOLID = 64 +FILL_STYLE_CHECKERBOARD = 65 +FILL_STYLE_CROSSHATCH = 66 +FILL_STYLE_DIAMONDS = 67 +FILL_STYLE_HORIZONTAL_BARS = 68 +FILL_STYLE_SLANT_LEFT = 69 +FILL_STYLE_SLANT_RIGHT = 70 +FILL_STYLE_SQUARE_DOTS = 71 +FILL_STYLE_VERICAL_BARS = 72 +FILL_STYLE_OBJECT = 73 + +DITHERING_ON = 1 # bit coded color_policy +GRAYSCALE_ON = 2 # bit coded color_policy +NAMED_COLOR = 4 # bit coded color_policy + +AUTOMATIC = 0 +OBJECT_LINEWEIGHT = 0 +OBJECT_LINETYPE = 31 +OBJECT_COLOR = -1 +OBJECT_COLOR2 = -1006632961 + +STYLE_COUNT = 255 + +DEFAULT_LINE_WEIGHTS = [ + 0.00, # 0 + 0.05, # 1 + 0.09, # 2 + 0.10, # 3 + 0.13, # 4 + 0.15, # 5 + 0.18, # 6 + 0.20, # 7 + 0.25, # 8 + 0.30, # 9 + 0.35, # 10 + 0.40, # 11 + 0.45, # 12 + 0.50, # 13 + 0.53, # 14 + 0.60, # 15 + 0.65, # 16 + 0.70, # 17 + 0.80, # 18 + 0.90, # 19 + 1.00, # 20 + 1.06, # 21 + 1.20, # 22 + 1.40, # 23 + 1.58, # 24 + 2.00, # 25 + 2.11, # 26 +] + +# color_type: (thx to Rammi) + +# Take color from layer, ignore other bytes. +COLOR_BY_LAYER = 0xC0 + +# Take color from insertion, ignore other bytes +COLOR_BY_BLOCK = 0xC1 + +# RGB value, other bytes are R,G,B. +COLOR_RGB = 0xC2 + +# ACI, AutoCAD color index, other bytes are 0,0,index ??? +COLOR_ACI = 0xC3 + + +def color_name(index: int) -> str: + return "Color_%d" % (index + 1) + + +def get_bool(value: Union[str, bool]) -> bool: + if isinstance(value, str): + upperstr = value.upper() + if upperstr == "TRUE": + value = True + elif upperstr == "FALSE": + value = False + else: + raise ValueError("Unknown bool value '%s'." % str(value)) + return value + + +class PlotStyle: + def __init__( + self, + index: int, + data: Optional[dict] = None, + parent: Optional[PlotStyleTable] = None, + ): + data = data or {} + self.parent = parent + self.index = int(index) + self.name = str(data.get("name", color_name(index))) + self.localized_name = str(data.get("localized_name", color_name(index))) + self.description = str(data.get("description", "")) + # do not set _color, _mode_color or _color_policy directly + # use set_color() method, and the properties dithering and grayscale + self._color = int(data.get("color", OBJECT_COLOR)) + self._color_type = COLOR_RGB + if self._color != OBJECT_COLOR: + self._mode_color = int(data.get("mode_color", self._color)) + self._color_policy = int(data.get("color_policy", DITHERING_ON)) + self.physical_pen_number = int(data.get("physical_pen_number", AUTOMATIC)) + self.virtual_pen_number = int(data.get("virtual_pen_number", AUTOMATIC)) + self.screen = int(data.get("screen", 100)) + self.linepattern_size = float(data.get("linepattern_size", 0.5)) + self.linetype = int(data.get("linetype", OBJECT_LINETYPE)) # 0 .. 30 + self.adaptive_linetype = get_bool(data.get("adaptive_linetype", True)) + + # lineweight index + self.lineweight = int(data.get("lineweight", OBJECT_LINEWEIGHT)) + self.end_style = int(data.get("end_style", END_STYLE_OBJECT)) + self.join_style = int(data.get("join_style", JOIN_STYLE_OBJECT)) + self.fill_style = int(data.get("fill_style", FILL_STYLE_OBJECT)) + + @property + def color(self) -> Optional[tuple[int, int, int]]: + """Get style color as ``(r, g, b)`` tuple or ``None``, if style has + object color. + """ + if self.has_object_color(): + return None # object color + else: + return int2color(self._mode_color)[:3] + + @color.setter + def color(self, rgb: tuple[int, int, int]) -> None: + """Set color as RGB values.""" + r, g, b = rgb + # when defining a user-color, `mode_color` represents the real + # true_color as (r, g, b) tuple and color_type = COLOR_RGB (0xC2) as + # highest byte, the `color` value calculated for a user-color is not a + # (r, g, b) tuple and has color_type = COLOR_ACI (0xC3) (sometimes), set + # for `color` the same value as for `mode_color`, because AutoCAD + # corrects the `color` value by itself. + self._mode_color = mode_color2int(r, g, b, color_type=self._color_type) + self._color = self._mode_color + + @property + def color_type(self): + if self.has_object_color(): + return None # object color + else: + return self._color_type + + @color_type.setter + def color_type(self, value: int): + self._color_type = value + + def set_object_color(self) -> None: + """Set color to object color.""" + self._color = OBJECT_COLOR + self._mode_color = OBJECT_COLOR + + def set_lineweight(self, lineweight: float) -> None: + """Set `lineweight` in millimeters. Use ``0.0`` to set lineweight by + object. + """ + assert self.parent is not None + self.lineweight = self.parent.get_lineweight_index(lineweight) + + def get_lineweight(self) -> float: + """Returns the lineweight in millimeters or `0.0` for use entity + lineweight. + """ + assert self.parent is not None + return self.parent.lineweights[self.lineweight] + + def has_object_color(self) -> bool: + """``True`` if style has object color.""" + return self._color in (OBJECT_COLOR, OBJECT_COLOR2) + + @property + def aci(self) -> int: + """:ref:`ACI` in range from ``1`` to ``255``. Has no meaning for named + plot styles. (int) + """ + return self.index + 1 + + @property + def dithering(self) -> bool: + """Depending on the capabilities of your plotter, dithering approximates + the colors with dot patterns. When this option is ``False``, the colors + are mapped to the nearest color, resulting in a smaller range of + colors when plotting. + + Dithering is available only whether you select the object’s color or + assign a plot style color. + + """ + return bool(self._color_policy & DITHERING_ON) + + @dithering.setter + def dithering(self, status: bool) -> None: + if status: + self._color_policy |= DITHERING_ON + else: + self._color_policy &= ~DITHERING_ON + + @property + def grayscale(self) -> bool: + """Plot colors in grayscale. (bool)""" + return bool(self._color_policy & GRAYSCALE_ON) + + @grayscale.setter + def grayscale(self, status: bool) -> None: + if status: + self._color_policy |= GRAYSCALE_ON + else: + self._color_policy &= ~GRAYSCALE_ON + + @property + def named_color(self) -> bool: + return bool(self._color_policy & NAMED_COLOR) + + @named_color.setter + def named_color(self, status: bool) -> None: + if status: + self._color_policy |= NAMED_COLOR + else: + self._color_policy &= ~NAMED_COLOR + + def write(self, stream: TextIO) -> None: + """Write style data to file-like object `stream`.""" + index = self.index + stream.write(" %d{\n" % index) + stream.write(' name="%s\n' % self.name) + stream.write(' localized_name="%s\n' % self.localized_name) + stream.write(' description="%s\n' % self.description) + stream.write(" color=%d\n" % self._color) + if self._color != OBJECT_COLOR: + stream.write(" mode_color=%d\n" % self._mode_color) + stream.write(" color_policy=%d\n" % self._color_policy) + stream.write(" physical_pen_number=%d\n" % self.physical_pen_number) + stream.write(" virtual_pen_number=%d\n" % self.virtual_pen_number) + stream.write(" screen=%d\n" % self.screen) + stream.write(" linepattern_size=%s\n" % str(self.linepattern_size)) + stream.write(" linetype=%d\n" % self.linetype) + stream.write( + " adaptive_linetype=%s\n" % str(bool(self.adaptive_linetype)).upper() + ) + stream.write(" lineweight=%s\n" % str(self.lineweight)) + stream.write(" fill_style=%d\n" % self.fill_style) + stream.write(" end_style=%d\n" % self.end_style) + stream.write(" join_style=%d\n" % self.join_style) + stream.write(" }\n") + + +class PlotStyleTable: + """PlotStyle container""" + + def __init__( + self, + description: str = "", + scale_factor: float = 1.0, + apply_factor: bool = False, + ): + self.description = description + self.scale_factor = scale_factor + self.apply_factor = apply_factor + + # set custom_lineweight_display_units to 1 for showing lineweight in inch in + # AutoCAD CTB editor window, but lineweight is always defined in mm + self.custom_lineweight_display_units = 0 + self.lineweights = array("f", DEFAULT_LINE_WEIGHTS) + + def get_lineweight_index(self, lineweight: float) -> int: + """Get index of `lineweight` in the lineweight table or append + `lineweight` to lineweight table. + """ + try: + return self.lineweights.index(lineweight) + except ValueError: + self.lineweights.append(lineweight) + return len(self.lineweights) - 1 + + def set_table_lineweight(self, index: int, lineweight: float) -> int: + """Argument `index` is the lineweight table index, not the :ref:`ACI`. + + Args: + index: lineweight table index = :attr:`PlotStyle.lineweight` + lineweight: in millimeters + + """ + try: + self.lineweights[index] = lineweight + return index + except IndexError: + self.lineweights.append(lineweight) + return len(self.lineweights) - 1 + + def get_table_lineweight(self, index: int) -> float: + """Returns lineweight in millimeters of lineweight table entry `index`. + + Args: + index: lineweight table index = :attr:`PlotStyle.lineweight` + + Returns: + lineweight in mm or ``0.0`` for use entity lineweight + + """ + return self.lineweights[index] + + def save(self, filename: str | os.PathLike) -> None: + """Save CTB or STB file as `filename` to the file system.""" + with open(filename, "wb") as stream: + self.write(stream) + + def write(self, stream: BinaryIO) -> None: + """Compress and write the CTB or STB file to binary `stream`.""" + memfile = StringIO() + self.write_content(memfile) + memfile.write(chr(0)) # end of file + body = memfile.getvalue() + memfile.close() + _compress(stream, body) + + @abstractmethod + def write_content(self, stream: TextIO) -> None: + pass + + def _write_lineweights(self, stream: TextIO) -> None: + """Write custom lineweight table to text `stream`.""" + stream.write("custom_lineweight_table{\n") + for index, weight in enumerate(self.lineweights): + stream.write(" %d=%.2f\n" % (index, weight)) + stream.write("}\n") + + def parse(self, text: str) -> None: + """Parse plot styles from CTB string `text`.""" + + def set_lineweights(lineweights): + if lineweights is None: + return + self.lineweights = array("f", [0.0] * len(lineweights)) + for key, value in lineweights.items(): + self.lineweights[int(key)] = float(value) + + parser = PlotStyleFileParser(text) + self.description = parser.get("description", "") + self.scale_factor = float(parser.get("scale_factor", 1.0)) + self.apply_factor = get_bool(parser.get("apply_factor", True)) + self.custom_lineweight_display_units = int( + parser.get("custom_lineweight_display_units", 0) + ) + set_lineweights(parser.get("custom_lineweight_table", None)) + self.load_styles(parser.get("plot_style", {})) + + @abstractmethod + def load_styles(self, styles): + pass + + +class ColorDependentPlotStyles(PlotStyleTable): + def __init__( + self, + description: str = "", + scale_factor: float = 1.0, + apply_factor: bool = False, + ): + super().__init__(description, scale_factor, apply_factor) + self._styles: list[PlotStyle] = [ + PlotStyle(index, parent=self) for index in range(STYLE_COUNT) + ] + self._styles.insert( + 0, PlotStyle(256) + ) # 1-based array: insert dummy value for index 0 + + def __getitem__(self, aci: int) -> PlotStyle: + """Returns :class:`PlotStyle` for :ref:`ACI` `aci`.""" + if 0 < aci < 256: + return self._styles[aci] + else: + raise IndexError(aci) + + def __setitem__(self, aci: int, style: PlotStyle): + """Set plot `style` for `aci`.""" + if 0 < aci < 256: + style.parent = self + self._styles[aci] = style + else: + raise IndexError(aci) + + def __iter__(self): + """Iterable of all plot styles.""" + return iter(self._styles[1:]) + + def new_style(self, aci: int, data: Optional[dict] = None) -> PlotStyle: + """Set `aci` to new attributes defined by `data` dict. + + Args: + aci: :ref:`ACI` + data: ``dict`` of :class:`PlotStyle` attributes: description, color, + physical_pen_number, virtual_pen_number, screen, + linepattern_size, linetype, adaptive_linetype, + lineweight, end_style, join_style, fill_style + + """ + # ctb table index = aci - 1 + # ctb table starts with index 0, where aci == 0 means BYBLOCK + style = PlotStyle(index=aci - 1, data=data) + style.color_type = COLOR_RGB + self[aci] = style + return style + + def get_lineweight(self, aci: int): + """Returns the assigned lineweight for :class:`PlotStyle` `aci` in + millimeter. + """ + style = self[aci] + lineweight = style.get_lineweight() + if lineweight == 0.0: + return None + else: + return lineweight + + def write_content(self, stream: TextIO) -> None: + """Write the CTB-file to text `stream`.""" + self._write_header(stream) + self._write_aci_table(stream) + self._write_plot_styles(stream) + self._write_lineweights(stream) + + def _write_header(self, stream: TextIO) -> None: + """Write header values of CTB-file to text `stream`.""" + stream.write('description="%s\n' % self.description) + stream.write("aci_table_available=TRUE\n") + stream.write("scale_factor=%.1f\n" % self.scale_factor) + stream.write("apply_factor=%s\n" % str(self.apply_factor).upper()) + stream.write( + "custom_lineweight_display_units=%s\n" + % str(self.custom_lineweight_display_units) + ) + + def _write_aci_table(self, stream: TextIO) -> None: + """Write AutoCAD Color Index table to text `stream`.""" + stream.write("aci_table{\n") + for style in self: + index = style.index + stream.write(' %d="%s\n' % (index, color_name(index))) + stream.write("}\n") + + def _write_plot_styles(self, stream: TextIO) -> None: + """Write user styles to text `stream`.""" + stream.write("plot_style{\n") + for style in self: + style.write(stream) + stream.write("}\n") + + def load_styles(self, styles): + for index, style in styles.items(): + index = int(index) + style = PlotStyle(index, style) + style.color_type = COLOR_RGB + aci = index + 1 + self[aci] = style + + +class NamedPlotStyles(PlotStyleTable): + def __init__( + self, + description: str = "", + scale_factor: float = 1.0, + apply_factor: bool = False, + ): + super().__init__(description, scale_factor, apply_factor) + normal = PlotStyle( + 0, + data={ + "name": "Normal", + "localized_name": "Normal", + }, + ) + self._styles: dict[str, PlotStyle] = {"Normal": normal} + + def __iter__(self) -> Iterable[str]: + """Iterable of all plot style names.""" + return self.keys() + + def __getitem__(self, name: str) -> PlotStyle: + """Returns :class:`PlotStyle` by `name`.""" + return self._styles[name] + + def __delitem__(self, name: str) -> None: + """Delete plot style `name`. Plot style ``'Normal'`` is not deletable.""" + if name != "Normal": + del self._styles[name] + else: + raise ValueError("Can't delete plot style 'Normal'. ") + + def keys(self) -> Iterable[str]: + """Iterable of all plot style names.""" + keys = set(self._styles.keys()) + keys.discard("Normal") + result = ["Normal"] + result.extend(sorted(keys)) + return iter(result) + + def items(self) -> Iterator[tuple[str, PlotStyle]]: + """Iterable of all plot styles as (``name``, class:`PlotStyle`) tuples.""" + for key in self.keys(): + yield key, self._styles[key] + + def values(self) -> Iterable[PlotStyle]: + """Iterable of all class:`PlotStyle` objects.""" + for key, value in self.items(): + yield value + + def new_style( + self, + name: str, + data: Optional[dict] = None, + localized_name: Optional[str] = None, + ) -> PlotStyle: + """Create new class:`PlotStyle` `name` by attribute dict `data`, replaces + existing class:`PlotStyle` objects. + + Args: + name: plot style name + localized_name: name shown in plot style editor, uses `name` if ``None`` + data: ``dict`` of :class:`PlotStyle` attributes: description, color, + physical_pen_number, virtual_pen_number, screen, + linepattern_size, linetype, adaptive_linetype, lineweight, + end_style, join_style, fill_style + + """ + if name.lower() == "Normal": + raise ValueError("Can't replace or modify plot style 'Normal'. ") + data = data or {} + data["name"] = name + data["localized_name"] = localized_name or name + index = len(self._styles) + style = PlotStyle(index=index, data=data, parent=self) + style.color_type = COLOR_ACI + style.named_color = True + self._styles[name] = style + return style + + def get_lineweight(self, name: str): + """Returns the assigned lineweight for :class:`PlotStyle` `name` in + millimeter. + """ + style = self[name] + lineweight = style.get_lineweight() + if lineweight == 0.0: + return None + else: + return lineweight + + def write_content(self, stream: TextIO) -> None: + """Write the STB-file to text `stream`.""" + self._write_header(stream) + self._write_plot_styles(stream) + self._write_lineweights(stream) + + def _write_header(self, stream: TextIO) -> None: + """Write header values of CTB-file to text `stream`.""" + stream.write('description="%s\n' % self.description) + stream.write("aci_table_available=FALSE\n") + stream.write("scale_factor=%.1f\n" % self.scale_factor) + stream.write("apply_factor=%s\n" % str(self.apply_factor).upper()) + stream.write( + "custom_lineweight_display_units=%s\n" + % str(self.custom_lineweight_display_units) + ) + + def _write_plot_styles(self, stream: TextIO) -> None: + """Write user styles to text `stream`.""" + stream.write("plot_style{\n") + for index, style in enumerate(self.values()): + style.index = index + style.write(stream) + stream.write("}\n") + + def load_styles(self, styles): + for index, style in styles.items(): + index = int(index) + style = PlotStyle(index, style) + style.color_type = COLOR_ACI + self._styles[style.name] = style + + +def _read_ctb(stream: BinaryIO) -> ColorDependentPlotStyles: + """Read a CTB-file from binary `stream`.""" + content: bytes = _decompress(stream) + styles = ColorDependentPlotStyles() + styles.parse(content.decode()) + return styles + + +def _read_stb(stream: BinaryIO) -> NamedPlotStyles: + """Read a STB-file from binary `stream`.""" + content: bytes = _decompress(stream) + styles = NamedPlotStyles() + styles.parse(content.decode()) + return styles + + +def load( + filename: str | os.PathLike, +) -> Union[ColorDependentPlotStyles, NamedPlotStyles]: + """Load the CTB or STB file `filename` from file system.""" + filename = str(filename) + with open(filename, "rb") as stream: + if filename.lower().endswith(".ctb"): + return _read_ctb(stream) + elif filename.lower().endswith(".stb"): + return _read_stb(stream) + else: + raise ValueError('Invalid file type: "{}"'.format(filename)) + + +def new_ctb() -> ColorDependentPlotStyles: + """Create a new CTB file.""" + return ColorDependentPlotStyles() + + +def new_stb() -> NamedPlotStyles: + """Create a new STB file.""" + return NamedPlotStyles() + + +def _decompress(stream: BinaryIO) -> bytes: + """Read and decompress the file content from binray `stream`.""" + content = stream.read() + data = zlib.decompress(content[60:]) # type: bytes + return data[:-1] # truncate trailing \nul + + +def _compress(stream: BinaryIO, content: str): + """Compress `content` and write to binary `stream`.""" + comp_body = zlib.compress(content.encode()) + adler_chksum = zlib.adler32(comp_body) + stream.write(b"PIAFILEVERSION_2.0,CTBVER1,compress\r\npmzlibcodec") + stream.write(pack("LLL", adler_chksum, len(content), len(comp_body))) + stream.write(comp_body) + + +class PlotStyleFileParser: + """A very simple CTB/STB file parser. CTB/STB files are created by + applications, so the file structure should be correct in the most cases. + """ + + def __init__(self, text: str): + self.data = {} + for element, value in PlotStyleFileParser.iteritems(text): + self.data[element] = value + + @staticmethod + def iteritems(text: str): + """Iterate over all first level (start at col 0) elements.""" + line_index = 0 + + def get_name() -> str: + """Get element name of line .""" + line = lines[line_index] + if line.endswith("{"): # start of a list like 'plot_style{' + name = line[:-1] + else: # simple name=value line + name = line.split("=", 1)[0] + return name.strip() + + def get_mapping() -> dict: + """Get mapping of elements enclosed by { }. + + e. g. lineweights, plot_styles, aci_table + + """ + + def end_of_list(): + return lines[line_index].endswith("}") + + nonlocal line_index + data = dict() + while not end_of_list(): + name = get_name() + value = get_value() # get value or sub-list + data[name] = value + line_index += 1 + return data # skip '}' - end of list + + def get_value() -> Union[str, dict]: + """Get value of line or the list that starts in line + . + """ + nonlocal line_index + line = lines[line_index] + if line.endswith("{"): # start of a list + line_index += 1 + return get_mapping() + else: # it's a simple name=value line + value: str = line.split("=", 1)[1] + value = sanitized_value(value) + line_index += 1 + return value + + def skip_empty_lines(): + nonlocal line_index + while line_index < len(lines) and len(lines[line_index]) == 0: + line_index += 1 + + lines = text.split("\n") + while line_index < len(lines): + name = get_name() + value = get_value() + yield name, value + skip_empty_lines() + + def get(self, name: str, default: Any) -> Any: + return self.data.get(name, default) + + +def sanitized_value(value: str) -> str: + value = value.strip() + if value.startswith('"'): # strings: ="string + return value[1:] + + # remove unknown appendix like this: "0.0076200000000 (+7.Z+"8V?S_LC )" + # the pattern is " ()", see issue #1069 + if value.endswith(")"): + return value.split(" ")[0] + return value + + +def int2color(color: int) -> tuple[int, int, int, int]: + """Convert color integer value from CTB-file to ``(r, g, b, color_type) + tuple. + """ + # Take color from layer, ignore other bytes. + color_type = (color & 0xFF000000) >> 24 + red = (color & 0xFF0000) >> 16 + green = (color & 0xFF00) >> 8 + blue = color & 0xFF + return red, green, blue, color_type + + +def mode_color2int(red: int, green: int, blue: int, color_type=COLOR_RGB) -> int: + """Convert mode_color (r, g, b, color_type) tuple to integer.""" + return -color2int(red, green, blue, color_type) + + +def color2int(red: int, green: int, blue: int, color_type: int) -> int: + """Convert color (r, g, b, color_type) to integer.""" + return -((color_type << 24) + (red << 16) + (green << 8) + blue) & 0xFFFFFFFF diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__init__.py new file mode 100644 index 0000000..ce35acf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..246a8ec Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/browser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/browser.cpython-312.pyc new file mode 100644 index 0000000..8f291bb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/browser.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/data.cpython-312.pyc new file mode 100644 index 0000000..9f330ef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/__pycache__/data.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/browser.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/browser.py new file mode 100644 index 0000000..dad2e31 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/browser.py @@ -0,0 +1,297 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Iterable, Optional +import ezdxf +from ezdxf.addons.xqt import ( + QtWidgets, + QtGui, + QAction, + QMessageBox, + QFileDialog, + Qt, + QModelIndex, +) +from ezdxf.document import Drawing +from ezdxf.entities import Body +from ezdxf.lldxf.const import DXFStructureError +from .data import AcisData, BinaryAcisData, TextAcisData + + +APP_NAME = "ACIS Structure Browser" +BROWSER_WIDTH = 1024 +BROWSER_HEIGHT = 768 +SELECTOR_WIDTH_FACTOR = 0.20 +FONT_FAMILY = "monospaced" + + +def make_font(): + font = QtGui.QFont(FONT_FAMILY) + font.setStyleHint(QtGui.QFont.Monospace) + return font + + +class AcisStructureBrowser(QtWidgets.QMainWindow): + def __init__( + self, + filename: str = "", + handle: str = "", + ): + super().__init__() + self.doc: Optional[Drawing] = None + self.acis_entities: list[AcisData] = [] + self.current_acis_entity = AcisData() + self.entity_selector = self.make_entity_selector() + self.acis_content_viewer = self.make_content_viewer() + self.statusbar = QtWidgets.QStatusBar(self) + self.setup_actions() + self.setup_menu() + + if filename: + self.load_dxf(filename) + else: + self.setWindowTitle(APP_NAME) + + self.setStatusBar(self.statusbar) + self.setCentralWidget(self.make_central_widget()) + self.resize(BROWSER_WIDTH, BROWSER_HEIGHT) + self.connect_slots() + if handle: + try: + int(handle, 16) + except ValueError: + msg = f"Given handle is not a hex value: '{handle}'" + self.statusbar.showMessage(msg) + print(msg) + else: + if not self.goto_handle(handle): + msg = f"Handle '{handle}' not found." + self.statusbar.showMessage(msg) + print(msg) + + def make_entity_selector(self): + return QtWidgets.QListWidget(self) + + def make_content_viewer(self): + viewer = QtWidgets.QPlainTextEdit(self) + viewer.setReadOnly(True) + viewer.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap) + return viewer + + def make_central_widget(self): + container = QtWidgets.QSplitter(Qt.Horizontal) + container.addWidget(self.entity_selector) + container.addWidget(self.acis_content_viewer) + selector_width = int(BROWSER_WIDTH * SELECTOR_WIDTH_FACTOR) + entity_view_width = BROWSER_WIDTH - selector_width + container.setSizes([selector_width, entity_view_width]) + container.setCollapsible(0, False) + container.setCollapsible(1, False) + return container + + def connect_slots(self): + self.entity_selector.clicked.connect(self.acis_entity_activated) + self.entity_selector.activated.connect(self.acis_entity_activated) + + # noinspection PyAttributeOutsideInit + def setup_actions(self): + self._open_action = self.make_action( + "&Open DXF File...", self.open_dxf, shortcut="Ctrl+O" + ) + self._reload_action = self.make_action( + "Reload DXF File", + self.reload_dxf, + shortcut="Ctrl+R", + ) + self._export_entity_action = self.make_action( + "&Export Current Entity View...", + self.export_entity, + shortcut="Ctrl+E", + ) + self._export_raw_data_action = self.make_action( + "&Export Raw SAT/SAB Data...", + self.export_raw_entity, + shortcut="Ctrl+W", + ) + self._quit_action = self.make_action( + "&Quit", self.close, shortcut="Ctrl+Q" + ) + + def make_action( + self, + name, + slot, + *, + shortcut: str = "", + tip: str = "", + ) -> QAction: + action = QAction(name, self) + if shortcut: + action.setShortcut(shortcut) + if tip: + action.setToolTip(tip) + action.triggered.connect(slot) + return action + + def setup_menu(self): + menu = self.menuBar() + file_menu = menu.addMenu("&File") + file_menu.addAction(self._open_action) + file_menu.addAction(self._reload_action) + file_menu.addSeparator() + file_menu.addAction(self._export_entity_action) + file_menu.addAction(self._export_raw_data_action) + file_menu.addSeparator() + file_menu.addAction(self._quit_action) + + def open_dxf(self): + path, _ = QtWidgets.QFileDialog.getOpenFileName( + self, + caption="Select DXF file", + filter="DXF Documents (*.dxf *.DXF)", + ) + if path: + self.load_dxf(path) + + def load_dxf(self, path: str): + try: + doc = ezdxf.readfile(path) + except IOError as e: + QMessageBox.critical(self, "Loading Error", str(e)) + return + except DXFStructureError as e: + QMessageBox.critical( + self, + "DXF Structure Error", + f'Invalid DXF file "{path}": {str(e)}', + ) + return + entities = list(get_acis_entities(doc)) + if len(entities): + self.doc = doc + self.set_acis_entities(entities) + self.update_title(path) + self.statusbar.showMessage(self.make_loading_message()) + else: + msg = f"DXF file '{path}' contains no ACIS data" + QMessageBox.information(self, "Loading Error", msg) + + def make_loading_message(self) -> str: + assert self.doc is not None + dxfversion = self.doc.dxfversion + acis_type = "SAB" if dxfversion >= "AC1027" else "SAT" + return f"Loaded DXF file has version {self.doc.acad_release}/{dxfversion}" \ + f" and contains {acis_type} data" + + def set_acis_entities(self, entities: list[AcisData]): + self.acis_entities = entities + self.update_entity_selector(entities) + self.set_current_acis_entity(entities[0]) + + def reload_dxf(self): + try: + index = self.acis_entities.index(self.current_acis_entity) + except IndexError: + index = -1 + self.load_dxf(self.doc.filename) + if index > 0: + self.set_current_acis_entity(self.acis_entities[index]) + + def export_entity(self): + dxf_entity = self.get_current_dxf_entity() + if dxf_entity is None: + return + path, _ = QFileDialog.getSaveFileName( + self, + caption="Export Current Entity View", + dir=f"{dxf_entity.dxftype()}-{dxf_entity.dxf.handle}.txt", + filter="Text Files (*.txt *.TXT)", + ) + if path: + write_data(self.current_acis_entity, path) + + def export_raw_entity(self): + dxf_entity = self.get_current_dxf_entity() + if dxf_entity is None: + return + filename = f"{dxf_entity.dxftype()}-{dxf_entity.dxf.handle}" + sab = dxf_entity.has_binary_data + if sab: + filter_ = "Standard ACIS Binary Files (*.sab *.SAB)" + filename += ".sab" + else: + filter_ = "Standard ACIS Text Files (*.sat *.SAT)" + filename += ".sat" + + path, _ = QFileDialog.getSaveFileName( + self, + caption="Export ACIS Raw Data", + dir=filename, + filter=filter_, + ) + if path: + if sab: + with open(path, "wb") as fp: + fp.write(dxf_entity.sab) + else: + with open(path, "wt") as fp: + fp.write("\n".join(dxf_entity.sat)) + + def get_current_dxf_entity(self) -> Optional[Body]: + current = self.current_acis_entity + if not current.handle or self.doc is None: + return None + return self.doc.entitydb.get(current.handle) # type: ignore + + def update_title(self, path: str): + self.setWindowTitle(f"{APP_NAME} - {path}") + + def acis_entity_activated(self, index: QModelIndex): + if len(self.acis_entities) == 0: + return + try: + self.set_current_acis_entity(self.acis_entities[index.row()]) + except IndexError: + self.set_current_acis_entity(self.acis_entities[0]) + + def set_current_acis_entity(self, entity: AcisData): + if entity: + self.current_acis_entity = entity + self.update_acis_content_viewer(entity) + + def update_acis_content_viewer(self, entity: AcisData): + viewer = self.acis_content_viewer + viewer.clear() + viewer.setPlainText("\n".join(entity.lines)) + + def update_entity_selector(self, entities: Iterable[AcisData]): + viewer = self.entity_selector + viewer.clear() + viewer.addItems([e.name for e in entities]) + + def goto_handle(self, handle: str) -> bool: + for entity in self.acis_entities: + if entity.handle == handle: + self.set_current_acis_entity(entity) + return True + return False + + +def get_acis_entities(doc: Drawing) -> Iterator[AcisData]: + for e in doc.entitydb.values(): + if isinstance(e, Body): + handle = e.dxf.handle + name = f"<{handle}> {e.dxftype()}" + if e.has_binary_data: + yield BinaryAcisData(e.sab, name, handle) + else: + yield TextAcisData(e.sat, name, handle) + + +def write_data(entity: AcisData, path: str): + try: + with open(path, "wt") as fp: + fp.write("\n".join(entity.lines)) + except IOError: + pass + diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/data.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/data.py new file mode 100644 index 0000000..e26367f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/acisbrowser/data.py @@ -0,0 +1,60 @@ +# Copyright (c) 2022-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Sequence + +from ezdxf.acis.sat import parse_sat, SatEntity +from ezdxf.acis.sab import parse_sab, SabEntity + + +class AcisData: + def __init__(self, name: str = "unknown", handle: str = ""): + self.lines: list[str] = [] + self.name: str = name + self.handle: str = handle + + +class BinaryAcisData(AcisData): + def __init__(self, data: bytes, name: str, handle: str): + super().__init__(name, handle) + self.lines = list(make_sab_records(data)) + + +class TextAcisData(AcisData): + def __init__(self, data: Sequence[str], name: str, handle: str): + super().__init__(name, handle) + self.lines = list(make_sat_records(data)) + + +def ptr_str(e): + return "~" if e.is_null_ptr else str(e) + + +def make_sat_records(data: Sequence[str]) -> Iterator[str]: + builder = parse_sat(data) + yield from builder.header.dumps() + builder.reset_ids() + for entity in builder.entities: + content = [str(entity)] + content.append(ptr_str(entity.attributes)) + for field in entity.data: + if isinstance(field, SatEntity): + content.append(ptr_str(field)) + else: + content.append(field) + yield " ".join(content) + + +def make_sab_records(data: bytes) -> Iterator[str]: + builder = parse_sab(data) + yield from builder.header.dumps() + builder.reset_ids() + for entity in builder.entities: + content = [str(entity)] + content.append(ptr_str(entity.attributes)) + for tag in entity.data: + if isinstance(tag.value, SabEntity): + content.append(ptr_str(tag.value)) + else: + content.append(f"{tag.value}<{tag.tag}>") + yield " ".join(content) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/binpacking.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/binpacking.py new file mode 100644 index 0000000..438e4c1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/binpacking.py @@ -0,0 +1,716 @@ +# Source package: "py3dbp" hosted on PyPI +# (c) Enzo Ruiz Pelaez +# https://github.com/enzoruiz/3dbinpacking +# License: MIT License +# Credits: +# - https://github.com/enzoruiz/3dbinpacking/blob/master/erick_dube_507-034.pdf +# - https://github.com/gedex/bp3d - implementation in Go +# - https://github.com/bom-d-van/binpacking - implementation in Go +# +# ezdxf add-on: +# License: MIT License +# (c) 2022, Manfred Moitzi: +# - refactoring +# - type annotations +# - adaptations: +# - removing Decimal class usage +# - utilizing ezdxf.math.BoundingBox for intersection checks +# - removed non-distributing mode; copy packer and use different bins for each copy +# - additions: +# - Item.get_transformation() +# - shuffle_pack() +# - pack_item_subset() +# - DXF exporter for debugging +from __future__ import annotations +from typing import ( + Iterable, + TYPE_CHECKING, + TypeVar, + Optional, +) +from enum import Enum, auto +import copy +import math +import random + + +from ezdxf.enums import TextEntityAlignment +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + BoundingBox, + BoundingBox2d, + AbstractBoundingBox, + Matrix44, +) +from . import genetic_algorithm as ga + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +__all__ = [ + "Item", + "FlatItem", + "Box", # contains Item + "Envelope", # contains FlatItem + "AbstractPacker", + "Packer", + "FlatPacker", + "RotationType", + "PickStrategy", + "shuffle_pack", + "pack_item_subset", + "export_dxf", +] + +UNLIMITED_WEIGHT = 1e99 +T = TypeVar("T") +PI_2 = math.pi / 2 + + +class RotationType(Enum): + """Rotation type of an item: + + - W = width + - H = height + - D = depth + + """ + + WHD = auto() + HWD = auto() + HDW = auto() + DHW = auto() + DWH = auto() + WDH = auto() + + +class Axis(Enum): + WIDTH = auto() + HEIGHT = auto() + DEPTH = auto() + + +class PickStrategy(Enum): + """Order of how to pick items for placement.""" + + SMALLER_FIRST = auto() + BIGGER_FIRST = auto() + SHUFFLE = auto() + + +START_POSITION: tuple[float, float, float] = (0, 0, 0) + + +class Item: + """3D container item.""" + + def __init__( + self, + payload, + width: float, + height: float, + depth: float, + weight: float = 0.0, + ): + self.payload = payload # arbitrary associated Python object + self.width = float(width) + self.height = float(height) + self.depth = float(depth) + self.weight = float(weight) + self._rotation_type = RotationType.WHD + self._position = START_POSITION + self._bbox: Optional[AbstractBoundingBox] = None + + def __str__(self): + return ( + f"{str(self.payload)}({self.width}x{self.height}x{self.depth}, " + f"weight: {self.weight}) pos({str(self.position)}) " + f"rt({self.rotation_type}) vol({self.get_volume()})" + ) + + def copy(self): + """Returns a copy, all copies have a reference to the same payload + object. + """ + return copy.copy(self) # shallow copy + + @property + def bbox(self) -> AbstractBoundingBox: + if self._bbox is None: + self._update_bbox() + return self._bbox # type: ignore + + def _update_bbox(self) -> None: + v1 = Vec3(self._position) + self._bbox = BoundingBox([v1, v1 + Vec3(self.get_dimension())]) + + def _taint(self): + self._bbox = None + + @property + def rotation_type(self) -> RotationType: + return self._rotation_type + + @rotation_type.setter + def rotation_type(self, value: RotationType) -> None: + self._rotation_type = value + self._taint() + + @property + def position(self) -> tuple[float, float, float]: + """Returns the position of then lower left corner of the item in the + container, the lower left corner is the origin (0, 0, 0). + """ + return self._position + + @position.setter + def position(self, value: tuple[float, float, float]) -> None: + self._position = value + self._taint() + + def get_volume(self) -> float: + """Returns the volume of the item.""" + return self.width * self.height * self.depth + + def get_dimension(self) -> tuple[float, float, float]: + """Returns the item dimension according the :attr:`rotation_type`.""" + rt = self.rotation_type + if rt == RotationType.WHD: + return self.width, self.height, self.depth + elif rt == RotationType.HWD: + return self.height, self.width, self.depth + elif rt == RotationType.HDW: + return self.height, self.depth, self.width + elif rt == RotationType.DHW: + return self.depth, self.height, self.width + elif rt == RotationType.DWH: + return self.depth, self.width, self.height + elif rt == RotationType.WDH: + return self.width, self.depth, self.height + raise ValueError(rt) + + def get_transformation(self) -> Matrix44: + """Returns the transformation matrix to transform the source entity + located with the minimum extension corner of its bounding box in + (0, 0, 0) to the final location including the required rotation. + """ + x, y, z = self.position + rt = self.rotation_type + if rt == RotationType.WHD: # width, height, depth + return Matrix44.translate(x, y, z) + if rt == RotationType.HWD: # height, width, depth + return Matrix44.z_rotate(PI_2) @ Matrix44.translate( + x + self.height, y, z + ) + if rt == RotationType.HDW: # height, depth, width + return Matrix44.xyz_rotate(PI_2, 0, PI_2) @ Matrix44.translate( + x + self.height, y + self.depth, z + ) + if rt == RotationType.DHW: # depth, height, width + return Matrix44.y_rotate(-PI_2) @ Matrix44.translate( + x + self.depth, y, z + ) + if rt == RotationType.DWH: # depth, width, height + return Matrix44.xyz_rotate(0, PI_2, PI_2) @ Matrix44.translate( + x, y, z + ) + if rt == RotationType.WDH: # width, depth, height + return Matrix44.x_rotate(PI_2) @ Matrix44.translate( + x, y + self.depth, z + ) + raise TypeError(rt) + + +class FlatItem(Item): + """2D container item, inherited from :class:`Item`. Has a default depth of + 1.0. + """ + + def __init__( + self, + payload, + width: float, + height: float, + weight: float = 0.0, + ): + super().__init__(payload, width, height, 1.0, weight) + + def _update_bbox(self) -> None: + v1 = Vec2(self._position) + self._bbox = BoundingBox2d([v1, v1 + Vec2(self.get_dimension())]) + + def __str__(self): + return ( + f"{str(self.payload)}({self.width}x{self.height}, " + f"weight: {self.weight}) pos({str(self.position)}) " + f"rt({self.rotation_type}) area({self.get_volume()})" + ) + + +class Bin: + def __init__( + self, + name, + width: float, + height: float, + depth: float, + max_weight: float = UNLIMITED_WEIGHT, + ): + self.name = name + self.width = float(width) + if self.width <= 0.0: + raise ValueError("invalid width") + self.height = float(height) + if self.height <= 0.0: + raise ValueError("invalid height") + self.depth = float(depth) + if self.depth <= 0.0: + raise ValueError("invalid depth") + self.max_weight = float(max_weight) + self.items: list[Item] = [] + + def __len__(self): + return len(self.items) + + def __iter__(self): + return iter(self.items) + + def copy(self): + """Returns a copy.""" + box = copy.copy(self) # shallow copy + box.items = list(self.items) + return box + + def reset(self): + """Reset the container to empty state.""" + self.items.clear() + + @property + def is_empty(self) -> bool: + return not len(self.items) + + def __str__(self) -> str: + return ( + f"{str(self.name)}({self.width:.3f}x{self.height:.3f}x{self.depth:.3f}, " + f"max_weight:{self.max_weight}) " + f"vol({self.get_capacity():.3f})" + ) + + def put_item(self, item: Item, pivot: tuple[float, float, float]) -> bool: + valid_item_position = item.position + item.position = pivot + x, y, z = pivot + + # Try all possible rotations: + for rotation_type in self.rotations(): + item.rotation_type = rotation_type + w, h, d = item.get_dimension() + if self.width < x + w or self.height < y + h or self.depth < z + d: + continue + # new item fits inside the box at he current location and rotation: + item_bbox = item.bbox + if ( + not any(item_bbox.has_intersection(i.bbox) for i in self.items) + and self.get_total_weight() + item.weight <= self.max_weight + ): + self.items.append(item) + return True + + item.position = valid_item_position + return False + + def get_capacity(self) -> float: + """Returns the maximum fill volume of the bin.""" + return self.width * self.height * self.depth + + def get_total_weight(self) -> float: + """Returns the total weight of all fitted items.""" + return sum(item.weight for item in self.items) + + def get_total_volume(self) -> float: + """Returns the total volume of all fitted items.""" + return sum(item.get_volume() for item in self.items) + + def get_fill_ratio(self) -> float: + """Return the fill ratio.""" + try: + return self.get_total_volume() / self.get_capacity() + except ZeroDivisionError: + return 0.0 + + def rotations(self) -> Iterable[RotationType]: + return RotationType + + +class Box(Bin): + """3D container inherited from :class:`Bin`.""" + + pass + + +class Envelope(Bin): + """2D container inherited from :class:`Bin`.""" + + def __init__( + self, + name, + width: float, + height: float, + max_weight: float = UNLIMITED_WEIGHT, + ): + super().__init__(name, width, height, 1.0, max_weight) + + def __str__(self) -> str: + return ( + f"{str(self.name)}({self.width:.3f}x{self.height:.3f}, " + f"max_weight:{self.max_weight}) " + f"area({self.get_capacity():.3f})" + ) + + def rotations(self) -> Iterable[RotationType]: + return RotationType.WHD, RotationType.HWD + + +def _smaller_first(bins: list, items: list) -> None: + # SMALLER_FIRST is often very bad! Especially for many in small + # amounts increasing sizes. + bins.sort(key=lambda b: b.get_capacity()) + items.sort(key=lambda i: i.get_volume()) + + +def _bigger_first(bins: list, items: list) -> None: + # BIGGER_FIRST is the best strategy + bins.sort(key=lambda b: b.get_capacity(), reverse=True) + items.sort(key=lambda i: i.get_volume(), reverse=True) + + +def _shuffle(bins: list, items: list) -> None: + # Better as SMALLER_FIRST + random.shuffle(bins) + random.shuffle(items) + + +PICK_STRATEGY = { + PickStrategy.SMALLER_FIRST: _smaller_first, + PickStrategy.BIGGER_FIRST: _bigger_first, + PickStrategy.SHUFFLE: _shuffle, +} + + +class AbstractPacker: + def __init__(self) -> None: + self.bins: list[Bin] = [] + self.items: list[Item] = [] + self._init_state = True + + def copy(self): + """Copy packer in init state to apply different pack strategies.""" + if self.is_packed: + raise TypeError("cannot copy packed state") + if not all(box.is_empty for box in self.bins): + raise TypeError("bins contain data in unpacked state") + packer = self.__class__() + packer.bins = [box.copy() for box in self.bins] + packer.items = [item.copy() for item in self.items] + return packer + + @property + def is_packed(self) -> bool: + """Returns ``True`` if packer is packed, each packer can only be used + once. + """ + return not self._init_state + + @property + def unfitted_items(self) -> list[Item]: # just an alias + """Returns the unfitted items.""" + return self.items + + def __str__(self) -> str: + fill = "" + if self.is_packed: + fill = f", fill ratio: {self.get_fill_ratio()}" + return f"{self.__class__.__name__}, {len(self.bins)} bins{fill}" + + def append_bin(self, box: Bin) -> None: + """Append a container.""" + if self.is_packed: + raise TypeError("cannot append bins to packed state") + if not box.is_empty: + raise TypeError("cannot append bins with content") + self.bins.append(box) + + def append_item(self, item: Item) -> None: + """Append a item.""" + if self.is_packed: + raise TypeError("cannot append items to packed state") + self.items.append(item) + + def get_fill_ratio(self) -> float: + """Return the fill ratio of all bins.""" + total_capacity = self.get_capacity() + if total_capacity == 0.0: + return 0.0 + return self.get_total_volume() / total_capacity + + def get_capacity(self) -> float: + """Returns the maximum fill volume of all bins.""" + return sum(box.get_capacity() for box in self.bins) + + def get_total_weight(self) -> float: + """Returns the total weight of all fitted items in all bins.""" + return sum(box.get_total_weight() for box in self.bins) + + def get_total_volume(self) -> float: + """Returns the total volume of all fitted items in all bins.""" + return sum(box.get_total_volume() for box in self.bins) + + def get_unfitted_volume(self) -> float: + """Returns the total volume of all unfitted items.""" + return sum(item.get_volume() for item in self.items) + + def pack(self, pick=PickStrategy.BIGGER_FIRST) -> None: + """Pack items into bins. Distributes all items across all bins.""" + PICK_STRATEGY[pick](self.bins, self.items) + # items are removed from self.items while packing! + self._pack(self.bins, list(self.items)) + # unfitted items remain in self.items + + def _pack(self, bins: Iterable[Bin], items: Iterable[Item]) -> None: + """Pack items into bins, removes packed items from self.items!""" + self._init_state = False + for box in bins: + for item in items: + if self.pack_to_bin(box, item): + self.items.remove(item) + # unfitted items remain in self.items + + def pack_to_bin(self, box: Bin, item: Item) -> bool: + if not box.items: + return box.put_item(item, START_POSITION) + + for axis in self._axis(): + for placed_item in box.items: + w, h, d = placed_item.get_dimension() + x, y, z = placed_item.position + if axis == Axis.WIDTH: + pivot = (x + w, y, z) # new item right of the placed item + elif axis == Axis.HEIGHT: + pivot = (x, y + h, z) # new item above of the placed item + elif axis == Axis.DEPTH: + pivot = (x, y, z + d) # new item on top of the placed item + else: + raise TypeError(axis) + if box.put_item(item, pivot): + return True + return False + + @staticmethod + def _axis() -> Iterable[Axis]: + return Axis + + +def shuffle_pack(packer: AbstractPacker, attempts: int) -> AbstractPacker: + """Random shuffle packing. Returns a new packer with the best packing result, + the input packer is unchanged. + """ + if attempts < 1: + raise ValueError("expected attempts >= 1") + best_ratio = 0.0 + best_packer = packer + for _ in range(attempts): + new_packer = packer.copy() + new_packer.pack(PickStrategy.SHUFFLE) + new_ratio = new_packer.get_fill_ratio() + if new_ratio > best_ratio: + best_ratio = new_ratio + best_packer = new_packer + return best_packer + + +def pack_item_subset( + packer: AbstractPacker, picker: Iterable, strategy=PickStrategy.BIGGER_FIRST +) -> None: + """Pack a subset of `packer.items`, which are chosen by an iterable + yielding a True or False value for each item. + """ + assert packer.is_packed is False + chosen, rejects = get_item_subset(packer.items, picker) + packer.items = chosen + packer.pack(strategy) # unfitted items remain in packer.items + packer.items.extend(rejects) # append rejects as unfitted items + + +def get_item_subset( + items: list[Item], picker: Iterable +) -> tuple[list[Item], list[Item]]: + """Returns a subset of `items`, where items are chosen by an iterable + yielding a True or False value for each item. + """ + chosen: list[Item] = [] + rejects: list[Item] = [] + count = 0 + for item, pick in zip(items, picker): + count += 1 + if pick: + chosen.append(item) + else: + rejects.append(item) + + if count < len(items): # too few pick values given + rejects.extend(items[count:]) + return chosen, rejects + + +class SubSetEvaluator(ga.Evaluator): + def __init__(self, packer: AbstractPacker): + self.packer = packer + + def evaluate(self, dna: ga.DNA) -> float: + packer = self.run_packer(dna) + return packer.get_fill_ratio() + + def run_packer(self, dna: ga.DNA) -> AbstractPacker: + packer = self.packer.copy() + pack_item_subset(packer, dna) + return packer + + +class Packer(AbstractPacker): + """3D Packer inherited from :class:`AbstractPacker`.""" + + def add_bin( + self, + name: str, + width: float, + height: float, + depth: float, + max_weight: float = UNLIMITED_WEIGHT, + ) -> Box: + """Add a 3D :class:`Box` container.""" + box = Box(name, width, height, depth, max_weight) + self.append_bin(box) + return box + + def add_item( + self, + payload, + width: float, + height: float, + depth: float, + weight: float = 0.0, + ) -> Item: + """Add a 3D :class:`Item` to pack.""" + item = Item(payload, width, height, depth, weight) + self.append_item(item) + return item + + +class FlatPacker(AbstractPacker): + """2D Packer inherited from :class:`AbstractPacker`. All containers and + items used by this packer must have a depth of 1.""" + + def add_bin( + self, + name: str, + width: float, + height: float, + max_weight: float = UNLIMITED_WEIGHT, + ) -> Envelope: + """Add a 2D :class:`Envelope` container.""" + envelope = Envelope(name, width, height, max_weight) + self.append_bin(envelope) + return envelope + + def add_item( + self, + payload, + width: float, + height: float, + weight: float = 0.0, + ) -> Item: + """Add a 2D :class:`FlatItem` to pack.""" + item = FlatItem(payload, width, height, weight) + self.append_item(item) + return item + + @staticmethod + def _axis() -> Iterable[Axis]: + return Axis.WIDTH, Axis.HEIGHT + + +def export_dxf( + layout: "GenericLayoutType", bins: list[Bin], offset: UVec = (1, 0, 0) +) -> None: + from ezdxf import colors + + offset_vec = Vec3(offset) + start = Vec3() + index = 0 + rgb = (colors.RED, colors.GREEN, colors.BLUE, colors.MAGENTA, colors.CYAN) + for box in bins: + m = Matrix44.translate(start.x, start.y, start.z) + _add_frame(layout, box, "FRAME", m) + for item in box.items: + _add_mesh(layout, item, "ITEMS", rgb[index], m) + index += 1 + if index >= len(rgb): + index = 0 + start += offset_vec + + +def _add_frame(layout: "GenericLayoutType", box: Bin, layer: str, m: Matrix44): + def add_line(v1, v2): + line = layout.add_line(v1, v2, dxfattribs=attribs) + line.transform(m) + + attribs = {"layer": layer} + x0, y0, z0 = (0.0, 0.0, 0.0) + x1 = float(box.width) + y1 = float(box.height) + z1 = float(box.depth) + corners = [ + (x0, y0), + (x1, y0), + (x1, y1), + (x0, y1), + (x0, y0), + ] + for (sx, sy), (ex, ey) in zip(corners, corners[1:]): + add_line((sx, sy, z0), (ex, ey, z0)) + add_line((sx, sy, z1), (ex, ey, z1)) + for x, y in corners[:-1]: + add_line((x, y, z0), (x, y, z1)) + + text = layout.add_text(box.name, height=0.25, dxfattribs=attribs) + text.set_placement((x0 + 0.25, y1 - 0.5, z1)) + text.transform(m) + + +def _add_mesh( + layout: "GenericLayoutType", item: Item, layer: str, color: int, m: Matrix44 +): + from ezdxf.render.forms import cube + + attribs = { + "layer": layer, + "color": color, + } + mesh = cube(center=False) + sx, sy, sz = item.get_dimension() + mesh.scale(sx, sy, sz) + x, y, z = item.position + mesh.translate(x, y, z) + mesh.render_polyface(layout, attribs, matrix=m) + text = layout.add_text( + str(item.payload), height=0.25, dxfattribs={"layer": "TEXT"} + ) + if sy > sx: + text.dxf.rotation = 90 + align = TextEntityAlignment.TOP_LEFT + else: + align = TextEntityAlignment.BOTTOM_LEFT + text.set_placement((x + 0.25, y + 0.25, z + sz), align=align) + text.transform(m) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__init__.py new file mode 100644 index 0000000..332e3f3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +from .data import * +from .model import * +from .browser import * + diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..a1cd7b3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/bookmarks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/bookmarks.cpython-312.pyc new file mode 100644 index 0000000..2c5beb2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/bookmarks.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/browser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/browser.cpython-312.pyc new file mode 100644 index 0000000..346bcc8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/browser.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/data.cpython-312.pyc new file mode 100644 index 0000000..d6733c7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/data.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/find_dialog.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/find_dialog.cpython-312.pyc new file mode 100644 index 0000000..67582db Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/find_dialog.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/loader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/loader.cpython-312.pyc new file mode 100644 index 0000000..cb56ffc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/loader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/model.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/model.cpython-312.pyc new file mode 100644 index 0000000..ba44d89 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/model.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/reflinks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/reflinks.cpython-312.pyc new file mode 100644 index 0000000..1090036 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/reflinks.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/tags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/tags.cpython-312.pyc new file mode 100644 index 0000000..89334b1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/tags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/views.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000..82a226b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/__pycache__/views.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/bookmarks.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/bookmarks.py new file mode 100644 index 0000000..015da8e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/bookmarks.py @@ -0,0 +1,33 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import NamedTuple, Optional + + +class Bookmark(NamedTuple): + name: str + handle: str + offset: int + + +class Bookmarks: + def __init__(self) -> None: + self.bookmarks: dict[str, Bookmark] = dict() + + def add(self, name: str, handle: str, offset: int): + self.bookmarks[name] = Bookmark(name, handle, offset) + + def get(self, name: str) -> Optional[Bookmark]: + return self.bookmarks.get(name) + + def names(self) -> list[str]: + return list(self.bookmarks.keys()) + + def discard(self, name: str): + try: + del self.bookmarks[name] + except KeyError: + pass + + def clear(self): + self.bookmarks.clear() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/browser.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/browser.py new file mode 100644 index 0000000..56afe9a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/browser.py @@ -0,0 +1,796 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Optional, Set +from functools import partial +from pathlib import Path +import subprocess +import shlex + +from ezdxf.addons.xqt import ( + QtWidgets, + QtGui, + QAction, + QMessageBox, + QFileDialog, + QInputDialog, + Qt, + QModelIndex, + QSettings, + QFileSystemWatcher, + QSize, +) + +import ezdxf +from ezdxf.lldxf.const import DXFStructureError, DXFValueError +from ezdxf.lldxf.types import DXFTag, is_pointer_code +from ezdxf.lldxf.tags import Tags +from ezdxf.addons.browser.reflinks import get_reference_link + +from .model import ( + DXFStructureModel, + DXFTagsModel, + DXFTagsRole, +) +from .data import ( + DXFDocument, + get_row_from_line_number, + dxfstr, + EntityHistory, + SearchIndex, +) +from .views import StructureTree, DXFTagsTable +from .find_dialog import Ui_FindDialog +from .bookmarks import Bookmarks + +__all__ = ["DXFStructureBrowser"] + +APP_NAME = "DXF Structure Browser" +BROWSE_COMMAND = ezdxf.options.BROWSE_COMMAND +TEXT_EDITOR = ezdxf.options.get(BROWSE_COMMAND, "TEXT_EDITOR") +ICON_SIZE = max(16, ezdxf.options.get_int(BROWSE_COMMAND, "ICON_SIZE")) + +SearchSections = Set[str] + + +def searchable_entities( + doc: DXFDocument, search_sections: SearchSections +) -> list[Tags]: + entities: list[Tags] = [] + for name, section_entities in doc.sections.items(): + if name in search_sections: + entities.extend(section_entities) # type: ignore + return entities + + +BROWSER_WIDTH = 1024 +BROWSER_HEIGHT = 768 +TREE_WIDTH_FACTOR = 0.33 + + +class DXFStructureBrowser(QtWidgets.QMainWindow): + def __init__( + self, + filename: str = "", + line: Optional[int] = None, + handle: Optional[str] = None, + resource_path: Path = Path("."), + ): + super().__init__() + self.doc = DXFDocument() + self.resource_path = resource_path + self._structure_tree = StructureTree() + self._dxf_tags_table = DXFTagsTable() + self._current_entity: Optional[Tags] = None + self._active_search: Optional[SearchIndex] = None + self._search_sections: set[str] = set() + self._find_dialog: FindDialog = self.create_find_dialog() + self._file_watcher = QFileSystemWatcher() + self._exclusive_reload_dialog = True # see ask_for_reloading() method + self.history = EntityHistory() + self.bookmarks = Bookmarks() + self.setup_actions() + self.setup_menu() + self.setup_toolbar() + + if filename: + self.load_dxf(filename) + else: + self.setWindowTitle(APP_NAME) + + self.setCentralWidget(self.build_central_widget()) + self.resize(BROWSER_WIDTH, BROWSER_HEIGHT) + self.connect_slots() + if line is not None: + try: + line = int(line) + except ValueError: + print(f"Invalid line number: {line}") + else: + self.goto_line(line) + if handle is not None: + try: + int(handle, 16) + except ValueError: + print(f"Given handle is not a hex value: {handle}") + else: + if not self.goto_handle(handle): + print(f"Handle {handle} not found.") + + def build_central_widget(self): + container = QtWidgets.QSplitter(Qt.Horizontal) + container.addWidget(self._structure_tree) + container.addWidget(self._dxf_tags_table) + tree_width = int(BROWSER_WIDTH * TREE_WIDTH_FACTOR) + table_width = BROWSER_WIDTH - tree_width + container.setSizes([tree_width, table_width]) + container.setCollapsible(0, False) + container.setCollapsible(1, False) + return container + + def connect_slots(self): + self._structure_tree.activated.connect(self.entity_activated) + self._dxf_tags_table.activated.connect(self.tag_activated) + # noinspection PyUnresolvedReferences + self._file_watcher.fileChanged.connect(self.ask_for_reloading) + + # noinspection PyAttributeOutsideInit + def setup_actions(self): + + self._open_action = self.make_action( + "&Open DXF File...", self.open_dxf, shortcut="Ctrl+O" + ) + self._export_entity_action = self.make_action( + "&Export DXF Entity...", self.export_entity, shortcut="Ctrl+E" + ) + self._copy_entity_action = self.make_action( + "&Copy DXF Entity to Clipboard", + self.copy_entity, + shortcut="Shift+Ctrl+C", + icon_name="icon-copy-64px.png", + ) + self._copy_selected_tags_action = self.make_action( + "&Copy selected DXF Tags to Clipboard", + self.copy_selected_tags, + shortcut="Ctrl+C", + icon_name="icon-copy-64px.png", + ) + self._quit_action = self.make_action( + "&Quit", self.close, shortcut="Ctrl+Q" + ) + self._goto_handle_action = self.make_action( + "&Go to Handle...", + self.ask_for_handle, + shortcut="Ctrl+G", + icon_name="icon-goto-handle-64px.png", + tip="Go to Entity Handle", + ) + self._goto_line_action = self.make_action( + "Go to &Line...", + self.ask_for_line_number, + shortcut="Ctrl+L", + icon_name="icon-goto-line-64px.png", + tip="Go to Line Number", + ) + + self._find_text_action = self.make_action( + "Find &Text...", + self.find_text, + shortcut="Ctrl+F", + icon_name="icon-find-64px.png", + tip="Find Text in Entities", + ) + self._goto_predecessor_entity_action = self.make_action( + "&Previous Entity", + self.goto_previous_entity, + shortcut="Ctrl+Left", + icon_name="icon-prev-entity-64px.png", + tip="Go to Previous Entity in File Order", + ) + + self._goto_next_entity_action = self.make_action( + "&Next Entity", + self.goto_next_entity, + shortcut="Ctrl+Right", + icon_name="icon-next-entity-64px.png", + tip="Go to Next Entity in File Order", + ) + self._entity_history_back_action = self.make_action( + "Entity History &Back", + self.go_back_entity_history, + shortcut="Alt+Left", + icon_name="icon-left-arrow-64px.png", + tip="Go to Previous Entity in Browser History", + ) + self._entity_history_forward_action = self.make_action( + "Entity History &Forward", + self.go_forward_entity_history, + shortcut="Alt+Right", + icon_name="icon-right-arrow-64px.png", + tip="Go to Next Entity in Browser History", + ) + self._open_entity_in_text_editor_action = self.make_action( + "&Open in Text Editor", + self.open_entity_in_text_editor, + shortcut="Ctrl+T", + ) + self._show_entity_in_tree_view_action = self.make_action( + "Show Entity in Structure &Tree", + self.show_current_entity_in_tree_view, + shortcut="Ctrl+Down", + icon_name="icon-show-in-tree-64px.png", + tip="Show Current Entity in Structure Tree", + ) + self._goto_header_action = self.make_action( + "Go to HEADER Section", + partial(self.go_to_section, name="HEADER"), + shortcut="Shift+H", + ) + self._goto_blocks_action = self.make_action( + "Go to BLOCKS Section", + partial(self.go_to_section, name="BLOCKS"), + shortcut="Shift+B", + ) + self._goto_entities_action = self.make_action( + "Go to ENTITIES Section", + partial(self.go_to_section, name="ENTITIES"), + shortcut="Shift+E", + ) + self._goto_objects_action = self.make_action( + "Go to OBJECTS Section", + partial(self.go_to_section, name="OBJECTS"), + shortcut="Shift+O", + ) + self._store_bookmark = self.make_action( + "Store Bookmark...", + self.store_bookmark, + shortcut="Shift+Ctrl+B", + icon_name="icon-store-bookmark-64px.png", + ) + self._go_to_bookmark = self.make_action( + "Go to Bookmark...", + self.go_to_bookmark, + shortcut="Ctrl+B", + icon_name="icon-goto-bookmark-64px.png", + ) + self._reload_action = self.make_action( + "Reload DXF File", + self.reload_dxf, + shortcut="Ctrl+R", + ) + + def make_action( + self, + name, + slot, + *, + shortcut: str = "", + icon_name: str = "", + tip: str = "", + ) -> QAction: + action = QAction(name, self) + if shortcut: + action.setShortcut(shortcut) + if icon_name: + icon = QtGui.QIcon(str(self.resource_path / icon_name)) + action.setIcon(icon) + if tip: + action.setToolTip(tip) + action.triggered.connect(slot) + return action + + def setup_menu(self): + menu = self.menuBar() + file_menu = menu.addMenu("&File") + file_menu.addAction(self._open_action) + file_menu.addAction(self._reload_action) + file_menu.addAction(self._open_entity_in_text_editor_action) + file_menu.addSeparator() + file_menu.addAction(self._copy_selected_tags_action) + file_menu.addAction(self._copy_entity_action) + file_menu.addAction(self._export_entity_action) + file_menu.addSeparator() + file_menu.addAction(self._quit_action) + + navigate_menu = menu.addMenu("&Navigate") + navigate_menu.addAction(self._goto_handle_action) + navigate_menu.addAction(self._goto_line_action) + navigate_menu.addAction(self._find_text_action) + navigate_menu.addSeparator() + navigate_menu.addAction(self._goto_next_entity_action) + navigate_menu.addAction(self._goto_predecessor_entity_action) + navigate_menu.addAction(self._show_entity_in_tree_view_action) + navigate_menu.addSeparator() + navigate_menu.addAction(self._entity_history_back_action) + navigate_menu.addAction(self._entity_history_forward_action) + navigate_menu.addSeparator() + navigate_menu.addAction(self._goto_header_action) + navigate_menu.addAction(self._goto_blocks_action) + navigate_menu.addAction(self._goto_entities_action) + navigate_menu.addAction(self._goto_objects_action) + + bookmarks_menu = menu.addMenu("&Bookmarks") + bookmarks_menu.addAction(self._store_bookmark) + bookmarks_menu.addAction(self._go_to_bookmark) + + def setup_toolbar(self) -> None: + toolbar = QtWidgets.QToolBar("MainToolbar") + toolbar.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) + toolbar.addAction(self._entity_history_back_action) + toolbar.addAction(self._entity_history_forward_action) + toolbar.addAction(self._goto_predecessor_entity_action) + toolbar.addAction(self._goto_next_entity_action) + toolbar.addAction(self._show_entity_in_tree_view_action) + toolbar.addAction(self._find_text_action) + toolbar.addAction(self._goto_line_action) + toolbar.addAction(self._goto_handle_action) + toolbar.addAction(self._store_bookmark) + toolbar.addAction(self._go_to_bookmark) + toolbar.addAction(self._copy_selected_tags_action) + self.addToolBar(toolbar) + + def create_find_dialog(self) -> "FindDialog": + dialog = FindDialog() + dialog.setModal(True) + dialog.find_forward_button.clicked.connect(self.find_forward) + dialog.find_backwards_button.clicked.connect(self.find_backwards) + dialog.find_forward_button.setShortcut("F3") + dialog.find_backwards_button.setShortcut("F4") + return dialog + + def open_dxf(self): + path, _ = QtWidgets.QFileDialog.getOpenFileName( + self, + caption="Select DXF file", + filter="DXF Documents (*.dxf *.DXF)", + ) + if path: + self.load_dxf(path) + + def load_dxf(self, path: str): + try: + self._load(path) + except IOError as e: + QMessageBox.critical(self, "Loading Error", str(e)) + except DXFStructureError as e: + QMessageBox.critical( + self, + "DXF Structure Error", + f'Invalid DXF file "{path}": {str(e)}', + ) + else: + self.history.clear() + self.view_header_section() + self.update_title() + + def reload_dxf(self): + if self._current_entity is not None: + entity = self.get_current_entity() + handle = self.get_current_entity_handle() + first_row = self._dxf_tags_table.first_selected_row() + line_number = self.doc.get_line_number(entity, first_row) + + self._load(self.doc.filename) + if handle is not None: + entity = self.doc.get_entity(handle) + if entity is not None: # select entity with same handle + self.set_current_entity_and_row_index(entity, first_row) + self._structure_tree.expand_to_entity(entity) + return + # select entity at the same line number + entity = self.doc.get_entity_at_line(line_number) + self.set_current_entity_and_row_index(entity, first_row) + self._structure_tree.expand_to_entity(entity) + + def ask_for_reloading(self): + if self.doc.filename and self._exclusive_reload_dialog: + # Ignore further reload signals until first signal is processed. + # Saving files by ezdxf triggers two "fileChanged" signals!? + self._exclusive_reload_dialog = False + ok = QMessageBox.question( + self, + "Reload", + f'"{self.doc.absolute_filepath()}"\n\nThis file has been ' + f"modified by another program, reload file?", + buttons=QMessageBox.Yes | QMessageBox.No, + defaultButton=QMessageBox.Yes, + ) + if ok == QMessageBox.Yes: + self.reload_dxf() + self._exclusive_reload_dialog = True + + def _load(self, filename: str): + if self.doc.filename: + self._file_watcher.removePath(self.doc.filename) + self.doc.load(filename) + model = DXFStructureModel(self.doc.filepath.name, self.doc) + self._structure_tree.set_structure(model) + self.history.clear() + self._file_watcher.addPath(self.doc.filename) + + def export_entity(self): + if self._dxf_tags_table is None: + return + path, _ = QFileDialog.getSaveFileName( + self, + caption="Export DXF Entity", + filter="Text Files (*.txt *.TXT)", + ) + if path: + model = self._dxf_tags_table.model() + tags = model.compiled_tags() + self.export_tags(path, tags) + + def copy_entity(self): + if self._dxf_tags_table is None: + return + model = self._dxf_tags_table.model() + tags = model.compiled_tags() + copy_dxf_to_clipboard(tags) + + def copy_selected_tags(self): + if self._current_entity is None: + return + rows = self._dxf_tags_table.selected_rows() + model = self._dxf_tags_table.model() + tags = model.compiled_tags() + try: + export_tags = Tags(tags[row] for row in rows) + except IndexError: + return + copy_dxf_to_clipboard(export_tags) + + def view_header_section(self): + header = self.doc.get_section("HEADER") + if header: + self.set_current_entity_with_history(header[0]) + else: # DXF R12 with only a ENTITIES section + entities = self.doc.get_section("ENTITIES") + if entities: + self.set_current_entity_with_history(entities[1]) + + def update_title(self): + self.setWindowTitle(f"{APP_NAME} - {self.doc.absolute_filepath()}") + + def get_current_entity_handle(self) -> Optional[str]: + active_entity = self.get_current_entity() + if active_entity: + try: + return active_entity.get_handle() + except DXFValueError: + pass + return None + + def get_current_entity(self) -> Optional[Tags]: + return self._current_entity + + def set_current_entity_by_handle(self, handle: str): + entity = self.doc.get_entity(handle) + if entity: + self.set_current_entity(entity) + + def set_current_entity( + self, entity: Tags, select_line_number: Optional[int] = None + ): + if entity: + self._current_entity = entity + start_line_number = self.doc.get_line_number(entity) + model = DXFTagsModel( + entity, start_line_number, self.doc.entity_index + ) + self._dxf_tags_table.setModel(model) + if select_line_number is not None: + row = get_row_from_line_number( + model.compiled_tags(), start_line_number, select_line_number + ) + self._dxf_tags_table.selectRow(row) + index = self._dxf_tags_table.model().index(row, 0) + self._dxf_tags_table.scrollTo(index) + + def set_current_entity_with_history(self, entity: Tags): + self.set_current_entity(entity) + self.history.append(entity) + + def set_current_entity_and_row_index(self, entity: Tags, index: int): + line = self.doc.get_line_number(entity, index) + self.set_current_entity(entity, select_line_number=line) + self.history.append(entity) + + def entity_activated(self, index: QModelIndex): + tags = index.data(role=DXFTagsRole) + # PySide6: Tags() are converted to type list by PySide6? + # print(type(tags)) + if isinstance(tags, (Tags, list)): + self.set_current_entity_with_history(Tags(tags)) + + def tag_activated(self, index: QModelIndex): + tag = index.data(role=DXFTagsRole) + if isinstance(tag, DXFTag): + code, value = tag + if is_pointer_code(code): + if not self.goto_handle(value): + self.show_error_handle_not_found(value) + elif code == 0: + self.open_web_browser(get_reference_link(value)) + + def ask_for_handle(self): + handle, ok = QInputDialog.getText( + self, + "Go to", + "Go to entity handle:", + ) + if ok: + if not self.goto_handle(handle): + self.show_error_handle_not_found(handle) + + def goto_handle(self, handle: str) -> bool: + entity = self.doc.get_entity(handle) + if entity: + self.set_current_entity_with_history(entity) + return True + return False + + def show_error_handle_not_found(self, handle: str): + QMessageBox.critical(self, "Error", f"Handle {handle} not found!") + + def ask_for_line_number(self): + max_line_number = self.doc.max_line_number + number, ok = QInputDialog.getInt( + self, + "Go to", + f"Go to line number: (max. {max_line_number})", + 1, # value + 1, # PyQt5: min, PySide6: minValue + max_line_number, # PyQt5: max, PySide6: maxValue + ) + if ok: + self.goto_line(number) + + def goto_line(self, number: int) -> bool: + entity = self.doc.get_entity_at_line(int(number)) + if entity: + self.set_current_entity(entity, number) + return True + return False + + def find_text(self): + self._active_search = None + dialog = self._find_dialog + dialog.restore_geometry() + dialog.show_message("F3 searches forward, F4 searches backwards") + dialog.find_text_edit.setFocus() + dialog.show() + + def update_search(self): + def setup_search(): + self._search_sections = dialog.search_sections() + entities = searchable_entities(self.doc, self._search_sections) + self._active_search = SearchIndex(entities) + + dialog = self._find_dialog + if self._active_search is None: + setup_search() + # noinspection PyUnresolvedReferences + self._active_search.set_current_entity(self._current_entity) + else: + search_sections = dialog.search_sections() + if search_sections != self._search_sections: + setup_search() + dialog.update_options(self._active_search) + + def find_forward(self): + self._find(backward=False) + + def find_backwards(self): + self._find(backward=True) + + def _find(self, backward=False): + if self._find_dialog.isVisible(): + self.update_search() + search = self._active_search + if search.is_end_of_index: + search.reset_cursor(backward=backward) + + entity, index = ( + search.find_backwards() if backward else search.find_forward() + ) + + if entity: + self.set_current_entity_and_row_index(entity, index) + self.show_entity_found_message(entity, index) + else: + if search.is_end_of_index: + self.show_message("Not found and end of file!") + else: + self.show_message("Not found!") + + def show_message(self, msg: str): + self._find_dialog.show_message(msg) + + def show_entity_found_message(self, entity: Tags, index: int): + dxftype = entity.dxftype() + if dxftype == "SECTION": + tail = " @ {0} Section".format(entity.get_first_value(2)) + else: + try: + handle = entity.get_handle() + tail = f" @ {dxftype}(#{handle})" + except ValueError: + tail = "" + line = self.doc.get_line_number(entity, index) + self.show_message(f"Found in Line: {line}{tail}") + + def export_tags(self, filename: str, tags: Tags): + try: + with open(filename, "wt", encoding="utf8") as fp: + fp.write(dxfstr(tags)) + except IOError as e: + QMessageBox.critical(self, "IOError", str(e)) + + def goto_next_entity(self): + if self._dxf_tags_table: + current_entity = self.get_current_entity() + if current_entity is not None: + next_entity = self.doc.next_entity(current_entity) + if next_entity is not None: + self.set_current_entity_with_history(next_entity) + + def goto_previous_entity(self): + if self._dxf_tags_table: + current_entity = self.get_current_entity() + if current_entity is not None: + prev_entity = self.doc.previous_entity(current_entity) + if prev_entity is not None: + self.set_current_entity_with_history(prev_entity) + + def go_back_entity_history(self): + entity = self.history.back() + if entity is not None: + self.set_current_entity(entity) # do not change history + + def go_forward_entity_history(self): + entity = self.history.forward() + if entity is not None: + self.set_current_entity(entity) # do not change history + + def go_to_section(self, name: str): + section = self.doc.get_section(name) + if section: + index = 0 if name == "HEADER" else 1 + self.set_current_entity_with_history(section[index]) + + def open_entity_in_text_editor(self): + current_entity = self.get_current_entity() + line_number = self.doc.get_line_number(current_entity) + if self._dxf_tags_table: + indices = self._dxf_tags_table.selectedIndexes() + if indices: + model = self._dxf_tags_table.model() + row = indices[0].row() + line_number = model.line_number(row) + self._open_text_editor( + str(self.doc.absolute_filepath()), line_number + ) + + def _open_text_editor(self, filename: str, line_number: int) -> None: + cmd = TEXT_EDITOR.format( + filename=filename, + num=line_number, + ) + args = shlex.split(cmd) + try: + subprocess.Popen(args) + except FileNotFoundError: + QMessageBox.critical( + self, "Text Editor", "Error calling text editor:\n" + cmd + ) + + def open_web_browser(self, url: str): + import webbrowser + + webbrowser.open(url) + + def show_current_entity_in_tree_view(self): + entity = self.get_current_entity() + if entity: + self._structure_tree.expand_to_entity(entity) + + def store_bookmark(self): + if self._current_entity is not None: + bookmarks = self.bookmarks.names() + if len(bookmarks) == 0: + bookmarks = ["0"] + name, ok = QInputDialog.getItem( + self, + "Store Bookmark", + "Bookmark:", + bookmarks, + editable=True, + ) + if ok: + entity = self._current_entity + rows = self._dxf_tags_table.selectedIndexes() + if rows: + offset = rows[0].row() + else: + offset = 0 + handle = self.doc.get_handle(entity) + self.bookmarks.add(name, handle, offset) + + def go_to_bookmark(self): + bookmarks = self.bookmarks.names() + if len(bookmarks) == 0: + QMessageBox.information(self, "Info", "No Bookmarks defined!") + return + + name, ok = QInputDialog.getItem( + self, + "Go to Bookmark", + "Bookmark:", + self.bookmarks.names(), + editable=False, + ) + if ok: + bookmark = self.bookmarks.get(name) + if bookmark is not None: + self.set_current_entity_by_handle(bookmark.handle) + self._dxf_tags_table.selectRow(bookmark.offset) + model = self._dxf_tags_table.model() + index = QModelIndex(model.index(bookmark.offset, 0)) + self._dxf_tags_table.scrollTo(index) + + else: + QtWidgets.QMessageBox.critical( + self, "Bookmark not found!", str(name) + ) + + +def copy_dxf_to_clipboard(tags: Tags): + clipboard = QtWidgets.QApplication.clipboard() + try: + mode = clipboard.Mode.Clipboard + except AttributeError: + mode = clipboard.Clipboard # type: ignore # legacy location + clipboard.setText(dxfstr(tags), mode=mode) + + +class FindDialog(QtWidgets.QDialog, Ui_FindDialog): + def __init__(self): + super().__init__() + self.setupUi(self) + self.close_button.clicked.connect(lambda: self.close()) + self.settings = QSettings("ezdxf", "DXFBrowser") + + def restore_geometry(self): + geometry = self.settings.value("find.dialog.geometry") + if geometry is not None: + self.restoreGeometry(geometry) + + def search_sections(self) -> SearchSections: + sections = set() + if self.header_check_box.isChecked(): + sections.add("HEADER") + if self.classes_check_box.isChecked(): + sections.add("CLASSES") + if self.tables_check_box.isChecked(): + sections.add("TABLES") + if self.blocks_check_box.isChecked(): + sections.add("BLOCKS") + if self.entities_check_box.isChecked(): + sections.add("ENTITIES") + if self.objects_check_box.isChecked(): + sections.add("OBJECTS") + return sections + + def update_options(self, search: SearchIndex) -> None: + search.reset_search_term(self.find_text_edit.text()) + search.case_insensitive = not self.match_case_check_box.isChecked() + search.whole_words = self.whole_words_check_box.isChecked() + search.numbers = self.number_tags_check_box.isChecked() + + def closeEvent(self, event): + self.settings.setValue("find.dialog.geometry", self.saveGeometry()) + super().closeEvent(event) + + def show_message(self, msg: str): + self.message.setText(msg) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/data.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/data.py new file mode 100644 index 0000000..b3b35c3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/data.py @@ -0,0 +1,428 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Optional, Iterable, Any, TYPE_CHECKING +from pathlib import Path +from ezdxf.addons.browser.loader import load_section_dict +from ezdxf.lldxf.types import DXFVertex, tag_type +from ezdxf.lldxf.tags import Tags + +if TYPE_CHECKING: + from ezdxf.eztypes import SectionDict + +__all__ = [ + "DXFDocument", + "IndexEntry", + "get_row_from_line_number", + "dxfstr", + "EntityHistory", + "SearchIndex", +] + + +class DXFDocument: + def __init__(self, sections: Optional[SectionDict] = None): + # Important: the section dict has to store the raw string tags + # else an association of line numbers to entities is not possible. + # Comment tags (999) are ignored, because the load_section_dict() + # function can not handle and store comments. + # Therefore comments causes incorrect results for the line number + # associations and should be stripped off before processing for precise + # debugging of DXF files (-b for backup): + # ezdxf strip -b + self.sections: SectionDict = dict() + self.entity_index: Optional[EntityIndex] = None + self.valid_handles = None + self.filename = "" + if sections: + self.update(sections) + + @property + def filepath(self): + return Path(self.filename) + + @property + def max_line_number(self) -> int: + if self.entity_index: + return self.entity_index.max_line_number + else: + return 1 + + def load(self, filename: str): + self.filename = filename + self.update(load_section_dict(filename)) + + def update(self, sections: SectionDict): + self.sections = sections + self.entity_index = EntityIndex(self.sections) + + def absolute_filepath(self): + return self.filepath.absolute() + + def get_section(self, name: str) -> list[Tags]: + return self.sections.get(name) # type: ignore + + def get_entity(self, handle: str) -> Optional[Tags]: + if self.entity_index: + return self.entity_index.get(handle) + return None + + def get_line_number(self, entity: Tags, offset: int = 0) -> int: + if self.entity_index: + return ( + self.entity_index.get_start_line_for_entity(entity) + offset * 2 + ) + return 0 + + def get_entity_at_line(self, number: int) -> Optional[Tags]: + if self.entity_index: + return self.entity_index.get_entity_at_line(number) + return None + + def next_entity(self, entity: Tags) -> Optional[Tags]: + return self.entity_index.next_entity(entity) # type: ignore + + def previous_entity(self, entity: Tags) -> Optional[Tags]: + return self.entity_index.previous_entity(entity) # type: ignore + + def get_handle(self, entity) -> Optional[str]: + return self.entity_index.get_handle(entity) # type: ignore + + +class IndexEntry: + def __init__(self, tags: Tags, line: int = 0): + self.tags: Tags = tags + self.start_line_number: int = line + self.prev: Optional["IndexEntry"] = None + self.next: Optional["IndexEntry"] = None + + +class EntityIndex: + def __init__(self, sections: SectionDict): + # dict() entries have to be ordered since Python 3.6! + # Therefore _index.values() returns the DXF entities in file order! + self._index: dict[str, IndexEntry] = dict() + # Index dummy handle of entities without handles by the id of the + # first tag for faster retrieval of the dummy handle from tags: + # dict items: (id, handle) + self._dummy_handle_index: dict[int, str] = dict() + self._max_line_number: int = 0 + self._build(sections) + + def _build(self, sections: SectionDict) -> None: + start_line_number = 1 + dummy_handle = 1 + entity_index: dict[str, IndexEntry] = dict() + dummy_handle_index: dict[int, str] = dict() + prev_entry: Optional[IndexEntry] = None + for section in sections.values(): + for tags in section: + assert isinstance(tags, Tags), "expected class Tags" + assert len(tags) > 0, "empty tags should not be possible" + try: + handle = tags.get_handle().upper() + except ValueError: + handle = f"*{dummy_handle:X}" + # index dummy handle by id of the first tag: + dummy_handle_index[id(tags[0])] = handle + dummy_handle += 1 + + next_entry = IndexEntry(tags, start_line_number) + if prev_entry is not None: + next_entry.prev = prev_entry + prev_entry.next = next_entry + entity_index[handle] = next_entry + prev_entry = next_entry + + # calculate next start line number: + # add 2 lines for each tag: group code, value + start_line_number += len(tags) * 2 + start_line_number += 2 # for removed ENDSEC tag + + # subtract 1 and 2 for the last ENDSEC tag! + self._max_line_number = start_line_number - 3 + self._index = entity_index + self._dummy_handle_index = dummy_handle_index + + def __contains__(self, handle: str) -> bool: + return handle.upper() in self._index + + @property + def max_line_number(self) -> int: + return self._max_line_number + + def get(self, handle: str) -> Optional[Tags]: + index_entry = self._index.get(handle.upper()) + if index_entry is not None: + return index_entry.tags + else: + return None + + def get_handle(self, entity: Tags) -> Optional[str]: + if not len(entity): + return None + + try: + return entity.get_handle() + except ValueError: + # fast retrieval of dummy handle which isn't stored in tags: + return self._dummy_handle_index.get(id(entity[0])) + + def next_entity(self, entity: Tags) -> Tags: + handle = self.get_handle(entity) + if handle: + index_entry = self._index.get(handle) + next_entry = index_entry.next # type: ignore + # next of last entity is None! + if next_entry: + return next_entry.tags + return entity + + def previous_entity(self, entity: Tags) -> Tags: + handle = self.get_handle(entity) + if handle: + index_entry = self._index.get(handle) + prev_entry = index_entry.prev # type: ignore + # prev of first entity is None! + if prev_entry: + return prev_entry.tags + return entity + + def get_start_line_for_entity(self, entity: Tags) -> int: + handle = self.get_handle(entity) + if handle: + index_entry = self._index.get(handle) + if index_entry: + return index_entry.start_line_number + return 0 + + def get_entity_at_line(self, number: int) -> Optional[Tags]: + tags = None + for index_entry in self._index.values(): + if index_entry.start_line_number > number: + return tags # tags of previous entry! + tags = index_entry.tags + return tags + + +def get_row_from_line_number( + entity: Tags, start_line_number: int, select_line_number: int +) -> int: + count = select_line_number - start_line_number + lines = 0 + row = 0 + for tag in entity: + if lines >= count: + return row + if isinstance(tag, DXFVertex): + lines += len(tag.value) * 2 + else: + lines += 2 + row += 1 + return row + + +def dxfstr(tags: Tags) -> str: + return "".join(tag.dxfstr() for tag in tags) + + +class EntityHistory: + def __init__(self) -> None: + self._history: list[Tags] = list() + self._index: int = 0 + self._time_travel: list[Tags] = list() + + def __len__(self): + return len(self._history) + + @property + def index(self): + return self._index + + def clear(self): + self._history.clear() + self._time_travel.clear() + self._index = 0 + + def append(self, entity: Tags): + if self._time_travel: + self._history.extend(self._time_travel) + self._time_travel.clear() + count = len(self._history) + if count: + # only append if different to last entity + if self._history[-1] is entity: + return + self._index = count + self._history.append(entity) + + def back(self) -> Optional[Tags]: + entity = None + if self._history: + index = self._index - 1 + if index >= 0: + entity = self._time_wrap(index) + else: + entity = self._history[0] + return entity + + def forward(self) -> Tags: + entity = None + history = self._history + if history: + index = self._index + 1 + if index < len(history): + entity = self._time_wrap(index) + else: + entity = history[-1] + return entity # type: ignore + + def _time_wrap(self, index) -> Tags: + self._index = index + entity = self._history[index] + self._time_travel.append(entity) + return entity + + def content(self) -> list[Tags]: + return list(self._history) + + +class SearchIndex: + NOT_FOUND = None, -1 + + def __init__(self, entities: Iterable[Tags]): + self.entities: list[Tags] = list(entities) + self._current_entity_index: int = 0 + self._current_tag_index: int = 0 + self._search_term: Optional[str] = None + self._search_term_lower: Optional[str] = None + self._backward = False + self._end_of_index = not bool(self.entities) + self.case_insensitive = True + self.whole_words = False + self.numbers = False + self.regex = False # False = normal mode + + @property + def is_end_of_index(self) -> bool: + return self._end_of_index + + @property + def search_term(self) -> Optional[str]: + return self._search_term + + def set_current_entity(self, entity: Tags, tag_index: int = 0): + self._current_tag_index = tag_index + try: + self._current_entity_index = self.entities.index(entity) + except ValueError: + self.reset_cursor() + + def update_entities(self, entities: list[Tags]): + current_entity, index = self.current_entity() + self.entities = entities + if current_entity: + self.set_current_entity(current_entity, index) + + def current_entity(self) -> tuple[Optional[Tags], int]: + if self.entities and not self._end_of_index: + return ( + self.entities[self._current_entity_index], + self._current_tag_index, + ) + return self.NOT_FOUND + + def reset_cursor(self, backward: bool = False): + self._current_entity_index = 0 + self._current_tag_index = 0 + count = len(self.entities) + if count: + self._end_of_index = False + if backward: + self._current_entity_index = count - 1 + entity = self.entities[-1] + self._current_tag_index = len(entity) - 1 + else: + self._end_of_index = True + + def cursor(self) -> tuple[int, int]: + return self._current_entity_index, self._current_tag_index + + def move_cursor_forward(self) -> None: + if self.entities: + entity: Tags = self.entities[self._current_entity_index] + tag_index = self._current_tag_index + 1 + if tag_index >= len(entity): + entity_index = self._current_entity_index + 1 + if entity_index < len(self.entities): + self._current_entity_index = entity_index + self._current_tag_index = 0 + else: + self._end_of_index = True + else: + self._current_tag_index = tag_index + + def move_cursor_backward(self) -> None: + if self.entities: + tag_index = self._current_tag_index - 1 + if tag_index < 0: + entity_index = self._current_entity_index - 1 + if entity_index >= 0: + self._current_entity_index = entity_index + self._current_tag_index = ( + len(self.entities[entity_index]) - 1 + ) + else: + self._end_of_index = True + else: + self._current_tag_index = tag_index + + def reset_search_term(self, term: str) -> None: + self._search_term = str(term) + self._search_term_lower = self._search_term.lower() + + def find( + self, term: str, backward: bool = False, reset_index: bool = True + ) -> tuple[Optional[Tags], int]: + self.reset_search_term(term) + if reset_index: + self.reset_cursor(backward) + if len(self.entities) and not self._end_of_index: + if backward: + return self.find_backwards() + else: + return self.find_forward() + else: + return self.NOT_FOUND + + def find_forward(self) -> tuple[Optional[Tags], int]: + return self._find(self.move_cursor_forward) + + def find_backwards(self) -> tuple[Optional[Tags], int]: + return self._find(self.move_cursor_backward) + + def _find(self, move_cursor) -> tuple[Optional[Tags], int]: + if self.entities and self._search_term and not self._end_of_index: + while not self._end_of_index: + entity, tag_index = self.current_entity() + move_cursor() + if self._match(*entity[tag_index]): # type: ignore + return entity, tag_index + return self.NOT_FOUND + + def _match(self, code: int, value: Any) -> bool: + if tag_type(code) is not str: + if not self.numbers: + return False + value = str(value) + + if self.case_insensitive: + search_term = self._search_term_lower + value = value.lower() + else: + search_term = self._search_term + + if self.whole_words: + return any(search_term == word for word in value.split()) + else: + return search_term in value diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/find_dialog.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/find_dialog.py new file mode 100644 index 0000000..856aa8c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/find_dialog.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'find_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.15.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from ezdxf.addons.xqt import QtCore, QtGui, QtWidgets + + +class Ui_FindDialog(object): + def setupUi(self, FindDialog): + FindDialog.setObjectName("FindDialog") + FindDialog.resize(320, 376) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(FindDialog.sizePolicy().hasHeightForWidth()) + FindDialog.setSizePolicy(sizePolicy) + FindDialog.setMinimumSize(QtCore.QSize(320, 376)) + FindDialog.setMaximumSize(QtCore.QSize(320, 376)) + FindDialog.setBaseSize(QtCore.QSize(320, 376)) + self.verticalLayout_5 = QtWidgets.QVBoxLayout(FindDialog) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(FindDialog) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.find_text_edit = QtWidgets.QLineEdit(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.find_text_edit.sizePolicy().hasHeightForWidth()) + self.find_text_edit.setSizePolicy(sizePolicy) + self.find_text_edit.setMinimumSize(QtCore.QSize(0, 24)) + self.find_text_edit.setMaximumSize(QtCore.QSize(16777215, 24)) + self.find_text_edit.setObjectName("find_text_edit") + self.horizontalLayout.addWidget(self.find_text_edit) + self.verticalLayout.addLayout(self.horizontalLayout) + self.groupBox = QtWidgets.QGroupBox(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + self.groupBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.groupBox.setFlat(False) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.whole_words_check_box = QtWidgets.QCheckBox(self.groupBox) + self.whole_words_check_box.setObjectName("whole_words_check_box") + self.verticalLayout_3.addWidget(self.whole_words_check_box) + self.match_case_check_box = QtWidgets.QCheckBox(self.groupBox) + self.match_case_check_box.setObjectName("match_case_check_box") + self.verticalLayout_3.addWidget(self.match_case_check_box) + self.number_tags_check_box = QtWidgets.QCheckBox(self.groupBox) + self.number_tags_check_box.setObjectName("number_tags_check_box") + self.verticalLayout_3.addWidget(self.number_tags_check_box) + self.verticalLayout.addWidget(self.groupBox, 0, QtCore.Qt.AlignTop) + self.groupBox_2 = QtWidgets.QGroupBox(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth()) + self.groupBox_2.setSizePolicy(sizePolicy) + self.groupBox_2.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.header_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.header_check_box.setChecked(True) + self.header_check_box.setObjectName("header_check_box") + self.verticalLayout_4.addWidget(self.header_check_box) + self.classes_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.classes_check_box.setObjectName("classes_check_box") + self.verticalLayout_4.addWidget(self.classes_check_box) + self.tables_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.tables_check_box.setChecked(True) + self.tables_check_box.setObjectName("tables_check_box") + self.verticalLayout_4.addWidget(self.tables_check_box) + self.blocks_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.blocks_check_box.setChecked(True) + self.blocks_check_box.setObjectName("blocks_check_box") + self.verticalLayout_4.addWidget(self.blocks_check_box) + self.entities_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.entities_check_box.setChecked(True) + self.entities_check_box.setObjectName("entities_check_box") + self.verticalLayout_4.addWidget(self.entities_check_box) + self.objects_check_box = QtWidgets.QCheckBox(self.groupBox_2) + self.objects_check_box.setChecked(False) + self.objects_check_box.setObjectName("objects_check_box") + self.verticalLayout_4.addWidget(self.objects_check_box) + self.verticalLayout.addWidget(self.groupBox_2, 0, QtCore.Qt.AlignTop) + self.verticalLayout_5.addLayout(self.verticalLayout) + self.message = QtWidgets.QLabel(FindDialog) + self.message.setObjectName("message") + self.verticalLayout_5.addWidget(self.message) + self.buttons_layout = QtWidgets.QHBoxLayout() + self.buttons_layout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint) + self.buttons_layout.setObjectName("buttons_layout") + self.find_forward_button = QtWidgets.QPushButton(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.find_forward_button.sizePolicy().hasHeightForWidth()) + self.find_forward_button.setSizePolicy(sizePolicy) + self.find_forward_button.setMinimumSize(QtCore.QSize(0, 0)) + self.find_forward_button.setMaximumSize(QtCore.QSize(200, 100)) + self.find_forward_button.setObjectName("find_forward_button") + self.buttons_layout.addWidget(self.find_forward_button, 0, QtCore.Qt.AlignBottom) + self.find_backwards_button = QtWidgets.QPushButton(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.find_backwards_button.sizePolicy().hasHeightForWidth()) + self.find_backwards_button.setSizePolicy(sizePolicy) + self.find_backwards_button.setMinimumSize(QtCore.QSize(0, 0)) + self.find_backwards_button.setMaximumSize(QtCore.QSize(200, 100)) + self.find_backwards_button.setObjectName("find_backwards_button") + self.buttons_layout.addWidget(self.find_backwards_button, 0, QtCore.Qt.AlignBottom) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.buttons_layout.addItem(spacerItem) + self.close_button = QtWidgets.QPushButton(FindDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.close_button.sizePolicy().hasHeightForWidth()) + self.close_button.setSizePolicy(sizePolicy) + self.close_button.setMinimumSize(QtCore.QSize(0, 0)) + self.close_button.setMaximumSize(QtCore.QSize(200, 100)) + self.close_button.setToolTip("") + self.close_button.setObjectName("close_button") + self.buttons_layout.addWidget(self.close_button, 0, QtCore.Qt.AlignRight|QtCore.Qt.AlignBottom) + self.verticalLayout_5.addLayout(self.buttons_layout) + + self.retranslateUi(FindDialog) + QtCore.QMetaObject.connectSlotsByName(FindDialog) + + def retranslateUi(self, FindDialog): + _translate = QtCore.QCoreApplication.translate + FindDialog.setWindowTitle(_translate("FindDialog", "Find")) + self.label.setText(_translate("FindDialog", "Find Text:")) + self.groupBox.setTitle(_translate("FindDialog", "Options")) + self.whole_words_check_box.setToolTip(_translate("FindDialog", "Search only whole words in normal mode if checked.")) + self.whole_words_check_box.setText(_translate("FindDialog", "Whole Words")) + self.match_case_check_box.setToolTip(_translate("FindDialog", "Case sensitive search in normal mode if checked.")) + self.match_case_check_box.setText(_translate("FindDialog", "Match Case")) + self.number_tags_check_box.setToolTip(_translate("FindDialog", "Ignore numeric DXF tags if checked.")) + self.number_tags_check_box.setText(_translate("FindDialog", "Search in Numeric Tags")) + self.groupBox_2.setToolTip(_translate("FindDialog", "Select sections to search in.")) + self.groupBox_2.setTitle(_translate("FindDialog", "Search in Sections")) + self.header_check_box.setText(_translate("FindDialog", "HEADER")) + self.classes_check_box.setText(_translate("FindDialog", "CLASSES")) + self.tables_check_box.setText(_translate("FindDialog", "TABLES")) + self.blocks_check_box.setText(_translate("FindDialog", "BLOCKS")) + self.entities_check_box.setText(_translate("FindDialog", "ENTITIES")) + self.objects_check_box.setText(_translate("FindDialog", "OBJECTS")) + self.message.setText(_translate("FindDialog", "TextLabel")) + self.find_forward_button.setToolTip(_translate("FindDialog", "or press F3")) + self.find_forward_button.setText(_translate("FindDialog", "Find &Forward")) + self.find_backwards_button.setToolTip(_translate("FindDialog", "or press F4")) + self.find_backwards_button.setText(_translate("FindDialog", "Find &Backwards")) + self.close_button.setText(_translate("FindDialog", "Close")) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/loader.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/loader.py new file mode 100644 index 0000000..a889875 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/loader.py @@ -0,0 +1,36 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, Iterable, TYPE_CHECKING +from pathlib import Path +from ezdxf.lldxf import loader +from ezdxf.lldxf.types import DXFTag +from ezdxf.lldxf.tagger import ascii_tags_loader, binary_tags_loader +from ezdxf.lldxf.validator import is_dxf_file, is_binary_dxf_file +from ezdxf.filemanagement import dxf_file_info + +if TYPE_CHECKING: + from ezdxf.eztypes import SectionDict + + +def load_section_dict(filename: Union[str, Path]) -> SectionDict: + tagger = get_tag_loader(filename) + return loader.load_dxf_structure(tagger) + + +def get_tag_loader( + filename: Union[str, Path], errors: str = "ignore" +) -> Iterable[DXFTag]: + + filename = str(filename) + if is_binary_dxf_file(filename): + with open(filename, "rb") as fp: + data = fp.read() + return binary_tags_loader(data, errors=errors) + + if not is_dxf_file(filename): + raise IOError(f"File '{filename}' is not a DXF file.") + + info = dxf_file_info(filename) + with open(filename, mode="rt", encoding=info.encoding, errors=errors) as fp: + return list(ascii_tags_loader(fp, skip_comments=True)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/model.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/model.py new file mode 100644 index 0000000..6095313 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/model.py @@ -0,0 +1,574 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +# mypy: ignore_errors=True +from __future__ import annotations +from typing import Any, Optional +import textwrap +from ezdxf.lldxf.types import ( + render_tag, + DXFVertex, + GROUP_MARKERS, + POINTER_CODES, +) +from ezdxf.addons.xqt import QModelIndex, QAbstractTableModel, Qt, QtWidgets +from ezdxf.addons.xqt import QStandardItemModel, QStandardItem, QColor +from .tags import compile_tags, Tags + +__all__ = [ + "DXFTagsModel", + "DXFStructureModel", + "EntityContainer", + "Entity", + "DXFTagsRole", +] + +DXFTagsRole = Qt.UserRole + 1 # type: ignore + + +def name_fmt(handle, name: str) -> str: + if handle is None: + return name + else: + return f"<{handle}> {name}" + + +HEADER_LABELS = ["Group Code", "Data Type", "Content", "4", "5"] + + +def calc_line_numbers(start: int, tags: Tags) -> list[int]: + numbers = [start] + index = start + for tag in tags: + if isinstance(tag, DXFVertex): + index += len(tag.value) * 2 + else: + index += 2 + numbers.append(index) + return numbers + + +class DXFTagsModel(QAbstractTableModel): + def __init__( + self, tags: Tags, start_line_number: int = 1, valid_handles=None + ): + super().__init__() + self._tags = compile_tags(tags) + self._line_numbers = calc_line_numbers(start_line_number, self._tags) + self._valid_handles = valid_handles or set() + palette = QtWidgets.QApplication.palette() + self._group_marker_color = palette.highlight().color() + + def data(self, index: QModelIndex, role: int = ...) -> Any: # type: ignore + def is_invalid_handle(tag): + if ( + tag.code in POINTER_CODES + and not tag.value.upper() in self._valid_handles + ): + return True + return False + + if role == Qt.DisplayRole: + tag = self._tags[index.row()] + return render_tag(tag, index.column()) + elif role == Qt.ForegroundRole: + tag = self._tags[index.row()] + if tag.code in GROUP_MARKERS: + return self._group_marker_color + elif is_invalid_handle(tag): + return QColor("red") + elif role == DXFTagsRole: + return self._tags[index.row()] + elif role == Qt.ToolTipRole: + code, value = self._tags[index.row()] + if index.column() == 0: # group code column + return GROUP_CODE_TOOLTIPS_DICT.get(code) + + code, value = self._tags[index.row()] + if code in POINTER_CODES: + if value.upper() in self._valid_handles: + return f"Double click to go to the referenced entity" + else: + return f"Handle does not exist" + elif code == 0: + return f"Double click to go to the DXF reference provided by Autodesk" + + def headerData( + self, section: int, orientation: Qt.Orientation, role: int = ... # type: ignore + ) -> Any: + if orientation == Qt.Horizontal: + if role == Qt.DisplayRole: + return HEADER_LABELS[section] + elif role == Qt.TextAlignmentRole: + return Qt.AlignLeft + elif orientation == Qt.Vertical: + if role == Qt.DisplayRole: + return self._line_numbers[section] + elif role == Qt.ToolTipRole: + return "Line number in DXF file" + + def rowCount(self, parent: QModelIndex = ...) -> int: # type: ignore + return len(self._tags) + + def columnCount(self, parent: QModelIndex = ...) -> int: # type: ignore + return 3 + + def compiled_tags(self) -> Tags: + """Returns the compiled tags. Only points codes are compiled, group + code 10, ... + """ + return self._tags + + def line_number(self, row: int) -> int: + """Return the DXF file line number of the widget-row.""" + try: + return self._line_numbers[row] + except IndexError: + return 0 + + +class EntityContainer(QStandardItem): + def __init__(self, name: str, entities: list[Tags]): + super().__init__() + self.setEditable(False) + self.setText(name + f" ({len(entities)})") + self.setup_content(entities) + + def setup_content(self, entities): + self.appendRows([Entity(e) for e in entities]) + + +class Classes(EntityContainer): + def setup_content(self, entities): + self.appendRows([Class(e) for e in entities]) + + +class AcDsData(EntityContainer): + def setup_content(self, entities): + self.appendRows([AcDsEntry(e) for e in entities]) + + +class NamedEntityContainer(EntityContainer): + def setup_content(self, entities): + self.appendRows([NamedEntity(e) for e in entities]) + + +class Tables(EntityContainer): + def setup_content(self, entities): + container = [] + name = "" + for e in entities: + container.append(e) + dxftype = e.dxftype() + if dxftype == "TABLE": + try: + handle = e.get_handle() + except ValueError: + handle = None + name = e.get_first_value(2, default="UNDEFINED") + name = name_fmt(handle, name) + elif dxftype == "ENDTAB": + if container: + container.pop() # remove ENDTAB + self.appendRow(NamedEntityContainer(name, container)) + container.clear() + + +class Blocks(EntityContainer): + def setup_content(self, entities): + container = [] + name = "UNDEFINED" + for e in entities: + container.append(e) + dxftype = e.dxftype() + if dxftype == "BLOCK": + try: + handle = e.get_handle() + except ValueError: + handle = None + name = e.get_first_value(2, default="UNDEFINED") + name = name_fmt(handle, name) + elif dxftype == "ENDBLK": + if container: + self.appendRow(EntityContainer(name, container)) + container.clear() + + +def get_section_name(section: list[Tags]) -> str: + if len(section) > 0: + header = section[0] + if len(header) > 1 and header[0].code == 0 and header[1].code == 2: + return header[1].value + return "INVALID SECTION HEADER!" + + +class Entity(QStandardItem): + def __init__(self, tags: Tags): + super().__init__() + self.setEditable(False) + self._tags = tags + self._handle: Optional[str] + try: + self._handle = tags.get_handle() + except ValueError: + self._handle = None + self.setText(self.entity_name()) + + def entity_name(self): + name = "INVALID ENTITY!" + tags = self._tags + if tags and tags[0].code == 0: + name = name_fmt(self._handle, tags[0].value) + return name + + def data(self, role: int = ...) -> Any: # type: ignore + if role == DXFTagsRole: + return self._tags + else: + return super().data(role) + + +class Header(Entity): + def entity_name(self): + return "HEADER" + + +class ThumbnailImage(Entity): + def entity_name(self): + return "THUMBNAILIMAGE" + + +class NamedEntity(Entity): + def entity_name(self): + name = self._tags.get_first_value(2, "") + return name_fmt(str(self._handle), name) + + +class Class(Entity): + def entity_name(self): + tags = self._tags + name = "INVALID CLASS!" + if len(tags) > 1 and tags[0].code == 0 and tags[1].code == 1: + name = tags[1].value + return name + + +class AcDsEntry(Entity): + def entity_name(self): + return self._tags[0].value + + +class DXFStructureModel(QStandardItemModel): + def __init__(self, filename: str, doc): + super().__init__() + root = QStandardItem(filename) + root.setEditable(False) + self.appendRow(root) + row: Any + for section in doc.sections.values(): + name = get_section_name(section) + if name == "HEADER": + row = Header(section[0]) + elif name == "THUMBNAILIMAGE": + row = ThumbnailImage(section[0]) + elif name == "CLASSES": + row = Classes(name, section[1:]) + elif name == "TABLES": + row = Tables(name, section[1:]) + elif name == "BLOCKS": + row = Blocks(name, section[1:]) + elif name == "ACDSDATA": + row = AcDsData(name, section[1:]) + else: + row = EntityContainer(name, section[1:]) + root.appendRow(row) + + def index_of_entity(self, entity: Tags) -> QModelIndex: + root = self.item(0, 0) + index = find_index(root, entity) + if index is None: + return root.index() + else: + return index + + +def find_index(item: QStandardItem, entity: Tags) -> Optional[QModelIndex]: + def _find(sub_item: QStandardItem): + for index in range(sub_item.rowCount()): + child = sub_item.child(index, 0) + tags = child.data(DXFTagsRole) + if tags and tags is entity: + return child.index() + if child.rowCount() > 0: + index2 = _find(child) + if index2 is not None: + return index2 + return None + + return _find(item) + + +GROUP_CODE_TOOLTIPS = [ + (0, "Text string indicating the entity type (fixed)"), + (1, "Primary text value for an entity"), + (2, "Name (attribute tag, block name, and so on)"), + ((3, 4), "Other text or name values"), + (5, "Entity handle; text string of up to 16 hexadecimal digits (fixed)"), + (6, "Linetype name (fixed)"), + (7, "Text style name (fixed)"), + (8, "Layer name (fixed)"), + ( + 9, + "DXF: variable name identifier (used only in HEADER section of the DXF file)", + ), + ( + 10, + "Primary point; this is the start point of a line or text entity, center " + "of a circle, and so on DXF: X value of the primary point (followed by Y " + "and Z value codes 20 and 30) APP: 3D point (list of three reals)", + ), + ( + (11, 18), + "Other points DXF: X value of other points (followed by Y value codes " + "21-28 and Z value codes 31-38) APP: 3D point (list of three reals)", + ), + (20, "DXF: Y value of the primary point"), + (30, "DXF: Z value of the primary point"), + ((21, 28), "DXF: Y values of other points"), + ((31, 37), "DXF: Z values of other points"), + (38, "DXF: entity's elevation if nonzero"), + (39, "Entity's thickness if nonzero (fixed)"), + ( + (40, 47), + "Double-precision floating-point values (text height, scale factors, and so on)", + ), + (48, "Linetype scale; default value is defined for all entity types"), + ( + 49, + "Multiple 49 groups may appear in one entity for variable-length tables " + "(such as the dash lengths in the LTYPE table). A 7x group always appears " + "before the first 49 group to specify the table length", + ), + ( + (50, 58), + "Angles (output in degrees to DXF files and radians through AutoLISP and ObjectARX applications)", + ), + ( + 60, + "Entity visibility; absence or 0 indicates visibility; 1 indicates invisibility", + ), + (62, "Color number (fixed)"), + (66, "Entities follow flag (fixed)"), + (67, "0 for model space or 1 for paper space (fixed)"), + ( + 68, + "APP: identifies whether viewport is on but fully off screen; is not active or is off", + ), + (69, "APP: viewport identification number"), + ((70, 79), "Integer values, such as repeat counts, flag bits, or modes"), + ((90, 99), "32-bit integer values"), + ( + 100, + "Subclass data marker (with derived class name as a string). " + "Required for all objects and entity classes that are derived from " + "another concrete class. The subclass data marker segregates data defined by different " + "classes in the inheritance chain for the same object. This is in addition " + "to the requirement for DXF names for each distinct concrete class derived " + "from ObjectARX (see Subclass Markers)", + ), + (101, "Embedded object marker"), + ( + 102, + "Control string, followed by '{arbitrary name' or '}'. Similar to the " + "xdata 1002 group code, except that when the string begins with '{', it " + "can be followed by an arbitrary string whose interpretation is up to the " + "application. The only other control string allowed is '}' as a group " + "terminator. AutoCAD does not interpret these strings except during d" + "rawing audit operations. They are for application use.", + ), + (105, "Object handle for DIMVAR symbol table entry"), + ( + 110, + "UCS origin (appears only if code 72 is set to 1); DXF: X value; APP: 3D point", + ), + ( + 111, + "UCS Y-axis (appears only if code 72 is set to 1); DXF: Y value; APP: 3D vector", + ), + ( + 112, + "UCS Z-axis (appears only if code 72 is set to 1); DXF: Z value; APP: 3D vector", + ), + ((120, 122), "DXF: Y value of UCS origin, UCS X-axis, and UCS Y-axis"), + ((130, 132), "DXF: Z value of UCS origin, UCS X-axis, and UCS Y-axis"), + ( + (140, 149), + "Double-precision floating-point values (points, elevation, and DIMSTYLE settings, for example)", + ), + ( + (170, 179), + "16-bit integer values, such as flag bits representing DIMSTYLE settings", + ), + ( + 210, + "Extrusion direction (fixed) " + + "DXF: X value of extrusion direction " + + "APP: 3D extrusion direction vector", + ), + (220, "DXF: Y value of the extrusion direction"), + (230, "DXF: Z value of the extrusion direction"), + ((270, 279), "16-bit integer values"), + ((280, 289), "16-bit integer value"), + ((290, 299), "Boolean flag value; 0 = False; 1 = True"), + ((300, 309), "Arbitrary text strings"), + ( + (310, 319), + "Arbitrary binary chunks with same representation and limits as 1004 " + "group codes: hexadecimal strings of up to 254 characters represent data " + "chunks of up to 127 bytes", + ), + ( + (320, 329), + "Arbitrary object handles; handle values that are taken 'as is'. They " + "are not translated during INSERT and XREF operations", + ), + ( + (330, 339), + "Soft-pointer handle; arbitrary soft pointers to other objects within " + "same DXF file or drawing. Translated during INSERT and XREF operations", + ), + ( + (340, 349), + "Hard-pointer handle; arbitrary hard pointers to other objects within " + "same DXF file or drawing. Translated during INSERT and XREF operations", + ), + ( + (350, 359), + "Soft-owner handle; arbitrary soft ownership links to other objects " + "within same DXF file or drawing. Translated during INSERT and XREF " + "operations", + ), + ( + (360, 369), + "Hard-owner handle; arbitrary hard ownership links to other objects within " + "same DXF file or drawing. Translated during INSERT and XREF operations", + ), + ( + (370, 379), + "Lineweight enum value (AcDb::LineWeight). Stored and moved around as a 16-bit integer. " + "Custom non-entity objects may use the full range, but entity classes only use 371-379 DXF " + "group codes in their representation, because AutoCAD and AutoLISP both always assume a 370 " + "group code is the entity's lineweight. This allows 370 to behave like other 'common' entity fields", + ), + ( + (380, 389), + "PlotStyleName type enum (AcDb::PlotStyleNameType). Stored and moved around as a 16-bit integer. " + "Custom non-entity objects may use the full range, but entity classes only use 381-389 " + "DXF group codes in their representation, for the same reason as the lineweight range", + ), + ( + (390, 399), + "String representing handle value of the PlotStyleName object, basically a hard pointer, but has " + "a different range to make backward compatibility easier to deal with. Stored and moved around " + "as an object ID (a handle in DXF files) and a special type in AutoLISP. Custom non-entity objects " + "may use the full range, but entity classes only use 391-399 DXF group codes in their representation, " + "for the same reason as the lineweight range", + ), + ((400, 409), "16-bit integers"), + ((410, 419), "String"), + ( + (420, 427), + "32-bit integer value. When used with True Color; a 32-bit integer representing a 24-bit color value. " + "The high-order byte (8 bits) is 0, the low-order byte an unsigned char holding the Blue value (0-255), " + "then the Green value, and the next-to-high order byte is the Red Value. Converting this integer value to " + "hexadecimal yields the following bit mask: 0x00RRGGBB. " + "For example, a true color with Red==200, Green==100 and Blue==50 is 0x00C86432, and in DXF, in decimal, 13132850", + ), + ( + (430, 437), + "String; when used for True Color, a string representing the name of the color", + ), + ( + (440, 447), + "32-bit integer value. When used for True Color, the transparency value", + ), + ((450, 459), "Long"), + ((460, 469), "Double-precision floating-point value"), + ((470, 479), "String"), + ( + (480, 481), + "Hard-pointer handle; arbitrary hard pointers to other objects within same DXF file or drawing. " + "Translated during INSERT and XREF operations", + ), + ( + 999, + "DXF: The 999 group code indicates that the line following it is a comment string. SAVEAS does " + "not include such groups in a DXF output file, but OPEN honors them and ignores the comments. " + "You can use the 999 group to include comments in a DXF file that you have edited", + ), + (1000, "ASCII string (up to 255 bytes long) in extended data"), + ( + 1001, + "Registered application name (ASCII string up to 31 bytes long) for extended data", + ), + (1002, "Extended data control string ('{' or '}')"), + (1003, "Extended data layer name"), + (1004, "Chunk of bytes (up to 127 bytes long) in extended data"), + ( + 1005, + "Entity handle in extended data; text string of up to 16 hexadecimal digits", + ), + ( + 1010, + "A point in extended data; DXF: X value (followed by 1020 and 1030 groups); APP: 3D point", + ), + (1020, "DXF: Y values of a point"), + (1030, "DXF: Z values of a point"), + ( + 1011, + "A 3D world space position in extended data " + "DXF: X value (followed by 1021 and 1031 groups) " + "APP: 3D point", + ), + (1021, "DXF: Y value of a world space position"), + (1031, "DXF: Z value of a world space position"), + ( + 1012, + "A 3D world space displacement in extended data " + "DXF: X value (followed by 1022 and 1032 groups) " + "APP: 3D vector", + ), + (1022, "DXF: Y value of a world space displacement"), + (1032, "DXF: Z value of a world space displacement"), + ( + 1013, + "A 3D world space direction in extended data " + "DXF: X value (followed by 1022 and 1032 groups) " + "APP: 3D vector", + ), + (1023, "DXF: Y value of a world space direction"), + (1033, "DXF: Z value of a world space direction"), + (1040, "Extended data double-precision floating-point value"), + (1041, "Extended data distance value"), + (1042, "Extended data scale factor"), + (1070, "Extended data 16-bit signed integer"), + (1071, "Extended data 32-bit signed long"), +] + + +def build_group_code_tooltip_dict() -> dict[int, str]: + tooltips = dict() + for code, tooltip in GROUP_CODE_TOOLTIPS: + tooltip = "\n".join(textwrap.wrap(tooltip, width=80)) + if isinstance(code, int): + tooltips[code] = tooltip + elif isinstance(code, tuple): + s, e = code + for group_code in range(s, e + 1): + tooltips[group_code] = tooltip + else: + raise ValueError(type(code)) + + return tooltips + + +GROUP_CODE_TOOLTIPS_DICT = build_group_code_tooltip_dict() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/reflinks.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/reflinks.py new file mode 100644 index 0000000..571c8a7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/reflinks.py @@ -0,0 +1,117 @@ +# Autodesk DXF 2018 Reference +link_tpl = "https://help.autodesk.com/view/OARX/2018/ENU/?guid={guid}" +# Autodesk DXF 2014 Reference +# link_tpl = 'https://docs.autodesk.com/ACD/2014/ENU/files/{guid}.htm' +main_index_guid = "GUID-235B22E0-A567-4CF6-92D3-38A2306D73F3" # main index + +reference_guids = { + "HEADER": "GUID-EA9CDD11-19D1-4EBC-9F56-979ACF679E3C", + "CLASSES": "GUID-6160F1F1-2805-4C69-8077-CA1AEB6B1005", + "TABLES": "GUID-A9FD9590-C97B-4E41-9F26-BD82C34A4F9F", + "BLOCKS": "GUID-1D14A213-5E4D-4EA6-A6B5-8709EB925D01", + "ENTITIES": "GUID-7D07C886-FD1D-4A0C-A7AB-B4D21F18E484", + "OBJECTS": "GUID-2D71EE99-A6BE-4060-9B43-808CF1E201C6", + "THUMBNAILIMAGE": "GUID-792F79DC-0D5D-43B5-AB0E-212E0EDF6BAE", + "APPIDS": "GUID-6E3140E9-E560-4C77-904E-480382F0553E", + "APPID": "GUID-6E3140E9-E560-4C77-904E-480382F0553E", + "BLOCK_RECORDS": "GUID-A1FD1934-7EF5-4D35-A4B0-F8AE54A9A20A", + "BLOCK_RECORD": "GUID-A1FD1934-7EF5-4D35-A4B0-F8AE54A9A20A", + "DIMSTYLES": "GUID-F2FAD36F-0CE3-4943-9DAD-A9BCD2AE81DA", + "DIMSTYLE": "GUID-F2FAD36F-0CE3-4943-9DAD-A9BCD2AE81DA", + "LAYERS": "GUID-D94802B0-8BE8-4AC9-8054-17197688AFDB", + "LAYER": "GUID-D94802B0-8BE8-4AC9-8054-17197688AFDB", + "LINETYPES": "GUID-F57A316C-94A2-416C-8280-191E34B182AC", + "LTYPE": "GUID-F57A316C-94A2-416C-8280-191E34B182AC", + "STYLES": "GUID-EF68AF7C-13EF-45A1-8175-ED6CE66C8FC9", + "STYLE": "GUID-EF68AF7C-13EF-45A1-8175-ED6CE66C8FC9", + "UCS": "GUID-1906E8A7-3393-4BF9-BD27-F9AE4352FB8B", + "VIEWS": "GUID-CF3094AB-ECA9-43C1-8075-7791AC84F97C", + "VIEW": "GUID-CF3094AB-ECA9-43C1-8075-7791AC84F97C", + "VIEWPORTS": "GUID-8CE7CC87-27BD-4490-89DA-C21F516415A9", + "VPORT": "GUID-8CE7CC87-27BD-4490-89DA-C21F516415A9", + "BLOCK": "GUID-66D32572-005A-4E23-8B8B-8726E8C14302", + "ENDBLK": "GUID-27F7CC8A-E340-4C7F-A77F-5AF139AD502D", + "3DFACE": "GUID-747865D5-51F0-45F2-BEFE-9572DBC5B151", + "3DSOLID": "GUID-19AB1C40-0BE0-4F32-BCAB-04B37044A0D3", + "ACAD_PROXY_ENTITY": "GUID-89A690F9-E859-4D57-89EA-750F3FB76C6B", + "ARC": "GUID-0B14D8F1-0EBA-44BF-9108-57D8CE614BC8", + "ATTDEF": "GUID-F0EA099B-6F88-4BCC-BEC7-247BA64838A4", + "ATTRIB": "GUID-7DD8B495-C3F8-48CD-A766-14F9D7D0DD9B", + "BODY": "GUID-7FB91514-56FF-4487-850E-CF1047999E77", + "CIRCLE": "GUID-8663262B-222C-414D-B133-4A8506A27C18", + "DIMENSION": "GUID-239A1BDD-7459-4BB9-8DD7-08EC79BF1EB0", + "ELLIPSE": "GUID-107CB04F-AD4D-4D2F-8EC9-AC90888063AB", + "HATCH": "GUID-C6C71CED-CE0F-4184-82A5-07AD6241F15B", + "HELIX": "GUID-76DB3ABF-3C8C-47D1-8AFB-72942D9AE1FF", + "IMAGE": "GUID-3A2FF847-BE14-4AC5-9BD4-BD3DCAEF2281", + "INSERT": "GUID-28FA4CFB-9D5E-4880-9F11-36C97578252F", + "LEADER": "GUID-396B2369-F89F-47D7-8223-8B7FB794F9F3", + "LIGHT": "GUID-1A23DB42-6A92-48E9-9EB2-A7856A479930", + "LINE": "GUID-FCEF5726-53AE-4C43-B4EA-C84EB8686A66", + "LWPOLYLINE": "GUID-748FC305-F3F2-4F74-825A-61F04D757A50", + "MESH": "GUID-4B9ADA67-87C8-4673-A579-6E4C76FF7025", + "MLINE": "GUID-590E8AE3-C6D9-4641-8485-D7B3693E432C", + "MLEADERSTYLE": "GUID-0E489B69-17A4-4439-8505-9DCE032100B4", + "MLEADER": "GUID-72D20B8C-0F5E-4993-BEB7-0FCF94F32BE0", + "MULTILEADER": "GUID-72D20B8C-0F5E-4993-BEB7-0FCF94F32BE0", + "MTEXT": "GUID-5E5DB93B-F8D3-4433-ADF7-E92E250D2BAB", + "OLEFRAME": "GUID-4A10EF68-35A3-4961-8B15-1222ECE5E8C6", + "OLE2FRAME": "GUID-77747CE6-82C6-4452-97ED-4CEEB38BE960", + "POINT": "GUID-9C6AD32D-769D-4213-85A4-CA9CCB5C5317", + "POLYLINE": "GUID-ABF6B778-BE20-4B49-9B58-A94E64CEFFF3", + "RAY": "GUID-638B9F01-5D86-408E-A2DE-FA5D6ADBD415", + "REGION": "GUID-644BF0F0-FD79-4C5E-AD5A-0053FCC5A5A4", + "SECTION": "GUID-8B60CBAB-B226-4A5F-ABB1-46FD8AABB928", + "SEQEND": "GUID-FD4FAA74-1F6D-45F6-B132-BF0C4BE6CC3B", + "SHAPE": "GUID-0988D755-9AAB-4D6C-8E26-EC636F507F2C", + "SOLID": "GUID-E0C5F04E-D0C5-48F5-AC09-32733E8848F2", + "SPLINE": "GUID-E1F884F8-AA90-4864-A215-3182D47A9C74", + "SUN": "GUID-BB191D89-9302-45E4-9904-108AB418FAE1", + "SURFACE": "GUID-BB62483A-89C3-47C4-80E5-EA3F08979863", + "TABLE": "GUID-D8CCD2F0-18A3-42BB-A64D-539114A07DA0", + "TEXT": "GUID-62E5383D-8A14-47B4-BFC4-35824CAE8363", + "TOLERANCE": "GUID-ADFCED35-B312-4996-B4C1-61C53757B3FD", + "TRACE": "GUID-EA6FBCA8-1AD6-4FB2-B149-770313E93511", + "UNDERLAY": "GUID-3EC8FBCC-A85A-4B0B-93CD-C6C785959077", + "VERTEX": "GUID-0741E831-599E-4CBF-91E1-8ADBCFD6556D", + "VIEWPORT": "GUID-2602B0FB-02E4-4B9A-B03C-B1D904753D34", + "WIPEOUT": "GUID-2229F9C4-3C80-4C67-9EDA-45ED684808DC", + "XLINE": "GUID-55080553-34B6-40AA-9EE2-3F3A3A2A5C0A", + "ACAD_PROXY_OBJECT": "GUID-F59F0EC3-D34D-4C1A-91AC-7FDA569EF016", + "ACDBDICTIONARYWDFLT": "GUID-A6605C05-1CF4-42A4-95EC-42190B2424EE", + "ACDBPLACEHOLDER": "GUID-3BC75FF1-6139-49F4-AEBB-AE2AB4F437E4", + "DATATABLE": "GUID-D09D0650-B926-40DD-A2F2-4FD5BDDFC330", + "DICTIONARY": "GUID-40B92C63-26F0-485B-A9C2-B349099B26D0", + "DICTIONARYVAR": "GUID-D305303C-F9CE-4714-9C92-607BFDA891B4", + "DIMASSOC": "GUID-C0B96256-A911-4B4D-85E6-EB4AF2C91E27", + "FIELD": "GUID-51B921F2-16CA-4948-AC75-196198DD1796", + "GEODATA": "GUID-104FE0E2-4801-4AC8-B92C-1DDF5AC7AB64", + "GROUP": "GUID-5F1372C4-37C8-4056-9303-EE1715F58E67", + "IDBUFFER": "GUID-7A243F2B-72D8-4C48-A29A-3F251B86D03F", + "IMAGEDEF": "GUID-EFE5319F-A71A-4612-9431-42B6C7C3941F", + "IMAGEDEF_REACTOR": "GUID-46C12333-1EDA-4619-B2C9-D7D2607110C8", + "LAYER_INDEX": "GUID-17560B05-31B9-44A5-BA92-E92C799398C0", + "LAYER_FILTER": "GUID-3B44DCFD-FA96-482B-8468-37B3C5B5F289", + "LAYOUT": "GUID-433D25BF-655D-4697-834E-C666EDFD956D", + "LIGHTLIST": "GUID-C4E7FFF8-C3ED-43DD-854D-304F87FFCF06", + "MATERIAL": "GUID-E540C5BB-E166-44FA-B36C-5C739878B272", + "MLINESTYLE": "GUID-3EC12E5B-F5F6-484D-880F-D69EBE186D79", + "OBJECT_PTR": "GUID-6D6885E2-281C-410A-92FB-8F6A7F54C9DF", + "PLOTSETTINGS": "GUID-1113675E-AB07-4567-801A-310CDE0D56E9", + "RASTERVARIABLES": "GUID-DDCC21A4-822A-469B-9954-1E1EC4F6DF82", + "SPATIAL_INDEX": "GUID-CD1E44DA-CDBA-4AA7-B08E-C53F71648984", + "SPATIAL_FILTER": "GUID-34F179D8-2030-47E4-8D49-F87B6538A05A", + "SORTENTSTABLE": "GUID-462F4378-F850-4E89-90F2-3C1880F55779", + "SUNSTUDY": "GUID-1C7C073F-4CFD-4939-97D9-7AB0C1E163A3", + "TABLESTYLE": "GUID-0DBCA057-9F6C-4DEB-A66F-8A9B3C62FB1A", + "UNDERLAYDEFINITION": "GUID-A4FF15D3-F745-4E1F-94D4-1DC3DF297B0F", + "VISUALSTYLE": "GUID-8A8BF2C4-FC56-44EC-A8C4-A60CE33A530C", + "VBA_PROJECT": "GUID-F247DB75-5C4D-4944-8C20-1567480221F4", + "WIPEOUTVARIABLES": "GUID-CD28B95F-483C-4080-82A6-420606F88356", + "XRECORD": "GUID-24668FAF-AE03-41AE-AFA4-276C3692827F", +} + + +def get_reference_link(name: str) -> str: + guid = reference_guids.get(name, main_index_guid) + return link_tpl.format(guid=guid) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/tags.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/tags.py new file mode 100644 index 0000000..f6a75e5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/tags.py @@ -0,0 +1,71 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from typing import Iterable, Sequence + +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import ( + DXFTag, + DXFVertex, + POINT_CODES, + TYPE_TABLE, +) + + +def tag_compiler(tags: Tags) -> Iterable[DXFTag]: + """Special tag compiler for the DXF browser. + + This compiler should never fail and always return printable tags: + + - invalid point coordinates are returned as float("nan") + - invalid ints are returned as string + - invalid floats are returned as string + + """ + + def to_float(v: str) -> float: + try: + return float(v) + except ValueError: + return float("NaN") + + count = len(tags) + index = 0 + while index < count: + code, value = tags[index] + if code in POINT_CODES: + try: + y_code, y_value = tags[index + 1] + except IndexError: # x-coord as last tag + yield DXFTag(code, to_float(value)) + return + + if y_code != code + 10: # not an y-coord? + yield DXFTag(code, to_float(value)) # x-coord as single tag + index += 1 + continue + + try: + z_code, z_value = tags[index + 2] + except IndexError: # no z-coord exist + z_code = 0 + z_value = 0 + point: Sequence[float] + if z_code == code + 20: # is a z-coord? + point = (to_float(value), to_float(y_value), to_float(z_value)) + index += 3 + else: # a valid 2d point(x, y) + point = (to_float(value), to_float(y_value)) + index += 2 + yield DXFVertex(code, point) + else: # a single tag + try: + if code == 0: + value = value.strip() + yield DXFTag(code, TYPE_TABLE.get(code, str)(value)) + except ValueError: + yield DXFTag(code, str(value)) # just as string + index += 1 + + +def compile_tags(tags: Tags) -> Tags: + return Tags(tag_compiler(tags)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/views.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/views.py new file mode 100644 index 0000000..1796222 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/browser/views.py @@ -0,0 +1,41 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from ezdxf.addons.xqt import QTableView, QTreeView, QModelIndex +from ezdxf.lldxf.tags import Tags + + +class StructureTree(QTreeView): + def set_structure(self, model): + self.setModel(model) + self.expand(model.index(0, 0, QModelIndex())) + self.setHeaderHidden(True) + + def expand_to_entity(self, entity: Tags): + model = self.model() + index = model.index_of_entity(entity) # type: ignore + self.setCurrentIndex(index) + + +class DXFTagsTable(QTableView): + def __init__(self): + super().__init__() + col_header = self.horizontalHeader() + col_header.setStretchLastSection(True) + row_header = self.verticalHeader() + row_header.setDefaultSectionSize(24) # default row height in pixels + self.setSelectionBehavior(QTableView.SelectRows) + + def first_selected_row(self) -> int: + first_row: int = 0 + selection = self.selectedIndexes() + if selection: + first_row = selection[0].row() + return first_row + + def selected_rows(self) -> list[int]: + rows: set[int] = set() + selection = self.selectedIndexes() + for item in selection: + rows.add(item.row()) + return sorted(rows) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dimlines.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dimlines.py new file mode 100644 index 0000000..cb5a4f3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dimlines.py @@ -0,0 +1,766 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +"""Dimension lines as composite entities build up by DXF primitives. + +This add-on exist just for an easy transition from `dxfwrite` to `ezdxf`. + +Classes +------- + +- LinearDimension +- AngularDimension +- ArcDimension +- RadiusDimension +- DimStyle + +This code was written long before I had any understanding of the DIMENSION +entity and therefore, the classes have completely different implementations and +styling features than the dimensions based on the DIMENSION entity . + +.. warning:: + + Try to not use these classes beside porting `dxfwrite` code to `ezdxf` + and even for that case the usage of the regular DIMENSION entity is to + prefer because this module will not get much maintenance and may be removed + in the future. + +""" +from __future__ import annotations +from typing import Any, TYPE_CHECKING, Iterable, Optional +from math import radians, degrees, pi +from abc import abstractmethod +from ezdxf.enums import TextEntityAlignment +from ezdxf.math import Vec3, Vec2, distance, lerp, ConstructionRay, UVec + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.eztypes import GenericLayoutType + +DIMENSIONS_MIN_DISTANCE = 0.05 +DIMENSIONS_FLOATINGPOINT = "." + +ANGLE_DEG = 180.0 / pi +ANGLE_GRAD = 200.0 / pi +ANGLE_RAD = 1.0 + + +class DimStyle(dict): + """DimStyle parameter struct, a dumb object just to store values + """ + + default_values = [ + # tick block name, use setup to generate default blocks + ("tick", "DIMTICK_ARCH"), + # scale factor for ticks-block + ("tickfactor", 1.0), + # tick2x means tick is drawn only for one side, insert tick a second + # time rotated about 180 degree, but only one time at the dimension line + # ends, this is useful for arrow-like ticks. hint: set dimlineext to 0. + ("tick2x", False), + # dimension value scale factor, value = drawing-units * scale + ("scale", 100.0), + # round dimension value to roundval fractional digits + ("roundval", 0), + # round dimension value to half units, round 0.4, 0.6 to 0.5 + ("roundhalf", False), + # dimension value text color + ("textcolor", 7), + # dimension value text height + ("height", 0.5), + # dimension text prefix and suffix like 'x=' ... ' cm' + ("prefix", ""), + ("suffix", ""), + # dimension value text style + ("style", "OpenSansCondensed-Light"), + # default layer for whole dimension object + ("layer", "DIMENSIONS"), + # dimension line color index (0 from layer) + ("dimlinecolor", 7), + # dimension line extensions (in dimline direction, left and right) + ("dimlineext", 0.3), + # draw dimension value text `textabove` drawing-units above the + # dimension line + ("textabove", 0.2), + # switch extension line False=off, True=on + ("dimextline", True), + # dimension extension line color index (0 from layer) + ("dimextlinecolor", 5), + # gap between measure target point and end of extension line + ("dimextlinegap", 0.3), + ] + + def __init__(self, name: str, **kwargs): + super().__init__(DimStyle.default_values) + # dimstyle name + self["name"] = name + self.update(kwargs) + + def __getattr__(self, attr: str) -> Any: + return self[attr] + + def __setattr__(self, attr: str, value: Any) -> None: + self[attr] = value + + +class DimStyles: + """ + DimStyle container + + """ + + def __init__(self) -> None: + self._styles: dict[str, DimStyle] = {} + self.default = DimStyle("Default") + + self.new( + "angle.deg", + scale=ANGLE_DEG, + suffix=str("°"), + roundval=0, + tick="DIMTICK_RADIUS", + tick2x=True, + dimlineext=0.0, + dimextline=False, + ) + self.new( + "angle.grad", + scale=ANGLE_GRAD, + suffix="gon", + roundval=0, + tick="DIMTICK_RADIUS", + tick2x=True, + dimlineext=0.0, + dimextline=False, + ) + self.new( + "angle.rad", + scale=ANGLE_RAD, + suffix="rad", + roundval=3, + tick="DIMTICK_RADIUS", + tick2x=True, + dimlineext=0.0, + dimextline=False, + ) + + def get(self, name: str) -> DimStyle: + """ + Get DimStyle() object by name. + """ + return self._styles.get(name, self.default) + + def new(self, name: str, **kwargs) -> DimStyle: + """ + Create a new dimstyle + """ + style = DimStyle(name, **kwargs) + self._styles[name] = style + return style + + @staticmethod + def setup(drawing: "Drawing"): + """ + Insert necessary definitions into drawing: + + ticks: DIMTICK_ARCH, DIMTICK_DOT, DIMTICK_ARROW + """ + # default pen assignment: + # 1 : 1.40mm - red + # 2 : 0.35mm - yellow + # 3 : 0.70mm - green + # 4 : 0.50mm - cyan + # 5 : 0.13mm - blue + # 6 : 1.00mm - magenta + # 7 : 0.25mm - white/black + # 8, 9 : 2.00mm + # >=10 : 1.40mm + + dimcolor = { + "color": dimstyles.default.dimextlinecolor, + "layer": "BYBLOCK", + } + color4 = {"color": 4, "layer": "BYBLOCK"} + color7 = {"color": 7, "layer": "BYBLOCK"} + + block = drawing.blocks.new("DIMTICK_ARCH") + block.add_line(start=(0.0, +0.5), end=(0.0, -0.5), dxfattribs=dimcolor) + block.add_line(start=(-0.2, -0.2), end=(0.2, +0.2), dxfattribs=color4) + + block = drawing.blocks.new("DIMTICK_DOT") + block.add_line(start=(0.0, 0.5), end=(0.0, -0.5), dxfattribs=dimcolor) + block.add_circle(center=(0, 0), radius=0.1, dxfattribs=color4) + + block = drawing.blocks.new("DIMTICK_ARROW") + + block.add_line(start=(0.0, 0.5), end=(0.0, -0.50), dxfattribs=dimcolor) + block.add_solid([(0, 0), (0.3, 0.05), (0.3, -0.05)], dxfattribs=color7) + + block = drawing.blocks.new("DIMTICK_RADIUS") + block.add_solid( + [(0, 0), (0.3, 0.05), (0.25, 0.0), (0.3, -0.05)], dxfattribs=color7 + ) + + +dimstyles = DimStyles() # use this factory to create new dimstyles + + +class _DimensionBase: + """ + Abstract base class for dimension lines. + + """ + + def __init__(self, dimstyle: str, layer: str, roundval: int): + self.dimstyle = dimstyles.get(dimstyle) + self.layer = layer + self.roundval = roundval + + def prop(self, property_name: str) -> Any: + """ + Get dimension line properties by `property_name` with the possibility to override several properties. + """ + if property_name == "layer": + return self.layer if self.layer is not None else self.dimstyle.layer + elif property_name == "roundval": + return ( + self.roundval + if self.roundval is not None + else self.dimstyle.roundval + ) + else: # pass through self.dimstyle object DimStyle() + return self.dimstyle[property_name] + + def format_dimtext(self, dimvalue: float) -> str: + """ + Format the dimension text. + """ + dimtextfmt = "%." + str(self.prop("roundval")) + "f" + dimtext = dimtextfmt % dimvalue + if DIMENSIONS_FLOATINGPOINT in dimtext: + # remove successional zeros + dimtext.rstrip("0") + # remove floating point as last char + dimtext.rstrip(DIMENSIONS_FLOATINGPOINT) + return self.prop("prefix") + dimtext + self.prop("suffix") + + @abstractmethod + def render(self, layout: "GenericLayoutType"): + pass + + +class LinearDimension(_DimensionBase): + """ + Simple straight dimension line with two or more measure points, build with basic DXF entities. This is NOT a dxf + dimension entity. And This is a 2D element, so all z-values will be ignored! + + """ + + def __init__( + self, + pos: UVec, + measure_points: Iterable[UVec], + angle: float = 0.0, + dimstyle: str = "Default", + layer: Optional[str] = None, + roundval: Optional[int] = None, + ): + """ + LinearDimension Constructor. + + Args: + pos: location as (x, y) tuple of dimension line, line goes through this point + measure_points: list of points as (x, y) tuples to dimension (two or more) + angle: angle (in degree) of dimension line + dimstyle: dimstyle name, 'Default' - style is the default value + layer: dimension line layer, override the default value of dimstyle + roundval: count of decimal places + + """ + super().__init__(dimstyle, layer, roundval) # type: ignore + self.angle = angle + self.measure_points = list(measure_points) + self.text_override = [""] * self.section_count + self.dimlinepos = Vec3(pos) + self.layout = None + + def set_text(self, section: int, text: str) -> None: + """ + Set and override the text of the dimension text for the given dimension line section. + """ + self.text_override[section] = text + + def _setup(self) -> None: + """ + Calc setup values and determines the point order of the dimension line points. + """ + self.measure_points = [Vec3(point) for point in self.measure_points] + dimlineray = ConstructionRay(self.dimlinepos, angle=radians(self.angle)) + self.dimline_points = [ + self._get_point_on_dimline(point, dimlineray) + for point in self.measure_points + ] + self.point_order = self._indices_of_sorted_points(self.dimline_points) + self._build_vectors() + + def _get_dimline_point(self, index: int) -> UVec: + """ + Get point on the dimension line, index runs left to right. + """ + return self.dimline_points[self.point_order[index]] + + def _get_section_points(self, section: int) -> tuple[Vec3, Vec3]: + """ + Get start and end point on the dimension line of dimension section. + """ + return self._get_dimline_point(section), self._get_dimline_point( + section + 1 + ) + + def _get_dimline_bounds(self) -> tuple[Vec3, Vec3]: + """ + Get the first and the last point of dimension line. + """ + return self._get_dimline_point(0), self._get_dimline_point(-1) + + @property + def section_count(self) -> int: + """count of dimline sections""" + return len(self.measure_points) - 1 + + @property + def point_count(self) -> int: + """count of dimline points""" + return len(self.measure_points) + + def render(self, layout: "GenericLayoutType") -> None: + """build dimension line object with basic dxf entities""" + self._setup() + self._draw_dimline(layout) + if self.prop("dimextline"): + self._draw_extension_lines(layout) + self._draw_text(layout) + self._draw_ticks(layout) + + @staticmethod + def _indices_of_sorted_points(points: Iterable[UVec]) -> list[int]: + """get indices of points, for points sorted by x, y values""" + indexed_points = [(point, idx) for idx, point in enumerate(points)] + indexed_points.sort() + return [idx for point, idx in indexed_points] + + def _build_vectors(self) -> None: + """build unit vectors, parallel and normal to dimension line""" + point1, point2 = self._get_dimline_bounds() + self.parallel_vector = (Vec3(point2) - Vec3(point1)).normalize() + self.normal_vector = self.parallel_vector.orthogonal() + + @staticmethod + def _get_point_on_dimline(point: UVec, dimray: ConstructionRay) -> Vec3: + """get the measure target point projection on the dimension line""" + return dimray.intersect(dimray.orthogonal(point)) + + def _draw_dimline(self, layout: "GenericLayoutType") -> None: + """build dimension line entity""" + start_point, end_point = self._get_dimline_bounds() + + dimlineext = self.prop("dimlineext") + if dimlineext > 0: + start_point = start_point - (self.parallel_vector * dimlineext) + end_point = end_point + (self.parallel_vector * dimlineext) + + attribs = { + "color": self.prop("dimlinecolor"), + "layer": self.prop("layer"), + } + layout.add_line( + start=start_point, + end=end_point, + dxfattribs=attribs, + ) + + def _draw_extension_lines(self, layout: "GenericLayoutType") -> None: + """build the extension lines entities""" + dimextlinegap = self.prop("dimextlinegap") + attribs = { + "color": self.prop("dimlinecolor"), + "layer": self.prop("layer"), + } + + for dimline_point, target_point in zip( + self.dimline_points, self.measure_points + ): + if distance(dimline_point, target_point) > max( + dimextlinegap, DIMENSIONS_MIN_DISTANCE + ): + direction_vector = (target_point - dimline_point).normalize() + target_point = target_point - (direction_vector * dimextlinegap) + layout.add_line( + start=dimline_point, + end=target_point, + dxfattribs=attribs, + ) + + def _draw_text(self, layout: "GenericLayoutType") -> None: + """build the dimension value text entity""" + attribs = { + "height": self.prop("height"), + "color": self.prop("textcolor"), + "layer": self.prop("layer"), + "rotation": self.angle, + "style": self.prop("style"), + } + for section in range(self.section_count): + dimvalue_text = self._get_dimvalue_text(section) + insert_point = self._get_text_insert_point(section) + layout.add_text( + text=dimvalue_text, + dxfattribs=attribs, + ).set_placement( + insert_point, align=TextEntityAlignment.MIDDLE_CENTER + ) + + def _get_dimvalue_text(self, section: int) -> str: + """get the dimension value as text, distance from point1 to point2""" + override = self.text_override[section] + if len(override): + return override + point1, point2 = self._get_section_points(section) + + dimvalue = distance(point1, point2) * self.prop("scale") + return self.format_dimtext(dimvalue) + + def _get_text_insert_point(self, section: int) -> Vec3: + """get the dimension value text insert point""" + point1, point2 = self._get_section_points(section) + dist = self.prop("height") / 2.0 + self.prop("textabove") + return lerp(point1, point2) + (self.normal_vector * dist) + + def _draw_ticks(self, layout: "GenericLayoutType") -> None: + """insert the dimension line ticks, (markers on the dimension line)""" + attribs = { + "xscale": self.prop("tickfactor"), + "yscale": self.prop("tickfactor"), + "layer": self.prop("layer"), + } + + def add_tick(index: int, rotate: bool = False) -> None: + """build the insert-entity for the tick block""" + attribs["rotation"] = self.angle + (180.0 if rotate else 0.0) + layout.add_blockref( + insert=self._get_dimline_point(index), + name=self.prop("tick"), + dxfattribs=attribs, + ) + + if self.prop("tick2x"): + for index in range(0, self.point_count - 1): + add_tick(index, False) + for index in range(1, self.point_count): + add_tick(index, True) + else: + for index in range(self.point_count): + add_tick(index, False) + + +class AngularDimension(_DimensionBase): + """ + Draw an angle dimensioning line at dimline pos from start to end, dimension text is the angle build of the three + points start-center-end. + + """ + + DEG = ANGLE_DEG + GRAD = ANGLE_GRAD + RAD = ANGLE_RAD + + def __init__( + self, + pos: UVec, + center: UVec, + start: UVec, + end: UVec, + dimstyle: str = "angle.deg", + layer: Optional[str] = None, + roundval: Optional[int] = None, + ): + """ + AngularDimension constructor. + + Args: + pos: location as (x, y) tuple of dimension line, line goes through this point + center: center point as (x, y) tuple of angle + start: line from center to start is the first side of the angle + end: line from center to end is the second side of the angle + dimstyle: dimstyle name, 'Default' - style is the default value + layer: dimension line layer, override the default value of dimstyle + roundval: count of decimal places + + """ + super().__init__(dimstyle, layer, roundval) # type: ignore + self.dimlinepos = Vec3(pos) + self.center = Vec3(center) + self.start = Vec3(start) + self.end = Vec3(end) + + def _setup(self) -> None: + """setup calculation values""" + self.pos_radius = distance(self.center, self.dimlinepos) # type: float + self.radius = distance(self.center, self.start) # type: float + self.start_vector = (self.start - self.center).normalize() # type: Vec3 + self.end_vector = (self.end - self.center).normalize() # type: Vec3 + self.start_angle = self.start_vector.angle # type: float + self.end_angle = self.end_vector.angle # type: float + + def render(self, layout: "GenericLayoutType") -> None: + """build dimension line object with basic dxf entities""" + + self._setup() + self._draw_dimension_line(layout) + if self.prop("dimextline"): + self._draw_extension_lines(layout) + self._draw_dimension_text(layout) + self._draw_ticks(layout) + + def _draw_dimension_line(self, layout: "GenericLayoutType") -> None: + """draw the dimension line from start- to endangle.""" + layout.add_arc( + radius=self.pos_radius, + center=self.center, + start_angle=degrees(self.start_angle), + end_angle=degrees(self.end_angle), + dxfattribs={ + "layer": self.prop("layer"), + "color": self.prop("dimlinecolor"), + }, + ) + + def _draw_extension_lines(self, layout: "GenericLayoutType") -> None: + """build the extension lines entities""" + for vector in [self.start_vector, self.end_vector]: + layout.add_line( + start=self._get_extline_start(vector), + end=self._get_extline_end(vector), + dxfattribs={ + "layer": self.prop("layer"), + "color": self.prop("dimextlinecolor"), + }, + ) + + def _get_extline_start(self, vector: Vec3) -> Vec3: + return self.center + (vector * self.prop("dimextlinegap")) + + def _get_extline_end(self, vector: Vec3) -> Vec3: + return self.center + (vector * self.pos_radius) + + def _draw_dimension_text(self, layout: "GenericLayoutType") -> None: + attribs = { + "height": self.prop("height"), + "rotation": degrees( + (self.start_angle + self.end_angle) / 2 - pi / 2.0 + ), + "layer": self.prop("layer"), + "style": self.prop("style"), + "color": self.prop("textcolor"), + } + layout.add_text( + text=self._get_dimtext(), + dxfattribs=attribs, + ).set_placement( + self._get_text_insert_point(), + align=TextEntityAlignment.MIDDLE_CENTER, + ) + + def _get_text_insert_point(self) -> Vec3: + midvector = ((self.start_vector + self.end_vector) / 2.0).normalize() + length = ( + self.pos_radius + self.prop("textabove") + self.prop("height") / 2.0 + ) + return self.center + (midvector * length) + + def _draw_ticks(self, layout: "GenericLayoutType") -> None: + attribs = { + "xscale": self.prop("tickfactor"), + "yscale": self.prop("tickfactor"), + "layer": self.prop("layer"), + } + for vector, mirror in [ + (self.start_vector, False), + (self.end_vector, self.prop("tick2x")), + ]: + insert_point = self.center + (vector * self.pos_radius) + rotation = vector.angle + pi / 2.0 + attribs["rotation"] = degrees(rotation + (pi if mirror else 0.0)) + layout.add_blockref( + insert=insert_point, + name=self.prop("tick"), + dxfattribs=attribs, + ) + + def _get_dimtext(self) -> str: + # set scale = ANGLE_DEG for degrees (circle = 360 deg) + # set scale = ANGLE_GRAD for grad(circle = 400 grad) + # set scale = ANGLE_RAD for rad(circle = 2*pi) + angle = (self.end_angle - self.start_angle) * self.prop("scale") + return self.format_dimtext(angle) + + +class ArcDimension(AngularDimension): + """ + Arc is defined by start- and endpoint on arc and the center point, or by three points lying on the arc if acr3points + is True. Measured length goes from start- to endpoint. The dimension line goes through the dimlinepos. + + """ + + def __init__( + self, + pos: UVec, + center: UVec, + start: UVec, + end: UVec, + arc3points: bool = False, + dimstyle: str = "Default", + layer: Optional[str] = None, + roundval: Optional[int] = None, + ): + """ + Args: + pos: location as (x, y) tuple of dimension line, line goes through this point + center: center point of arc + start: start point of arc + end: end point of arc + arc3points: if **True** arc is defined by three points on the arc (center, start, end) + dimstyle: dimstyle name, 'Default' - style is the default value + layer: dimension line layer, override the default value of dimstyle + roundval: count of decimal places + + """ + super().__init__(pos, center, start, end, dimstyle, layer, roundval) + self.arc3points = arc3points + + def _setup(self) -> None: + super()._setup() + if self.arc3points: + self.center = center_of_3points_arc( + self.center, self.start, self.end + ) + + def _get_extline_start(self, vector: Vec3) -> Vec3: + return self.center + ( + vector * (self.radius + self.prop("dimextlinegap")) + ) + + def _get_extline_end(self, vector: Vec3) -> Vec3: + return self.center + (vector * self.pos_radius) + + def _get_dimtext(self) -> str: + arc_length = ( + (self.end_angle - self.start_angle) + * self.radius + * self.prop("scale") + ) + return self.format_dimtext(arc_length) + + +class RadialDimension(_DimensionBase): + """ + Draw a radius dimension line from `target` in direction of `center` with length drawing units. RadiusDimension has + a special tick!! + """ + + def __init__( + self, + center: UVec, + target: UVec, + length: float = 1.0, + dimstyle: str = "Default", + layer: Optional[str] = None, + roundval: Optional[int] = None, + ): + """ + Args: + center: center point of radius + target: target point of radius + length: length of radius arrow (drawing length) + dimstyle: dimstyle name, 'Default' - style is the default value + layer: dimension line layer, override the default value of dimstyle + roundval: count of decimal places + + """ + super().__init__(dimstyle, layer, roundval) # type: ignore + self.center = Vec3(center) + self.target = Vec3(target) + self.length = float(length) + + def _setup(self) -> None: + self.target_vector = ( + self.target - self.center + ).normalize() # type: Vec3 + self.radius = distance(self.center, self.target) # type: float + + def render(self, layout: "GenericLayoutType") -> None: + """build dimension line object with basic dxf entities""" + self._setup() + self._draw_dimension_line(layout) + self._draw_dimension_text(layout) + self._draw_ticks(layout) + + def _draw_dimension_line(self, layout: "GenericLayoutType") -> None: + start_point = self.center + ( + self.target_vector * (self.radius - self.length) + ) + layout.add_line( + start=start_point, + end=self.target, + dxfattribs={ + "color": self.prop("dimlinecolor"), + "layer": self.prop("layer"), + }, + ) + + def _draw_dimension_text(self, layout: "GenericLayoutType") -> None: + layout.add_text( + text=self._get_dimtext(), + dxfattribs={ + "height": self.prop("height"), + "rotation": self.target_vector.angle_deg, + "layer": self.prop("layer"), + "style": self.prop("style"), + "color": self.prop("textcolor"), + }, + ).set_placement( + self._get_insert_point(), align=TextEntityAlignment.MIDDLE_RIGHT + ) + + def _get_insert_point(self) -> Vec3: + return self.target - ( + self.target_vector * (self.length + self.prop("textabove")) + ) + + def _get_dimtext(self) -> str: + return self.format_dimtext(self.radius * self.prop("scale")) + + def _draw_ticks(self, layout: "GenericLayoutType") -> None: + layout.add_blockref( + insert=self.target, + name="DIMTICK_RADIUS", + dxfattribs={ + "rotation": self.target_vector.angle_deg + 180, + "xscale": self.prop("tickfactor"), + "yscale": self.prop("tickfactor"), + "layer": self.prop("layer"), + }, + ) + + +def center_of_3points_arc(point1: UVec, point2: UVec, point3: UVec) -> Vec2: + """ + Calc center point of 3 point arc. ConstructionCircle is defined by 3 points + on the circle: point1, point2 and point3. + """ + ray1 = ConstructionRay(point1, point2) + ray2 = ConstructionRay(point1, point3) + midpoint1 = lerp(point1, point2) + midpoint2 = lerp(point1, point3) + center_ray1 = ray1.orthogonal(midpoint1) + center_ray2 = ray2.orthogonal(midpoint2) + return center_ray1.intersect(center_ray2) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__init__.py new file mode 100644 index 0000000..344c82e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) 2020-2021, Matthew Broadway +# License: MIT License + +from .frontend import Frontend +from .properties import Properties, RenderContext, LayerProperties diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..f8cf7a3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/backend.cpython-312.pyc new file mode 100644 index 0000000..4192867 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/backend.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/config.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000..477424f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/config.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_backend.cpython-312.pyc new file mode 100644 index 0000000..c52fc70 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_backend.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_utils.cpython-312.pyc new file mode 100644 index 0000000..9f3874f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/debug_utils.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/dxf.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/dxf.cpython-312.pyc new file mode 100644 index 0000000..ffb8cc7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/dxf.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/file_output.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/file_output.cpython-312.pyc new file mode 100644 index 0000000..1b00684 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/file_output.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/frontend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/frontend.cpython-312.pyc new file mode 100644 index 0000000..3a36483 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/frontend.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/gfxproxy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/gfxproxy.cpython-312.pyc new file mode 100644 index 0000000..d82fe3c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/gfxproxy.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/hpgl2.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/hpgl2.cpython-312.pyc new file mode 100644 index 0000000..c6ba125 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/hpgl2.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/json.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/json.cpython-312.pyc new file mode 100644 index 0000000..34a4f04 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/json.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/layout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/layout.cpython-312.pyc new file mode 100644 index 0000000..201b37c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/layout.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/matplotlib.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/matplotlib.cpython-312.pyc new file mode 100644 index 0000000..3d3eea4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/matplotlib.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/mtext_complex.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/mtext_complex.cpython-312.pyc new file mode 100644 index 0000000..ef3f75c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/mtext_complex.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pipeline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pipeline.cpython-312.pyc new file mode 100644 index 0000000..4649ac8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pipeline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/properties.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/properties.cpython-312.pyc new file mode 100644 index 0000000..a11899e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/properties.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pymupdf.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pymupdf.cpython-312.pyc new file mode 100644 index 0000000..8c0ee27 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pymupdf.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pyqt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pyqt.cpython-312.pyc new file mode 100644 index 0000000..3dc6bfb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/pyqt.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/qtviewer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/qtviewer.cpython-312.pyc new file mode 100644 index 0000000..237d9fb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/qtviewer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/recorder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/recorder.cpython-312.pyc new file mode 100644 index 0000000..c960d3b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/recorder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/svg.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/svg.cpython-312.pyc new file mode 100644 index 0000000..959ef44 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/svg.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text.cpython-312.pyc new file mode 100644 index 0000000..2b1a873 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text_renderer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text_renderer.cpython-312.pyc new file mode 100644 index 0000000..dbff654 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/text_renderer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/type_hints.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/type_hints.cpython-312.pyc new file mode 100644 index 0000000..f61d5a1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/type_hints.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/unified_text_renderer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/unified_text_renderer.cpython-312.pyc new file mode 100644 index 0000000..92d4e80 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/__pycache__/unified_text_renderer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/backend.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/backend.py new file mode 100644 index 0000000..d71b434 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/backend.py @@ -0,0 +1,265 @@ +# Copyright (c) 2020-2023, Matthew Broadway +# License: MIT License +from __future__ import annotations +from abc import ABC, abstractmethod, ABCMeta +from typing import Optional, Iterable + +import numpy as np +from typing_extensions import TypeAlias +import dataclasses + +from ezdxf.addons.drawing.config import Configuration +from ezdxf.addons.drawing.properties import Properties, BackendProperties +from ezdxf.addons.drawing.type_hints import Color +from ezdxf.entities import DXFGraphic +from ezdxf.math import Vec2, Matrix44 +from ezdxf.npshapes import NumpyPath2d, NumpyPoints2d, single_paths + +BkPath2d: TypeAlias = NumpyPath2d +BkPoints2d: TypeAlias = NumpyPoints2d + +# fmt: off +_IMAGE_FLIP_MATRIX = [ + 1.0, 0.0, 0.0, 0.0, + 0.0, -1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 999, 0.0, 1.0 # index 13: 999 = image height +] +# fmt: on + + +@dataclasses.dataclass +class ImageData: + """Image data. + + Attributes: + image: an array of RGBA pixels + transform: the transformation to apply to the image when drawing + (the transform from pixel coordinates to wcs) + pixel_boundary_path: boundary path vertices in pixel coordinates, the image + coordinate system has an inverted y-axis and the top-left corner is (0, 0) + remove_outside: remove image outside the clipping boundary if ``True`` otherwise + remove image inside the clipping boundary + + """ + + image: np.ndarray + transform: Matrix44 + pixel_boundary_path: NumpyPoints2d + use_clipping_boundary: bool = False + remove_outside: bool = True + + def image_size(self) -> tuple[int, int]: + """Returns the image size as tuple (width, height).""" + image_height, image_width, *_ = self.image.shape + return image_width, image_height + + def flip_matrix(self) -> Matrix44: + """Returns the transformation matrix to align the image coordinate system with + the WCS. + """ + _, image_height = self.image_size() + _IMAGE_FLIP_MATRIX[13] = image_height + return Matrix44(_IMAGE_FLIP_MATRIX) + + +class BackendInterface(ABC): + """Public interface for 2D rendering backends.""" + + @abstractmethod + def configure(self, config: Configuration) -> None: + raise NotImplementedError + + @abstractmethod + def enter_entity(self, entity: DXFGraphic, properties: Properties) -> None: + # gets the full DXF properties information + raise NotImplementedError + + @abstractmethod + def exit_entity(self, entity: DXFGraphic) -> None: + raise NotImplementedError + + @abstractmethod + def set_background(self, color: Color) -> None: + raise NotImplementedError + + @abstractmethod + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + raise NotImplementedError + + @abstractmethod + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + raise NotImplementedError + + @abstractmethod + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + raise NotImplementedError + + @abstractmethod + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + raise NotImplementedError + + @abstractmethod + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + raise NotImplementedError + + @abstractmethod + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + raise NotImplementedError + + @abstractmethod + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + raise NotImplementedError + + @abstractmethod + def clear(self) -> None: + raise NotImplementedError + + @abstractmethod + def finalize(self) -> None: + raise NotImplementedError + + +class Backend(BackendInterface, metaclass=ABCMeta): + def __init__(self) -> None: + self.entity_stack: list[tuple[DXFGraphic, Properties]] = [] + self.config: Configuration = Configuration() + + def configure(self, config: Configuration) -> None: + self.config = config + + def enter_entity(self, entity: DXFGraphic, properties: Properties) -> None: + # gets the full DXF properties information + self.entity_stack.append((entity, properties)) + + def exit_entity(self, entity: DXFGraphic) -> None: + e, p = self.entity_stack.pop() + assert e is entity, "entity stack mismatch" + + @property + def current_entity(self) -> Optional[DXFGraphic]: + """Obtain the current entity being drawn""" + return self.entity_stack[-1][0] if self.entity_stack else None + + @abstractmethod + def set_background(self, color: Color) -> None: + raise NotImplementedError + + @abstractmethod + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + """Draw a real dimensionless point, because not all backends support + zero-length lines! + """ + raise NotImplementedError + + @abstractmethod + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + raise NotImplementedError + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + """Fast method to draw a bunch of solid lines with the same properties.""" + # Must be overridden by the backend to gain a performance benefit. + # This is the default implementation to ensure compatibility with + # existing backends. + for s, e in lines: + if e.isclose(s): + self.draw_point(s, properties) + else: + self.draw_line(s, e, properties) + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + """Draw an outline path (connected string of line segments and Bezier + curves). + + The :meth:`draw_path` implementation is a fall-back implementation + which approximates Bezier curves by flattening as line segments. + Backends can override this method if better path drawing functionality + is available for that backend. + + """ + if len(path): + vertices = iter( + path.flattening(distance=self.config.max_flattening_distance) + ) + prev = next(vertices) + for vertex in vertices: + self.draw_line(prev, vertex, properties) + prev = vertex + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + """Draw multiple filled paths (connected string of line segments and + Bezier curves). + + The current implementation passes these paths to the backend, all backends + included in ezdxf handle holes by the even-odd method. If a backend requires + oriented paths (exterior paths in counter-clockwise and holes in clockwise + orientation) use the function :func:`oriented_paths` to separate and orient the + input paths. + + The default implementation draws all paths as filled polygons. + + Args: + paths: sequence of paths + properties: HATCH properties + + """ + for path in paths: + self.draw_filled_polygon( + BkPoints2d( + path.flattening(distance=self.config.max_flattening_distance) + ), + properties, + ) + + @abstractmethod + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + """Fill a polygon whose outline is defined by the given points. + Used to draw entities with simple outlines where :meth:`draw_path` may + be an inefficient way to draw such a polygon. + """ + raise NotImplementedError + + @abstractmethod + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + """Draw an image with the given pixels.""" + raise NotImplementedError + + @abstractmethod + def clear(self) -> None: + """Clear the canvas. Does not reset the internal state of the backend. + Make sure that the previous drawing is finished before clearing. + + """ + raise NotImplementedError + + def finalize(self) -> None: + pass + + +def oriented_paths(paths: Iterable[BkPath2d]) -> tuple[list[BkPath2d], list[BkPath2d]]: + """Separate paths into exterior paths and holes. Exterior paths are oriented + counter-clockwise, holes are oriented clockwise. + """ + from ezdxf.path import winding_deconstruction, make_polygon_structure + + polygons = make_polygon_structure(single_paths(paths)) + external_paths: list[BkPath2d] + holes: list[BkPath2d] + external_paths, holes = winding_deconstruction(polygons) + for p in external_paths: + p.counter_clockwise() + for p in holes: + p.clockwise() + return external_paths, holes diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/config.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/config.py new file mode 100644 index 0000000..516e3bc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/config.py @@ -0,0 +1,292 @@ +# Copyright (c) 2021-2024, Matthew Broadway +# License: MIT License +from __future__ import annotations +from typing import Optional +import warnings +import dataclasses +from dataclasses import dataclass +from enum import Enum, auto + +from ezdxf import disassemble +from ezdxf.enums import Measurement +from .type_hints import Color + + +class LinePolicy(Enum): + """This enum is used to define how to render linetypes. + + .. note:: + + Text and shapes in linetypes are not supported. + + Attributes: + SOLID: draw all lines as solid regardless of the linetype style + ACCURATE: render styled lines as accurately as possible + APPROXIMATE: ignored since v0.18.1 - uses always ACCURATE by default + + """ + + SOLID = auto() + APPROXIMATE = auto() # ignored since v0.18.1 + ACCURATE = auto() + + +class ProxyGraphicPolicy(Enum): + """The action to take when an entity with a proxy graphic is encountered + + .. note:: + + To get proxy graphics support proxy graphics have to be loaded: + Set the global option :attr:`ezdxf.options.load_proxy_graphics` to + ``True``, which is the default value. + + This can not prevent drawing proxy graphic inside of blocks, + because this is beyond the domain of the drawing add-on! + + Attributes: + IGNORE: do not display proxy graphics (skip_entity will be called instead) + SHOW: if the entity cannot be rendered directly (e.g. if not implemented) + but a proxy is present: display the proxy + PREFER: display proxy graphics even for entities where direct rendering + is available + """ + + IGNORE = auto() + SHOW = auto() + PREFER = auto() + + +class HatchPolicy(Enum): + """The action to take when a HATCH entity is encountered + + Attributes: + NORMAL: render pattern and solid fillings + IGNORE: do not show HATCH entities at all + SHOW_OUTLINE: show only the outline of HATCH entities + SHOW_SOLID: show HATCH entities as solid filling regardless of the pattern + + """ + + NORMAL = auto() + IGNORE = auto() + SHOW_OUTLINE = auto() + SHOW_SOLID = auto() + SHOW_APPROXIMATE_PATTERN = auto() # ignored since v0.18.1 == NORMAL + + +class LineweightPolicy(Enum): + """This enum is used to define how to determine the lineweight. + + Attributes: + ABSOLUTE: in mm as resolved by the :class:`Frontend` class + RELATIVE: lineweight is relative to page size + RELATIVE_FIXED: fixed lineweight relative to page size for all strokes + + """ + + ABSOLUTE = auto() + # set fixed lineweight for all strokes in absolute mode: + # set Configuration.min_lineweight to the desired lineweight in 1/300 inch! + # set Configuration.lineweight_scaling to 0 + + # The RELATIVE policy is a backend feature and is not supported by all backends! + RELATIVE = auto() + RELATIVE_FIXED = auto() + + +class ColorPolicy(Enum): + """This enum is used to define how to determine the line/fill color. + + Attributes: + COLOR: as resolved by the :class:`Frontend` class + COLOR_SWAP_BW: as resolved by the :class:`Frontend` class but swaps black and white + COLOR_NEGATIVE: invert all colors + MONOCHROME: maps all colors to gray scale in range [0%, 100%] + MONOCHROME_DARK_BG: maps all colors to gray scale in range [30%, 100%], brightens + colors for dark backgrounds + MONOCHROME_LIGHT_BG: maps all colors to gray scale in range [0%, 70%], darkens + colors for light backgrounds + BLACK: maps all colors to black + WHITE: maps all colors to white + CUSTOM: maps all colors to custom color :attr:`Configuration.custom_fg_color` + + """ + + COLOR = auto() + COLOR_SWAP_BW = auto() + COLOR_NEGATIVE = auto() + MONOCHROME = auto() + MONOCHROME_DARK_BG = auto() + MONOCHROME_LIGHT_BG = auto() + BLACK = auto() + WHITE = auto() + CUSTOM = auto() + + +class BackgroundPolicy(Enum): + """This enum is used to define the background color. + + Attributes: + DEFAULT: as resolved by the :class:`Frontend` class + WHITE: white background + BLACK: black background + PAPERSPACE: default paperspace background + MODELSPACE: default modelspace background + OFF: fully transparent background + CUSTOM: custom background color by :attr:`Configuration.custom_bg_color` + + """ + + DEFAULT = auto() + WHITE = auto() + BLACK = auto() + PAPERSPACE = auto() + MODELSPACE = auto() + OFF = auto() + CUSTOM = auto() + + +class TextPolicy(Enum): + """This enum is used to define the text rendering. + + Attributes: + FILLING: text is rendered as solid filling (default) + OUTLINE: text is rendered as outline paths + REPLACE_RECT: replace text by a rectangle + REPLACE_FILL: replace text by a filled rectangle + IGNORE: ignore text entirely + + """ + + FILLING = auto() + OUTLINE = auto() + REPLACE_RECT = auto() + REPLACE_FILL = auto() + IGNORE = auto() + + +class ImagePolicy(Enum): + """This enum is used to define the image rendering. + + Attributes: + DISPLAY: display images as they would appear in a regular CAD application + RECT: display images as rectangles + MISSING: images are always rendered as-if they are missing (rectangle + path text) + PROXY: images are rendered using their proxy representations (rectangle) + IGNORE: ignore images entirely + + """ + + DISPLAY = auto() + RECT = auto() + MISSING = auto() + PROXY = auto() + IGNORE = auto() + + +@dataclass(frozen=True) +class Configuration: + """Configuration options for the :mod:`drawing` add-on. + + Attributes: + pdsize: the size to draw POINT entities (in drawing units) + set to None to use the $PDSIZE value from the dxf document header + + ======= ==================================================== + 0 5% of draw area height + <0 Specifies a percentage of the viewport size + >0 Specifies an absolute size + None use the $PDMODE value from the dxf document header + ======= ==================================================== + + pdmode: point styling mode (see POINT documentation) + + see :class:`~ezdxf.entities.Point` class documentation + + measurement: whether to use metric or imperial units as enum :class:`ezdxf.enums.Measurement` + + ======= ====================================================== + 0 use imperial units (in, ft, yd, ...) + 1 use metric units (ISO meters) + None use the $MEASUREMENT value from the dxf document header + ======= ====================================================== + + show_defpoints: whether to show or filter out POINT entities on the defpoints layer + proxy_graphic_policy: the action to take when a proxy graphic is encountered + line_policy: the method to use when drawing styled lines (eg dashed, + dotted etc) + hatch_policy: the method to use when drawing HATCH entities + infinite_line_length: the length to use when drawing infinite lines + lineweight_scaling: + multiplies every lineweight by this factor; set this factor to 0.0 for a + constant minimum line width defined by the :attr:`min_lineweight` setting + for all lineweights; + the correct DXF lineweight often looks too thick in SVG, so setting a + factor < 1 can improve the visual appearance + min_lineweight: the minimum line width in 1/300 inch; set to ``None`` for + let the backend choose. + min_dash_length: the minimum length for a dash when drawing a styled line + (default value is arbitrary) + max_flattening_distance: Max flattening distance in drawing units + see Path.flattening documentation. + The backend implementation should calculate an appropriate value, + like 1 screen- or paper pixel on the output medium, but converted + into drawing units. Sets Path() approximation accuracy + circle_approximation_count: Approximate a full circle by `n` segments, arcs + have proportional less segments. Only used for approximation of arcs + in banded polylines. + hatching_timeout: hatching timeout for a single entity, very dense + hatching patterns can cause a very long execution time, the default + timeout for a single entity is 30 seconds. + min_hatch_line_distance: minimum hatch line distance to render, narrower pattern + lines are rendered as solid filling + color_policy: + custom_fg_color: Used for :class:`ColorPolicy.custom` policy, custom foreground + color as "#RRGGBBAA" color string (RGB+alpha) + background_policy: + custom_bg_color: Used for :class:`BackgroundPolicy.custom` policy, custom + background color as "#RRGGBBAA" color string (RGB+alpha) + lineweight_policy: + text_policy: + image_policy: the method for drawing IMAGE entities + + """ + + pdsize: Optional[int] = None # use $PDSIZE from HEADER section + pdmode: Optional[int] = None # use $PDMODE from HEADER section + measurement: Optional[Measurement] = None + show_defpoints: bool = False + proxy_graphic_policy: ProxyGraphicPolicy = ProxyGraphicPolicy.SHOW + line_policy: LinePolicy = LinePolicy.ACCURATE + hatch_policy: HatchPolicy = HatchPolicy.NORMAL + infinite_line_length: float = 20 + lineweight_scaling: float = 1.0 + min_lineweight: Optional[float] = None + min_dash_length: float = 0.1 + max_flattening_distance: float = disassemble.Primitive.max_flattening_distance + circle_approximation_count: int = 128 + hatching_timeout: float = 30.0 + # Keep value in sync with ezdxf.render.hatching.MIN_HATCH_LINE_DISTANCE + min_hatch_line_distance: float = 1e-4 + color_policy: ColorPolicy = ColorPolicy.COLOR + custom_fg_color: Color = "#000000" + background_policy: BackgroundPolicy = BackgroundPolicy.DEFAULT + custom_bg_color: Color = "#ffffff" + lineweight_policy: LineweightPolicy = LineweightPolicy.ABSOLUTE + text_policy: TextPolicy = TextPolicy.FILLING + image_policy: ImagePolicy = ImagePolicy.DISPLAY + + @staticmethod + def defaults() -> Configuration: + warnings.warn( + "use Configuration() instead of Configuration.defaults()", + DeprecationWarning, + ) + return Configuration() + + def with_changes(self, **kwargs) -> Configuration: + """Returns a new frozen :class:`Configuration` object with modified values.""" + params = dataclasses.asdict(self) + for k, v in kwargs.items(): + params[k] = v + return Configuration(**params) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_backend.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_backend.py new file mode 100644 index 0000000..53ba884 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_backend.py @@ -0,0 +1,52 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable + +from ezdxf.math import Vec2 +from .properties import BackendProperties +from .backend import Backend, BkPath2d, BkPoints2d, ImageData +from .config import Configuration + + +class BasicBackend(Backend): + """The basic backend has no draw_path() support and approximates all curves + by lines. + """ + + def __init__(self): + super().__init__() + self.collector = [] + self.configure(Configuration()) + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.collector.append(("point", pos, properties)) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.collector.append(("line", start, end, properties)) + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + self.collector.append(("filled_polygon", points, properties)) + + def draw_image( + self, image_data: ImageData, properties: BackendProperties + ) -> None: + self.collector.append(("image", image_data, properties)) + + def set_background(self, color: str) -> None: + self.collector.append(("bgcolor", color)) + + def clear(self) -> None: + self.collector = [] + + +class PathBackend(BasicBackend): + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + self.collector.append(("path", path, properties)) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + self.collector.append(("filled_path", tuple(paths), properties)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_utils.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_utils.py new file mode 100644 index 0000000..8d78f29 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/debug_utils.py @@ -0,0 +1,15 @@ +# Copyright (c) 2020-2021, Matthew Broadway +# License: MIT License +from __future__ import annotations + +from ezdxf.addons.drawing.backend import BackendInterface +from ezdxf.addons.drawing.type_hints import Color +from ezdxf.math import Vec3 + + +def draw_rect(points: list[Vec3], color: Color, out: BackendInterface): + from ezdxf.addons.drawing.properties import BackendProperties + + props = BackendProperties(color=color) + for a, b in zip(points, points[1:]): + out.draw_line(a, b, props) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/dxf.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/dxf.py new file mode 100644 index 0000000..51ab311 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/dxf.py @@ -0,0 +1,223 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, TYPE_CHECKING, no_type_check +from functools import lru_cache +import enum +import numpy as np + +from ezdxf import colors +from ezdxf.lldxf.const import VALID_DXF_LINEWEIGHTS +from ezdxf.math import Vec2, BoundingBox2d, Matrix44 +from ezdxf.path import to_splines_and_polylines, to_hatches +from ezdxf.layouts import BaseLayout + +from .type_hints import Color +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import Configuration +from .properties import BackendProperties + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import Solid + + +class ColorMode(enum.Enum): + """This enum is used to define the color output mode of the :class:`DXFBackend`. + + Attributes: + ACI: the color is set as :ref:`ACI` and assigned by layer + RGB: the color is set as RGB true color value + + """ + + # Use color index as primary color + ACI = enum.auto() + + # Use always the RGB value + RGB = enum.auto() + + +DARK_COLOR_THRESHOLD = 0.2 +RGB_BLACK = colors.RGB(0, 0, 0) +BYLAYER = 256 + + +class DXFBackend(BackendInterface): + """The :class:`DXFBackend` creates simple DXF files of POINT, LINE, LWPOLYLINE and + HATCH entities. This backend does ot need any additional packages. + + Args: + layout: a DXF :class:`~ezdxf.layouts.BaseLayout` + color_mode: see :class:`ColorMode` + + """ + + def __init__( + self, layout: BaseLayout, color_mode: ColorMode = ColorMode.RGB + ) -> None: + assert layout.doc is not None, "valid DXF document required" + super().__init__() + self.layout = layout + self.doc = layout.doc + self.color_mode = color_mode + self.bg_color = RGB_BLACK + self.is_dark_bg = True + self._layers: dict[int, str] = dict() + self._dxfattribs: dict[int, dict] = dict() + + def set_background(self, color: Color) -> None: + self.bg_color = colors.RGB.from_hex(color) + self.is_dark_bg = self.bg_color.luminance < DARK_COLOR_THRESHOLD + + def get_layer_name(self, pen: int) -> str: + try: + return self._layers[pen] + except KeyError: + pass + + layer_name = f"PEN_{pen:03d}" + self._layers[pen] = layer_name + if not self.doc.layers.has_entry(layer_name): + self.doc.layers.add(layer_name, color=pen) + return layer_name + + def resolve_properties(self, properties: BackendProperties) -> dict: + key = hash(properties) + try: + return self._dxfattribs[key] + except KeyError: + pass + + rgb = properties.rgb + pen = properties.pen + if pen < 1 or pen > 255: + pen = 7 + aci = pen + if self.color_mode == ColorMode.ACI: + aci = BYLAYER + attribs = { + "color": aci, + "layer": self.get_layer_name(pen), + "lineweight": make_lineweight(properties.lineweight), + } + if self.color_mode == ColorMode.RGB: + attribs["true_color"] = colors.rgb2int(rgb) + + alpha = properties.color[7:9] + if alpha: + try: + f = int(alpha, 16) / 255 + except ValueError: + pass + else: + attribs["transparency"] = colors.float2transparency(f) + self._dxfattribs[key] = attribs + return attribs + + def set_solid_fill(self, hatch, properties: BackendProperties) -> None: + rgb: colors.RGB | None = None + aci = BYLAYER + if self.color_mode == ColorMode.RGB: + rgb = properties.rgb + aci = properties.pen + hatch.set_solid_fill(color=aci, style=0, rgb=rgb) + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.layout.add_point(pos, dxfattribs=self.resolve_properties(properties)) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.layout.add_line(start, end, dxfattribs=self.resolve_properties(properties)) + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + lines = list(lines) + if len(lines) == 0: + return + attribs = self.resolve_properties(properties) + for start, end in lines: + self.layout.add_line(start, end, dxfattribs=attribs) + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + attribs = self.resolve_properties(properties) + if path.has_curves: + for entity in to_splines_and_polylines(path, dxfattribs=attribs): # type: ignore + self.layout.add_entity(entity) + else: + self.layout.add_lwpolyline(path.control_vertices(), dxfattribs=attribs) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + attribs = self.resolve_properties(properties) + py_paths = [p.to_path() for p in paths] + for hatch in to_hatches(py_paths, dxfattribs=attribs): + self.layout.add_entity(hatch) + self.set_solid_fill(hatch, properties) + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + hatch = self.layout.add_hatch(dxfattribs=self.resolve_properties(properties)) + hatch.paths.add_polyline_path(points.vertices(), is_closed=True) + self.set_solid_fill(hatch, properties) + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + pass # TODO: not implemented + + def configure(self, config: Configuration) -> None: + pass + + def clear(self) -> None: + pass + + def finalize(self) -> None: + pass + + def enter_entity(self, entity, properties) -> None: + pass + + def exit_entity(self, entity) -> None: + pass + + +def alpha_to_transparency(alpha: int) -> float: + return colors.float2transparency(alpha / 255) + + +@lru_cache(maxsize=None) +def make_lineweight(width: float) -> int: + width_int = int(width * 100) + for lw in VALID_DXF_LINEWEIGHTS: + if width_int <= lw: + return lw + return VALID_DXF_LINEWEIGHTS[-1] + + +@no_type_check +def update_extents(doc: Drawing, bbox: BoundingBox2d) -> None: + doc.header["$EXTMIN"] = (bbox.extmin.x, bbox.extmin.y, 0) + doc.header["$EXTMAX"] = (bbox.extmax.x, bbox.extmax.y, 0) + + +def setup_paperspace(doc: Drawing, bbox: BoundingBox2d): + psp_size = bbox.size / 40.0 # plu to mm + psp_center = psp_size * 0.5 + psp = doc.paperspace() + psp.page_setup(size=(psp_size.x, psp_size.y), margins=(0, 0, 0, 0), units="mm") + psp.add_viewport( + center=psp_center, + size=(psp_size.x, psp_size.y), + view_center_point=bbox.center, + view_height=bbox.size.y, + status=2, + ) + + +def add_background(msp: BaseLayout, bbox: BoundingBox2d, color: colors.RGB) -> Solid: + v = bbox.rect_vertices() + bg = msp.add_solid( + [v[0], v[1], v[3], v[2]], dxfattribs={"true_color": colors.rgb2int(color)} + ) + return bg diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/file_output.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/file_output.py new file mode 100644 index 0000000..6a619c8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/file_output.py @@ -0,0 +1,228 @@ +import pathlib +import sys +from abc import ABC, abstractmethod +import subprocess +import os +import platform + +from ezdxf.addons.drawing.backend import BackendInterface + + +class FileOutputRenderBackend(ABC): + def __init__(self, dpi: float) -> None: + self._dpi = dpi + + @abstractmethod + def supported_formats(self) -> list[tuple[str, str]]: + raise NotImplementedError + + @abstractmethod + def default_format(self) -> str: + raise NotImplementedError + + @abstractmethod + def backend(self) -> BackendInterface: + raise NotImplementedError + + @abstractmethod + def save(self, output: pathlib.Path) -> None: + raise NotImplementedError + + +class MatplotlibFileOutput(FileOutputRenderBackend): + def __init__(self, dpi: float) -> None: + super().__init__(dpi) + + try: + import matplotlib.pyplot as plt + except ImportError: + raise ImportError("Matplotlib not found") from None + + from ezdxf.addons.drawing.matplotlib import MatplotlibBackend + + self._plt = plt + self._fig = plt.figure() + self._ax = self._fig.add_axes((0, 0, 1, 1)) + self._backend = MatplotlibBackend(self._ax) + + def supported_formats(self) -> list[tuple[str, str]]: + return list(self._fig.canvas.get_supported_filetypes().items()) + + def default_format(self) -> str: + return "png" + + def backend(self) -> BackendInterface: + return self._backend + + def save(self, output: pathlib.Path) -> None: + self._fig.savefig(output, dpi=self._dpi) + self._plt.close(self._fig) + + +class PyQtFileOutput(FileOutputRenderBackend): + def __init__(self, dpi: float) -> None: + super().__init__(dpi) + + try: + from ezdxf.addons.xqt import QtCore, QtGui, QtWidgets + from ezdxf.addons.drawing.pyqt import PyQtBackend + except ImportError: + raise ImportError("PyQt not found") from None + + self._qc = QtCore + self._qg = QtGui + self._qw = QtWidgets + self._app = QtWidgets.QApplication(sys.argv) + self._scene = QtWidgets.QGraphicsScene() + self._backend = PyQtBackend() + self._backend.set_scene(self._scene) + + def supported_formats(self) -> list[tuple[str, str]]: + # https://doc.qt.io/qt-6/qimage.html#reading-and-writing-image-files + return [ + ("bmp", "Windows Bitmap"), + ("jpg", "Joint Photographic Experts Group"), + ("jpeg", "Joint Photographic Experts Group"), + ("png", "Portable Network Graphics"), + ("ppm", "Portable Pixmap"), + ("xbm", "X11 Bitmap"), + ("xpm", "X11 Pixmap"), + ("svg", "Scalable Vector Graphics"), + ] + + def default_format(self) -> str: + return "png" + + def backend(self) -> BackendInterface: + return self._backend + + def save(self, output: pathlib.Path) -> None: + if output.suffix.lower() == ".svg": + from PySide6.QtSvg import QSvgGenerator + + generator = QSvgGenerator() + generator.setFileName(str(output)) + generator.setResolution(int(self._dpi)) + scene_rect = self._scene.sceneRect() + output_size = self._qc.QSize( + round(scene_rect.size().width()), round(scene_rect.size().height()) + ) + generator.setSize(output_size) + generator.setViewBox( + self._qc.QRect(0, 0, output_size.width(), output_size.height()) + ) + + painter = self._qg.QPainter() + + transform = self._qg.QTransform() + transform.scale(1, -1) + transform.translate(0, -output_size.height()) + + painter.begin(generator) + painter.setWorldTransform(transform, combine=True) + painter.setRenderHint(self._qg.QPainter.RenderHint.Antialiasing) + self._scene.render(painter) + painter.end() + + else: + + view = self._qw.QGraphicsView(self._scene) + view.setRenderHint(self._qg.QPainter.RenderHint.Antialiasing) + sizef: QRectF = self._scene.sceneRect() * self._dpi / 92 # type: ignore + image = self._qg.QImage( + self._qc.QSize(round(sizef.width()), round(sizef.height())), + self._qg.QImage.Format.Format_ARGB32, + ) + painter = self._qg.QPainter(image) + painter.setRenderHint(self._qg.QPainter.RenderHint.Antialiasing) + painter.fillRect(image.rect(), self._scene.backgroundBrush()) + self._scene.render(painter) + painter.end() + image.mirror(False, True) + image.save(str(output)) + + +class MuPDFFileOutput(FileOutputRenderBackend): + def __init__(self, dpi: float) -> None: + super().__init__(dpi) + + from ezdxf.addons.drawing.pymupdf import PyMuPdfBackend, is_pymupdf_installed + + if not is_pymupdf_installed: + raise ImportError("PyMuPDF not found") + self._backend = PyMuPdfBackend() + + def supported_formats(self) -> list[tuple[str, str]]: + # https://pymupdf.readthedocs.io/en/latest/pixmap.html#pixmapoutput + return [ + ("pdf", "Portable Document Format"), + ("svg", "Scalable Vector Graphics"), + ("jpg", "Joint Photographic Experts Group"), + ("jpeg", "Joint Photographic Experts Group"), + ("pam", "Portable Arbitrary Map"), + ("pbm", "Portable Bitmap"), + ("pgm", "Portable Graymap"), + ("png", "Portable Network Graphics"), + ("pnm", "Portable Anymap"), + ("ppm", "Portable Pixmap (no alpha channel)"), + ("ps", "Adobe PostScript Image"), + ("psd", "Adobe Photoshop Document"), + ] + + def default_format(self) -> str: + return "pdf" + + def backend(self) -> BackendInterface: + return self._backend + + def save(self, output: pathlib.Path) -> None: + from ezdxf.addons.drawing import layout + + backend = self._backend.get_replay(layout.Page(0, 0)) + if output.suffix == ".pdf": + output.write_bytes(backend.get_pdf_bytes()) + elif output.suffix == ".svg": + output.write_text(backend.get_svg_image()) + else: + pixmap = backend.get_pixmap(int(self._dpi), alpha=True) + pixmap.save(str(output)) + + +class SvgFileOutput(FileOutputRenderBackend): + def __init__(self, dpi: float) -> None: + super().__init__(dpi) + + from ezdxf.addons.drawing.svg import SVGBackend + + self._backend = SVGBackend() + + def supported_formats(self) -> list[tuple[str, str]]: + return [("svg", "Scalable Vector Graphics")] + + def default_format(self) -> str: + return "svg" + + def backend(self) -> BackendInterface: + return self._backend + + def save(self, output: pathlib.Path) -> None: + from ezdxf.addons.drawing import layout + + output.write_text(self._backend.get_string(layout.Page(0, 0))) + + +def open_file(path: pathlib.Path) -> None: + """open the given path in the default application""" + system = platform.system() + if system == "Darwin": + subprocess.call( + ["open", str(path)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL + ) + elif system == "Windows": + os.startfile(str(path)) # type: ignore + else: + subprocess.call( + ["xdg-open", str(path)], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/frontend.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/frontend.py new file mode 100644 index 0000000..c437e3c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/frontend.py @@ -0,0 +1,1097 @@ +# Copyright (c) 2020-2024, Matthew Broadway +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + cast, + Union, + Dict, + Callable, + Optional, + TYPE_CHECKING, +) +from typing_extensions import TypeAlias +import contextlib +import math +import os +import pathlib +import logging +import time + +import PIL.Image +import PIL.ImageEnhance +import PIL.ImageDraw +import numpy as np + + +import ezdxf.bbox +from ezdxf.addons.drawing.config import ( + Configuration, + ProxyGraphicPolicy, + HatchPolicy, + ImagePolicy, +) +from ezdxf.addons.drawing.backend import BackendInterface, ImageData +from ezdxf.addons.drawing.properties import ( + RenderContext, + OLE2FRAME_COLOR, + Properties, + Filling, + LayoutProperties, + MODEL_SPACE_BG_COLOR, + PAPER_SPACE_BG_COLOR, +) +from ezdxf.addons.drawing.config import BackgroundPolicy, TextPolicy +from ezdxf.addons.drawing.text import simplified_text_chunks +from ezdxf.addons.drawing.type_hints import FilterFunc +from ezdxf.addons.drawing.gfxproxy import DXFGraphicProxy +from ezdxf.addons.drawing.mtext_complex import complex_mtext_renderer +from ezdxf.entities import ( + DXFEntity, + DXFGraphic, + Insert, + MText, + Polyline, + LWPolyline, + Text, + Polyface, + Wipeout, + Solid, + Face3d, + OLE2Frame, + Point, + Viewport, + Image, +) +from ezdxf.tools import clipping_portal +from ezdxf.entities.attrib import BaseAttrib +from ezdxf.entities.polygon import DXFPolygon +from ezdxf.entities.boundary_paths import AbstractBoundaryPath +from ezdxf.layouts import Layout +from ezdxf.math import Vec2, Vec3, OCS, NULLVEC, Matrix44 +from ezdxf.path import ( + Path, + make_path, + from_hatch_boundary_path, + from_vertices, +) +from ezdxf.render import MeshBuilder, TraceBuilder +from ezdxf import reorder +from ezdxf.proxygraphic import ProxyGraphic, ProxyGraphicError +from ezdxf.protocols import SupportsVirtualEntities, virtual_entities +from ezdxf.tools.text import has_inline_formatting_codes +from ezdxf.tools import text_layout +from ezdxf.lldxf import const +from ezdxf.render import hatching +from ezdxf.fonts import fonts +from ezdxf.colors import RGB, RGBA +from ezdxf.npshapes import NumpyPoints2d +from ezdxf import xclip + +from .type_hints import Color + +if TYPE_CHECKING: + from .pipeline import AbstractPipeline + +__all__ = ["Frontend", "UniversalFrontend"] + +TEntityFunc: TypeAlias = Callable[[DXFGraphic, Properties], None] +TDispatchTable: TypeAlias = Dict[str, TEntityFunc] + +POST_ISSUE_MSG = ( + "Please post sample DXF file at https://github.com/mozman/ezdxf/issues." +) +logger = logging.getLogger("ezdxf") + + +class UniversalFrontend: + """Drawing frontend, responsible for decomposing entities into graphic + primitives and resolving entity properties. Supports 2D and 3D backends. + + By passing the bounding box cache of the modelspace entities can speed up + paperspace rendering, because the frontend can filter entities which are not + visible in the VIEWPORT. Even passing in an empty cache can speed up + rendering time when multiple viewports need to be processed. + + Args: + ctx: the properties relevant to rendering derived from a DXF document + designer: connection between frontend and backend + config: settings to configure the drawing frontend and backend + bbox_cache: bounding box cache of the modelspace entities or an empty + cache which will be filled dynamically when rendering multiple + viewports or ``None`` to disable bounding box caching at all + + """ + + def __init__( + self, + ctx: RenderContext, + pipeline: AbstractPipeline, + config: Configuration = Configuration(), + bbox_cache: Optional[ezdxf.bbox.Cache] = None, + ): + # RenderContext contains all information to resolve resources for a + # specific DXF document. + self.ctx = ctx + + # the render pipeline is the connection between frontend and backend + self.pipeline = pipeline + pipeline.set_draw_entities_callback(self.draw_entities_callback) + + # update all configs: + self.config = ctx.update_configuration(config) + # backend.configure() is called in pipeline.set_config() + pipeline.set_config(self.config) + + if self.config.pdsize is None or self.config.pdsize <= 0: + self.log_message("relative point size is not supported") + self.config = self.config.with_changes(pdsize=1) + + # Parents entities of current entity/sub-entity + self.parent_stack: list[DXFGraphic] = [] + + self._dispatch = self._build_dispatch_table() + + # Supported DXF entities which use only proxy graphic for rendering: + self._proxy_graphic_only_entities: set[str] = { + "MLEADER", # todo: remove if MLeader.virtual_entities() is implemented + "MULTILEADER", + "ACAD_PROXY_ENTITY", + } + + # Optional bounding box cache, which maybe was created by detecting the + # modelspace extends. This cache is used when rendering VIEWPORT + # entities in paperspace to detect if an entity is even visible, + # this can speed up rendering time if multiple viewports are present. + # If the bbox_cache is not ``None``, entities not in cache will be + # added dynamically. This is only beneficial when rendering multiple + # viewports, as the upfront bounding box calculation adds some rendering + # time. + self._bbox_cache = bbox_cache + + # Entity property override function stack: + self._property_override_functions: list[TEntityFunc] = [] + self.push_property_override_function(self.override_properties) + + @property + def text_engine(self): + return self.pipeline.text_engine + + def _build_dispatch_table(self) -> TDispatchTable: + dispatch_table: TDispatchTable = { + "POINT": self.draw_point_entity, + "HATCH": self.draw_hatch_entity, + "MPOLYGON": self.draw_mpolygon_entity, + "MESH": self.draw_mesh_entity, + "WIPEOUT": self.draw_wipeout_entity, + "MTEXT": self.draw_mtext_entity, + "OLE2FRAME": self.draw_ole2frame_entity, + "IMAGE": self.draw_image_entity, + } + for dxftype in ("LINE", "XLINE", "RAY"): + dispatch_table[dxftype] = self.draw_line_entity + for dxftype in ("TEXT", "ATTRIB", "ATTDEF"): + dispatch_table[dxftype] = self.draw_text_entity + for dxftype in ("CIRCLE", "ARC", "ELLIPSE", "SPLINE"): + dispatch_table[dxftype] = self.draw_curve_entity + for dxftype in ("3DFACE", "SOLID", "TRACE"): + dispatch_table[dxftype] = self.draw_solid_entity + for dxftype in ("POLYLINE", "LWPOLYLINE"): + dispatch_table[dxftype] = self.draw_polyline_entity + # Composite entities are detected by implementing the + # __virtual_entities__() protocol. + return dispatch_table + + def log_message(self, message: str): + """Log given message - override to alter behavior.""" + logger.info(message) + + def skip_entity(self, entity: DXFEntity, msg: str) -> None: + """Called for skipped entities - override to alter behavior.""" + self.log_message(f'skipped entity {str(entity)}. Reason: "{msg}"') + + def exec_property_override( + self, entity: DXFGraphic, properties: Properties + ) -> None: + """Execute entity property override functions. (internal API)""" + for override_fn in self._property_override_functions: + override_fn(entity, properties) + + def override_properties(self, entity: DXFGraphic, properties: Properties) -> None: + """This method can change the resolved properties of an DXF entity. + + The method has access to the DXF entity attributes, the current render context + and the resolved properties. It is recommended to modify only the resolved + `properties` in this method, because the DXF entities are not copies - except + for virtual entities. + + .. versionchanged:: 1.3.0 + + This method is the first function in the stack of new property override + functions. It is possible to push additional override functions onto this + stack, see also :meth:`push_property_override_function`. + + """ + + def push_property_override_function(self, override_fn: TEntityFunc) -> None: + """The override function can change the resolved properties of an DXF entity. + + The override function has access to the DXF entity attributes and the resolved + properties. It is recommended to modify only the resolved `properties` in this + function, because the DXF entities are not copies - except for virtual entities. + + The override functions are called after resolving the DXF attributes of an entity + and before the :meth:`Frontend.draw_entity` method in the order from first to + last. + + .. versionadded:: 1.3.0 + + """ + self._property_override_functions.append(override_fn) + + def pop_property_override_function(self) -> None: + """Remove the last function from the property override stack. + + Does not raise an exception if the override stack is empty. + + .. versionadded:: 1.3.0 + + """ + if self._property_override_functions: + self._property_override_functions.pop() + + def draw_layout( + self, + layout: Layout, + finalize: bool = True, + *, + filter_func: Optional[FilterFunc] = None, + layout_properties: Optional[LayoutProperties] = None, + ) -> None: + """Draw all entities of the given `layout`. + + Draws the entities of the layout in the default or redefined redraw-order + and calls the :meth:`finalize` method of the backend if requested. + The default redraw order is the ascending handle order not the order the + entities are stored in the layout. + + The method skips invisible entities and entities for which the given + filter function returns ``False``. + + Args: + layout: layout to draw of type :class:`~ezdxf.layouts.Layout` + finalize: ``True`` if the :meth:`finalize` method of the backend + should be called automatically + filter_func: function to filter DXf entities, the function should + return ``False`` if a given entity should be ignored + layout_properties: override the default layout properties + + """ + if layout_properties is not None: + self.ctx.current_layout_properties = layout_properties + else: + self.ctx.set_current_layout(layout) + # set background before drawing entities + self.set_background(self.ctx.current_layout_properties.background_color) + self.parent_stack = [] + handle_mapping = list(layout.get_redraw_order()) + if handle_mapping: + self.draw_entities( + reorder.ascending(layout, handle_mapping), + filter_func=filter_func, + ) + else: + self.draw_entities( + layout, + filter_func=filter_func, + ) + if finalize: + self.pipeline.finalize() + + def set_background(self, color: Color) -> None: + policy = self.config.background_policy + override = True + if policy == BackgroundPolicy.DEFAULT: + override = False + elif policy == BackgroundPolicy.OFF: + color = "#ffffff00" # white, fully transparent + elif policy == BackgroundPolicy.WHITE: + color = "#ffffff" + elif policy == BackgroundPolicy.BLACK: + color = "#000000" + elif policy == BackgroundPolicy.PAPERSPACE: + color = PAPER_SPACE_BG_COLOR + elif policy == BackgroundPolicy.MODELSPACE: + color = MODEL_SPACE_BG_COLOR + elif policy == BackgroundPolicy.CUSTOM: + color = self.config.custom_bg_color + if override: + self.ctx.current_layout_properties.set_colors(color) + self.pipeline.set_background(color) + + def draw_entities( + self, + entities: Iterable[DXFGraphic], + *, + filter_func: Optional[FilterFunc] = None, + ) -> None: + """Draw the given `entities`. The method skips invisible entities + and entities for which the given filter function returns ``False``. + + """ + _draw_entities(self, self.ctx, entities, filter_func=filter_func) + + def draw_entities_callback( + self, ctx: RenderContext, entities: Iterable[DXFGraphic] + ) -> None: + _draw_entities(self, ctx, entities) + + def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None: + """Draw a single DXF entity. + + Args: + entity: DXF entity inherited from DXFGraphic() + properties: resolved entity properties + + """ + self.pipeline.enter_entity(entity, properties) + if not entity.is_virtual: + # top level entity + self.pipeline.set_current_entity_handle(entity.dxf.handle) + if ( + entity.proxy_graphic + and self.config.proxy_graphic_policy == ProxyGraphicPolicy.PREFER + ): + self.draw_proxy_graphic(entity.proxy_graphic, entity.doc) + else: + draw_method = self._dispatch.get(entity.dxftype(), None) + if draw_method is not None: + draw_method(entity, properties) + # Composite entities (INSERT, DIMENSION, ...) have to implement the + # __virtual_entities__() protocol. + # Unsupported DXF types which have proxy graphic, are wrapped into + # DXFGraphicProxy, which also implements the __virtual_entities__() + # protocol. + elif isinstance(entity, SupportsVirtualEntities): + assert isinstance(entity, DXFGraphic) + # The __virtual_entities__() protocol does not distinguish + # content from DXF entities or from proxy graphic. + # In the long run ACAD_PROXY_ENTITY should be the only + # supported DXF entity which uses proxy graphic. Unsupported + # DXF entities (DXFGraphicProxy) do not get to this point if + # proxy graphic is ignored. + if ( + self.config.proxy_graphic_policy != ProxyGraphicPolicy.IGNORE + or entity.dxftype() not in self._proxy_graphic_only_entities + ): + self.draw_composite_entity(entity, properties) + else: + self.skip_entity(entity, "unsupported") + + self.pipeline.exit_entity(entity) + + def draw_line_entity(self, entity: DXFGraphic, properties: Properties) -> None: + d, dxftype = entity.dxf, entity.dxftype() + if dxftype == "LINE": + self.pipeline.draw_line(d.start, d.end, properties) + + elif dxftype in ("XLINE", "RAY"): + start = d.start + delta = d.unit_vector * self.config.infinite_line_length + if dxftype == "XLINE": + self.pipeline.draw_line( + start - delta / 2, start + delta / 2, properties + ) + elif dxftype == "RAY": + self.pipeline.draw_line(start, start + delta, properties) + else: + raise TypeError(dxftype) + + def draw_text_entity(self, entity: DXFGraphic, properties: Properties) -> None: + if self.config.text_policy == TextPolicy.IGNORE: + return + # Draw embedded MTEXT entity as virtual MTEXT entity: + if isinstance(entity, BaseAttrib) and entity.has_embedded_mtext_entity: + self.draw_mtext_entity(entity.virtual_mtext_entity(), properties) + elif is_spatial_text(Vec3(entity.dxf.extrusion)): + self.draw_text_entity_3d(entity, properties) + else: + self.draw_text_entity_2d(entity, properties) + + def get_font_face(self, properties: Properties) -> fonts.FontFace: + font_face = properties.font + if font_face is None: + return self.pipeline.default_font_face + return font_face + + def draw_text_entity_2d(self, entity: DXFGraphic, properties: Properties) -> None: + if isinstance(entity, Text): + for line, transform, cap_height in simplified_text_chunks( + entity, self.text_engine, font_face=self.get_font_face(properties) + ): + self.pipeline.draw_text( + line, transform, properties, cap_height, entity.dxftype() + ) + else: + raise TypeError(entity.dxftype()) + + def draw_text_entity_3d(self, entity: DXFGraphic, properties: Properties) -> None: + self.skip_entity(entity, "3D text not supported") + + def draw_mtext_entity(self, entity: DXFGraphic, properties: Properties) -> None: + if self.config.text_policy == TextPolicy.IGNORE: + return + mtext = cast(MText, entity) + if is_spatial_text(Vec3(mtext.dxf.extrusion)): + self.skip_entity(mtext, "3D MTEXT not supported") + return + if mtext.has_columns or has_inline_formatting_codes(mtext.text): + try: + self.draw_complex_mtext(mtext, properties) + except text_layout.LayoutError as e: + print(f"skipping {str(mtext)} - {str(e)}") + else: + self.draw_simple_mtext(mtext, properties) + + def draw_simple_mtext(self, mtext: MText, properties: Properties) -> None: + """Draw the content of a MTEXT entity without inline formatting codes.""" + for line, transform, cap_height in simplified_text_chunks( + mtext, self.text_engine, font_face=self.get_font_face(properties) + ): + self.pipeline.draw_text( + line, transform, properties, cap_height, mtext.dxftype() + ) + + def draw_complex_mtext(self, mtext: MText, properties: Properties) -> None: + """Draw the content of a MTEXT entity including inline formatting codes.""" + complex_mtext_renderer(self.ctx, self.pipeline, mtext, properties) + + def draw_curve_entity(self, entity: DXFGraphic, properties: Properties) -> None: + try: + path = make_path(entity) + except AttributeError: # API usage error + raise TypeError(f"Unsupported DXF type {entity.dxftype()}") + self.pipeline.draw_path(path, properties) + + def draw_point_entity(self, entity: DXFGraphic, properties: Properties) -> None: + point = cast(Point, entity) + pdmode = self.config.pdmode + pdsize = self.config.pdsize + assert pdmode is not None + assert pdsize is not None + + # Defpoints are regular POINT entities located at the "defpoints" layer: + if properties.layer.lower() == "defpoints": + if not self.config.show_defpoints: + return + else: # Render defpoints as dimensionless points: + pdmode = 0 + + if pdmode == 0: + self.pipeline.draw_point(entity.dxf.location, properties) + else: + for entity in point.virtual_entities(pdsize, pdmode): + dxftype = entity.dxftype() + if dxftype == "LINE": + start = entity.dxf.start + end = entity.dxf.end + if start.isclose(end): + self.pipeline.draw_point(start, properties) + else: # direct draw by backend is OK! + self.pipeline.draw_line(start, end, properties) + pass + elif dxftype == "CIRCLE": + self.draw_curve_entity(entity, properties) + else: + raise ValueError(dxftype) + + def draw_solid_entity(self, entity: DXFGraphic, properties: Properties) -> None: + if isinstance(entity, Face3d): + dxf = entity.dxf + try: + # this implementation supports all features of example file: + # examples_dxf/3dface.dxf without changing the behavior of + # Face3d.wcs_vertices() which removes the last vertex if + # duplicated. + points = [dxf.vtx0, dxf.vtx1, dxf.vtx2, dxf.vtx3, dxf.vtx0] + except AttributeError: + # all 4 vertices are required, otherwise the entity is invalid + # for AutoCAD + self.skip_entity(entity, "missing required vertex attribute") + return + edge_visibility = entity.get_edges_visibility() + if all(edge_visibility): + self.pipeline.draw_path(from_vertices(points), properties) + else: + for a, b, visible in zip(points, points[1:], edge_visibility): + if visible: + self.pipeline.draw_line(a, b, properties) + + elif isinstance(entity, Solid): + # set solid fill type for SOLID and TRACE + properties.filling = Filling() + self.pipeline.draw_filled_polygon( + entity.wcs_vertices(close=False), properties + ) + else: + raise TypeError("API error, requires a SOLID, TRACE or 3DFACE entity") + + def draw_hatch_pattern( + self, polygon: DXFPolygon, paths: list[Path], properties: Properties + ): + if polygon.pattern is None or len(polygon.pattern.lines) == 0: + return + ocs = polygon.ocs() + elevation = polygon.dxf.elevation.z + properties.linetype_pattern = tuple() + lines: list[tuple[Vec3, Vec3]] = [] + + t0 = time.perf_counter() + max_time = self.config.hatching_timeout + + def timeout() -> bool: + if time.perf_counter() - t0 > max_time: + print( + f"hatching timeout of {max_time}s reached for {str(polygon)} - aborting" + ) + return True + return False + + for baseline in hatching.pattern_baselines( + polygon, + min_hatch_line_distance=self.config.min_hatch_line_distance, + jiggle_origin=True, + ): + for line in hatching.hatch_paths(baseline, paths, timeout): + line_pattern = baseline.pattern_renderer(line.distance) + for s, e in line_pattern.render(line.start, line.end): + if ocs.transform: + s, e = ( + ocs.to_wcs((s.x, s.y, elevation)), + ocs.to_wcs((e.x, e.y, elevation)), + ) + lines.append((s, e)) + self.pipeline.draw_solid_lines(lines, properties) + + def draw_hatch_entity( + self, + entity: DXFGraphic, + properties: Properties, + *, + loops: Optional[list[Path]] = None, + ) -> None: + if properties.filling is None: + return + filling = properties.filling + show_only_outline = False + hatch_policy = self.config.hatch_policy + if hatch_policy == HatchPolicy.NORMAL: + pass + elif hatch_policy == HatchPolicy.IGNORE: + return + elif hatch_policy == HatchPolicy.SHOW_SOLID: + filling = Filling() # solid filling + elif hatch_policy == HatchPolicy.SHOW_OUTLINE: + filling = Filling() # solid filling + show_only_outline = True + + polygon = cast(DXFPolygon, entity) + if filling.type == Filling.PATTERN: + if loops is None: + loops = hatching.hatch_boundary_paths(polygon, filter_text_boxes=True) + try: + self.draw_hatch_pattern(polygon, loops, properties) + except hatching.DenseHatchingLinesError: + pass # fallthrough to solid fill rendering + else: + return + + # draw SOLID filling + ocs = polygon.ocs() + # all OCS coordinates have the same z-axis stored as vector (0, 0, z), + # default (0, 0, 0) + elevation = entity.dxf.elevation.z + paths: list[Path] + if loops is not None: # only MPOLYGON + paths = loops + else: # only HATCH + boundary_paths = list( + polygon.paths.rendering_paths(polygon.dxf.hatch_style) + ) + paths = closed_loops(boundary_paths, ocs, elevation) + if show_only_outline: + for p in ignore_text_boxes(paths): + self.pipeline.draw_path(p, properties) + return + if paths: + self.pipeline.draw_filled_paths(ignore_text_boxes(paths), properties) + + def draw_mpolygon_entity(self, entity: DXFGraphic, properties: Properties): + def resolve_fill_color() -> str: + return self.ctx.resolve_aci_color(entity.dxf.fill_color, properties.layer) + + polygon = cast(DXFPolygon, entity) + ocs = polygon.ocs() + elevation: float = polygon.dxf.elevation.z + offset = Vec3(polygon.dxf.get("offset_vector", NULLVEC)) + # MPOLYGON does not support hatch styles, all paths are rendered. + loops = closed_loops(polygon.paths, ocs, elevation, offset) # type: ignore + + line_color: str = properties.color + assert properties.filling is not None + pattern_name: str = properties.filling.name # normalized pattern name + # 1. draw filling + if polygon.dxf.solid_fill: + properties.filling.type = Filling.SOLID + if polygon.gradient is not None and polygon.gradient.number_of_colors > 0: + # true color filling is stored as gradient + properties.color = str(properties.filling.gradient_color1) + else: + properties.color = resolve_fill_color() + self.draw_hatch_entity(entity, properties, loops=loops) + + # checking properties.filling.type == Filling.PATTERN is not sufficient: + elif pattern_name and pattern_name != "SOLID": + # line color is also pattern color: properties.color + self.draw_hatch_entity(entity, properties, loops=loops) + + # 2. draw boundary paths + properties.color = line_color + # draw boundary paths as lines + for loop in loops: + self.pipeline.draw_path(loop, properties) + + def draw_wipeout_entity(self, entity: DXFGraphic, properties: Properties) -> None: + wipeout = cast(Wipeout, entity) + properties.filling = Filling() + properties.color = self.ctx.current_layout_properties.background_color + clipping_polygon = wipeout.boundary_path_wcs() + self.pipeline.draw_filled_polygon(clipping_polygon, properties) + + def draw_viewport(self, vp: Viewport) -> None: + # the "active" viewport and invisible viewports should be filtered at this + # stage, see function _draw_viewports() + if vp.dxf.status < 1: + return + + if not vp.is_top_view: + self.log_message("Cannot render non top-view viewports") + return + self.pipeline.draw_viewport(vp, self.ctx, self._bbox_cache) + + def draw_ole2frame_entity(self, entity: DXFGraphic, properties: Properties) -> None: + ole2frame = cast(OLE2Frame, entity) + bbox = ole2frame.bbox() + if not bbox.is_empty: + self._draw_filled_rect(bbox.rect_vertices(), OLE2FRAME_COLOR) + + def draw_image_entity(self, entity: DXFGraphic, properties: Properties) -> None: + image = cast(Image, entity) + image_policy = self.config.image_policy + image_def = image.image_def + assert image_def is not None + + if image_policy in ( + ImagePolicy.DISPLAY, + ImagePolicy.RECT, + ImagePolicy.MISSING, + ): + loaded_image = None + show_filename_if_missing = True + + if ( + image_policy == ImagePolicy.RECT + or not image.dxf.flags & Image.SHOW_IMAGE + ): + loaded_image = None + show_filename_if_missing = False + elif ( + image_policy != ImagePolicy.MISSING + and self.ctx.document_dir is not None + ): + image_path = _find_image_path( + self.ctx.document_dir, image_def.dxf.filename + ) + with contextlib.suppress(FileNotFoundError): + loaded_image = PIL.Image.open(image_path) + + if loaded_image is not None: + color: RGB | RGBA + loaded_image = loaded_image.convert("RGBA") + + if image.dxf.contrast != 50: + # note: this is only an approximation. + # Unclear what the exact operation AutoCAD uses + amount = image.dxf.contrast / 50 + loaded_image = PIL.ImageEnhance.Contrast(loaded_image).enhance( + amount + ) + + if image.dxf.fade != 0: + # note: this is only an approximation. + # Unclear what the exact operation AutoCAD uses + amount = image.dxf.fade / 100 + color = RGB.from_hex( + self.ctx.current_layout_properties.background_color + ) + loaded_image = _blend_image_towards(loaded_image, amount, color) # type: ignore + if image.dxf.brightness != 50: + # note: this is only an approximation. + # Unclear what the exact operation AutoCAD uses + amount = image.dxf.brightness / 50 - 1 + if amount > 0: + color = RGBA(255, 255, 255, 255) + else: + color = RGBA(0, 0, 0, 255) + amount = -amount + loaded_image = _blend_image_towards(loaded_image, amount, color) # type: ignore + + if not image.dxf.flags & Image.USE_TRANSPARENCY: + loaded_image.putalpha(255) # type: ignore + + if image.transparency != 0.0: + loaded_image = _multiply_alpha( + loaded_image, # type: ignore + 1.0 - image.transparency, + ) + image_data = ImageData( + image=np.array(loaded_image), + transform=image.get_wcs_transform(), + pixel_boundary_path=NumpyPoints2d(image.pixel_boundary_path()), + use_clipping_boundary=image.dxf.flags & Image.USE_CLIPPING_BOUNDARY, + remove_outside=image.dxf.clip_mode == 0, + ) + self.pipeline.draw_image(image_data, properties) + + elif show_filename_if_missing: + default_cap_height = 20 + text = image_def.dxf.filename + font = self.pipeline.text_engine.get_font( + self.get_font_face(properties) + ) + text_width = font.text_width_ex(text, default_cap_height) + image_size = image.dxf.image_size + desired_width = image_size.x * 0.75 + scale = desired_width / text_width + translate = Matrix44.translate( + (image_size.x - desired_width) / 2, + (image_size.y - default_cap_height * scale) / 2, + 0, + ) + transform = ( + Matrix44.scale(scale) @ translate @ image.get_wcs_transform() + ) + self.pipeline.draw_text( + text, + transform, + properties, + default_cap_height, + ) + + points = [v.vec2 for v in image.boundary_path_wcs()] + self.pipeline.draw_solid_lines(list(zip(points, points[1:])), properties) + + elif self.config.image_policy == ImagePolicy.PROXY: + self.draw_proxy_graphic(entity.proxy_graphic, entity.doc) + + elif self.config.image_policy == ImagePolicy.IGNORE: + pass + + else: + raise ValueError(self.config.image_policy) + + def _draw_filled_rect( + self, + points: Iterable[Vec2], + color: str, + ) -> None: + props = Properties() + props.color = color + # default SOLID filling + props.filling = Filling() + self.pipeline.draw_filled_polygon(points, props) + + def draw_mesh_entity(self, entity: DXFGraphic, properties: Properties) -> None: + builder = MeshBuilder.from_mesh(entity) # type: ignore + self.draw_mesh_builder_entity(builder, properties) + + def draw_mesh_builder_entity( + self, builder: MeshBuilder, properties: Properties + ) -> None: + for face in builder.faces_as_vertices(): + self.pipeline.draw_path( + from_vertices(face, close=True), properties=properties + ) + + def draw_polyline_entity(self, entity: DXFGraphic, properties: Properties) -> None: + dxftype = entity.dxftype() + if dxftype == "POLYLINE": + e = cast(Polyface, entity) + if e.is_polygon_mesh or e.is_poly_face_mesh: + # draw 3D mesh or poly-face entity + self.draw_mesh_builder_entity( + MeshBuilder.from_polyface(e), + properties, + ) + return + + entity = cast(Union[LWPolyline, Polyline], entity) + is_lwpolyline = dxftype == "LWPOLYLINE" + + if entity.has_width: # draw banded 2D polyline + elevation = 0.0 + ocs = entity.ocs() + transform = ocs.transform + if transform: + if is_lwpolyline: # stored as float + elevation = entity.dxf.elevation + else: # stored as vector (0, 0, elevation) + elevation = Vec3(entity.dxf.elevation).z + + trace = TraceBuilder.from_polyline( + entity, segments=self.config.circle_approximation_count // 2 + ) + for polygon in trace.polygons(): # polygon is a sequence of Vec2() + if len(polygon) < 3: + continue + if transform: + points = ocs.points_to_wcs( + Vec3(v.x, v.y, elevation) for v in polygon + ) + else: + points = polygon # type: ignore + # Set default SOLID filling for LWPOLYLINE + properties.filling = Filling() + self.pipeline.draw_filled_polygon(points, properties) + return + polyline_path = make_path(entity) + if len(polyline_path): + self.pipeline.draw_path(polyline_path, properties) + + def draw_composite_entity(self, entity: DXFGraphic, properties: Properties) -> None: + def draw_insert(insert: Insert): + # Block reference attributes are located __outside__ the block reference! + self.draw_entities(insert.attribs) + clip = xclip.XClip(insert) + is_clipping_active = clip.has_clipping_path and clip.is_clipping_enabled + + if is_clipping_active: + boundary_path = clip.get_wcs_clipping_path() + if not boundary_path.is_inverted_clip: + clipping_shape = clipping_portal.find_best_clipping_shape( + boundary_path.vertices + ) + else: # inverted clipping path + clipping_shape = clipping_portal.make_inverted_clipping_shape( + boundary_path.inner_polygon(), + outer_bounds=boundary_path.outer_bounds(), + ) + self.pipeline.push_clipping_shape(clipping_shape, None) + + # draw_entities() includes the visibility check: + self.draw_entities( + insert.virtual_entities( + skipped_entity_callback=self.skip_entity + # TODO: redraw_order=True? + ) + ) + + if is_clipping_active and clip.get_xclip_frame_policy(): + self.pipeline.draw_path( + path=from_vertices(boundary_path.inner_polygon(), close=True), + properties=properties, + ) + self.pipeline.pop_clipping_shape() + + if isinstance(entity, Insert): + self.ctx.push_state(properties) + if entity.mcount > 1: + for virtual_insert in entity.multi_insert(): + draw_insert(virtual_insert) + else: + draw_insert(entity) + self.ctx.pop_state() + elif isinstance(entity, SupportsVirtualEntities): + # draw_entities() includes the visibility check: + try: + self.draw_entities(virtual_entities(entity)) + except ProxyGraphicError as e: + print(str(e)) + print(POST_ISSUE_MSG) + else: + raise TypeError(entity.dxftype()) + + def draw_proxy_graphic(self, data: bytes | None, doc) -> None: + if not data: + return + try: + self.draw_entities(virtual_entities(ProxyGraphic(data, doc))) + except ProxyGraphicError as e: + print(str(e)) + print(POST_ISSUE_MSG) + + +class Frontend(UniversalFrontend): + """Drawing frontend for 2D backends, responsible for decomposing entities into + graphic primitives and resolving entity properties. + + By passing the bounding box cache of the modelspace entities can speed up + paperspace rendering, because the frontend can filter entities which are not + visible in the VIEWPORT. Even passing in an empty cache can speed up + rendering time when multiple viewports need to be processed. + + Args: + ctx: the properties relevant to rendering derived from a DXF document + out: the 2D backend to draw to + config: settings to configure the drawing frontend and backend + bbox_cache: bounding box cache of the modelspace entities or an empty + cache which will be filled dynamically when rendering multiple + viewports or ``None`` to disable bounding box caching at all + + """ + + def __init__( + self, + ctx: RenderContext, + out: BackendInterface, + config: Configuration = Configuration(), + bbox_cache: Optional[ezdxf.bbox.Cache] = None, + ): + from .pipeline import RenderPipeline2d + + super().__init__(ctx, RenderPipeline2d(out), config, bbox_cache) + + +def is_spatial_text(extrusion: Vec3) -> bool: + # note: the magnitude of the extrusion vector has no effect on text scale + return not math.isclose(extrusion.x, 0) or not math.isclose(extrusion.y, 0) + + +def closed_loops( + paths: list[AbstractBoundaryPath], + ocs: OCS, + elevation: float, + offset: Vec3 = NULLVEC, +) -> list[Path]: + loops = [] + for boundary in paths: + path = from_hatch_boundary_path(boundary, ocs, elevation, offset) + assert isinstance( + path.user_data, const.BoundaryPathState + ), "missing attached boundary path state" + for sub_path in path.sub_paths(): + if len(sub_path): + sub_path.close() + loops.append(sub_path) + return loops + + +def ignore_text_boxes(paths: Iterable[Path]) -> Iterable[Path]: + """Filters text boxes from paths if BoundaryPathState() information is + attached. + """ + for path in paths: + if ( + isinstance(path.user_data, const.BoundaryPathState) + and path.user_data.textbox + ): + continue # skip text box paths + yield path + + +def _draw_entities( + frontend: UniversalFrontend, + ctx: RenderContext, + entities: Iterable[DXFGraphic], + *, + filter_func: Optional[FilterFunc] = None, +) -> None: + if filter_func is not None: + entities = filter(filter_func, entities) + viewports: list[Viewport] = [] + for entity in entities: + if isinstance(entity, Viewport): + viewports.append(entity) + continue + if not isinstance(entity, DXFGraphic): + if frontend.config.proxy_graphic_policy != ProxyGraphicPolicy.IGNORE: + entity = DXFGraphicProxy(entity) + else: + frontend.skip_entity(entity, "Cannot parse DXF entity") + continue + properties = ctx.resolve_all(entity) + frontend.exec_property_override(entity, properties) + if properties.is_visible: + frontend.draw_entity(entity, properties) + else: + frontend.skip_entity(entity, "invisible") + _draw_viewports(frontend, viewports) + + +def _draw_viewports(frontend: UniversalFrontend, viewports: list[Viewport]) -> None: + # The VIEWPORT attributes "id" and "status" are very unreliable, maybe because of + # the "great" documentation by Autodesk. + # Viewport status field: (according to the DXF Reference) + # -1 = On, but is fully off-screen, or is one of the viewports that is not + # active because the $MAXACTVP count is currently being exceeded. + # 0 = Off + # = On and active. The value indicates the order of + # stacking for the viewports, where 1 is the "active" viewport, 2 is the + # next, and so on. + viewports.sort(key=lambda e: e.dxf.status) + # Remove all invisible viewports: + viewports = [vp for vp in viewports if vp.dxf.status > 0] + if not viewports: + return + # The "active" viewport determines how the paperspace layout is presented as a + # whole (location & zoom state). + # Maybe there are more than one "active" viewports, just remove the first one, + # or there is no "active" viewport at all - in this case the "status" attribute + # is not reliable at all - but what else is there to do? The "active" layout should + # have the id "1", but this information is also not reliable. + if viewports[0].dxf.get("status", 1) == 1: + viewports.pop(0) + # Draw viewports in order of "status" + for viewport in viewports: + frontend.draw_viewport(viewport) + + +def _blend_image_towards( + image: PIL.Image.Image, amount: float, color: RGB | RGBA +) -> PIL.Image.Image: + original_alpha = image.split()[-1] + destination = PIL.Image.new("RGBA", image.size, color) + updated_image = PIL.Image.blend(image, destination, amount) + updated_image.putalpha(original_alpha) + return updated_image + + +def _multiply_alpha(image: PIL.Image.Image, amount: float) -> PIL.Image.Image: + output_image = np.array(image, dtype=np.float64) + output_image[:, :, 3] *= amount + return PIL.Image.fromarray(output_image.astype(np.uint8), "RGBA") + + +def _find_image_path(document_dir: pathlib.Path, filename: str) -> pathlib.Path: + # BricsCAD stores the path to the image as full-path or relative-path if so + # set in the "Attach Raster Image" dialog. + # See notes in knowledge graph: [[IMAGE File Paths]] + # https://ezdxf.mozman.at/notes/#/page/image%20file%20paths + + # BricsCAD/AutoCAD stores filepaths with backslashes. + filename = filename.replace("\\", os.path.sep) + + # try absolute path: + filepath = pathlib.Path(filename) + if filepath.exists(): + return filepath + + # try relative path to document: + filepath = document_dir / filename + filepath = filepath.resolve() + if filepath.exists(): + return filepath + + # try document dir: + filepath = document_dir / pathlib.Path(filename).name # stem + suffix + return filepath diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/gfxproxy.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/gfxproxy.py new file mode 100644 index 0000000..1648272 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/gfxproxy.py @@ -0,0 +1,48 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Iterator +from ezdxf.entities import DXFGraphic, DXFEntity +from ezdxf.lldxf import const +from ezdxf.lldxf.tagwriter import AbstractTagWriter +from ezdxf.protocols import SupportsVirtualEntities +from ezdxf.entities.copy import default_copy, CopyNotSupported + + +class DXFGraphicProxy(DXFGraphic): + """DO NOT USE THIS WRAPPER AS REAL DXF ENTITY OUTSIDE THE DRAWING ADD-ON!""" + + def __init__(self, entity: DXFEntity): + super().__init__() + self.entity = entity + self.dxf = self._setup_dxf_namespace(entity) + + def _setup_dxf_namespace(self, entity): + # copy DXF namespace - modifications do not effect the wrapped entity + dxf = entity.dxf.copy(self) + # setup mandatory DXF attributes without default values like layer: + for k, v in self.DEFAULT_ATTRIBS.items(): + if not dxf.hasattr(k): + dxf.set(k, v) + return dxf + + def dxftype(self) -> str: + return self.entity.dxftype() + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + if isinstance(self.entity, SupportsVirtualEntities): + return self.entity.__virtual_entities__() + if hasattr(self.entity, "virtual_entities"): + return self.entity.virtual_entities() + return iter([]) + + def virtual_entities(self) -> Iterable[DXFGraphic]: + return self.__virtual_entities__() + + def copy(self, copy_strategy=default_copy) -> DXFGraphicProxy: + raise CopyNotSupported(f"Copying of DXFGraphicProxy() not supported.") + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + # prevent dxf export + return False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/hpgl2.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/hpgl2.py new file mode 100644 index 0000000..64e3fef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/hpgl2.py @@ -0,0 +1,549 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence, no_type_check +import copy +import numpy as np + +from ezdxf import colors +from ezdxf.math import Vec2, BoundingBox2d, Matrix44 +from ezdxf.path import Command + +from .type_hints import Color +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import Configuration, LineweightPolicy +from .properties import BackendProperties +from . import layout, recorder + + +__all__ = ["PlotterBackend"] + +SEMICOLON = ord(";") +PRELUDE = b"%0B;IN;BP;" +EPILOG = b"PU;PA0,0;" +FLATTEN_MAX = 10 # plot units +MM_TO_PLU = 40 # 40 plu = 1mm +DEFAULT_PEN = 0 +WHITE = colors.RGB(255, 255, 255) +BLACK = colors.RGB(0, 0, 0) +MAX_FLATTEN = 10 + +# comparing Command. to ints is very slow +CMD_MOVE_TO = int(Command.MOVE_TO) +CMD_LINE_TO = int(Command.LINE_TO) +CMD_CURVE3_TO = int(Command.CURVE3_TO) +CMD_CURVE4_TO = int(Command.CURVE4_TO) + + +class PlotterBackend(recorder.Recorder): + """The :class:`PlotterBackend` creates HPGL/2 plot files for output on raster + plotters. This backend does not need any additional packages. This backend support + content cropping at page margins. + + The plot files are tested by the plot file viewer `ViewCompanion Standard`_ + but not on real hardware - please use with care and give feedback. + + .. _ViewCompanion Standard: http://www.softwarecompanions.com/ + + """ + + def __init__(self) -> None: + super().__init__() + + def get_bytes( + self, + page: layout.Page, + *, + settings: layout.Settings = layout.Settings(), + render_box: BoundingBox2d | None = None, + curves=True, + decimal_places: int = 1, + base=64, + ) -> bytes: + """Returns the HPGL/2 data as bytes. + + Args: + page: page definition, see :class:`~ezdxf.addons.drawing.layout.Page` + settings: layout settings, see :class:`~ezdxf.addons.drawing.layout.Settings` + render_box: set explicit region to render, default is content bounding box + curves: use Bèzier curves for HPGL/2 output + decimal_places: HPGL/2 output precision, less decimal places creates smaller + files but for the price of imprecise curves (text) + base: base for polyline encoding, 32 for 7 bit encoding or 64 for 8 bit encoding + + """ + top_origin = False + settings = copy.copy(settings) + # This player changes the original recordings! + player = self.player() + if render_box is None: + render_box = player.bbox() + + # the page origin (0, 0) is in the bottom-left corner. + output_layout = layout.Layout(render_box, flip_y=False) + page = output_layout.get_final_page(page, settings) + if page.width == 0 or page.height == 0: + return b"" # empty page + # DXF coordinates are mapped to integer coordinates (plu) in the first + # quadrant: 40 plu = 1mm + settings.output_coordinate_space = ( + max(page.width_in_mm, page.height_in_mm) * MM_TO_PLU + ) + # transform content to the output coordinates space: + m = output_layout.get_placement_matrix( + page, settings=settings, top_origin=top_origin + ) + player.transform(m) + if settings.crop_at_margins: + p1, p2 = page.get_margin_rect(top_origin=top_origin) # in mm + # scale factor to map page coordinates to output space coordinates: + output_scale = settings.page_output_scale_factor(page) + max_sagitta = 0.1 * MM_TO_PLU # curve approximation 0.1 mm + # crop content inplace by the margin rect: + player.crop_rect(p1 * output_scale, p2 * output_scale, max_sagitta) + backend = _RenderBackend( + page, + settings=settings, + curves=curves, + decimal_places=decimal_places, + base=base, + ) + player.replay(backend) + return backend.get_bytes() + + def compatible( + self, page: layout.Page, settings: layout.Settings = layout.Settings() + ) -> bytes: + """Returns the HPGL/2 data as 7-bit encoded bytes curves as approximated + polylines and coordinates are rounded to integer values. + Has often the smallest file size and should be compatible to all output devices + but has a low quality text rendering. + """ + return self.get_bytes( + page, settings=settings, curves=False, decimal_places=0, base=32 + ) + + def low_quality( + self, page: layout.Page, settings: layout.Settings = layout.Settings() + ) -> bytes: + """Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier + curves and coordinates are rounded to integer values. + Has a smaller file size than normal quality and the output device must support + 8-bit encoding and Bèzier curves. + """ + return self.get_bytes( + page, settings=settings, curves=True, decimal_places=0, base=64 + ) + + def normal_quality( + self, page: layout.Page, settings: layout.Settings = layout.Settings() + ) -> bytes: + """Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier + curves and coordinates are floats rounded to one decimal place. + Has a smaller file size than high quality and the output device must support + 8-bit encoding, Bèzier curves and fractional coordinates. + """ + return self.get_bytes( + page, settings=settings, curves=True, decimal_places=1, base=64 + ) + + def high_quality( + self, page: layout.Page, settings: layout.Settings = layout.Settings() + ) -> bytes: + """Returns the HPGL/2 data as 8-bit encoded bytes and all curves as Bézier + curves and coordinates are floats rounded to two decimal places. + Has the largest file size and the output device must support 8-bit encoding, + Bèzier curves and fractional coordinates. + """ + return self.get_bytes( + page, settings=settings, curves=True, decimal_places=2, base=64 + ) + + +class PenTable: + def __init__(self, max_pens: int = 64) -> None: + self.pens: dict[int, colors.RGB] = dict() + self.max_pens = int(max_pens) + + def __contains__(self, index: int) -> bool: + return index in self.pens + + def __getitem__(self, index: int) -> colors.RGB: + return self.pens[index] + + def add_pen(self, index: int, color: colors.RGB): + self.pens[index] = color + + def to_bytes(self) -> bytes: + command: list[bytes] = [f"NP{self.max_pens-1};".encode()] + pens: list[tuple[int, colors.RGB]] = [ + (index, rgb) for index, rgb in self.pens.items() + ] + pens.sort() + for index, rgb in pens: + command.append(make_pc(index, rgb)) + return b"".join(command) + + +def make_pc(pen: int, rgb: colors.RGB) -> bytes: + # pen color + return f"PC{pen},{rgb.r},{rgb.g},{rgb.b};".encode() + + +class _RenderBackend(BackendInterface): + """Creates the HPGL/2 output. + + This backend requires some preliminary work, record the frontend output via the + Recorder backend to accomplish the following requirements: + + - Move content in the first quadrant of the coordinate system. + - The output coordinates are integer values, scale the content appropriately: + - 1 plot unit (plu) = 0.025mm + - 40 plu = 1mm + - 1016 plu = 1 inch + - 3.39 plu = 1 dot @300 dpi + - Replay the recorded output on this backend. + + """ + + def __init__( + self, + page: layout.Page, + *, + settings: layout.Settings, + curves=True, + decimal_places: int = 2, + base: int = 64, + ) -> None: + self.settings = settings + self.curves = curves + self.factional_bits = round(decimal_places * 3.33) + self.decimal_places: int | None = ( + int(decimal_places) if decimal_places else None + ) + self.base = base + self.header: list[bytes] = [] + self.data: list[bytes] = [] + self.pen_table = PenTable(max_pens=256) + self.current_pen: int = 0 + self.current_pen_width: float = 0.0 + self.setup(page) + + self._stroke_width_cache: dict[float, float] = dict() + # StrokeWidthPolicy.absolute: + # pen width in mm as resolved by the frontend + self.min_lineweight = 0.05 # in mm, set by configure() + self.lineweight_scaling = 1.0 # set by configure() + self.lineweight_policy = LineweightPolicy.ABSOLUTE # set by configure() + # fixed lineweight for all strokes in ABSOLUTE mode: + # set Configuration.min_lineweight to the desired lineweight in 1/300 inch! + # set Configuration.lineweight_scaling to 0 + + # LineweightPolicy.RELATIVE: + # max_stroke_width is determined as a certain percentage of max(width, height) + max_size = max(page.width_in_mm, page.height_in_mm) + self.max_stroke_width: float = round(max_size * settings.max_stroke_width, 2) + # min_stroke_width is determined as a certain percentage of max_stroke_width + self.min_stroke_width: float = round( + self.max_stroke_width * settings.min_stroke_width, 2 + ) + # LineweightPolicy.RELATIVE_FIXED: + # all strokes have a fixed stroke-width as a certain percentage of max_stroke_width + self.fixed_stroke_width: float = round( + self.max_stroke_width * settings.fixed_stroke_width, 2 + ) + + def setup(self, page: layout.Page) -> None: + cmd = f"PS{page.width_in_mm*MM_TO_PLU:.0f},{page.height_in_mm*MM_TO_PLU:.0f};" + self.header.append(cmd.encode()) + self.header.append(b"FT1;PA;") # solid fill; plot absolute; + + def get_bytes(self) -> bytes: + header: list[bytes] = list(self.header) + header.append(self.pen_table.to_bytes()) + return compile_hpgl2(header, self.data) + + def switch_current_pen(self, pen_number: int, rgb: colors.RGB) -> int: + if pen_number in self.pen_table: + pen_color = self.pen_table[pen_number] + if rgb != pen_color: + self.data.append(make_pc(DEFAULT_PEN, rgb)) + pen_number = DEFAULT_PEN + else: + self.pen_table.add_pen(pen_number, rgb) + return pen_number + + def set_pen(self, pen_number: int) -> None: + if self.current_pen == pen_number: + return + self.data.append(f"SP{pen_number};".encode()) + self.current_pen = pen_number + + def set_pen_width(self, width: float) -> None: + if self.current_pen_width == width: + return + self.data.append(f"PW{width:g};".encode()) # pen width in mm + self.current_pen_width = width + + def enter_polygon_mode(self, start_point: Vec2) -> None: + x = round(start_point.x, self.decimal_places) + y = round(start_point.y, self.decimal_places) + self.data.append(f"PA;PU{x},{y};PM;".encode()) + + def close_current_polygon(self) -> None: + self.data.append(b"PM1;") + + def fill_polygon(self) -> None: + self.data.append(b"PM2;FP;") # even/odd fill method + + def set_properties(self, properties: BackendProperties) -> None: + pen_number = properties.pen + pen_color, opacity = self.resolve_pen_color(properties.color) + pen_width = self.resolve_pen_width(properties.lineweight) + pen_number = self.switch_current_pen(pen_number, pen_color) + self.set_pen(pen_number) + self.set_pen_width(pen_width) + + def add_polyline_encoded( + self, vertices: Iterable[Vec2], properties: BackendProperties + ): + self.set_properties(properties) + self.data.append(polyline_encoder(vertices, self.factional_bits, self.base)) + + def add_path(self, path: BkPath2d, properties: BackendProperties): + if self.curves and path.has_curves: + self.set_properties(properties) + self.data.append(path_encoder(path, self.decimal_places)) + else: + points = list(path.flattening(MAX_FLATTEN, segments=4)) + self.add_polyline_encoded(points, properties) + + @staticmethod + def resolve_pen_color(color: Color) -> tuple[colors.RGB, float]: + rgb = colors.RGB.from_hex(color) + if rgb == WHITE: + rgb = BLACK + return rgb, alpha_to_opacity(color[7:9]) + + def resolve_pen_width(self, width: float) -> float: + try: + return self._stroke_width_cache[width] + except KeyError: + pass + stroke_width = self.fixed_stroke_width + policy = self.lineweight_policy + if policy == LineweightPolicy.ABSOLUTE: + if self.lineweight_scaling: + width = max(self.min_lineweight, width) * self.lineweight_scaling + else: + width = self.min_lineweight + stroke_width = round(width, 2) # in mm + elif policy == LineweightPolicy.RELATIVE: + stroke_width = round( + map_lineweight_to_stroke_width( + width, self.min_stroke_width, self.max_stroke_width + ), + 2, + ) + self._stroke_width_cache[width] = stroke_width + return stroke_width + + def set_background(self, color: Color) -> None: + # background is always a white paper + pass + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.add_polyline_encoded([pos], properties) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.add_polyline_encoded([start, end], properties) + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + lines = list(lines) + if len(lines) == 0: + return + for line in lines: + self.add_polyline_encoded(line, properties) + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + for sub_path in path.sub_paths(): + if len(sub_path) == 0: + continue + self.add_path(sub_path, properties) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + paths = list(paths) + if len(paths) == 0: + return + self.enter_polygon_mode(paths[0].start) + for p in paths: + for sub_path in p.sub_paths(): + if len(sub_path) == 0: + continue + self.add_path(sub_path, properties) + self.close_current_polygon() + self.fill_polygon() + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + points2d: list[Vec2] = points.vertices() + if points2d: + self.enter_polygon_mode(points2d[0]) + self.add_polyline_encoded(points2d, properties) + self.fill_polygon() + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + pass # TODO: not implemented + + def configure(self, config: Configuration) -> None: + self.lineweight_policy = config.lineweight_policy + if config.min_lineweight: + # config.min_lineweight in 1/300 inch! + min_lineweight_mm = config.min_lineweight * 25.4 / 300 + self.min_lineweight = max(0.05, min_lineweight_mm) + self.lineweight_scaling = config.lineweight_scaling + + def clear(self) -> None: + pass + + def finalize(self) -> None: + pass + + def enter_entity(self, entity, properties) -> None: + pass + + def exit_entity(self, entity) -> None: + pass + + +def alpha_to_opacity(alpha: str) -> float: + # stroke-opacity: 0.0 = transparent; 1.0 = opaque + # alpha: "00" = transparent; "ff" = opaque + if len(alpha): + try: + return int(alpha, 16) / 255 + except ValueError: + pass + return 1.0 + + +def map_lineweight_to_stroke_width( + lineweight: float, + min_stroke_width: float, + max_stroke_width: float, + min_lineweight=0.05, # defined by DXF + max_lineweight=2.11, # defined by DXF +) -> float: + lineweight = max(min(lineweight, max_lineweight), min_lineweight) - min_lineweight + factor = (max_stroke_width - min_stroke_width) / (max_lineweight - min_lineweight) + return round(min_stroke_width + round(lineweight * factor), 2) + + +def flatten_path(path: BkPath2d) -> Sequence[Vec2]: + points = list(path.flattening(distance=FLATTEN_MAX)) + return points + + +def compile_hpgl2(header: Sequence[bytes], commands: Sequence[bytes]) -> bytes: + output = bytearray(PRELUDE) + output.extend(b"".join(header)) + output.extend(b"".join(commands)) + output.extend(EPILOG) + return bytes(output) + + +def pe_encode(value: float, frac_bits: int = 0, base: int = 64) -> bytes: + if frac_bits: + value *= 1 << frac_bits + x = round(value) + if x >= 0: + x *= 2 + else: + x = abs(x) * 2 + 1 + + chars = bytearray() + while x >= base: + x, r = divmod(x, base) + chars.append(63 + r) + if base == 64: + chars.append(191 + x) + else: + chars.append(95 + x) + return bytes(chars) + + +def polyline_encoder(vertices: Iterable[Vec2], frac_bits: int, base: int) -> bytes: + cmd = b"PE" + if base == 32: + cmd = b"PE7" + if frac_bits: + cmd += b">" + pe_encode(frac_bits, 0, base) + data = [cmd + b"<="] + vertices = list(vertices) + # first point as absolute coordinates + current = vertices[0] + data.append(pe_encode(current.x, frac_bits, base)) + data.append(pe_encode(current.y, frac_bits, base)) + for vertex in vertices[1:]: + # remaining points as relative coordinates + delta = vertex - current + data.append(pe_encode(delta.x, frac_bits, base)) + data.append(pe_encode(delta.y, frac_bits, base)) + current = vertex + data.append(b";") + return b"".join(data) + + +@no_type_check +def path_encoder(path: BkPath2d, decimal_places: int | None) -> bytes: + # first point as absolute coordinates + current = path.start + x = round(current.x, decimal_places) + y = round(current.y, decimal_places) + data = [f"PU;PA{x:g},{y:g};PD;".encode()] + prev_command = Command.MOVE_TO + if len(path): + commands: list[bytes] = [] + for cmd in path.commands(): + delta = cmd.end - current + xe = round(delta.x, decimal_places) + ye = round(delta.y, decimal_places) + if cmd.type == Command.LINE_TO: + coords = f"{xe:g},{ye:g};".encode() + if prev_command == Command.LINE_TO: + # extend previous PR command + commands[-1] = commands[-1][:-1] + b"," + coords + else: + commands.append(b"PR" + coords) + prev_command = Command.LINE_TO + else: + if cmd.type == Command.CURVE3_TO: + control = cmd.ctrl - current + end = cmd.end - current + control_1 = 2.0 * control / 3.0 + control_2 = end + 2.0 * (control - end) / 3.0 + elif cmd.type == Command.CURVE4_TO: + control_1 = cmd.ctrl1 - current + control_2 = cmd.ctrl2 - current + else: + raise ValueError("internal error: MOVE_TO command is illegal here") + x1 = round(control_1.x, decimal_places) + y1 = round(control_1.y, decimal_places) + x2 = round(control_2.x, decimal_places) + y2 = round(control_2.y, decimal_places) + coords = f"{x1:g},{y1:g},{x2:g},{y2:g},{xe:g},{ye:g};".encode() + if prev_command == Command.CURVE4_TO: + # extend previous BR command + commands[-1] = commands[-1][:-1] + b"," + coords + else: + commands.append(b"BR" + coords) + prev_command = Command.CURVE4_TO + current = cmd.end + data.append(b"".join(commands)) + data.append(b"PU;") + return b"".join(data) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/json.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/json.py new file mode 100644 index 0000000..21ea1fb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/json.py @@ -0,0 +1,590 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence, no_type_check, Any, Callable, Dict, List, Tuple +from typing_extensions import TypeAlias, override +import abc +import json + +from ezdxf.math import Vec2, world_mercator_to_gps +from ezdxf.path import Command, nesting +from ezdxf.npshapes import orient_paths, single_paths + +from .type_hints import Color +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import Configuration +from .properties import BackendProperties + + +__all__ = ["CustomJSONBackend", "GeoJSONBackend"] + +CUSTOM_JSON_SPECS = """ +JSON content = [entity, entity, ...] + +entity = { + "type": point | lines | path | filled-paths | filled-polygon, + "properties": { + "color": "#RRGGBBAA", + "stroke-width": 0.25, # in mm + "layer": "name" + }, + "geometry": depends on "type" +} +DXF linetypes (DASH, DOT, ...) are resolved into solid lines. + +A single point: +point = { + "type": "point", + "properties": {...}, + "geometry": [x, y] +} + +Multiple lines with common properties: +lines = { + "type": "lines", + "properties": {...}, + "geometry": [ + (x0, y0, x1, y1), # 1. line + (x0, y0, x1, y1), # 2. line + .... + ] +} +Lines can contain points where x0 == x1 and y0 == y1! + +A single linear path without filling: +path = { + "type": "path", + "properties": {...}, + "geometry": [path-command, ...] +} + +SVG-like path structure: +- The first path-command is always an absolute move to "M" +- The "M" command does not appear inside a path, each path is a continuouse geometry + (no multi-paths). + +path-command = + ("M", x, y) = absolute move to + ("L", x, y) = absolute line to + ("Q", x0, y0, x1, y1) = absolute quadratice Bezier curve to + - (x0, y0) = control point + - (x1, y1) = end point + ("C", x0, y0, x1, y1, x2, y2) = absolute cubic Bezier curve to + - (x0, y0) = control point 1 + - (x1, y1) = control point 2 + - (x2, y2) = end point + ("Z",) = close path + +Multiple filled paths: + +Exterior paths and holes are mixed and NOT oriented by default (clockwise or +counter-clockwise) - PyQt and SVG have no problem with that structure but matplotlib +requires oriented paths. When oriented paths are required the CustomJSONBackend can +orient the paths on demand. + +filled-paths = { + "type": "filled-paths", + "properties": {...}, + "geometry": [ + [path-command, ...], # 1. path + [path-command, ...], # 2. path + ... + ] +} + +A single filled polygon: +A polygon is explicitly closed, so first vertex == last vertex is guaranteed. +filled-polygon = { + "type": "filled-polygon", + "properties": {...}, + "geometry": [ + (x0, y0), + (x1, y1), + (x2, y2), + ... + ] +} + +""" + + +class _JSONBackend(BackendInterface): + def __init__(self) -> None: + self._entities: list[dict[str, Any]] = [] + self.max_sagitta = 0.01 # set by configure() + self.min_lineweight = 0.05 # in mm, set by configure() + self.lineweight_scaling = 1.0 # set by configure() + # set fixed lineweight for all strokes: + # set Configuration.min_lineweight to the desired lineweight in 1/300 inch! + # set Configuration.lineweight_scaling to 0 + self.fixed_lineweight = 0.0 + + @abc.abstractmethod + def get_json_data(self) -> Any: ... + def get_string(self, *, indent: int | str = 2) -> str: + """Returns the result as a JSON string.""" + return json.dumps(self.get_json_data(), indent=indent) + + @override + def configure(self, config: Configuration) -> None: + if config.min_lineweight: + # config.min_lineweight in 1/300 inch! + min_lineweight_mm = config.min_lineweight * 25.4 / 300 + self.min_lineweight = max(0.05, min_lineweight_mm) + self.lineweight_scaling = config.lineweight_scaling + if self.lineweight_scaling == 0.0: + # use a fixed lineweight for all strokes defined by min_lineweight + self.fixed_lineweight = self.min_lineweight + self.max_sagitta = config.max_flattening_distance + + @override + def clear(self) -> None: + self._entities.clear() + + @override + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + pass + + @override + def set_background(self, color: Color) -> None: + pass + + @override + def finalize(self) -> None: + pass + + @override + def enter_entity(self, entity, properties) -> None: + pass + + @override + def exit_entity(self, entity) -> None: + pass + + +MOVE_TO_ABS = "M" +LINE_TO_ABS = "L" +QUAD_TO_ABS = "Q" +CUBIC_TO_ABS = "C" +CLOSE_PATH = "Z" + + +class CustomJSONBackend(_JSONBackend): + """Creates a JSON-like output with a custom JSON scheme. This scheme supports + curved shapes by a SVG-path like structure and coordinates are not limited in + any way. This backend can be used to send geometries from a web-backend to a + frontend. + + The JSON scheme is documented in the source code: + + https://github.com/mozman/ezdxf/blob/master/src/ezdxf/addons/drawing/json.py + + Args: + orient_paths: orient exterior and hole paths on demand, exterior paths have + counter-clockwise orientation and holes have clockwise orientation. + + **Class Methods** + + .. automethod:: get_json_data + + .. automethod:: get_string + + .. versionadded:: 1.3.0 + + """ + + def __init__(self, orient_paths=False) -> None: + super().__init__() + self.orient_paths = orient_paths + + @override + def get_json_data(self) -> list[dict[str, Any]]: + """Returns the result as a JSON-like data structure.""" + return self._entities + + def add_entity( + self, entity_type: str, geometry: Sequence[Any], properties: BackendProperties + ): + if not geometry: + return + self._entities.append( + { + "type": entity_type, + "properties": self.make_properties_dict(properties), + "geometry": geometry, + } + ) + + def make_properties_dict(self, properties: BackendProperties) -> dict[str, Any]: + if self.fixed_lineweight: + stroke_width = self.fixed_lineweight + else: + stroke_width = max( + self.min_lineweight, properties.lineweight * self.lineweight_scaling + ) + return { + "color": properties.color, + "stroke-width": round(stroke_width, 2), + "layer": properties.layer, + } + + @override + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.add_entity("point", [pos.x, pos.y], properties) + + @override + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.add_entity("lines", [(start.x, start.y, end.x, end.y)], properties) + + @override + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + lines = list(lines) + if len(lines) == 0: + return + self.add_entity("lines", [(s.x, s.y, e.x, e.y) for s, e in lines], properties) + + @override + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + self.add_entity("path", make_json_path(path), properties) + + @override + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + paths = list(paths) + if len(paths) == 0: + return + if self.orient_paths: + paths = orient_paths(paths) # returns single paths + else: + # Just single paths allowed, no multi paths! + paths = single_paths(paths) + json_paths: list[Any] = [] + for path in paths: + if len(path): + json_paths.append(make_json_path(path, close=True)) + if json_paths: + self.add_entity("filled-paths", json_paths, properties) + + @override + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + vertices: list[Vec2] = points.vertices() + if len(vertices) < 3: + return + if not vertices[0].isclose(vertices[-1]): + vertices.append(vertices[0]) + self.add_entity("filled-polygon", [(v.x, v.y) for v in vertices], properties) + + +@no_type_check +def make_json_path(path: BkPath2d, close=False) -> list[Any]: + if len(path) == 0: + return [] + end: Vec2 = path.start + commands: list = [(MOVE_TO_ABS, end.x, end.y)] + for cmd in path.commands(): + end = cmd.end + if cmd.type == Command.MOVE_TO: + commands.append((MOVE_TO_ABS, end.x, end.y)) + elif cmd.type == Command.LINE_TO: + commands.append((LINE_TO_ABS, end.x, end.y)) + elif cmd.type == Command.CURVE3_TO: + c1 = cmd.ctrl + commands.append((QUAD_TO_ABS, c1.x, c1.y, end.x, end.y)) + elif cmd.type == Command.CURVE4_TO: + c1 = cmd.ctrl1 + c2 = cmd.ctrl2 + commands.append((CUBIC_TO_ABS, c1.x, c1.y, c2.x, c2.y, end.x, end.y)) + if close: + commands.append(CLOSE_PATH) + return commands + + +# dict and list not allowed here for Python < 3.10 +PropertiesMaker: TypeAlias = Callable[[str, float, str], Dict[str, Any]] +TransformFunc: TypeAlias = Callable[[Vec2], Tuple[float, float]] +# GeoJSON ring +Ring: TypeAlias = List[Tuple[float, float]] + +# The first ring is the exterior path followed by optional holes, nested polygons are +# not supported by the GeoJSON specification. +GeoJsonPolygon: TypeAlias = List[Ring] + + +def properties_maker(color: str, stroke_width: float, layer: str) -> dict[str, Any]: + """Returns the property dict:: + + { + "color": color, + "stroke-width": stroke_width, + "layer": layer, + } + + Returning an empty dict prevents properties in the GeoJSON output and also avoids + wraping entities into "Feature" objects. + """ + return { + "color": color, + "stroke-width": round(stroke_width, 2), + "layer": layer, + } + + +def no_transform(location: Vec2) -> tuple[float, float]: + """Dummy transformation function. Does not apply any transformations and + just returns the input coordinates. + """ + return (location.x, location.y) + + +def make_world_mercator_to_gps_function(tol: float = 1e-6) -> TransformFunc: + """Returns a function to transform WGS84 World Mercator `EPSG:3395 `_ + location given as cartesian 2D coordinates x, y in meters into WGS84 decimal + degrees as longitude and latitude `EPSG:4326 `_ as + used by GPS. + + Args: + tol: accuracy for latitude calculation + + """ + + def _transform(location: Vec2) -> tuple[float, float]: + """Transforms WGS84 World Mercator EPSG:3395 coordinates to WGS84 EPSG:4326.""" + return world_mercator_to_gps(location.x, location.y, tol) + return _transform + + +class GeoJSONBackend(_JSONBackend): + """Creates a JSON-like output according the `GeoJSON`_ scheme. + GeoJSON uses a geographic coordinate reference system, World Geodetic + System 1984 `EPSG:4326 `_, and units of decimal degrees. + + - Latitude: -90 to +90 (South/North) + - Longitude: -180 to +180 (East/West) + + So most DXF files will produce invalid coordinates and it is the job of the + **package-user** to provide a function to transfrom the input coordinates to + EPSG:4326! The :class:`~ezdxf.addons.drawing.recorder.Recorder` and + :class:`~ezdxf.addons.drawing.recorder.Player` classes can help to detect the + extents of the DXF content. + + Default implementation: + + .. autofunction:: no_transform + + Factory function to make a transform function from WGS84 World Mercator + `EPSG:3395 `_ coordinates to WGS84 (GPS) + `EPSG:4326 `_. + + .. autofunction:: make_world_mercator_to_gps_function + + The GeoJSON format supports only straight lines so curved shapes are flattened to + polylines and polygons. + + The properties are handled as a foreign member feature and is therefore not defined + in the GeoJSON specs. It is possible to provide a custom function to create these + property objects. + + Default implementation: + + .. autofunction:: properties_maker + + + Args: + properties_maker: function to create a properties dict. + + **Class Methods** + + .. automethod:: get_json_data + + .. automethod:: get_string + + .. versionadded:: 1.3.0 + + .. _GeoJSON: https://geojson.org/ + """ + + def __init__( + self, + properties_maker: PropertiesMaker = properties_maker, + transform_func: TransformFunc = no_transform, + ) -> None: + super().__init__() + self._properties_dict_maker = properties_maker + self._transform_function = transform_func + + @override + def get_json_data(self) -> dict[str, Any]: + """Returns the result as a JSON-like data structure according the GeoJSON specs.""" + if len(self._entities) == 0: + return {} + using_features = self._entities[0]["type"] == "Feature" + if using_features: + return {"type": "FeatureCollection", "features": self._entities} + else: + return {"type": "GeometryCollection", "geometries": self._entities} + + def add_entity(self, entity: dict[str, Any], properties: BackendProperties): + if not entity: + return + properties_dict: dict[str, Any] = self._properties_dict_maker( + *self.make_properties(properties) + ) + if properties_dict: + self._entities.append( + { + "type": "Feature", + "properties": properties_dict, + "geometry": entity, + } + ) + else: + self._entities.append(entity) + + def make_properties(self, properties: BackendProperties) -> tuple[str, float, str]: + if self.fixed_lineweight: + stroke_width = self.fixed_lineweight + else: + stroke_width = max( + self.min_lineweight, properties.lineweight * self.lineweight_scaling + ) + return (properties.color, round(stroke_width, 2), properties.layer) + + @override + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.add_entity( + geojson_object("Point", list(self._transform_function(pos))), properties + ) + + @override + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + tf = self._transform_function + self.add_entity( + geojson_object("LineString", [tf(start), tf(end)]), + properties, + ) + + @override + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + lines = list(lines) + if len(lines) == 0: + return + tf = self._transform_function + json_lines = [(tf(s), tf(e)) for s, e in lines] + self.add_entity(geojson_object("MultiLineString", json_lines), properties) + + @override + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + if len(path) == 0: + return + tf = self._transform_function + vertices = [tf(v) for v in path.flattening(distance=self.max_sagitta)] + self.add_entity(geojson_object("LineString", vertices), properties) + + @override + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + paths = list(paths) + if len(paths) == 0: + return + + polygons: list[GeoJsonPolygon] = [] + for path in paths: + if len(path): + polygons.extend( + geojson_polygons( + path, max_sagitta=self.max_sagitta, tf=self._transform_function + ) + ) + if polygons: + self.add_entity(geojson_object("MultiPolygon", polygons), properties) + + @override + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + vertices: list[Vec2] = points.vertices() + if len(vertices) < 3: + return + if not vertices[0].isclose(vertices[-1]): + vertices.append(vertices[0]) + # exterior ring, without holes + tf = self._transform_function + self.add_entity( + geojson_object("Polygon", [[tf(v) for v in vertices]]), properties + ) + + +def geojson_object(name: str, coordinates: Any) -> dict[str, Any]: + return {"type": name, "coordinates": coordinates} + + +def geojson_ring( + path: BkPath2d, is_hole: bool, max_sagitta: float, tf: TransformFunc +) -> Ring: + """Returns a linear ring according to the GeoJSON specs. + + - A linear ring is a closed LineString with four or more positions. + - The first and last positions are equivalent, and they MUST contain + identical values; their representation SHOULD also be identical. + - A linear ring is the boundary of a surface or the boundary of a + hole in a surface. + - A linear ring MUST follow the right-hand rule with respect to the + area it bounds, i.e., exterior rings are counterclockwise, and + holes are clockwise. + + """ + if path.has_sub_paths: + raise TypeError("multi-paths not allowed") + vertices: Ring = [tf(v) for v in path.flattening(max_sagitta)] + if not path.is_closed: + start = path.start + vertices.append(tf(start)) + clockwise = path.has_clockwise_orientation() + if (is_hole and not clockwise) or (not is_hole and clockwise): + vertices.reverse() + return vertices + + +def geojson_polygons( + path: BkPath2d, max_sagitta: float, tf: TransformFunc +) -> list[GeoJsonPolygon]: + """Returns a list of polygons, where each polygon is a list of an exterior path and + optional holes e.g. [[ext0, hole0, hole1], [ext1], [ext2, hole0], ...]. + + """ + sub_paths: list[BkPath2d] = path.sub_paths() + if len(sub_paths) == 0: + return [] + if len(sub_paths) == 1: + return [[geojson_ring(sub_paths[0], False, max_sagitta, tf)]] + + polygons = nesting.make_polygon_structure(sub_paths) + geojson_polygons: list[GeoJsonPolygon] = [] + for polygon in polygons: + geojson_polygon: GeoJsonPolygon = [ + geojson_ring(polygon[0], False, max_sagitta, tf) + ] # exterior ring + if len(polygon) > 1: + # GeoJSON has no support for nested hole structures, so the sub polygons of + # holes (hole[1]) are ignored yet! + holes = polygon[1] + if isinstance(holes, BkPath2d): # single hole + geojson_polygon.append(geojson_ring(holes, True, max_sagitta, tf)) + continue + if isinstance(holes, (tuple, list)): # multiple holes + for hole in holes: + if isinstance(hole, (tuple, list)): # nested polygon + # TODO: add sub polygons of holes as separated polygons + hole = hole[0] # exterior path + geojson_polygon.append(geojson_ring(hole, True, max_sagitta, tf)) + + geojson_polygons.append(geojson_polygon) + return geojson_polygons diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/layout.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/layout.py new file mode 100644 index 0000000..3a813df --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/layout.py @@ -0,0 +1,561 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import NamedTuple, TYPE_CHECKING +from typing_extensions import Self + +import math +import enum +import dataclasses +from ezdxf.math import Vec2, BoundingBox2d, Matrix44 + +if TYPE_CHECKING: + from ezdxf.layouts.layout import Layout as DXFLayout + + +class Units(enum.IntEnum): + """Page units as enum. + + Attributes: + inch: 25.4 mm + px: 1/96 inch + pt: 1/72 inch + mm: + cm: + + """ + + # equivalent to ezdxf.units if possible + inch = 1 + px = 2 # no equivalent DXF unit + pt = 3 # no equivalent DXF unit + mm = 4 + cm = 5 + + +# all page sizes in landscape orientation +PAGE_SIZES = { + "ISO A0": (1189, 841, Units.mm), + "ISO A1": (841, 594, Units.mm), + "ISO A2": (594, 420, Units.mm), + "ISO A3": (420, 297, Units.mm), + "ISO A4": (297, 210, Units.mm), + "ANSI A": (11, 8.5, Units.inch), + "ANSI B": (17, 11, Units.inch), + "ANSI C": (22, 17, Units.inch), + "ANSI D": (34, 22, Units.inch), + "ANSI E": (44, 34, Units.inch), + "ARCH C": (24, 18, Units.inch), + "ARCH D": (36, 24, Units.inch), + "ARCH E": (48, 36, Units.inch), + "ARCH E1": (42, 30, Units.inch), + "Letter": (11, 8.5, Units.inch), + "Legal": (14, 8.5, Units.inch), +} + + +UNITS_TO_MM = { + Units.mm: 1.0, + Units.cm: 10.0, + Units.inch: 25.4, + Units.px: 25.4 / 96.0, + Units.pt: 25.4 / 72.0, +} + + +class PageAlignment(enum.IntEnum): + """Page alignment of content as enum. + + Attributes: + TOP_LEFT: + TOP_CENTER: + TOP_RIGHT: + MIDDLE_LEFT: + MIDDLE_CENTER: + MIDDLE_RIGHT: + BOTTOM_LEFT: + BOTTOM_CENTER: + BOTTOM_RIGHT: + + """ + + TOP_LEFT = 1 + TOP_CENTER = 2 + TOP_RIGHT = 3 + MIDDLE_LEFT = 4 + MIDDLE_CENTER = 5 + MIDDLE_RIGHT = 6 + BOTTOM_LEFT = 7 + BOTTOM_CENTER = 8 + BOTTOM_RIGHT = 9 + + +class Margins(NamedTuple): + """Page margins definition class + + Attributes: + top: + left: + bottom: + right: + + """ + + top: float + right: float + bottom: float + left: float + + @classmethod + def all(cls, margin: float) -> Self: + """Returns a page margins definition class with four equal margins.""" + return cls(margin, margin, margin, margin) + + @classmethod + def all2(cls, top_bottom: float, left_right: float) -> Self: + """Returns a page margins definition class with equal top-bottom and + left-right margins. + """ + return cls(top_bottom, left_right, top_bottom, left_right) + + # noinspection PyArgumentList + def scale(self, factor: float) -> Self: + return self.__class__( + self.top * factor, + self.right * factor, + self.bottom * factor, + self.left * factor, + ) + + +@dataclasses.dataclass +class Page: + """Page definition class + + Attributes: + + width: page width, 0 for auto-detect + height: page height, 0 for auto-detect + units: page units as enum :class:`Units` + margins: page margins in page units + max_width: limit width for auto-detection, 0 for unlimited + max_height: limit height for auto-detection, 0 for unlimited + + """ + + width: float + height: float + units: Units = Units.mm + margins: Margins = Margins.all(0) + max_width: float = 0.0 + max_height: float = 0.0 + + def __post_init__(self): + assert isinstance(self.units, Units), "units require type " + assert isinstance(self.margins, Margins), "margins require type " + + @property + def to_mm_factor(self) -> float: + return UNITS_TO_MM[self.units] + + @property + def width_in_mm(self) -> float: + """Returns the page width in mm.""" + return round(self.width * self.to_mm_factor, 1) + + @property + def max_width_in_mm(self) -> float: + """Returns max page width in mm.""" + return round(self.max_width * self.to_mm_factor, 1) + + @property + def height_in_mm(self) -> float: + """Returns the page height in mm.""" + return round(self.height * self.to_mm_factor, 1) + + @property + def max_height_in_mm(self) -> float: + """Returns max page height in mm.""" + return round(self.max_height * self.to_mm_factor, 1) + + @property + def margins_in_mm(self) -> Margins: + """Returns the page margins in mm.""" + return self.margins.scale(self.to_mm_factor) + + @property + def is_landscape(self) -> bool: + """Returns ``True`` if the page has landscape orientation.""" + return self.width > self.height + + @property + def is_portrait(self) -> bool: + """Returns ``True`` if the page has portrait orientation. (square is portrait)""" + return self.width <= self.height + + def to_landscape(self) -> None: + """Converts the page to landscape orientation.""" + if self.is_portrait: + self.width, self.height = self.height, self.width + + def to_portrait(self) -> None: + """Converts the page to portrait orientation.""" + if self.is_landscape: + self.width, self.height = self.height, self.width + + def get_margin_rect(self, top_origin=True) -> tuple[Vec2, Vec2]: + """Returns the bottom-left and the top-right corner of the page margins in mm. + The origin (0, 0) is the top-left corner of the page if `top_origin` is + ``True`` or in the bottom-left corner otherwise. + """ + margins = self.margins_in_mm + right_margin = self.width_in_mm - margins.right + page_height = self.height_in_mm + if top_origin: + bottom_left = Vec2(margins.left, margins.top) + top_right = Vec2(right_margin, page_height - margins.bottom) + else: # bottom origin + bottom_left = Vec2(margins.left, margins.bottom) + top_right = Vec2(right_margin, page_height - margins.top) + return bottom_left, top_right + + @classmethod + def from_dxf_layout(cls, layout: DXFLayout) -> Self: + """Returns the :class:`Page` based on the DXF attributes stored in the LAYOUT + entity. The modelspace layout often **doesn't** have usable page settings! + + Args: + layout: any paperspace layout or the modelspace layout + + """ + # all layout measurements in mm + width = round(layout.dxf.paper_width, 1) + height = round(layout.dxf.paper_height, 1) + top = round(layout.dxf.top_margin, 1) + right = round(layout.dxf.right_margin, 1) + bottom = round(layout.dxf.bottom_margin, 1) + left = round(layout.dxf.left_margin, 1) + + rotation = layout.dxf.plot_rotation + if rotation == 1: # 90 degrees + return cls( + height, + width, + Units.mm, + margins=Margins(top=right, right=bottom, bottom=left, left=top), + ) + elif rotation == 2: # 180 degrees + return cls( + width, + height, + Units.mm, + margins=Margins(top=bottom, right=left, bottom=top, left=right), + ) + elif rotation == 3: # 270 degrees + return cls( + height, + width, + Units.mm, + margins=Margins(top=left, right=top, bottom=right, left=bottom), + ) + return cls( # 0 degrees + width, + height, + Units.mm, + margins=Margins(top=top, right=right, bottom=bottom, left=left), + ) + + +@dataclasses.dataclass +class Settings: + """The Layout settings. + + Attributes: + content_rotation: Rotate content about 0, 90, 180 or 270 degrees + fit_page: Scale content to fit the page. + page_alignment: Supported by backends that use the :class:`Page` class to define + the size of the output media, default alignment is :attr:`PageAlignment.MIDDLE_CENTER` + crop_at_margins: crops the content at the page margins if ``True``, when + supported by the backend, default is ``False`` + scale: Factor to scale the DXF units of model- or paperspace, to represent 1mm + in the rendered output drawing. Only uniform scaling is supported. + + e.g. scale 1:100 and DXF units are meters, 1m = 1000mm corresponds 10mm in + the output drawing = 10 / 1000 = 0.01; + + e.g. scale 1:1; DXF units are mm = 1 / 1 = 1.0 the default value + + The value is ignored if the page size is defined and the content fits the page and + the value is also used to determine missing page sizes (width or height). + max_stroke_width: Used for :class:`LineweightPolicy.RELATIVE` policy, + :attr:`max_stroke_width` is defined as percentage of the content extents, + e.g. 0.001 is 0.1% of max(page-width, page-height) + min_stroke_width: Used for :class:`LineweightPolicy.RELATIVE` policy, + :attr:`min_stroke_width` is defined as percentage of :attr:`max_stroke_width`, + e.g. 0.05 is 5% of :attr:`max_stroke_width` + fixed_stroke_width: Used for :class:`LineweightPolicy.RELATIVE_FIXED` policy, + :attr:`fixed_stroke_width` is defined as percentage of :attr:`max_stroke_width`, + e.g. 0.15 is 15% of :attr:`max_stroke_width` + output_coordinate_space: expert feature to map the DXF coordinates to the + output coordinate system [0, output_coordinate_space] + output_layers: For supported backends, separate the entities into 'layers' in the output + + """ + + content_rotation: int = 0 + fit_page: bool = True + scale: float = 1.0 + page_alignment: PageAlignment = PageAlignment.MIDDLE_CENTER + crop_at_margins: bool = False + # for LineweightPolicy.RELATIVE + # max_stroke_width is defined as percentage of the content extents + max_stroke_width: float = 0.001 # 0.1% of max(width, height) in viewBox coords + # min_stroke_width is defined as percentage of max_stroke_width + min_stroke_width: float = 0.05 # 5% of max_stroke_width + # StrokeWidthPolicy.fixed_1 + # fixed_stroke_width is defined as percentage of max_stroke_width + fixed_stroke_width: float = 0.15 # 15% of max_stroke_width + # PDF, HPGL expect the coordinates in the first quadrant and SVG has an inverted + # y-axis, so transformation from DXF to the output coordinate system is required. + # The output_coordinate_space defines the space into which the DXF coordinates are + # mapped, the range is [0, output_coordinate_space] for the larger page + # dimension - aspect ratio is always preserved - these are CAD drawings! + # The SVGBackend uses this feature to map all coordinates to integer values: + output_coordinate_space: float = 1_000_000 # e.g. for SVGBackend + output_layers: bool = True + + def __post_init__(self) -> None: + if self.content_rotation not in (0, 90, 180, 270): + raise ValueError( + f"invalid content rotation {self.content_rotation}, " + f"expected: 0, 90, 180, 270" + ) + + def page_output_scale_factor(self, page: Page) -> float: + """Returns the scaling factor to map page coordinates in mm to output space + coordinates. + """ + try: + return self.output_coordinate_space / max( + page.width_in_mm, page.height_in_mm + ) + except ZeroDivisionError: + return 1.0 + + +class Layout: + def __init__(self, render_box: BoundingBox2d, flip_y=False) -> None: + super().__init__() + self.flip_y: float = -1.0 if flip_y else 1.0 + self.render_box = render_box + + def get_rotation(self, settings: Settings) -> int: + if settings.content_rotation not in (0, 90, 180, 270): + raise ValueError("content rotation must be 0, 90, 180 or 270 degrees") + rotation = settings.content_rotation + if self.flip_y == -1.0: + if rotation == 90: + rotation = 270 + elif rotation == 270: + rotation = 90 + return rotation + + def get_content_size(self, rotation: int) -> Vec2: + content_size = self.render_box.size + if rotation in (90, 270): + # swap x, y to apply rotation to content_size + content_size = Vec2(content_size.y, content_size.x) + return content_size + + def get_final_page(self, page: Page, settings: Settings) -> Page: + rotation = self.get_rotation(settings) + content_size = self.get_content_size(rotation) + return final_page_size(content_size, page, settings) + + def get_placement_matrix( + self, page: Page, settings=Settings(), top_origin=True + ) -> Matrix44: + # Argument `page` has to be the resolved final page size! + rotation = self.get_rotation(settings) + + content_size = self.get_content_size(rotation) + content_size_mm = content_size * settings.scale + if settings.fit_page: + content_size_mm *= fit_to_page(content_size_mm, page) + try: + scale_dxf_to_mm = content_size_mm.x / content_size.x + except ZeroDivisionError: + scale_dxf_to_mm = 1.0 + # map output coordinates to range [0, output_coordinate_space] + scale_mm_to_output_space = settings.page_output_scale_factor(page) + scale = scale_dxf_to_mm * scale_mm_to_output_space + m = placement_matrix( + self.render_box, + sx=scale, + sy=scale * self.flip_y, + rotation=rotation, + page=page, + output_coordinate_space=settings.output_coordinate_space, + page_alignment=settings.page_alignment, + top_origin=top_origin, + ) + return m + + +def final_page_size(content_size: Vec2, page: Page, settings: Settings) -> Page: + scale = settings.scale + width = page.width_in_mm + height = page.height_in_mm + margins = page.margins_in_mm + if width == 0.0: + width = scale * content_size.x + margins.left + margins.right + if height == 0.0: + height = scale * content_size.y + margins.top + margins.bottom + + width, height = limit_page_size( + width, height, page.max_width_in_mm, page.max_height_in_mm + ) + return Page(round(width, 1), round(height, 1), Units.mm, margins) + + +def limit_page_size( + width: float, height: float, max_width: float, max_height: float +) -> tuple[float, float]: + try: + ar = width / height + except ZeroDivisionError: + return width, height + if max_height: + height = min(max_height, height) + width = height * ar + if max_width and width > max_width: + width = min(max_width, width) + height = width / ar + return width, height + + +def fit_to_page(content_size_mm: Vec2, page: Page) -> float: + margins = page.margins_in_mm + try: + sx = (page.width_in_mm - margins.left - margins.right) / content_size_mm.x + sy = (page.height_in_mm - margins.top - margins.bottom) / content_size_mm.y + except ZeroDivisionError: + return 1.0 + return min(sx, sy) + + +def placement_matrix( + bbox: BoundingBox2d, + sx: float, + sy: float, + rotation: float, + page: Page, + output_coordinate_space: float, + page_alignment: PageAlignment = PageAlignment.MIDDLE_CENTER, + # top_origin True: page origin (0, 0) in top-left corner, +y axis pointing down + # top_origin False: page origin (0, 0) in bottom-left corner, +y axis pointing up + top_origin=True, +) -> Matrix44: + """Returns a matrix to place the bbox in the first quadrant of the coordinate + system (+x, +y). + """ + try: + scale_mm_to_vb = output_coordinate_space / max( + page.width_in_mm, page.height_in_mm + ) + except ZeroDivisionError: + scale_mm_to_vb = 1.0 + margins = page.margins_in_mm + + # create scaling and rotation matrix: + if abs(sx) < 1e-9: + sx = 1.0 + if abs(sy) < 1e-9: + sy = 1.0 + m = Matrix44.scale(sx, sy, 1.0) + if rotation: + m @= Matrix44.z_rotate(math.radians(rotation)) + + # calc bounding box of the final output canvas: + corners = m.transform_vertices(bbox.rect_vertices()) + canvas = BoundingBox2d(corners) + + # shift content to first quadrant +x/+y + tx, ty = canvas.extmin + + # align content within margins + view_box_content_x = ( + page.width_in_mm - margins.left - margins.right + ) * scale_mm_to_vb + view_box_content_y = ( + page.height_in_mm - margins.top - margins.bottom + ) * scale_mm_to_vb + dx = view_box_content_x - canvas.size.x + dy = view_box_content_y - canvas.size.y + offset_x = margins.left * scale_mm_to_vb # left + if top_origin: + offset_y = margins.top * scale_mm_to_vb + else: + offset_y = margins.bottom * scale_mm_to_vb + + if is_center_aligned(page_alignment): + offset_x += dx / 2 + elif is_right_aligned(page_alignment): + offset_x += dx + if is_middle_aligned(page_alignment): + offset_y += dy / 2 + elif is_bottom_aligned(page_alignment): + if top_origin: + offset_y += dy + else: # top aligned + if not top_origin: + offset_y += dy + return m @ Matrix44.translate(-tx + offset_x, -ty + offset_y, 0) + + +def is_left_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.TOP_LEFT, + PageAlignment.MIDDLE_LEFT, + PageAlignment.BOTTOM_LEFT, + ) + + +def is_center_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.TOP_CENTER, + PageAlignment.MIDDLE_CENTER, + PageAlignment.BOTTOM_CENTER, + ) + + +def is_right_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.TOP_RIGHT, + PageAlignment.MIDDLE_RIGHT, + PageAlignment.BOTTOM_RIGHT, + ) + + +def is_top_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.TOP_LEFT, + PageAlignment.TOP_CENTER, + PageAlignment.TOP_RIGHT, + ) + + +def is_middle_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.MIDDLE_LEFT, + PageAlignment.MIDDLE_CENTER, + PageAlignment.MIDDLE_RIGHT, + ) + + +def is_bottom_aligned(align: PageAlignment) -> bool: + return align in ( + PageAlignment.BOTTOM_LEFT, + PageAlignment.BOTTOM_CENTER, + PageAlignment.BOTTOM_RIGHT, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/matplotlib.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/matplotlib.py new file mode 100644 index 0000000..d314058 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/matplotlib.py @@ -0,0 +1,361 @@ +# Copyright (c) 2020-2023, Matthew Broadway +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional, Union +import math +import logging +from os import PathLike + +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.collections import LineCollection +from matplotlib.image import AxesImage +from matplotlib.lines import Line2D +from matplotlib.patches import PathPatch +from matplotlib.path import Path +from matplotlib.transforms import Affine2D + +from ezdxf.npshapes import to_matplotlib_path +from ezdxf.addons.drawing.backend import Backend, BkPath2d, BkPoints2d, ImageData +from ezdxf.addons.drawing.properties import BackendProperties, LayoutProperties +from ezdxf.addons.drawing.type_hints import FilterFunc +from ezdxf.addons.drawing.type_hints import Color +from ezdxf.math import Vec2, Matrix44 +from ezdxf.layouts import Layout +from .config import Configuration + +logger = logging.getLogger("ezdxf") +# matplotlib docs: https://matplotlib.org/index.html + +# line style: +# https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linestyle +# https://matplotlib.org/gallery/lines_bars_and_markers/linestyles.html + +# line width: +# https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linewidth +# points unit (pt), 1pt = 1/72 inch, 1pt = 0.3527mm +POINTS = 1.0 / 0.3527 # mm -> points +CURVE4x3 = (Path.CURVE4, Path.CURVE4, Path.CURVE4) +SCATTER_POINT_SIZE = 0.1 + + +def setup_axes(ax: plt.Axes): + # like set_axis_off, except that the face_color can still be set + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + for s in ax.spines.values(): + s.set_visible(False) + + ax.autoscale(False) + ax.set_aspect("equal", "datalim") + + +class MatplotlibBackend(Backend): + """Backend which uses the :mod:`Matplotlib` package for image export. + + Args: + ax: drawing canvas as :class:`matplotlib.pyplot.Axes` object + adjust_figure: automatically adjust the size of the parent + :class:`matplotlib.pyplot.Figure` to display all content + """ + + def __init__( + self, + ax: plt.Axes, + *, + adjust_figure: bool = True, + ): + super().__init__() + setup_axes(ax) + self.ax = ax + self._adjust_figure = adjust_figure + self._current_z = 0 + + def configure(self, config: Configuration) -> None: + if config.min_lineweight is None: + # If not set by user, use ~1 pixel + figure = self.ax.get_figure() + if figure: + config = config.with_changes(min_lineweight=72.0 / figure.dpi) + super().configure(config) + # LinePolicy.ACCURATE is handled by the frontend since v0.18.1 + + def _get_z(self) -> int: + z = self._current_z + self._current_z += 1 + return z + + def set_background(self, color: Color): + self.ax.set_facecolor(color) + + def draw_point(self, pos: Vec2, properties: BackendProperties): + """Draw a real dimensionless point.""" + color = properties.color + self.ax.scatter( + [pos.x], + [pos.y], + s=SCATTER_POINT_SIZE, + c=color, + zorder=self._get_z(), + ) + + def get_lineweight(self, properties: BackendProperties) -> float: + """Set lineweight_scaling=0 to use a constant minimal lineweight.""" + assert self.config.min_lineweight is not None + return max( + properties.lineweight * self.config.lineweight_scaling, + self.config.min_lineweight, + ) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties): + """Draws a single solid line, line type rendering is done by the + frontend since v0.18.1 + """ + if start.isclose(end): + # matplotlib draws nothing for a zero-length line: + self.draw_point(start, properties) + else: + self.ax.add_line( + Line2D( + (start.x, end.x), + (start.y, end.y), + linewidth=self.get_lineweight(properties), + color=properties.color, + zorder=self._get_z(), + ) + ) + + def draw_solid_lines( + self, + lines: Iterable[tuple[Vec2, Vec2]], + properties: BackendProperties, + ): + """Fast method to draw a bunch of solid lines with the same properties.""" + color = properties.color + lineweight = self.get_lineweight(properties) + _lines = [] + point_x = [] + point_y = [] + z = self._get_z() + for s, e in lines: + if s.isclose(e): + point_x.append(s.x) + point_y.append(s.y) + else: + _lines.append(((s.x, s.y), (e.x, e.y))) + + self.ax.scatter(point_x, point_y, s=SCATTER_POINT_SIZE, c=color, zorder=z) + self.ax.add_collection( + LineCollection( + _lines, + linewidths=lineweight, + color=color, + zorder=z, + capstyle="butt", + ) + ) + + def draw_path(self, path: BkPath2d, properties: BackendProperties): + """Draw a solid line path, line type rendering is done by the + frontend since v0.18.1 + """ + + mpl_path = to_matplotlib_path([path]) + try: + patch = PathPatch( + mpl_path, + linewidth=self.get_lineweight(properties), + fill=False, + color=properties.color, + zorder=self._get_z(), + ) + except ValueError as e: + logger.info(f"ignored matplotlib error: {str(e)}") + else: + self.ax.add_patch(patch) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ): + linewidth = 0 + + try: + patch = PathPatch( + to_matplotlib_path(paths, detect_holes=True), + color=properties.color, + linewidth=linewidth, + fill=True, + zorder=self._get_z(), + ) + except ValueError as e: + logger.info(f"ignored matplotlib error in draw_filled_paths(): {str(e)}") + else: + self.ax.add_patch(patch) + + def draw_filled_polygon(self, points: BkPoints2d, properties: BackendProperties): + self.ax.fill( + *zip(*((p.x, p.y) for p in points.vertices())), + color=properties.color, + linewidth=0, + zorder=self._get_z(), + ) + + def draw_image( + self, image_data: ImageData, properties: BackendProperties + ) -> None: + height, width, depth = image_data.image.shape + assert depth == 4 + + # using AxesImage directly avoids an issue with ax.imshow where the data limits + # are updated to include the un-transformed image because the transform is applied + # afterward. We can use a slight hack which is that the outlines of images are drawn + # as well as the image itself, so we don't have to adjust the data limits at all here + # as the outline will take care of that + handle = AxesImage(self.ax, interpolation="antialiased") + handle.set_data(np.flip(image_data.image, axis=0)) + handle.set_zorder(self._get_z()) + + ( + m11, + m12, + m13, + m14, + m21, + m22, + m23, + m24, + m31, + m32, + m33, + m34, + m41, + m42, + m43, + m44, + ) = image_data.transform + matplotlib_transform = Affine2D( + matrix=np.array( + [ + [m11, m21, m41], + [m12, m22, m42], + [0, 0, 1], + ] + ) + ) + handle.set_transform(matplotlib_transform + self.ax.transData) + self.ax.add_image(handle) + + def clear(self): + self.ax.clear() + + def finalize(self): + super().finalize() + self.ax.autoscale(True) + if self._adjust_figure: + minx, maxx = self.ax.get_xlim() + miny, maxy = self.ax.get_ylim() + data_width, data_height = maxx - minx, maxy - miny + if not math.isclose(data_width, 0): + width, height = plt.figaspect(data_height / data_width) + self.ax.get_figure().set_size_inches(width, height, forward=True) + + +def _get_aspect_ratio(ax: plt.Axes) -> float: + minx, maxx = ax.get_xlim() + miny, maxy = ax.get_ylim() + data_width, data_height = maxx - minx, maxy - miny + if abs(data_height) > 1e-9: + return data_width / data_height + return 1.0 + + +def _get_width_height(ratio: float, width: float, height: float) -> tuple[float, float]: + if width == 0.0 and height == 0.0: + raise ValueError("invalid (width, height) values") + if width == 0.0: + width = height * ratio + elif height == 0.0: + height = width / ratio + return width, height + + +def qsave( + layout: Layout, + filename: Union[str, PathLike], + *, + bg: Optional[Color] = None, + fg: Optional[Color] = None, + dpi: int = 300, + backend: str = "agg", + config: Optional[Configuration] = None, + filter_func: Optional[FilterFunc] = None, + size_inches: Optional[tuple[float, float]] = None, +) -> None: + """Quick and simplified render export by matplotlib. + + Args: + layout: modelspace or paperspace layout to export + filename: export filename, file extension determines the format e.g. + "image.png" to save in PNG format. + bg: override default background color in hex format #RRGGBB or #RRGGBBAA, + e.g. use bg="#FFFFFF00" to get a transparent background and a black + foreground color (ACI=7), because a white background #FFFFFF gets a + black foreground color or vice versa bg="#00000000" for a transparent + (black) background and a white foreground color. + fg: override default foreground color in hex format #RRGGBB or #RRGGBBAA, + requires also `bg` argument. There is no explicit foreground color + in DXF defined (also not a background color), but the ACI color 7 + has already a variable color value, black on a light background and + white on a dark background, this argument overrides this (ACI=7) + default color value. + dpi: image resolution (dots per inches). + size_inches: paper size in inch as `(width, height)` tuple, which also + defines the size in pixels = (`width` * `dpi`) x (`height` * `dpi`). + If `width` or `height` is 0.0 the value is calculated by the aspect + ratio of the drawing. + backend: the matplotlib rendering backend to use (agg, cairo, svg etc) + (see documentation for `matplotlib.use() `_ + for a complete list of backends) + config: drawing parameters + filter_func: filter function which takes a DXFGraphic object as input + and returns ``True`` if the entity should be drawn or ``False`` if + the entity should be ignored + + """ + from .properties import RenderContext + from .frontend import Frontend + import matplotlib + + # Set the backend to prevent warnings about GUIs being opened from a thread + # other than the main thread. + old_backend = matplotlib.get_backend() + matplotlib.use(backend) + if config is None: + config = Configuration() + + try: + fig: plt.Figure = plt.figure(dpi=dpi) + ax: plt.Axes = fig.add_axes((0, 0, 1, 1)) + ctx = RenderContext(layout.doc) + layout_properties = LayoutProperties.from_layout(layout) + if bg is not None: + layout_properties.set_colors(bg, fg) + out = MatplotlibBackend(ax) + Frontend(ctx, out, config).draw_layout( + layout, + finalize=True, + filter_func=filter_func, + layout_properties=layout_properties, + ) + # transparent=True sets the axes color to fully transparent + # facecolor sets the figure color + # (semi-)transparent axes colors do not produce transparent outputs + # but (semi-)transparent figure colors do. + if size_inches is not None: + ratio = _get_aspect_ratio(ax) + w, h = _get_width_height(ratio, size_inches[0], size_inches[1]) + fig.set_size_inches(w, h, True) + fig.savefig(filename, dpi=dpi, facecolor=ax.get_facecolor(), transparent=True) + plt.close(fig) + finally: + matplotlib.use(old_backend) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/mtext_complex.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/mtext_complex.py new file mode 100644 index 0000000..944c270 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/mtext_complex.py @@ -0,0 +1,310 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional +from typing_extensions import Protocol +import copy +import math + +from ezdxf import colors +from ezdxf.entities import MText +from ezdxf.lldxf import const +from ezdxf.math import Matrix44, Vec3, AnyVec +from ezdxf.render.abstract_mtext_renderer import AbstractMTextRenderer +from ezdxf.fonts import fonts +from ezdxf.tools import text_layout as tl +from ezdxf.tools.text import MTextContext +from .properties import Properties, RenderContext, rgb_to_hex +from .type_hints import Color + +__all__ = ["complex_mtext_renderer"] + + +def corner_vertices( + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, +) -> Iterable[Vec3]: + corners = [ # closed polygon: fist vertex == last vertex + (left, top), + (right, top), + (right, bottom), + (left, bottom), + (left, top), + ] + if m is None: + return Vec3.generate(corners) + else: + return m.transform_vertices(corners) + + +class DrawInterface(Protocol): + def draw_line(self, start: AnyVec, end: AnyVec, properties: Properties) -> None: + ... + + def draw_filled_polygon( + self, points: Iterable[AnyVec], properties: Properties + ) -> None: + ... + + def draw_text( + self, + text: str, + transform: Matrix44, + properties: Properties, + cap_height: float, + ) -> None: + ... + + +class FrameRenderer(tl.ContentRenderer): + def __init__(self, properties: Properties, backend: DrawInterface): + self.properties = properties + self.backend = backend + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ) -> None: + self._render_outline(list(corner_vertices(left, bottom, right, top, m))) + + def _render_outline(self, vertices: list[Vec3]) -> None: + backend = self.backend + properties = self.properties + prev = vertices.pop(0) + for vertex in vertices: + backend.draw_line(prev, vertex, properties) + prev = vertex + + def line( + self, x1: float, y1: float, x2: float, y2: float, m: Matrix44 = None + ) -> None: + points = [(x1, y1), (x2, y2)] + if m is not None: + p1, p2 = m.transform_vertices(points) + else: + p1, p2 = Vec3.generate(points) + self.backend.draw_line(p1, p2, self.properties) + + +class ColumnBackgroundRenderer(FrameRenderer): + def __init__( + self, + properties: Properties, + backend: DrawInterface, + bg_properties: Optional[Properties] = None, + offset: float = 0, + text_frame: bool = False, + ): + super().__init__(properties, backend) + self.bg_properties = bg_properties + self.offset = offset # background border offset + self.has_text_frame = text_frame + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ) -> None: + # Important: this is not a clipping box, it is possible to + # render anything outside of the given borders! + offset = self.offset + vertices = list( + corner_vertices( + left - offset, bottom - offset, right + offset, top + offset, m + ) + ) + if self.bg_properties is not None: + self.backend.draw_filled_polygon(vertices, self.bg_properties) + if self.has_text_frame: + self._render_outline(vertices) + + +class TextRenderer(FrameRenderer): + """Text content renderer.""" + + def __init__( + self, + text: str, + cap_height: float, + width_factor: float, + oblique: float, # angle in degrees + properties: Properties, + backend: DrawInterface, + ): + super().__init__(properties, backend) + self.text = text + self.cap_height = cap_height + self.width_factor = width_factor + self.oblique = oblique # angle in degrees + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ): + """Create/render the text content""" + sx = 1.0 + tx = 0.0 + if not math.isclose(self.width_factor, 1.0, rel_tol=1e-6): + sx = self.width_factor + if abs(self.oblique) > 1e-3: # degrees + tx = math.tan(math.radians(self.oblique)) + # fmt: off + t = Matrix44(( + sx, 0.0, 0.0, 0.0, + tx, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + left, bottom, 0.0, 1.0 + )) + # fmt: on + if m is not None: + t *= m + self.backend.draw_text(self.text, t, self.properties, self.cap_height) + + +def complex_mtext_renderer( + ctx: RenderContext, + backend: DrawInterface, + mtext: MText, + properties: Properties, +) -> None: + cmr = ComplexMTextRenderer(ctx, backend, properties) + align = tl.LayoutAlignment(mtext.dxf.attachment_point) + layout_engine = cmr.layout_engine(mtext) + layout_engine.place(align=align) + layout_engine.render(mtext.ucs().matrix) + + +class ComplexMTextRenderer(AbstractMTextRenderer): + def __init__( + self, + ctx: RenderContext, + backend: DrawInterface, + properties: Properties, + ): + super().__init__() + self._render_ctx = ctx + self._backend = backend + self._properties = properties + + # Implementation of required AbstractMTextRenderer methods: + + def word(self, text: str, ctx: MTextContext) -> tl.ContentCell: + return tl.Text( + width=self.get_font(ctx).text_width(text), + height=ctx.cap_height, + valign=tl.CellAlignment(ctx.align), + stroke=self.get_stroke(ctx), + renderer=TextRenderer( + text, + ctx.cap_height, + ctx.width_factor, + ctx.oblique, + self.new_text_properties(self._properties, ctx), + self._backend, + ), + ) + + def fraction(self, data: tuple[str, str, str], ctx: MTextContext) -> tl.ContentCell: + upr, lwr, type_ = data + if type_: + return tl.Fraction( + top=self.word(upr, ctx), + bottom=self.word(lwr, ctx), + stacking=self.get_stacking(type_), + # renders just the divider line: + renderer=FrameRenderer(self._properties, self._backend), + ) + else: + return self.word(upr, ctx) + + def get_font_face(self, mtext: MText) -> fonts.FontFace: + return self._properties.font # type: ignore + + def make_bg_renderer(self, mtext: MText) -> tl.ContentRenderer: + dxf = mtext.dxf + bg_fill = dxf.get("bg_fill", 0) + + bg_aci = None + bg_true_color = None + bg_properties: Optional[Properties] = None + has_text_frame = False + offset = 0 + if bg_fill: + # The fill scale is a multiple of the initial char height and + # a scale of 1, fits exact the outer border + # of the column -> offset = 0 + offset = dxf.char_height * (dxf.get("box_fill_scale", 1.5) - 1) + if bg_fill & const.MTEXT_BG_COLOR: + if dxf.hasattr("bg_fill_color"): + bg_aci = dxf.bg_fill_color + + if dxf.hasattr("bg_fill_true_color"): + bg_aci = None + bg_true_color = dxf.bg_fill_true_color + + if (bg_fill & 3) == 3: # canvas color = bit 0 and 1 set + # can not detect canvas color from DXF document! + # do not draw any background: + bg_aci = None + bg_true_color = None + + if bg_fill & const.MTEXT_TEXT_FRAME: + has_text_frame = True + bg_properties = self.new_bg_properties(bg_aci, bg_true_color) + + return ColumnBackgroundRenderer( + self._properties, + self._backend, + bg_properties, + offset=offset, + text_frame=has_text_frame, + ) + + # Implementation details of ComplexMTextRenderer: + + @property + def backend(self) -> DrawInterface: + return self._backend + + def resolve_aci_color(self, aci: int) -> Color: + return self._render_ctx.resolve_aci_color(aci, self._properties.layer) + + def new_text_properties( + self, properties: Properties, ctx: MTextContext + ) -> Properties: + new_properties = copy.copy(properties) + if ctx.rgb is None: + new_properties.color = self.resolve_aci_color(ctx.aci) + else: + new_properties.color = rgb_to_hex(ctx.rgb) + new_properties.font = ctx.font_face + return new_properties + + def new_bg_properties( + self, aci: Optional[int], true_color: Optional[int] + ) -> Properties: + new_properties = copy.copy(self._properties) + new_properties.color = ( # canvas background color + self._render_ctx.current_layout_properties.background_color + ) + if true_color is None: + if aci is not None: + new_properties.color = self.resolve_aci_color(aci) + # else canvas background color + else: + new_properties.color = rgb_to_hex(colors.int2rgb(true_color)) + return new_properties diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pipeline.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pipeline.py new file mode 100644 index 0000000..68dbef6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pipeline.py @@ -0,0 +1,886 @@ +# Copyright (c) 2023-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Sequence, + Optional, + Iterable, + Tuple, + Iterator, + Callable, +) +from typing_extensions import TypeAlias +import abc + +import numpy as np +import PIL.Image +import PIL.ImageDraw +import PIL.ImageOps + + +from ezdxf.colors import RGB +import ezdxf.bbox + +from ezdxf.fonts import fonts +from ezdxf.math import Vec2, Matrix44, BoundingBox2d, AnyVec +from ezdxf.path import make_path, Path +from ezdxf.render import linetypes +from ezdxf.entities import DXFGraphic, Viewport +from ezdxf.tools.text import replace_non_printable_characters +from ezdxf.tools.clipping_portal import ( + ClippingPortal, + ClippingShape, + find_best_clipping_shape, +) +from ezdxf.layouts import Layout +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import LinePolicy, TextPolicy, ColorPolicy, Configuration +from .properties import BackendProperties, Filling +from .properties import Properties, RenderContext +from .type_hints import Color +from .unified_text_renderer import UnifiedTextRenderer + +PatternKey: TypeAlias = Tuple[str, float] +DrawEntitiesCallback: TypeAlias = Callable[[RenderContext, Iterable[DXFGraphic]], None] + +__all__ = ["AbstractPipeline", "RenderPipeline2d"] + + +class AbstractPipeline(abc.ABC): + """This drawing pipeline separates the frontend from the backend and implements + these features: + + - automatically linetype rendering + - font rendering + - VIEWPORT rendering + - foreground color mapping according Frontend.config.color_policy + + The pipeline is organized as concatenated render stages. + + """ + + text_engine = UnifiedTextRenderer() + default_font_face = fonts.FontFace() + draw_entities: DrawEntitiesCallback + + @abc.abstractmethod + def set_draw_entities_callback(self, callback: DrawEntitiesCallback) -> None: ... + + @abc.abstractmethod + def set_config(self, config: Configuration) -> None: ... + + @abc.abstractmethod + def set_current_entity_handle(self, handle: str) -> None: ... + + @abc.abstractmethod + def push_clipping_shape( + self, shape: ClippingShape, transform: Matrix44 | None + ) -> None: ... + + @abc.abstractmethod + def pop_clipping_shape(self) -> None: ... + + @abc.abstractmethod + def draw_viewport( + self, + vp: Viewport, + layout_ctx: RenderContext, + bbox_cache: Optional[ezdxf.bbox.Cache] = None, + ) -> None: + """Draw the content of the given viewport current viewport.""" + ... + + @abc.abstractmethod + def draw_point(self, pos: AnyVec, properties: Properties) -> None: ... + + @abc.abstractmethod + def draw_line(self, start: AnyVec, end: AnyVec, properties: Properties): ... + + @abc.abstractmethod + def draw_solid_lines( + self, lines: Iterable[tuple[AnyVec, AnyVec]], properties: Properties + ) -> None: ... + + @abc.abstractmethod + def draw_path(self, path: Path, properties: Properties): ... + + @abc.abstractmethod + def draw_filled_paths( + self, + paths: Iterable[Path], + properties: Properties, + ) -> None: ... + + @abc.abstractmethod + def draw_filled_polygon( + self, points: Iterable[AnyVec], properties: Properties + ) -> None: ... + + @abc.abstractmethod + def draw_text( + self, + text: str, + transform: Matrix44, + properties: Properties, + cap_height: float, + dxftype: str = "TEXT", + ) -> None: ... + + @abc.abstractmethod + def draw_image(self, image_data: ImageData, properties: Properties) -> None: ... + + @abc.abstractmethod + def finalize(self) -> None: ... + + @abc.abstractmethod + def set_background(self, color: Color) -> None: ... + + @abc.abstractmethod + def enter_entity(self, entity: DXFGraphic, properties: Properties) -> None: + # gets the full DXF properties information + ... + + @abc.abstractmethod + def exit_entity(self, entity: DXFGraphic) -> None: ... + + +class RenderStage2d(abc.ABC): + next_stage: RenderStage2d + + def set_config(self, config: Configuration) -> None: + pass + + @abc.abstractmethod + def draw_point(self, pos: Vec2, properties: Properties) -> None: ... + + @abc.abstractmethod + def draw_line(self, start: Vec2, end: Vec2, properties: Properties): ... + + @abc.abstractmethod + def draw_solid_lines( + self, lines: list[tuple[Vec2, Vec2]], properties: Properties + ) -> None: ... + + @abc.abstractmethod + def draw_path(self, path: BkPath2d, properties: Properties): ... + + @abc.abstractmethod + def draw_filled_paths( + self, + paths: list[BkPath2d], + properties: Properties, + ) -> None: ... + + @abc.abstractmethod + def draw_filled_polygon( + self, points: BkPoints2d, properties: Properties + ) -> None: ... + + @abc.abstractmethod + def draw_image(self, image_data: ImageData, properties: Properties) -> None: ... + + +class RenderPipeline2d(AbstractPipeline): + """Render pipeline for 2D backends.""" + + def __init__(self, backend: BackendInterface): + self.backend = backend + self.config = Configuration() + try: # request default font face + self.default_font_face = fonts.font_manager.get_font_face("") + except fonts.FontNotFoundError: # no default font found + # last resort MonospaceFont which renders only "tofu" + pass + self.clipping_portal = ClippingPortal() + self.current_vp_scale = 1.0 + self._current_entity_handle: str = "" + self._color_mapping: dict[str, str] = dict() + self._pipeline = self.build_render_pipeline() + + def build_render_pipeline(self) -> RenderStage2d: + backend_stage = BackendStage2d( + self.backend, converter=self.get_backend_properties + ) + linetype_stage = LinetypeStage2d( + self.config, + get_ltype_scale=self.get_vp_ltype_scale, + next_stage=backend_stage, + ) + clipping_stage = ClippingStage2d( + self.config, self.clipping_portal, next_stage=linetype_stage + ) + return clipping_stage + + def get_vp_ltype_scale(self) -> float: + """The linetype pattern should look the same in all viewports + regardless of the viewport scale. + """ + return 1.0 / max(self.current_vp_scale, 0.0001) # max out at 1:10000 + + def get_backend_properties(self, properties: Properties) -> BackendProperties: + try: + color = self._color_mapping[properties.color] + except KeyError: + color = apply_color_policy( + properties.color, self.config.color_policy, self.config.custom_fg_color + ) + self._color_mapping[properties.color] = color + return BackendProperties( + color, + properties.lineweight, + properties.layer, + properties.pen, + self._current_entity_handle, + ) + + def set_draw_entities_callback(self, callback: DrawEntitiesCallback) -> None: + self.draw_entities = callback + + def set_config(self, config: Configuration) -> None: + self.backend.configure(config) + self.config = config + stage = self._pipeline + while True: + stage.set_config(config) + if not hasattr(stage, "next_stage"): # BackendStage2d + return + stage = stage.next_stage + + def set_current_entity_handle(self, handle: str) -> None: + assert handle is not None + self._current_entity_handle = handle + + def push_clipping_shape( + self, shape: ClippingShape, transform: Matrix44 | None + ) -> None: + self.clipping_portal.push(shape, transform) + + def pop_clipping_shape(self) -> None: + self.clipping_portal.pop() + + def draw_viewport( + self, + vp: Viewport, + layout_ctx: RenderContext, + bbox_cache: Optional[ezdxf.bbox.Cache] = None, + ) -> None: + """Draw the content of the given viewport current viewport.""" + if vp.doc is None: + return + try: + msp_limits = vp.get_modelspace_limits() + except ValueError: # modelspace limits not detectable + return + if self.enter_viewport(vp): + self.draw_entities( + layout_ctx.from_viewport(vp), + filter_vp_entities(vp.doc.modelspace(), msp_limits, bbox_cache), + ) + self.exit_viewport() + + def enter_viewport(self, vp: Viewport) -> bool: + """Set current viewport, returns ``True`` for valid viewports.""" + self.current_vp_scale = vp.get_scale() + m = vp.get_transformation_matrix() + clipping_path = make_path(vp) + if len(clipping_path): + vertices = clipping_path.control_vertices() + if clipping_path.has_curves: + layout = vp.get_layout() + if isinstance(layout, Layout): + # plot paper units: + # 0: inches, max sagitta = 1/254 = 0.1 mm + # 1: millimeters, max sagitta = 0.1 mm + # 2: pixels, max sagitta = 0.1 pixel + units = layout.dxf.get("plot_paper_units", 1) + max_sagitta = 1.0 / 254.0 if units == 0 else 0.1 + vertices = list(clipping_path.flattening(max_sagitta)) + clipping_shape = find_best_clipping_shape(vertices) + self.clipping_portal.push(clipping_shape, m) + return True + return False + + def exit_viewport(self): + self.clipping_portal.pop() + # Reset viewport scaling: viewports cannot be nested! + self.current_vp_scale = 1.0 + + def draw_text( + self, + text: str, + transform: Matrix44, + properties: Properties, + cap_height: float, + dxftype: str = "TEXT", + ) -> None: + """Render text as filled paths.""" + text_policy = self.config.text_policy + pipeline = self._pipeline + + if not text.strip() or text_policy == TextPolicy.IGNORE: + return # no point rendering empty strings + text = prepare_string_for_rendering(text, dxftype) + font_face = properties.font + if font_face is None: + font_face = self.default_font_face + + try: + glyph_paths = self.text_engine.get_text_glyph_paths( + text, font_face, cap_height + ) + except (RuntimeError, ValueError): + return + for p in glyph_paths: + p.transform_inplace(transform) + transformed_paths: list[BkPath2d] = glyph_paths + + points: list[Vec2] + if text_policy == TextPolicy.REPLACE_RECT: + points = [] + for p in transformed_paths: + points.extend(p.extents()) + if len(points) < 2: + return + rect = BkPath2d.from_vertices(BoundingBox2d(points).rect_vertices()) + pipeline.draw_path(rect, properties) + return + if text_policy == TextPolicy.REPLACE_FILL: + points = [] + for p in transformed_paths: + points.extend(p.extents()) + if len(points) < 2: + return + polygon = BkPoints2d(BoundingBox2d(points).rect_vertices()) + if properties.filling is None: + properties.filling = Filling() + pipeline.draw_filled_polygon(polygon, properties) + return + + if ( + self.text_engine.is_stroke_font(font_face) + or text_policy == TextPolicy.OUTLINE + ): + for text_path in transformed_paths: + pipeline.draw_path(text_path, properties) + return + + if properties.filling is None: + properties.filling = Filling() + pipeline.draw_filled_paths(transformed_paths, properties) + + def finalize(self) -> None: + self.backend.finalize() + + def set_background(self, color: Color) -> None: + self.backend.set_background(color) + + def enter_entity(self, entity: DXFGraphic, properties: Properties) -> None: + self.backend.enter_entity(entity, properties) + + def exit_entity(self, entity: DXFGraphic) -> None: + self.backend.exit_entity(entity) + + # Enter render pipeline: + def draw_point(self, pos: AnyVec, properties: Properties) -> None: + self._pipeline.draw_point(Vec2(pos), properties) + + def draw_line(self, start: AnyVec, end: AnyVec, properties: Properties): + self._pipeline.draw_line(Vec2(start), Vec2(end), properties) + + def draw_solid_lines( + self, lines: Iterable[tuple[AnyVec, AnyVec]], properties: Properties + ) -> None: + self._pipeline.draw_solid_lines( + [(Vec2(s), Vec2(e)) for s, e in lines], properties + ) + + def draw_path(self, path: Path, properties: Properties): + self._pipeline.draw_path(BkPath2d(path), properties) + + def draw_filled_paths( + self, + paths: Iterable[Path], + properties: Properties, + ) -> None: + self._pipeline.draw_filled_paths(list(map(BkPath2d, paths)), properties) + + def draw_filled_polygon( + self, points: Iterable[AnyVec], properties: Properties + ) -> None: + self._pipeline.draw_filled_polygon(BkPoints2d(points), properties) + + def draw_image(self, image_data: ImageData, properties: Properties) -> None: + self._pipeline.draw_image(image_data, properties) + + +class ClippingStage2d(RenderStage2d): + def __init__( + self, + config: Configuration, + clipping_portal: ClippingPortal, + next_stage: RenderStage2d, + ): + self.clipping_portal = clipping_portal + self.config = config + self.next_stage = next_stage + + def set_config(self, config: Configuration) -> None: + self.config = config + + def draw_point(self, pos: Vec2, properties: Properties) -> None: + if self.clipping_portal.is_active: + pos = self.clipping_portal.clip_point(pos) + if pos is None: + return + self.next_stage.draw_point(pos, properties) + + def draw_line(self, start: Vec2, end: Vec2, properties: Properties): + next_stage = self.next_stage + clipping_portal = self.clipping_portal + + if clipping_portal.is_active: + for segment in clipping_portal.clip_line(start, end): + next_stage.draw_line(segment[0], segment[1], properties) + return + next_stage.draw_line(start, end, properties) + + def draw_solid_lines( + self, lines: list[tuple[Vec2, Vec2]], properties: Properties + ) -> None: + clipping_portal = self.clipping_portal + + if clipping_portal.is_active: + cropped_lines: list[tuple[Vec2, Vec2]] = [] + for start, end in lines: + cropped_lines.extend(clipping_portal.clip_line(start, end)) + lines = cropped_lines + self.next_stage.draw_solid_lines(lines, properties) + + def draw_path(self, path: BkPath2d, properties: Properties): + clipping_portal = self.clipping_portal + next_stage = self.next_stage + max_sagitta = self.config.max_flattening_distance + + if clipping_portal.is_active: + for clipped_path in clipping_portal.clip_paths([path], max_sagitta): + next_stage.draw_path(clipped_path, properties) + return + next_stage.draw_path(path, properties) + + def draw_filled_paths( + self, + paths: list[BkPath2d], + properties: Properties, + ) -> None: + clipping_portal = self.clipping_portal + max_sagitta = self.config.max_flattening_distance + + if clipping_portal.is_active: + paths = clipping_portal.clip_filled_paths(paths, max_sagitta) + if len(paths) == 0: + return + self.next_stage.draw_filled_paths(paths, properties) + + def draw_filled_polygon(self, points: BkPoints2d, properties: Properties) -> None: + clipping_portal = self.clipping_portal + next_stage = self.next_stage + + if clipping_portal.is_active: + for points in clipping_portal.clip_polygon(points): + if len(points) > 0: + next_stage.draw_filled_polygon(points, properties) + return + + if len(points) > 0: + next_stage.draw_filled_polygon(points, properties) + + def draw_image(self, image_data: ImageData, properties: Properties) -> None: + # the outer bounds contain the visible parts of the image for the + # clip mode "remove inside" + outer_bounds: list[BkPoints2d] = [] + clipping_portal = self.clipping_portal + + if not clipping_portal.is_active: + self._draw_image(image_data, outer_bounds, properties) + return + + # the pixel boundary path can be split into multiple paths + transform = image_data.flip_matrix() * image_data.transform + pixel_boundary_path = image_data.pixel_boundary_path + clipping_paths = _clip_image_polygon( + clipping_portal, pixel_boundary_path, transform + ) + if not image_data.remove_outside: + # remove inside: + # detect the visible parts of the image which are not removed by + # clipping through viewports or block references + width, height = image_data.image_size() + outer_boundary = BkPoints2d( + Vec2.generate([(0, 0), (width, 0), (width, height), (0, height)]) + ) + outer_bounds = _clip_image_polygon( + clipping_portal, outer_boundary, transform + ) + image_data.transform = clipping_portal.transform_matrix(image_data.transform) + if len(clipping_paths) == 1: + new_clipping_path = clipping_paths[0] + if new_clipping_path is not image_data.pixel_boundary_path: + image_data.pixel_boundary_path = new_clipping_path + # forced clipping triggered by viewport- or block reference clipping: + image_data.use_clipping_boundary = True + self._draw_image(image_data, outer_bounds, properties) + else: + for clipping_path in clipping_paths: + # when clipping path is split into multiple parts: + # copy image for each part, not efficient but works + # this should be a rare usecase so optimization is not required + self._draw_image( + ImageData( + image=image_data.image.copy(), + transform=image_data.transform, + pixel_boundary_path=clipping_path, + use_clipping_boundary=True, + ), + outer_bounds, + properties, + ) + + def _draw_image( + self, + image_data: ImageData, + outer_bounds: list[BkPoints2d], + properties: Properties, + ) -> None: + if image_data.use_clipping_boundary: + _mask_image(image_data, outer_bounds) + self.next_stage.draw_image(image_data, properties) + + +class LinetypeStage2d(RenderStage2d): + def __init__( + self, + config: Configuration, + get_ltype_scale: Callable[[], float], + next_stage: RenderStage2d, + ): + self.config = config + self.solid_lines_only = False + self.next_stage = next_stage + self.get_ltype_scale = get_ltype_scale + self.pattern_cache: dict[PatternKey, Sequence[float]] = dict() + self.set_config(config) + + def set_config(self, config: Configuration) -> None: + self.config = config + self.solid_lines_only = config.line_policy == LinePolicy.SOLID + + def pattern(self, properties: Properties) -> Sequence[float]: + """Returns simplified linetype tuple: on-off sequence""" + if self.solid_lines_only: + scale = 0.0 + else: + scale = properties.linetype_scale * self.get_ltype_scale() + + key: PatternKey = (properties.linetype_name, scale) + pattern_ = self.pattern_cache.get(key) + if pattern_ is None: + pattern_ = self._create_pattern(properties, scale) + self.pattern_cache[key] = pattern_ + return pattern_ + + def _create_pattern(self, properties: Properties, scale: float) -> Sequence[float]: + if len(properties.linetype_pattern) < 2: + # Do not return None -> None indicates: "not cached" + return tuple() + + min_dash_length = self.config.min_dash_length * self.get_ltype_scale() + pattern = [max(e * scale, min_dash_length) for e in properties.linetype_pattern] + if len(pattern) % 2: + pattern.pop() + return pattern + + def draw_point(self, pos: Vec2, properties: Properties) -> None: + self.next_stage.draw_point(pos, properties) + + def draw_line(self, start: Vec2, end: Vec2, properties: Properties): + s = Vec2(start) + e = Vec2(end) + next_stage = self.next_stage + + if self.solid_lines_only or len(properties.linetype_pattern) < 2: # CONTINUOUS + next_stage.draw_line(s, e, properties) + return + + renderer = linetypes.LineTypeRenderer(self.pattern(properties)) + next_stage.draw_solid_lines( + [(s, e) for s, e in renderer.line_segment(s, e)], + properties, + ) + + def draw_solid_lines( + self, lines: list[tuple[Vec2, Vec2]], properties: Properties + ) -> None: + self.next_stage.draw_solid_lines(lines, properties) + + def draw_path(self, path: BkPath2d, properties: Properties): + next_stage = self.next_stage + + if self.solid_lines_only or len(properties.linetype_pattern) < 2: # CONTINUOUS + next_stage.draw_path(path, properties) + return + + renderer = linetypes.LineTypeRenderer(self.pattern(properties)) + vertices = path.flattening(self.config.max_flattening_distance, segments=16) + next_stage.draw_solid_lines( + [(Vec2(s), Vec2(e)) for s, e in renderer.line_segments(vertices)], + properties, + ) + + def draw_filled_paths( + self, + paths: list[BkPath2d], + properties: Properties, + ) -> None: + self.next_stage.draw_filled_paths(paths, properties) + + def draw_filled_polygon(self, points: BkPoints2d, properties: Properties) -> None: + self.next_stage.draw_filled_polygon(points, properties) + + def draw_image(self, image_data: ImageData, properties: Properties) -> None: + self.next_stage.draw_image(image_data, properties) + + +class BackendStage2d(RenderStage2d): + """Send data to the output backend.""" + + def __init__( + self, + backend: BackendInterface, + converter: Callable[[Properties], BackendProperties], + ): + self.backend = backend + self.converter = converter + assert not hasattr(self, "next_stage"), "has to be the last render stage" + + def draw_point(self, pos: Vec2, properties: Properties) -> None: + self.backend.draw_point(pos, self.converter(properties)) + + def draw_line(self, start: Vec2, end: Vec2, properties: Properties): + self.backend.draw_line(start, end, self.converter(properties)) + + def draw_solid_lines( + self, lines: list[tuple[Vec2, Vec2]], properties: Properties + ) -> None: + self.backend.draw_solid_lines(lines, self.converter(properties)) + + def draw_path(self, path: BkPath2d, properties: Properties): + self.backend.draw_path(path, self.converter(properties)) + + def draw_filled_paths( + self, + paths: list[BkPath2d], + properties: Properties, + ) -> None: + self.backend.draw_filled_paths(paths, self.converter(properties)) + + def draw_filled_polygon(self, points: BkPoints2d, properties: Properties) -> None: + self.backend.draw_filled_polygon(points, self.converter(properties)) + + def draw_image(self, image_data: ImageData, properties: Properties) -> None: + self.backend.draw_image(image_data, self.converter(properties)) + + +def _mask_image(image_data: ImageData, outer_bounds: list[BkPoints2d]) -> None: + """Mask away the clipped parts of the image. The argument `outer_bounds` is only + used for clip mode "remove_inside". The outer bounds can be composed of multiple + parts. If `outer_bounds` is empty the image has no removed parts and is fully + visible before applying the image clipping path. + + Args: + image_data: + image_data.pixel_boundary: path contains the image clipping path + image_data.remove_outside: defines the clipping mode (inside/outside) + outer_bounds: countain the parts of the image which are __not__ removed by + clipping through viewports or clipped block references + e.g. an image without any removed parts has the outer bounds + [(0, 0) (width, 0), (width, height), (0, height)] + + """ + clip_polygon = [(p.x, p.y) for p in image_data.pixel_boundary_path.vertices()] + # create an empty image + clipping_image = PIL.Image.new("L", image_data.image_size(), 0) + # paint in the clipping path + PIL.ImageDraw.ImageDraw(clipping_image).polygon( + clip_polygon, outline=None, width=0, fill=1 + ) + clipping_mask = np.asarray(clipping_image) + + if not image_data.remove_outside: # clip mode "remove_inside" + if outer_bounds: + # create a new empty image + visible_image = PIL.Image.new("L", image_data.image_size(), 0) + # paint in parts of the image which are still visible + for boundary in outer_bounds: + clip_polygon = [(p.x, p.y) for p in boundary.vertices()] + PIL.ImageDraw.ImageDraw(visible_image).polygon( + clip_polygon, outline=None, width=0, fill=1 + ) + # remove the clipping path + clipping_mask = np.asarray(visible_image) - clipping_mask + else: + # create mask for fully visible image + fully_visible_image_mask = np.full( + clipping_mask.shape, fill_value=1, dtype=clipping_mask.dtype + ) + # remove the clipping path + clipping_mask = fully_visible_image_mask - clipping_mask + image_data.image[:, :, 3] *= clipping_mask + + +def _clip_image_polygon( + clipping_portal: ClippingPortal, polygon_px: BkPoints2d, m: Matrix44 +) -> list[BkPoints2d]: + original = [polygon_px] + + # inverse matrix includes the transformation applied by the clipping portal + inverse = clipping_portal.transform_matrix(m) + try: + inverse.inverse() + except ZeroDivisionError: + # inverse transformation from WCS to pixel coordinates is not possible + return original + + # transform image coordinates to WCS coordinates + polygon = polygon_px.clone() + polygon.transform_inplace(m) + + clipped_polygons = clipping_portal.clip_polygon(polygon) + if (len(clipped_polygons) == 1) and (clipped_polygons[0] is polygon): + # this shows the caller that the image boundary path wasn't clipped + return original + # transform WCS coordinates to image coordinates + for polygon in clipped_polygons: + polygon.transform_inplace(inverse) + return clipped_polygons # in image coordinates! + + +def invert_color(color: Color) -> Color: + r, g, b = RGB.from_hex(color) + return RGB(255 - r, 255 - g, 255 - b).to_hex() + + +def swap_bw(color: str) -> Color: + color = color.lower() + if color == "#000000": + return "#ffffff" + if color == "#ffffff": + return "#000000" + return color + + +def color_to_monochrome(color: Color, scale: float = 1.0, offset: float = 0.0) -> Color: + lum = RGB.from_hex(color).luminance * scale + offset + if lum < 0.0: + lum = 0.0 + elif lum > 1.0: + lum = 1.0 + gray = round(lum * 255) + return RGB(gray, gray, gray).to_hex() + + +def apply_color_policy(color: Color, policy: ColorPolicy, custom_color: Color) -> Color: + alpha = color[7:9] + color = color[:7] + if policy == ColorPolicy.COLOR_SWAP_BW: + color = swap_bw(color) + elif policy == ColorPolicy.COLOR_NEGATIVE: + color = invert_color(color) + elif policy == ColorPolicy.MONOCHROME_DARK_BG: # [0.3, 1.0] + color = color_to_monochrome(color, scale=0.7, offset=0.3) + elif policy == ColorPolicy.MONOCHROME_LIGHT_BG: # [0.0, 0.7] + color = color_to_monochrome(color, scale=0.7, offset=0.0) + elif policy == ColorPolicy.MONOCHROME: # [0.0, 1.0] + color = color_to_monochrome(color) + elif policy == ColorPolicy.BLACK: + color = "#000000" + elif policy == ColorPolicy.WHITE: + color = "#ffffff" + elif policy == ColorPolicy.CUSTOM: + fg = custom_color + color = fg[:7] + alpha = fg[7:9] + return color + alpha + + +def filter_vp_entities( + msp: Layout, + limits: Sequence[float], + bbox_cache: Optional[ezdxf.bbox.Cache] = None, +) -> Iterator[DXFGraphic]: + """Yields all DXF entities that need to be processed by the given viewport + `limits`. The entities may be partially of even complete outside the viewport. + By passing the bounding box cache of the modelspace entities, + the function can filter entities outside the viewport to speed up rendering + time. + + There are two processing modes for the `bbox_cache`: + + 1. The `bbox_cache` is``None``: all entities must be processed, + pass through mode + 2. If the `bbox_cache` is given but does not contain an entity, + the bounding box is computed and added to the cache. + Even passing in an empty cache can speed up rendering time when + multiple viewports need to be processed. + + Args: + msp: modelspace layout + limits: modelspace limits of the viewport, as tuple (min_x, min_y, max_x, max_y) + bbox_cache: the bounding box cache of the modelspace entities + + """ + + # WARNING: this works only with top-view viewports + # The current state of the drawing add-on supports only top-view viewports! + def is_visible(e): + entity_bbox = bbox_cache.get(e) + if entity_bbox is None: + # compute and add bounding box + entity_bbox = ezdxf.bbox.extents((e,), fast=True, cache=bbox_cache) + if not entity_bbox.has_data: + return True + # Check for separating axis: + if min_x >= entity_bbox.extmax.x: + return False + if max_x <= entity_bbox.extmin.x: + return False + if min_y >= entity_bbox.extmax.y: + return False + if max_y <= entity_bbox.extmin.y: + return False + return True + + if bbox_cache is None: # pass through all entities + yield from msp + return + + min_x, min_y, max_x, max_y = limits + if not bbox_cache.has_data: + # fill cache at once + ezdxf.bbox.extents(msp, fast=True, cache=bbox_cache) + + for entity in msp: + if is_visible(entity): + yield entity + + +def prepare_string_for_rendering(text: str, dxftype: str) -> str: + assert "\n" not in text, "not a single line of text" + if dxftype in {"TEXT", "ATTRIB", "ATTDEF"}: + text = replace_non_printable_characters(text, replacement="?") + text = text.replace("\t", "?") + elif dxftype == "MTEXT": + text = replace_non_printable_characters(text, replacement="▯") + text = text.replace("\t", " ") + else: + raise TypeError(dxftype) + return text diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/properties.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/properties.py new file mode 100644 index 0000000..054c121 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/properties.py @@ -0,0 +1,1017 @@ +# Copyright (c) 2020-2021, Matthew Broadway +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Optional, + Union, + cast, + Sequence, + Callable, + Iterable, + NamedTuple, +) +from typing_extensions import TypeAlias +import os +import pathlib +import re +import copy +import logging + +from ezdxf import options +from ezdxf.colors import RGB +from ezdxf.addons import acadctb +from ezdxf.addons.drawing.config import Configuration +from ezdxf.addons.drawing.type_hints import Color +from ezdxf.colors import DXF_DEFAULT_COLORS, int2rgb +from ezdxf.entities import ( + Attrib, + Insert, + Face3d, + Linetype, + Viewport, + Layer, + LayerOverrides, + Textstyle, + DXFGraphic, +) +from ezdxf.entities.ltype import CONTINUOUS_PATTERN +from ezdxf.entities.polygon import DXFPolygon +from ezdxf.enums import InsertUnits, Measurement +from ezdxf.filemanagement import find_support_file +from ezdxf.lldxf import const +from ezdxf.lldxf.validator import make_table_key as layer_key +from ezdxf.fonts import fonts +from ezdxf.tools.pattern import scale_pattern, HatchPatternType + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.sections.table import Table + from ezdxf.layouts import Layout + +__all__ = [ + "Properties", + "BackendProperties", + "LayerProperties", + "LayoutProperties", + "RenderContext", + "layer_key", + "is_valid_color", + "rgb_to_hex", + "hex_to_rgb", + "MODEL_SPACE_BG_COLOR", + "PAPER_SPACE_BG_COLOR", + "VIEWPORT_COLOR", + "OLE2FRAME_COLOR", + "set_color_alpha", + "Filling", +] + +table_key = layer_key +MODEL_SPACE_BG_COLOR = "#212830" +PAPER_SPACE_BG_COLOR = "#ffffff" +VIEWPORT_COLOR = "#aaaaaa" # arbitrary choice +OLE2FRAME_COLOR = "#89adba" # arbitrary choice +logger = logging.getLogger("ezdxf") +CTB: TypeAlias = acadctb.ColorDependentPlotStyles + + +def is_dark_color(color: Color, dark: float = 0.2) -> bool: + return RGB.from_hex(color).luminance <= dark + + +class Filling: + SOLID = 0 + PATTERN = 1 + GRADIENT = 2 + + def __init__(self) -> None: + # Solid fill color is stored in Properties.color attribute + self.type = Filling.SOLID + # Gradient- or pattern name + self.name: str = "SOLID" + # Gradient- or pattern angle + self.angle: float = 0.0 # in degrees + self.gradient_color1: Optional[Color] = None + self.gradient_color2: Optional[Color] = None + self.gradient_centered: float = 0.0 # todo: what's the meaning? + self.pattern_scale: float = 1.0 + self.pattern: HatchPatternType = [] + + +class Properties: + """An implementation agnostic representation of DXF entity properties like + color and linetype. These properties represent the actual values after + resolving all DXF specific rules like "by layer", "by block" and so on. + """ + + def __init__(self) -> None: + # color string format "#RRGGBB" or "#RRGGBBAA" + # alpha channel AA: 0x00 = transparent; 0xff = opaque + self.color: str = "#ffffff" + self.pen = 7 # equals the ACI (1-255), for pen based backends like plotters + + # Linetype rendering is done by the frontend, the backend receives only solid + # lines. + self.linetype_name: str = "CONTINUOUS" + + # Simplified DXF linetype definition: + # all line elements >= 0.0, 0.0 = point + # all gap elements > 0.0 + # Usage as alternating line - gap sequence: line-gap-line-gap .... + # (line could be a point 0.0), line-line or gap-gap - makes no sense + # Examples: + # DXF: ("DASHED", "Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _", + # [0.6, 0.5, -0.1]) + # first entry 0.6 is the total pattern length = sum(linetype_pattern) + # linetype_pattern: [0.5, 0.1] = line-gap + # DXF: ("DASHDOTX2", "Dash dot (2x) ____ . ____ . ____ . ____", + # [2.4, 2.0, -0.2, 0.0, -0.2]) + # linetype_pattern: [2.0, 0.2, 0.0, 0.2] = line-gap-point-gap + # The continuous pattern is an empty tuple () + self.linetype_pattern: Sequence[float] = CONTINUOUS_PATTERN + self.linetype_scale: float = 1.0 + # line weight in mm, todo: default lineweight is 0.25? + self.lineweight: float = 0.25 + self.is_visible = True + + # The 'layer' attribute stores the resolved layer of an entity: + # Entities inside a block references get properties from the layer + # of the INSERT entity, if they reside on the layer '0'. + # To get the "real" layer of an entity, you have to use `entity.dxf.layer` + self.layer: str = "0" + + # Font definition object for text entities: + # Font rendering is done by the frontend, backends receive paths for + # stroke-fonts (.shx) and filled paths for outline fonts (.ttf). + self.font: Optional[fonts.FontFace] = None # use default font + + # Filling properties: Solid, Pattern, Gradient + # Pattern rendering is done by the frontend, backends receive only solid lines, + # and the fill color for filled polygons and filled paths is passed as the + # color attribute in the BackendProperties, gradients are not supported. + self.filling: Optional[Filling] = None + + self.units = InsertUnits.Unitless + + def __str__(self): + return ( + f"({self.color}, {self.linetype_name}, {self.lineweight}, " + f'"{self.layer}")' + ) + + @property + def rgb(self) -> RGB: + """Returns color as RGB tuple.""" + return RGB.from_hex(self.color) + + @property + def luminance(self) -> float: + """Returns perceived color luminance in range [0, 1] from dark to light.""" + return self.rgb.luminance + + +class BackendProperties(NamedTuple): + """The backend receives a condensed version of the entity properties.""" + + color: Color = "#000000" + lineweight: float = 0.25 # in mm + layer: str = "0" # maybe useful to group entities (SVG, PDF) + pen: int = 1 # equals the ACI (1-255), for pen based backends like plotters + handle: str = "" # top level entity handle + + @property + def rgb(self) -> RGB: + """Returns color as RGB tuple.""" + return RGB.from_hex(self.color) + + @property + def luminance(self) -> float: + """Returns perceived color luminance in range [0, 1] from dark to light.""" + return self.rgb.luminance + + +class LayerProperties(Properties): + """Modified attribute meaning: + + is_visible: Whether entities belonging to this layer should be drawn + layer: Stores real layer name (mixed case) + + """ + + def __init__(self): + super().__init__() + self.has_aci_color_7 = False + + def get_entity_color_from_layer(self, fg: Color) -> Color: + """Returns the layer color or if layer color is ACI color 7 the + given layout default foreground color `fg`. + """ + if self.has_aci_color_7: + return fg + else: + return self.color + + +DEFAULT_LAYER_PROPERTIES = LayerProperties() + + +class LayoutProperties: + # The LAYOUT, BLOCK and BLOCK_RECORD entities do not have + # explicit graphic properties. + def __init__( + self, + name: str, + background_color: Color, + foreground_color: Optional[Color] = None, + units=InsertUnits.Unitless, + dark_background: Optional[bool] = None, + ): + """ + Args: + name: tab/display name + units: enum :class:`ezdxf.enums.InsertUnits` + """ + self.name = name + self.units: InsertUnits = units + + self._background_color = "" + self._default_color = "" + self._has_dark_background = False + self.set_colors(background_color, foreground_color) + + if dark_background is not None: + self._has_dark_background = dark_background + + @property + def background_color(self) -> Color: + """Returns the default layout background color.""" + return self._background_color + + @property + def default_color(self) -> Color: + """Returns the default layout foreground color.""" + return self._default_color + + @property + def has_dark_background(self) -> bool: + """Returns ``True`` if the actual background-color is "dark".""" + return self._has_dark_background + + @staticmethod + def modelspace(units=InsertUnits.Unitless) -> LayoutProperties: + return LayoutProperties( + "Model", + MODEL_SPACE_BG_COLOR, + units=units, + ) + + @staticmethod + def from_layout(layout: Layout, units: Optional[int] = None) -> LayoutProperties: + """Setup default layout properties.""" + if layout.name == "Model": + bg = MODEL_SPACE_BG_COLOR + else: + bg = PAPER_SPACE_BG_COLOR + if units is None: + units = layout.units + return LayoutProperties(layout.name, bg, units=units) + + def set_colors(self, bg: Color, fg: Optional[Color] = None) -> None: + """Setup default layout colors. + + Required color format "#RRGGBB" or including alpha transparency + "#RRGGBBAA". + """ + if not is_valid_color(bg): + raise ValueError(f"Invalid background color: {bg}") + self._background_color = bg + if len(bg) == 9: # including transparency + bg = bg[:7] + self._has_dark_background = is_dark_color(bg) + if fg is not None: + if not is_valid_color(fg): + raise ValueError(f"Invalid foreground color: {fg}") + self._default_color = fg + else: + self._default_color = "#ffffff" if self._has_dark_background else "#000000" + + +LayerPropsOverride = Callable[[Sequence[LayerProperties]], None] + + +class RenderContext: + """The render context for the given DXF document. The :class:`RenderContext` + resolves the properties of DXF entities from the context they reside in to actual + values like RGB colors, transparency, linewidth and so on. + + A given `ctb` file (plot style file) overrides the default properties for all + layouts, which means the plot style table stored in the layout is always ignored. + + Args: + doc: DXF document + ctb: path to a plot style table or a :class:`~ezdxf.addons.acadctb.ColorDependentPlotStyles` + instance + export_mode: Whether to render the document as it would look when + exported (plotted) by a CAD application to a file such as pdf, + or whether to render the document as it would appear inside a + CAD application. + """ + + def __init__( + self, + doc: Optional[Drawing] = None, + *, + ctb: str | CTB = "", + export_mode: bool = False, + ): + self._saved_states: list[Properties] = [] + self.line_pattern: dict[str, Sequence[float]] = dict() + self.current_block_reference_properties: Optional[Properties] = None + self.export_mode = export_mode + self.override_ctb = ctb + self.layers: dict[str, LayerProperties] = dict() + self.fonts: dict[str, fonts.FontFace] = dict() + self.units = InsertUnits.Unitless # modelspace units + self.linetype_scale: float = 1.0 # overall modelspace linetype scaling + self.measurement = Measurement.Imperial + self.pdsize: float = 0 + self.pdmode: int = 0 + self.document_dir: Optional[pathlib.Path] = None + self._hatch_pattern_cache: dict[str, HatchPatternType] = dict() + self.current_layout_properties = LayoutProperties.modelspace() + self.plot_styles = self._load_plot_style_table(self.override_ctb) + # Order for resolving SHX fonts: 1. "t"=TrueType; 2. "s"=SHX; 3. "l"=LFF + self.shx_resolve_order = options.get( + "drawing-addon", "shx_resolve_order", "tsl" + ) + # callable to override layer properties: + self._layer_properties_override: Optional[LayerPropsOverride] = None + + if doc: + self.set_current_layout(doc.modelspace()) + self.line_pattern = _load_line_pattern(doc.linetypes) + self.linetype_scale = doc.header.get("$LTSCALE", 1.0) + self.pdsize = doc.header.get("$PDSIZE", 1.0) + self.pdmode = doc.header.get("$PDMODE", 0) + if doc.filename is not None: + filename = doc.filename + if isinstance(filename, str): + filename = filename.replace("\\", os.path.sep) + self.document_dir = pathlib.Path(filename).parent.resolve() + self._setup_text_styles(doc) + try: + self.units = InsertUnits(doc.header.get("$INSUNITS", 0)) + except ValueError: + self.units = InsertUnits.Unitless + try: + self.measurement = Measurement(doc.header.get("$MEASUREMENT", 0)) + except ValueError: + self.measurement = Measurement.Imperial + if self.units == InsertUnits.Unitless: + if self.measurement == Measurement.Metric: + self.units = InsertUnits.Meters + else: + self.units = InsertUnits.Inches + self.current_layout_properties.units = self.units # default modelspace + + def set_layer_properties_override(self, func: Optional[LayerPropsOverride] = None): + """The function `func` is called with the current layer properties as + argument after resetting them, so the function can override the layer + properties. + """ + self._layer_properties_override = func + + def _override_layer_properties(self, layers: Sequence[LayerProperties]): + if self._layer_properties_override: + self._layer_properties_override(layers) + + def set_current_layout(self, layout: Layout, ctb: str | CTB = ""): + """Set the current layout and update layout specific properties. + + Args: + layout: modelspace or a paperspace layout + ctb: path to a plot style table or a :class:`~ezdxf.addons.acadctb.ColorDependentPlotStyles` + instance + + """ + # the given ctb has the highest priority + if isinstance(ctb, str): + if ctb == "": + # next is the override ctb + ctb = self.override_ctb + if ctb == "": + # last is the ctb stored in the layout + ctb = layout.get_plot_style_filename() + elif not isinstance(ctb, CTB): + raise TypeError( + f"expected argument ctb of type str or {CTB.__name__}, got {type(ctb)}" + ) + self.current_layout_properties = LayoutProperties.from_layout(layout) + self.plot_styles = self._load_plot_style_table(ctb) + self.layers = dict() + if layout.doc: + self.layers = self._setup_layers(layout.doc) + self._override_layer_properties(list(self.layers.values())) + + def copy(self): + """Returns a shallow copy.""" + return copy.copy(self) + + def update_configuration(self, config: Configuration) -> Configuration: + """Where the user has not specified a value, populate configuration + fields based on the dxf header values + """ + changes = {} + if config.pdsize is None: + changes["pdsize"] = self.pdsize + if config.pdmode is None: + changes["pdmode"] = self.pdmode + if config.measurement is None: + changes["measurement"] = self.measurement + return config.with_changes(**changes) + + def _setup_layers(self, doc: Drawing) -> dict[str, LayerProperties]: + layers: dict[str, LayerProperties] = dict() + for layer in doc.layers: + layer_properties = self.resolve_layer_properties(cast(Layer, layer)) + layers[layer_key(layer_properties.layer)] = layer_properties + return layers + + def _setup_text_styles(self, doc: Drawing): + for text_style in doc.styles: + self.add_text_style(cast("Textstyle", text_style)) + + def _setup_vp_layers(self, vp: Viewport) -> dict[str, LayerProperties]: + doc = vp.doc + assert doc is not None + frozen_layer_names = {layer_key(name) for name in vp.frozen_layers} + vp_handle = vp.dxf.handle + layers: dict[str, LayerProperties] = dict() + for layer in doc.layers: + layer = cast(Layer, layer) + overrides = layer.get_vp_overrides() + if overrides.has_overrides(vp_handle): + layer = layer.copy() + self._apply_layer_overrides(vp_handle, layer, overrides) + layer_properties = self.resolve_layer_properties(layer) + key = layer_key(layer_properties.layer) + layers[key] = layer_properties + if key in frozen_layer_names: + layer_properties.is_visible = False + return layers + + @staticmethod + def _apply_layer_overrides( + vp_handle: str, + layer: Layer, + overrides: LayerOverrides, + ) -> None: + layer.color = overrides.get_color(vp_handle) + rgb_color = overrides.get_rgb(vp_handle) + if rgb_color is not None: + layer.rgb = rgb_color + layer.transparency = overrides.get_transparency(vp_handle) + layer.dxf.linetype = overrides.get_linetype(vp_handle) + layer.dxf.lineweight = overrides.get_lineweight(vp_handle) + + def from_viewport(self, vp: Viewport) -> RenderContext: + if vp.doc is None: + return self + vp_ctx = self.copy() + ctb = vp_ctx.override_ctb + if ctb == "": + ctb = vp.dxf.get("plot_style_name") + if ctb: + vp_ctx.plot_styles = vp_ctx._load_plot_style_table(ctb) + layers = vp_ctx._setup_vp_layers(vp) + vp_ctx.layers = layers + vp_ctx._override_layer_properties(list(layers.values())) + return vp_ctx + + def resolve_layer_properties(self, layer: Layer) -> LayerProperties: + """Resolve layer properties.""" + properties = LayerProperties() + # Store real layer name (mixed case): + properties.layer = layer.dxf.name + properties.pen = layer.dxf.color + properties.color = self._true_layer_color(layer) + + # set layer transparency + alpha = transparency_to_alpha(layer.transparency) + if alpha < 255: + properties.color = set_color_alpha(properties.color, alpha) + + # Depend layer ACI color from layout background color? + # True color overrides ACI color and layers with only true color set + # have default ACI color 7! + if not layer.has_dxf_attrib("true_color"): + properties.has_aci_color_7 = layer.dxf.color == 7 + + # Normalize linetype names to UPPERCASE: + properties.linetype_name = str(layer.dxf.linetype).upper() + properties.linetype_pattern = self.line_pattern.get( + properties.linetype_name, CONTINUOUS_PATTERN + ) + properties.lineweight = self._true_layer_lineweight(layer.dxf.lineweight) + properties.is_visible = layer.is_on() and not layer.is_frozen() + if self.export_mode: + properties.is_visible &= bool(layer.dxf.plot) + return properties + + def add_text_style(self, text_style: Textstyle): + """Setup text style properties.""" + name = table_key(text_style.dxf.name) + font_file = text_style.dxf.font + font_face = None + if font_file == "": # Font family stored in XDATA? + family, italic, bold = text_style.get_extended_font_data() + if family: + font_face = fonts.find_best_match( + family=family, weight=700 if bold else 400, italic=italic + ) + else: + try: + font_face = fonts.resolve_font_face( + font_file, order=self.shx_resolve_order + ) + except fonts.FontNotFoundError: + logger.warning("no fonts available, not even fallback fonts") + + if font_face is None: # fall back to default font + font_face = fonts.FontFace() + self.fonts[name] = font_face + + def _true_layer_color(self, layer: Layer) -> Color: + if layer.dxf.hasattr("true_color"): + return rgb_to_hex(layer.rgb) # type: ignore + else: + # Don't use layer.dxf.color: color < 0 is layer state off + aci = layer.color + # aci: 0=BYBLOCK, 256=BYLAYER, 257=BYOBJECT + if aci < 1 or aci > 255: + aci = 7 # default layer color + return self._aci_to_true_color(aci) + + def _true_layer_lineweight(self, lineweight: int) -> float: + if lineweight < 0: + return self.default_lineweight() + else: + return float(lineweight) / 100.0 + + @staticmethod + def _load_plot_style_table(filename: str | CTB): + # Each layout can have a different plot style table stored in + # Layout.dxf.current_style_sheet. + # HEADER var $STYLESHEET stores the default ctb-file name. + if isinstance(filename, str): + filename = find_support_file(filename, options.support_dirs) + try: + ctb = acadctb.load(filename) + except IOError: + ctb = acadctb.new_ctb() + else: + ctb = filename + + # Colors in CTB files can be RGB colors but don't have to, + # therefore initialize color without RGB values by the + # default AutoCAD palette: + for aci in range(1, 256): + entry = ctb[aci] # type: ignore + if entry.has_object_color(): + # initialize with default AutoCAD palette + entry.color = int2rgb(DXF_DEFAULT_COLORS[aci]) + return ctb + + @property + def inside_block_reference(self) -> bool: + """Returns ``True`` if current processing state is inside of a block + reference (INSERT). + """ + return bool(self.current_block_reference_properties) + + def push_state(self, block_reference: Properties) -> None: + self._saved_states.append(self.current_block_reference_properties) # type: ignore + self.current_block_reference_properties = block_reference + + def pop_state(self) -> None: + self.current_block_reference_properties = self._saved_states.pop() + + def resolve_all(self, entity: DXFGraphic) -> Properties: + """Resolve all properties of `entity`.""" + p = Properties() + p.layer = self.resolve_layer(entity) + resolved_layer = layer_key(p.layer) + p.units = self.resolve_units() + p.color = self.resolve_color(entity, resolved_layer=resolved_layer) + p.pen = self.resolve_pen(entity, resolved_layer=resolved_layer) + p.linetype_name, p.linetype_pattern = self.resolve_linetype( + entity, resolved_layer=resolved_layer + ) + p.lineweight = self.resolve_lineweight(entity, resolved_layer=resolved_layer) + p.linetype_scale = self.resolve_linetype_scale(entity) + p.is_visible = self.resolve_visible(entity, resolved_layer=resolved_layer) + if entity.is_supported_dxf_attrib("style"): + p.font = self.resolve_font(entity) + if isinstance(entity, DXFPolygon): + p.filling = self.resolve_filling(entity) + return p + + def resolve_units(self) -> InsertUnits: + return self.current_layout_properties.units + + def resolve_linetype_scale(self, entity: DXFGraphic) -> float: + return entity.dxf.ltscale * self.linetype_scale + + def resolve_visible( + self, entity: DXFGraphic, *, resolved_layer: Optional[str] = None + ) -> bool: + """Resolve the visibility state of `entity`. Returns ``True`` if + `entity` is visible. + """ + if isinstance(entity, Insert): + # depends only on the invisible flag, the layer state has no effect! + return not bool(entity.dxf.invisible) + elif isinstance(entity, Face3d): + return any(entity.get_edges_visibility()) + elif isinstance(entity, Viewport): + # The layer visibility of the VIEWPORT entity does not affect the + # content of the Viewport. If the layer is off the viewport borders + # are invisible. + return entity.is_visible + + entity_layer = resolved_layer or layer_key(self.resolve_layer(entity)) + layer_properties = self.layers.get(entity_layer) + if layer_properties and not layer_properties.is_visible: + return False + elif isinstance(entity, Attrib): + return not bool(entity.dxf.invisible) and not entity.is_invisible + else: + return not bool(entity.dxf.invisible) + + def resolve_layer(self, entity: DXFGraphic) -> str: + """Resolve the layer of `entity`, this is only relevant for entities + inside of block references. + """ + layer = entity.dxf.layer + if layer == "0" and self.inside_block_reference: + layer = self.current_block_reference_properties.layer # type: ignore + return layer + + def resolve_color( + self, entity: DXFGraphic, *, resolved_layer: Optional[str] = None + ) -> Color: + """Resolve the rgb-color of `entity` as hex color string: + "#RRGGBB" or "#RRGGBBAA". + """ + if entity.dxf.hasattr("true_color"): + # An existing true color value always overrides ACI color! + # Do not default to BYLAYER or BYBLOCK, this ACI value is ignored! + aci = 7 + else: + aci = entity.dxf.color # defaults to BYLAYER + + entity_layer = resolved_layer or layer_key(self.resolve_layer(entity)) + layer_properties = self.layers.get(entity_layer, DEFAULT_LAYER_PROPERTIES) + + if aci == const.BYLAYER: + color = layer_properties.get_entity_color_from_layer( + self.current_layout_properties.default_color + ) + elif aci == const.BYBLOCK: + if not self.inside_block_reference: + color = self.current_layout_properties.default_color + else: + color = self.current_block_reference_properties.color # type: ignore + else: # BYOBJECT + color = self._true_entity_color(entity.rgb, aci) + alpha = self._entity_alpha_str( + entity.dxf.get("transparency"), layer_properties.color + ) + return color[:7] + alpha + + def resolve_pen( + self, entity: DXFGraphic, *, resolved_layer: Optional[str] = None + ) -> int: + """Resolve the aci-color of `entity` as pen number in the range of [1..255].""" + pen = entity.dxf.color # defaults to BYLAYER + entity_layer = resolved_layer or layer_key(self.resolve_layer(entity)) + layer_properties = self.layers.get(entity_layer, DEFAULT_LAYER_PROPERTIES) + + if pen == const.BYLAYER: + pen = layer_properties.pen + elif pen == const.BYBLOCK: + if not self.inside_block_reference: + pen = 7 + else: + pen = self.current_block_reference_properties.pen # type: ignore + elif pen == const.BYOBJECT: + pen = 7 # ??? + return pen + + def _entity_alpha_str( + self, raw_transparency: Optional[int], layer_color: Color + ) -> str: + """Returns the alpha value as hex string "xx" or empty string if opaque.""" + # alpha 0 = fully transparent + # alpha 255 = opaque + # DXF Transparency 0 = fully transparent + # DXF Transparency 255 = opaque + if raw_transparency == const.TRANSPARENCY_BYBLOCK: + if self.inside_block_reference: + return self.current_block_reference_properties.color[7:] # type: ignore + # else: entity is not in a block + # There is no default transparency value for layouts, AutoCAD and + # BricsCAD shows opaque entities! + return "" + # No transparency attribute means "by layer" + elif raw_transparency is None: + return layer_color[7:] + + alpha = raw_transparency & 0xFF + if alpha < 255: + return f"{alpha:02x}" + return "" + + def resolve_aci_color(self, aci: int, resolved_layer: str) -> Color: + """Resolve the `aci` color as hex color string: "#RRGGBB" """ + if aci == const.BYLAYER: + layer = self.layers.get(layer_key(resolved_layer), DEFAULT_LAYER_PROPERTIES) + color = layer.get_entity_color_from_layer( + self.current_layout_properties.default_color + ) + elif aci == const.BYBLOCK: + if not self.inside_block_reference: + color = self.current_layout_properties.default_color + else: + color = self.current_block_reference_properties.color # type: ignore + else: # BYOBJECT + color = self._true_entity_color(None, aci) + return color + + def _true_entity_color( + self, true_color: Optional[tuple[int, int, int]], aci: int + ) -> Color: + """Returns rgb color in hex format: "#RRGGBB". + + `true_color` has higher priority than `aci`. + """ + if true_color is not None: + return rgb_to_hex(true_color) + elif 0 < aci < 256: + return self._aci_to_true_color(aci) + else: + return self.current_layout_properties.default_color # unknown / invalid + + def _aci_to_true_color(self, aci: int) -> Color: + """Returns the `aci` value (AutoCAD Color Index) as rgb value in + hex format: "#RRGGBB". + """ + if aci == 7: # black/white + return self.current_layout_properties.default_color + else: + return rgb_to_hex(self.plot_styles[aci].color) + + def resolve_linetype( + self, entity: DXFGraphic, *, resolved_layer: Optional[str] = None + ) -> tuple[str, Sequence[float]]: + """Resolve the linetype of `entity`. Returns a tuple of the linetype + name as upper-case string and the simplified linetype pattern as tuple + of floats. + """ + aci = entity.dxf.color + # Not sure if plotstyle table overrides actual entity setting? + if (0 < aci < 256) and self.plot_styles[ + aci + ].linetype != acadctb.OBJECT_LINETYPE: + # todo: return special line types - overriding linetypes by + # plotstyle table + pass + name = entity.dxf.linetype.upper() # default is 'BYLAYER' + if name == "BYLAYER": + entity_layer = resolved_layer or layer_key(self.resolve_layer(entity)) + layer = self.layers.get(entity_layer, DEFAULT_LAYER_PROPERTIES) + name = layer.linetype_name + pattern = layer.linetype_pattern + + elif name == "BYBLOCK": + if self.inside_block_reference: + name = self.current_block_reference_properties.linetype_name # type: ignore + pattern = ( + self.current_block_reference_properties.linetype_pattern # type: ignore + ) + else: + # There is no default layout linetype + name = "STANDARD" + pattern = CONTINUOUS_PATTERN + else: + pattern = self.line_pattern.get(name, CONTINUOUS_PATTERN) + return name, pattern + + def resolve_lineweight( + self, entity: DXFGraphic, *, resolved_layer: Optional[str] = None + ) -> float: + """Resolve the lineweight of `entity` in mm. + + DXF stores the lineweight in mm times 100 (e.g. 0.13mm = 13). + The smallest line weight is 0 and the biggest line weight is 211. + The DXF/DWG format is limited to a fixed value table, + see: :attr:`ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS` + + CAD applications draw lineweight 0mm as an undefined small value, to + prevent backends to draw nothing for lineweight 0mm the smallest + return value is 0.01mm. + + """ + + def lineweight(): + aci = entity.dxf.color + # Not sure if plotstyle table overrides actual entity setting? + if (0 < aci < 256) and self.plot_styles[ + aci + ].lineweight != acadctb.OBJECT_LINEWEIGHT: + # overriding lineweight by plotstyle table + return self.plot_styles.get_lineweight(aci) + lineweight = entity.dxf.lineweight # default is BYLAYER + if lineweight == const.LINEWEIGHT_BYLAYER: + entity_layer = resolved_layer or layer_key(self.resolve_layer(entity)) + return self.layers.get( + entity_layer, DEFAULT_LAYER_PROPERTIES + ).lineweight + + elif lineweight == const.LINEWEIGHT_BYBLOCK: + if self.inside_block_reference: + return self.current_block_reference_properties.lineweight + else: + # There is no default layout lineweight + return self.default_lineweight() + elif lineweight == const.LINEWEIGHT_DEFAULT: + return self.default_lineweight() + else: + return float(lineweight) / 100.0 + + return max(0.01, lineweight()) + + def default_lineweight(self): + """Returns the default lineweight of the document.""" + # todo: is this value stored anywhere (e.g. HEADER section)? + return 0.25 + + def resolve_font(self, entity: DXFGraphic) -> Optional[fonts.FontFace]: + """Resolve the text style of `entity` to a font name. + Returns ``None`` for the default font. + """ + # todo: extended font data + style = entity.dxf.get("style", "Standard") + return self.fonts.get(table_key(style)) + + def resolve_filling(self, entity: DXFGraphic) -> Optional[Filling]: + """Resolve filling properties (SOLID, GRADIENT, PATTERN) of `entity`.""" + + def setup_gradient(): + filling.type = Filling.GRADIENT + filling.name = gradient.name.upper() + # todo: no idea when to use aci1 and aci2 + filling.gradient_color1 = rgb_to_hex(gradient.color1) + if gradient.one_color: + c = round(gradient.tint * 255) # channel value + filling.gradient_color2 = rgb_to_hex((c, c, c)) + else: + filling.gradient_color2 = rgb_to_hex(gradient.color2) + + filling.angle = gradient.rotation + filling.gradient_centered = gradient.centered + + def setup_pattern(): + filling.type = Filling.PATTERN + filling.name = polygon.dxf.pattern_name.upper() + filling.pattern_scale = polygon.dxf.pattern_scale + filling.angle = polygon.dxf.pattern_angle + if polygon.dxf.pattern_double: + # This value is not editable by CAD-App-GUI: + filling.pattern_scale *= 2 # todo: is this correct? + + filling.pattern = self._hatch_pattern_cache.get(filling.name) + if filling.pattern: + return + + pattern = polygon.pattern + if not pattern: + return + + # DXF stores the hatch pattern already rotated and scaled, + # pattern_scale and pattern_rotation are just hints for the CAD + # application to modify the pattern if required. + # It's better to revert the scaling and rotation, because in general + # back-ends do not handle pattern that way, they need a base-pattern + # and separated scaling and rotation attributes and these + # base-pattern could be cached by their name. + # + # There is no advantage of simplifying the hatch line pattern and + # this format is required by the PatternAnalyser(): + filling.pattern = scale_pattern( + pattern.as_list(), 1.0 / filling.pattern_scale, -filling.angle + ) + self._hatch_pattern_cache[filling.name] = filling.pattern + + if not isinstance(entity, DXFPolygon): + return None + + polygon = cast(DXFPolygon, entity) + filling = Filling() + if polygon.dxf.solid_fill: + gradient = polygon.gradient + if gradient is None: + filling.type = Filling.SOLID + else: + if gradient.kind == 0: # Solid + filling.type = Filling.SOLID + filling.gradient_color1 = rgb_to_hex(gradient.color1) + else: + setup_gradient() + else: + setup_pattern() + return filling + + +COLOR_PATTERN = re.compile("#[0-9A-Fa-f]{6,8}") + + +def is_valid_color(color: Color) -> bool: + if type(color) is not Color: + raise TypeError(f"Invalid argument type: {type(color)}.") + if len(color) in (7, 9): + return bool(COLOR_PATTERN.fullmatch(color)) + return False + + +def rgb_to_hex(rgb: Union[tuple[int, int, int], tuple[float, float, float]]) -> Color: + """Returns color in hex format: "#RRGGBB".""" + assert all(0 <= x <= 255 for x in rgb), f"invalid RGB color: {rgb}" + r, g, b = rgb + return f"#{r:02x}{g:02x}{b:02x}" + + +def hex_to_rgb(hex_string: Color) -> RGB: + """Returns hex string color as (r, g, b) tuple.""" + hex_string = hex_string.lstrip("#") + assert len(hex_string) == 6 + r = int(hex_string[0:2], 16) + g = int(hex_string[2:4], 16) + b = int(hex_string[4:6], 16) + return RGB(r, g, b) + + +def set_color_alpha(color: Color, alpha: int) -> Color: + """Returns `color` including the new `alpha` channel in hex format: + "#RRGGBBAA". + + Args: + color: may be an RGB or RGBA hex color string + alpha: the new alpha value (0-255) + """ + assert color.startswith("#") and len(color) in ( + 7, + 9, + ), f'invalid RGB color: "{color}"' + assert 0 <= alpha < 256, f"alpha out of range: {alpha}" + return f"{color[:7]}{alpha:02x}" + + +def transparency_to_alpha(value: float) -> int: + # clamp into range [0, 1] + value = min(max(0.0, value), 1.0) + return int(round((1.0 - value) * 255)) + + +def _load_line_pattern(linetypes: Table) -> dict[str, Sequence[float]]: + """Load linetypes defined in a DXF document into as dictionary, + key is the upper case linetype name, value is the simplified line pattern, + see :func:`compile_line_pattern`. + """ + pattern: dict[str, Sequence[float]] = dict() + for linetype in linetypes: + assert isinstance(linetype, Linetype) + name = linetype.dxf.name.upper() + pattern[name] = linetype.simplified_line_pattern() + return pattern + + +def set_layers_state( + layers: Sequence[LayerProperties], layer_names: Iterable[str], state=True +): + """Set layer state of `layers` to on/off. + + Args: + layers: layer properties + layer_names: iterable of layer names + state: `True` turn this `layers` on and others off, + `False` turn this `layers` off and others on + """ + unique_layer_names = {layer_key(name) for name in layer_names} + for layer in layers: + if layer_key(layer.layer) in unique_layer_names: + layer.is_visible = state + else: + layer.is_visible = not state diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pymupdf.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pymupdf.py new file mode 100644 index 0000000..6b4dc9a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pymupdf.py @@ -0,0 +1,492 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import math +from typing import Iterable, no_type_check, Any +import copy + +import PIL.Image +import numpy as np + +from ezdxf.math import Vec2, BoundingBox2d +from ezdxf.colors import RGB +from ezdxf.path import Command +from ezdxf.version import __version__ +from ezdxf.lldxf.validator import make_table_key as layer_key + +from .type_hints import Color +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import Configuration, LineweightPolicy +from .properties import BackendProperties +from . import layout, recorder + +is_pymupdf_installed = True +pymupdf: Any = None +try: + import pymupdf # type: ignore[import-untyped, no-redef] +except ImportError: + print( + "Python module PyMuPDF (AGPL!) is required: https://pypi.org/project/PyMuPDF/" + ) + is_pymupdf_installed = False +# PyMuPDF docs: https://pymupdf.readthedocs.io/en/latest/ + +__all__ = ["PyMuPdfBackend", "is_pymupdf_installed"] + +# PDF units are points (pt), 1 pt is 1/72 of an inch: +MM_TO_POINTS = 72.0 / 25.4 # 25.4 mm = 1 inch / 72 +# psd does not work in PyMuPDF v1.22.3 +SUPPORTED_IMAGE_FORMATS = ("png", "ppm", "pbm") + + +class PyMuPdfBackend(recorder.Recorder): + """This backend uses the `PyMuPdf`_ package to create PDF, PNG, PPM and PBM output. + This backend support content cropping at page margins. + + PyMuPDF is licensed under the `AGPL`_. Sorry, but it's the best package for the job + I've found so far. + + Install package:: + + pip install pymupdf + + .. _PyMuPdf: https://pypi.org/project/PyMuPDF/ + .. _AGPL: https://www.gnu.org/licenses/agpl-3.0.html + + """ + + def __init__(self) -> None: + super().__init__() + self._init_flip_y = True + + def get_replay( + self, + page: layout.Page, + *, + settings: layout.Settings = layout.Settings(), + render_box: BoundingBox2d | None = None, + ) -> PyMuPdfRenderBackend: + """Returns the PDF document as bytes. + + Args: + page: page definition, see :class:`~ezdxf.addons.drawing.layout.Page` + settings: layout settings, see :class:`~ezdxf.addons.drawing.layout.Settings` + render_box: set explicit region to render, default is content bounding box + """ + top_origin = True + # This player changes the original recordings! + player = self.player() + if render_box is None: + render_box = player.bbox() + + # the page origin (0, 0) is in the top-left corner. + output_layout = layout.Layout(render_box, flip_y=self._init_flip_y) + page = output_layout.get_final_page(page, settings) + + # DXF coordinates are mapped to PDF Units in the first quadrant + settings = copy.copy(settings) + settings.output_coordinate_space = get_coordinate_output_space(page) + + m = output_layout.get_placement_matrix( + page, settings=settings, top_origin=top_origin + ) + # transform content to the output coordinates space: + player.transform(m) + if settings.crop_at_margins: + p1, p2 = page.get_margin_rect(top_origin=top_origin) # in mm + # scale factor to map page coordinates to output space coordinates: + output_scale = settings.page_output_scale_factor(page) + max_sagitta = 0.1 * MM_TO_POINTS # curve approximation 0.1 mm + # crop content inplace by the margin rect: + player.crop_rect(p1 * output_scale, p2 * output_scale, max_sagitta) + + self._init_flip_y = False + backend = self.make_backend(page, settings) + player.replay(backend) + return backend + + def get_pdf_bytes( + self, + page: layout.Page, + *, + settings: layout.Settings = layout.Settings(), + render_box: BoundingBox2d | None = None, + ) -> bytes: + """Returns the PDF document as bytes. + + Args: + page: page definition, see :class:`~ezdxf.addons.drawing.layout.Page` + settings: layout settings, see :class:`~ezdxf.addons.drawing.layout.Settings` + render_box: set explicit region to render, default is content bounding box + """ + backend = self.get_replay(page, settings=settings, render_box=render_box) + return backend.get_pdf_bytes() + + def get_pixmap_bytes( + self, + page: layout.Page, + *, + fmt="png", + settings: layout.Settings = layout.Settings(), + dpi: int = 96, + alpha=False, + render_box: BoundingBox2d | None = None, + ) -> bytes: + """Returns a pixel image as bytes, supported image formats: + + === ========================= + png Portable Network Graphics + ppm Portable Pixmap (no alpha channel) + pbm Portable Bitmap (no alpha channel) + === ========================= + + Args: + page: page definition, see :class:`~ezdxf.addons.drawing.layout.Page` + fmt: image format + settings: layout settings, see :class:`~ezdxf.addons.drawing.layout.Settings` + dpi: output resolution in dots per inch + alpha: add alpha channel (transparency) + render_box: set explicit region to render, default is content bounding box + """ + if fmt not in SUPPORTED_IMAGE_FORMATS: + raise ValueError(f"unsupported image format: '{fmt}'") + backend = self.get_replay(page, settings=settings, render_box=render_box) + try: + pixmap = backend.get_pixmap(dpi=dpi, alpha=alpha) + return pixmap.tobytes(output=fmt) + except RuntimeError as e: + print(f"PyMuPDF Runtime Error: {str(e)}") + return b"" + + @staticmethod + def make_backend( + page: layout.Page, settings: layout.Settings + ) -> PyMuPdfRenderBackend: + """Override this method to use a customized render backend.""" + return PyMuPdfRenderBackend(page, settings) + + +def get_coordinate_output_space(page: layout.Page) -> int: + page_width_in_pt = int(page.width_in_mm * MM_TO_POINTS) + page_height_in_pt = int(page.height_in_mm * MM_TO_POINTS) + return max(page_width_in_pt, page_height_in_pt) + + +class PyMuPdfRenderBackend(BackendInterface): + """Creates the PDF/PNG/PSD/SVG output. + + This backend requires some preliminary work, record the frontend output via the + Recorder backend to accomplish the following requirements: + + - Move content in the first quadrant of the coordinate system. + - The page is defined by the upper left corner in the origin (0, 0) and + the lower right corner at (page-width, page-height) + - The output coordinates are floats in 1/72 inch, scale the content appropriately + - Replay the recorded output on this backend. + + .. important:: + + Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/ + + """ + + def __init__(self, page: layout.Page, settings: layout.Settings) -> None: + assert ( + is_pymupdf_installed + ), "Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/" + self.doc = pymupdf.open() + self.doc.set_metadata( + { + "producer": f"PyMuPDF {pymupdf.version[0]}", + "creator": f"ezdxf {__version__}", + } + ) + self.settings = settings + self._optional_content_groups: dict[str, int] = {} + self._stroke_width_cache: dict[float, float] = {} + self._color_cache: dict[str, tuple[float, float, float]] = {} + self.page_width_in_pt = int(page.width_in_mm * MM_TO_POINTS) + self.page_height_in_pt = int(page.height_in_mm * MM_TO_POINTS) + # LineweightPolicy.ABSOLUTE: + self.min_lineweight = 0.05 # in mm, set by configure() + self.lineweight_scaling = 1.0 # set by configure() + self.lineweight_policy = LineweightPolicy.ABSOLUTE # set by configure() + + # when the stroke width is too thin PDF viewers may get confused; + self.abs_min_stroke_width = 0.1 # pt == 0.03528mm (arbitrary choice) + + # LineweightPolicy.RELATIVE: + # max_stroke_width is determined as a certain percentage of settings.output_coordinate_space + self.max_stroke_width: float = max( + self.abs_min_stroke_width, + int(settings.output_coordinate_space * settings.max_stroke_width), + ) + # min_stroke_width is determined as a certain percentage of max_stroke_width + self.min_stroke_width: float = max( + self.abs_min_stroke_width, + int(self.max_stroke_width * settings.min_stroke_width), + ) + # LineweightPolicy.RELATIVE_FIXED: + # all strokes have a fixed stroke-width as a certain percentage of max_stroke_width + self.fixed_stroke_width: float = max( + self.abs_min_stroke_width, + int(self.max_stroke_width * settings.fixed_stroke_width), + ) + self.page = self.doc.new_page(-1, self.page_width_in_pt, self.page_height_in_pt) + + def get_pdf_bytes(self) -> bytes: + return self.doc.tobytes() + + def get_pixmap(self, dpi: int, alpha=False): + return self.page.get_pixmap(dpi=dpi, alpha=alpha) + + def get_svg_image(self) -> str: + return self.page.get_svg_image() + + def set_background(self, color: Color) -> None: + rgb = self.resolve_color(color) + opacity = alpha_to_opacity(color[7:9]) + if color == (1.0, 1.0, 1.0) or opacity == 0.0: + return + shape = self.new_shape() + shape.draw_rect([0, 0, self.page_width_in_pt, self.page_height_in_pt]) + shape.finish(width=None, color=None, fill=rgb, fill_opacity=opacity) + shape.commit() + + def new_shape(self): + return self.page.new_shape() + + def get_optional_content_group(self, layer_name: str) -> int: + if not self.settings.output_layers: + return 0 # the default value of `oc` when not provided + layer_name = layer_key(layer_name) + if layer_name not in self._optional_content_groups: + self._optional_content_groups[layer_name] = self.doc.add_ocg( + name=layer_name, + config=-1, + on=True, + ) + return self._optional_content_groups[layer_name] + + def finish_line(self, shape, properties: BackendProperties, close: bool) -> None: + color = self.resolve_color(properties.color) + width = self.resolve_stroke_width(properties.lineweight) + shape.finish( + width=width, + color=color, + fill=None, + lineJoin=1, + lineCap=1, + stroke_opacity=alpha_to_opacity(properties.color[7:9]), + closePath=close, + oc=self.get_optional_content_group(properties.layer), + ) + + def finish_filling(self, shape, properties: BackendProperties) -> None: + shape.finish( + width=None, + color=None, + fill=self.resolve_color(properties.color), + fill_opacity=alpha_to_opacity(properties.color[7:9]), + lineJoin=1, + lineCap=1, + closePath=True, + even_odd=True, + oc=self.get_optional_content_group(properties.layer), + ) + + def resolve_color(self, color: Color) -> tuple[float, float, float]: + key = color[:7] + try: + return self._color_cache[key] + except KeyError: + pass + color_floats = RGB.from_hex(color).to_floats() + self._color_cache[key] = color_floats + return color_floats + + def resolve_stroke_width(self, width: float) -> float: + try: + return self._stroke_width_cache[width] + except KeyError: + pass + stroke_width = self.min_stroke_width + if self.lineweight_policy == LineweightPolicy.ABSOLUTE: + stroke_width = ( # in points (pt) = 1/72 inch + max(self.min_lineweight, width) * MM_TO_POINTS * self.lineweight_scaling + ) + elif self.lineweight_policy == LineweightPolicy.RELATIVE: + stroke_width = map_lineweight_to_stroke_width( + width, self.min_stroke_width, self.max_stroke_width + ) + stroke_width = max(self.abs_min_stroke_width, stroke_width) + self._stroke_width_cache[width] = stroke_width + return stroke_width + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + shape = self.new_shape() + pos = Vec2(pos) + shape.draw_line(pos, pos) + self.finish_line(shape, properties, close=False) + shape.commit() + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + shape = self.new_shape() + shape.draw_line(Vec2(start), Vec2(end)) + self.finish_line(shape, properties, close=False) + shape.commit() + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + shape = self.new_shape() + for start, end in lines: + shape.draw_line(start, end) + self.finish_line(shape, properties, close=False) + shape.commit() + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + if len(path) == 0: + return + shape = self.new_shape() + add_path_to_shape(shape, path, close=False) + self.finish_line(shape, properties, close=False) + shape.commit() + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + shape = self.new_shape() + for p in paths: + add_path_to_shape(shape, p, close=True) + self.finish_filling(shape, properties) + shape.commit() + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + vertices = points.to_list() + if len(vertices) < 3: + return + # pymupdf >= 1.23.19 does not accept Vec2() instances + # input coordinates are page coordinates in pdf units + shape = self.new_shape() + shape.draw_polyline(vertices) + self.finish_filling(shape, properties) + shape.commit() + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + transform = image_data.transform + image = image_data.image + height, width, depth = image.shape + assert depth == 4 + + corners = list( + transform.transform_vertices( + [Vec2(0, 0), Vec2(width, 0), Vec2(width, height), Vec2(0, height)] + ) + ) + xs = [p.x for p in corners] + ys = [p.y for p in corners] + r = pymupdf.Rect((min(xs), min(ys)), (max(xs), max(ys))) + + # translation and non-uniform scale are handled by having the image stretch to fill the given rect. + angle = (corners[1] - corners[0]).angle_deg + need_rotate = not math.isclose(angle, 0.0) + # already mirroring once to go from pixels (+y down) to wcs (+y up) + # so a positive determinant means an additional reflection + need_flip = transform.determinant() > 0 + + if need_rotate or need_flip: + pil_image = PIL.Image.fromarray(image, mode="RGBA") + if need_flip: + pil_image = pil_image.transpose(PIL.Image.Transpose.FLIP_TOP_BOTTOM) + if need_rotate: + pil_image = pil_image.rotate( + -angle, + resample=PIL.Image.Resampling.BICUBIC, + expand=True, + fillcolor=(0, 0, 0, 0), + ) + image = np.asarray(pil_image) + height, width, depth = image.shape + + pixmap = pymupdf.Pixmap( + pymupdf.Colorspace(pymupdf.CS_RGB), width, height, bytes(image.data), True + ) + # TODO: could improve by caching and re-using xrefs. If a document contains many + # identical images redundant copies will be stored for each one + self.page.insert_image( + r, + keep_proportion=False, + pixmap=pixmap, + oc=self.get_optional_content_group(properties.layer), + ) + + def configure(self, config: Configuration) -> None: + self.lineweight_policy = config.lineweight_policy + if config.min_lineweight: + # config.min_lineweight in 1/300 inch! + min_lineweight_mm = config.min_lineweight * 25.4 / 300 + self.min_lineweight = max(0.05, min_lineweight_mm) + self.lineweight_scaling = config.lineweight_scaling + + def clear(self) -> None: + pass + + def finalize(self) -> None: + pass + + def enter_entity(self, entity, properties) -> None: + pass + + def exit_entity(self, entity) -> None: + pass + + +@no_type_check +def add_path_to_shape(shape, path: BkPath2d, close: bool) -> None: + start = path.start + sub_path_start = start + last_point = start + for command in path.commands(): + end = command.end + if command.type == Command.MOVE_TO: + if close and not sub_path_start.isclose(end): + shape.draw_line(start, sub_path_start) + sub_path_start = end + elif command.type == Command.LINE_TO: + shape.draw_line(start, end) + elif command.type == Command.CURVE3_TO: + shape.draw_curve(start, command.ctrl, end) + elif command.type == Command.CURVE4_TO: + shape.draw_bezier(start, command.ctrl1, command.ctrl2, end) + start = end + last_point = end + if close and not sub_path_start.isclose(last_point): + shape.draw_line(last_point, sub_path_start) + + +def map_lineweight_to_stroke_width( + lineweight: float, + min_stroke_width: float, + max_stroke_width: float, + min_lineweight=0.05, # defined by DXF + max_lineweight=2.11, # defined by DXF +) -> float: + """Map the DXF lineweight in mm to stroke-width in viewBox coordinates.""" + lineweight = max(min(lineweight, max_lineweight), min_lineweight) - min_lineweight + factor = (max_stroke_width - min_stroke_width) / (max_lineweight - min_lineweight) + return min_stroke_width + round(lineweight * factor, 1) + + +def alpha_to_opacity(alpha: str) -> float: + # stroke-opacity: 0.0 = transparent; 1.0 = opaque + # alpha: "00" = transparent; "ff" = opaque + if len(alpha): + try: + return int(alpha, 16) / 255 + except ValueError: + pass + return 1.0 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pyqt.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pyqt.py new file mode 100644 index 0000000..d4e1d9a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/pyqt.py @@ -0,0 +1,314 @@ +# Copyright (c) 2020-2023, Matthew Broadway +# License: MIT License +# mypy: ignore_errors=True +from __future__ import annotations +from typing import Optional, Iterable +import abc +import math + +import numpy as np + +from ezdxf.addons.xqt import QtCore as qc, QtGui as qg, QtWidgets as qw +from ezdxf.addons.drawing.backend import Backend, BkPath2d, BkPoints2d, ImageData +from ezdxf.addons.drawing.config import Configuration +from ezdxf.addons.drawing.type_hints import Color +from ezdxf.addons.drawing.properties import BackendProperties +from ezdxf.math import Vec2, Matrix44 +from ezdxf.npshapes import to_qpainter_path + + +class _Point(qw.QAbstractGraphicsShapeItem): + """A dimensionless point which is drawn 'cosmetically' (scale depends on + view) + """ + + def __init__(self, x: float, y: float, brush: qg.QBrush): + super().__init__() + self.location = qc.QPointF(x, y) + self.radius = 1.0 + self.setPen(qg.QPen(qc.Qt.NoPen)) + self.setBrush(brush) + + def paint( + self, + painter: qg.QPainter, + option: qw.QStyleOptionGraphicsItem, + widget: Optional[qw.QWidget] = None, + ) -> None: + view_scale = _get_x_scale(painter.transform()) + radius = self.radius / view_scale + painter.setBrush(self.brush()) + painter.setPen(qc.Qt.NoPen) + painter.drawEllipse(self.location, radius, radius) + + def boundingRect(self) -> qc.QRectF: + return qc.QRectF(self.location, qc.QSizeF(1, 1)) + + +# The key used to store the dxf entity corresponding to each graphics element +CorrespondingDXFEntity = qc.Qt.UserRole + 0 # type: ignore +CorrespondingDXFParentStack = qc.Qt.UserRole + 1 # type: ignore + + +class _PyQtBackend(Backend): + """ + Abstract PyQt backend which uses the :mod:`PySide6` package to implement an + interactive viewer. The :mod:`PyQt5` package can be used as fallback if the + :mod:`PySide6` package is not available. + """ + + def __init__(self, scene: qw.QGraphicsScene): + super().__init__() + self._scene = scene + self._color_cache: dict[Color, qg.QColor] = {} + self._no_line = qg.QPen(qc.Qt.NoPen) + self._no_fill = qg.QBrush(qc.Qt.NoBrush) + + def configure(self, config: Configuration) -> None: + if config.min_lineweight is None: + config = config.with_changes(min_lineweight=0.24) + super().configure(config) + + def set_scene(self, scene: qw.QGraphicsScene) -> None: + self._scene = scene + + def _add_item(self, item: qw.QGraphicsItem, entity_handle: str) -> None: + self.set_item_data(item, entity_handle) + self._scene.addItem(item) + + @abc.abstractmethod + def set_item_data(self, item: qw.QGraphicsItem, entity_handle: str) -> None: + ... + + def _get_color(self, color: Color) -> qg.QColor: + try: + return self._color_cache[color] + except KeyError: + pass + if len(color) == 7: + qt_color = qg.QColor(color) # '#RRGGBB' + elif len(color) == 9: + rgb = color[1:7] + alpha = color[7:9] + qt_color = qg.QColor(f"#{alpha}{rgb}") # '#AARRGGBB' + else: + raise TypeError(color) + + self._color_cache[color] = qt_color + return qt_color + + def _get_pen(self, properties: BackendProperties) -> qg.QPen: + """Returns a cosmetic pen with applied lineweight but without line type + support. + """ + px = properties.lineweight / 0.3527 * self.config.lineweight_scaling + pen = qg.QPen(self._get_color(properties.color), px) + # Use constant width in pixel: + pen.setCosmetic(True) + pen.setJoinStyle(qc.Qt.RoundJoin) + return pen + + def _get_fill_brush(self, color: Color) -> qg.QBrush: + return qg.QBrush(self._get_color(color), qc.Qt.SolidPattern) # type: ignore + + def set_background(self, color: Color): + self._scene.setBackgroundBrush(qg.QBrush(self._get_color(color))) + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + """Draw a real dimensionless point.""" + brush = self._get_fill_brush(properties.color) + item = _Point(pos.x, pos.y, brush) + self._add_item(item, properties.handle) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + # PyQt draws a long line for a zero-length line: + if start.isclose(end): + self.draw_point(start, properties) + else: + item = qw.QGraphicsLineItem(start.x, start.y, end.x, end.y) + item.setPen(self._get_pen(properties)) + self._add_item(item, properties.handle) + + def draw_solid_lines( + self, + lines: Iterable[tuple[Vec2, Vec2]], + properties: BackendProperties, + ): + """Fast method to draw a bunch of solid lines with the same properties.""" + pen = self._get_pen(properties) + add_line = self._add_item + for s, e in lines: + if s.isclose(e): + self.draw_point(s, properties) + else: + item = qw.QGraphicsLineItem(s.x, s.y, e.x, e.y) + item.setPen(pen) + add_line(item, properties.handle) + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + if len(path) == 0: + return + item = qw.QGraphicsPathItem(to_qpainter_path([path])) + item.setPen(self._get_pen(properties)) + item.setBrush(self._no_fill) + self._add_item(item, properties.handle) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + # Default fill rule is OddEvenFill! Detecting the path orientation is not + # necessary! + _paths = list(paths) + if len(_paths) == 0: + return + item = _CosmeticPath(to_qpainter_path(_paths)) + item.setPen(self._get_pen(properties)) + item.setBrush(self._get_fill_brush(properties.color)) + self._add_item(item, properties.handle) + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + brush = self._get_fill_brush(properties.color) + polygon = qg.QPolygonF() + for p in points.vertices(): + polygon.append(qc.QPointF(p.x, p.y)) + item = _CosmeticPolygon(polygon) + item.setPen(self._no_line) + item.setBrush(brush) + self._add_item(item, properties.handle) + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + image = image_data.image + transform = image_data.transform + height, width, depth = image.shape + assert depth == 4 + bytes_per_row = width * depth + image = np.ascontiguousarray(np.flip(image, axis=0)) + pixmap = qg.QPixmap( + qg.QImage( + image.data, + width, + height, + bytes_per_row, + qg.QImage.Format.Format_RGBA8888, + ) + ) + item = qw.QGraphicsPixmapItem() + item.setPixmap(pixmap) + item.setTransformationMode(qc.Qt.TransformationMode.SmoothTransformation) + item.setTransform(_matrix_to_qtransform(transform)) + self._add_item(item, properties.handle) + + def clear(self) -> None: + self._scene.clear() + + def finalize(self) -> None: + super().finalize() + self._scene.setSceneRect(self._scene.itemsBoundingRect()) + + +class PyQtBackend(_PyQtBackend): + """ + Backend which uses the :mod:`PySide6` package to implement an interactive + viewer. The :mod:`PyQt5` package can be used as fallback if the :mod:`PySide6` + package is not available. + + Args: + scene: drawing canvas of type :class:`QtWidgets.QGraphicsScene`, + if ``None`` a new canvas will be created + """ + + def __init__( + self, + scene: Optional[qw.QGraphicsScene] = None, + ): + super().__init__(scene or qw.QGraphicsScene()) + + # This implementation keeps all virtual entities alive by attaching references + # to entities to the graphic scene items. + + def set_item_data(self, item: qw.QGraphicsItem, entity_handle: str) -> None: + parent_stack = tuple(e for e, props in self.entity_stack[:-1]) + current_entity = self.current_entity + item.setData(CorrespondingDXFEntity, current_entity) + item.setData(CorrespondingDXFParentStack, parent_stack) + + +class PyQtPlaybackBackend(_PyQtBackend): + """ + Backend which uses the :mod:`PySide6` package to implement an interactive + viewer. The :mod:`PyQt5` package can be used as fallback if the :mod:`PySide6` + package is not available. + + This backend can be used a playback backend for the :meth:`replay` method of the + :class:`Player` class + + Args: + scene: drawing canvas of type :class:`QtWidgets.QGraphicsScene`, + if ``None`` a new canvas will be created + """ + + def __init__( + self, + scene: Optional[qw.QGraphicsScene] = None, + ): + super().__init__(scene or qw.QGraphicsScene()) + + # The backend recorder does not record enter_entity() and exit_entity() events. + # This implementation attaches only entity handles (str) to the graphic scene items. + # Each item references the top level entity e.g. all items of a block reference + # references the handle of the INSERT entity. + + def set_item_data(self, item: qw.QGraphicsItem, entity_handle: str) -> None: + item.setData(CorrespondingDXFEntity, entity_handle) + + +class _CosmeticPath(qw.QGraphicsPathItem): + def paint( + self, + painter: qg.QPainter, + option: qw.QStyleOptionGraphicsItem, + widget: Optional[qw.QWidget] = None, + ) -> None: + _set_cosmetic_brush(self, painter) + super().paint(painter, option, widget) + + +class _CosmeticPolygon(qw.QGraphicsPolygonItem): + def paint( + self, + painter: qg.QPainter, + option: qw.QStyleOptionGraphicsItem, + widget: Optional[qw.QWidget] = None, + ) -> None: + _set_cosmetic_brush(self, painter) + super().paint(painter, option, widget) + + +def _set_cosmetic_brush( + item: qw.QAbstractGraphicsShapeItem, painter: qg.QPainter +) -> None: + """like a cosmetic pen, this sets the brush pattern to appear the same independent of the view""" + brush = item.brush() + # scale by -1 in y because the view is always mirrored in y and undoing the view transformation entirely would make + # the hatch mirrored w.r.t the view + brush.setTransform(painter.transform().inverted()[0].scale(1, -1)) # type: ignore + item.setBrush(brush) + + +def _get_x_scale(t: qg.QTransform) -> float: + return math.sqrt(t.m11() * t.m11() + t.m21() * t.m21()) + + +def _matrix_to_qtransform(matrix: Matrix44) -> qg.QTransform: + """Qt also uses row-vectors so the translation elements are placed in the + bottom row. + + This is only a simple conversion which assumes that although the + transformation is 4x4,it does not involve the z axis. + + A more correct transformation could be implemented like so: + https://stackoverflow.com/questions/10629737/convert-3d-4x4-rotation-matrix-into-2d + """ + return qg.QTransform(*matrix.get_2d_transformation()) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/qtviewer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/qtviewer.py new file mode 100644 index 0000000..0e29e17 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/qtviewer.py @@ -0,0 +1,623 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020-2023, Matthew Broadway +# License: MIT License +# mypy: ignore_errors=True +from __future__ import annotations +from typing import Iterable, Sequence, Set, Optional +import math +import os +import time + +from ezdxf.addons.xqt import QtWidgets as qw, QtCore as qc, QtGui as qg +from ezdxf.addons.xqt import Slot, QAction, Signal + +import ezdxf +import ezdxf.bbox +from ezdxf import recover +from ezdxf.addons import odafc +from ezdxf.addons.drawing import Frontend, RenderContext +from ezdxf.addons.drawing.config import Configuration + +from ezdxf.addons.drawing.properties import ( + is_dark_color, + set_layers_state, + LayerProperties, +) +from ezdxf.addons.drawing.pyqt import ( + _get_x_scale, + PyQtBackend, + CorrespondingDXFEntity, + CorrespondingDXFParentStack, +) +from ezdxf.audit import Auditor +from ezdxf.document import Drawing +from ezdxf.entities import DXFGraphic, DXFEntity +from ezdxf.layouts import Layout +from ezdxf.lldxf.const import DXFStructureError + + +class CADGraphicsView(qw.QGraphicsView): + closing = Signal() + + def __init__( + self, + *, + view_buffer: float = 0.2, + zoom_per_scroll_notch: float = 0.2, + loading_overlay: bool = True, + ): + super().__init__() + self._zoom = 1.0 + self._default_zoom = 1.0 + self._zoom_limits = (0.5, 100) + self._zoom_per_scroll_notch = zoom_per_scroll_notch + self._view_buffer = view_buffer + self._loading_overlay = loading_overlay + self._is_loading = False + + self.setTransformationAnchor(qw.QGraphicsView.AnchorUnderMouse) + self.setResizeAnchor(qw.QGraphicsView.AnchorUnderMouse) + self.setVerticalScrollBarPolicy(qc.Qt.ScrollBarAlwaysOff) + self.setHorizontalScrollBarPolicy(qc.Qt.ScrollBarAlwaysOff) + self.setDragMode(qw.QGraphicsView.ScrollHandDrag) + self.setFrameShape(qw.QFrame.NoFrame) + self.setRenderHints( + qg.QPainter.Antialiasing + | qg.QPainter.TextAntialiasing + | qg.QPainter.SmoothPixmapTransform + ) + + self.setScene(qw.QGraphicsScene()) + self.scale(1, -1) # so that +y is up + + def closeEvent(self, event: qg.QCloseEvent) -> None: + super().closeEvent(event) + self.closing.emit() + + def clear(self): + pass + + def begin_loading(self): + self._is_loading = True + self.scene().invalidate(qc.QRectF(), qw.QGraphicsScene.AllLayers) + qw.QApplication.processEvents() + + def end_loading(self, new_scene: qw.QGraphicsScene): + self.setScene(new_scene) + self._is_loading = False + self.buffer_scene_rect() + self.scene().invalidate(qc.QRectF(), qw.QGraphicsScene.AllLayers) + + def buffer_scene_rect(self): + scene = self.scene() + r = scene.sceneRect() + bx, by = ( + r.width() * self._view_buffer / 2, + r.height() * self._view_buffer / 2, + ) + scene.setSceneRect(r.adjusted(-bx, -by, bx, by)) + + def fit_to_scene(self): + self.fitInView(self.sceneRect(), qc.Qt.KeepAspectRatio) + self._default_zoom = _get_x_scale(self.transform()) + self._zoom = 1 + + def _get_zoom_amount(self) -> float: + return _get_x_scale(self.transform()) / self._default_zoom + + def wheelEvent(self, event: qg.QWheelEvent) -> None: + # dividing by 120 gets number of notches on a typical scroll wheel. + # See QWheelEvent documentation + delta_notches = event.angleDelta().y() / 120 + direction = math.copysign(1, delta_notches) + factor = (1.0 + self._zoom_per_scroll_notch * direction) ** abs(delta_notches) + resulting_zoom = self._zoom * factor + if resulting_zoom < self._zoom_limits[0]: + factor = self._zoom_limits[0] / self._zoom + elif resulting_zoom > self._zoom_limits[1]: + factor = self._zoom_limits[1] / self._zoom + self.scale(factor, factor) + self._zoom *= factor + + def save_view(self) -> SavedView: + return SavedView( + self.transform(), + self._default_zoom, + self._zoom, + self.horizontalScrollBar().value(), + self.verticalScrollBar().value(), + ) + + def restore_view(self, view: SavedView): + self.setTransform(view.transform) + self._default_zoom = view.default_zoom + self._zoom = view.zoom + self.horizontalScrollBar().setValue(view.x) + self.verticalScrollBar().setValue(view.y) + + def drawForeground(self, painter: qg.QPainter, rect: qc.QRectF) -> None: + if self._is_loading and self._loading_overlay: + painter.save() + painter.fillRect(rect, qg.QColor("#aa000000")) + painter.setWorldMatrixEnabled(False) + r = self.viewport().rect() + painter.setBrush(qc.Qt.NoBrush) + painter.setPen(qc.Qt.white) + painter.drawText(r.center(), "Loading...") + painter.restore() + + +class SavedView: + def __init__( + self, transform: qg.QTransform, default_zoom: float, zoom: float, x: int, y: int + ): + self.transform = transform + self.default_zoom = default_zoom + self.zoom = zoom + self.x = x + self.y = y + + +class CADGraphicsViewWithOverlay(CADGraphicsView): + mouse_moved = Signal(qc.QPointF) + element_hovered = Signal(object, int) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._selected_items: list[qw.QGraphicsItem] = [] + self._selected_index = None + self._mark_selection = True + + @property + def current_hovered_element(self) -> Optional[DXFEntity]: + if self._selected_items: + graphics_item = self._selected_items[self._selected_index] + dxf_entity = graphics_item.data(CorrespondingDXFEntity) + return dxf_entity + else: + return None + + def clear(self): + super().clear() + self._selected_items = None + self._selected_index = None + + def begin_loading(self): + self.clear() + super().begin_loading() + + def drawForeground(self, painter: qg.QPainter, rect: qc.QRectF) -> None: + super().drawForeground(painter, rect) + if self._selected_items and self._mark_selection: + item = self._selected_items[self._selected_index] + r = item.sceneTransform().mapRect(item.boundingRect()) + painter.fillRect(r, qg.QColor(0, 255, 0, 100)) + + def mouseMoveEvent(self, event: qg.QMouseEvent) -> None: + super().mouseMoveEvent(event) + pos = self.mapToScene(event.pos()) + self.mouse_moved.emit(pos) + selected_items = self.scene().items(pos) + if selected_items != self._selected_items: + self._selected_items = selected_items + self._selected_index = 0 if self._selected_items else None + self._emit_selected() + + def mouseReleaseEvent(self, event: qg.QMouseEvent) -> None: + super().mouseReleaseEvent(event) + if event.button() == qc.Qt.LeftButton and self._selected_items: + self._selected_index = (self._selected_index + 1) % len( + self._selected_items + ) + self._emit_selected() + + def _emit_selected(self): + self.element_hovered.emit(self._selected_items, self._selected_index) + self.scene().invalidate(self.sceneRect(), qw.QGraphicsScene.ForegroundLayer) + + def toggle_selection_marker(self): + self._mark_selection = not self._mark_selection + + +class CADWidget(qw.QWidget): + def __init__(self, view: CADGraphicsView, config: Configuration = Configuration()): + super().__init__() + layout = qw.QVBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(view) + self.setLayout(layout) + self._view = view + self._view.closing.connect(self.close) + self._config = config + self._bbox_cache = ezdxf.bbox.Cache() + self._doc: Drawing = None # type: ignore + self._render_context: RenderContext = None # type: ignore + self._visible_layers: set[str] = set() + self._current_layout: str = "Model" + self._reset_backend() + + def _reset_backend(self): + # clear caches + self._backend = PyQtBackend() + + @property + def doc(self) -> Drawing: + return self._doc + + @property + def view(self) -> CADGraphicsView: + return self._view + + @property + def render_context(self) -> RenderContext: + return self._render_context + + @property + def current_layout(self) -> str: + return self._current_layout + + def set_document( + self, + document: Drawing, + *, + layout: str = "Model", + draw: bool = True, + ): + self._doc = document + # initialize bounding box cache for faste paperspace drawing + self._bbox_cache = ezdxf.bbox.Cache() + self._render_context = self._make_render_context(document) + self._reset_backend() + self._visible_layers = set() + self._current_layout = None + if draw: + self.draw_layout(layout) + + def set_visible_layers(self, layers: Set[str]) -> None: + self._visible_layers = layers + self.draw_layout(self._current_layout, reset_view=False) + + def _make_render_context(self, doc: Drawing) -> RenderContext: + def update_layers_state(layers: Sequence[LayerProperties]): + if self._visible_layers: + set_layers_state(layers, self._visible_layers, state=True) + + render_context = RenderContext(doc) + render_context.set_layer_properties_override(update_layers_state) + return render_context + + def draw_layout( + self, + layout_name: str, + reset_view: bool = True, + ): + self._current_layout = layout_name + self._view.begin_loading() + new_scene = qw.QGraphicsScene() + self._backend.set_scene(new_scene) + layout = self._doc.layout(layout_name) + self._update_render_context(layout) + try: + self._create_frontend().draw_layout(layout) + finally: + self._backend.finalize() + self._view.end_loading(new_scene) + self._view.buffer_scene_rect() + if reset_view: + self._view.fit_to_scene() + + def _create_frontend(self) -> Frontend: + return Frontend( + ctx=self._render_context, + out=self._backend, + config=self._config, + bbox_cache=self._bbox_cache, + ) + + def _update_render_context(self, layout: Layout) -> None: + assert self._render_context is not None + self._render_context.set_current_layout(layout) + + +class CADViewer(qw.QMainWindow): + def __init__(self, cad: Optional[CADWidget] = None): + super().__init__() + self._doc: Optional[Drawing] = None + if cad is None: + self._cad = CADWidget(CADGraphicsViewWithOverlay(), config=Configuration()) + else: + self._cad = cad + self._view = self._cad.view + + if isinstance(self._view, CADGraphicsViewWithOverlay): + self._view.element_hovered.connect(self._on_element_hovered) + self._view.mouse_moved.connect(self._on_mouse_moved) + + menu = self.menuBar() + select_doc_action = QAction("Select Document", self) + select_doc_action.triggered.connect(self._select_doc) + menu.addAction(select_doc_action) + self.select_layout_menu = menu.addMenu("Select Layout") + + toggle_sidebar_action = QAction("Toggle Sidebar", self) + toggle_sidebar_action.triggered.connect(self._toggle_sidebar) + menu.addAction(toggle_sidebar_action) + + toggle_selection_marker_action = QAction("Toggle Entity Marker", self) + toggle_selection_marker_action.triggered.connect(self._toggle_selection_marker) + menu.addAction(toggle_selection_marker_action) + + self.reload_menu = menu.addMenu("Reload") + reload_action = QAction("Reload", self) + reload_action.setShortcut(qg.QKeySequence("F5")) + reload_action.triggered.connect(self._reload) + self.reload_menu.addAction(reload_action) + self.keep_view_action = QAction("Keep View", self) + self.keep_view_action.setCheckable(True) + self.keep_view_action.setChecked(True) + self.reload_menu.addAction(self.keep_view_action) + watch_action = QAction("Watch", self) + watch_action.setCheckable(True) + watch_action.toggled.connect(self._toggle_watch) + self.reload_menu.addAction(watch_action) + self._watch_timer = qc.QTimer() + self._watch_timer.setInterval(50) + self._watch_timer.timeout.connect(self._check_watch) + self._watch_mtime = None + + self.sidebar = qw.QSplitter(qc.Qt.Vertical) + self.layers = qw.QListWidget() + self.layers.setStyleSheet( + "QListWidget {font-size: 12pt;} " + "QCheckBox {font-size: 12pt; padding-left: 5px;}" + ) + self.sidebar.addWidget(self.layers) + info_container = qw.QWidget() + info_layout = qw.QVBoxLayout() + info_layout.setContentsMargins(0, 0, 0, 0) + self.selected_info = qw.QPlainTextEdit() + self.selected_info.setReadOnly(True) + info_layout.addWidget(self.selected_info) + self.mouse_pos = qw.QLabel() + info_layout.addWidget(self.mouse_pos) + info_container.setLayout(info_layout) + self.sidebar.addWidget(info_container) + + container = qw.QSplitter() + self.setCentralWidget(container) + container.addWidget(self._cad) + container.addWidget(self.sidebar) + container.setCollapsible(0, False) + container.setCollapsible(1, True) + w = container.width() + container.setSizes([int(3 * w / 4), int(w / 4)]) + self.setWindowTitle("CAD Viewer") + self.resize(1600, 900) + self.show() + + @staticmethod + def from_config(config: Configuration) -> CADViewer: + return CADViewer(cad=CADWidget(CADGraphicsViewWithOverlay(), config=config)) + + def _create_cad_widget(self): + self._view = CADGraphicsViewWithOverlay() + self._cad = CADWidget(self._view) + + def load_file(self, path: str, layout: str = "Model"): + try: + if os.path.splitext(path)[1].lower() == ".dwg": + doc = odafc.readfile(path) + auditor = doc.audit() + else: + try: + doc = ezdxf.readfile(path) + except ezdxf.DXFError: + doc, auditor = recover.readfile(path) + else: + auditor = doc.audit() + self.set_document(doc, auditor, layout=layout) + except IOError as e: + qw.QMessageBox.critical(self, "Loading Error", str(e)) + except DXFStructureError as e: + qw.QMessageBox.critical( + self, + "DXF Structure Error", + f'Invalid DXF file "{path}": {str(e)}', + ) + + def _select_doc(self): + path, _ = qw.QFileDialog.getOpenFileName( + self, + caption="Select CAD Document", + filter="CAD Documents (*.dxf *.DXF *.dwg *.DWG)", + ) + if path: + self.load_file(path) + + def set_document( + self, + document: Drawing, + auditor: Auditor, + *, + layout: str = "Model", + draw: bool = True, + ): + error_count = len(auditor.errors) + if error_count > 0: + ret = qw.QMessageBox.question( + self, + "Found DXF Errors", + f'Found {error_count} errors in file "{document.filename}"\n' + f"Load file anyway? ", + ) + if ret == qw.QMessageBox.No: + auditor.print_error_report(auditor.errors) + return + + if document.filename: + try: + self._watch_mtime = os.stat(document.filename).st_mtime + except OSError: + self._watch_mtime = None + else: + self._watch_mtime = None + self._cad.set_document(document, layout=layout, draw=draw) + self._doc = document + self._populate_layouts() + self._populate_layer_list() + self.setWindowTitle("CAD Viewer - " + str(document.filename)) + + def _populate_layer_list(self): + self.layers.blockSignals(True) + self.layers.clear() + for layer in self._cad.render_context.layers.values(): + name = layer.layer + item = qw.QListWidgetItem() + self.layers.addItem(item) + checkbox = qw.QCheckBox(name) + checkbox.setCheckState( + qc.Qt.Checked if layer.is_visible else qc.Qt.Unchecked + ) + checkbox.stateChanged.connect(self._layers_updated) + text_color = "#FFFFFF" if is_dark_color(layer.color, 0.4) else "#000000" + checkbox.setStyleSheet( + f"color: {text_color}; background-color: {layer.color}" + ) + self.layers.setItemWidget(item, checkbox) + self.layers.blockSignals(False) + + def _populate_layouts(self): + def draw_layout(name: str): + def run(): + self.draw_layout(name, reset_view=True) + + return run + + self.select_layout_menu.clear() + for layout_name in self._cad.doc.layout_names_in_taborder(): + action = QAction(layout_name, self) + action.triggered.connect(draw_layout(layout_name)) + self.select_layout_menu.addAction(action) + + def draw_layout( + self, + layout_name: str, + reset_view: bool = True, + ): + print(f"drawing {layout_name}") + try: + start = time.perf_counter() + self._cad.draw_layout(layout_name, reset_view=reset_view) + duration = time.perf_counter() - start + print(f"took {duration:.4f} seconds") + except DXFStructureError as e: + qw.QMessageBox.critical( + self, + "DXF Structure Error", + f'Abort rendering of layout "{layout_name}": {str(e)}', + ) + + def resizeEvent(self, event: qg.QResizeEvent) -> None: + self._view.fit_to_scene() + + def _layer_checkboxes(self) -> Iterable[tuple[int, qw.QCheckBox]]: + for i in range(self.layers.count()): + item = self.layers.itemWidget(self.layers.item(i)) + yield i, item # type: ignore + + @Slot(int) # type: ignore + def _layers_updated(self, item_state: qc.Qt.CheckState): + shift_held = qw.QApplication.keyboardModifiers() & qc.Qt.ShiftModifier + if shift_held: + for i, item in self._layer_checkboxes(): + item.blockSignals(True) + item.setCheckState(item_state) + item.blockSignals(False) + + visible_layers = set() + for i, layer in self._layer_checkboxes(): + if layer.checkState() == qc.Qt.Checked: + visible_layers.add(layer.text()) + self._cad.set_visible_layers(visible_layers) + + @Slot() + def _toggle_sidebar(self): + self.sidebar.setHidden(not self.sidebar.isHidden()) + + @Slot() + def _toggle_selection_marker(self): + self._view.toggle_selection_marker() + + @Slot() + def _reload(self): + if self._cad.doc is not None and self._cad.doc.filename: + keep_view = self.keep_view_action.isChecked() + view = self._view.save_view() if keep_view else None + self.load_file(self._cad.doc.filename, layout=self._cad.current_layout) + if keep_view: + self._view.restore_view(view) + + @Slot() + def _toggle_watch(self): + if self._watch_timer.isActive(): + self._watch_timer.stop() + else: + self._watch_timer.start() + + @Slot() + def _check_watch(self): + if self._watch_mtime is None or self._cad.doc is None: + return + filename = self._cad.doc.filename + if filename: + try: + mtime = os.stat(filename).st_mtime + except OSError: + return + if mtime != self._watch_mtime: + self._reload() + + @Slot(qc.QPointF) + def _on_mouse_moved(self, mouse_pos: qc.QPointF): + self.mouse_pos.setText( + f"mouse position: {mouse_pos.x():.4f}, {mouse_pos.y():.4f}\n" + ) + + @Slot(object, int) + def _on_element_hovered(self, elements: list[qw.QGraphicsItem], index: int): + if not elements: + text = "No element selected" + else: + text = f"Selected: {index + 1} / {len(elements)} (click to cycle)\n" + element = elements[index] + dxf_entity: DXFGraphic | str | None = element.data(CorrespondingDXFEntity) + if isinstance(dxf_entity, str): + dxf_entity = self.load_dxf_entity(dxf_entity) + if dxf_entity is None: + text += "No data" + else: + text += ( + f"Selected Entity: {dxf_entity}\n" + f"Layer: {dxf_entity.dxf.layer}\n\nDXF Attributes:\n" + ) + text += _entity_attribs_string(dxf_entity) + + dxf_parent_stack = element.data(CorrespondingDXFParentStack) + if dxf_parent_stack: + text += "\nParents:\n" + for entity in reversed(dxf_parent_stack): + text += f"- {entity}\n" + text += _entity_attribs_string(entity, indent=" ") + self.selected_info.setPlainText(text) + + def load_dxf_entity(self, entity_handle: str) -> DXFGraphic | None: + if self._doc is not None: + return self._doc.entitydb.get(entity_handle) + return None + + +def _entity_attribs_string(dxf_entity: DXFGraphic, indent: str = "") -> str: + text = "" + for key, value in dxf_entity.dxf.all_existing_dxf_attribs().items(): + text += f"{indent}- {key}: {value}\n" + return text diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/recorder.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/recorder.py new file mode 100644 index 0000000..68f8518 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/recorder.py @@ -0,0 +1,447 @@ +# Copyright (c) 2023-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + Sequence, + Callable, + Optional, + NamedTuple, +) +from typing_extensions import Self, TypeAlias +import copy +import abc + +from ezdxf.math import BoundingBox2d, Matrix44, Vec2, UVec +from ezdxf.npshapes import NumpyPath2d, NumpyPoints2d, EmptyShapeError +from ezdxf.tools import take2 +from ezdxf.tools.clipping_portal import ClippingRect + +from .backend import BackendInterface, ImageData +from .config import Configuration +from .properties import BackendProperties +from .type_hints import Color + + +class DataRecord(abc.ABC): + def __init__(self) -> None: + self.property_hash: int = 0 + self.handle: str = "" + + @abc.abstractmethod + def bbox(self) -> BoundingBox2d: + ... + + @abc.abstractmethod + def transform_inplace(self, m: Matrix44) -> None: + ... + + +class PointsRecord(DataRecord): + # n=1 point; n=2 line; n>2 filled polygon + def __init__(self, points: NumpyPoints2d) -> None: + super().__init__() + self.points: NumpyPoints2d = points + + def bbox(self) -> BoundingBox2d: + try: + return self.points.bbox() + except EmptyShapeError: + pass + return BoundingBox2d() + + def transform_inplace(self, m: Matrix44) -> None: + self.points.transform_inplace(m) + + +class SolidLinesRecord(DataRecord): + def __init__(self, lines: NumpyPoints2d) -> None: + super().__init__() + self.lines: NumpyPoints2d = lines + + def bbox(self) -> BoundingBox2d: + try: + return self.lines.bbox() + except EmptyShapeError: + pass + return BoundingBox2d() + + def transform_inplace(self, m: Matrix44) -> None: + self.lines.transform_inplace(m) + + +class PathRecord(DataRecord): + def __init__(self, path: NumpyPath2d) -> None: + super().__init__() + self.path: NumpyPath2d = path + + def bbox(self) -> BoundingBox2d: + try: + return self.path.bbox() + except EmptyShapeError: + pass + return BoundingBox2d() + + def transform_inplace(self, m: Matrix44) -> None: + self.path.transform_inplace(m) + + +class FilledPathsRecord(DataRecord): + def __init__(self, paths: Sequence[NumpyPath2d]) -> None: + super().__init__() + self.paths: Sequence[NumpyPath2d] = paths + + def bbox(self) -> BoundingBox2d: + bbox = BoundingBox2d() + for path in self.paths: + if len(path): + bbox.extend(path.extents()) + return bbox + + def transform_inplace(self, m: Matrix44) -> None: + for path in self.paths: + path.transform_inplace(m) + + +class ImageRecord(DataRecord): + def __init__(self, boundary: NumpyPoints2d, image_data: ImageData) -> None: + super().__init__() + self.boundary: NumpyPoints2d = boundary + self.image_data: ImageData = image_data + + def bbox(self) -> BoundingBox2d: + try: + return self.boundary.bbox() + except EmptyShapeError: + pass + return BoundingBox2d() + + def transform_inplace(self, m: Matrix44) -> None: + self.boundary.transform_inplace(m) + self.image_data.transform @= m + + +class Recorder(BackendInterface): + """Records the output of the Frontend class.""" + + def __init__(self) -> None: + self.config = Configuration() + self.background: Color = "#000000" + self.records: list[DataRecord] = [] + self.properties: dict[int, BackendProperties] = dict() + + def player(self) -> Player: + """Returns a :class:`Player` instance with the original recordings! Make a copy + of this player to protect the original recordings from being modified:: + + safe_player = recorder.player().copy() + + """ + player = Player() + player.config = self.config + player.background = self.background + player.records = self.records + player.properties = self.properties + player.has_shared_recordings = True + return player + + def configure(self, config: Configuration) -> None: + self.config = config + + def set_background(self, color: Color) -> None: + self.background = color + + def store(self, record: DataRecord, properties: BackendProperties) -> None: + # exclude top-level entity handle to reduce the variance: + # color, lineweight, layer, pen + prop_hash = hash(properties[:4]) + record.property_hash = prop_hash + record.handle = properties.handle + self.records.append(record) + self.properties[prop_hash] = properties + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.store(PointsRecord(NumpyPoints2d((pos,))), properties) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.store(PointsRecord(NumpyPoints2d((start, end))), properties) + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + def flatten() -> Iterator[Vec2]: + for s, e in lines: + yield s + yield e + + self.store(SolidLinesRecord(NumpyPoints2d(flatten())), properties) + + def draw_path(self, path: NumpyPath2d, properties: BackendProperties) -> None: + assert isinstance(path, NumpyPath2d) + self.store(PathRecord(path), properties) + + def draw_filled_polygon( + self, points: NumpyPoints2d, properties: BackendProperties + ) -> None: + assert isinstance(points, NumpyPoints2d) + self.store(PointsRecord(points), properties) + + def draw_filled_paths( + self, paths: Iterable[NumpyPath2d], properties: BackendProperties + ) -> None: + paths = tuple(paths) + if len(paths) == 0: + return + + assert isinstance(paths[0], NumpyPath2d) + self.store(FilledPathsRecord(paths), properties) + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + # preserve the boundary in image_data in pixel coordinates + boundary = copy.deepcopy(image_data.pixel_boundary_path) + boundary.transform_inplace(image_data.transform) + self.store(ImageRecord(boundary, image_data), properties) + + def enter_entity(self, entity, properties) -> None: + pass + + def exit_entity(self, entity) -> None: + pass + + def clear(self) -> None: + raise NotImplementedError() + + def finalize(self) -> None: + pass + + +class Override(NamedTuple): + """Represents the override state for a data record. + + Attributes: + properties: original or modified :class:`BackendProperties` + is_visible: override visibility e.g. switch layers on/off + + """ + + properties: BackendProperties + is_visible: bool = True + + +OverrideFunc: TypeAlias = Callable[[BackendProperties], Override] + + +class Player: + """Plays the recordings of the :class:`Recorder` backend on another backend.""" + + def __init__(self) -> None: + self.config = Configuration() + self.background: Color = "#000000" + self.records: list[DataRecord] = [] + self.properties: dict[int, BackendProperties] = dict() + self._bbox = BoundingBox2d() + self.has_shared_recordings: bool = False + + def __copy__(self) -> Self: + """Returns a copy of the player with non-shared recordings.""" + player = self.__class__() + # config is a frozen dataclass: + player.config = self.config + player.background = self.background + # recordings are mutable: transform and crop inplace + player.records = copy.deepcopy(self.records) + # the properties dict may grow, but entries will never be removed: + player.properties = self.properties + player.has_shared_recordings = False + return player + + copy = __copy__ + + def recordings(self) -> Iterator[tuple[DataRecord, BackendProperties]]: + """Yields all recordings as `(DataRecord, BackendProperties)` tuples.""" + props = self.properties + for record in self.records: + properties = BackendProperties( + *props[record.property_hash][:4], record.handle + ) + yield record, properties + + def replay( + self, backend: BackendInterface, override: Optional[OverrideFunc] = None + ) -> None: + """Replay the recording on another backend that implements the + :class:`BackendInterface`. The optional `override` function can be used to + override the properties and state of data records, it gets the :class:`BackendProperties` + as input and must return an :class:`Override` instance. + """ + + backend.configure(self.config) + backend.set_background(self.background) + for record, properties in self.recordings(): + if override: + state = override(properties) + if not state.is_visible: + continue + properties = state.properties + if isinstance(record, PointsRecord): + count = len(record.points) + if count == 0: + continue + if count > 2: + backend.draw_filled_polygon(record.points, properties) + continue + vertices = record.points.vertices() + if len(vertices) == 1: + backend.draw_point(vertices[0], properties) + else: + backend.draw_line(vertices[0], vertices[1], properties) + elif isinstance(record, SolidLinesRecord): + backend.draw_solid_lines(take2(record.lines.vertices()), properties) + elif isinstance(record, PathRecord): + backend.draw_path(record.path, properties) + elif isinstance(record, FilledPathsRecord): + backend.draw_filled_paths(record.paths, properties) + elif isinstance(record, ImageRecord): + backend.draw_image(record.image_data, properties) + backend.finalize() + + def transform(self, m: Matrix44) -> None: + """Transforms the recordings inplace by a transformation matrix `m` of type + :class:`~ezdxf.math.Matrix44`. + """ + for record in self.records: + record.transform_inplace(m) + + if self._bbox.has_data: + # works for 90-, 180- and 270-degree rotation + self._bbox = BoundingBox2d(m.fast_2d_transform(self._bbox.rect_vertices())) + + def bbox(self) -> BoundingBox2d: + """Returns the bounding box of all records as :class:`~ezdxf.math.BoundingBox2d`.""" + if not self._bbox.has_data: + self.update_bbox() + return self._bbox + + def update_bbox(self) -> None: + bbox = BoundingBox2d() + for record in self.records: + bbox.extend(record.bbox()) + self._bbox = bbox + + def crop_rect(self, p1: UVec, p2: UVec, distance: float) -> None: + """Crop recorded shapes inplace by a rectangle defined by two points. + + The argument `distance` defines the approximation precision for paths which have + to be approximated as polylines for cropping but only paths which are really get + cropped are approximated, paths that are fully inside the crop box will not be + approximated. + + Args: + p1: first corner of the clipping rectangle + p2: second corner of the clipping rectangle + distance: maximum distance from the center of the curve to the + center of the line segment between two approximation points to + determine if a segment should be subdivided. + + """ + crop_rect = BoundingBox2d([Vec2(p1), Vec2(p2)]) + self.records = crop_records_rect(self.records, crop_rect, distance) + self._bbox = BoundingBox2d() # determine new bounding box on demand + + +def crop_records_rect( + records: list[DataRecord], crop_rect: BoundingBox2d, distance: float +) -> list[DataRecord]: + """Crop recorded shapes inplace by a rectangle.""" + + def sort_paths(np_paths: Sequence[NumpyPath2d]): + _inside: list[NumpyPath2d] = [] + _crop: list[NumpyPath2d] = [] + + for np_path in np_paths: + bbox = BoundingBox2d(np_path.extents()) + if not crop_rect.has_intersection(bbox): + # path is complete outside the cropping rectangle + pass + elif crop_rect.inside(bbox.extmin) and crop_rect.inside(bbox.extmax): + # path is complete inside the cropping rectangle + _inside.append(np_path) + else: + _crop.append(np_path) + + return _crop, _inside + + def crop_paths( + np_paths: Sequence[NumpyPath2d], + ) -> list[NumpyPath2d]: + return list(clipper.clip_filled_paths(np_paths, distance)) + + # an undefined crop box crops nothing: + if not crop_rect.has_data: + return records + cropped_records: list[DataRecord] = [] + size = crop_rect.size + # a crop box size of zero in any dimension crops everything: + if size.x < 1e-12 or size.y < 1e-12: + return cropped_records + + clipper = ClippingRect(crop_rect.rect_vertices()) + for record in records: + record_box = record.bbox() + if not crop_rect.has_intersection(record_box): + # record is complete outside the cropping rectangle + continue + if crop_rect.inside(record_box.extmin) and crop_rect.inside(record_box.extmax): + # record is complete inside the cropping rectangle + cropped_records.append(record) + continue + + if isinstance(record, FilledPathsRecord): + paths_to_crop, inside = sort_paths(record.paths) + cropped_paths = crop_paths(paths_to_crop) + inside + if cropped_paths: + record.paths = tuple(cropped_paths) + cropped_records.append(record) + elif isinstance(record, PathRecord): + # could be split into multiple parts + for p in clipper.clip_paths([record.path], distance): + path_record = PathRecord(p) + path_record.property_hash = record.property_hash + path_record.handle = record.handle + cropped_records.append(path_record) + elif isinstance(record, PointsRecord): + count = len(record.points) + if count == 1: + # record is inside the clipping shape! + cropped_records.append(record) + elif count == 2: + s, e = record.points.vertices() + for segment in clipper.clip_line(s, e): + if not segment: + continue + _record = copy.copy(record) # shallow copy + _record.points = NumpyPoints2d(segment) + cropped_records.append(_record) + else: + for polygon in clipper.clip_polygon(record.points): + if not polygon: + continue + _record = copy.copy(record) # shallow copy! + _record.points = polygon + cropped_records.append(_record) + elif isinstance(record, SolidLinesRecord): + points: list[Vec2] = [] + for s, e in take2(record.lines.vertices()): + for segment in clipper.clip_line(s, e): + points.extend(segment) + record.lines = NumpyPoints2d(points) + cropped_records.append(record) + elif isinstance(record, ImageRecord): + pass + # TODO: Image cropping not supported + # Crop image boundary and apply transparency to cropped + # parts of the image? -> Image boundary is now a polygon! + else: + raise ValueError("invalid record type") + return cropped_records diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/svg.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/svg.py new file mode 100644 index 0000000..3b0d1b2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/svg.py @@ -0,0 +1,422 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence, no_type_check + +import copy +from xml.etree import ElementTree as ET +import numpy as np + +from ezdxf.math import Vec2, BoundingBox2d, Matrix44 +from ezdxf.path import Command + + +from .type_hints import Color +from .backend import BackendInterface, BkPath2d, BkPoints2d, ImageData +from .config import Configuration, LineweightPolicy +from .properties import BackendProperties +from . import layout, recorder + +__all__ = ["SVGBackend"] + + +class SVGBackend(recorder.Recorder): + """This is a native SVG rendering backend and does not require any external packages + to render SVG images other than the core dependencies. This backend support content + cropping at page margins. + """ + + def __init__(self) -> None: + super().__init__() + self._init_flip_y = True + + def get_xml_root_element( + self, + page: layout.Page, + *, + settings: layout.Settings = layout.Settings(), + render_box: BoundingBox2d | None = None, + ) -> ET.Element: + top_origin = True + settings = copy.copy(settings) + # DXF coordinates are mapped to integer viewBox coordinates in the first + # quadrant, producing compact SVG files. The larger the coordinate range, the + # more precise and the lager the files. + settings.output_coordinate_space = 1_000_000 + + # This player changes the original recordings! + player = self.player() + if render_box is None: + render_box = player.bbox() + + # the page origin (0, 0) is in the top-left corner. + output_layout = layout.Layout(render_box, flip_y=self._init_flip_y) + page = output_layout.get_final_page(page, settings) + if page.width == 0 or page.height == 0: + return ET.Element("svg") # empty page + + m = output_layout.get_placement_matrix( + page, settings=settings, top_origin=top_origin + ) + # transform content to the output coordinates space: + player.transform(m) + if settings.crop_at_margins: + p1, p2 = page.get_margin_rect(top_origin=top_origin) # in mm + # scale factor to map page coordinates to output space coordinates: + output_scale = settings.page_output_scale_factor(page) + max_sagitta = 0.1 * output_scale # curve approximation 0.1 mm + # crop content inplace by the margin rect: + player.crop_rect(p1 * output_scale, p2 * output_scale, max_sagitta) + + self._init_flip_y = False + backend = self.make_backend(page, settings) + player.replay(backend) + return backend.get_xml_root_element() + + def get_string( + self, + page: layout.Page, + *, + settings: layout.Settings = layout.Settings(), + render_box: BoundingBox2d | None = None, + xml_declaration=True, + ) -> str: + """Returns the XML data as unicode string. + + Args: + page: page definition, see :class:`~ezdxf.addons.drawing.layout.Page` + settings: layout settings, see :class:`~ezdxf.addons.drawing.layout.Settings` + render_box: set explicit region to render, default is content bounding box + xml_declaration: inserts the "" string + in front of the element + + """ + xml = self.get_xml_root_element(page, settings=settings, render_box=render_box) + return ET.tostring(xml, encoding="unicode", xml_declaration=xml_declaration) + + @staticmethod + def make_backend(page: layout.Page, settings: layout.Settings) -> SVGRenderBackend: + """Override this method to use a customized render backend.""" + return SVGRenderBackend(page, settings) + + +def make_view_box(page: layout.Page, output_coordinate_space: float) -> tuple[int, int]: + size = round(output_coordinate_space) + if page.width > page.height: + return size, round(size * (page.height / page.width)) + return round(size * (page.width / page.height)), size + + +def scale_page_to_view_box(page: layout.Page, output_coordinate_space: float) -> float: + # The viewBox coordinates are integer values in the range of [0, output_coordinate_space] + return min( + output_coordinate_space / page.width, + output_coordinate_space / page.height, + ) + + +class Styles: + def __init__(self, xml: ET.Element) -> None: + self._xml = xml + self._class_names: dict[int, str] = dict() + self._counter = 1 + + def get_class( + self, + *, + stroke: Color = "none", + stroke_width: int | str = "none", + stroke_opacity: float = 1.0, + fill: Color = "none", + fill_opacity: float = 1.0, + ) -> str: + style = ( + f"{{stroke: {stroke}; " + f"stroke-width: {stroke_width}; " + f"stroke-opacity: {stroke_opacity:.3f}; " + f"fill: {fill}; " + f"fill-opacity: {fill_opacity:.3f};}}" + ) + key = hash(style) + try: + return self._class_names[key] + except KeyError: + pass + name = f"C{self._counter:X}" + self._counter += 1 + self._add_class(name, style) + self._class_names[key] = name + return name + + def _add_class(self, name, style_str: str) -> None: + style = ET.Element("style") + style.text = f".{name} {style_str}" + self._xml.append(style) + + +CMD_M_ABS = "M {0.x:.0f} {0.y:.0f}" +CMD_M_REL = "m {0.x:.0f} {0.y:.0f}" +CMD_L_ABS = "L {0.x:.0f} {0.y:.0f}" +CMD_L_REL = "l {0.x:.0f} {0.y:.0f}" +CMD_C3_ABS = "Q {0.x:.0f} {0.y:.0f} {1.x:.0f} {1.y:.0f}" +CMD_C3_REL = "q {0.x:.0f} {0.y:.0f} {1.x:.0f} {1.y:.0f}" +CMD_C4_ABS = "C {0.x:.0f} {0.y:.0f} {1.x:.0f} {1.y:.0f} {2.x:.0f} {2.y:.0f}" +CMD_C4_REL = "c {0.x:.0f} {0.y:.0f} {1.x:.0f} {1.y:.0f} {2.x:.0f} {2.y:.0f}" +CMD_CONT = "{0.x:.0f} {0.y:.0f}" + + +class SVGRenderBackend(BackendInterface): + """Creates the SVG output. + + This backend requires some preliminary work, record the frontend output via the + Recorder backend to accomplish the following requirements: + + - Scale the content in y-axis by -1 to invert the y-axis (SVG). + - Move content in the first quadrant of the coordinate system. + - The viewBox is defined by the lower left corner in the origin (0, 0) and + the upper right corner at (view_box_width, view_box_height) + - The output coordinates are integer values, scale the content appropriately. + - Replay the recorded output on this backend. + + """ + + def __init__(self, page: layout.Page, settings: layout.Settings) -> None: + self.settings = settings + self._stroke_width_cache: dict[float, int] = dict() + view_box_width, view_box_height = make_view_box( + page, settings.output_coordinate_space + ) + # StrokeWidthPolicy.absolute: + # stroke-width in mm as resolved by the frontend + self.stroke_width_scale: float = view_box_width / page.width_in_mm + self.min_lineweight = 0.05 # in mm, set by configure() + self.lineweight_scaling = 1.0 # set by configure() + self.lineweight_policy = LineweightPolicy.ABSOLUTE # set by configure() + # fixed lineweight for all strokes in ABSOLUTE mode: + # set Configuration.min_lineweight to the desired lineweight in 1/300 inch! + # set Configuration.lineweight_scaling to 0 + + # LineweightPolicy.RELATIVE: + # max_stroke_width is determined as a certain percentage of settings.output_coordinate_space + self.max_stroke_width: int = int( + settings.output_coordinate_space * settings.max_stroke_width + ) + # min_stroke_width is determined as a certain percentage of max_stroke_width + self.min_stroke_width: int = int( + self.max_stroke_width * settings.min_stroke_width + ) + # LineweightPolicy.RELATIVE_FIXED: + # all strokes have a fixed stroke-width as a certain percentage of max_stroke_width + self.fixed_stroke_width: int = int( + self.max_stroke_width * settings.fixed_stroke_width + ) + self.root = ET.Element( + "svg", + xmlns="http://www.w3.org/2000/svg", + width=f"{page.width_in_mm:g}mm", + height=f"{page.height_in_mm:g}mm", + viewBox=f"0 0 {view_box_width} {view_box_height}", + ) + self.styles = Styles(ET.SubElement(self.root, "defs")) + self.background = ET.SubElement( + self.root, + "rect", + fill="white", + x="0", + y="0", + width=str(view_box_width), + height=str(view_box_height), + ) + self.entities = ET.SubElement(self.root, "g") + self.entities.set("stroke-linecap", "round") + self.entities.set("stroke-linejoin", "round") + self.entities.set("fill-rule", "evenodd") + + def get_xml_root_element(self) -> ET.Element: + return self.root + + def add_strokes(self, d: str, properties: BackendProperties): + if not d: + return + element = ET.SubElement(self.entities, "path", d=d) + stroke_width = self.resolve_stroke_width(properties.lineweight) + stroke_color, stroke_opacity = self.resolve_color(properties.color) + cls = self.styles.get_class( + stroke=stroke_color, + stroke_width=stroke_width, + stroke_opacity=stroke_opacity, + ) + element.set("class", cls) + + def add_filling(self, d: str, properties: BackendProperties): + if not d: + return + element = ET.SubElement(self.entities, "path", d=d) + fill_color, fill_opacity = self.resolve_color(properties.color) + cls = self.styles.get_class(fill=fill_color, fill_opacity=fill_opacity) + element.set("class", cls) + + def resolve_color(self, color: Color) -> tuple[Color, float]: + return color[:7], alpha_to_opacity(color[7:9]) + + def resolve_stroke_width(self, width: float) -> int: + try: + return self._stroke_width_cache[width] + except KeyError: + pass + stroke_width = self.fixed_stroke_width + policy = self.lineweight_policy + if policy == LineweightPolicy.ABSOLUTE: + if self.lineweight_scaling: + width = max(self.min_lineweight, width) * self.lineweight_scaling + else: + width = self.min_lineweight + stroke_width = round(width * self.stroke_width_scale) + elif policy == LineweightPolicy.RELATIVE: + stroke_width = map_lineweight_to_stroke_width( + width, self.min_stroke_width, self.max_stroke_width + ) + self._stroke_width_cache[width] = stroke_width + return stroke_width + + def set_background(self, color: Color) -> None: + color_str = color[:7] + opacity = alpha_to_opacity(color[7:9]) + self.background.set("fill", color_str) + self.background.set("fill-opacity", str(opacity)) + + def draw_point(self, pos: Vec2, properties: BackendProperties) -> None: + self.add_strokes(self.make_polyline_str([pos, pos]), properties) + + def draw_line(self, start: Vec2, end: Vec2, properties: BackendProperties) -> None: + self.add_strokes(self.make_polyline_str([start, end]), properties) + + def draw_solid_lines( + self, lines: Iterable[tuple[Vec2, Vec2]], properties: BackendProperties + ) -> None: + lines = list(lines) + if len(lines) == 0: + return + self.add_strokes(self.make_multi_line_str(lines), properties) + + def draw_path(self, path: BkPath2d, properties: BackendProperties) -> None: + self.add_strokes(self.make_path_str(path), properties) + + def draw_filled_paths( + self, paths: Iterable[BkPath2d], properties: BackendProperties + ) -> None: + d = [] + for path in paths: + if len(path): + d.append(self.make_path_str(path, close=True)) + self.add_filling(" ".join(d), properties) + + def draw_filled_polygon( + self, points: BkPoints2d, properties: BackendProperties + ) -> None: + self.add_filling( + self.make_polyline_str(points.vertices(), close=True), properties + ) + + def draw_image(self, image_data: ImageData, properties: BackendProperties) -> None: + pass # TODO: not implemented + + @staticmethod + def make_polyline_str(points: Sequence[Vec2], close=False) -> str: + if len(points) < 2: + return "" + current = points[0] + # first move is absolute, consecutive lines are relative: + d: list[str] = [CMD_M_ABS.format(current), "l"] + for point in points[1:]: + relative = point - current + current = point + d.append(CMD_CONT.format(relative)) + if close: + d.append("Z") + return " ".join(d) + + @staticmethod + def make_multi_line_str(lines: Sequence[tuple[Vec2, Vec2]]) -> str: + assert len(lines) > 0 + start, end = lines[0] + d: list[str] = [CMD_M_ABS.format(start), CMD_L_REL.format(end - start)] + current = end + for start, end in lines[1:]: + d.append(CMD_M_REL.format(start - current)) + current = start + d.append(CMD_L_REL.format(end - current)) + current = end + return " ".join(d) + + @staticmethod + @no_type_check + def make_path_str(path: BkPath2d, close=False) -> str: + d: list[str] = [CMD_M_ABS.format(path.start)] + if len(path) == 0: + return "" + + current = path.start + for cmd in path.commands(): + end = cmd.end + if cmd.type == Command.MOVE_TO: + d.append(CMD_M_REL.format(end - current)) + elif cmd.type == Command.LINE_TO: + d.append(CMD_L_REL.format(end - current)) + elif cmd.type == Command.CURVE3_TO: + d.append(CMD_C3_REL.format(cmd.ctrl - current, end - current)) + elif cmd.type == Command.CURVE4_TO: + d.append( + CMD_C4_REL.format( + cmd.ctrl1 - current, cmd.ctrl2 - current, end - current + ) + ) + current = end + if close: + d.append("Z") + + return " ".join(d) + + def configure(self, config: Configuration) -> None: + self.lineweight_policy = config.lineweight_policy + if config.min_lineweight: + # config.min_lineweight in 1/300 inch! + min_lineweight_mm = config.min_lineweight * 25.4 / 300 + self.min_lineweight = max(0.05, min_lineweight_mm) + self.lineweight_scaling = config.lineweight_scaling + + def clear(self) -> None: + pass + + def finalize(self) -> None: + pass + + def enter_entity(self, entity, properties) -> None: + pass + + def exit_entity(self, entity) -> None: + pass + + +def alpha_to_opacity(alpha: str) -> float: + # stroke-opacity: 0.0 = transparent; 1.0 = opaque + # alpha: "00" = transparent; "ff" = opaque + if len(alpha): + try: + return int(alpha, 16) / 255 + except ValueError: + pass + return 1.0 + + +def map_lineweight_to_stroke_width( + lineweight: float, + min_stroke_width: int, + max_stroke_width: int, + min_lineweight=0.05, # defined by DXF + max_lineweight=2.11, # defined by DXF +) -> int: + """Map the DXF lineweight in mm to stroke-width in viewBox coordinates.""" + lineweight = max(min(lineweight, max_lineweight), min_lineweight) - min_lineweight + factor = (max_stroke_width - min_stroke_width) / (max_lineweight - min_lineweight) + return min_stroke_width + round(lineweight * factor) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text.py new file mode 100644 index 0000000..3bf57dd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text.py @@ -0,0 +1,351 @@ +# Copyright (c) 2020-2023, Matthew Broadway +# License: MIT License +from __future__ import annotations +from typing import Union, Tuple, Iterable, Optional, Callable +from typing_extensions import TypeAlias +import enum +from math import radians + +import ezdxf.lldxf.const as DXFConstants +from ezdxf.enums import ( + TextEntityAlignment, + MAP_TEXT_ENUM_TO_ALIGN_FLAGS, + MTextEntityAlignment, +) +from ezdxf.entities import MText, Text, Attrib, AttDef +from ezdxf.math import Matrix44, Vec3, sign +from ezdxf.fonts import fonts +from ezdxf.fonts.font_measurements import FontMeasurements +from ezdxf.tools.text import plain_text, text_wrap +from .text_renderer import TextRenderer + +""" +Search google for 'typography' or 'font anatomy' for explanations of terms like +'baseline' and 'x-height' + +A Visual Guide to the Anatomy of Typography: https://visme.co/blog/type-anatomy/ +Anatomy of a Character: https://www.fonts.com/content/learning/fontology/level-1/type-anatomy/anatomy +""" + + +@enum.unique +class HAlignment(enum.Enum): + LEFT = 0 + CENTER = 1 + RIGHT = 2 + + +@enum.unique +class VAlignment(enum.Enum): + TOP = 0 # the top of capital letters or letters with ascenders (like 'b') + LOWER_CASE_CENTER = 1 # the midpoint between the baseline and the x-height + BASELINE = 2 # the line which text rests on, characters with descenders (like 'p') are partially below this line + BOTTOM = 3 # the lowest point on a character with a descender (like 'p') + UPPER_CASE_CENTER = 4 # the midpoint between the baseline and the cap-height + + +Alignment: TypeAlias = Tuple[HAlignment, VAlignment] +AnyText: TypeAlias = Union[Text, MText, Attrib, AttDef] + +# multiple of cap_height between the baseline of the previous line and the +# baseline of the next line +DEFAULT_LINE_SPACING = 5 / 3 + +DXF_TEXT_ALIGNMENT_TO_ALIGNMENT: dict[TextEntityAlignment, Alignment] = { + TextEntityAlignment.LEFT: (HAlignment.LEFT, VAlignment.BASELINE), + TextEntityAlignment.CENTER: (HAlignment.CENTER, VAlignment.BASELINE), + TextEntityAlignment.RIGHT: (HAlignment.RIGHT, VAlignment.BASELINE), + TextEntityAlignment.ALIGNED: (HAlignment.CENTER, VAlignment.BASELINE), + TextEntityAlignment.MIDDLE: ( + HAlignment.CENTER, + VAlignment.LOWER_CASE_CENTER, + ), + TextEntityAlignment.FIT: (HAlignment.CENTER, VAlignment.BASELINE), + TextEntityAlignment.BOTTOM_LEFT: (HAlignment.LEFT, VAlignment.BOTTOM), + TextEntityAlignment.BOTTOM_CENTER: (HAlignment.CENTER, VAlignment.BOTTOM), + TextEntityAlignment.BOTTOM_RIGHT: (HAlignment.RIGHT, VAlignment.BOTTOM), + TextEntityAlignment.MIDDLE_LEFT: ( + HAlignment.LEFT, + VAlignment.UPPER_CASE_CENTER, + ), + TextEntityAlignment.MIDDLE_CENTER: ( + HAlignment.CENTER, + VAlignment.UPPER_CASE_CENTER, + ), + TextEntityAlignment.MIDDLE_RIGHT: ( + HAlignment.RIGHT, + VAlignment.UPPER_CASE_CENTER, + ), + TextEntityAlignment.TOP_LEFT: (HAlignment.LEFT, VAlignment.TOP), + TextEntityAlignment.TOP_CENTER: (HAlignment.CENTER, VAlignment.TOP), + TextEntityAlignment.TOP_RIGHT: (HAlignment.RIGHT, VAlignment.TOP), +} +assert DXF_TEXT_ALIGNMENT_TO_ALIGNMENT.keys() == MAP_TEXT_ENUM_TO_ALIGN_FLAGS.keys() + +DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT: dict[int, Alignment] = { + DXFConstants.MTEXT_TOP_LEFT: (HAlignment.LEFT, VAlignment.TOP), + DXFConstants.MTEXT_TOP_CENTER: (HAlignment.CENTER, VAlignment.TOP), + DXFConstants.MTEXT_TOP_RIGHT: (HAlignment.RIGHT, VAlignment.TOP), + DXFConstants.MTEXT_MIDDLE_LEFT: ( + HAlignment.LEFT, + VAlignment.LOWER_CASE_CENTER, + ), + DXFConstants.MTEXT_MIDDLE_CENTER: ( + HAlignment.CENTER, + VAlignment.LOWER_CASE_CENTER, + ), + DXFConstants.MTEXT_MIDDLE_RIGHT: ( + HAlignment.RIGHT, + VAlignment.LOWER_CASE_CENTER, + ), + DXFConstants.MTEXT_BOTTOM_LEFT: (HAlignment.LEFT, VAlignment.BOTTOM), + DXFConstants.MTEXT_BOTTOM_CENTER: (HAlignment.CENTER, VAlignment.BOTTOM), + DXFConstants.MTEXT_BOTTOM_RIGHT: (HAlignment.RIGHT, VAlignment.BOTTOM), +} +assert len(DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT) == len(MTextEntityAlignment) + + +def _calc_aligned_rotation(text: Text) -> float: + p1: Vec3 = text.dxf.insert + p2: Vec3 = text.dxf.align_point + if not p1.isclose(p2): + return (p2 - p1).angle + else: + return radians(text.dxf.rotation) + + +def _get_rotation(text: AnyText) -> Matrix44: + if isinstance(text, Text): # Attrib and AttDef are sub-classes of Text + if text.get_align_enum() in ( + TextEntityAlignment.FIT, + TextEntityAlignment.ALIGNED, + ): + rotation = _calc_aligned_rotation(text) + else: + rotation = radians(text.dxf.rotation) + return Matrix44.axis_rotate(text.dxf.extrusion, rotation) + elif isinstance(text, MText): + return Matrix44.axis_rotate(Vec3(0, 0, 1), radians(text.get_rotation())) + else: + raise TypeError(type(text)) + + +def _get_alignment(text: AnyText) -> Alignment: + if isinstance(text, Text): # Attrib and AttDef are sub-classes of Text + return DXF_TEXT_ALIGNMENT_TO_ALIGNMENT[text.get_align_enum()] + elif isinstance(text, MText): + return DXF_MTEXT_ALIGNMENT_TO_ALIGNMENT[text.dxf.attachment_point] + else: + raise TypeError(type(text)) + + +def _get_cap_height(text: AnyText) -> float: + if isinstance(text, (Text, Attrib, AttDef)): + return text.dxf.height + elif isinstance(text, MText): + return text.dxf.char_height + else: + raise TypeError(type(text)) + + +def _get_line_spacing(text: AnyText, cap_height: float) -> float: + if isinstance(text, (Attrib, AttDef, Text)): + return 0.0 + elif isinstance(text, MText): + return cap_height * DEFAULT_LINE_SPACING * text.dxf.line_spacing_factor + else: + raise TypeError(type(text)) + + +def _split_into_lines( + entity: AnyText, + box_width: Optional[float], + get_text_width: Callable[[str], float], +) -> list[str]: + if isinstance(entity, AttDef): + # ATTDEF outside of an Insert renders the tag rather than the value + text = plain_text(entity.dxf.tag) + else: + text = entity.plain_text() # type: ignore + if isinstance(entity, (Text, Attrib, AttDef)): + assert "\n" not in text + return [text] + else: + return text_wrap(text, box_width, get_text_width) + + +def _get_text_width(text: AnyText) -> Optional[float]: + if isinstance(text, Text): # Attrib and AttDef are sub-classes of Text + return None + elif isinstance(text, MText): + width = text.dxf.width + return None if width == 0.0 else width + else: + raise TypeError(type(text)) + + +def _get_extra_transform(text: AnyText, line_width: float) -> Matrix44: + extra_transform = Matrix44() + if isinstance(text, Text): # Attrib and AttDef are sub-classes of Text + # 'width' is the width *scale factor* so 1.0 by default: + scale_x = text.dxf.width + scale_y = 1.0 + + # Calculate text stretching for FIT and ALIGNED: + alignment = text.get_align_enum() + line_width = abs(line_width) + if ( + alignment in (TextEntityAlignment.FIT, TextEntityAlignment.ALIGNED) + and line_width > 1e-9 + ): + defined_length = (text.dxf.align_point - text.dxf.insert).magnitude + stretch_factor = defined_length / line_width + scale_x = stretch_factor + if alignment == TextEntityAlignment.ALIGNED: + scale_y = stretch_factor + + if text.dxf.text_generation_flag & DXFConstants.MIRROR_X: + scale_x *= -1.0 + if text.dxf.text_generation_flag & DXFConstants.MIRROR_Y: + scale_y *= -1.0 + + # Magnitude of extrusion does not have any effect. + # An extrusion of (0, 0, 0) acts like (0, 0, 1) + scale_x *= sign(text.dxf.extrusion.z) + + if scale_x != 1.0 or scale_y != 1.0: + extra_transform = Matrix44.scale(scale_x, scale_y) + + elif isinstance(text, MText): + # Not sure about the rationale behind this but it does match AutoCAD + # behavior... + scale_y = sign(text.dxf.extrusion.z) + if scale_y != 1.0: + extra_transform = Matrix44.scale(1.0, scale_y) + + return extra_transform + + +def _apply_alignment( + alignment: Alignment, + line_widths: list[float], + line_spacing: float, + box_width: Optional[float], + font_measurements: FontMeasurements, +) -> tuple[tuple[float, float], list[float], list[float]]: + if not line_widths: + return (0, 0), [], [] + + halign, valign = alignment + line_ys = [ + -font_measurements.baseline - (font_measurements.cap_height + i * line_spacing) + for i in range(len(line_widths)) + ] + + if box_width is None: + box_width = max(line_widths) + + last_baseline = line_ys[-1] + + if halign == HAlignment.LEFT: + anchor_x = 0.0 + line_xs = [0.0] * len(line_widths) + elif halign == HAlignment.CENTER: + anchor_x = box_width / 2 + line_xs = [anchor_x - w / 2 for w in line_widths] + elif halign == HAlignment.RIGHT: + anchor_x = box_width + line_xs = [anchor_x - w for w in line_widths] + else: + raise ValueError(halign) + + if valign == VAlignment.TOP: + anchor_y = 0.0 + elif valign == VAlignment.LOWER_CASE_CENTER: + first_line_lower_case_top = line_ys[0] + font_measurements.x_height + anchor_y = (first_line_lower_case_top + last_baseline) / 2 + elif valign == VAlignment.UPPER_CASE_CENTER: + first_line_upper_case_top = line_ys[0] + font_measurements.cap_height + anchor_y = (first_line_upper_case_top + last_baseline) / 2 + elif valign == VAlignment.BASELINE: + anchor_y = last_baseline + elif valign == VAlignment.BOTTOM: + anchor_y = last_baseline - font_measurements.descender_height + else: + raise ValueError(valign) + + return (anchor_x, anchor_y), line_xs, line_ys + + +def _get_wcs_insert(text: AnyText) -> Vec3: + if isinstance(text, Text): # Attrib and AttDef are sub-classes of Text + insert: Vec3 = text.dxf.insert + align_point: Vec3 = text.dxf.align_point + alignment: TextEntityAlignment = text.get_align_enum() + if alignment == TextEntityAlignment.LEFT: + # LEFT/BASELINE is always located at the insert point. + pass + elif alignment in ( + TextEntityAlignment.FIT, + TextEntityAlignment.ALIGNED, + ): + # Interpolate insertion location between insert and align point: + insert = insert.lerp(align_point, factor=0.5) + else: + # Everything else is located at the align point: + insert = align_point + return text.ocs().to_wcs(insert) + else: + return text.dxf.insert + + +# Simple but fast MTEXT renderer: +def simplified_text_chunks( + text: AnyText, + render_engine: TextRenderer, + *, + font_face: fonts.FontFace, +) -> Iterable[tuple[str, Matrix44, float]]: + """Splits a complex text entity into simple chunks of text which can all be + rendered the same way: + render the string (which will not contain any newlines) with the given + cap_height with (left, baseline) at (0, 0) then transform it with the given + matrix to move it into place. + """ + alignment = _get_alignment(text) + box_width = _get_text_width(text) + + cap_height = _get_cap_height(text) + lines = _split_into_lines( + text, + box_width, + lambda s: render_engine.get_text_line_width(s, font_face, cap_height), + ) + line_spacing = _get_line_spacing(text, cap_height) + line_widths = [ + render_engine.get_text_line_width(line, font_face, cap_height) for line in lines + ] + font_measurements = render_engine.get_font_measurements(font_face, cap_height) + anchor, line_xs, line_ys = _apply_alignment( + alignment, line_widths, line_spacing, box_width, font_measurements + ) + rotation = _get_rotation(text) + + # first_line_width is used for TEXT, ATTRIB and ATTDEF stretching + if line_widths: + first_line_width = line_widths[0] + else: # no text lines -> no output, value is not important + first_line_width = 1.0 + + extra_transform = _get_extra_transform(text, first_line_width) + insert = _get_wcs_insert(text) + + whole_text_transform = ( + Matrix44.translate(-anchor[0], -anchor[1], 0) + @ extra_transform + @ rotation + @ Matrix44.translate(*insert.xyz) + ) + for i, (line, line_x, line_y) in enumerate(zip(lines, line_xs, line_ys)): + transform = Matrix44.translate(line_x, line_y, 0) @ whole_text_transform + yield line, transform, cap_height diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text_renderer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text_renderer.py new file mode 100644 index 0000000..34e392c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/text_renderer.py @@ -0,0 +1,46 @@ +# Copyright (c) 2022-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TypeVar, TYPE_CHECKING +import abc +from ezdxf.fonts import fonts + +if TYPE_CHECKING: + from ezdxf.npshapes import NumpyPath2d + +T = TypeVar("T") + + +class TextRenderer(abc.ABC): + """Minimal requirement to be usable as a universal text renderer""" + + @abc.abstractmethod + def get_font_measurements( + self, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> fonts.FontMeasurements: + ... + + @abc.abstractmethod + def get_text_line_width( + self, + text: str, + font_face: fonts.FontFace, + cap_height: float = 1.0, + ) -> float: + ... + + @abc.abstractmethod + def get_text_path( + self, text: str, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> NumpyPath2d: + ... + + @abc.abstractmethod + def get_text_glyph_paths( + self, text: str, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> list[NumpyPath2d]: + ... + + @abc.abstractmethod + def is_stroke_font(self, font_face: fonts.FontFace) -> bool: + ... diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/type_hints.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/type_hints.py new file mode 100644 index 0000000..f9cb37e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/type_hints.py @@ -0,0 +1,10 @@ +# Copyright (c) 2020-2022, Matthew Broadway +# License: MIT License +from typing import Callable +from typing_extensions import TypeAlias +from ezdxf.entities import DXFGraphic + +LayerName: TypeAlias = str +Color: TypeAlias = str +Radians: TypeAlias = float +FilterFunc: TypeAlias = Callable[[DXFGraphic], bool] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/unified_text_renderer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/unified_text_renderer.py new file mode 100644 index 0000000..55b9ca6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/drawing/unified_text_renderer.py @@ -0,0 +1,72 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING +from ezdxf.fonts import fonts +from ezdxf.fonts.font_measurements import FontMeasurements + +from .text_renderer import TextRenderer + +if TYPE_CHECKING: + from ezdxf.npshapes import NumpyPath2d + + +class UnifiedTextRenderer(TextRenderer): + """This text renderer supports .ttf, .ttc, .otf, .shx, .shp and .lff fonts. + + The resolving order for .shx fonts is applied in the RenderContext.add_text_style() + method. + + """ + + def __init__(self) -> None: + self._font_cache: dict[str, fonts.AbstractFont] = dict() + + def get_font(self, font_face: fonts.FontFace) -> fonts.AbstractFont: + if not font_face.filename and font_face.family: + found = fonts.find_best_match( + family=font_face.family, + weight=700 if font_face.is_bold else 400, + italic=font_face.is_italic, + ) + if found is not None: + font_face = found + key = font_face.filename.lower() + try: + return self._font_cache[key] + except KeyError: + pass + abstract_font = fonts.make_font(font_face.filename, 1.0) + self._font_cache[key] = abstract_font + return abstract_font + + def is_stroke_font(self, font_face: fonts.FontFace) -> bool: + abstract_font = self.get_font(font_face) + return abstract_font.font_render_type == fonts.FontRenderType.STROKE + + def get_font_measurements( + self, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> FontMeasurements: + abstract_font = self.get_font(font_face) + return abstract_font.measurements.scale(cap_height) + + def get_text_path( + self, text: str, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> NumpyPath2d: + abstract_font = self.get_font(font_face) + return abstract_font.text_path_ex(text, cap_height) + + def get_text_glyph_paths( + self, text: str, font_face: fonts.FontFace, cap_height: float = 1.0 + ) -> list[NumpyPath2d]: + abstract_font = self.get_font(font_face) + return abstract_font.text_glyph_paths(text, cap_height) + + def get_text_line_width( + self, + text: str, + font_face: fonts.FontFace, + cap_height: float = 1.0, + ) -> float: + abstract_font = self.get_font(font_face) + return abstract_font.text_width_ex(text, cap_height) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__init__.py new file mode 100644 index 0000000..9cc9c79 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License + +from .loader import load, readfile +from .fileheader import FileHeader diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4c9671f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/classes_section.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/classes_section.cpython-312.pyc new file mode 100644 index 0000000..645f8b3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/classes_section.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/const.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/const.cpython-312.pyc new file mode 100644 index 0000000..f5891ac Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/const.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/crc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/crc.cpython-312.pyc new file mode 100644 index 0000000..3e7feff Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/crc.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/fileheader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/fileheader.cpython-312.pyc new file mode 100644 index 0000000..41c4728 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/fileheader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/header_section.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/header_section.cpython-312.pyc new file mode 100644 index 0000000..6627449 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/header_section.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/loader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/loader.cpython-312.pyc new file mode 100644 index 0000000..1495e84 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/__pycache__/loader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/classes_section.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/classes_section.py new file mode 100644 index 0000000..3f11467 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/classes_section.py @@ -0,0 +1,82 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License +from typing import Iterable, Tuple +import struct + +from ezdxf.tools.binarydata import BitStream +from ezdxf.entities import DXFClass + +from .const import * +from .crc import crc8 +from .fileheader import FileHeader +from .header_section import DwgSectionLoader + + +def load_classes_section(specs: FileHeader, data: Bytes, crc_check=False): + if specs.version <= ACAD_2000: + return DwgClassesSectionR2000(specs, data, crc_check) + else: + return DwgClassesSectionR2004(specs, data, crc_check) + + +class DwgClassesSectionR2000(DwgSectionLoader): + def load_data_section(self, data: Bytes) -> Bytes: + if self.specs.version > ACAD_2000: + raise DwgVersionError(self.specs.version) + seeker, section_size = self.specs.sections[CLASSES_ID] + return data[seeker : seeker + section_size] + + def load_classes(self) -> Iterable[Tuple[int, DXFClass]]: + sentinel = self.data[:SENTINEL_SIZE] + if ( + sentinel + != b"\x8D\xA1\xC4\xB8\xC4\xA9\xF8\xC5\xC0\xDC\xF4\x5F\xE7\xCF\xB6\x8A" + ): + raise DwgCorruptedClassesSection( + "Sentinel for start of CLASSES section not found." + ) + start_index = SENTINEL_SIZE + bs = BitStream( + self.data[start_index:], + dxfversion=self.specs.version, + encoding=self.specs.encoding, + ) + class_data_size = bs.read_unsigned_long() # data size in bytes + end_sentinel_index = SENTINEL_SIZE + 6 + class_data_size + end_index = end_sentinel_index - 2 + end_bit_index = (3 + class_data_size) << 3 + + while bs.bit_index < end_bit_index: + class_num = bs.read_bit_short() + dxfattribs = { + "flags": bs.read_bit_short(), # version? + "app_name": bs.read_text(), + "cpp_class_name": bs.read_text(), + "name": bs.read_text(), + "was_a_proxy": bs.read_bit(), + "is_an_entity": int(bs.read_bit_short() == 0x1F2), + } + yield class_num, DXFClass.new(dxfattribs=dxfattribs) + + if self.crc_check and False: + check = struct.unpack_from(" Bytes: + raise NotImplementedError() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/const.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/const.py new file mode 100644 index 0000000..9cef533 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/const.py @@ -0,0 +1,45 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License +from typing import Union + +ACAD_13 = "AC1012" +ACAD_14 = "AC1014" +ACAD_2000 = "AC1015" +ACAD_2004 = "AC1018" +ACAD_2007 = "AC1021" +ACAD_2010 = "AC1024" +ACAD_2013 = "AC1027" +ACAD_2018 = "AC1032" +ACAD_LATEST = ACAD_2018 + +SUPPORTED_VERSIONS = [ACAD_13, ACAD_14, ACAD_2000] +HEADER_ID = 0 +CLASSES_ID = 1 +OBJECTS_ID = 2 +SENTINEL_SIZE = 16 + +Bytes = Union[bytes, bytearray, memoryview] + + +class DwgError(Exception): + pass + + +class DwgVersionError(DwgError): + pass + + +class DwgCorruptedFileHeader(DwgError): + pass + + +class DwgCorruptedClassesSection(DwgError): + pass + + +class DwgCorruptedHeaderSection(DwgError): + pass + + +class CRCError(DwgError): + pass diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/crc.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/crc.py new file mode 100644 index 0000000..467f069 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/crc.py @@ -0,0 +1,83 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License + +__all__ = ["crc8", "crc32"] + +from .const import Bytes + + +def crc8(data: Bytes, seed: int = 0) -> int: + for byte in data: + index = byte ^ (seed & 0xFF) + seed = (seed >> 8) & 0xFF + seed ^= CRC8_TABLE[index & 0xFF] + return seed + + +def crc32(data: Bytes, seed: int = 0) -> int: + inverted_crc = ~seed + for byte in data: + inverted_crc = (inverted_crc >> 8) ^ CRC32_TABLE[ + (inverted_crc ^ byte) & 0xFF + ] + return ~inverted_crc + + +# fmt: off +# Source: Open Design Specification for .dwg +CRC8_TABLE = [ + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, + 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, + 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, + 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, + 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, + 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, + 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, + 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, + 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, + 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, + 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, + 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, + 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, + 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, + 0x4100, 0x81C1, 0x8081, 0x4040, +] + +# Source: Open Design Specification for .dwg +CRC32_TABLE = [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, + 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, + 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, + 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, + 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, + 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, + 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, + 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, + 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, + 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +] + +# fmt: on diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/fileheader.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/fileheader.py new file mode 100644 index 0000000..6d51350 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/fileheader.py @@ -0,0 +1,92 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License +from typing import Dict, Tuple +import struct +from .const import * +from .crc import crc8 + +codepage_to_encoding = { + 37: "cp874", # Thai, + 38: "cp932", # Japanese + 39: "gbk", # UnifiedChinese + 40: "cp949", # Korean + 41: "cp950", # TradChinese + 28: "cp1250", # CentralEurope + 29: "cp1251", # Cyrillic + 30: "cp1252", # WesternEurope + 32: "cp1253", # Greek + 33: "cp1254", # Turkish + 34: "cp1255", # Hebrew + 35: "cp1256", # Arabic + 36: "cp1257", # Baltic +} + +FILE_HEADER_MAGIC = { + 3: 0xA598, + 4: 0x8101, + 5: 0x3CC4, + 6: 0x8461, +} + + +class FileHeader: + def __init__(self, data: Bytes, crc_check=False): + self.crc_check = crc_check + if len(data) < 6: + raise DwgVersionError("Not a DWG file.") + ver = data[:6].decode(errors="ignore") # type: ignore + if ver not in SUPPORTED_VERSIONS: + raise DwgVersionError( + f"Not a DWG file or unsupported DWG version, signature: {ver}." + ) + self.version: str = ver + codepage: int = struct.unpack_from(" Bytes: + ... + + +class DwgHeaderSectionR2000(DwgSectionLoader): + def load_data_section(self, data: Bytes) -> Bytes: + if self.specs.version > ACAD_2000: + raise DwgVersionError(self.specs.version) + seeker, section_size = self.specs.sections[HEADER_ID] + return data[seeker : seeker + section_size] + + def load_header_vars(self) -> Dict: + data = self.data + sentinel = data[:16] + if ( + sentinel + != b"\xCF\x7B\x1F\x23\xFD\xDE\x38\xA9\x5F\x7C\x68\xB8\x4E\x6D\x33\x5F" + ): + raise DwgCorruptedHeaderSection( + "Sentinel for start of HEADER section not found." + ) + index = 16 + size = struct.unpack_from(" Bytes: + raise NotImplementedError() + + +CMD_SET_VERSION = "ver" +CMD_SKIP_BITS = "skip_bits" +CMD_SKIP_NEXT_IF = "skip_next_if" +CMD_SET_VAR = "var" + + +def _min_max_versions(version: str) -> Tuple[str, str]: + min_ver = ACAD_13 + max_ver = ACAD_LATEST + if version != "all": + v = version.split("-") + if len(v) > 1: + min_ver = acad_release_to_dxf_version[v[0].strip()] + max_ver = acad_release_to_dxf_version[v[1].strip()] + else: + v_str: str = v[0].strip() + if v_str[-1] == "+": + min_ver = acad_release_to_dxf_version[v_str[:-1]] + else: + min_ver = max_ver = acad_release_to_dxf_version[v_str] + return min_ver, max_ver + + +def load_commands(desc: str) -> List[Tuple[str, Any]]: + commands = [] + lines = desc.split("\n") + for line in lines: + line = line.strip() + if not line or line[0] == "#": + continue + try: + command, param = line.split(":") + except ValueError: + raise ValueError(f"Unpack Error in line: {line}") + command = command.strip() + param = param.split("#")[0].strip() + if command == CMD_SET_VERSION: + commands.append((CMD_SET_VERSION, _min_max_versions(param))) + elif command in {CMD_SKIP_BITS, CMD_SKIP_NEXT_IF}: + commands.append((command, param)) # type: ignore + elif command[0] == "$": + commands.append((CMD_SET_VAR, (command, param))) + else: + raise ValueError(f"Unknown command: {command}") + return commands + + +def parse_bitstream( + bs: BitStream, commands: List[Tuple[str, Any]] +) -> Dict[str, Any]: + version = bs.dxfversion + min_ver = ACAD_13 + max_ver = ACAD_LATEST + hdr_vars: Dict[str, Any] = dict() + skip_next_cmd = False + for cmd, params in commands: + if skip_next_cmd: + skip_next_cmd = False + continue + + if cmd == CMD_SET_VERSION: + min_ver, max_ver = params + elif cmd == CMD_SKIP_BITS: + bs.skip(int(params)) + elif cmd == CMD_SKIP_NEXT_IF: + skip_next_cmd = eval(params, None, {"header": hdr_vars}) + elif cmd == CMD_SET_VAR: + if min_ver <= version <= max_ver: + name, code = params + hdr_vars[name] = bs.read_code(code) + else: + raise ValueError(f"Unknown command: {cmd}") + return hdr_vars + + +def parse_header(bs: BitStream) -> Dict[str, Any]: + commands = load_commands(HEADER_DESCRIPTION) + return parse_bitstream(bs, commands) + + +HEADER_DESCRIPTION = """ +ver: R2007 +$SIZE_IN_BITS: RL # Size in bits + +ver: R2013+ +$REQUIREDVERSIONS: BLL # default value 0, read only + +ver: all +$UNKNOWN: BD # Unknown, default value 412148564080.0 +$UNKNOWN: BD # Unknown, default value 1.0 +$UNKNOWN: BD # Unknown, default value 1.0 +$UNKNOWN: BD # Unknown, default value 1.0 +$UNKNOWN: TV # Unknown text string, default "" +$UNKNOWN: TV # Unknown text string, default "" +$UNKNOWN: TV # Unknown text string, default "" +$UNKNOWN: TV # Unknown text string, default "" +$UNKNOWN: BL # Unknown long, default value 24L +$UNKNOWN: BL # Unknown long, default value 0L; + +ver: R13-R14 +$UNKNOWN: BS # Unknown short, default value 0 + +ver: R13-R2000 +$CURRENT_VIEWPORT_ENTITY_HEADER: H # Handle of the current viewport entity header (hard pointer) + +ver: all +$DIMASO: B +$DIMSHO: B + +ver: R13-R14 +$DIMSAV: B # Undocumented + +ver: all +$PLINEGEN: B +$ORTHOMODE: B +$REGENMODE: B +$FILLMODE: B +$QTEXTMODE: B +$PSLTSCALE: B +$LIMCHECK: B + +ver: R13-R14 +$BLIPMODE: B + +ver: R2004+ +$UNKNOWN: B # Undocumented + +ver: all +$USRTIMER: B # (User timer on/off) +$SKPOLY: B +$ANGDIR: B +$SPLFRAME: B + +ver: R13-R14 +$ATTREQ: B +$ATTDIA: B + +ver: all +$MIRRTEXT: B +$WORLDVIEW: B + +ver: R13-R14 +$WIREFRAME: B # Undocumented. + +ver: all +$TILEMODE: B +$PLIMCHECK: B +$VISRETAIN: B + +ver: R13-R14 +$DELOBJ: B + +ver: all +$DISPSILH: B +$PELLIPSE: B # (not present in DXF) +$PROXYGRAPHICS: BS + +ver: R13-R14 +$DRAGMODE: BS + +ver: all +$TREEDEPTH: BS +$LUNITS: BS +$LUPREC: BS +$AUNITS: BS +$AUPREC: BS + +ver: R13-R14 +$OSMODE: BS + +ver: all +$ATTMODE: BS + +ver: R13-R14 +$COORDS: BS + +ver: all +$PDMODE: BS + +ver: R13-R14 +$PICKSTYLE: BS + +ver: R2004+ +$UNKNOWN: BL +$UNKNOWN: BL +$UNKNOWN: BL + +ver: all +$USERI1: BS +$USERI2: BS +$USERI3: BS +$USERI4: BS +$USERI5: BS +$SPLINESEGS: BS +$SURFU: BS +$SURFV: BS +$SURFTYPE: BS +$SURFTAB1: BS +$SURFTAB2: BS +$SPLINETYPE: BS +$SHADEDGE: BS +$SHADEDIF: BS +$UNITMODE: BS +$MAXACTVP: BS +$ISOLINES: BS +$CMLJUST: BS +$TEXTQLTY: BS +$LTSCALE: BD +$TEXTSIZE: BD +$TRACEWID: BD +$SKETCHINC: BD +$FILLETRAD: BD +$THICKNESS: BD +$ANGBASE: BD +$PDSIZE: BD +$PLINEWID: BD +$USERR1: BD +$USERR2: BD +$USERR3: BD +$USERR4: BD +$USERR5: BD +$CHAMFERA: BD +$CHAMFERB: BD +$CHAMFERC: BD +$CHAMFERD: BD +$FACETRES: BD +$CMLSCALE: BD +$CELTSCALE: BD + +ver: R13-R2004 +$MENUNAME: TV + +ver: all +$TDCREATE: BL # (Julian day) +$TDCREATE: BL # (Milliseconds into the day) +$TDUPDATE: BL # (Julian day) +$TDUPDATE: BL # (Milliseconds into the day) + +ver: R2004+ +$UNKNOWN: BL +$UNKNOWN: BL +$UNKNOWN: BL + +ver: all +$TDINDWG: BL # (Days) +$TDINDWG: BL # (Milliseconds into the day) +$TDUSRTIMER: BL # (Days) +$TDUSRTIMER: BL # (Milliseconds into the day) +$CECOLOR: CMC + +# with an 8-bit length specifier preceding the handle bytes (standard hex handle form) (code 0). +# The HANDSEED is not part of the handle stream, but of the normal data stream (relevant for R21 and later). + +$HANDSEED: H # The next handle +$CLAYER: H # (hard pointer) +$TEXTSTYLE: H # (hard pointer) +$CELTYPE: H # (hard pointer) + +ver: R2007+ +$CMATERIAL: H # (hard pointer) + +ver: all +$DIMSTYLE: H # (hard pointer) +$CMLSTYLE: H # (hard pointer) + +ver: R2000+ +$PSVPSCALE: BD + +ver: all +$PINSBASE: 3BD # (PSPACE) +$PEXTMIN: 3BD # (PSPACE) +$PEXTMAX: 3BD # (PSPACE) +$PLIMMIN: 2RD # (PSPACE) +$PLIMMAX: 2RD # (PSPACE) +$PELEVATION: BD # (PSPACE) +$PUCSORG: 3BD # (PSPACE) +$PUCSXDIR: 3BD # (PSPACE) +$PUCSYDIR: 3BD # (PSPACE) +$PUCSNAME: H # (PSPACE) (hard pointer) + +ver: R2000+ +$PUCSORTHOREF: H # (hard pointer) +$PUCSORTHOVIEW: BS +$PUCSBASE: H # (hard pointer) +$PUCSORGTOP: 3BD +$PUCSORGBOTTOM: 3BD +$PUCSORGLEFT: 3BD +$PUCSORGRIGHT: 3BD +$PUCSORGFRONT: 3BD +$PUCSORGBACK: 3BD + +ver: all +$INSBASE: 3BD # (MSPACE) +$EXTMIN: 3BD # (MSPACE) +$EXTMAX: 3BD # (MSPACE) +$LIMMIN: 2RD # (MSPACE) +$LIMMAX: 2RD # (MSPACE) +$ELEVATION: BD # (MSPACE) +$UCSORG: 3BD # (MSPACE) +$UCSXDIR: 3BD # (MSPACE) +$UCSYDIR: 3BD # (MSPACE) +$UCSNAME: H # (MSPACE) (hard pointer) + +ver: R2000+ +$UCSORTHOREF: H # (hard pointer) +$UCSORTHOVIEW: BS +$UCSBASE: H # (hard pointer) +$UCSORGTOP: 3BD +$UCSORGBOTTOM: 3BD +$UCSORGLEFT: 3BD +$UCSORGRIGHT: 3BD +$UCSORGFRONT: 3BD +$UCSORGBACK: 3BD +$DIMPOST: TV +$DIMAPOST: TV + +ver: R13-R14 +$DIMTOL: B +$DIMLIM: B +$DIMTIH: B +$DIMTOH: B +$DIMSE1: B +$DIMSE2: B +$DIMALT: B +$DIMTOFL: B +$DIMSAH: B +$DIMTIX: B +$DIMSOXD: B +$DIMALTD: RC +$DIMZIN: RC +$DIMSD1: B +$DIMSD2: B +$DIMTOLJ: RC +$DIMJUST: RC +$DIMFIT: RC +$DIMUPT: B +$DIMTZIN: RC +$DIMALTZ: RC +$DIMALTTZ: RC +$DIMTAD: RC +$DIMUNIT: BS +$DIMAUNIT: BS +$DIMDEC: BS +$DIMTDEC: BS +$DIMALTU: BS +$DIMALTTD: BS +$DIMTXSTY: H # (hard pointer) + +ver: all +$DIMSCALE: BD +$DIMASZ: BD +$DIMEXO: BD +$DIMDLI: BD +$DIMEXE: BD +$DIMRND: BD +$DIMDLE: BD +$DIMTP: BD +$DIMTM: BD + +ver: R2007+ +$DIMFXL: BD +$DIMJOGANG: BD +$DIMTFILL: BS +$DIMTFILLCLR: CMC + +ver: R2000+ +$DIMTOL: B +$DIMLIM: B +$DIMTIH: B +$DIMTOH: B +$DIMSE1: B +$DIMSE2: B +$DIMTAD: BS +$DIMZIN: BS +$DIMAZIN: BS + +ver: R2007+ +$DIMARCSYM: BS + +ver: all +$DIMTXT: BD +$DIMCEN: BD +$DIMTSZ: BD +$DIMALTF: BD +$DIMLFAC: BD +$DIMTVP: BD +$DIMTFAC: BD +$DIMGAP: BD + +ver: R13-R14 +$DIMPOST: T +$DIMAPOST: T +$DIMBLK: T +$DIMBLK1: T +$DIMBLK2: T + +ver: R2000+ +$DIMALTRND: BD +$DIMALT: B +$DIMALTD: BS +$DIMTOFL: B +$DIMSAH: B +$DIMTIX: B +$DIMSOXD: B + +ver: all +$DIMCLRD: CMC +$DIMCLRE: CMC +$DIMCLRT: CMC + +ver: R2000+ +$DIMADEC: BS +$DIMDEC: BS +$DIMTDEC: BS +$DIMALTU: BS +$DIMALTTD: BS +$DIMAUNIT: BS +$DIMFRAC: BS +$DIMLUNIT: BS +$DIMDSEP: BS +$DIMTMOVE: BS +$DIMJUST: BS +$DIMSD1: B +$DIMSD2: B +$DIMTOLJ: BS +$DIMTZIN: BS +$DIMALTZ: BS +$DIMALTTZ: BS +$DIMUPT: B +$DIMATFIT: BS + +ver: R2007+ +$DIMFXLON: B + +ver: R2010+ +$DIMTXTDIRECTION: B +$DIMALTMZF: BD +$DIMALTMZS: T +$DIMMZF: BD +$DIMMZS: T + +ver: R2000+ +$DIMTXSTY: H # (hard pointer) +$DIMLDRBLK: H # (hard pointer) +$DIMBLK: H # (hard pointer) +$DIMBLK1: H # (hard pointer) +$DIMBLK2: H # (hard pointer) + +ver: R2007+ +$DIMLTYPE: H # (hard pointer) +$DIMLTEX1: H # (hard pointer) +$DIMLTEX2: H # (hard pointer) + +ver: R2000+ +$DIMLWD: BS +$DIMLWE: BS + +ver: all +$BLOCK_CONTROL_OBJECT: H # (hard owner) Block Record Table +$LAYER_CONTROL_OBJECT: H # (hard owner) Layer Table +$STYLE_CONTROL_OBJECT: H # (hard owner) Style Table +$LINETYPE_CONTROL_OBJECT: H # (hard owner) Linetype Table +$VIEW_CONTROL_OBJECT: H # (hard owner) View table +$UCS_CONTROL_OBJECT: H # (hard owner) UCS Table +$VPORT_CONTROL_OBJECT: H # (hard owner) Viewport table +$APPID_CONTROL_OBJECT: H # (hard owner) AppID Table +$DIMSTYLE_CONTROL_OBJECT: H # (hard owner) Dimstyle Table + +ver: R13-R2000 +$VIEWPORT_ENTITY_HEADER_CONTROL_OBJECT: H # (hard owner) + +ver: all +$ACAD_GROUP_DICTIONARY: H # (hard pointer) +$ACAD_MLINESTYLE_DICTIONARY: H # (hard pointer) +$ROOT_DICTIONARY: H # (NAMED OBJECTS) (hard owner) + +ver: R2000+ +$TSTACKALIGN: BS # default = 1 (not present in DXF) +$TSTACKSIZE: BS # default = 70 (not present in DXF) +$HYPERLINKBASE: TV +$STYLESHEET: TV +$LAYOUTS_DICTIONARY: H # (hard pointer) +$PLOTSETTINGS_DICTIONARY: H # (hard pointer) +$PLOTSTYLES_DICTIONARY: H # (hard pointer) + +ver: R2004+ +$MATERIALS_DICTIONARY: H # (hard pointer) +$COLORS_DICTIONARY: H # (hard pointer) + +ver: R2007+ +$VISUALSTYLE_DICTIONARY: H # (hard pointer) + +ver: R2013+ +$UNKNOWN: H # (hard pointer) + +ver: R2000+ +$R2000_PLUS_FLAGS: BL +# CELWEIGHT Flags & 0x001F +# ENDCAPS Flags & 0x0060 +# JOINSTYLE Flags & 0x0180 +# LWDISPLAY !(Flags & 0x0200) +# XEDIT !(Flags & 0x0400) +# EXTNAMES Flags & 0x0800 +# PSTYLEMODE Flags & 0x2000 +# OLESTARTUP Flags & 0x4000 +$INSUNITS: BS +$CEPSNTYPE: BS + +skip_next_if: header['$CEPSNTYPE'] != 3 +$CPSNID: H # (present only if CEPSNTYPE == 3) (hard pointer) + +$FINGERPRINTGUID: TV +$VERSIONGUID: TV + +ver: R2004+ +$SORTENTS: RC +$INDEXCTL: RC +$HIDETEXT: RC +$XCLIPFRAME: RC # before R2010 the value can be 0 or 1 only. +$DIMASSOC: RC +$HALOGAP: RC +$OBSCUREDCOLOR: BS +$INTERSECTIONCOLOR: BS +$OBSCUREDLTYPE: RC +$INTERSECTIONDISPLAY: RC +$PROJECTNAME: TV + +ver: all +$PAPER_SPACE_BLOCK_RECORD: H # (hard pointer) +$MODEL_SPACE_BLOCK_RECORD: H # (hard pointer) +$BYLAYER_LTYPE: H # (hard pointer) +$BYBLOCK_LTYPE: H # (hard pointer) +$CONTINUOUS_LTYPE: H # (hard pointer) + +ver: R2007+ +$CAMERADISPLAY: B +$UNKNOWN: BL +$UNKNOWN: BL +$UNKNOWN: BD +$STEPSPERSEC: BD +$STEPSIZE: BD +$3DDWFPREC: BD +$LENSLENGTH: BD +$CAMERAHEIGHT: BD +$SOLIDHIST: RC +$SHOWHIST: RC +$PSOLWIDTH: BD +$PSOLHEIGHT: BD +$LOFTANG1: BD +$LOFTANG2: BD +$LOFTMAG1: BD +$LOFTMAG2: BD +$LOFTPARAM: BS +$LOFTNORMALS: RC +$LATITUDE: BD +$LONGITUDE: BD +$NORTHDIRECTION: BD +$TIMEZONE: BL +$LIGHTGLYPHDISPLAY: RC +$TILEMODELIGHTSYNCH: RC +$DWFFRAME: RC +$DGNFRAME: RC +$UNKNOWN: B +$INTERFERECOLOR: CMC +$INTERFEREOBJVS: H # (hard pointer) +$INTERFEREVPVS: H # (hard pointer) +$CSHADOW: RC +$UNKNOWN: BD + +ver: R14+ +$UNKNOWN: BS # short (type 5/6 only) these do not seem to be required, +$UNKNOWN: BS # short (type 5/6 only) even for type 5. +$UNKNOWN: BS # short (type 5/6 only) +$UNKNOWN: BS # short (type 5/6 only) + +""" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/loader.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/loader.py new file mode 100644 index 0000000..a198fa0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dwg/loader.py @@ -0,0 +1,88 @@ +# Copyright (c) 2020-2021, Manfred Moitzi +# License: MIT License +from typing import Dict + +from ezdxf.document import Drawing +from ezdxf.tools import codepage + +from ezdxf.sections.header import HeaderSection +from ezdxf.sections.classes import ClassesSection +from ezdxf.sections.tables import TablesSection +from ezdxf.sections.blocks import BlocksSection +from ezdxf.sections.entities import EntitySection +from ezdxf.sections.objects import ObjectsSection +from ezdxf.sections.acdsdata import AcDsDataSection + +from .const import * +from .fileheader import FileHeader +from .header_section import load_header_section +from .classes_section import load_classes_section + +__all__ = ["readfile", "load"] + + +def readfile(filename: str, crc_check=False) -> "Drawing": + data = open(filename, "rb").read() + return load(data, crc_check) + + +def load(data: bytes, crc_check=False) -> Drawing: + doc = DwgDocument(data, crc_check=crc_check) + doc.load() + return doc.doc + + +class DwgDocument: + def __init__(self, data: Bytes, crc_check=False): + self.data = memoryview(data) + self.crc_check = crc_check + self.specs = FileHeader(data, crc_check=crc_check) + self.doc: Drawing = self._setup_doc() + # Store DXF object types by class number: + self.dxf_object_types: Dict[int, str] = dict() + + def _setup_doc(self) -> Drawing: + doc = Drawing(dxfversion=self.specs.version) + doc.encoding = self.specs.encoding + doc.header = HeaderSection.new() + + # Setup basic header variables not stored in the header section of the DWG file. + doc.header["$ACADVER"] = self.specs.version + doc.header["$ACADMAINTVER"] = self.specs.maintenance_release_version + doc.header["$DWGCODEPAGE"] = codepage.tocodepage(self.specs.encoding) + + doc.classes = ClassesSection(doc) + # doc.tables = TablesSection(doc) + # doc.blocks = BlocksSection(doc) + # doc.entities = EntitySection(doc) + # doc.objects = ObjectsSection(doc) + # doc.acdsdata = AcDsDataSection(doc) + return doc + + def load(self): + self.load_header() + self.load_classes() + self.load_objects() + self.store_objects() + + def load_header(self) -> None: + hdr_section = load_header_section(self.specs, self.data, self.crc_check) + hdr_vars = hdr_section.load_header_vars() + self.set_header_vars(hdr_vars) + + def set_header_vars(self, hdr_vars: Dict): + pass + + def load_classes(self) -> None: + cls_section = load_classes_section( + self.specs, self.data, self.crc_check + ) + for class_num, dxfclass in cls_section.load_classes(): + self.doc.classes.register(dxfclass) + self.dxf_object_types[class_num] = dxfclass.dxf.name + + def load_objects(self) -> None: + pass + + def store_objects(self) -> None: + pass diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/dxf2code.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/dxf2code.py new file mode 100644 index 0000000..0188254 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/dxf2code.py @@ -0,0 +1,904 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Mapping, Optional +import json + +from ezdxf.sections.tables import TABLENAMES +from ezdxf.lldxf.tags import Tags +from ezdxf.entities import BoundaryPathType, EdgeType +import numpy as np + +if TYPE_CHECKING: + from ezdxf.lldxf.types import DXFTag + from ezdxf.entities import ( + Insert, + MText, + LWPolyline, + Polyline, + Spline, + Leader, + Dimension, + Image, + Mesh, + Hatch, + MPolygon, + Wipeout, + ) + from ezdxf.entities import DXFEntity, Linetype + from ezdxf.entities.polygon import DXFPolygon + from ezdxf.layouts import BlockLayout + +__all__ = [ + "entities_to_code", + "block_to_code", + "table_entries_to_code", + "black", +] + + +def black(code: str, line_length=88, fast: bool = True) -> str: + """Returns the source `code` as a single string formatted by `Black`_ + + Requires the installed `Black`_ formatter:: + + pip3 install black + + Args: + code: source code + line_length: max. source code line length + fast: ``True`` for fast mode, ``False`` to check that the reformatted + code is valid + + Raises: + ImportError: Black is not available + + .. _black: https://pypi.org/project/black/ + + """ + + import black + + mode = black.FileMode() + mode.line_length = line_length + return black.format_file_contents(code, fast=fast, mode=mode) + + +def entities_to_code( + entities: Iterable[DXFEntity], + layout: str = "layout", + ignore: Optional[Iterable[str]] = None, +) -> Code: + """ + Translates DXF entities into Python source code to recreate this entities + by ezdxf. + + Args: + entities: iterable of DXFEntity + layout: variable name of the layout (model space or block) as string + ignore: iterable of entities types to ignore as strings + like ``['IMAGE', 'DIMENSION']`` + + Returns: + :class:`Code` + + """ + code = _SourceCodeGenerator(layout=layout) + code.translate_entities(entities, ignore=ignore) + return code.code + + +def block_to_code( + block: BlockLayout, + drawing: str = "doc", + ignore: Optional[Iterable[str]] = None, +) -> Code: + """ + Translates a BLOCK into Python source code to recreate the BLOCK by ezdxf. + + Args: + block: block definition layout + drawing: variable name of the drawing as string + ignore: iterable of entities types to ignore as strings + like ['IMAGE', 'DIMENSION'] + + Returns: + :class:`Code` + + """ + assert block.block is not None + dxfattribs = _purge_handles(block.block.dxfattribs()) + block_name = dxfattribs.pop("name") + base_point = dxfattribs.pop("base_point") + code = _SourceCodeGenerator(layout="b") + prolog = f'b = {drawing}.blocks.new("{block_name}", base_point={base_point}, dxfattribs={{' + code.add_source_code_line(prolog) + code.add_source_code_lines(_fmt_mapping(dxfattribs, indent=4)) + code.add_source_code_line(" }") + code.add_source_code_line(")") + code.translate_entities(block, ignore=ignore) + return code.code + + +def table_entries_to_code( + entities: Iterable[DXFEntity], drawing="doc" +) -> Code: + code = _SourceCodeGenerator(doc=drawing) + code.translate_entities(entities) + return code.code + + +class Code: + """Source code container.""" + + def __init__(self) -> None: + self.code: list[str] = [] + # global imports -> indentation level 0: + self.imports: set[str] = set() + # layer names as string: + self.layers: set[str] = set() + # text style name as string, requires a TABLE entry: + self.styles: set[str] = set() + # line type names as string, requires a TABLE entry: + self.linetypes: set[str] = set() + # dimension style names as string, requires a TABLE entry: + self.dimstyles: set[str] = set() + # block names as string, requires a BLOCK definition: + self.blocks: set[str] = set() + + def code_str(self, indent: int = 0) -> str: + """Returns the source code as a single string. + + Args: + indent: source code indentation count by spaces + + """ + lead_str = " " * indent + return "\n".join(lead_str + line for line in self.code) + + def black_code_str(self, line_length=88) -> str: + """Returns the source code as a single string formatted by `Black`_ + + Args: + line_length: max. source code line length + + Raises: + ImportError: Black is not available + + """ + return black(self.code_str(), line_length) + + def __str__(self) -> str: + """Returns the source code as a single string.""" + + return self.code_str() + + def import_str(self, indent: int = 0) -> str: + """Returns required imports as a single string. + + Args: + indent: source code indentation count by spaces + + """ + lead_str = " " * indent + return "\n".join(lead_str + line for line in self.imports) + + def add_import(self, statement: str) -> None: + """Add import statement, identical import statements are merged + together. + """ + self.imports.add(statement) + + def add_line(self, code: str, indent: int = 0) -> None: + """Add a single source code line without line ending ``\\n``.""" + self.code.append(" " * indent + code) + + def add_lines(self, code: Iterable[str], indent: int = 0) -> None: + """Add multiple source code lines without line ending ``\\n``.""" + for line in code: + self.add_line(line, indent=indent) + + def merge(self, code: Code, indent: int = 0) -> None: + """Add another :class:`Code` object.""" + # merge used resources + self.imports.update(code.imports) + self.layers.update(code.layers) + self.linetypes.update(code.linetypes) + self.styles.update(code.styles) + self.dimstyles.update(code.dimstyles) + self.blocks.update(code.blocks) + + # append source code lines + self.add_lines(code.code, indent=indent) + + +_PURGE_DXF_ATTRIBUTES = { + "handle", + "owner", + "paperspace", + "material_handle", + "visualstyle_handle", + "plotstyle_handle", +} + + +def _purge_handles(attribs: dict) -> dict: + """Purge handles from DXF attributes which will be invalid in a new + document, or which will be set automatically by adding an entity to a + layout (paperspace). + + Args: + attribs: entity DXF attributes dictionary + + """ + return {k: v for k, v in attribs.items() if k not in _PURGE_DXF_ATTRIBUTES} + + +def _fmt_mapping(mapping: Mapping, indent: int = 0) -> Iterable[str]: + # key is always a string + fmt = " " * indent + "'{}': {}," + for k, v in mapping.items(): + assert isinstance(k, str) + if isinstance(v, str): + v = json.dumps(v) # for correct escaping of quotes + else: + v = str(v) # format uses repr() for Vec3s + yield fmt.format(k, v) + + +def _fmt_list(l: Iterable, indent: int = 0) -> Iterable[str]: + def cleanup(values: Iterable) -> Iterable: + for value in values: + if isinstance(value, np.float64): + yield float(value) + else: + yield value + + fmt = " " * indent + "{}," + for v in l: + if not isinstance(v, (float, int, str)): + v = tuple(cleanup(v)) + yield fmt.format(str(v)) + + +def _fmt_api_call( + func_call: str, args: Iterable[str], dxfattribs: dict +) -> list[str]: + attributes = dict(dxfattribs) + args = list(args) if args else [] + + def fmt_keywords() -> Iterable[str]: + for arg in args: + if arg not in attributes: + continue + value = attributes.pop(arg) + if isinstance(value, str): + valuestr = json.dumps(value) # quoted string! + else: + valuestr = str(value) + yield " {}={},".format(arg, valuestr) + + s = [func_call] + s.extend(fmt_keywords()) + s.append(" dxfattribs={") + s.extend(_fmt_mapping(attributes, indent=8)) + s.extend( + [ + " },", + ")", + ] + ) + return s + + +def _fmt_dxf_tags(tags: Iterable[DXFTag], indent: int = 0): + fmt = " " * indent + "dxftag({}, {})," + for code, value in tags: + assert isinstance(code, int) + if isinstance(value, str): + value = json.dumps(value) # for correct escaping of quotes + else: + value = str(value) # format uses repr() for Vec3s + yield fmt.format(code, value) + + +class _SourceCodeGenerator: + """ + The :class:`_SourceCodeGenerator` translates DXF entities into Python source + code for creating the same DXF entity in another model space or block + definition. + + :ivar code: list of source code lines without line endings + :ivar required_imports: list of import source code lines, which are required + to create executable Python code. + + """ + + def __init__(self, layout: str = "layout", doc: str = "doc"): + self.doc = doc + self.layout = layout + self.code = Code() + + def translate_entity(self, entity: DXFEntity) -> None: + """Translates one DXF entity into Python source code. The generated + source code is appended to the attribute `source_code`. + + Args: + entity: DXFEntity object + + """ + dxftype = entity.dxftype() + try: + entity_translator = getattr(self, "_" + dxftype.lower()) + except AttributeError: + self.add_source_code_line(f'# unsupported DXF entity "{dxftype}"') + else: + entity_translator(entity) + + def translate_entities( + self, + entities: Iterable[DXFEntity], + ignore: Optional[Iterable[str]] = None, + ) -> None: + """Translates multiple DXF entities into Python source code. The + generated source code is appended to the attribute `source_code`. + + Args: + entities: iterable of DXFEntity + ignore: iterable of entities types to ignore as strings + like ['IMAGE', 'DIMENSION'] + + """ + ignore = set(ignore) if ignore else set() + + for entity in entities: + if entity.dxftype() not in ignore: + self.translate_entity(entity) + + def add_used_resources(self, dxfattribs: Mapping) -> None: + """Register used resources like layers, line types, text styles and + dimension styles. + + Args: + dxfattribs: DXF attributes dictionary + + """ + if "layer" in dxfattribs: + self.code.layers.add(dxfattribs["layer"]) + if "linetype" in dxfattribs: + self.code.linetypes.add(dxfattribs["linetype"]) + if "style" in dxfattribs: + self.code.styles.add(dxfattribs["style"]) + if "dimstyle" in dxfattribs: + self.code.dimstyles.add(dxfattribs["dimstyle"]) + + def add_import_statement(self, statement: str) -> None: + self.code.add_import(statement) + + def add_source_code_line(self, code: str) -> None: + self.code.add_line(code) + + def add_source_code_lines(self, code: Iterable[str]) -> None: + assert not isinstance(code, str) + self.code.add_lines(code) + + def add_list_source_code( + self, + values: Iterable, + prolog: str = "[", + epilog: str = "]", + indent: int = 0, + ) -> None: + fmt_str = " " * indent + "{}" + self.add_source_code_line(fmt_str.format(prolog)) + self.add_source_code_lines(_fmt_list(values, indent=4 + indent)) + self.add_source_code_line(fmt_str.format(epilog)) + + def add_dict_source_code( + self, + mapping: Mapping, + prolog: str = "{", + epilog: str = "}", + indent: int = 0, + ) -> None: + fmt_str = " " * indent + "{}" + self.add_source_code_line(fmt_str.format(prolog)) + self.add_source_code_lines(_fmt_mapping(mapping, indent=4 + indent)) + self.add_source_code_line(fmt_str.format(epilog)) + + def add_tags_source_code( + self, tags: Tags, prolog="tags = Tags(", epilog=")", indent=4 + ): + fmt_str = " " * indent + "{}" + self.add_source_code_line(fmt_str.format(prolog)) + self.add_source_code_lines(_fmt_dxf_tags(tags, indent=4 + indent)) + self.add_source_code_line(fmt_str.format(epilog)) + + def generic_api_call( + self, dxftype: str, dxfattribs: dict, prefix: str = "e = " + ) -> Iterable[str]: + """Returns the source code strings to create a DXF entity by a generic + `new_entity()` call. + + Args: + dxftype: DXF entity type as string, like 'LINE' + dxfattribs: DXF attributes dictionary + prefix: prefix string like variable assignment 'e = ' + + """ + dxfattribs = _purge_handles(dxfattribs) + self.add_used_resources(dxfattribs) + s = [ + f"{prefix}{self.layout}.new_entity(", + f" '{dxftype}',", + " dxfattribs={", + ] + s.extend(_fmt_mapping(dxfattribs, indent=8)) + s.extend( + [ + " },", + ")", + ] + ) + return s + + def api_call( + self, + api_call: str, + args: Iterable[str], + dxfattribs: dict, + prefix: str = "e = ", + ) -> Iterable[str]: + """Returns the source code strings to create a DXF entity by the + specialised API call. + + Args: + api_call: API function call like 'add_line(' + args: DXF attributes to pass as arguments + dxfattribs: DXF attributes dictionary + prefix: prefix string like variable assignment 'e = ' + + """ + dxfattribs = _purge_handles(dxfattribs) + func_call = f"{prefix}{self.layout}.{api_call}" + return _fmt_api_call(func_call, args, dxfattribs) + + def new_table_entry(self, dxftype: str, dxfattribs: dict) -> Iterable[str]: + """Returns the source code strings to create a new table entity by + ezdxf. + + Args: + dxftype: table entry type as string, like 'LAYER' + dxfattribs: DXF attributes dictionary + + """ + table = f"{self.doc}.{TABLENAMES[dxftype]}" + dxfattribs = _purge_handles(dxfattribs) + name = dxfattribs.pop("name") + s = [ + f"if '{name}' not in {table}:", + f" t = {table}.new(", + f" '{name}',", + " dxfattribs={", + ] + s.extend(_fmt_mapping(dxfattribs, indent=12)) + s.extend( + [ + " },", + " )", + ] + ) + return s + + # simple graphical types + + def _line(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call("add_line(", ["start", "end"], entity.dxfattribs()) + ) + + def _point(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call("add_point(", ["location"], entity.dxfattribs()) + ) + + def _circle(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call( + "add_circle(", ["center", "radius"], entity.dxfattribs() + ) + ) + + def _arc(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call( + "add_arc(", + ["center", "radius", "start_angle", "end_angle"], + entity.dxfattribs(), + ) + ) + + def _text(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call("add_text(", ["text"], entity.dxfattribs()) + ) + + def _solid(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.generic_api_call("SOLID", entity.dxfattribs()) + ) + + def _trace(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.generic_api_call("TRACE", entity.dxfattribs()) + ) + + def _3dface(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.generic_api_call("3DFACE", entity.dxfattribs()) + ) + + def _shape(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call( + "add_shape(", ["name", "insert", "size"], entity.dxfattribs() + ) + ) + + def _attrib(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call( + "add_attrib(", ["tag", "text", "insert"], entity.dxfattribs() + ) + ) + + def _attdef(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.generic_api_call("ATTDEF", entity.dxfattribs()) + ) + + def _ellipse(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.api_call( + "add_ellipse(", + ["center", "major_axis", "ratio", "start_param", "end_param"], + entity.dxfattribs(), + ) + ) + + def _viewport(self, entity: DXFEntity) -> None: + self.add_source_code_lines( + self.generic_api_call("VIEWPORT", entity.dxfattribs()) + ) + self.add_source_code_line( + '# Set valid handles or remove attributes ending with "_handle", ' + "otherwise the DXF file is invalid for AutoCAD" + ) + + # complex graphical types + + def _insert(self, entity: Insert) -> None: + self.code.blocks.add(entity.dxf.name) + self.add_source_code_lines( + self.api_call( + "add_blockref(", ["name", "insert"], entity.dxfattribs() + ) + ) + if len(entity.attribs): + for attrib in entity.attribs: + dxfattribs = attrib.dxfattribs() + dxfattribs[ + "layer" + ] = entity.dxf.layer # set ATTRIB layer to same as INSERT + self.add_source_code_lines( + self.generic_api_call( + "ATTRIB", attrib.dxfattribs(), prefix="a = " + ) + ) + self.add_source_code_line("e.attribs.append(a)") + + def _mtext(self, entity: MText) -> None: + self.add_source_code_lines( + self.generic_api_call("MTEXT", entity.dxfattribs()) + ) + # MTEXT content 'text' is not a single DXF tag and therefore not a DXF + # attribute + self.add_source_code_line("e.text = {}".format(json.dumps(entity.text))) + + def _lwpolyline(self, entity: LWPolyline) -> None: + self.add_source_code_lines( + self.generic_api_call("LWPOLYLINE", entity.dxfattribs()) + ) + # lwpolyline points are not DXF attributes + self.add_list_source_code( + entity.get_points(), prolog="e.set_points([", epilog="])" + ) + + def _spline(self, entity: Spline) -> None: + self.add_source_code_lines( + self.api_call("add_spline(", ["degree"], entity.dxfattribs()) + ) + # spline points, knots and weights are not DXF attributes + if len(entity.fit_points): + self.add_list_source_code( + entity.fit_points, prolog="e.fit_points = [", epilog="]" + ) + + if len(entity.control_points): + self.add_list_source_code( + entity.control_points, prolog="e.control_points = [", epilog="]" + ) + + if len(entity.knots): + self.add_list_source_code( + entity.knots, prolog="e.knots = [", epilog="]" + ) + + if len(entity.weights): + self.add_list_source_code( + entity.weights, prolog="e.weights = [", epilog="]" + ) + + def _polyline(self, entity: Polyline) -> None: + self.add_source_code_lines( + self.generic_api_call("POLYLINE", entity.dxfattribs()) + ) + # polyline vertices are separate DXF entities and therefore not DXF attributes + for v in entity.vertices: + attribs = _purge_handles(v.dxfattribs()) + location = attribs.pop("location") + if "layer" in attribs: + del attribs[ + "layer" + ] # layer is automatically set to the POLYLINE layer + + # each VERTEX can have different DXF attributes: bulge, start_width, end_width ... + self.add_source_code_line( + f"e.append_vertex({str(location)}, dxfattribs={attribs})" + ) + + def _leader(self, entity: Leader): + self.add_source_code_line( + "# Dimension style attribute overriding is not supported!" + ) + self.add_source_code_lines( + self.generic_api_call("LEADER", entity.dxfattribs()) + ) + self.add_list_source_code( + entity.vertices, prolog="e.set_vertices([", epilog="])" + ) + + def _dimension(self, entity: Dimension): + self.add_import_statement( + "from ezdxf.dimstyleoverride import DimStyleOverride" + ) + self.add_source_code_line( + "# Dimension style attribute overriding is not supported!" + ) + self.add_source_code_lines( + self.generic_api_call("DIMENSION", entity.dxfattribs()) + ) + self.add_source_code_lines( + [ + "# You have to create the required graphical representation for ", + "# the DIMENSION entity as anonymous block, otherwise the DXF file", + "# is invalid for AutoCAD (but not for BricsCAD):", + "# DimStyleOverride(e).render()", + "", + ] + ) + + def _image(self, entity: Image): + self.add_source_code_line( + "# Image requires IMAGEDEF and IMAGEDEFREACTOR objects in the " + "OBJECTS section!" + ) + self.add_source_code_lines( + self.generic_api_call("IMAGE", entity.dxfattribs()) + ) + if len(entity.boundary_path): + self.add_list_source_code( + (v for v in entity.boundary_path), # just x, y axis + prolog="e.set_boundary_path([", + epilog="])", + ) + self.add_source_code_line( + "# Set valid image_def_handle and image_def_reactor_handle, " + "otherwise the DXF file is invalid for AutoCAD" + ) + + def _wipeout(self, entity: Wipeout): + self.add_source_code_lines( + self.generic_api_call("WIPEOUT", entity.dxfattribs()) + ) + if len(entity.boundary_path): + self.add_list_source_code( + (v for v in entity.boundary_path), # just x, y axis + prolog="e.set_boundary_path([", + epilog="])", + ) + + def _mesh(self, entity: Mesh): + self.add_source_code_lines( + self.api_call("add_mesh(", [], entity.dxfattribs()) + ) + if len(entity.vertices): + self.add_list_source_code( + entity.vertices, prolog="e.vertices = [", epilog="]" + ) + if len(entity.edges): + # array.array -> tuple + self.add_list_source_code( + (tuple(e) for e in entity.edges), + prolog="e.edges = [", + epilog="]", + ) + if len(entity.faces): + # array.array -> tuple + self.add_list_source_code( + (tuple(f) for f in entity.faces), + prolog="e.faces = [", + epilog="]", + ) + if len(entity.creases): + self.add_list_source_code( + entity.creases, prolog="e.creases = [", epilog="]" + ) + + def _hatch(self, entity: Hatch): + dxfattribs = entity.dxfattribs() + dxfattribs["associative"] = 0 # associative hatch not supported + self.add_source_code_lines( + self.api_call("add_hatch(", ["color"], dxfattribs) + ) + self._polygon(entity) + + def _mpolygon(self, entity: MPolygon): + dxfattribs = entity.dxfattribs() + self.add_source_code_lines( + self.api_call("add_mpolygon(", ["color"], dxfattribs) + ) + if entity.dxf.solid_fill: + self.add_source_code_line( + f"e.set_solid_fill(color={entity.dxf.fill_color})\n" + ) + self._polygon(entity) + + def _polygon(self, entity: DXFPolygon): + add_line = self.add_source_code_line + if len(entity.seeds): + add_line(f"e.set_seed_points({entity.seeds})") + if entity.pattern: + self.add_list_source_code( + map(str, entity.pattern.lines), + prolog="e.set_pattern_definition([", + epilog="])", + ) + self.add_source_code_line("e.dxf.solid_fill = 0") + arg = " {}={}," + + if entity.gradient is not None: + g = entity.gradient + add_line("e.set_gradient(") + add_line(arg.format("color1", str(g.color1))) + add_line(arg.format("color2", str(g.color2))) + add_line(arg.format("rotation", g.rotation)) + add_line(arg.format("centered", g.centered)) + add_line(arg.format("one_color", g.one_color)) + add_line(arg.format("name", json.dumps(g.name))) + add_line(")") + for count, path in enumerate(entity.paths, start=1): + if path.type == BoundaryPathType.POLYLINE: + add_line("# {}. polyline path".format(count)) + self.add_list_source_code( + path.vertices, + prolog="e.paths.add_polyline_path([", + epilog=" ],", + ) + add_line(arg.format("is_closed", str(path.is_closed))) + add_line(arg.format("flags", str(path.path_type_flags))) + add_line(")") + else: # EdgePath + add_line( + f"# {count}. edge path: associative hatch not supported" + ) + add_line( + f"ep = e.paths.add_edge_path(flags={path.path_type_flags})" + ) + for edge in path.edges: + if edge.type == EdgeType.LINE: + add_line(f"ep.add_line({edge.start}, {str(edge.end)})") + elif edge.type == EdgeType.ARC: + # Start- and end angles are always stored in ccw + # orientation: + add_line("ep.add_arc(") + add_line(arg.format("center", str(edge.center))) + add_line(arg.format("radius", edge.radius)) + add_line(arg.format("start_angle", edge.start_angle)) + add_line(arg.format("end_angle", edge.end_angle)) + add_line(arg.format("ccw", edge.ccw)) + add_line(")") + elif edge.type == EdgeType.ELLIPSE: + # Start- and end params are always stored in ccw + # orientation: + add_line("ep.add_ellipse(") + add_line(arg.format("center", str(edge.center))) + add_line(arg.format("major_axis", str(edge.major_axis))) + add_line(arg.format("ratio", edge.ratio)) + add_line(arg.format("start_angle", edge.start_angle)) + add_line(arg.format("end_angle", edge.end_angle)) + add_line(arg.format("ccw", edge.ccw)) + add_line(")") + elif edge.type == EdgeType.SPLINE: + add_line("ep.add_spline(") + if edge.fit_points: + add_line( + arg.format( + "fit_points", + str([fp for fp in edge.fit_points]), + ) + ) + if edge.control_points: + add_line( + arg.format( + "control_points", + str([cp for cp in edge.control_points]), + ) + ) + if edge.knot_values: + add_line( + arg.format("knot_values", str(edge.knot_values)) + ) + if edge.weights: + add_line(arg.format("weights", str(edge.weights))) + add_line(arg.format("degree", edge.degree)) + add_line(arg.format("periodic", edge.periodic)) + if edge.start_tangent is not None: + add_line( + arg.format( + "start_tangent", str(edge.start_tangent) + ) + ) + if edge.end_tangent is not None: + add_line( + arg.format("end_tangent", str(edge.end_tangent)) + ) + add_line(")") + + # simple table entries + def _layer(self, layer: DXFEntity): + self.add_source_code_lines( + self.new_table_entry("LAYER", layer.dxfattribs()) + ) + + def _ltype(self, ltype: Linetype): + self.add_import_statement("from ezdxf.lldxf.tags import Tags") + self.add_import_statement("from ezdxf.lldxf.types import dxftag") + self.add_import_statement( + "from ezdxf.entities.ltype import LinetypePattern" + ) + self.add_source_code_lines( + self.new_table_entry("LTYPE", ltype.dxfattribs()) + ) + self.add_tags_source_code( + ltype.pattern_tags.tags, + prolog="tags = Tags([", + epilog="])", + indent=4, + ) + self.add_source_code_line(" t.pattern_tags = LinetypePattern(tags)") + + def _style(self, style: DXFEntity): + self.add_source_code_lines( + self.new_table_entry("STYLE", style.dxfattribs()) + ) + + def _dimstyle(self, dimstyle: DXFEntity): + self.add_source_code_lines( + self.new_table_entry("DIMSTYLE", dimstyle.dxfattribs()) + ) + + def _appid(self, appid: DXFEntity): + self.add_source_code_lines( + self.new_table_entry("APPID", appid.dxfattribs()) + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/genetic_algorithm.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/genetic_algorithm.py new file mode 100644 index 0000000..aa3279f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/genetic_algorithm.py @@ -0,0 +1,721 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Sequence, + Iterable, + Optional, + Callable, + Union, +) +import abc +import copy +from dataclasses import dataclass +import json +import random +import time + +# example usage: +# examples\addons\optimize\bin_packing_forms.py +# examples\addons\optimize\tsp.py + + +class DNA(abc.ABC): + """Abstract DNA class.""" + + fitness: Optional[float] = None + _data: list + + @abc.abstractmethod + def reset(self, values: Iterable): + ... + + @property + @abc.abstractmethod + def is_valid(self) -> bool: + ... + + def copy(self): + return copy.deepcopy(self) + + def _taint(self): + self.fitness = None + + def __repr__(self): + return f"{self.__class__.__name__}({str(self._data)})" + + def __eq__(self, other): + assert isinstance(other, self.__class__) + return self._data == other._data + + def __len__(self): + return len(self._data) + + def __getitem__(self, item): + return self._data.__getitem__(item) + + def __setitem__(self, key, value): + self._data.__setitem__(key, value) + self._taint() + + def __iter__(self): + return iter(self._data) + + @abc.abstractmethod + def flip_mutate_at(self, index: int) -> None: + ... + + +def dna_fitness(dna: DNA) -> float: + return dna.fitness # type: ignore + + +class Mutate(abc.ABC): + """Abstract mutation.""" + + @abc.abstractmethod + def mutate(self, dna: DNA, rate: float): + ... + + +class FlipMutate(Mutate): + """Flip one bit mutation.""" + + def mutate(self, dna: DNA, rate: float): + for index in range(len(dna)): + if random.random() < rate: + dna.flip_mutate_at(index) + + +class NeighborSwapMutate(Mutate): + """Swap two neighbors mutation.""" + + def mutate(self, dna: DNA, rate: float): + for index in range(len(dna)): + if random.random() < rate: + i2 = index - 1 + tmp = dna[i2] + dna[i2] = dna[index] + dna[index] = tmp + + +class RandomSwapMutate(Mutate): + """Swap two random places mutation.""" + + def mutate(self, dna: DNA, rate: float): + length = len(dna) + for index in range(length): + if random.random() < rate: + i2 = random.randrange(0, length) + if i2 == index: + i2 -= 1 + tmp = dna[i2] + dna[i2] = dna[index] + dna[index] = tmp + + +class ReverseMutate(Mutate): + """Reverse some consecutive bits mutation.""" + + def __init__(self, bits: int = 3): + self._bits = int(max(bits, 1)) + + def mutate(self, dna: DNA, rate: float): + length = len(dna) + if random.random() < rate * ( + length / self._bits + ): # applied to all bits at ones + i1 = random.randrange(length - self._bits) + i2 = i1 + self._bits + bits = dna[i1:i2] + dna[i1:i2] = reversed(bits) + + +class ScrambleMutate(Mutate): + """Scramble some consecutive bits mutation.""" + + def __init__(self, bits: int = 3): + self._bits = int(max(bits, 1)) + + def mutate(self, dna: DNA, rate: float): + length = len(dna) + if random.random() < rate * ( + length / self._bits + ): # applied to all bits at ones + i1 = random.randrange(length - self._bits) + i2 = i1 + self._bits + bits = dna[i1:i2] + random.shuffle(bits) + dna[i1:i2] = bits + + +class Mate(abc.ABC): + """Abstract recombination.""" + + @abc.abstractmethod + def recombine(self, dna1: DNA, dna2: DNA): + pass + + +class Mate1pCX(Mate): + """One point crossover recombination.""" + + def recombine(self, dna1: DNA, dna2: DNA): + length = len(dna1) + index = random.randrange(0, length) + recombine_dna_2pcx(dna1, dna2, index, length) + + +class Mate2pCX(Mate): + """Two point crossover recombination.""" + + def recombine(self, dna1: DNA, dna2: DNA): + length = len(dna1) + i1 = random.randrange(0, length) + i2 = random.randrange(0, length) + if i1 > i2: + i1, i2 = i2, i1 + recombine_dna_2pcx(dna1, dna2, i1, i2) + + +class MateUniformCX(Mate): + """Uniform recombination.""" + + def recombine(self, dna1: DNA, dna2: DNA): + for index in range(len(dna1)): + if random.random() > 0.5: + tmp = dna1[index] + dna1[index] = dna2[index] + dna2[index] = tmp + + +class MateOrderedCX(Mate): + """Recombination class for ordered DNA like UniqueIntDNA().""" + + def recombine(self, dna1: DNA, dna2: DNA): + length = len(dna1) + i1 = random.randrange(0, length) + i2 = random.randrange(0, length) + if i1 > i2: + i1, i2 = i2, i1 + recombine_dna_ocx1(dna1, dna2, i1, i2) + + +def recombine_dna_2pcx(dna1: DNA, dna2: DNA, i1: int, i2: int) -> None: + """Two point crossover.""" + part1 = dna1[i1:i2] + part2 = dna2[i1:i2] + dna1[i1:i2] = part2 + dna2[i1:i2] = part1 + + +def recombine_dna_ocx1(dna1: DNA, dna2: DNA, i1: int, i2: int) -> None: + """Ordered crossover.""" + copy1 = dna1.copy() + replace_dna_ocx1(dna1, dna2, i1, i2) + replace_dna_ocx1(dna2, copy1, i1, i2) + + +def replace_dna_ocx1(dna1: DNA, dna2: DNA, i1: int, i2: int) -> None: + """Replace a part in dna1 by dna2 and preserve order of remaining values in + dna1. + """ + old = dna1.copy() + new = dna2[i1:i2] + dna1[i1:i2] = new + index = 0 + new_set = set(new) + for value in old: + if value in new_set: + continue + if index == i1: + index = i2 + dna1[index] = value + index += 1 + + +class FloatDNA(DNA): + """Arbitrary float numbers in the range [0, 1].""" + + __slots__ = ("_data", "fitness") + + def __init__(self, values: Iterable[float]): + self._data: list[float] = list(values) + self._check_valid_data() + self.fitness: Optional[float] = None + + @classmethod + def random(cls, length: int) -> FloatDNA: + return cls((random.random() for _ in range(length))) + + @classmethod + def n_random(cls, n: int, length: int) -> list[FloatDNA]: + return [cls.random(length) for _ in range(n)] + + @property + def is_valid(self) -> bool: + return all(0.0 <= v <= 1.0 for v in self._data) + + def _check_valid_data(self): + if not self.is_valid: + raise ValueError("data value out of range") + + def __str__(self): + if self.fitness is None: + fitness = ", fitness=None" + else: + fitness = f", fitness={self.fitness:.4f}" + return f"{str([round(v, 4) for v in self._data])}{fitness}" + + def reset(self, values: Iterable[float]): + self._data = list(values) + self._check_valid_data() + self._taint() + + def flip_mutate_at(self, index: int) -> None: + self._data[index] = 1.0 - self._data[index] # flip pick location + + +class BitDNA(DNA): + """One bit DNA.""" + + __slots__ = ("_data", "fitness") + + def __init__(self, values: Iterable): + self._data: list[bool] = list(bool(v) for v in values) + self.fitness: Optional[float] = None + + @property + def is_valid(self) -> bool: + return True # everything can be evaluated to True/False + + @classmethod + def random(cls, length: int) -> BitDNA: + return cls(bool(random.randint(0, 1)) for _ in range(length)) + + @classmethod + def n_random(cls, n: int, length: int) -> list[BitDNA]: + return [cls.random(length) for _ in range(n)] + + def __str__(self): + if self.fitness is None: + fitness = ", fitness=None" + else: + fitness = f", fitness={self.fitness:.4f}" + return f"{str([int(v) for v in self._data])}{fitness}" + + def reset(self, values: Iterable) -> None: + self._data = list(bool(v) for v in values) + self._taint() + + def flip_mutate_at(self, index: int) -> None: + self._data[index] = not self._data[index] + + +class UniqueIntDNA(DNA): + """Unique integer values in the range from 0 to length-1. + E.g. UniqueIntDNA(10) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + Requires MateOrderedCX() as recombination class to preserve order and + validity after DNA recombination. + + Requires mutation by swapping like SwapRandom(), SwapNeighbors(), + ReversMutate() or ScrambleMutate() + """ + + __slots__ = ("_data", "fitness") + + def __init__(self, values: Union[int, Iterable]): + self._data: list[int] + if isinstance(values, int): + self._data = list(range(values)) + else: + self._data = [int(v) for v in values] + if not self.is_valid: + raise TypeError(self._data) + self.fitness: Optional[float] = None + + @classmethod + def random(cls, length: int) -> UniqueIntDNA: + dna = cls(length) + random.shuffle(dna._data) + return dna + + @classmethod + def n_random(cls, n: int, length: int) -> list[UniqueIntDNA]: + return [cls.random(length) for _ in range(n)] + + @property + def is_valid(self) -> bool: + return len(set(self._data)) == len(self._data) + + def __str__(self): + if self.fitness is None: + fitness = ", fitness=None" + else: + fitness = f", fitness={self.fitness:.4f}" + return f"{str([int(v) for v in self._data])}{fitness}" + + def reset(self, values: Iterable) -> None: + self._data = list(int(v) for v in values) + self._taint() + + def flip_mutate_at(self, index: int) -> None: + raise TypeError("flip mutation not supported") + + +class IntegerDNA(DNA): + """Integer values in the range from 0 to max_ - 1. + E.g. IntegerDNA([0, 1, 2, 3, 4, 0, 1, 2, 3, 4], 5) + """ + + __slots__ = ("_data", "fitness") + + def __init__(self, values: Iterable[int], max_: int): + self._max = int(max_) + self._data: list[int] = list(values) + if not self.is_valid: + raise TypeError(self._data) + self.fitness: Optional[float] = None + + @classmethod + def random(cls, length: int, max_: int) -> IntegerDNA: + imax = int(max_) + return cls((random.randrange(0, imax) for _ in range(length)), imax) + + @classmethod + def n_random(cls, n: int, length: int, max_: int) -> list[IntegerDNA]: + return [cls.random(length, max_) for _ in range(n)] + + @property + def is_valid(self) -> bool: + return all(0 <= v < self._max for v in self._data) + + def __repr__(self): + return f"{self.__class__.__name__}({str(self._data)}, {self._max})" + + def __str__(self): + if self.fitness is None: + fitness = ", fitness=None" + else: + fitness = f", fitness={self.fitness:.4f}" + return f"{str([int(v) for v in self._data])}{fitness}" + + def reset(self, values: Iterable) -> None: + self._data = list(int(v) for v in values) + self._taint() + + def flip_mutate_at(self, index: int) -> None: + self._data[index] = self._max - self._data[index] - 1 + + +class Selection(abc.ABC): + """Abstract selection class.""" + + @abc.abstractmethod + def pick(self, count: int) -> Iterable[DNA]: + ... + + @abc.abstractmethod + def reset(self, candidates: Iterable[DNA]): + ... + + +class Evaluator(abc.ABC): + """Abstract evaluation class.""" + + @abc.abstractmethod + def evaluate(self, dna: DNA) -> float: + ... + + +class Log: + @dataclass + class Entry: + runtime: float + fitness: float + avg_fitness: float + + def __init__(self) -> None: + self.entries: list[Log.Entry] = [] + + def add(self, runtime: float, fitness: float, avg_fitness: float) -> None: + self.entries.append(Log.Entry(runtime, fitness, avg_fitness)) + + def dump(self, filename: str) -> None: + data = [(e.runtime, e.fitness, e.avg_fitness) for e in self.entries] + with open(filename, "wt") as fp: + json.dump(data, fp, indent=4) + + @classmethod + def load(cls, filename: str) -> Log: + with open(filename, "rt") as fp: + data = json.load(fp) + log = Log() + for runtime, fitness, avg_fitness in data: + log.add(runtime, fitness, avg_fitness) + return log + + +class HallOfFame: + def __init__(self, count): + self.count = count + self._unique_entries = dict() + + def __iter__(self): + return ( + self._unique_entries[k] for k in self._sorted_keys()[: self.count] + ) + + def _sorted_keys(self): + return sorted(self._unique_entries.keys(), reverse=True) + + def add(self, dna: DNA): + assert dna.fitness is not None + self._unique_entries[dna.fitness] = dna + + def get(self, count: int) -> list[DNA]: + entries = self._unique_entries + keys = self._sorted_keys() + return [entries[k] for k in keys[: min(count, self.count)]] + + def purge(self): + if len(self._unique_entries) <= self.count: + return + entries = self._unique_entries + keys = self._sorted_keys() + self._unique_entries = {k: entries[k] for k in keys[: self.count]} + + +def threshold_filter( + candidates: Sequence[DNA], best_fitness: float, threshold: float +) -> Iterable[DNA]: + if best_fitness <= 0.0: + minimum = min(candidates, key=dna_fitness) + min_value = (1.0 - threshold) * minimum.fitness # type: ignore + else: + min_value = best_fitness * threshold + return (c for c in candidates if c.fitness > min_value) # type: ignore + + +class GeneticOptimizer: + """A genetic algorithm (GA) is a meta-heuristic inspired by the process of + natural selection. Genetic algorithms are commonly used to generate + high-quality solutions to optimization and search problems by relying on + biologically inspired operators such as mutation, crossover and selection. + + Source: https://en.wikipedia.org/wiki/Genetic_algorithm + + This implementation searches always for the maximum fitness, fitness + comparisons are always done by the "greater than" operator (">"). + The algorithm supports negative values to search for the minimum fitness + (e.g. Travelling Salesmen Problem: -900 > -1000). Reset the start fitness + by the method :meth:`reset_fitness` accordingly:: + + optimizer.reset_fitness(-1e99) + + """ + + def __init__( + self, + evaluator: Evaluator, + max_generations: int, + max_fitness: float = 1.0, + ): + if max_generations < 1: + raise ValueError("requires max_generations > 0") + # data: + self.name = "GeneticOptimizer" + self.log = Log() + self.candidates: list[DNA] = [] + + # core components: + self.evaluator: Evaluator = evaluator + self.selection: Selection = RouletteSelection() + self.mate: Mate = Mate2pCX() + self.mutation = FlipMutate() + + # options: + self.max_generations = int(max_generations) + self.max_fitness: float = float(max_fitness) + self.max_runtime: float = 1e99 + self.max_stagnation = 100 + self.crossover_rate = 0.70 + self.mutation_rate = 0.01 + self.elitism: int = 2 + # percentage (0.1 = 10%) of candidates with least fitness to ignore in + # next generation + self.threshold: float = 0.0 + + # state of last (current) generation: + self.generation: int = 0 + self.start_time = 0.0 + self.runtime: float = 0.0 + self.best_dna: DNA = BitDNA([]) + self.best_fitness: float = 0.0 + self.stagnation: int = 0 # generations without improvement + self.hall_of_fame = HallOfFame(10) + + def reset_fitness(self, value: float) -> None: + self.best_fitness = float(value) + + @property + def is_executed(self) -> bool: + return bool(self.generation) + + @property + def count(self) -> int: + return len(self.candidates) + + def add_candidates(self, dna: Iterable[DNA]): + if not self.is_executed: + self.candidates.extend(dna) + else: + raise TypeError("already executed") + + def execute( + self, + feedback: Optional[Callable[[GeneticOptimizer], bool]] = None, + interval: float = 1.0, + ) -> None: + if self.is_executed: + raise TypeError("can only run once") + if not self.candidates: + print("no DNA defined!") + t0 = time.perf_counter() + self.start_time = t0 + for self.generation in range(1, self.max_generations + 1): + self.measure_fitness() + t1 = time.perf_counter() + self.runtime = t1 - self.start_time + if ( + self.best_fitness >= self.max_fitness + or self.runtime >= self.max_runtime + or self.stagnation >= self.max_stagnation + ): + break + if feedback and t1 - t0 > interval: + if feedback(self): # stop if feedback() returns True + break + t0 = t1 + self.next_generation() + + def measure_fitness(self) -> None: + self.stagnation += 1 + fitness_sum: float = 0.0 + for dna in self.candidates: + if dna.fitness is not None: + fitness_sum += dna.fitness + continue + fitness = self.evaluator.evaluate(dna) + dna.fitness = fitness + fitness_sum += fitness + self.hall_of_fame.add(dna) + if fitness > self.best_fitness: + self.best_fitness = fitness + self.best_dna = dna + self.stagnation = 0 + + self.hall_of_fame.purge() + try: + avg_fitness = fitness_sum / len(self.candidates) + except ZeroDivisionError: + avg_fitness = 0.0 + self.log.add( + time.perf_counter() - self.start_time, + self.best_fitness, + avg_fitness, + ) + + def next_generation(self) -> None: + count = len(self.candidates) + candidates: list[DNA] = [] + selector = self.selection + selector.reset(self.filter_threshold(self.candidates)) + + if self.elitism > 0: + candidates.extend(self.hall_of_fame.get(self.elitism)) + + while len(candidates) < count: + dna1, dna2 = selector.pick(2) + dna1 = dna1.copy() + dna2 = dna2.copy() + self.recombine(dna1, dna2) + self.mutate(dna1, dna2) + candidates.append(dna1) + candidates.append(dna2) + self.candidates = candidates + + def filter_threshold(self, candidates: Sequence[DNA]) -> Iterable[DNA]: + if self.threshold > 0.0: + return threshold_filter( + candidates, self.best_fitness, self.threshold + ) + else: + return candidates + + def recombine(self, dna1: DNA, dna2: DNA): + if random.random() < self.crossover_rate: + self.mate.recombine(dna1, dna2) + + def mutate(self, dna1: DNA, dna2: DNA): + self.mutation.mutate(dna1, self.mutation_rate) + self.mutation.mutate(dna2, self.mutation_rate) + + +def conv_negative_weights(weights: Iterable[float]) -> Iterable[float]: + # random.choices does not accept negative values: -100 -> 1/100, -10 -> 1/10 + return (0.0 if w == 0.0 else 1.0 / abs(w) for w in weights) + + +class RouletteSelection(Selection): + """Selection by fitness values.""" + + def __init__(self, negative_values: bool = False) -> None: + self._candidates: list[DNA] = [] + self._weights: list[float] = [] + self._negative_values = bool(negative_values) + + def reset(self, candidates: Iterable[DNA]): + # dna.fitness is not None here! + self._candidates = list(candidates) + if self._negative_values: + self._weights = list( + conv_negative_weights(dna.fitness for dna in self._candidates) # type: ignore + ) + else: + self._weights = [dna.fitness for dna in self._candidates] # type: ignore + + def pick(self, count: int) -> Iterable[DNA]: + return random.choices(self._candidates, self._weights, k=count) + + +class RankBasedSelection(RouletteSelection): + """Selection by rank of fitness.""" + + def reset(self, candidates: Iterable[DNA]): + # dna.fitness is not None here! + self._candidates = list(candidates) + self._candidates.sort(key=dna_fitness) + # weight of best_fitness == len(strands) + # and decreases until 1 for the least fitness + self._weights = list(range(1, len(self._candidates) + 1)) + + +class TournamentSelection(Selection): + """Selection by choosing the best of a certain count of candidates.""" + + def __init__(self, candidates: int): + self._candidates: list[DNA] = [] + self.candidates = candidates + + def reset(self, candidates: Iterable[DNA]): + self._candidates = list(candidates) + + def pick(self, count: int) -> Iterable[DNA]: + for _ in range(count): + values = [ + random.choice(self._candidates) for _ in range(self.candidates) + ] + values.sort(key=dna_fitness) + yield values[-1] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/geo.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/geo.py new file mode 100644 index 0000000..edc5eaf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/geo.py @@ -0,0 +1,1042 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +""" +Implementation of the `__geo_interface__`: https://gist.github.com/sgillies/2217756 + +Which is also supported by Shapely: https://pypi.org/project/Shapely/ + +Type definitions see GeoJson Standard: https://tools.ietf.org/html/rfc7946 +and examples : https://tools.ietf.org/html/rfc7946#appendix-A + +GeoJSON Linter: https://geojsonlint.com/ + +""" +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + Union, + cast, + Callable, + Sequence, + Optional, + Any, + MutableMapping, +) +from typing_extensions import TypeAlias, Self +import numbers +import copy +import math +import enum +from ezdxf.math import ( + Vec3, + has_clockwise_orientation, + Matrix44, + world_mercator_to_gps, + gps_to_world_mercator, +) +from ezdxf.path import make_path, from_hatch_boundary_path, make_polygon_structure +from ezdxf.entities import DXFGraphic, LWPolyline, Point, Polyline, Line +from ezdxf.entities.polygon import DXFPolygon +from ezdxf.lldxf import const +from ezdxf.entities import factory + + +__all__ = ["proxy", "dxf_entities", "gfilter", "GeoProxy", "PolygonConversion"] + +TYPE = "type" +COORDINATES = "coordinates" +POINT = "Point" +MULTI_POINT = "MultiPoint" +LINE_STRING = "LineString" +MULTI_LINE_STRING = "MultiLineString" +POLYGON = "Polygon" +MULTI_POLYGON = "MultiPolygon" +GEOMETRY_COLLECTION = "GeometryCollection" +GEOMETRIES = "geometries" +GEOMETRY = "geometry" +FEATURES = "features" +FEATURE = "Feature" +PROPERTIES = "properties" +FEATURE_COLLECTION = "FeatureCollection" +MAX_FLATTENING_DISTANCE = 0.1 +SUPPORTED_DXF_TYPES = { + "POINT", + "LINE", + "LWPOLYLINE", + "POLYLINE", + "HATCH", + "MPOLYGON", + "SOLID", + "TRACE", + "3DFACE", + "CIRCLE", + "ARC", + "ELLIPSE", + "SPLINE", +} + +GeoMapping: TypeAlias = MutableMapping[str, Any] +PostProcessFunc: TypeAlias = Callable[[DXFGraphic, GeoMapping], None] + + +class PolygonConversion(enum.IntEnum): + """Polygon conversion types as :class:`IntEnum`. + + Attributes: + HATCH: + POLYLINE: + HATCH_AND_POLYLINE: + MPOLYGON: + + """ + + HATCH = 1 + POLYLINE = 2 + HATCH_AND_POLYLINE = 3 + MPOLYGON = 4 + + +def proxy( + entity: Union[DXFGraphic, Iterable[DXFGraphic]], + distance: float = MAX_FLATTENING_DISTANCE, + force_line_string: bool = False, +) -> GeoProxy: + """Returns a :class:`GeoProxy` object. + + Args: + entity: a single DXF entity or iterable of DXF entities + distance: maximum flattening distance for curve approximations + force_line_string: by default this function returns Polygon objects for + closed geometries like CIRCLE, SOLID, closed POLYLINE and so on, + by setting argument `force_line_string` to ``True``, this entities + will be returned as LineString objects. + + """ + return GeoProxy.from_dxf_entities(entity, distance, force_line_string) + + +def dxf_entities( + geo_mapping: GeoMapping, + polygon=PolygonConversion.HATCH, + dxfattribs=None, + *, + post_process: Optional[PostProcessFunc] = None, +) -> Iterator[DXFGraphic]: + """Returns ``__geo_interface__`` mappings as DXF entities. + + The enum `polygon` determines the method to convert polygons, + use :attr:`PolygonConversion.HATCH` for :class:`~ezdxf.entities.Hatch` entity, + :attr:`PolygonConversion.POLYLINE` for :class:`~ezdxf.entities.LWPolyline` or + :attr:`PolygonConversion.HATCH_AND_POLYLINE` for both. + Option :attr:`PolygonConversion.POLYLINE` returns for the exterior path and each hole + a separated :class:`LWPolyline` entity. The :class:`Hatch` entity supports holes, + but has no explicit borderline. + + Yields :class:`Hatch` always before :class:`LWPolyline` entities. + + :attr:`PolygonConversion.MPOLYGON` support was added in v0.16.6, which is + like a :class:`~ezdxf.entities.Hatch` entity with additional borderlines, + but the MPOLYGON entity is not a core DXF entity and DXF viewers, + applications and libraries my not support this entity. The DXF attribute + `color` defines the borderline color and `fill_color` the color of the + solid filling. + + The returned DXF entities can be added to a layout by the + :meth:`Layout.add_entity` method. + + Args: + geo_mapping: ``__geo__interface__`` mapping as :class:`dict` or a Python + object with a :attr:`__geo__interface__` property + polygon: see :class:`PolygonConversion` + dxfattribs: dict with additional DXF attributes + post_process: post process function of type :class:`PostProcessFunc` that get the + created DXF entity and the geo mapping as input, see reference implementation + :func:`assign_layers` + + """ + return GeoProxy.parse(geo_mapping).to_dxf_entities( + polygon, dxfattribs, post_process=post_process + ) + + +def gfilter(entities: Iterable[DXFGraphic]) -> Iterator[DXFGraphic]: + """Filter DXF entities from iterable `entities`, which are incompatible to + the ``__geo_reference__`` interface. + """ + for e in entities: + if isinstance(e, Polyline): + if e.is_2d_polyline or e.is_3d_polyline: + yield e + elif e.dxftype() in SUPPORTED_DXF_TYPES: + yield e + + +TFunc: TypeAlias = Callable[[Vec3], Vec3] + + +class GeoProxy: + """Stores the ``__geo_interface__`` mapping in a parsed and compiled form. + + Stores coordinates as :class:`Vec3` objects and represents "Polygon" + always as tuple (exterior, holes) even without holes. + + The GeoJSON specification recommends 6 decimal places for latitude and + longitude which equates to roughly 10cm of precision. You may need + slightly more for certain applications, 9 decimal places would be + sufficient for professional survey-grade GPS coordinates. + + Args: + geo_mapping: parsed and compiled ``__geo_interface__`` mapping + places: decimal places to round for ``__geo_interface__`` export + + """ + + def __init__(self, geo_mapping: GeoMapping, places: int = 6): + self._root = geo_mapping + self.places = places + + @classmethod + def parse(cls, geo_mapping: GeoMapping) -> Self: + """Parse and compile a ``__geo_interface__`` mapping as :class:`dict` + or a Python object with a ``__geo_interface__`` property, does some + basic syntax checks, converts all coordinates into :class:`Vec3` + objects, represents "Polygon" always as tuple (exterior, holes) even + without holes. + + """ + if hasattr(geo_mapping, "__geo_interface__"): + geo_mapping = geo_mapping.__geo_interface__ + return cls(parse(geo_mapping)) + + @property + def root(self) -> GeoMapping: + return self._root + + @property + def geotype(self): + """Property returns the top level entity type or ``None``.""" + return self._root.get("type") + + def __copy__(self) -> GeoProxy: + """Returns a deep copy.""" + return copy.deepcopy(self) + + copy = __copy__ + + @property + def __geo_interface__(self) -> GeoMapping: + """Returns the ``__geo_interface__`` compatible mapping as + :class:`dict`. + """ + return _rebuild(self._root, self.places) + + def __iter__(self) -> Iterator[GeoMapping]: + """Iterate over all geometry entities. + + Yields only "Point", "LineString", "Polygon", "MultiPoint", + "MultiLineString" and "MultiPolygon" objects, returns the content of + "GeometryCollection", "FeatureCollection" and "Feature" as geometry + objects ("Point", ...). + + """ + + def _iter(node: GeoMapping) -> Iterator[GeoMapping]: + type_ = node[TYPE] + if type_ == FEATURE_COLLECTION: + for feature in node[FEATURES]: + yield from _iter(feature) + elif type_ == GEOMETRY_COLLECTION: + for geometry in node[GEOMETRIES]: + yield from _iter(geometry) + elif type_ == FEATURE: + geometry = node[GEOMETRY] + if geometry[TYPE] == GEOMETRY_COLLECTION: + yield from _iter(geometry) + else: + yield geometry + else: + yield node + + yield from _iter(self._root) + + def filter(self, func: Callable[[GeoProxy], bool]) -> None: + """Removes all mappings for which `func()` returns ``False``. + The function only has to handle Point, LineString and Polygon entities, + other entities like MultiPolygon are divided into separate entities + also any collection. + + """ + + def multi_entity(root, type_) -> bool: + coordinates = [] + for entity in root[COORDINATES]: + if func(GeoProxy({TYPE: type_, COORDINATES: entity})): + coordinates.append(entity) + root[COORDINATES] = coordinates + return bool(len(coordinates)) + + def check(root) -> bool: + type_ = root[TYPE] + if type_ == FEATURE_COLLECTION: + root[FEATURES] = [ + feature for feature in root[FEATURES] if check(feature) + ] + return bool(len(root[FEATURES])) + elif type_ == GEOMETRY_COLLECTION: + root[GEOMETRIES] = [ + geometry for geometry in root[GEOMETRIES] if check(geometry) + ] + return bool(len(root[GEOMETRIES])) + elif type_ == FEATURE: + root[GEOMETRY] = root[GEOMETRY] if check(root[GEOMETRY]) else {} + return bool(root[GEOMETRY]) + elif type_ == MULTI_POINT: + return multi_entity(root, POINT) + elif type_ == MULTI_LINE_STRING: + return multi_entity(root, LINE_STRING) + elif type_ == MULTI_POLYGON: + return multi_entity(root, POLYGON) + else: + return func(GeoProxy(root)) + + if not check(self._root): + self._root = {} + + def globe_to_map(self, func: Optional[TFunc] = None) -> None: + """Transform all coordinates recursive from globe representation + in longitude and latitude in decimal degrees into 2D map representation + in meters. + + Default is WGS84 `EPSG:4326 `_ (GPS) to WGS84 + `EPSG:3395 `_ World Mercator function + :func:`wgs84_4326_to_3395`. + + Use the `pyproj `_ package to write + a custom projection function as needed. + + Args: + func: custom transformation function, which takes one + :class:`Vec3` object as argument and returns the result as + a :class:`Vec3` object. + + """ + if func is None: + func = wgs84_4326_to_3395 + self.apply(func) + + def map_to_globe(self, func: Optional[TFunc] = None) -> None: + """Transform all coordinates recursive from 2D map representation in + meters into globe representation as longitude and latitude in decimal + degrees. + + Default is WGS84 `EPSG:3395 `_ World Mercator + to WGS84 `EPSG:4326 `_ GPS function + :func:`wgs84_3395_to_4326`. + + Use the `pyproj `_ package to write + a custom projection function as needed. + + Args: + func: custom transformation function, which takes one + :class:`Vec3` object as argument and returns the result as + a :class:`Vec3` object. + + """ + if func is None: + func = wgs84_3395_to_4326 + self.apply(func) + + def crs_to_wcs(self, crs: Matrix44) -> None: + """Transform all coordinates recursive from CRS into + :ref:`WCS` coordinates by transformation matrix `crs` inplace, + see also :meth:`GeoProxy.wcs_to_crs`. + + Args: + crs: transformation matrix of type :class:`~ezdxf.math.Matrix44` + + """ + self.apply(crs.ucs_vertex_from_wcs) + + def wcs_to_crs(self, crs: Matrix44) -> None: + """Transform all coordinates recursive from :ref:`WCS` coordinates into + Coordinate Reference System (CRS) by transformation matrix `crs` + inplace. + + The CRS is defined by the :class:`~ezdxf.entities.GeoData` entity, + get the :class:`GeoData` entity from the modelspace by method + :meth:`~ezdxf.layouts.Modelspace.get_geodata`. + The CRS transformation matrix can be acquired form the :class:`GeoData` + object by :meth:`~ezdxf.entities.GeoData.get_crs_transformation` method: + + .. code:: Python + + doc = ezdxf.readfile('file.dxf') + msp = doc.modelspace() + geodata = msp.get_geodata() + if geodata: + matrix, axis_ordering = geodata.get_crs_transformation() + + If `axis_ordering` is ``False`` the CRS is not compatible with the + ``__geo_interface__`` or GeoJSON (see chapter 3.1.1). + + Args: + crs: transformation matrix of type :class:`~ezdxf.math.Matrix44` + + """ + + self.apply(crs.transform) + + def apply(self, func: TFunc) -> None: + """Apply the transformation function `func` recursive to all + coordinates. + + Args: + func: transformation function as Callable[[Vec3], Vec3] + + """ + + def process(entity: GeoMapping): + def transform(coords): + if isinstance(coords, Vec3): + return func(coords) + else: + return [transform(c) for c in coords] + + entity[COORDINATES] = transform(entity[COORDINATES]) + + for entity in self.__iter__(): + process(entity) + + @classmethod + def from_dxf_entities( + cls, + entity: Union[DXFGraphic, Iterable[DXFGraphic]], + distance: float = MAX_FLATTENING_DISTANCE, + force_line_string: bool = False, + ) -> GeoProxy: + """Constructor from a single DXF entity or an iterable of DXF entities. + + Args: + entity: DXF entity or entities + distance: maximum flattening distance for curve approximations + force_line_string: by default this function returns Polygon objects for + closed geometries like CIRCLE, SOLID, closed POLYLINE and so on, + by setting argument `force_line_string` to ``True``, this entities + will be returned as LineString objects. + + """ + if isinstance(entity, DXFGraphic): + m = mapping(entity, distance, force_line_string) + else: + m = collection(entity, distance, force_line_string) + return cls(m) + + def to_dxf_entities( + self, + polygon=PolygonConversion.HATCH, + dxfattribs=None, + *, + post_process: Optional[PostProcessFunc] = None, + ) -> Iterator[DXFGraphic]: + """Returns stored ``__geo_interface__`` mappings as DXF entities. + + The `polygon` argument determines the method to convert polygons, + use 1 for :class:`~ezdxf.entities.Hatch` entity, 2 for + :class:`~ezdxf.entities.LWPolyline` or 3 for both. + Option 2 returns for the exterior path and each hole a separated + :class:`LWPolyline` entity. The :class:`Hatch` entity supports holes, + but has no explicit borderline. + + Yields :class:`Hatch` always before :class:`LWPolyline` entities. + + :class:`~ezdxf.entities.MPolygon` support was added in v0.16.6, which is + like a :class:`~ezdxf.entities.Hatch` entity with additional borderlines, + but the MPOLYGON entity is not a core DXF entity and DXF viewers, + applications and libraries my not support this entity. The DXF attribute + `color` defines the borderline color and `fill_color` the color of the + solid filling. + + The returned DXF entities can be added to a layout by the + :meth:`Layout.add_entity` method. + + Args: + polygon: see :class:`PolygonConversion` + dxfattribs: dict with additional DXF attributes + post_process: post process function of type :class:`PostProcesFunc` that get the + created DXF entity and the geo mapping as input, see reference implementation + :func:`assign_layers` + + """ + + def point(vertex: Sequence) -> Point: + point = cast(Point, factory.new("POINT", dxfattribs=dxfattribs)) + point.dxf.location = vertex + return point + + def lwpolyline(vertices: Sequence) -> LWPolyline: + polyline = cast( + LWPolyline, factory.new("LWPOLYLINE", dxfattribs=dxfattribs) + ) + polyline.append_points(vertices, format="xy") + return polyline + + def polygon_(exterior: list, holes: list) -> Iterator[DXFGraphic]: + if polygon == PolygonConversion.MPOLYGON: + yield mpolygon_(exterior, holes) + # the following DXF entities do not support the + # "fill_color" attribute + return + if polygon & PolygonConversion.HATCH: + yield hatch_(exterior, holes) + if polygon & PolygonConversion.POLYLINE: + for path in [exterior] + holes: + yield lwpolyline(path) + + def dxf_polygon_( + dxftype: str, exterior: Sequence, holes: Sequence + ) -> DXFPolygon: + dxf_polygon = cast(DXFPolygon, factory.new(dxftype, dxfattribs=dxfattribs)) + dxf_polygon.dxf.hatch_style = const.HATCH_STYLE_OUTERMOST + dxf_polygon.paths.add_polyline_path( + exterior, flags=const.BOUNDARY_PATH_EXTERNAL + ) + for hole in holes: + dxf_polygon.paths.add_polyline_path( + hole, flags=const.BOUNDARY_PATH_OUTERMOST + ) + return dxf_polygon + + def hatch_(exterior: Sequence, holes: Sequence) -> DXFPolygon: + return dxf_polygon_("HATCH", exterior, holes) + + def mpolygon_(exterior: Sequence, holes: Sequence) -> DXFPolygon: + return dxf_polygon_("MPOLYGON", exterior, holes) + + def entity(type_, coordinates) -> Iterator[DXFGraphic]: + if type_ == POINT: + yield point(coordinates) + elif type_ == LINE_STRING: + yield lwpolyline(coordinates) + elif type_ == POLYGON: + exterior, holes = coordinates + yield from polygon_(exterior, holes) + elif type_ == MULTI_POINT: + for data in coordinates: + yield point(data) + elif type_ == MULTI_LINE_STRING: + for data in coordinates: + yield lwpolyline(data) + elif type_ == MULTI_POLYGON: + for data in coordinates: + exterior, holes = data + yield from polygon_(exterior, holes) + + if polygon < 1 or polygon > 4: + raise ValueError(f"invalid value for polygon: {polygon}") + + dxfattribs = dict(dxfattribs or {}) + for feature, geometry in iter_features(self._root): + type_ = geometry.get(TYPE) + for e in entity(type_, geometry.get(COORDINATES)): + if post_process: + post_process(e, feature) + yield e + + +def iter_features(geo_mapping: GeoMapping) -> Iterator[tuple[GeoMapping, GeoMapping]]: + """Yields all geometries of a ``__geo_mapping__`` as (`feature`, `geometry`) tuples. + + If no feature is defined the `feature` value is an empty ``dict``. When a `feature` + contains `GeometryCollections`, the function yields for each sub-geometry a separate + (`feature`, `geometry`) tuple. + + """ + current_feature: GeoMapping = {} + + def features(node: GeoMapping) -> Iterator[tuple[GeoMapping, GeoMapping]]: + nonlocal current_feature + + type_ = node[TYPE] + if type_ == FEATURE_COLLECTION: + for feature in node[FEATURES]: + yield from features(feature) + elif type_ == GEOMETRY_COLLECTION: + for geometry in node[GEOMETRIES]: + yield from features(geometry) + elif type_ == FEATURE: + current_feature = node + geometry = node[GEOMETRY] + if geometry[TYPE] == GEOMETRY_COLLECTION: + yield from features(geometry) + else: + yield current_feature, geometry + else: + yield current_feature, node + + yield from features(geo_mapping) + + +def parse(geo_mapping: GeoMapping) -> GeoMapping: + """Parse ``__geo_interface__`` convert all coordinates into + :class:`Vec3` objects, Polygon['coordinates'] is always a + tuple (exterior, holes), holes maybe an empty list. + + """ + geo_mapping = copy.deepcopy(geo_mapping) + type_ = geo_mapping.get(TYPE) + if type_ is None: + raise ValueError(f'Required key "{TYPE}" not found.') + + if type_ == FEATURE_COLLECTION: + # It is possible for this array to be empty. + features = geo_mapping.get(FEATURES) + if features: + geo_mapping[FEATURES] = [parse(f) for f in features] + else: + raise ValueError(f'Missing key "{FEATURES}" in FeatureCollection.') + elif type_ == GEOMETRY_COLLECTION: + # It is possible for this array to be empty. + geometries = geo_mapping.get(GEOMETRIES) + if geometries: + geo_mapping[GEOMETRIES] = [parse(g) for g in geometries] + else: + raise ValueError(f'Missing key "{GEOMETRIES}" in GeometryCollection.') + elif type_ == FEATURE: + # The value of the geometry member SHALL be either a Geometry object + # or, in the case that the Feature is unlocated, a JSON null value. + if GEOMETRY in geo_mapping: + geometry = geo_mapping.get(GEOMETRY) + geo_mapping[GEOMETRY] = parse(geometry) if geometry else None + else: + raise ValueError(f'Missing key "{GEOMETRY}" in Feature.') + elif type_ in { + POINT, + LINE_STRING, + POLYGON, + MULTI_POINT, + MULTI_LINE_STRING, + MULTI_POLYGON, + }: + coordinates = geo_mapping.get(COORDINATES) + if coordinates is None: + raise ValueError(f'Missing key "{COORDINATES}" in {type_}.') + if type_ == POINT: + coordinates = Vec3(coordinates) + elif type_ in (LINE_STRING, MULTI_POINT): + coordinates = Vec3.list(coordinates) + elif type_ == POLYGON: + coordinates = _parse_polygon(coordinates) + elif type_ == MULTI_LINE_STRING: + coordinates = [Vec3.list(v) for v in coordinates] + elif type_ == MULTI_POLYGON: + coordinates = [_parse_polygon(v) for v in coordinates] + geo_mapping[COORDINATES] = coordinates + else: + raise TypeError(f'Invalid type "{type_}".') + return geo_mapping + + +def _is_coordinate_sequence(coordinates: Sequence) -> bool: + """Returns ``True`` for a sequence of coordinates like [(0, 0), (1, 0)] + and ``False`` for a sequence of sequences: + [[(0, 0), (1, 0)], [(2, 0), (3, 0)]] + """ + if not isinstance(coordinates, Sequence): + raise ValueError("Invalid coordinate sequence.") + if len(coordinates) == 0: + raise ValueError("Invalid coordinate sequence.") + first_item = coordinates[0] + if len(first_item) == 0: + raise ValueError("Invalid coordinate sequence.") + return isinstance(first_item[0], numbers.Real) + + +def _parse_polygon(coordinates: Sequence) -> Sequence: + """Returns polygon definition as tuple (exterior, [holes]).""" + if _is_coordinate_sequence(coordinates): + exterior = coordinates + holes: Sequence = [] + else: + exterior = coordinates[0] + holes = coordinates[1:] + return Vec3.list(exterior), [Vec3.list(h) for h in holes] + + +def _rebuild(geo_mapping: GeoMapping, places: int = 6) -> GeoMapping: + """Returns ``__geo_interface__`` compatible mapping as :class:`dict` from + compiled internal representation. + + """ + + def pnt(v: Vec3) -> tuple[float, float]: + return round(v.x, places), round(v.y, places) + + def _polygon(exterior, holes): + # For type "Polygon", the "coordinates" member MUST be an array of + # linear ring coordinate arrays. + return [[pnt(v) for v in ring] for ring in [exterior] + holes] + + geo_interface = dict(geo_mapping) + type_ = geo_interface[TYPE] + if type_ == FEATURE_COLLECTION: + geo_interface[FEATURES] = [_rebuild(f) for f in geo_interface[FEATURES]] + elif type_ == GEOMETRY_COLLECTION: + geo_interface[GEOMETRIES] = [_rebuild(g) for g in geo_interface[GEOMETRIES]] + elif type_ == FEATURE: + geo_interface[GEOMETRY] = _rebuild(geo_interface[GEOMETRY]) + elif type_ == POINT: + v = geo_interface[COORDINATES] + geo_interface[COORDINATES] = pnt(v) + elif type_ in (LINE_STRING, MULTI_POINT): + coordinates = geo_interface[COORDINATES] + geo_interface[COORDINATES] = [pnt(v) for v in coordinates] + elif type_ == MULTI_LINE_STRING: + coordinates = [] + for line in geo_interface[COORDINATES]: + coordinates.append([pnt(v) for v in line]) + elif type_ == POLYGON: + geo_interface[COORDINATES] = _polygon(*geo_interface[COORDINATES]) + elif type_ == MULTI_POLYGON: + geo_interface[COORDINATES] = [ + _polygon(exterior, holes) for exterior, holes in geo_interface[COORDINATES] + ] + return geo_interface + + +def mapping( + entity: DXFGraphic, + distance: float = MAX_FLATTENING_DISTANCE, + force_line_string: bool = False, +) -> GeoMapping: + """Create the compiled ``__geo_interface__`` mapping as :class:`dict` + for the given DXF `entity`, all coordinates are :class:`Vec3` objects and + represents "Polygon" always as tuple (exterior, holes) even without holes. + + + Internal API - result is **not** a valid ``_geo_interface__`` mapping! + + Args: + entity: DXF entity + distance: maximum flattening distance for curve approximations + force_line_string: by default this function returns Polygon objects for + closed geometries like CIRCLE, SOLID, closed POLYLINE and so on, + by setting argument `force_line_string` to ``True``, this entities + will be returned as LineString objects. + + """ + + dxftype = entity.dxftype() + if isinstance(entity, Point): + return {TYPE: POINT, COORDINATES: entity.dxf.location} + elif isinstance(entity, Line): + return line_string_mapping([entity.dxf.start, entity.dxf.end]) + elif isinstance(entity, Polyline): + if entity.is_3d_polyline or entity.is_2d_polyline: + # May contain arcs as bulge values: + path = make_path(entity) + points = list(path.flattening(distance)) + return _line_string_or_polygon_mapping(points, force_line_string) + else: + raise TypeError("Polymesh and Polyface not supported.") + elif isinstance(entity, LWPolyline): + # May contain arcs as bulge values: + path = make_path(entity) + points = list(path.flattening(distance)) + return _line_string_or_polygon_mapping(points, force_line_string) + elif dxftype in {"CIRCLE", "ARC", "ELLIPSE", "SPLINE"}: + return _line_string_or_polygon_mapping( + list(entity.flattening(distance)), force_line_string # type: ignore + ) + elif dxftype in {"SOLID", "TRACE", "3DFACE"}: + return _line_string_or_polygon_mapping( + entity.wcs_vertices(close=True), force_line_string # type: ignore + ) + elif isinstance(entity, DXFPolygon): + return _hatch_as_polygon(entity, distance, force_line_string) + else: + raise TypeError(dxftype) + + +def _line_string_or_polygon_mapping(points: list[Vec3], force_line_string: bool): + len_ = len(points) + if len_ < 2: + raise ValueError("Invalid vertex count.") + if len_ == 2 or force_line_string: + return line_string_mapping(points) + else: + if is_linear_ring(points): + return polygon_mapping(points, []) + else: + return line_string_mapping(points) + + +def _hatch_as_polygon( + hatch: DXFPolygon, distance: float, force_line_string: bool +) -> GeoMapping: + def boundary_to_vertices(boundary) -> list[Vec3]: + path = from_hatch_boundary_path(boundary, ocs, elevation) + return path_to_vertices(path) + + def path_to_vertices(path) -> list[Vec3]: + path.close() + return list(path.flattening(distance)) + + # Path vertex winding order can be ignored here, validation and + # correction is done in polygon_mapping(). + + elevation = hatch.dxf.elevation.z + ocs = hatch.ocs() + hatch_style = hatch.dxf.hatch_style + + # Returns boundaries in EXTERNAL, OUTERMOST and DEFAULT order and filters + # unused boundaries according the hatch style: + boundaries = list(hatch.paths.rendering_paths(hatch_style)) + count = len(boundaries) + if count == 0: + raise ValueError(f"{hatch.dxftype()} without any boundary path.") + # Take first path as exterior path, multiple EXTERNAL paths are possible + exterior = boundaries[0] + if count == 1 or hatch_style == const.HATCH_STYLE_IGNORE: + points = boundary_to_vertices(exterior) + return _line_string_or_polygon_mapping(points, force_line_string) + else: + if force_line_string: + # Build a MultiString collection: + points = boundary_to_vertices(exterior) + geometries = [_line_string_or_polygon_mapping(points, force_line_string)] + # All other boundary paths are treated as holes + for hole in boundaries[1:]: + points = boundary_to_vertices(hole) + geometries.append( + _line_string_or_polygon_mapping(points, force_line_string) + ) + return join_multi_single_type_mappings(geometries) + else: + # Multiple separated polygons are possible in one HATCH entity: + polygons = [] + for exterior, holes in _boundaries_to_polygons(boundaries, ocs, elevation): + points = path_to_vertices(exterior) + polygons.append( + polygon_mapping(points, [path_to_vertices(hole) for hole in holes]) + ) + if len(polygons) > 1: + return join_multi_single_type_mappings(polygons) + return polygons[0] + + +def _boundaries_to_polygons(boundaries, ocs, elevation): + paths = ( + from_hatch_boundary_path(boundary, ocs, elevation) for boundary in boundaries + ) + for polygon in make_polygon_structure(paths): + exterior = polygon[0] + # only take exterior path of level 1 holes, nested holes are ignored + yield exterior, [hole[0] for hole in polygon[1:]] + + +def collection( + entities: Iterable[DXFGraphic], + distance: float = MAX_FLATTENING_DISTANCE, + force_line_string: bool = False, +) -> GeoMapping: + """Create the ``__geo_interface__`` mapping as :class:`dict` for the + given DXF `entities`, see https://gist.github.com/sgillies/2217756 + + Returns a "MultiPoint", "MultiLineString" or "MultiPolygon" collection if + all entities return the same GeoJSON type ("Point", "LineString", "Polygon") + else a "GeometryCollection". + + Internal API - result is **not** a valid ``_geo_interface__`` mapping! + + Args: + entities: iterable of DXF entities + distance: maximum flattening distance for curve approximations + force_line_string: by default this function returns "Polygon" objects for + closed geometries like CIRCLE, SOLID, closed POLYLINE and so on, + by setting argument `force_line_string` to ``True``, this entities + will be returned as "LineString" objects. + """ + m = [mapping(e, distance, force_line_string) for e in entities] + types = set(g[TYPE] for g in m) + if len(types) > 1: + return geometry_collection_mapping(m) + else: + return join_multi_single_type_mappings(m) + + +def line_string_mapping(points: list[Vec3]) -> GeoMapping: + """Returns a "LineString" mapping. + + .. code:: + + { + "type": "LineString", + "coordinates": [ + (100.0, 0.0), + (101.0, 1.0) + ] + } + """ + + return {TYPE: LINE_STRING, COORDINATES: points} + + +def is_linear_ring(points: list[Vec3]): + return points[0].isclose(points[-1]) + + +# GeoJSON : A linear ring MUST follow the right-hand rule with respect +# to the area it bounds, i.e., exterior rings are counterclockwise, and +# holes are clockwise. +def linear_ring(points: list[Vec3], ccw=True) -> list[Vec3]: + """Return `points` as linear ring (last vertex == first vertex), + argument `ccw` defines the winding orientation, ``True`` for counter-clock + wise and ``False`` for clock wise. + + """ + if len(points) < 3: + raise ValueError(f"Invalid vertex count: {len(points)}") + if not points[0].isclose(points[-1]): + points.append(points[0]) + + if has_clockwise_orientation(points): + if ccw: + points.reverse() + else: + if not ccw: + points.reverse() + + return points + + +def polygon_mapping(points: list[Vec3], holes: list[list[Vec3]]) -> GeoMapping: + """Returns a "Polygon" mapping. + + .. code:: + + { + "type": "Polygon", + "coordinates": [ + [ + (100.0, 0.0), + (101.0, 0.0), + (101.0, 1.0), + (100.0, 1.0), + (100.0, 0.0) + ], + [ + (100.8, 0.8), + (100.8, 0.2), + (100.2, 0.2), + (100.2, 0.8), + (100.8, 0.8) + ] + ] + } + """ + + exterior = linear_ring(points, ccw=True) + if holes: + holes = [linear_ring(hole, ccw=False) for hole in holes] + rings = exterior, holes + else: + rings = exterior, [] + return { + TYPE: POLYGON, + COORDINATES: rings, + } + + +def join_multi_single_type_mappings(geometries: Iterable[GeoMapping]) -> GeoMapping: + """Returns multiple geometries as a "MultiPoint", "MultiLineString" or + "MultiPolygon" mapping. + """ + types = set() + data = list() + for g in geometries: + types.add(g[TYPE]) + data.append(g[COORDINATES]) + + if len(types) > 1: + raise TypeError(f"Type mismatch: {str(types)}") + elif len(types) == 0: + return dict() + else: + return {TYPE: "Multi" + tuple(types)[0], COORDINATES: data} + + +def geometry_collection_mapping(geometries: Iterable[GeoMapping]) -> GeoMapping: + """Returns multiple geometries as a "GeometryCollection" mapping.""" + return {TYPE: GEOMETRY_COLLECTION, GEOMETRIES: list(geometries)} + + +# Values stored in GeoData RSS tag are not precise enough to match +# control calculation at epsg.io: +# Semi Major Axis: 6.37814e+06 +# Semi Minor Axis: 6.35675e+06 + +WGS84_SEMI_MAJOR_AXIS = 6378137 +WGS84_SEMI_MINOR_AXIS = 6356752.3142 +WGS84_ELLIPSOID_ECCENTRIC = math.sqrt( + 1.0 - WGS84_SEMI_MINOR_AXIS**2 / WGS84_SEMI_MAJOR_AXIS**2 +) +CONST_E2 = math.e / 2.0 +CONST_PI_2 = math.pi / 2.0 +CONST_PI_4 = math.pi / 4.0 + + +def wgs84_4326_to_3395(location: Vec3) -> Vec3: + """Transform WGS84 `EPSG:4326 `_ location given as + latitude and longitude in decimal degrees as used by GPS into World Mercator + cartesian 2D coordinates in meters `EPSG:3395 `_. + + Args: + location: :class:`Vec3` object, x-attribute represents the longitude + value (East-West) in decimal degrees and the y-attribute + represents the latitude value (North-South) in decimal degrees. + """ + return Vec3(gps_to_world_mercator(location.x, location.y)) + + +def wgs84_3395_to_4326(location: Vec3, tol: float = 1e-6) -> Vec3: + """Transform WGS84 World Mercator `EPSG:3395 `_ + location given as cartesian 2D coordinates x, y in meters into WGS84 decimal + degrees as longitude and latitude `EPSG:4326 `_ as + used by GPS. + + Args: + location: :class:`Vec3` object, z-axis is ignored + tol: accuracy for latitude calculation + + """ + return Vec3(world_mercator_to_gps(location.x, location.y, tol)) + + +def dms2dd(d: float, m: float = 0, s: float = 0) -> float: + """Convert degree, minutes, seconds into decimal degrees.""" + dd = d + float(m) / 60 + float(s) / 3600 + return dd + + +def dd2dms(dd: float) -> tuple[float, float, float]: + """Convert decimal degrees into degree, minutes, seconds.""" + m, s = divmod(dd * 3600, 60) + d, m = divmod(m, 60) + return d, m, s + + +def assign_layers(entity: DXFGraphic, mapping: GeoMapping) -> None: + """Reference implementation for a :func:`post_process` function. + + .. seealso:: + + :func:`dxf_entities` + + """ + properties = mapping.get(PROPERTIES) + if properties is None: + return + layer = properties.get("layer") + if layer: + entity.dxf.layer = layer diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/gerber_D6673.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/gerber_D6673.py new file mode 100644 index 0000000..440c6f9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/gerber_D6673.py @@ -0,0 +1,69 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +# This add-on was created to solve this problem: https://github.com/mozman/ezdxf/discussions/789 +from __future__ import annotations +from typing import TextIO +import os +import io + +import ezdxf +from ezdxf.document import Drawing +from ezdxf.layouts import Modelspace +from ezdxf.lldxf.tagwriter import TagWriter, AbstractTagWriter + +__all__ = ["export_file", "export_stream"] + + +def export_file(doc: Drawing, filename: str | os.PathLike) -> None: + """Exports the specified DXF R12 document, which should contain content conforming + to the ASTM-D6673-10 standard, in a special way so that Gerber Technology applications + can parse it by their low-quality DXF parser. + """ + fp = io.open(filename, mode="wt", encoding="ascii", errors="dxfreplace") + export_stream(doc, fp) + + +def export_stream(doc: Drawing, stream: TextIO) -> None: + """Exports the specified DXF R12 document into a `stream` object.""" + + if doc.dxfversion != ezdxf.const.DXF12: + raise ezdxf.DXFVersionError("only DXF R12 format is supported") + tagwriter = TagWriter(stream, write_handles=False, dxfversion=ezdxf.const.DXF12) + _export_sections(doc, tagwriter) + + +def _export_sections(doc: Drawing, tagwriter: AbstractTagWriter) -> None: + _export_header(tagwriter) + _export_blocks(doc, tagwriter) + _export_entities(doc.modelspace(), tagwriter) + + +def _export_header(tagwriter: AbstractTagWriter) -> None: + # export empty header section + tagwriter.write_str(" 0\nSECTION\n 2\nHEADER\n") + tagwriter.write_tag2(0, "ENDSEC") + + +def _export_blocks(doc: Drawing, tagwriter: AbstractTagWriter) -> None: + # This is the important part: + # + # Gerber Technology applications have a bad DXF parser which do not accept DXF + # files that contain blocks without ASTM-D6673-10 content, such as the standard + # $MODEL_SPACE and $PAPER_SPACE block definitions. + # + # This is annoying but the presence of these blocks is NOT mandatory for + # the DXF R12 standard. + # + tagwriter.write_str(" 0\nSECTION\n 2\nBLOCKS\n") + for block_record in doc.block_records: + # export only BLOCK definitions, ignore LAYOUT definition blocks + if block_record.is_block_layout: + block_record.export_block_definition(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + + +def _export_entities(msp: Modelspace, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_str(" 0\nSECTION\n 2\nENTITIES\n") + msp.entity_space.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + tagwriter.write_tag2(0, "EOF") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__init__.py new file mode 100644 index 0000000..d769d6d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +# +# 1 plot unit (plu) = 0.025mm +# 40 plu = 1mm +# 1016 plu = 1 inch +# 3.39 plu = 1 dot @300 dpi diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..c5bdeb7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000..b94ae61 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/api.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/backend.cpython-312.pyc new file mode 100644 index 0000000..c798557 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/backend.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/deps.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/deps.cpython-312.pyc new file mode 100644 index 0000000..940eeb8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/deps.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/interpreter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/interpreter.cpython-312.pyc new file mode 100644 index 0000000..1eb4b8d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/interpreter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/page.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/page.cpython-312.pyc new file mode 100644 index 0000000..52c2e5a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/page.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/plotter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/plotter.cpython-312.pyc new file mode 100644 index 0000000..b959308 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/plotter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/polygon_buffer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/polygon_buffer.cpython-312.pyc new file mode 100644 index 0000000..59d371f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/polygon_buffer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/properties.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/properties.cpython-312.pyc new file mode 100644 index 0000000..ae7bca6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/properties.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/tokenizer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/tokenizer.cpython-312.pyc new file mode 100644 index 0000000..89587a6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/tokenizer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/viewer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/viewer.cpython-312.pyc new file mode 100644 index 0000000..47252d4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/__pycache__/viewer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/api.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/api.py new file mode 100644 index 0000000..5ecdf81 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/api.py @@ -0,0 +1,398 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import enum +from xml.etree import ElementTree as ET + +import ezdxf +from ezdxf.document import Drawing +from ezdxf import zoom, colors +from ezdxf.addons import xplayer +from ezdxf.addons.drawing import svg, layout, pymupdf, dxf +from ezdxf.addons.drawing.dxf import ColorMode + +from .tokenizer import hpgl2_commands +from .plotter import Plotter +from .interpreter import Interpreter +from .backend import Recorder, placement_matrix, Player + + +DEBUG = False +ENTER_HPGL2_MODE = b"%1B" + + +class Hpgl2Error(Exception): + """Base exception for the :mod:`hpgl2` add-on.""" + + pass + + +class Hpgl2DataNotFound(Hpgl2Error): + """No HPGL/2 data was found, maybe the "Enter HPGL/2 mode" escape sequence is missing.""" + + pass + + +class EmptyDrawing(Hpgl2Error): + """The HPGL/2 commands do not produce any content.""" + + pass + + +class MergeControl(enum.IntEnum): + NONE = 0 # print order + LUMINANCE = 1 # sort filled polygons by luminance + AUTO = 2 # guess best method + + +def to_dxf( + b: bytes, + *, + rotation: int = 0, + mirror_x: bool = False, + mirror_y: bool = False, + color_mode=ColorMode.RGB, + merge_control: MergeControl = MergeControl.AUTO, +) -> Drawing: + """ + Exports the HPGL/2 commands of the byte stream `b` as a DXF document. + + The page content is created at the origin of the modelspace and 1 drawing unit is 1 + plot unit (1 plu = 0.025mm) unless scaling values are provided. + + The content of HPGL files is intended to be plotted on white paper, therefore a white + filling will be added as background in color mode :attr:`RGB`. + + All entities are assigned to a layer according to the pen number with the name scheme + ``PEN_<###>``. In order to be able to process the file better, it is also possible to + assign the :term:`ACI` color by layer by setting the argument `color_mode` to + :attr:`ColorMode.ACI`, but then the RGB color is lost because the RGB color has + always the higher priority over the :term:`ACI`. + + The first paperspace layout "Layout1" of the DXF document is set up to print the entire + modelspace on one sheet, the size of the page is the size of the original plot file in + millimeters. + + HPGL/2's merge control works at the pixel level and cannot be replicated by DXF, + but to prevent fillings from obscuring text, the filled polygons are + sorted by luminance - this can be forced or disabled by the argument `merge_control`, + see also :class:`MergeControl` enum. + + Args: + b: plot file content as bytes + rotation: rotation angle of 0, 90, 180 or 270 degrees + mirror_x: mirror in x-axis direction + mirror_y: mirror in y-axis direction + color_mode: the color mode controls how color values are assigned to DXF entities, + see :class:`ColorMode` + merge_control: how to order filled polygons, see :class:`MergeControl` + + Returns: DXF document as instance of class :class:`~ezdxf.document.Drawing` + + """ + if rotation not in (0, 90, 180, 270): + raise ValueError("rotation angle must be 0, 90, 180, or 270") + + # 1st pass records output of the plotting commands and detects the bounding box + doc = ezdxf.new() + try: + player = record_plotter_output(b, merge_control) + except Hpgl2Error: + return doc + + bbox = player.bbox() + m = placement_matrix(bbox, -1 if mirror_x else 1, -1 if mirror_y else 1, rotation) + player.transform(m) + bbox = player.bbox() + msp = doc.modelspace() + dxf_backend = dxf.DXFBackend(msp, color_mode=color_mode) + bg_color = colors.RGB(255, 255, 255) + if color_mode == ColorMode.RGB: + doc.layers.add("BACKGROUND") + bg = dxf.add_background(msp, bbox, color=bg_color) + bg.dxf.layer = "BACKGROUND" + + # 2nd pass replays the plotting commands to plot the DXF + # exports the HPGL/2 content in plot units (plu) as modelspace: + # 1 plu = 0.025mm or 40 plu == 1mm + xplayer.hpgl2_to_drawing(player, dxf_backend, bg_color=bg_color.to_hex()) + del player + + if bbox.has_data: # non-empty page + zoom.window(msp, bbox.extmin, bbox.extmax) + dxf.update_extents(doc, bbox) + # paperspace is set up in mm: + dxf.setup_paperspace(doc, bbox) + return doc + + +def to_svg( + b: bytes, + *, + rotation: int = 0, + mirror_x: bool = False, + mirror_y: bool = False, + merge_control=MergeControl.AUTO, +) -> str: + """ + Exports the HPGL/2 commands of the byte stream `b` as SVG string. + + The plot units are mapped 1:1 to ``viewBox`` units and the size of image is the size + of the original plot file in millimeters. + + HPGL/2's merge control works at the pixel level and cannot be replicated by the + backend, but to prevent fillings from obscuring text, the filled polygons are + sorted by luminance - this can be forced or disabled by the argument `merge_control`, + see also :class:`MergeControl` enum. + + Args: + b: plot file content as bytes + rotation: rotation angle of 0, 90, 180 or 270 degrees + mirror_x: mirror in x-axis direction + mirror_y: mirror in y-axis direction + merge_control: how to order filled polygons, see :class:`MergeControl` + + Returns: SVG content as ``str`` + + """ + if rotation not in (0, 90, 180, 270): + raise ValueError("rotation angle must be 0, 90, 180, or 270") + # 1st pass records output of the plotting commands and detects the bounding box + try: + player = record_plotter_output(b, merge_control) + except Hpgl2Error: + return "" + + # transform content for the SVGBackend of the drawing add-on + bbox = player.bbox() + size = bbox.size + + # HPGL/2 uses (integer) plot units, 1 plu = 0.025mm or 1mm = 40 plu + width_in_mm = size.x / 40 + height_in_mm = size.y / 40 + + if rotation in (0, 180): + page = layout.Page(width_in_mm, height_in_mm) + else: + page = layout.Page(height_in_mm, width_in_mm) + # adjust rotation for y-axis mirroring + rotation += 180 + + # The SVGBackend expects coordinates in the range [0, output_coordinate_space] + max_plot_units = round(max(size.x, size.y)) + settings = layout.Settings(output_coordinate_space=max_plot_units) + m = layout.placement_matrix( + bbox, + sx=-1 if mirror_x else 1, + sy=1 if mirror_y else -1, # inverted y-axis + rotation=rotation, + page=page, + output_coordinate_space=settings.output_coordinate_space, + ) + player.transform(m) + + # 2nd pass replays the plotting commands on the SVGBackend of the drawing add-on + svg_backend = svg.SVGRenderBackend(page, settings) + xplayer.hpgl2_to_drawing(player, svg_backend, bg_color="#ffffff") + del player + xml = svg_backend.get_xml_root_element() + return ET.tostring(xml, encoding="unicode", xml_declaration=True) + + +def to_pdf( + b: bytes, + *, + rotation: int = 0, + mirror_x: bool = False, + mirror_y: bool = False, + merge_control=MergeControl.AUTO, +) -> bytes: + """ + Exports the HPGL/2 commands of the byte stream `b` as PDF data. + + The plot units (1 plu = 0.025mm) are converted to PDF units (1/72 inch) so the image + has the size of the original plot file. + + HPGL/2's merge control works at the pixel level and cannot be replicated by the + backend, but to prevent fillings from obscuring text, the filled polygons are + sorted by luminance - this can be forced or disabled by the argument `merge_control`, + see also :class:`MergeControl` enum. + + Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/ + + Args: + b: plot file content as bytes + rotation: rotation angle of 0, 90, 180 or 270 degrees + mirror_x: mirror in x-axis direction + mirror_y: mirror in y-axis direction + merge_control: how to order filled polygons, see :class:`MergeControl` + + Returns: PDF content as ``bytes`` + + """ + return _pymupdf( + b, + rotation=rotation, + mirror_x=mirror_x, + mirror_y=mirror_y, + merge_control=merge_control, + fmt="pdf", + ) + + +def to_pixmap( + b: bytes, + *, + rotation: int = 0, + mirror_x: bool = False, + mirror_y: bool = False, + merge_control=MergeControl.AUTO, + fmt: str = "png", + dpi: int = 96, +) -> bytes: + """ + Exports the HPGL/2 commands of the byte stream `b` as pixel image. + + Supported image formats: + + === ========================= + png Portable Network Graphics + ppm Portable Pixmap + pbm Portable Bitmap + === ========================= + + The plot units (1 plu = 0.025mm) are converted to dot per inch (dpi) so the image + has the size of the original plot file. + + HPGL/2's merge control works at the pixel level and cannot be replicated by the + backend, but to prevent fillings from obscuring text, the filled polygons are + sorted by luminance - this can be forced or disabled by the argument `merge_control`, + see also :class:`MergeControl` enum. + + Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/ + + Args: + b: plot file content as bytes + rotation: rotation angle of 0, 90, 180 or 270 degrees + mirror_x: mirror in x-axis direction + mirror_y: mirror in y-axis direction + merge_control: how to order filled polygons, see :class:`MergeControl` + fmt: image format + dpi: output resolution in dots per inch + + Returns: image content as ``bytes`` + + """ + fmt = fmt.lower() + if fmt not in pymupdf.SUPPORTED_IMAGE_FORMATS: + raise ValueError(f"image format '{fmt}' not supported") + return _pymupdf( + b, + rotation=rotation, + mirror_x=mirror_x, + mirror_y=mirror_y, + merge_control=merge_control, + fmt=fmt, + dpi=dpi, + ) + + +def _pymupdf( + b: bytes, + *, + rotation: int = 0, + mirror_x: bool = False, + mirror_y: bool = False, + merge_control=MergeControl.AUTO, + fmt: str = "pdf", + dpi=96, +) -> bytes: + if not pymupdf.is_pymupdf_installed: + print("Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/") + return b"" + + if rotation not in (0, 90, 180, 270): + raise ValueError("rotation angle must be 0, 90, 180, or 270") + # 1st pass records output of the plotting commands and detects the bounding box + try: + player = record_plotter_output(b, merge_control) + except Hpgl2Error: + return b"" + + # transform content for the SVGBackend of the drawing add-on + bbox = player.bbox() + size = bbox.size + + # HPGL/2 uses (integer) plot units, 1 plu = 0.025mm or 1mm = 40 plu + width_in_mm = size.x / 40 + height_in_mm = size.y / 40 + + if rotation in (0, 180): + page = layout.Page(width_in_mm, height_in_mm) + else: + page = layout.Page(height_in_mm, width_in_mm) + # adjust rotation for y-axis mirroring + rotation += 180 + + # The PDFBackend expects coordinates as pt = 1/72 inch; 1016 plu = 1 inch + max_plot_units = max(size.x, size.y) / 1016 * 72 + settings = layout.Settings(output_coordinate_space=max_plot_units) + m = layout.placement_matrix( + bbox, + sx=-1 if mirror_x else 1, + sy=-1 if mirror_y else 1, + rotation=rotation, + page=page, + output_coordinate_space=settings.output_coordinate_space, + ) + player.transform(m) + + # 2nd pass replays the plotting commands on the PyMuPdfBackend of the drawing add-on + pymupdf_backend = pymupdf.PyMuPdfBackend() + xplayer.hpgl2_to_drawing(player, pymupdf_backend, bg_color="#ffffff") + del player + if fmt == "pdf": + return pymupdf_backend.get_pdf_bytes(page, settings=settings) + else: + return pymupdf_backend.get_pixmap_bytes( + page, fmt=fmt, settings=settings, dpi=dpi + ) + + +def print_interpreter_log(interpreter: Interpreter) -> None: + print("HPGL/2 interpreter log:") + print(f"unsupported commands: {interpreter.not_implemented_commands}") + if interpreter.errors: + print("parsing errors:") + for err in interpreter.errors: + print(err) + + +def record_plotter_output( + b: bytes, + merge_control: MergeControl, +) -> Player: + commands = hpgl2_commands(b) + if len(commands) == 0: + print("HPGL2 data not found.") + raise Hpgl2DataNotFound + + recorder = Recorder() + plotter = Plotter(recorder) + interpreter = Interpreter(plotter) + interpreter.run(commands) + if DEBUG: + print_interpreter_log(interpreter) + player = recorder.player() + bbox = player.bbox() + if not bbox.has_data: + raise EmptyDrawing + + if merge_control == MergeControl.AUTO: + if plotter.has_merge_control: + merge_control = MergeControl.LUMINANCE + if merge_control == MergeControl.LUMINANCE: + if DEBUG: + print("merge control on: sorting filled polygons by luminance") + player.sort_filled_paths() + return player diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/backend.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/backend.py new file mode 100644 index 0000000..6cc02ec --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/backend.py @@ -0,0 +1,237 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, NamedTuple, Any, Iterator +from typing_extensions import Self +import abc +import copy +import enum +import math +from .deps import ( + Vec2, + Path, + colors, + Matrix44, + BoundingBox2d, +) +from .properties import Properties, Pen +from ezdxf.npshapes import NumpyPath2d, NumpyPoints2d + +# Page coordinates are always plot units: +# 1 plot unit (plu) = 0.025mm +# 40 plu = 1mm +# 1016 plu = 1 inch +# 3.39 plu = 1 dot @300 dpi +# positive x-axis is horizontal from left to right +# positive y-axis is vertical from bottom to top + + +class Backend(abc.ABC): + """Abstract base class for implementing a low level output backends.""" + + @abc.abstractmethod + def draw_polyline(self, properties: Properties, points: Sequence[Vec2]) -> None: + """Draws a polyline from a sequence `points`. The input coordinates are page + coordinates in plot units. The `points` sequence can contain 0 or more + points! + + Args: + properties: display :class:`Properties` for the polyline + points: sequence of :class:`ezdxf.math.Vec2` instances + + """ + ... + + @abc.abstractmethod + def draw_paths( + self, properties: Properties, paths: Sequence[Path], filled: bool + ) -> None: + """Draws filled or outline paths from the sequence of `paths`. The input coordinates + are page coordinates in plot units. The `paths` sequence can contain 0 or more + single :class:`~ezdxf.path.Path` instances. Draws outline paths if + Properties.FillType is NONE and filled paths otherwise. + + Args: + properties: display :class:`Properties` for the filled polygon + paths: sequence of single :class:`ezdxf.path.Path` instances + filled: draw filled paths if ``True`` otherwise outline paths + + """ + ... + + +class RecordType(enum.Enum): + POLYLINE = enum.auto() + FILLED_PATHS = enum.auto() + OUTLINE_PATHS = enum.auto() + + +class DataRecord(NamedTuple): + type: RecordType + property_hash: int + data: Any + + +class Recorder(Backend): + """The :class:`Recorder` class records the output of the :class:`Plotter` class. + + All input coordinates are page coordinates: + + - 1 plot unit (plu) = 0.025mm + - 40 plu = 1 mm + - 1016 plu = 1 inch + + """ + + def __init__(self) -> None: + self._records: list[DataRecord] = [] + self._properties: dict[int, Properties] = {} + self._pens: Sequence[Pen] = [] + + def player(self) -> Player: + """Returns a :class:`Player` instance with the original recordings. Make a copy + of this player to protect the original recordings from being modified:: + + safe_player = recorder.player().copy() + + """ + return Player(self._records, self._properties) + + def draw_polyline(self, properties: Properties, points: Sequence[Vec2]) -> None: + self.store(RecordType.POLYLINE, properties, NumpyPoints2d(points)) + + def draw_paths( + self, properties: Properties, paths: Sequence[Path], filled: bool + ) -> None: + data = tuple(map(NumpyPath2d, paths)) + record_type = RecordType.FILLED_PATHS if filled else RecordType.OUTLINE_PATHS + self.store(record_type, properties, data) + + def store(self, record_type: RecordType, properties: Properties, args) -> None: + prop_hash = properties.hash() + if prop_hash not in self._properties: + self._properties[prop_hash] = properties.copy() + self._records.append(DataRecord(record_type, prop_hash, args)) + if len(self._pens) != len(properties.pen_table): + self._pens = list(properties.pen_table.values()) + + +class Player: + """This class replays the recordings of the :class:`Recorder` class on another + backend. The class can modify the recorded output. + """ + + def __init__(self, records: list[DataRecord], properties: dict[int, Properties]): + self._records: list[DataRecord] = records + self._properties: dict[int, Properties] = properties + self._bbox = BoundingBox2d() + + def __copy__(self) -> Self: + """Returns a new :class:`Player` instance with a copy of recordings.""" + records = copy.deepcopy(self._records) + player = self.__class__(records, self._properties) + player._bbox = self._bbox.copy() + return player + + copy = __copy__ + + def recordings(self) -> Iterator[tuple[RecordType, Properties, Any]]: + """Yields all recordings as `(RecordType, Properties, Data)` tuples. + + The content of the `Data` field is determined by the enum :class:`RecordType`: + + - :attr:`RecordType.POLYLINE` returns a :class:`NumpyPoints2d` instance + - :attr:`RecordType.FILLED_POLYGON` returns a tuple of :class:`NumpyPath2d` instances + + """ + props = self._properties + for record in self._records: + yield record.type, props[record.property_hash], record.data + + def bbox(self) -> BoundingBox2d: + """Returns the bounding box of all recorded polylines and polygons as + :class:`~ezdxf.math.BoundingBox2d`. + """ + if not self._bbox.has_data: + self.update_bbox() + return self._bbox + + def update_bbox(self) -> None: + points: list[Vec2] = [] + for record in self._records: + if record.type == RecordType.POLYLINE: + points.extend(record.data.extents()) + else: + for path in record.data: + points.extend(path.extents()) + self._bbox = BoundingBox2d(points) + + def replay(self, backend: Backend) -> None: + """Replay the recording on another backend.""" + current_props = Properties() + props = self._properties + for record in self._records: + current_props = props.get(record.property_hash, current_props) + if record.type == RecordType.POLYLINE: + backend.draw_polyline(current_props, record.data.vertices()) + else: + paths = [p.to_path2d() for p in record.data] + backend.draw_paths( + current_props, paths, filled=record.type == RecordType.FILLED_PATHS + ) + + def transform(self, m: Matrix44) -> None: + """Transforms the recordings by a transformation matrix `m` of type + :class:`~ezdxf.math.Matrix44`. + """ + for record in self._records: + if record.type == RecordType.POLYLINE: + record.data.transform_inplace(m) + else: + for path in record.data: + path.transform_inplace(m) + + if self._bbox.has_data: + # fast, but maybe inaccurate update + self._bbox = BoundingBox2d(m.fast_2d_transform(self._bbox.rect_vertices())) + + def sort_filled_paths(self) -> None: + """Sort filled paths by descending luminance (from light to dark). + + This also changes the plot order in the way that all filled paths are plotted + before polylines and outline paths. + """ + fillings = [] + outlines = [] + current = Properties() + props = self._properties + for record in self._records: + if record.type == RecordType.FILLED_PATHS: + current = props.get(record.property_hash, current) + key = colors.luminance(current.resolve_fill_color()) + fillings.append((key, record)) + else: + outlines.append(record) + + fillings.sort(key=lambda r: r[0], reverse=True) + records = [sort_rec[1] for sort_rec in fillings] + records.extend(outlines) + self._records = records + + +def placement_matrix( + bbox: BoundingBox2d, sx: float = 1.0, sy: float = 1.0, rotation: float = 0.0 +) -> Matrix44: + """Returns a matrix to place the bbox in the first quadrant of the coordinate + system (+x, +y). + """ + if abs(sx) < 1e-9: + sx = 1.0 + if abs(sy) < 1e-9: + sy = 1.0 + m = Matrix44.scale(sx, sy, 1.0) + if rotation: + m @= Matrix44.z_rotate(math.radians(rotation)) + corners = m.fast_2d_transform(bbox.rect_vertices()) + tx, ty = BoundingBox2d(corners).extmin + return m @ Matrix44.translate(-tx, -ty, 0) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/deps.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/deps.py new file mode 100644 index 0000000..540ae64 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/deps.py @@ -0,0 +1,13 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +# +# Central import location of frontend dependencies. +# To extract te hpgl2 add-on from the ezdxf package, the following tools have to be +# implemented or extracted too. The dependencies of the implemented backends are not +# listed here. + +from ezdxf.math import Vec2, ConstructionCircle, BoundingBox2d, Bezier4P, AnyVec, Matrix44 +from ezdxf.path import Path, bbox as path_bbox, transform_paths +from ezdxf.tools.standards import PAGE_SIZES +from ezdxf import colors +NULLVEC2 = Vec2(0, 0) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/interpreter.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/interpreter.py new file mode 100644 index 0000000..0f9f8e1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/interpreter.py @@ -0,0 +1,458 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Iterable +import string + +from .deps import Vec2, NULLVEC2 +from .properties import RGB +from .plotter import Plotter +from .tokenizer import Command, pe_decode + + +class Interpreter: + """The :class:`Interpreter` is the frontend for the :class:`Plotter` class. + The :meth:`run` methods interprets the low level HPGL commands from the + :func:`hpgl2_commands` parser and sends the commands to the virtual plotter + device, which sends his output to a low level :class:`Backend` class. + + Most CAD application send a very restricted subset of commands to plotters, + mostly just polylines and filled polygons. Implementing the whole HPGL/2 command set + is not worth the effort - unless reality proofs otherwise. + + Not implemented commands: + + - the whole character group - text is send as filled polygons or polylines + - configuration group: IN, DF, RO, IW - the plotter is initialized by creating a + new plotter and page rotation is handled by the add-on itself + - polygon group: EA, ER, EW, FA, RR, WG, the rectangle and wedge commands + - line and fill attributes group: LA, RF, SM, SV, TR, UL, WU, linetypes and + hatch patterns are decomposed into simple lines by CAD applications + + Args: + plotter: virtual :class:`Plotter` device + + """ + def __init__(self, plotter: Plotter) -> None: + self.errors: list[str] = [] + self.not_implemented_commands: set[str] = set() + self._disabled_commands: set[str] = set() + self.plotter = plotter + + def add_error(self, error: str) -> None: + self.errors.append(error) + + def run(self, commands: list[Command]) -> None: + """Interprets the low level HPGL commands from the :func:`hpgl2_commands` parser + and sends the commands to the virtual plotter device. + """ + for name, args in commands: + if name in self._disabled_commands: + continue + method = getattr(self, f"cmd_{name.lower()}", None) + if method: + method(args) + elif name[0] in string.ascii_letters: + self.not_implemented_commands.add(name) + + def disable_commands(self, commands: Iterable[str]) -> None: + """Disable commands manually, like the scaling command ["SC", "IP", "IR"]. + This is a feature for experts, because disabling commands which changes the pen + location may distort or destroy the plotter output. + """ + self._disabled_commands.update(commands) + + # Configure pens, line types, fill types + def cmd_ft(self, args: list[bytes]): + """Set fill type.""" + fill_type = 1 + spacing = 0.0 + angle = 0.0 + values = tuple(to_floats(args)) + arg_count = len(values) + if arg_count > 0: + fill_type = int(values[0]) + if arg_count > 1: + spacing = values[1] + if arg_count > 2: + angle = values[2] + self.plotter.set_fill_type(fill_type, spacing, angle) + + def cmd_pc(self, args: list[bytes]): + """Set pen color as RGB tuple.""" + values = list(to_ints(args)) + if len(values) == 4: + index, r, g, b = values + self.plotter.set_pen_color(index, RGB(r, g, b)) + else: + self.add_error("invalid arguments for PC command") + + def cmd_pw(self, args: list[bytes]): + """Set pen width.""" + arg_count = len(args) + if arg_count: + width = to_float(args[0], 0.35) + else: + self.add_error("invalid arguments for PW command") + return + index = -1 + if arg_count > 1: + index = to_int(args[1], index) + self.plotter.set_pen_width(index, width) + + def cmd_sp(self, args: list[bytes]): + """Select pen.""" + if len(args): + self.plotter.set_current_pen(to_int(args[0], 1)) + + def cmd_np(self, args: list[bytes]): + """Set number of pens.""" + if len(args): + self.plotter.set_max_pen_count(to_int(args[0], 2)) + + def cmd_ip(self, args: list[bytes]): + """Set input points p1 and p2 absolute.""" + if len(args) == 0: + self.plotter.reset_scaling() + return + + points = to_points(to_floats(args)) + if len(points) > 1: + self.plotter.set_scaling_points(points[0], points[1]) + else: + self.add_error("invalid arguments for IP command") + + def cmd_ir(self, args: list[bytes]): + """Set input points p1 and p2 in percentage of page size.""" + if len(args) == 0: + self.plotter.reset_scaling() + return + + values = list(to_floats(args)) + if len(values) == 2: + xp1 = clamp(values[0], 0.0, 100.0) + yp1 = clamp(values[1], 0.0, 100.0) + self.plotter.set_scaling_points_relative_1(xp1 / 100.0, yp1 / 100.0) + elif len(values) == 4: + xp1 = clamp(values[0], 0.0, 100.0) + yp1 = clamp(values[1], 0.0, 100.0) + xp2 = clamp(values[2], 0.0, 100.0) + yp2 = clamp(values[3], 0.0, 100.0) + self.plotter.set_scaling_points_relative_2( + xp1 / 100.0, yp1 / 100.0, xp2 / 100.0, yp2 / 100.0 + ) + else: + self.add_error("invalid arguments for IP command") + + def cmd_sc(self, args: list[bytes]): + if len(args) == 0: + self.plotter.reset_scaling() + return + values = list(to_floats(args)) + if len(values) < 4: + self.add_error("invalid arguments for SC command") + return + scaling_type = 0 + if len(values) > 4: + scaling_type = int(values[4]) + if scaling_type == 1: # isotropic + left = 50.0 + if len(values) > 5: + left = clamp(values[5], 0.0, 100.0) + bottom = 50.0 + if len(values) > 6: + bottom = clamp(values[6], 0.0, 100.0) + self.plotter.set_isotropic_scaling( + values[0], + values[1], + values[2], + values[3], + left, + bottom, + ) + elif scaling_type == 2: # point factor + self.plotter.set_point_factor( + Vec2(values[0], values[2]), values[1], values[3] + ) + else: # anisotropic + self.plotter.set_anisotropic_scaling( + values[0], values[1], values[2], values[3] + ) + + def cmd_mc(self, args: list[bytes]): + status = 0 + if len(args): + status = to_int(args[0], status) + self.plotter.set_merge_control(bool(status)) + + def cmd_ps(self, args: list[bytes]): + length = 1189 # A0 + height = 841 + count = len(args) + if count: + length = to_int(args[0], length) + height = int(length * 1.5) + if count > 1: + height = to_int(args[1], height) + self.plotter.setup_page(length, height) + + # pen movement: + def cmd_pd(self, args: list[bytes]): + """Lower pen down and plot lines.""" + self.plotter.pen_down() + if len(args): + self.plotter.plot_polyline(to_points(to_floats(args))) + + def cmd_pu(self, args: list[bytes]): + """Lift pen up and move pen.""" + self.plotter.pen_up() + if len(args): + self.plotter.plot_polyline(to_points(to_floats(args))) + + def cmd_pa(self, args: list[bytes]): + """Place pen absolute. Plots polylines if pen is down.""" + self.plotter.set_absolute_mode() + if len(args): + self.plotter.plot_polyline(to_points(to_floats(args))) + + def cmd_pr(self, args: list[bytes]): + """Place pen relative.Plots polylines if pen is down.""" + self.plotter.set_relative_mode() + if len(args): + self.plotter.plot_polyline(to_points(to_floats(args))) + + # plot commands: + def cmd_ci(self, args: list[bytes]): + """Plot full circle.""" + arg_count = len(args) + if not arg_count: + self.add_error("invalid arguments for CI command") + return + self.plotter.push_pen_state() + # implicit pen down! + self.plotter.pen_down() + radius = to_float(args[0], 1.0) + chord_angle = 5.0 + if arg_count > 1: + chord_angle = to_float(args[1], chord_angle) + self.plotter.plot_abs_circle(radius, chord_angle) + self.plotter.pop_pen_state() + + def cmd_aa(self, args: list[bytes]): + """Plot arc absolute.""" + if len(args) < 3: + self.add_error("invalid arguments for AR command") + return + self._arc_out(args, self.plotter.plot_abs_arc) + + def cmd_ar(self, args: list[bytes]): + """Plot arc relative.""" + if len(args) < 3: + self.add_error("invalid arguments for AR command") + return + self._arc_out(args, self.plotter.plot_rel_arc) + + @staticmethod + def _arc_out(args: list[bytes], output_method): + """Plot arc""" + arg_count = len(args) + if arg_count < 3: + return + x = to_float(args[0]) + y = to_float(args[1]) + sweep_angle = to_float(args[2]) + chord_angle = 5.0 + if arg_count > 3: + chord_angle = to_float(args[3], chord_angle) + output_method(Vec2(x, y), sweep_angle, chord_angle) + + def cmd_at(self, args: list[bytes]): + """Plot arc absolute from three points.""" + if len(args) < 4: + self.add_error("invalid arguments for AT command") + return + self._arc_3p_out(args, self.plotter.plot_abs_arc_three_points) + + def cmd_rt(self, args: list[bytes]): + """Plot arc relative from three points.""" + if len(args) < 4: + self.add_error("invalid arguments for RT command") + return + self._arc_3p_out(args, self.plotter.plot_rel_arc_three_points) + + @staticmethod + def _arc_3p_out(args: list[bytes], output_method): + """Plot arc from three points""" + arg_count = len(args) + if arg_count < 4: + return + points = to_points(to_floats(args)) + if len(points) < 2: + return + chord_angle = 5.0 + if arg_count > 4: + chord_angle = to_float(args[4], chord_angle) + try: + output_method(points[0], points[1], chord_angle) + except ZeroDivisionError: + pass + + def cmd_bz(self, args: list[bytes]): + """Plot cubic Bezier curves with absolute user coordinates.""" + self._bezier_out(args, self.plotter.plot_abs_cubic_bezier) + + def cmd_br(self, args: list[bytes]): + """Plot cubic Bezier curves with relative user coordinates.""" + self._bezier_out(args, self.plotter.plot_rel_cubic_bezier) + + @staticmethod + def _bezier_out(args: list[bytes], output_method): + kind = 0 + ctrl1 = NULLVEC2 + ctrl2 = NULLVEC2 + for point in to_points(to_floats(args)): + if kind == 0: + ctrl1 = point + elif kind == 1: + ctrl2 = point + elif kind == 2: + end = point + output_method(ctrl1, ctrl2, end) + kind = (kind + 1) % 3 + + def cmd_pe(self, args: list[bytes]): + """Plot Polyline Encoded.""" + if len(args): + data = args[0] + else: + self.add_error("invalid arguments for PE command") + return + + plotter = self.plotter + # The last pen up/down state remains after leaving the PE command. + pen_down = True + # Ignores and preserves the current absolute/relative mode of the plotter. + absolute = False + frac_bin_bits = 0 + base = 64 + index = 0 + length = len(data) + point_queue: list[Vec2] = [] + + while index < length: + char = data[index] + if char in b":<>=7": + index += 1 + if char == 58: # ":" - select pen + values, index = pe_decode(data, base=base, start=index) + plotter.set_current_pen(int(values[0])) + if len(values) > 1: + point_queue.extend(to_points(values[1:])) + elif char == 60: # "<" - pen up and goto coordinates + pen_down = False + elif char == 62: # ">" - fractional data + values, index = pe_decode(data, base=base, start=index) + frac_bin_bits = int(values[0]) + if len(values) > 1: + point_queue.extend(to_points(values[1:])) + elif char == 61: # "=" - next coordinates are absolute + absolute = True + elif char == 55: # "7" - 7-bit mode + base = 32 + else: + values, index = pe_decode( + data, frac_bits=frac_bin_bits, base=base, start=index + ) + point_queue.extend(to_points(values)) + + if point_queue: + plotter.pen_down() + if absolute: + # next point is absolute: make relative + point_queue[0] = point_queue[0] - plotter.user_location + if not pen_down: + target = point_queue.pop(0) + plotter.move_to_rel(target) + if not point_queue: # last point in queue + plotter.pen_up() + if point_queue: + plotter.plot_rel_polyline(point_queue) + point_queue.clear() + pen_down = True + absolute = False + + # polygon mode: + def cmd_pm(self, args: list[bytes]) -> None: + """Enter/Exit polygon mode.""" + status = 0 + if len(args): + status = to_int(args[0], status) + if status == 2: + self.plotter.exit_polygon_mode() + else: + self.plotter.enter_polygon_mode(status) + + def cmd_fp(self, args: list[bytes]) -> None: + """Plot filled polygon.""" + fill_method = 0 + if len(args): + fill_method = one_of(to_int(args[0], fill_method), (0, 1)) + self.plotter.fill_polygon(fill_method) + + def cmd_ep(self, _) -> None: + """Plot edged polygon.""" + self.plotter.edge_polygon() + + +def to_floats(args: Iterable[bytes]) -> Iterator[float]: + for arg in args: + try: + yield float(arg) + except ValueError: + pass + + +def to_ints(args: Iterable[bytes]) -> Iterator[int]: + for arg in args: + try: + yield int(arg) + except ValueError: + pass + + +def to_points(values: Iterable[float]) -> list[Vec2]: + points: list[Vec2] = [] + append_point = False + buffer: float = 0.0 + for value in values: + if append_point: + points.append(Vec2(buffer, value)) + append_point = False + else: + buffer = value + append_point = True + return points + + +def to_float(s: bytes, default=0.0) -> float: + try: + return float(s) + except ValueError: + return default + + +def to_int(s: bytes, default=0) -> int: + try: + return int(s) + except ValueError: + return default + + +def clamp(v, v_min, v_max): + return max(min(v_max, v), v_min) + + +def one_of(value, choice): + if value in choice: + return value + return choice[0] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/page.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/page.py new file mode 100644 index 0000000..96cba09 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/page.py @@ -0,0 +1,134 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +# 1 plot unit (plu) = 0.025mm +# 40 plu = 1 mm +# 1016 plu = 1 inch +# 3.39 plu = 1 dot @300 dpi + +from __future__ import annotations +from typing import Sequence +import math +from .deps import Vec2, NULLVEC2 + +INCH_TO_PLU = 1016 +MM_TO_PLU = 40 + + +class Page: + def __init__(self, size_x: int, size_y: int): + self.size_x = int(size_x) # in plotter units (plu) + self.size_y = int(size_y) # plu + + self.p1 = NULLVEC2 # plu + self.p2 = Vec2(size_x, size_y) + self.user_scaling = False + self.user_scale_x: float = 1.0 + self.user_scale_y: float = 1.0 + self.user_origin = NULLVEC2 # plu + + def set_scaling_points(self, p1: Vec2, p2: Vec2) -> None: + self.reset_scaling() + self.p1 = Vec2(p1) + self.p2 = Vec2(p2) + + def apply_scaling_factors(self, sx: float, sy: float) -> None: + self.set_ucs(self.user_origin, self.user_scale_x * sx, self.user_scale_y * sy) + + def set_scaling_points_relative_1(self, xp1: float, yp1: float) -> None: + size = self.p2 - self.p1 + p1 = Vec2(self.size_x * xp1, self.size_y * yp1) + self.set_scaling_points(p1, p1 + size) + + def set_scaling_points_relative_2( + self, xp1: float, yp1: float, xp2: float, yp2: float + ) -> None: + p1 = Vec2(self.size_x * xp1, self.size_y * yp1) + p2 = Vec2(self.size_x * xp2, self.size_y * yp2) + self.set_scaling_points(p1, p2) + + def reset_scaling(self) -> None: + self.p1 = NULLVEC2 + self.p2 = Vec2(self.size_x, self.size_y) + self.set_ucs(NULLVEC2) + + def set_isotropic_scaling( + self, + x_min: float, + x_max: float, + y_min: float, + y_max: float, + left=0.5, + bottom=0.5, + ) -> None: + size = self.p2 - self.p1 + delta_x = x_max - x_min + delta_y = y_max - y_min + scale_x = 1.0 + if abs(delta_x) > 1e-9: + scale_x = size.x / delta_x + scale_y = 1.0 + if abs(delta_y) > 1e-9: + scale_y = size.y / delta_y + + scale = min(abs(scale_x), abs(scale_y)) + scale_x = math.copysign(scale, scale_x) + scale_y = math.copysign(scale, scale_y) + offset_x = (size.x - delta_x * scale_x) * left + offset_y = (size.y - delta_y * scale_y) * bottom + origin_x = self.p1.x + offset_x - x_min * scale_x + origin_y = self.p1.y + offset_y - y_min * scale_y + self.set_ucs(Vec2(origin_x, origin_y), scale_x, scale_y) + + def set_anisotropic_scaling( + self, x_min: float, x_max: float, y_min: float, y_max: float + ) -> None: + size = self.p2 - self.p1 + delta_x = x_max - x_min + delta_y = y_max - y_min + scale_x = 1.0 + if abs(delta_x) > 1e-9: + scale_x = size.x / delta_x + scale_y = 1.0 + if abs(delta_y) > 1e-9: + scale_y = size.y / delta_y + origin_x = self.p1.x - x_min * scale_x + origin_y = self.p1.y - y_min * scale_y + self.set_ucs(Vec2(origin_x, origin_y), scale_x, scale_y) + + def set_ucs(self, origin: Vec2, sx: float = 1.0, sy: float = 1.0): + self.user_origin = Vec2(origin) + self.user_scale_x = float(sx) + self.user_scale_y = float(sy) + if abs(self.user_scale_x) < 1e-6: + self.user_scale_x = 1.0 + if abs(self.user_scale_y) < 1e-6: + self.user_scale_y = 1.0 + if math.isclose(self.user_scale_x, 1.0) and math.isclose( + self.user_scale_y, 1.0 + ): + self.user_scaling = False + else: + self.user_scaling = True + + def page_point(self, x: float, y: float) -> Vec2: + """Returns the page location as page point in plotter units.""" + return self.page_vector(x, y) + self.user_origin + + def page_vector(self, x: float, y: float) -> Vec2: + """Returns the user vector in page vector in plotter units.""" + if self.user_scaling: + x = self.user_scale_x * x + y = self.user_scale_y * y + return Vec2(x, y) + + def page_points(self, points: Sequence[Vec2]) -> list[Vec2]: + """Returns all user points as page points in plotter units.""" + return [self.page_point(p.x, p.y) for p in points] + + def page_vectors(self, vectors: Sequence[Vec2]) -> list[Vec2]: + """Returns all user vectors as page vectors in plotter units.""" + return [self.page_vector(p.x, p.y) for p in vectors] + + def scale_length(self, length: float) -> tuple[float, float]: + """Scale a length in user units to plotter units, scaling can be non-uniform.""" + return length * self.user_scale_x, length * self.user_scale_y diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/plotter.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/plotter.py new file mode 100644 index 0000000..9ab9f47 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/plotter.py @@ -0,0 +1,315 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterator +import math + +from .deps import ( + Vec2, + Path, + NULLVEC2, + ConstructionCircle, + Bezier4P, +) +from .properties import RGB, Properties, FillType +from .backend import Backend +from .polygon_buffer import PolygonBuffer +from .page import Page + + +class Plotter: + """ + The :class:`Plotter` class represents a virtual plotter device. + + The HPGL/2 commands send by the :class:`Interpreter` are processed into simple + polylines and filled polygons and send to low level :class:`Backend`. + + HPGL/2 uses a units system called "Plot Units": + + - 1 plot unit (plu) = 0.025mm + - 40 plu = 1 mm + - 1016 plu = 1 inch + + The Plotter device does not support font rendering and page rotation (RO). + The scaling commands IP, RP, SC are supported. + + """ + def __init__(self, backend: Backend) -> None: + self.backend = backend + self._output_backend = backend + self._polygon_buffer = PolygonBuffer() + self.page = Page(1189, 841) + self.properties = Properties() + self.is_pen_down = False + self.is_absolute_mode = True + self.is_polygon_mode = False + self.has_merge_control = False + self._user_location = NULLVEC2 + self._pen_state_stack: list[bool] = [] + + @property + def user_location(self) -> Vec2: + """Returns the current pen location as point in the user coordinate system.""" + return self._user_location + + @property + def page_location(self) -> Vec2: + """Returns the current pen location as page point in plotter units.""" + location = self.user_location + return self.page.page_point(location.x, location.y) + + def setup_page(self, size_x: int, size_y: int): + self.page = Page(size_x, size_y) + + def set_scaling_points(self, p1: Vec2, p2: Vec2) -> None: + self.page.set_scaling_points(p1, p2) + + def set_scaling_points_relative_1(self, xp1: float, yp1: float) -> None: + self.page.set_scaling_points_relative_1(xp1, yp1) + + def set_scaling_points_relative_2( + self, xp1: float, yp1: float, xp2: float, yp2: float + ) -> None: + self.page.set_scaling_points_relative_2(xp1, yp1, xp2, yp2) + + def reset_scaling(self) -> None: + self.page.reset_scaling() + + def set_point_factor(self, origin: Vec2, scale_x: float, scale_y: float) -> None: + self.page.set_ucs(origin, scale_x, scale_y) + + def set_isotropic_scaling( + self, + x_min: float, + x_max: float, + y_min: float, + y_max: float, + left=0.5, + bottom=0.5, + ) -> None: + self.page.set_isotropic_scaling(x_min, x_max, y_min, y_max, left, bottom) + + def set_anisotropic_scaling( + self, x_min: float, x_max: float, y_min: float, y_max: float + ) -> None: + self.page.set_anisotropic_scaling(x_min, x_max, y_min, y_max) + + def set_merge_control(self, status: bool) -> None: + self.has_merge_control = status + + def pen_up(self) -> None: + self.is_pen_down = False + + def pen_down(self) -> None: + self.is_pen_down = True + + def push_pen_state(self) -> None: + self._pen_state_stack.append(self.is_pen_down) + + def pop_pen_state(self) -> None: + if len(self._pen_state_stack): + self.is_pen_down = self._pen_state_stack.pop() + + def move_to(self, location: Vec2) -> None: + if self.is_absolute_mode: + self.move_to_abs(location) + else: + self.move_to_rel(location) + + def move_to_abs(self, user_location: Vec2) -> None: + self._user_location = user_location + + def move_to_rel(self, user_location: Vec2) -> None: + self._user_location += user_location + + def set_absolute_mode(self) -> None: + self.is_absolute_mode = True + + def set_relative_mode(self) -> None: + self.is_absolute_mode = False + + def set_current_pen(self, index: int) -> None: + self.properties.set_current_pen(index) + + def set_max_pen_count(self, index: int) -> None: + self.properties.set_max_pen_count(index) + + def set_pen_width(self, index: int, width: float) -> None: + self.properties.set_pen_width(index, width) + + def set_pen_color(self, index: int, color: RGB) -> None: + self.properties.set_pen_color(index, color) + + def set_fill_type(self, fill_type: int, spacing: float, angle: float) -> None: + if fill_type in (3, 4): # adjust spacing between hatching lines + spacing = max(self.page.scale_length(spacing)) + self.properties.set_fill_type(fill_type, spacing, angle) + + def enter_polygon_mode(self, status: int) -> None: + self.is_polygon_mode = True + self.backend = self._polygon_buffer + if status == 0: + self._polygon_buffer.reset(self.page_location) + elif status == 1: + self._polygon_buffer.close_path() + + def exit_polygon_mode(self) -> None: + self.is_polygon_mode = False + self._polygon_buffer.close_path() + self.backend = self._output_backend + + def fill_polygon(self, fill_method: int) -> None: + self.properties.set_fill_method(fill_method) + self.plot_filled_polygon_buffer(self._polygon_buffer.get_paths()) + + def edge_polygon(self) -> None: + self.plot_outline_polygon_buffer(self._polygon_buffer.get_paths()) + + def plot_polyline(self, points: Sequence[Vec2]): + if not points: + return + if self.is_absolute_mode: + self.plot_abs_polyline(points) + else: + self.plot_rel_polyline(points) + + def plot_abs_polyline(self, points: Sequence[Vec2]): + # input coordinates are user coordinates + if not points: + return + current_page_location = self.page_location + self.move_to_abs(points[-1]) # user coordinates! + if self.is_pen_down: + # convert to page coordinates: + points = self.page.page_points(points) + # insert current page location as starting point: + points.insert(0, current_page_location) + # draw polyline in absolute page coordinates: + self.backend.draw_polyline(self.properties, points) + + def plot_rel_polyline(self, points: Sequence[Vec2]): + # input coordinates are user coordinates + if not points: + return + # convert to absolute user coordinates: + self.plot_abs_polyline( + tuple(rel_to_abs_points_dynamic(self.user_location, points)) + ) + + def plot_abs_circle(self, radius: float, chord_angle: float): + # radius in user units + if self.is_pen_down: + center = self.user_location + vertices = [ + center + Vec2.from_deg_angle(a, radius) + for a in arc_angles(0, 360.0, chord_angle) + ] + # draw circle in absolute page coordinates: + self.backend.draw_polyline(self.properties, vertices) + + def plot_abs_arc(self, center: Vec2, sweep_angle: float, chord_angle: float): + start_point = self.user_location + radius_vec = start_point - center + radius = radius_vec.magnitude + start_angle = radius_vec.angle_deg + end_angle = start_angle + sweep_angle + end_point = center + Vec2.from_deg_angle(end_angle, radius) + + self.move_to_abs(end_point) + if self.is_pen_down: + vertices = [ + center + Vec2.from_deg_angle(a, radius) + for a in arc_angles(start_angle, sweep_angle, chord_angle) + ] + self.backend.draw_polyline(self.properties, vertices) + + def plot_rel_arc(self, center_rel: Vec2, sweep_angle: float, chord_angle: float): + self.plot_abs_arc(center_rel + self.user_location, sweep_angle, chord_angle) + + def plot_abs_arc_three_points(self, inter: Vec2, end: Vec2, chord_angle: float): + # input coordinates are user coordinates + start = self.user_location + circle = ConstructionCircle.from_3p(start, inter, end) + center = circle.center + start_angle = (start - center).angle_deg + end_angle = (end - center).angle_deg + inter_angle = (inter - center).angle_deg + sweep_angle = sweeping_angle(start_angle, inter_angle, end_angle) + self.plot_abs_arc(center, sweep_angle, chord_angle) + + def plot_rel_arc_three_points(self, inter: Vec2, end: Vec2, chord_angle: float): + # input coordinates are user coordinates + current = self.user_location + self.plot_abs_arc_three_points(current + inter, current + end, chord_angle) + + def plot_abs_cubic_bezier(self, ctrl1: Vec2, ctrl2: Vec2, end: Vec2): + # input coordinates are user coordinates + current_page_location = self.page_location + self.move_to_abs(end) # user coordinates! + if self.is_pen_down: + # convert to page coordinates: + ctrl1, ctrl2, end = self.page.page_points((ctrl1, ctrl2, end)) + # draw cubic bezier curve in absolute page coordinates: + p = Path(current_page_location) + p.curve4_to(end, ctrl1, ctrl2) + self.backend.draw_paths(self.properties, [p], filled=False) + + def plot_rel_cubic_bezier(self, ctrl1: Vec2, ctrl2: Vec2, end: Vec2): + # input coordinates are user coordinates + ctrl1, ctrl2, end = rel_to_abs_points_static( + self.user_location, (ctrl1, ctrl2, end) + ) + self.plot_abs_cubic_bezier(ctrl1, ctrl2, end) + + def plot_filled_polygon_buffer(self, paths: Sequence[Path]): + # input coordinates are page coordinates! + self.backend.draw_paths(self.properties, paths, filled=True) + + def plot_outline_polygon_buffer(self, paths: Sequence[Path]): + # input coordinates are page coordinates! + self.backend.draw_paths(self.properties, paths, filled=False) + + +def rel_to_abs_points_dynamic(current: Vec2, points: Sequence[Vec2]) -> Iterator[Vec2]: + """Returns the absolute location of increment points, each point is an increment + of the previous point starting at the current pen location. + """ + for point in points: + current += point + yield current + + +def rel_to_abs_points_static(current: Vec2, points: Sequence[Vec2]) -> Iterator[Vec2]: + """Returns the absolute location of increment points, all points are relative + to the current pen location. + """ + for point in points: + yield current + point + + +def arc_angles(start: float, sweep_angle: float, chord_angle: float) -> Iterator[float]: + # clamp to 0.5 .. 180 + chord_angle = min(180.0, max(0.5, chord_angle)) + count = abs(round(sweep_angle / chord_angle)) + delta = sweep_angle / count + for index in range(count + 1): + yield start + delta * index + + +def sweeping_angle(start: float, intermediate: float, end: float) -> float: + """Returns the sweeping angle from start angle to end angle passing the + intermediate angle. + """ + start = start % 360.0 + intermediate = intermediate % 360.0 + end = end % 360.0 + angle = end - start + i_to_s = start - intermediate + i_to_e = end - intermediate + if math.isclose(abs(i_to_e) + abs(i_to_s), abs(angle)): + return angle + else: # return complementary angle with opposite orientation + if angle < 0: + return 360.0 + angle + else: + return angle - 360.0 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/polygon_buffer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/polygon_buffer.py new file mode 100644 index 0000000..ced0dde --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/polygon_buffer.py @@ -0,0 +1,53 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence +from .backend import Backend +from .deps import Vec2, Path +from .properties import Properties + + +class PolygonBuffer(Backend): + def __init__(self): + self.path = Path() + self.start_new_sub_polygon = False + + def draw_polyline(self, properties: Properties, points: Sequence[Vec2]) -> None: + if len(points) == 0: + return + index = 0 + if self.start_new_sub_polygon: + self.start_new_sub_polygon = False + count = len(points) + while self.path.end.isclose(points[index]): + index += 1 + if index == count: + return + self.path.move_to(points[index]) + for p in points[index + 1 :]: + self.path.line_to(p) + + def draw_paths( + self, properties: Properties, paths: Sequence[Path], filled: bool + ) -> None: + if filled: + raise NotImplementedError() + for p in paths: + if len(p) == 0: + continue + if self.start_new_sub_polygon: + self.start_new_sub_polygon = False + self.path.move_to(p.start) + self.path.append_path(p) + + def get_paths(self) -> Sequence[Path]: + return list(self.path.sub_paths()) + + def close_path(self): + if len(self.path): + self.path.close_sub_path() + self.start_new_sub_polygon = True + + def reset(self, location: Vec2) -> None: + self.path = Path(location) + self.start_new_sub_polygon = False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/properties.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/properties.py new file mode 100644 index 0000000..2e6c1d1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/properties.py @@ -0,0 +1,175 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import dataclasses +import enum +import copy +from ezdxf.colors import RGB + + +class FillType(enum.IntEnum): + """Fill type enumeration.""" + + NONE = 0 + SOLID = 1 + HATCHING = 2 + CROSS_HATCHING = 3 + SHADING = 4 + + +class FillMethod(enum.IntEnum): + """Fill method enumeration.""" + + EVEN_ODD = 0 + NON_ZERO_WINDING = 1 + + +RGB_NONE = RGB(-1, -1, -1) +RGB_BLACK = RGB(0, 0, 0) +RGB_WHITE = RGB(255, 255, 255) +LIGHT_GREY = RGB(200, 200, 200) + + +@dataclasses.dataclass +class Pen: + """Represents a pen table entry.""" + + index: int + width: float # in mm + color: RGB + + +class Properties: + """Consolidated display properties.""" + + DEFAULT_PEN = Pen(1, 0.35, RGB_NONE) + + def __init__(self) -> None: + # hashed content + self.pen_index: int = 1 + self.pen_color = RGB_NONE + self.pen_width: float = 0.35 # in mm + self.fill_type = FillType.SOLID + self.fill_method = FillMethod.EVEN_ODD + self.fill_hatch_line_angle: float = 0.0 # in degrees + self.fill_hatch_line_spacing: float = 40.0 # in plotter units + self.fill_shading_density: float = 100.0 + # not hashed content + self.max_pen_count: int = 2 + self.pen_table: dict[int, Pen] = {} + self.reset() + + def hash(self) -> int: + return hash( + ( + self.pen_index, + self.pen_color, + self.pen_width, + self.fill_type, + self.fill_method, + self.fill_hatch_line_angle, + self.fill_hatch_line_spacing, + self.fill_shading_density, + ) + ) + + def copy(self) -> Properties: + # the pen table is shared across all copies of Properties + return copy.copy(self) + + def setup_default_pen_table(self): + if len(self.pen_table): + return + pens = self.pen_table + width = self.DEFAULT_PEN.width + pens[0] = Pen(0, width, RGB(255, 255, 255)) # white + pens[1] = Pen(1, width, RGB(0, 0, 0)) # black + pens[2] = Pen(2, width, RGB(255, 0, 0)) # red + pens[3] = Pen(3, width, RGB(0, 255, 0)) # green + pens[4] = Pen(4, width, RGB(255, 255, 0)) # yellow + pens[5] = Pen(5, width, RGB(0, 0, 255)) # blue + pens[6] = Pen(6, width, RGB(255, 0, 255)) # magenta + pens[7] = Pen(6, width, RGB(0, 255, 255)) # cyan + + def reset(self) -> None: + self.max_pen_count = 2 + self.pen_index = self.DEFAULT_PEN.index + self.pen_color = self.DEFAULT_PEN.color + self.pen_width = self.DEFAULT_PEN.width + self.pen_table = {} + self.fill_type = FillType.SOLID + self.fill_method = FillMethod.EVEN_ODD + self.fill_hatch_line_angle = 0.0 + self.fill_hatch_line_spacing = 40.0 + self.fill_shading_density = 1.0 + self.setup_default_pen_table() + + def get_pen(self, index: int) -> Pen: + return self.pen_table.get(index, self.DEFAULT_PEN) + + def set_max_pen_count(self, count: int) -> None: + self.max_pen_count = count + + def set_current_pen(self, index: int) -> None: + self.pen_index = index + pen = self.get_pen(index) + self.pen_width = pen.width + self.pen_color = pen.color + + def set_pen_width(self, index: int, width: float) -> None: + if index == -1: + self.pen_width = width + else: + pen = self.pen_table.setdefault( + index, Pen(index, width, self.DEFAULT_PEN.color) + ) + pen.width = width + + def set_pen_color(self, index: int, rgb: RGB) -> None: + if index == -1: + self.pen_color = rgb + else: + pen = self.pen_table.setdefault( + index, Pen(index, self.DEFAULT_PEN.width, rgb) + ) + pen.color = rgb + + def set_fill_type(self, fill_type: int, spacing: float, angle: float): + if fill_type == 3: + self.fill_type = FillType.HATCHING + self.fill_hatch_line_spacing = spacing + self.fill_hatch_line_angle = angle + elif fill_type == 4: + self.fill_type = FillType.CROSS_HATCHING + self.fill_hatch_line_spacing = spacing + self.fill_hatch_line_angle = angle + elif fill_type == 10: + self.fill_type = FillType.SHADING + self.fill_shading_density = spacing + else: + self.fill_type = FillType.SOLID + + def set_fill_method(self, fill_method: int) -> None: + self.fill_method = FillMethod(fill_method) + + def resolve_pen_color(self) -> RGB: + """Returns the final RGB pen color.""" + rgb = self.pen_color + if rgb is RGB_NONE: + pen = self.pen_table.get(self.pen_index, self.DEFAULT_PEN) + rgb = pen.color + if rgb is RGB_NONE: + return RGB_BLACK + return rgb + + def resolve_fill_color(self) -> RGB: + """Returns the final RGB fill color.""" + ft = self.fill_type + if ft == FillType.SOLID: + return self.resolve_pen_color() + elif ft == FillType.SHADING: + grey = min(int(2.55 * (100.0 - self.fill_shading_density)), 255) + return RGB(grey, grey, grey) + elif ft == FillType.HATCHING or ft == FillType.CROSS_HATCHING: + return LIGHT_GREY + return RGB_WHITE diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/tokenizer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/tokenizer.py new file mode 100644 index 0000000..1ea23bc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/tokenizer.py @@ -0,0 +1,224 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import NamedTuple, Sequence + + +class Command(NamedTuple): + name: str + args: Sequence[bytes] + + +ESCAPE = 27 +SEMICOLON = ord(";") +PERCENT = ord("%") +MINUS = ord("-") +QUOTE_CHAR = ord('"') +CHAR_A = ord("A") +CHAR_B = ord("B") +CHAR_Z = ord("Z") +DEFAULT_TEXT_TERMINATOR = 3 + +# Enter HPGL/2 mode commands +# b"%-0B", # ??? not documented (assumption) +# b"%-1B", # ??? not documented (really exist) +# b"%-2B", # ??? not documented (assumption) +# b"%-3B", # ??? not documented (assumption) +# b"%0B", # documented in the HPGL2 reference by HP +# b"%1B", # documented +# b"%2B", # documented +# b"%3B", # documented + + +def get_enter_hpgl2_mode_command_length(s: bytes, i: int) -> int: + try: + if s[i] != ESCAPE: + return 0 + if s[i + 1] != PERCENT: + return 0 + length = 4 + if s[i + 2] == MINUS: + i += 1 + length = 5 + # 0, 1, 2 or 3 + "B" + if 47 < s[i + 2] < 52 and s[i + 3] == CHAR_B: + return length + except IndexError: + pass + return 0 + + +KNOWN_START_SEQUENCES = [b"BPIN", b"BP;IN", b"INPS", b"IN;PS", b"INDF", b"IN;DF"] + + +def has_known_start_sequence(b: bytes) -> bool: + for start_sequence in KNOWN_START_SEQUENCES: + if b.startswith(start_sequence): + return True + return False + + +def find_hpgl2_entry_point(s: bytes, start: int) -> int: + while True: + try: + index = s.index(b"%", start) + except ValueError: + return len(s) + length = get_enter_hpgl2_mode_command_length(s, index) + if length: + return index + length + start += 2 + + +def hpgl2_commands(s: bytes) -> list[Command]: + """Low level plot file parser, extracts the HPGL/2 from the byte stream `b`. + + .. Important:: + + This parser expects the "Enter HPGL/2 mode" escape sequence to recognize + HPGL/2 commands. The sequence looks like this: ``[ESC]%1B``, multiple variants + of this sequence are supported. + + """ + text_terminator = DEFAULT_TEXT_TERMINATOR + + def find_terminator(i: int) -> int: + while i < length: + c = s[i] + if c == QUOTE_CHAR: + i = find_mark(i + 1, QUOTE_CHAR) + elif (CHAR_A <= c <= CHAR_Z) or c == SEMICOLON or c == ESCAPE: + break + i += 1 + return i + + def find_mark(i: int, mark: int) -> int: + while i < length and s[i] != mark: + i += 1 + return i + 1 + + def append_command(b: bytes) -> None: + if b[:2] == b"DT": + nonlocal text_terminator + if len(b) > 2: + text_terminator = b[2] + else: + text_terminator = DEFAULT_TEXT_TERMINATOR + else: + commands.append(make_command(b)) + + commands: list[Command] = [] + length = len(s) + if has_known_start_sequence(s): + index = 0 + else: + index = find_hpgl2_entry_point(s, 0) + while index < length: + char = s[index] + start = index + + if char == ESCAPE: + # HPGL/2 does not use escape sequences, whatever this sequence is, + # HPGL/2 mode was left. Find next entry point into HPGL/2 mode: + index = find_hpgl2_entry_point(s, index) + continue + + if char <= 32: # skip all white space and control chars between commands + index += 1 + continue + + index_plus_2 = index + 2 + if index_plus_2 >= length: + append_command(s[index:]) + break + + command = s[start:index_plus_2] + + if command == b"PE": + index = find_mark(index_plus_2, SEMICOLON) + index -= 1 # exclude terminator ";" from command args + elif command == b"LB": + index = find_mark(index_plus_2, text_terminator) + # include special terminator in command args, + # otherwise the parser is confused + else: + index = find_terminator(index_plus_2) + + append_command(s[start:index]) + if index < length and s[index] == SEMICOLON: + index += 1 + return commands + + +def make_command(cmd: bytes) -> Command: + if not cmd: + return Command("NOOP", tuple()) + name = cmd[:2].decode() + if name == "PE": + args = (bytes([c for c in cmd[2:] if c > 32]),) + else: + args = tuple(s for s in cmd[2:].split(b",")) # type: ignore + return Command(name, args) + + +def fractional_bits(decimal_places: int) -> int: + return round(decimal_places * 3.33) + + +def pe_encode(value: float, frac_bits: int = 0, base: int = 64) -> bytes: + if frac_bits: + value *= 1 << frac_bits + x = round(value) + else: + x = round(value) + if x >= 0: + x *= 2 + else: + x = abs(x) * 2 + 1 + + chars = bytearray() + while x >= base: + x, r = divmod(x, base) + chars.append(63 + r) + if base == 64: + chars.append(191 + x) + else: + chars.append(95 + x) + return bytes(chars) + + +def pe_decode( + s: bytes, frac_bits: int = 0, base=64, start: int = 0 +) -> tuple[list[float], int]: + def _decode(): + factors.reverse() + x = 0 + for f in factors: + x = x * base + f + factors.clear() + if x & 1: + x = -(x - 1) + x = x >> 1 + return x + + n = 1 << frac_bits + if base == 64: + terminator = 191 + else: + terminator = 95 + values: list[float] = [] + factors = [] + for index in range(start, len(s)): + value = s[index] + if value < 63: + return values, index + if value >= terminator: + factors.append(value - terminator) + x = _decode() + if frac_bits: + values.append(x / n) + else: + values.append(float(x)) + else: + factors.append(value - 63) + return values, len(s) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/viewer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/viewer.py new file mode 100644 index 0000000..e3550db --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/hpgl2/viewer.py @@ -0,0 +1,522 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, TYPE_CHECKING + +import math +import os +import pathlib + +from ezdxf.addons import xplayer +from ezdxf.addons.xqt import QtWidgets, QtGui, QtCore, QMessageBox +from ezdxf.addons.drawing import svg, layout, pymupdf, dxf +from ezdxf.addons.drawing.qtviewer import CADGraphicsView +from ezdxf.addons.drawing.pyqt import PyQtPlaybackBackend + +from . import api +from .deps import BoundingBox2d, Matrix44, colors + +if TYPE_CHECKING: + from ezdxf.document import Drawing + +VIEWER_NAME = "HPGL/2 Viewer" + + +class HPGL2Widget(QtWidgets.QWidget): + def __init__(self, view: CADGraphicsView) -> None: + super().__init__() + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(view) + self.setLayout(layout) + self._view = view + self._view.closing.connect(self.close) + self._player: api.Player = api.Player([], {}) + self._reset_backend() + + def _reset_backend(self) -> None: + self._backend = PyQtPlaybackBackend() + + @property + def view(self) -> CADGraphicsView: + return self._view + + @property + def player(self) -> api.Player: + return self._player.copy() + + def plot(self, data: bytes) -> None: + self._reset_backend() + self._player = api.record_plotter_output(data, api.MergeControl.AUTO) + + def replay( + self, bg_color="#ffffff", override=None, reset_view: bool = True + ) -> None: + self._reset_backend() + self._view.begin_loading() + new_scene = QtWidgets.QGraphicsScene() + self._backend.set_scene(new_scene) + new_scene.addItem(self._bg_paper(bg_color)) + + xplayer.hpgl2_to_drawing( + self._player, self._backend, bg_color="", override=override + ) + self._view.end_loading(new_scene) + self._view.buffer_scene_rect() + if reset_view: + self._view.fit_to_scene() + + def _bg_paper(self, color): + bbox = self._player.bbox() + insert = bbox.extmin + size = bbox.size + rect = QtWidgets.QGraphicsRectItem(insert.x, insert.y, size.x, size.y) + rect.setBrush(QtGui.QBrush(QtGui.QColor(color))) + return rect + + +SPACING = 20 +DEFAULT_DPI = 96 +COLOR_SCHEMA = [ + "Default", + "Black on White", + "White on Black", + "Monochrome Light", + "Monochrome Dark", + "Blueprint High Contrast", + "Blueprint Low Contrast", +] + + +class HPGL2Viewer(QtWidgets.QMainWindow): + def __init__(self) -> None: + super().__init__() + self._cad = HPGL2Widget(CADGraphicsView()) + self._view = self._cad.view + self._player: api.Player = api.Player([], {}) + self._bbox: BoundingBox2d = BoundingBox2d() + self._page_rotation = 0 + self._color_scheme = 0 + self._current_file = pathlib.Path() + + self.page_size_label = QtWidgets.QLabel() + self.png_size_label = QtWidgets.QLabel() + self.message_label = QtWidgets.QLabel() + self.scaling_factor_line_edit = QtWidgets.QLineEdit("1") + self.dpi_line_edit = QtWidgets.QLineEdit(str(DEFAULT_DPI)) + + self.flip_x_check_box = QtWidgets.QCheckBox("Horizontal") + self.flip_x_check_box.setCheckState(QtCore.Qt.CheckState.Unchecked) + self.flip_x_check_box.stateChanged.connect(self.update_view) + + self.flip_y_check_box = QtWidgets.QCheckBox("Vertical") + self.flip_y_check_box.setCheckState(QtCore.Qt.CheckState.Unchecked) + self.flip_y_check_box.stateChanged.connect(self.update_view) + + self.rotation_combo_box = QtWidgets.QComboBox() + self.rotation_combo_box.addItems(["0", "90", "180", "270"]) + self.rotation_combo_box.currentIndexChanged.connect(self.update_rotation) + + self.color_combo_box = QtWidgets.QComboBox() + self.color_combo_box.addItems(COLOR_SCHEMA) + self.color_combo_box.currentIndexChanged.connect(self.update_colors) + + self.aci_export_mode = QtWidgets.QCheckBox("ACI Export Mode") + self.aci_export_mode.setCheckState(QtCore.Qt.CheckState.Unchecked) + + self.export_svg_button = QtWidgets.QPushButton("Export SVG") + self.export_svg_button.clicked.connect(self.export_svg) + self.export_png_button = QtWidgets.QPushButton("Export PNG") + self.export_png_button.clicked.connect(self.export_png) + self.export_pdf_button = QtWidgets.QPushButton("Export PDF") + self.export_pdf_button.clicked.connect(self.export_pdf) + self.export_dxf_button = QtWidgets.QPushButton("Export DXF") + self.export_dxf_button.clicked.connect(self.export_dxf) + self.disable_export_buttons(True) + + self.scaling_factor_line_edit.editingFinished.connect(self.update_sidebar) + self.dpi_line_edit.editingFinished.connect(self.update_sidebar) + + layout = QtWidgets.QHBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + + container = QtWidgets.QWidget() + container.setLayout(layout) + self.setCentralWidget(container) + + layout.addWidget(self._cad) + sidebar = self.make_sidebar() + layout.addWidget(sidebar) + self.setWindowTitle(VIEWER_NAME) + self.resize(1600, 900) + self.show() + + def reset_values(self): + self.scaling_factor_line_edit.setText("1") + self.dpi_line_edit.setText(str(DEFAULT_DPI)) + self.flip_x_check_box.setCheckState(QtCore.Qt.CheckState.Unchecked) + self.flip_y_check_box.setCheckState(QtCore.Qt.CheckState.Unchecked) + self.rotation_combo_box.setCurrentIndex(0) + self._page_rotation = 0 + self.update_view() + + def make_sidebar(self) -> QtWidgets.QWidget: + sidebar = QtWidgets.QWidget() + v_layout = QtWidgets.QVBoxLayout() + v_layout.setContentsMargins(SPACING // 2, 0, SPACING // 2, 0) + sidebar.setLayout(v_layout) + + policy = QtWidgets.QSizePolicy() + policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Policy.Fixed) + sidebar.setSizePolicy(policy) + + open_button = QtWidgets.QPushButton("Open HPGL/2 File") + open_button.clicked.connect(self.select_plot_file) + v_layout.addWidget(open_button) + v_layout.addWidget(self.page_size_label) + h_layout = QtWidgets.QHBoxLayout() + h_layout.addWidget(QtWidgets.QLabel("Scaling Factor:")) + h_layout.addWidget(self.scaling_factor_line_edit) + v_layout.addLayout(h_layout) + + h_layout = QtWidgets.QHBoxLayout() + h_layout.addWidget(QtWidgets.QLabel("Page Rotation:")) + h_layout.addWidget(self.rotation_combo_box) + v_layout.addLayout(h_layout) + + group = QtWidgets.QGroupBox("Mirror Page") + h_layout = QtWidgets.QHBoxLayout() + h_layout.addWidget(self.flip_x_check_box) + h_layout.addWidget(self.flip_y_check_box) + group.setLayout(h_layout) + v_layout.addWidget(group) + + h_layout = QtWidgets.QHBoxLayout() + h_layout.addWidget(QtWidgets.QLabel("Colors:")) + h_layout.addWidget(self.color_combo_box) + v_layout.addLayout(h_layout) + + v_layout.addSpacing(SPACING) + + h_layout = QtWidgets.QHBoxLayout() + h_layout.addWidget(QtWidgets.QLabel("DPI (PNG only):")) + h_layout.addWidget(self.dpi_line_edit) + v_layout.addLayout(h_layout) + v_layout.addWidget(self.png_size_label) + + v_layout.addWidget(self.export_png_button) + v_layout.addWidget(self.export_svg_button) + v_layout.addWidget(self.export_pdf_button) + + v_layout.addSpacing(SPACING) + + v_layout.addWidget(self.aci_export_mode) + v_layout.addWidget(self.export_dxf_button) + + v_layout.addSpacing(SPACING) + + reset_button = QtWidgets.QPushButton("Reset") + reset_button.clicked.connect(self.reset_values) + v_layout.addWidget(reset_button) + + v_layout.addSpacing(SPACING) + + v_layout.addWidget(self.message_label) + return sidebar + + def disable_export_buttons(self, disabled: bool): + self.export_svg_button.setDisabled(disabled) + self.export_dxf_button.setDisabled(disabled) + if pymupdf.is_pymupdf_installed: + self.export_png_button.setDisabled(disabled) + self.export_pdf_button.setDisabled(disabled) + else: + print("PDF/PNG export requires the PyMuPdf package!") + self.export_png_button.setDisabled(True) + self.export_pdf_button.setDisabled(True) + + def load_plot_file(self, path: str | os.PathLike, force=False) -> None: + try: + with open(path, "rb") as fp: + data = fp.read() + if force: + data = b"%1B" + data + self.set_plot_data(data, path) + except IOError as e: + QtWidgets.QMessageBox.critical(self, "Loading Error", str(e)) + + def select_plot_file(self) -> None: + path, _ = QtWidgets.QFileDialog.getOpenFileName( + self, + dir=str(self._current_file.parent), + caption="Select HPGL/2 Plot File", + filter="Plot Files (*.plt)", + ) + if path: + self.load_plot_file(path) + + def set_plot_data(self, data: bytes, filename: str | os.PathLike) -> None: + try: + self._cad.plot(data) + except api.Hpgl2Error as e: + msg = f"Cannot plot HPGL/2 file '{filename}', {str(e)}" + QtWidgets.QMessageBox.critical(self, "Plot Error", msg) + return + self._player = self._cad.player + self._bbox = self._player.bbox() + self._current_file = pathlib.Path(filename) + self.update_colors(self._color_scheme) + self.update_sidebar() + self.setWindowTitle(f"{VIEWER_NAME} - " + str(filename)) + self.disable_export_buttons(False) + + def resizeEvent(self, event: QtGui.QResizeEvent) -> None: + self._view.fit_to_scene() + + def get_scale_factor(self) -> float: + try: + return float(self.scaling_factor_line_edit.text()) + except ValueError: + return 1.0 + + def get_dpi(self) -> int: + try: + return int(self.dpi_line_edit.text()) + except ValueError: + return DEFAULT_DPI + + def get_page_size(self) -> tuple[int, int]: + factor = self.get_scale_factor() + x = 0 + y = 0 + if self._bbox.has_data: + size = self._bbox.size + # 40 plot units = 1mm + x = round(size.x / 40 * factor) + y = round(size.y / 40 * factor) + if self._page_rotation in (90, 270): + x, y = y, x + return x, y + + def get_pixel_size(self) -> tuple[int, int]: + dpi = self.get_dpi() + x, y = self.get_page_size() + return round(x / 25.4 * dpi), round(y / 25.4 * dpi) + + def get_flip_x(self) -> bool: + return self.flip_x_check_box.checkState() == QtCore.Qt.CheckState.Checked + + def get_flip_y(self) -> bool: + return self.flip_y_check_box.checkState() == QtCore.Qt.CheckState.Checked + + def get_aci_export_mode(self) -> bool: + return self.aci_export_mode.checkState() == QtCore.Qt.CheckState.Checked + + def update_sidebar(self): + x, y = self.get_page_size() + self.page_size_label.setText(f"Page Size: {x}x{y}mm") + px, py = self.get_pixel_size() + self.png_size_label.setText(f"PNG Size: {px}x{py}px") + self.clear_message() + + def update_view(self): + self._view.setTransform(self.view_transformation()) + self._view.fit_to_scene() + self.update_sidebar() + + def update_rotation(self, index: int): + rotation = index * 90 + if rotation != self._page_rotation: + self._page_rotation = rotation + self.update_view() + + def update_colors(self, index: int): + self._color_scheme = index + self._cad.replay(*replay_properties(index)) + self.update_view() + + def view_transformation(self): + if self._page_rotation == 0: + m = Matrix44() + else: + m = Matrix44.z_rotate(math.radians(self._page_rotation)) + sx = -1 if self.get_flip_x() else 1 + # inverted y-axis + sy = 1 if self.get_flip_y() else -1 + m @= Matrix44.scale(sx, sy, 1) + return QtGui.QTransform(*m.get_2d_transformation()) + + def show_message(self, msg: str) -> None: + self.message_label.setText(msg) + + def clear_message(self) -> None: + self.message_label.setText("") + + def get_export_name(self, suffix: str) -> str: + return str(self._current_file.with_suffix(suffix)) + + def export_svg(self) -> None: + path, _ = QtWidgets.QFileDialog.getSaveFileName( + self, + dir=self.get_export_name(".svg"), + caption="Save SVG File", + filter="SVG Files (*.svg)", + ) + if not path: + return + try: + with open(path, "wt") as fp: + fp.write(self.make_svg_string()) + self.show_message("SVG successfully exported") + except IOError as e: + QMessageBox.critical(self, "Export Error", str(e)) + + def get_export_matrix(self) -> Matrix44: + scale = self.get_scale_factor() + rotation = self._page_rotation + sx = -scale if self.get_flip_x() else scale + sy = -scale if self.get_flip_y() else scale + if rotation in (90, 270): + sx, sy = sy, sx + m = Matrix44.scale(sx, sy, 1) + if rotation: + m @= Matrix44.z_rotate(math.radians(rotation)) + return m + + def make_svg_string(self) -> str: + """Replays the HPGL/2 recordings on the SVGBackend of the drawing add-on.""" + player = self._player.copy() + player.transform(self.get_export_matrix()) + size = player.bbox().size + svg_backend = svg.SVGBackend() + bg_color, override = replay_properties(self._color_scheme) + xplayer.hpgl2_to_drawing( + player, svg_backend, bg_color=bg_color, override=override + ) + del player # free memory as soon as possible + # 40 plot units == 1mm + page = layout.Page(width=size.x / 40, height=size.y / 40) + return svg_backend.get_string(page) + + def export_pdf(self) -> None: + path, _ = QtWidgets.QFileDialog.getSaveFileName( + self, + dir=self.get_export_name(".pdf"), + caption="Save PDF File", + filter="PDF Files (*.pdf)", + ) + if not path: + return + try: + with open(path, "wb") as fp: + fp.write(self._pymupdf_export(fmt="pdf")) + self.show_message("PDF successfully exported") + except IOError as e: + QMessageBox.critical(self, "Export Error", str(e)) + + def export_png(self) -> None: + path, _ = QtWidgets.QFileDialog.getSaveFileName( + self, + dir=self.get_export_name(".png"), + caption="Save PNG File", + filter="PNG Files (*.png)", + ) + if not path: + return + try: + with open(path, "wb") as fp: + fp.write(self._pymupdf_export(fmt="png")) + self.show_message("PNG successfully exported") + except IOError as e: + QMessageBox.critical(self, "Export Error", str(e)) + + def _pymupdf_export(self, fmt: str) -> bytes: + """Replays the HPGL/2 recordings on the PyMuPdfBackend of the drawing add-on.""" + player = self._player.copy() + player.transform(self.get_export_matrix()) + size = player.bbox().size + pdf_backend = pymupdf.PyMuPdfBackend() + bg_color, override = replay_properties(self._color_scheme) + xplayer.hpgl2_to_drawing( + player, pdf_backend, bg_color=bg_color, override=override + ) + del player # free memory as soon as possible + # 40 plot units == 1mm + page = layout.Page(width=size.x / 40, height=size.y / 40) + if fmt == "pdf": + return pdf_backend.get_pdf_bytes(page) + else: + return pdf_backend.get_pixmap_bytes(page, fmt=fmt, dpi=self.get_dpi()) + + def export_dxf(self) -> None: + path, _ = QtWidgets.QFileDialog.getSaveFileName( + self, + dir=self.get_export_name(".dxf"), + caption="Save DXF File", + filter="DXF Files (*.dxf)", + ) + if not path: + return + doc = self._get_dxf_document() + try: + doc.saveas(path) + self.show_message("DXF successfully exported") + except IOError as e: + QMessageBox.critical(self, "Export Error", str(e)) + + def _get_dxf_document(self) -> Drawing: + import ezdxf + from ezdxf import zoom + + color_mode = ( + dxf.ColorMode.ACI if self.get_aci_export_mode() else dxf.ColorMode.RGB + ) + + doc = ezdxf.new() + msp = doc.modelspace() + player = self._player.copy() + bbox = player.bbox() + + m = self.get_export_matrix() + corners = m.fast_2d_transform(bbox.rect_vertices()) + # move content to origin: + tx, ty = BoundingBox2d(corners).extmin + m @= Matrix44.translate(-tx, -ty, 0) + player.transform(m) + bbox = player.bbox() + + dxf_backend = dxf.DXFBackend(msp, color_mode=color_mode) + bg_color, override = replay_properties(self._color_scheme) + if color_mode == dxf.ColorMode.RGB: + doc.layers.add("BACKGROUND") + bg = dxf.add_background(msp, bbox, colors.RGB.from_hex(bg_color)) + bg.dxf.layer = "BACKGROUND" + # exports the HPGL/2 content in plot units (plu) as modelspace: + # 1 plu = 0.025mm or 40 plu == 1mm + xplayer.hpgl2_to_drawing( + player, dxf_backend, bg_color=bg_color, override=override + ) + del player + if bbox.has_data: # non-empty page + zoom.window(msp, bbox.extmin, bbox.extmax) + dxf.update_extents(doc, bbox) + # paperspace is set up in mm: + dxf.setup_paperspace(doc, bbox) + return doc + + +def replay_properties(index: int) -> tuple[str, Any]: + bg_color, override = "#ffffff", None # default + if index == 1: # black on white + bg_color, override = "#ffffff", xplayer.map_color("#000000") + elif index == 2: # white on black + bg_color, override = "#000000", xplayer.map_color("#ffffff") + elif index == 3: # monochrome light + bg_color, override = "#ffffff", xplayer.map_monochrome(dark_mode=False) + elif index == 4: # monochrome dark + bg_color, override = "#000000", xplayer.map_monochrome(dark_mode=True) + elif index == 5: # blueprint high contrast + bg_color, override = "#192c64", xplayer.map_color("#e9ebf3") + elif index == 6: # blueprint low contrast + bg_color, override = "#243f8f", xplayer.map_color("#bdc5dd") + return bg_color, override diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/importer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/importer.py new file mode 100644 index 0000000..da0e6d5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/importer.py @@ -0,0 +1,664 @@ +# Purpose: Import data from another DXF document +# Copyright (c) 2013-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, cast, Union, Optional +import logging +from ezdxf.lldxf import const +from ezdxf.render.arrows import ARROWS +from ezdxf.entities import ( + DXFEntity, + DXFGraphic, + Hatch, + Polyline, + DimStyle, + Dimension, + Viewport, + Linetype, + Insert, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.layouts import BaseLayout, Layout + +logger = logging.getLogger("ezdxf") + +IMPORT_TABLES = ["linetypes", "layers", "styles", "dimstyles"] +IMPORT_ENTITIES = { + "LINE", + "POINT", + "CIRCLE", + "ARC", + "TEXT", + "SOLID", + "TRACE", + "3DFACE", + "SHAPE", + "POLYLINE", + "ATTRIB", + "INSERT", + "ELLIPSE", + "MTEXT", + "LWPOLYLINE", + "SPLINE", + "HATCH", + "MESH", + "XLINE", + "RAY", + "ATTDEF", + "DIMENSION", + "LEADER", # dimension style override not supported! + "VIEWPORT", +} + + +class Importer: + """ + The :class:`Importer` class is central element for importing data from + other DXF documents. + + Args: + source: source :class:`~ezdxf.drawing.Drawing` + target: target :class:`~ezdxf.drawing.Drawing` + + Attributes: + source: source DXF document + target: target DXF document + used_layers: Set of used layer names as string, AutoCAD accepts layer + names without a LAYER table entry. + used_linetypes: Set of used linetype names as string, these linetypes + require a TABLE entry or AutoCAD will crash. + used_styles: Set of used text style names, these text styles require + a TABLE entry or AutoCAD will crash. + used_dimstyles: Set of used dimension style names, these dimension + styles require a TABLE entry or AutoCAD will crash. + + """ + + def __init__(self, source: Drawing, target: Drawing): + self.source: Drawing = source + self.target: Drawing = target + + self.used_layers: set[str] = set() + self.used_linetypes: set[str] = set() + self.used_styles: set[str] = set() + self.used_shape_files: set[str] = set() # style entry without a name! + self.used_dimstyles: set[str] = set() + self.used_arrows: set[str] = set() + self.handle_mapping: dict[str, str] = dict() # old_handle: new_handle + + # collects all imported INSERT entities, for later name resolving. + self.imported_inserts: list[DXFEntity] = list() # imported inserts + + # collects all imported block names and their assigned new name + # imported_block[original_name] = new_name + self.imported_blocks: dict[str, str] = dict() + self._default_plotstyle_handle = target.plotstyles["Normal"].dxf.handle + self._default_material_handle = target.materials["Global"].dxf.handle + + def _add_used_resources(self, entity: DXFEntity) -> None: + """Register used resources.""" + self.used_layers.add(entity.get_dxf_attrib("layer", "0")) + self.used_linetypes.add(entity.get_dxf_attrib("linetype", "BYLAYER")) + if entity.is_supported_dxf_attrib("style"): + self.used_styles.add(entity.get_dxf_attrib("style", "Standard")) + if entity.is_supported_dxf_attrib("dimstyle"): + self.used_dimstyles.add(entity.get_dxf_attrib("dimstyle", "Standard")) + + def _add_dimstyle_resources(self, dimstyle: DimStyle) -> None: + self.used_styles.add(dimstyle.get_dxf_attrib("dimtxsty", "Standard")) + self.used_linetypes.add(dimstyle.get_dxf_attrib("dimltype", "BYLAYER")) + self.used_linetypes.add(dimstyle.get_dxf_attrib("dimltex1", "BYLAYER")) + self.used_linetypes.add(dimstyle.get_dxf_attrib("dimltex2", "BYLAYER")) + self.used_arrows.add(dimstyle.get_dxf_attrib("dimblk", "")) + self.used_arrows.add(dimstyle.get_dxf_attrib("dimblk1", "")) + self.used_arrows.add(dimstyle.get_dxf_attrib("dimblk2", "")) + self.used_arrows.add(dimstyle.get_dxf_attrib("dimldrblk", "")) + + def _add_linetype_resources(self, linetype: Linetype) -> None: + if not linetype.pattern_tags.is_complex_type(): + return + style_handle = linetype.pattern_tags.get_style_handle() + style = self.source.entitydb.get(style_handle) + if style is None: + return + if style.dxf.name == "": + # Shape file entries have no name! + self.used_shape_files.add(style.dxf.font) + else: + self.used_styles.add(style.dxf.name) + + def import_tables( + self, table_names: Union[str, Iterable[str]] = "*", replace=False + ) -> None: + """Import DXF tables from the source document into the target document. + + Args: + table_names: iterable of tables names as strings, or a single table + name as string or "*" for all supported tables + replace: ``True`` to replace already existing table entries else + ignore existing entries + + Raises: + TypeError: unsupported table type + + """ + if isinstance(table_names, str): + if table_names == "*": # import all supported tables + table_names = IMPORT_TABLES + else: # import one specific table + table_names = (table_names,) + for table_name in table_names: + self.import_table(table_name, entries="*", replace=replace) + + def import_table( + self, name: str, entries: Union[str, Iterable[str]] = "*", replace=False + ) -> None: + """ + Import specific table entries from the source document into the + target document. + + Args: + name: valid table names are "layers", "linetypes" and "styles" + entries: Iterable of table names as strings, or a single table name + or "*" for all table entries + replace: ``True`` to replace the already existing table entry else + ignore existing entries + + Raises: + TypeError: unsupported table type + + """ + if name not in IMPORT_TABLES: + raise TypeError(f'Table "{name}" import not supported.') + source_table = getattr(self.source.tables, name) + target_table = getattr(self.target.tables, name) + + if isinstance(entries, str): + if entries == "*": # import all table entries + entries = (entry.dxf.name for entry in source_table) + else: # import just one table entry + entries = (entries,) + for entry_name in entries: + try: + table_entry = source_table.get(entry_name) + except const.DXFTableEntryError: + logger.warning( + f'Required table entry "{entry_name}" in table f{name} ' + f"not found." + ) + continue + entry_name = table_entry.dxf.name + if entry_name in target_table: + if replace: + logger.debug( + f'Replacing already existing entry "{entry_name}" ' + f"of {name} table." + ) + target_table.remove(table_entry.dxf.name) + else: + logger.debug( + f'Discarding already existing entry "{entry_name}" ' + f"of {name} table." + ) + continue + + if name == "layers": + self.used_linetypes.add( + table_entry.get_dxf_attrib("linetype", "Continuous") + ) + elif name == "dimstyles": + self._add_dimstyle_resources(table_entry) + elif name == "linetypes": + self._add_linetype_resources(table_entry) + + # Duplicate table entry: + new_table_entry = self._duplicate_table_entry(table_entry) + target_table.add_entry(new_table_entry) + + # Register resource handles for mapping: + self.handle_mapping[table_entry.dxf.handle] = new_table_entry.dxf.handle + + def import_shape_files(self, fonts: set[str]) -> None: + """Import shape file table entries from the source document into the + target document. + Shape file entries are stored in the styles table but without a name. + + """ + for font in fonts: + table_entry = self.source.styles.find_shx(font) + # copy is not necessary, just create a new entry: + new_table_entry = self.target.styles.get_shx(font) + if table_entry: + # Register resource handles for mapping: + self.handle_mapping[table_entry.dxf.handle] = new_table_entry.dxf.handle + else: + logger.warning(f'Required shape file entry "{font}" not found.') + + def _set_table_entry_dxf_attribs(self, entity: DXFEntity) -> None: + entity.doc = self.target + if entity.dxf.hasattr("plotstyle_handle"): + entity.dxf.plotstyle_handle = self._default_plotstyle_handle + if entity.dxf.hasattr("material_handle"): + entity.dxf.material_handle = self._default_material_handle + + def _duplicate_table_entry(self, entry: DXFEntity) -> DXFEntity: + # duplicate table entry + new_entry = new_clean_entity(entry) + self._set_table_entry_dxf_attribs(entry) + + # create a new handle and add entity to target entity database + self.target.entitydb.add(new_entry) + return new_entry + + def import_entity( + self, entity: DXFEntity, target_layout: Optional[BaseLayout] = None + ) -> None: + """ + Imports a single DXF `entity` into `target_layout` or the modelspace + of the target document, if `target_layout` is ``None``. + + Args: + entity: DXF entity to import + target_layout: any layout (modelspace, paperspace or block) from + the target document + + Raises: + DXFStructureError: `target_layout` is not a layout of target document + + """ + + def set_dxf_attribs(e): + e.doc = self.target + # remove invalid resources + e.dxf.discard("plotstyle_handle") + e.dxf.discard("material_handle") + e.dxf.discard("visualstyle_handle") + + if target_layout is None: + target_layout = self.target.modelspace() + elif target_layout.doc != self.target: + raise const.DXFStructureError( + "Target layout has to be a layout or block from the target " "document." + ) + + dxftype = entity.dxftype() + if dxftype not in IMPORT_ENTITIES: + logger.debug(f"Import of {str(entity)} not supported") + return + self._add_used_resources(entity) + + try: + new_entity = cast(DXFGraphic, new_clean_entity(entity)) + except const.DXFTypeError: + logger.debug(f"Copying for DXF type {dxftype} not supported.") + return + + set_dxf_attribs(new_entity) + self.target.entitydb.add(new_entity) + target_layout.add_entity(new_entity) + + try: # additional processing + getattr(self, "_import_" + dxftype.lower())(new_entity) + except AttributeError: + pass + + def _import_insert(self, insert: Insert): + self.imported_inserts.append(insert) + # remove all possible source document dependencies from sub entities + for attrib in insert.attribs: + remove_dependencies(attrib) + + def _import_polyline(self, polyline: Polyline): + # remove all possible source document dependencies from sub entities + for vertex in polyline.vertices: + remove_dependencies(vertex) + + def _import_hatch(self, hatch: Hatch): + hatch.dxf.discard("associative") + + def _import_viewport(self, viewport: Viewport): + viewport.dxf.discard("sun_handle") + viewport.dxf.discard("clipping_boundary_handle") + viewport.dxf.discard("ucs_handle") + viewport.dxf.discard("ucs_base_handle") + viewport.dxf.discard("background_handle") + viewport.dxf.discard("shade_plot_handle") + viewport.dxf.discard("visual_style_handle") + viewport.dxf.discard("ref_vp_object_1") + viewport.dxf.discard("ref_vp_object_2") + viewport.dxf.discard("ref_vp_object_3") + viewport.dxf.discard("ref_vp_object_4") + + def _import_dimension(self, dimension: Dimension): + if dimension.virtual_block_content: + for entity in dimension.virtual_block_content: + if isinstance(entity, Insert): # import arrow blocks + self.import_block(entity.dxf.name, rename=False) + self._add_used_resources(entity) + else: + logger.error("The required geometry block for DIMENSION is not defined.") + + def import_entities( + self, + entities: Iterable[DXFEntity], + target_layout: Optional[BaseLayout] = None, + ) -> None: + """Import all `entities` into `target_layout` or the modelspace of the + target document, if `target_layout` is ``None``. + + Args: + entities: Iterable of DXF entities + target_layout: any layout (modelspace, paperspace or block) from + the target document + + Raises: + DXFStructureError: `target_layout` is not a layout of target document + + """ + for entity in entities: + self.import_entity(entity, target_layout) + + def import_modelspace(self, target_layout: Optional[BaseLayout] = None) -> None: + """Import all entities from source modelspace into `target_layout` or + the modelspace of the target document, if `target_layout` is ``None``. + + Args: + target_layout: any layout (modelspace, paperspace or block) from + the target document + + Raises: + DXFStructureError: `target_layout` is not a layout of target document + + """ + self.import_entities(self.source.modelspace(), target_layout=target_layout) + + def recreate_source_layout(self, name: str) -> Layout: + """Recreate source paperspace layout `name` in the target document. + The layout will be renamed if `name` already exist in the target + document. Returns target modelspace for layout name "Model". + + Args: + name: layout name as string + + Raises: + KeyError: if source layout `name` not exist + + """ + + def get_target_name(): + tname = name + base_name = name + count = 1 + while tname in self.target.layouts: + tname = base_name + str(count) + count += 1 + + return tname + + def clear(dxfattribs: dict) -> dict: + def discard(name: str): + try: + del dxfattribs[name] + except KeyError: + pass + + discard("handle") + discard("owner") + discard("taborder") + discard("shade_plot_handle") + discard("block_record_handle") + discard("viewport_handle") + discard("ucs_handle") + discard("base_ucs_handle") + return dxfattribs + + if name.lower() == "model": + return self.target.modelspace() + + source_layout = self.source.layouts.get(name) # raises KeyError + target_name = get_target_name() + dxfattribs = clear(source_layout.dxf_layout.dxfattribs()) + target_layout = self.target.layouts.new(target_name, dxfattribs=dxfattribs) + return target_layout + + def import_paperspace_layout(self, name: str) -> Layout: + """Import paperspace layout `name` into the target document. + + Recreates the source paperspace layout in the target document, renames + the target paperspace if a paperspace with same `name` already exist + and imports all entities from the source paperspace into the target + paperspace. + + Args: + name: source paper space name as string + + Returns: new created target paperspace :class:`Layout` + + Raises: + KeyError: source paperspace does not exist + DXFTypeError: invalid modelspace import + + """ + if name.lower() == "model": + raise const.DXFTypeError( + "Can not import modelspace, use method import_modelspace()." + ) + source_layout = self.source.layouts.get(name) + target_layout = self.recreate_source_layout(name) + self.import_entities(source_layout, target_layout) + return target_layout + + def import_paperspace_layouts(self) -> None: + """Import all paperspace layouts and their content into the target + document. + Target layouts will be renamed if a layout with the same name already + exist. Layouts will be imported in original tab order. + + """ + for name in self.source.layouts.names_in_taborder(): + if name.lower() != "model": # do not import modelspace + self.import_paperspace_layout(name) + + def import_blocks(self, block_names: Iterable[str], rename=False) -> None: + """Import all BLOCK definitions from source document. + + If a BLOCK already exist the BLOCK will be renamed if argument + `rename` is ``True``, otherwise the existing BLOCK in the target + document will be used instead of the BLOCK from the source document. + Required name resolving for imported BLOCK references (INSERT), will be + done in the :meth:`Importer.finalize` method. + + Args: + block_names: names of BLOCK definitions to import + rename: rename BLOCK if a BLOCK with the same name already exist in + target document + + Raises: + ValueError: BLOCK in source document not found (defined) + + """ + for block_name in block_names: + self.import_block(block_name, rename=rename) + + def import_block(self, block_name: str, rename=True) -> str: + """Import one BLOCK definition from source document. + + If the BLOCK already exist the BLOCK will be renamed if argument + `rename` is ``True``, otherwise the existing BLOCK in the target + document will be used instead of the BLOCK in the source document. + Required name resolving for imported block references (INSERT), will be + done in the :meth:`Importer.finalize` method. + + To replace an existing BLOCK in the target document, just delete it + before importing data: + :code:`target.blocks.delete_block(block_name, safe=False)` + + Args: + block_name: name of BLOCK to import + rename: rename BLOCK if a BLOCK with the same name already exist in + target document + + Returns: (renamed) BLOCK name + + Raises: + ValueError: BLOCK in source document not found (defined) + + """ + + def get_new_block_name() -> str: + num = 0 + name = block_name + while name in target_blocks: + name = block_name + str(num) + num += 1 + return name + + try: # already imported block? + return self.imported_blocks[block_name] + except KeyError: + pass + + try: + source_block = self.source.blocks[block_name] + except const.DXFKeyError: + raise ValueError(f'Source block "{block_name}" not found.') + + target_blocks = self.target.blocks + if (block_name in target_blocks) and (rename is False): + self.imported_blocks[block_name] = block_name + return block_name + + new_block_name = get_new_block_name() + block = source_block.block + assert block is not None + target_block = target_blocks.new( + new_block_name, + base_point=block.dxf.base_point, + dxfattribs={ + "description": block.dxf.description, + "flags": block.dxf.flags, + "xref_path": block.dxf.xref_path, + }, + ) + self.import_entities(source_block, target_layout=target_block) + self.imported_blocks[block_name] = new_block_name + return new_block_name + + def _create_missing_arrows(self): + """Create or import required arrow blocks, used by the LEADER or the + DIMSTYLE entity, which are not imported automatically because they are + not used in an anonymous DIMENSION geometry BLOCK. + + """ + self.used_arrows.discard( + "" + ) # standard default arrow '' needs no block definition + for arrow_name in self.used_arrows: + if ARROWS.is_acad_arrow(arrow_name): + self.target.acquire_arrow(arrow_name) + else: + self.import_block(arrow_name, rename=False) + + def _resolve_inserts(self) -> None: + """Resolve BLOCK names of imported BLOCK reference entities (INSERT). + + This is required for the case the name of the imported BLOCK collides + with an already existing BLOCK in the target document and the conflict + resolving method is "rename". + + """ + while len(self.imported_inserts): + inserts = list(self.imported_inserts) + # clear imported inserts, block import may append additional inserts + self.imported_inserts = [] + for insert in inserts: + block_name = self.import_block(insert.dxf.name) + insert.dxf.name = block_name + + def _import_required_table_entries(self) -> None: + """Import required table entries collected while importing entities + into the target document. + + """ + # 1. dimstyles import adds additional required linetype and style + # resources and required arrows + if len(self.used_dimstyles): + self.import_table("dimstyles", self.used_dimstyles) + + # 2. layers import adds additional required linetype resources + if len(self.used_layers): + self.import_table("layers", self.used_layers) + + # 3. complex linetypes adds additional required style resources + if len(self.used_linetypes): + self.import_table("linetypes", self.used_linetypes) + + # 4. Text styles do not add additional required resources + if len(self.used_styles): + self.import_table("styles", self.used_styles) + + # 5. Shape files are text style entries without a name + if len(self.used_shape_files): + self.import_shape_files(self.used_shape_files) + + # 6. Update text style handles of imported complex linetypes: + self.update_complex_linetypes() + + def _add_required_complex_linetype_resources(self): + for ltype_name in self.used_linetypes: + try: + ltype = self.source.linetypes.get(ltype_name) + except const.DXFTableEntryError: + continue + self._add_linetype_resources(ltype) + + def update_complex_linetypes(self): + std_handle = self.target.styles.get("STANDARD").dxf.handle + for linetype in self.target.linetypes: + if linetype.pattern_tags.is_complex_type(): + old_handle = linetype.pattern_tags.get_style_handle() + new_handle = self.handle_mapping.get(old_handle, std_handle) + linetype.pattern_tags.set_style_handle(new_handle) + + def finalize(self) -> None: + """Finalize the import by importing required table entries and BLOCK + definitions, without finalization the target document is maybe invalid + for AutoCAD. Call the :meth:`~Importer.finalize()` method as last step + of the import process. + + """ + self._resolve_inserts() + self._add_required_complex_linetype_resources() + self._import_required_table_entries() + self._create_missing_arrows() + + +def new_clean_entity(entity: DXFEntity, keep_xdata: bool = False) -> DXFEntity: + """Copy entity and remove all external dependencies. + + Args: + entity: DXF entity + keep_xdata: keep xdata flag + + """ + new_entity = entity.copy() + new_entity.doc = None + return remove_dependencies(new_entity, keep_xdata=keep_xdata) + + +def remove_dependencies(entity: DXFEntity, keep_xdata: bool = False) -> DXFEntity: + """Remove all external dependencies. + + Args: + entity: DXF entity + keep_xdata: keep xdata flag + + """ + entity.appdata = None + entity.reactors = None + entity.extension_dict = None + if not keep_xdata: + entity.xdata = None + return entity diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/iterdxf.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/iterdxf.py new file mode 100644 index 0000000..978060c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/iterdxf.py @@ -0,0 +1,480 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + cast, + BinaryIO, + Optional, + Union, + Any, +) +from io import StringIO +from pathlib import Path +from ezdxf.lldxf.const import DXFStructureError +from ezdxf.lldxf.extendedtags import ExtendedTags, DXFTag +from ezdxf.lldxf.tagwriter import TagWriter +from ezdxf.lldxf.tagger import tag_compiler, ascii_tags_loader +from ezdxf.filemanagement import dxf_file_info +from ezdxf.lldxf import fileindex + +from ezdxf.entities import DXFGraphic, DXFEntity, Polyline, Insert +from ezdxf.entities import factory +from ezdxf.entities.subentity import entity_linker +from ezdxf.tools.codepage import toencoding + +__all__ = ["opendxf", "single_pass_modelspace", "modelspace"] + +SUPPORTED_TYPES = { + "ARC", + "LINE", + "CIRCLE", + "ELLIPSE", + "POINT", + "LWPOLYLINE", + "SPLINE", + "3DFACE", + "SOLID", + "TRACE", + "SHAPE", + "POLYLINE", + "VERTEX", + "SEQEND", + "MESH", + "TEXT", + "MTEXT", + "HATCH", + "INSERT", + "ATTRIB", + "ATTDEF", + "RAY", + "XLINE", + "DIMENSION", + "LEADER", + "IMAGE", + "WIPEOUT", + "HELIX", + "MLINE", + "MLEADER", +} + +Filename = Union[Path, str] + + +class IterDXF: + """Iterator for DXF entities stored in the modelspace. + + Args: + name: filename, has to be a seekable file. + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError`exception for invalid data + + Raises: + DXFStructureError: invalid or incomplete DXF file + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + + def __init__(self, name: Filename, errors: str = "surrogateescape"): + self.structure, self.sections = self._load_index(str(name)) + self.errors = errors + self.file: BinaryIO = open(name, mode="rb") + if "ENTITIES" not in self.sections: + raise DXFStructureError("ENTITIES section not found.") + if self.structure.version > "AC1009" and "OBJECTS" not in self.sections: + raise DXFStructureError("OBJECTS section not found.") + + def _load_index( + self, name: str + ) -> tuple[fileindex.FileStructure, dict[str, int]]: + structure = fileindex.load(name) + sections: dict[str, int] = dict() + new_index = [] + for e in structure.index: + if e.code == 0: + new_index.append(e) + elif e.code == 2: + sections[e.value] = len(new_index) - 1 + # remove all other tags like handles (code == 5) + structure.index = new_index + return structure, sections + + @property + def encoding(self): + return self.structure.encoding + + @property + def dxfversion(self): + return self.structure.version + + def export(self, name: Filename) -> IterDXFWriter: + """Returns a companion object to export parts from the source DXF file + into another DXF file, the new file will have the same HEADER, CLASSES, + TABLES, BLOCKS and OBJECTS sections, which guarantees all necessary + dependencies are present in the new file. + + Args: + name: filename, no special requirements + + """ + doc = IterDXFWriter(name, self) + # Copy everything from start of source DXF until the first entity + # of the ENTITIES section to the new DXF. + location = self.structure.index[self.sections["ENTITIES"] + 1].location + self.file.seek(0) + data = self.file.read(location) + doc.write_data(data) + return doc + + def copy_objects_section(self, f: BinaryIO) -> None: + start_index = self.sections["OBJECTS"] + try: + end_index = self.structure.get(0, "ENDSEC", start_index) + except ValueError: + raise DXFStructureError(f"ENDSEC of OBJECTS section not found.") + + start_location = self.structure.index[start_index].location + end_location = self.structure.index[end_index + 1].location + count = end_location - start_location + self.file.seek(start_location) + data = self.file.read(count) + f.write(data) + + def modelspace( + self, types: Optional[Iterable[str]] = None + ) -> Iterable[DXFGraphic]: + """Returns an iterator for all supported DXF entities in the + modelspace. These entities are regular :class:`~ezdxf.entities.DXFGraphic` + objects but without a valid document assigned. It is **not** + possible to add these entities to other `ezdxf` documents. + + It is only possible to recreate the objects by factory functions base + on attributes of the source entity. + For MESH, POLYMESH and POLYFACE it is possible to use the + :class:`~ezdxf.render.MeshTransformer` class to render (recreate) this + objects as new entities in another document. + + Args: + types: DXF types like ``['LINE', '3DFACE']`` which should be + returned, ``None`` returns all supported types. + + """ + linked_entity = entity_linker() + queued = None + requested_types = _requested_types(types) + for entity in self.load_entities( + self.sections["ENTITIES"] + 1, requested_types + ): + if not linked_entity(entity) and entity.dxf.paperspace == 0: + # queue one entity for collecting linked entities: + # VERTEX, ATTRIB + if queued: + yield queued + queued = entity + if queued: + yield queued + + def load_entities( + self, start: int, requested_types: set[str] + ) -> Iterable[DXFGraphic]: + def to_str(data: bytes) -> str: + return data.decode(self.encoding, errors=self.errors).replace( + "\r\n", "\n" + ) + + index = start + entry = self.structure.index[index] + self.file.seek(entry.location) + while entry.value != "ENDSEC": + index += 1 + next_entry = self.structure.index[index] + size = next_entry.location - entry.location + data = self.file.read(size) + if entry.value in requested_types: + xtags = ExtendedTags.from_text(to_str(data)) + yield factory.load(xtags) # type: ignore + entry = next_entry + + def close(self): + """Safe closing source DXF file.""" + self.file.close() + + +class IterDXFWriter: + def __init__(self, name: Filename, loader: IterDXF): + self.name = str(name) + self.file: BinaryIO = open(name, mode="wb") + self.text = StringIO() + self.entity_writer = TagWriter(self.text, loader.dxfversion) + self.loader = loader + + def write_data(self, data: bytes): + self.file.write(data) + + def write(self, entity: DXFGraphic): + """Write a DXF entity from the source DXF file to the export file. + + Don't write entities from different documents than the source DXF file, + dependencies and resources will not match, maybe it will work once, but + not in a reliable way for different DXF documents. + + """ + # Not necessary to remove this dependencies by copying + # them into the same document frame + # --------------------------------- + # remove all possible dependencies + # entity.xdata = None + # entity.appdata = None + # entity.extension_dict = None + # entity.reactors = None + # reset text stream + self.text.seek(0) + self.text.truncate() + + if entity.dxf.handle is None: # DXF R12 without handles + self.entity_writer.write_handles = False + + entity.export_dxf(self.entity_writer) + if entity.dxftype() == "POLYLINE": + polyline = cast(Polyline, entity) + for vertex in polyline.vertices: + vertex.export_dxf(self.entity_writer) + polyline.seqend.export_dxf(self.entity_writer) # type: ignore + elif entity.dxftype() == "INSERT": + insert = cast(Insert, entity) + if insert.attribs_follow: + for attrib in insert.attribs: + attrib.export_dxf(self.entity_writer) + insert.seqend.export_dxf(self.entity_writer) # type: ignore + data = self.text.getvalue().encode(self.loader.encoding) + self.file.write(data) + + def close(self): + """Safe closing of exported DXF file. Copying of OBJECTS section + happens only at closing the file, without closing the new DXF file is + invalid. + """ + self.file.write(b" 0\r\nENDSEC\r\n") # for ENTITIES section + if self.loader.dxfversion > "AC1009": + self.loader.copy_objects_section(self.file) + self.file.write(b" 0\r\nEOF\r\n") + self.file.close() + + +def opendxf(filename: Filename, errors: str = "surrogateescape") -> IterDXF: + """Open DXF file for iterating, be sure to open valid DXF files, no DXF + structure checks will be applied. + + Use this function to split up big DXF files as shown in the example above. + + Args: + filename: DXF filename of a seekable DXF file. + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: invalid or incomplete DXF file + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + return IterDXF(filename, errors=errors) + + +def modelspace( + filename: Filename, + types: Optional[Iterable[str]] = None, + errors: str = "surrogateescape", +) -> Iterable[DXFGraphic]: + """Iterate over all modelspace entities as :class:`DXFGraphic` objects of + a seekable file. + + Use this function to iterate "quick" over modelspace entities of a DXF file, + filtering DXF types may speed up things if many entity types will be skipped. + + Args: + filename: filename of a seekable DXF file + types: DXF types like ``['LINE', '3DFACE']`` which should be returned, + ``None`` returns all supported types. + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: invalid or incomplete DXF file + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + info = dxf_file_info(str(filename)) + prev_code: int = -1 + prev_value: Any = "" + entities = False + requested_types = _requested_types(types) + + with open(filename, mode="rt", encoding=info.encoding, errors=errors) as fp: + tagger = ascii_tags_loader(fp) + queued: Optional[DXFEntity] = None + tags: list[DXFTag] = [] + linked_entity = entity_linker() + + for tag in tag_compiler(tagger): + code = tag.code + value = tag.value + if entities: + if code == 0: + if len(tags) and tags[0].value in requested_types: + entity = factory.load(ExtendedTags(tags)) + if ( + not linked_entity(entity) + and entity.dxf.paperspace == 0 + ): + # queue one entity for collecting linked entities: + # VERTEX, ATTRIB + if queued: + yield queued # type: ignore + queued = entity + tags = [tag] + else: + tags.append(tag) + if code == 0 and value == "ENDSEC": + if queued: + yield queued # type: ignore + return + continue # if entities - nothing else matters + elif code == 2 and prev_code == 0 and prev_value == "SECTION": + entities = value == "ENTITIES" + + prev_code = code + prev_value = value + + +def single_pass_modelspace( + stream: BinaryIO, + types: Optional[Iterable[str]] = None, + errors: str = "surrogateescape", +) -> Iterable[DXFGraphic]: + """Iterate over all modelspace entities as :class:`DXFGraphic` objects in + a single pass. + + Use this function to 'quick' iterate over modelspace entities of a **not** + seekable binary DXF stream, filtering DXF types may speed up things if many + entity types will be skipped. + + Args: + stream: (not seekable) binary DXF stream + types: DXF types like ``['LINE', '3DFACE']`` which should be returned, + ``None`` returns all supported types. + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: Invalid or incomplete DXF file + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + fetch_header_var: Optional[str] = None + encoding = "cp1252" + version = "AC1009" + prev_code: int = -1 + prev_value: str = "" + entities = False + requested_types = _requested_types(types) + + for code, value in binary_tagger(stream): + if code == 0 and value == b"ENDSEC": + break + elif code == 2 and prev_code == 0 and value != b"HEADER": + # (0, SECTION), (2, name) + # First section is not the HEADER section + entities = value == b"ENTITIES" + break + elif code == 9 and value == b"$DWGCODEPAGE": + fetch_header_var = "ENCODING" + elif code == 9 and value == b"$ACADVER": + fetch_header_var = "VERSION" + elif fetch_header_var == "ENCODING": + encoding = toencoding(value.decode()) + fetch_header_var = None + elif fetch_header_var == "VERSION": + version = value.decode() + fetch_header_var = None + prev_code = code + + if version >= "AC1021": + encoding = "utf-8" + + queued: Optional[DXFGraphic] = None + tags: list[DXFTag] = [] + linked_entity = entity_linker() + + for tag in tag_compiler(binary_tagger(stream, encoding, errors)): + code = tag.code + value = tag.value + if entities: + if code == 0 and value == "ENDSEC": + if queued: + yield queued + return + if code == 0: + if len(tags) and tags[0].value in requested_types: + entity = cast(DXFGraphic, factory.load(ExtendedTags(tags))) + if not linked_entity(entity) and entity.dxf.paperspace == 0: + # queue one entity for collecting linked entities: + # VERTEX, ATTRIB + if queued: + yield queued + queued = entity + tags = [tag] + else: + tags.append(tag) + continue # if entities - nothing else matters + elif code == 2 and prev_code == 0 and prev_value == "SECTION": + entities = value == "ENTITIES" + + prev_code = code + prev_value = value + + +def binary_tagger( + file: BinaryIO, + encoding: Optional[str] = None, + errors: str = "surrogateescape", +) -> Iterator[DXFTag]: + while True: + try: + try: + code = int(file.readline()) + except ValueError: + raise DXFStructureError(f"Invalid group code") + value = file.readline().rstrip(b"\r\n") + yield DXFTag( + code, + value.decode(encoding, errors=errors) if encoding else value, + ) + except IOError: + return + + +def _requested_types(types: Optional[Iterable[str]]) -> set[str]: + if types: + requested = SUPPORTED_TYPES.intersection(set(types)) + if "POLYLINE" in requested: + requested.add("SEQEND") + requested.add("VERTEX") + if "INSERT" in requested: + requested.add("SEQEND") + requested.add("ATTRIB") + else: + requested = SUPPORTED_TYPES + return requested diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/menger_sponge.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/menger_sponge.py new file mode 100644 index 0000000..0a51498 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/menger_sponge.py @@ -0,0 +1,266 @@ +# Purpose: menger sponge addon for ezdxf +# Copyright (c) 2016-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Sequence, Optional +from ezdxf.math import Vec3, UVec, Matrix44, UCS +from ezdxf.render.mesh import MeshVertexMerger, MeshTransformer, MeshBuilder + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +# fmt: off +all_cubes_size_3_template = [ + (0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 1, 0), (1, 1, 0), (2, 1, 0), (0, 2, 0), (1, 2, 0), (2, 2, 0), + (0, 0, 1), (1, 0, 1), (2, 0, 1), (0, 1, 1), (1, 1, 1), (2, 1, 1), (0, 2, 1), (1, 2, 1), (2, 2, 1), + (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 2), (1, 1, 2), (2, 1, 2), (0, 2, 2), (1, 2, 2), (2, 2, 2), +] + +original_menger_cubes = [ + (0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 1, 0), (2, 1, 0), (0, 2, 0), (1, 2, 0), (2, 2, 0), + (0, 0, 1), (2, 0, 1), (0, 2, 1), (2, 2, 1), + (0, 0, 2), (1, 0, 2), (2, 0, 2), (0, 1, 2), (2, 1, 2), (0, 2, 2), (1, 2, 2), (2, 2, 2), +] + +menger_v1 = [ + (0, 0, 0), (2, 0, 0), (1, 1, 0), (0, 2, 0), (2, 2, 0), + (1, 0, 1), (0, 1, 1), (2, 1, 1), (1, 2, 1), + (0, 0, 2), (2, 0, 2), (1, 1, 2), (0, 2, 2), (2, 2, 2), +] + +menger_v2 = [ + (1, 0, 0), (0, 1, 0), (2, 1, 0), (1, 2, 0), + (0, 0, 1), (2, 0, 1), (1, 1, 1), (0, 2, 1), (2, 2, 1), + (1, 0, 2), (0, 1, 2), (2, 1, 2), (1, 2, 2), +] + +jerusalem_cube = [ + (0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (0, 1, 0), (1, 1, 0), (3, 1, 0), (4, 1, 0), (0, 2, 0), + (4, 2, 0), (0, 3, 0), (1, 3, 0), (3, 3, 0), (4, 3, 0), (0, 4, 0), (1, 4, 0), (2, 4, 0), (3, 4, 0), (4, 4, 0), + (0, 0, 1), (1, 0, 1), (3, 0, 1), (4, 0, 1), (0, 1, 1), (1, 1, 1), (3, 1, 1), (4, 1, 1), (0, 3, 1), (1, 3, 1), + (3, 3, 1), (4, 3, 1), (0, 4, 1), (1, 4, 1), (3, 4, 1), (4, 4, 1), (0, 0, 2), (4, 0, 2), (0, 4, 2), (4, 4, 2), + (0, 0, 3), (1, 0, 3), (3, 0, 3), (4, 0, 3), (0, 1, 3), (1, 1, 3), (3, 1, 3), (4, 1, 3), (0, 3, 3), (1, 3, 3), + (3, 3, 3), (4, 3, 3), (0, 4, 3), (1, 4, 3), (3, 4, 3), (4, 4, 3), (0, 0, 4), (1, 0, 4), (2, 0, 4), (3, 0, 4), + (4, 0, 4), (0, 1, 4), (1, 1, 4), (3, 1, 4), (4, 1, 4), (0, 2, 4), (4, 2, 4), (0, 3, 4), (1, 3, 4), (3, 3, 4), + (4, 3, 4), (0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4), +] + +building_schemas = [ + original_menger_cubes, + menger_v1, + menger_v2, + jerusalem_cube, +] + +# subdivide level in order of building_schemas +cube_sizes = [3., 3., 3., 5.] + +# 8 corner vertices +_cube_vertices = [ + (0, 0, 0), + (1, 0, 0), + (1, 1, 0), + (0, 1, 0), + (0, 0, 1), + (1, 0, 1), + (1, 1, 1), + (0, 1, 1), +] + +# 6 cube faces +cube_faces = [ + [0, 3, 2, 1], + [4, 5, 6, 7], + [0, 1, 5, 4], + [1, 2, 6, 5], + [3, 7, 6, 2], + [0, 4, 7, 3], +] + +# fmt: on + + +class MengerSponge: + """ + + Args: + location: location of lower left corner as (x, y, z) tuple + length: side length + level: subdivide level + kind: type of menger sponge + + === =========================== + 0 Original Menger Sponge + 1 Variant XOX + 2 Variant OXO + 3 Jerusalem Cube + === =========================== + + """ + + def __init__( + self, + location: UVec = (0.0, 0.0, 0.0), + length: float = 1.0, + level: int = 1, + kind: int = 0, + ): + self.cube_definitions = _menger_sponge( + location=location, length=length, level=level, kind=kind + ) + + def vertices(self) -> Iterator[list[Vec3]]: + """Yields the cube vertices as list of (x, y, z) tuples.""" + for location, length in self.cube_definitions: + x, y, z = location + yield [ + Vec3(x + xf * length, y + yf * length, z + zf * length) + for xf, yf, zf in _cube_vertices + ] + + __iter__ = vertices + + @staticmethod + def faces() -> list[list[int]]: + """Returns list of cube faces. All cube vertices have the same order, so + one faces list fits them all. + + """ + return cube_faces + + def render( + self, + layout: GenericLayoutType, + merge: bool = False, + dxfattribs=None, + matrix: Optional[Matrix44] = None, + ucs: Optional[UCS] = None, + ) -> None: + """Renders the menger sponge into layout, set `merge` to ``True`` for + rendering the whole menger sponge into one MESH entity, set `merge` to + ``False`` for rendering the individual cubes of the menger sponge as + MESH entities. + + Args: + layout: DXF target layout + merge: ``True`` for one MESH entity, ``False`` for individual MESH + entities per cube + dxfattribs: DXF attributes for the MESH entities + matrix: apply transformation matrix at rendering + ucs: apply UCS transformation at rendering + + """ + if merge: + mesh = self.mesh() + mesh.render_mesh( + layout, dxfattribs=dxfattribs, matrix=matrix, ucs=ucs + ) + else: + for cube in self.cubes(): + cube.render_mesh(layout, dxfattribs, matrix=matrix, ucs=ucs) + + def cubes(self) -> Iterator[MeshTransformer]: + """Yields all cubes of the menger sponge as individual + :class:`MeshTransformer` objects. + """ + faces = self.faces() + for vertices in self: + mesh = MeshVertexMerger() + mesh.add_mesh(vertices=vertices, faces=faces) # type: ignore + yield MeshTransformer.from_builder(mesh) + + def mesh(self) -> MeshTransformer: + """Returns geometry as one :class:`MeshTransformer` object.""" + faces = self.faces() + mesh = MeshVertexMerger() + for vertices in self: + mesh.add_mesh(vertices=vertices, faces=faces) # type: ignore + return remove_duplicate_inner_faces(mesh) + + +def remove_duplicate_inner_faces(mesh: MeshBuilder) -> MeshTransformer: + new_mesh = MeshTransformer() + new_mesh.vertices = mesh.vertices + new_mesh.faces = list(manifold_faces(mesh.faces)) + return new_mesh + + +def manifold_faces(faces: list[Sequence[int]]) -> Iterator[Sequence[int]]: + ledger: dict[tuple[int, ...], list[Sequence[int]]] = {} + for face in faces: + key = tuple(sorted(face)) + try: + ledger[key].append(face) + except KeyError: + ledger[key] = [face] + for faces in ledger.values(): + if len(faces) == 1: + yield faces[0] + + +def _subdivide( + location: UVec = (0.0, 0.0, 0.0), length: float = 1.0, kind: int = 0 +) -> list[tuple[Vec3, float]]: + """Divides a cube in sub-cubes and keeps only cubes determined by the + building schema. + + All sides are parallel to x-, y- and z-axis, location is a (x, y, z) tuple + and represents the coordinates of the lower left corner (nearest to the axis + origin) of the cube, length is the side-length of the cube + + Args: + location: (x, y, z) tuple, coordinates of the lower left corner of the cube + length: side length of the cube + kind: int for 0: original menger sponge; 1: Variant XOX; 2: Variant OXO; + 3: Jerusalem Cube; + + Returns: list of sub-cubes (location, length) + + """ + + init_x, init_y, init_z = location + step_size = float(length) / cube_sizes[kind] + remaining_cubes = building_schemas[kind] + + def sub_location(indices) -> Vec3: + x, y, z = indices + return Vec3( + init_x + x * step_size, + init_y + y * step_size, + init_z + z * step_size, + ) + + return [(sub_location(indices), step_size) for indices in remaining_cubes] + + +def _menger_sponge( + location: UVec = (0.0, 0.0, 0.0), + length: float = 1.0, + level: int = 1, + kind: int = 0, +) -> list[tuple[Vec3, float]]: + """Builds a menger sponge for given level. + + Args: + location: (x, y, z) tuple, coordinates of the lower left corner of the cube + length: side length of the cube + level: level of menger sponge, has to be 1 or bigger + kind: int for 0: original menger sponge; 1: Variant XOX; 2: Variant OXO; + 3: Jerusalem Cube; + + Returns: list of sub-cubes (location, length) + + """ + kind = int(kind) + if kind not in (0, 1, 2, 3): + raise ValueError("kind has to be 0, 1, 2 or 3.") + level = int(level) + if level < 1: + raise ValueError("level has to be 1 or bigger.") + cubes = _subdivide(location, length, kind=kind) + for _ in range(level - 1): + next_level_cubes = [] + for location, length in cubes: + next_level_cubes.extend(_subdivide(location, length, kind=kind)) + cubes = next_level_cubes + return cubes diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/meshex.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/meshex.py new file mode 100644 index 0000000..1c19edc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/meshex.py @@ -0,0 +1,675 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, Sequence +import os +import struct +import uuid +import datetime +import enum +import zipfile + +from ezdxf.math import Vec3, normal_vector_3p, BoundingBox +from ezdxf.render import MeshTransformer, MeshVertexMerger, MeshBuilder +from ezdxf import __version__ + + +class UnsupportedFileFormat(Exception): + pass + + +class ParsingError(Exception): + pass + + +def stl_readfile(filename: Union[str, os.PathLike]) -> MeshTransformer: + """Read ascii or binary `STL`_ file content as :class:`ezdxf.render.MeshTransformer` + instance. + + Raises: + ParsingError: vertex parsing error or invalid/corrupt data + + """ + with open(filename, "rb") as fp: + buffer = fp.read() + if buffer.startswith(b"solid"): + s = buffer.decode("ascii", errors="ignore") + return stl_loads(s) + else: + return stl_loadb(buffer) + + +def stl_loads(content: str) -> MeshTransformer: + """Load a mesh from an ascii `STL`_ content string as :class:`ezdxf.render.MeshTransformer` + instance. + + Raises: + ParsingError: vertex parsing error + + """ + # http://www.fabbers.com/tech/STL_Format#Sct_ASCII + # This implementation is not very picky and grabs only lines which start + # with "vertex" or "endloop" and ignores the rest. + def parse_vertex(line: str) -> Vec3: + data = line.split() + return Vec3(float(data[1]), float(data[2]), float(data[3])) + + mesh = MeshVertexMerger() + face: list[Vec3] = [] + for num, line in enumerate(content.split("\n"), start=1): + line = line.strip(" \r") + if line.startswith("vertex"): + try: + face.append(parse_vertex(line)) + except (IndexError, ValueError): + raise ParsingError(f"STL parsing error in line {num}: {line}") + elif line.startswith("endloop"): + if len(face) == 3: + mesh.add_face(face) + face.clear() + return MeshTransformer.from_builder(mesh) + + +def stl_loadb(buffer: bytes) -> MeshTransformer: + """Load a mesh from a binary `STL`_ data :class:`ezdxf.render.MeshTransformer` + instance. + + Raises: + ParsingError: invalid/corrupt data or not a binary STL file + + """ + # http://www.fabbers.com/tech/STL_Format#Sct_ASCII + index = 80 + n_faces = struct.unpack_from(" MeshTransformer: + """Read `OFF`_ file content as :class:`ezdxf.render.MeshTransformer` + instance. + + Raises: + ParsingError: vertex or face parsing error + + """ + with open(filename, "rt", encoding="ascii", errors="ignore") as fp: + content = fp.read() + return off_loads(content) + + +def off_loads(content: str) -> MeshTransformer: + """Load a mesh from a `OFF`_ content string as :class:`ezdxf.render.MeshTransformer` + instance. + + Raises: + ParsingError: vertex or face parsing error + + """ + # https://en.wikipedia.org/wiki/OFF_(file_format) + mesh = MeshVertexMerger() + lines: list[str] = [] + for line in content.split("\n"): + line = line.strip(" \n\r") + # "OFF" in a single line + if line.startswith("#") or line == "OFF" or line == "": + continue + lines.append(line) + + if len(lines) == 0: + raise ParsingError(f"OFF format parsing error: no data") + + if lines[0].startswith("OFF"): + # OFF v f e + lines[0] = lines[0][4:] + + n = lines[0].split() + try: + n_vertices, n_faces = int(n[0]), int(n[1]) + except ValueError: + raise ParsingError(f"OFF format parsing error: {lines[0]}") + + if len(lines) < n_vertices + n_faces: + raise ParsingError(f"OFF format parsing error: invalid data count") + + for vertex in lines[1 : n_vertices + 1]: + v = vertex.split() + try: + vtx = Vec3(float(v[0]), float(v[1]), float(v[2])) + except (ValueError, IndexError): + raise ParsingError(f"OFF format vertex parsing error: {vertex}") + mesh.vertices.append(vtx) + + index = n_vertices + 1 + face_indices = [] + for face in lines[index : index + n_faces]: + f = face.split() + try: + vertex_count = int(f[0]) + except ValueError: + raise ParsingError(f"OFF format face parsing error: {face}") + for index in range(vertex_count): + try: + face_indices.append(int(f[1 + index])) + except (ValueError, IndexError): + raise ParsingError( + f"OFF format face index parsing error: {face}" + ) + mesh.faces.append(tuple(face_indices)) + face_indices.clear() + return MeshTransformer.from_builder(mesh) + + +def obj_readfile(filename: Union[str, os.PathLike]) -> list[MeshTransformer]: + """Read `OBJ`_ file content as list of :class:`ezdxf.render.MeshTransformer` + instances. + + Raises: + ParsingError: vertex or face parsing error + + """ + with open(filename, "rt", encoding="ascii", errors="ignore") as fp: + content = fp.read() + return obj_loads(content) + + +def obj_loads(content: str) -> list[MeshTransformer]: + """Load one or more meshes from an `OBJ`_ content string as list of + :class:`ezdxf.render.MeshTransformer` instances. + + Raises: + ParsingError: vertex parsing error + + """ + # https://en.wikipedia.org/wiki/Wavefront_.obj_file + # This implementation is not very picky and grabs only lines which start + # with "v", "g" or "f" and ignores the rest. + def parse_vertex(l: str) -> Vec3: + v = l.split() + return Vec3(float(v[0]), float(v[1]), float(v[2])) + + def parse_face(l: str) -> Sequence[int]: + return tuple(int(s.split("/")[0]) for s in l.split()) + + vertices: list[Vec3] = [Vec3()] # 1-indexed + meshes: list[MeshTransformer] = [] + mesh = MeshVertexMerger() + for num, line in enumerate(content.split("\n"), start=1): + line = line.strip(" \r") + if line.startswith("v"): + try: + vtx = parse_vertex(line[2:]) + except (IndexError, ValueError): + raise ParsingError( + f"OBJ vertex parsing error in line {num}: {line}" + ) + vertices.append(vtx) + elif line.startswith("f"): + try: + mesh.add_face(vertices[i] for i in parse_face(line[2:])) + except ValueError: + raise ParsingError( + f"OBJ face parsing error in line {num}: {line}" + ) + except IndexError: + raise ParsingError( + f"OBJ face index error (n={len(vertices)}) in line {num}: {line}" + ) + + elif line.startswith("g") and len(mesh.vertices) > 0: + meshes.append(MeshTransformer.from_builder(mesh)) + mesh = MeshVertexMerger() + + if len(mesh.vertices) > 0: + meshes.append(MeshTransformer.from_builder(mesh)) + return meshes + + +def stl_dumps(mesh: MeshBuilder) -> str: + """Returns the `STL`_ data as string for the given `mesh`. + This function triangulates the meshes automatically because the `STL`_ + format supports only triangles as faces. + + This function does not check if the mesh obey the + `STL`_ format `rules `_: + + - The direction of the face normal is outward. + - The face vertices are listed in counter-clockwise order when looking + at the object from the outside (right-hand rule). + - Each triangle must share two vertices with each of its adjacent triangles. + - The object represented must be located in the all-positive octant + (non-negative and nonzero). + + """ + lines: list[str] = [f"solid STL generated by ezdxf {__version__}"] + for face in mesh.tessellation(max_vertex_count=3): + if len(face) < 3: + continue + try: + n = normal_vector_3p(face[0], face[1], face[2]) + except ZeroDivisionError: + continue + n = n.round(8) + lines.append(f" facet normal {n.x} {n.y} {n.z}") + lines.append(" outer loop") + for v in face: + lines.append(f" vertex {v.x} {v.y} {v.z}") + lines.append(" endloop") + lines.append(" endfacet") + lines.append("endsolid\n") + return "\n".join(lines) + + +STL_SIGNATURE = (b"STL generated ezdxf" + b" " * 80)[:80] + + +def stl_dumpb(mesh: MeshBuilder) -> bytes: + """Returns the `STL`_ binary data as bytes for the given `mesh`. + + For more information see function: :func:`stl_dumps` + """ + data: list[bytes] = [STL_SIGNATURE, b"0000"] + count = 0 + for face in mesh.tessellation(max_vertex_count=3): + try: + n = normal_vector_3p(face[0], face[1], face[2]) + except ZeroDivisionError: + continue + count += 1 + values = list(n.xyz) + for v in face: + values.extend(v.xyz) + values.append(0) + data.append(struct.pack("<12fH", *values)) + data[1] = struct.pack(" str: + """Returns the `OFF`_ data as string for the given `mesh`. + The `OFF`_ format supports ngons as faces. + + """ + lines: list[str] = ["OFF", f"{len(mesh.vertices)} {len(mesh.faces)} 0"] + for v in mesh.vertices: + v = v.round(6) + lines.append(f"{v.x} {v.y} {v.z}") + for face in mesh.open_faces(): + lines.append(f"{len(face)} {' '.join(str(i) for i in face)}") + lines[-1] += "\n" + return "\n".join(lines) + + +def obj_dumps(mesh: MeshBuilder) -> str: + """Returns the `OBJ`_ data as string for the given `mesh`. + The `OBJ`_ format supports ngons as faces. + + """ + lines: list[str] = [f"# OBJ generated by ezdxf {__version__}"] + for v in mesh.vertices: + v = v.round(6) + lines.append(f"v {v.x} {v.y} {v.z}") + for face in mesh.open_faces(): + # OBJ is 1-index + lines.append("f " + " ".join(str(i + 1) for i in face)) + lines[-1] += "\n" + return "\n".join(lines) + + +def scad_dumps(mesh: MeshBuilder) -> str: + """Returns the `OpenSCAD`_ `polyhedron`_ definition as string for the given + `mesh`. `OpenSCAD`_ supports ngons as faces. + + .. Important:: + + `OpenSCAD`_ requires the face normals pointing inwards, the method + :meth:`~ezdxf.render.MeshBuilder.flip_normals` of the + :class:`~ezdxf.render.MeshBuilder` class can flip the normals + inplace. + + """ + # polyhedron( points = [ [X0, Y0, Z0], [X1, Y1, Z1], ... ], faces = [ [P0, P1, P2, P3, ...], ... ], convexity = N); // 2014.03 & later + lines: list[str] = ["polyhedron(points = ["] + for v in mesh.vertices: + v = v.round(6) + lines.append(f" [{v.x}, {v.y}, {v.z}],") + # OpenSCAD accept the last "," + lines.append("], faces = [") + for face in mesh.open_faces(): + lines.append(" [" + ", ".join(str(i) for i in face) + "],") + # OpenSCAD accept the last "," + lines.append("], convexity = 10);\n") + return "\n".join(lines) + + +def ply_dumpb(mesh: MeshBuilder) -> bytes: + """Returns the `PLY`_ binary data as bytes for the given `mesh`. + The `PLY`_ format supports ngons as faces. + + """ + if any(len(f) > 255 for f in mesh.faces): + face_hdr_fmt = b"property list int int vertex_index" + face_fmt = " str: + return _guid_compress(uuid.uuid4().hex) + + +def _guid_compress(g: str) -> str: + # https://github.com/IfcOpenShell/IfcOpenShell/blob/master/src/ifcopenshell-python/ifcopenshell/guid.py#L56 + chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$" + bs = [int(g[i : i + 2], 16) for i in range(0, len(g), 2)] + + def b64(v: int, size: int = 4): + return "".join( + [chars[(v // (64**i)) % 64] for i in range(size)][::-1] + ) + + return "".join( + [b64(bs[0], 2)] + + [ + b64((bs[i] << 16) + (bs[i + 1] << 8) + bs[i + 2]) + for i in range(1, 16, 3) + ] + ) + + +class IfcEntityType(enum.Enum): + POLYGON_FACE_SET = "POLY_FACE_SET" + CLOSED_SHELL = "CLOSED_SHELL" + OPEN_SHELL = "OPEN_SHELL" + + +class Records: + def __init__(self) -> None: + # Record numbers are 1-based, record index in list is 0-based! + # records[0] is record #1 + self.records: list[str] = [] + + @property + def last_num(self) -> int: # list index + return len(self.records) + + @property + def prev_num(self) -> int: # list index + return self.last_num - 1 + + @property + def next_num(self) -> int: # list index + return self.last_num + 1 + + def add(self, record: str, num: int = 0) -> str: + assert record.endswith(");"), "invalid structure" + self.records.append(record) + if num != 0 and num != len(self.records): + raise ValueError("unexpected record number") + num = len(self.records) + return f"#{num}" + + def add_dummy(self): + self.records.append("") + + def get(self, num: int) -> str: + return self.records[num - 1] + + def update_all(self, tag: str, record_num: str): + for index, record in enumerate(self.records): + if tag in record: + self.update_record(index, tag, record_num) + + def update_record(self, index, tag: str, record_num: str): + self.records[index] = self.records[index].replace(tag, record_num) + + def dumps(self) -> str: + return "\n".join( + f"#{num+1}= {data}" for num, data in enumerate(self.records) if data + ) + + +def ifc4_dumps( + mesh: MeshBuilder, + entity_type=IfcEntityType.POLYGON_FACE_SET, + *, + layer: str = "MeshExport", + color: tuple[float, float, float] = (1.0, 1.0, 1.0), +) -> str: + """Returns the `IFC4`_ string for the given `mesh`. The caller is + responsible for checking if the mesh is a closed or open surface + (e.g. :code:`mesh.diagnose().euler_characteristic == 2`) and using the + appropriate entity type. + + Args: + mesh: :class:`~ezdxf.render.MeshBuilder` + entity_type: :class:`IfcEntityType` + layer: layer name as string + color: entity color as RGB tuple, values in the range [0,1] + + .. warning:: + + `IFC4`_ is a very complex data format and this is a minimal effort + exporter, so the exported data may not be importable by all CAD + applications. + + The exported `IFC4`_ data can be imported by the following applications: + + - BricsCAD + - FreeCAD (IfcOpenShell) + - Allplan + - Tekla BIMsight + + """ + + def make_header(): + date = datetime.datetime.now().isoformat()[:-7] + return f"""ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView_V2.0]'),'2;1'); +FILE_NAME('undefined.ifc','{date}',('Undefined'),('Undefined'),'ezdxf {__version__}','ezdxf {__version__}','Undefined'); +FILE_SCHEMA(('IFC4')); +ENDSEC; + +DATA; +""" + + def make_data_records() -> Records: + records = Records() + # fmt: off + if entity_type == IfcEntityType.POLYGON_FACE_SET: + kind = "SurfaceModel" + elif entity_type == IfcEntityType.OPEN_SHELL: + kind = "SurfaceModel" + elif entity_type == IfcEntityType.CLOSED_SHELL: + kind = "Brep" + else: + raise ValueError(f"invalid entity type: {entity_type}") + # for simplicity the first part has absolute record numbering: + records.add(f"IFCPROJECT('{ifc_guid()}',#2,'MeshExport',$,$,$,$,(#7),#13);", 1) + records.add("IFCOWNERHISTORY(#3,#6,$,$,$,$,$,0);", 2) + records.add("IFCPERSONANDORGANIZATION(#4,#5,$);", 3) + records.add("IFCPERSON($,$,'Undefined',$,$,$,$,$);", 4) + records.add("IFCORGANIZATION($,'Undefined',$,$,$);", 5) + records.add(f"IFCAPPLICATION(#5,'{__version__}','ezdxf','ezdxf');", 6) + records.add("IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.000000000000000E-05,#8,#12);", 7) + records.add("IFCAXIS2PLACEMENT3D(#9,#10,#11);", 8) + records.add("IFCCARTESIANPOINT((0.,0.,0.));", 9) + records.add("IFCDIRECTION((0.,0.,1.));", 10) + records.add("IFCDIRECTION((1.,0.,0.));", 11) + records.add("IFCDIRECTION((1.,0.));", 12) + records.add("IFCUNITASSIGNMENT((#14,#15,#16,#17,#18,#19));", 13) + records.add("IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);", 14) + records.add("IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);", 15) + records.add("IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);", 16) + records.add("IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);", 17) + records.add("IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.);", 18) + records.add("IFCSIUNIT(*,.MASSUNIT.,$,.GRAM.);", 19) + records.add("IFCLOCALPLACEMENT($,#8);", 20) + building = records.add(f"IFCBUILDING('{ifc_guid()}',#2,'MeshExport',$,$, #20,$,$,.ELEMENT.,$,$,$);", 21) + records.add_dummy() # I don't wanna redo the absolute record numbering + proxy = records.add(f"IFCBUILDINGELEMENTPROXY('{ifc_guid()}',#2,$,$,$,#24,#29,$,$);", 23) + records.add("IFCLOCALPLACEMENT(#25,#26);", 24) + records.add("IFCLOCALPLACEMENT(#20,#8);", 25) + records.add("IFCAXIS2PLACEMENT3D(#27,#10,#28);", 26) + records.add(f"IFCCARTESIANPOINT(({emin.x},{emin.y},{emin.z}));", 27) + records.add("IFCDIRECTION((1.,0.,0.));", 28) + records.add("IFCPRODUCTDEFINITIONSHAPE($,$,(#30));", 29) + shape = records.add(f"IFCSHAPEREPRESENTATION(#31,'Body','{kind}',($ENTITY$));", 30) + records.add("IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#7,$,.MODEL_VIEW.,$);", 31) + + # from here on only relative record numbering: + entity = "#0" + if entity_type == IfcEntityType.POLYGON_FACE_SET: + entity = make_polygon_face_set(records) + elif entity_type == IfcEntityType.CLOSED_SHELL: + entity = make_shell(records) + elif entity_type == IfcEntityType.OPEN_SHELL: + entity = make_shell(records) + color_str = f"IFCCOLOURRGB($,{color[0]:.3f},{color[1]:.3f},{color[2]:.3f});" + records.add(color_str) + records.add(f"IFCSURFACESTYLESHADING(#{records.prev_num+1},0.);") + records.add(f"IFCSURFACESTYLE($,.POSITIVE.,(#{records.prev_num+1}));") + records.add(f"IFCPRESENTATIONSTYLEASSIGNMENT((#{records.prev_num+1}));") + records.add(f"IFCSTYLEDITEM($ENTITY$,(#{records.prev_num+1}),$);") + records.add(f"IFCPRESENTATIONLAYERWITHSTYLE('{layer}',$,({shape}),$,.T.,.F.,.F.,(#{records.next_num+1}));") + records.add(f"IFCSURFACESTYLE($,.POSITIVE.,(#{records.next_num+1}));") + records.add(f"IFCSURFACESTYLESHADING(#{records.next_num+1},0.);") + records.add(color_str) + records.add(f"IFCRELCONTAINEDINSPATIALSTRUCTURE('{ifc_guid()}',#2,$,$,({proxy}),{building});") + records.add(f"IFCRELAGGREGATES('{ifc_guid()}',#2,$,$,#1,({building}));") + # fmt: on + records.update_all("$ENTITY$", entity) + return records + + def make_polygon_face_set(records: Records) -> str: + entity = records.add( + f"IFCPOLYGONALFACESET(#{records.next_num+1},$,($FACES$), $);" + ) + entity_num = records.last_num + vertices = ",".join([str(v.xyz) for v in mesh.vertices]) + records.add(f"IFCCARTESIANPOINTLIST3D(({vertices}));") + face_records: list[str] = [] + for face in mesh.open_faces(): + indices = ",".join(str(i + 1) for i in face) # 1-based indexing + face_records.append( + records.add(f"IFCINDEXEDPOLYGONALFACE(({indices}));") + ) + # list index required + records.update_record(entity_num - 1, "$FACES$", ",".join(face_records)) + return entity + + def make_shell(records: Records) -> str: + if entity_type == IfcEntityType.CLOSED_SHELL: + entity = records.add(f"IFCFACETEDBREP(#{records.next_num+1});") + records.add(f"IFCCLOSEDSHELL(($FACES$));") + elif entity_type == IfcEntityType.OPEN_SHELL: + entity = records.add( + f"IFCSHELLBASEDSURFACEMODEL((#{records.next_num + 1}));" + ) + records.add(f"IFCOPENSHELL(($FACES$));") + else: + raise ValueError(f"invalid entity type: {entity_type}") + shell_num = records.last_num + # add vertices + first_vertex = records.next_num + for v in mesh.vertices: + records.add(f"IFCCARTESIANPOINT({str(v.xyz)});") + # add faces + face_records: list[str] = [] + for face in mesh.open_faces(): + vertices = ",".join("#" + str(first_vertex + i) for i in face) + records.add(f"IFCPOLYLOOP(({vertices}));") + records.add(f"IFCFACEOUTERBOUND(#{records.prev_num+1},.T.);") + face_records.append( + records.add(f"IFCFACE((#{records.prev_num+1}));") + ) + # list index required + records.update_record(shell_num - 1, "$FACES$", ",".join(face_records)) + return entity + + if len(mesh.vertices) == 0: + return "" + bbox = BoundingBox(mesh.vertices) + emin = Vec3() + assert bbox.extmin is not None + if bbox.extmin.x < 0 or bbox.extmin.y < 0 or bbox.extmin.z < 0: + # Allplan (IFC?) requires all mesh vertices in the all-positive octant + # (non-negative). Record #27 does the final placement at the correct + # location. + emin = bbox.extmin + mesh = MeshTransformer.from_builder(mesh) + mesh.translate(-emin.x, -emin.y, -emin.z) + + header = make_header() + data = make_data_records() + return header + data.dumps() + "\nENDSEC;\nEND-ISO-10303-21;\n" + + +def export_ifcZIP( + filename: Union[str, os.PathLike], + mesh: MeshBuilder, + entity_type=IfcEntityType.POLYGON_FACE_SET, + *, + layer: str = "MeshExport", + color: tuple[float, float, float] = (1.0, 1.0, 1.0), +): + """Export the given `mesh` as zip-compressed `IFC4`_ file. The filename + suffix should be ``.ifcZIP``. For more information see function + :func:`ifc4_dumps`. + + Args: + filename: zip filename, the data file has the same name with suffix ``.ifc`` + mesh: :class:`~ezdxf.render.MeshBuilder` + entity_type: :class:`IfcEntityType` + layer: layer name as string + color: entity color as RGB tuple, values in the range [0,1] + + Raises: + IOError: IO error when opening the zip-file for writing + + """ + name = os.path.basename(filename) + ".ifc" + zf = zipfile.ZipFile(filename, mode="w", compression=zipfile.ZIP_DEFLATED) + try: + zf.writestr( + name, ifc4_dumps(mesh, entity_type, layer=layer, color=color) + ) + finally: + zf.close() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/mixins.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/mixins.py new file mode 100644 index 0000000..fa3569f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/mixins.py @@ -0,0 +1,19 @@ +# Copyright (c) 2011, Manfred Moitzi +# License: MIT License + + +class SubscriptAttributes: + def __getitem__(self, item): + if hasattr(self, item): + return getattr(self, item) + else: + raise KeyError(item) + + def __setitem__(self, key, value): + if hasattr(self, key): + setattr(self, key, value) + else: + raise KeyError(key) + + def __contains__(self, item): + return hasattr(self, item) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/mtextsurrogate.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/mtextsurrogate.py new file mode 100644 index 0000000..c3e69e6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/mtextsurrogate.py @@ -0,0 +1,174 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Any +import math +import enum + + +from ezdxf.enums import ( + MTextEntityAlignment, + MAP_MTEXT_ALIGN_TO_FLAGS, +) +from ezdxf.lldxf import const +from ezdxf.math import UVec, Vec3 +from .mixins import SubscriptAttributes + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +TOP_ALIGN = { + MTextEntityAlignment.TOP_LEFT, + MTextEntityAlignment.TOP_RIGHT, + MTextEntityAlignment.TOP_CENTER, +} +MIDDLE_ALIGN = { + MTextEntityAlignment.MIDDLE_LEFT, + MTextEntityAlignment.MIDDLE_CENTER, + MTextEntityAlignment.MIDDLE_RIGHT, +} + + +class Mirror(enum.IntEnum): + NONE = 0 + MIRROR_X = 2 + MIRROR_Y = 4 + + +class MTextSurrogate(SubscriptAttributes): + """MTEXT surrogate for DXF R12 build up by TEXT Entities. This add-on was + added to simplify the transition from :mod:`dxfwrite` to :mod:`ezdxf`. + + The rich-text formatting capabilities for the regular MTEXT entity are not + supported, if these features are required use the regular MTEXT entity and + the :class:`~ezdxf.addons.MTextExplode` add-on to explode the MTEXT entity + into DXF primitives. + + .. important:: + + The align-point is always the insert-point, there is no need for + a second align-point because the horizontal alignments FIT, ALIGN, + BASELINE_MIDDLE are not supported. + + Args: + text: content as string + insert: insert location in drawing units + line_spacing: line spacing in percent of height, 1.5 = 150% = 1+1/2 lines + align: text alignment as :class:`~ezdxf.enums.MTextEntityAlignment` enum + char_height: text height in drawing units + style: :class:`~ezdxf.entities.Textstyle` name as string + oblique: oblique angle in degrees, where 0 is vertical + rotation: text rotation angle in degrees + width_factor: text width factor as float + mirror: :attr:`MTextSurrogate.MIRROR_X` to mirror the text horizontal + or :attr:`MTextSurrogate.MIRROR_Y` to mirror the text vertical + layer: layer name as string + color: :ref:`ACI` + + """ + + MIRROR_NONE = Mirror.NONE + MIRROR_X = Mirror.MIRROR_X + MIRROR_Y = Mirror.MIRROR_Y + + def __init__( + self, + text: str, + insert: UVec, + line_spacing: float = 1.5, + align=MTextEntityAlignment.TOP_LEFT, + char_height: float = 1.0, + style="STANDARD", + oblique: float = 0.0, + rotation: float = 0.0, + width_factor: float = 1.0, + mirror=Mirror.NONE, + layer="0", + color: int = const.BYLAYER, + ): + self.content: list[str] = text.split("\n") + self.insert = Vec3(insert) + self.line_spacing = float(line_spacing) + assert isinstance(align, MTextEntityAlignment) + self.align = align + + self.char_height = float(char_height) + self.style = str(style) + self.oblique = float(oblique) # in degree + self.rotation = float(rotation) # in degree + self.width_factor = float(width_factor) + self.mirror = int(mirror) # renamed to text_generation_flag in ezdxf + self.layer = str(layer) + self.color = int(color) + + @property + def line_height(self) -> float: + """Absolute line spacing in drawing units.""" + return self.char_height * self.line_spacing + + def render(self, layout: GenericLayoutType) -> None: + """Render the multi-line content as separated TEXT entities into the + given `layout` instance. + """ + text_lines = self.content + if len(text_lines) > 1: + if self.mirror & const.MIRROR_Y: + text_lines.reverse() + for line_number, text in enumerate(text_lines): + align_point = self._get_align_point(line_number) + layout.add_text( + text, + dxfattribs=self._dxfattribs(align_point), + ) + elif len(text_lines) == 1: + layout.add_text( + text_lines[0], + dxfattribs=self._dxfattribs(self.insert), + ) + + def _get_align_point(self, line_number: int) -> Vec3: + """Calculate the align-point depending on the line number.""" + x = self.insert.x + y = self.insert.y + try: + z = self.insert.z + except IndexError: + z = 0.0 + # rotation not respected + + if self.align in TOP_ALIGN: + y -= line_number * self.line_height + elif self.align in MIDDLE_ALIGN: + y0 = line_number * self.line_height + full_height = (len(self.content) - 1) * self.line_height + y += (full_height / 2) - y0 + else: # BOTTOM ALIGN + y += (len(self.content) - 1 - line_number) * self.line_height + return self._rotate(Vec3(x, y, z)) + + def _rotate(self, alignpoint: Vec3) -> Vec3: + """Rotate `alignpoint` around insert-point about rotation degrees.""" + dx = alignpoint.x - self.insert.x + dy = alignpoint.y - self.insert.y + beta = math.radians(self.rotation) + x = self.insert.x + dx * math.cos(beta) - dy * math.sin(beta) + y = self.insert.y + dy * math.cos(beta) + dx * math.sin(beta) + return Vec3(round(x, 6), round(y, 6), alignpoint.z) + + def _dxfattribs(self, align_point: Vec3) -> dict[str, Any]: + """Build keyword arguments for TEXT entity creation.""" + halign, valign = MAP_MTEXT_ALIGN_TO_FLAGS[self.align] + return { + "insert": align_point, + "align_point": align_point, + "layer": self.layer, + "color": self.color, + "style": self.style, + "height": self.char_height, + "width": self.width_factor, + "text_generation_flag": self.mirror, + "rotation": self.rotation, + "oblique": self.oblique, + "halign": halign, + "valign": valign, + } diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/mtxpl.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/mtxpl.py new file mode 100644 index 0000000..8b6b2b2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/mtxpl.py @@ -0,0 +1,388 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import cast, Any, Optional, TYPE_CHECKING +import math +import ezdxf +from ezdxf.entities import MText, DXFGraphic, Textstyle +from ezdxf.enums import TextEntityAlignment + +# from ezdxf.layouts import BaseLayout +from ezdxf.document import Drawing +from ezdxf.math import Matrix44 +from ezdxf.fonts import fonts +from ezdxf.tools import text_layout as tl +from ezdxf.tools.text import MTextContext +from ezdxf.render.abstract_mtext_renderer import AbstractMTextRenderer + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +__all__ = ["MTextExplode"] + + +class FrameRenderer(tl.ContentRenderer): + def __init__(self, attribs: dict, layout: GenericLayoutType): + self.line_attribs = attribs + self.layout = layout + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ) -> None: + pline = self.layout.add_lwpolyline( + [(left, top), (right, top), (right, bottom), (left, bottom)], + close=True, + dxfattribs=self.line_attribs, + ) + if m: + pline.transform(m) + + def line( + self, x1: float, y1: float, x2: float, y2: float, m: Matrix44 = None + ) -> None: + line = self.layout.add_line((x1, y1), (x2, y2), dxfattribs=self.line_attribs) + if m: + line.transform(m) + + +class ColumnBackgroundRenderer(FrameRenderer): + def __init__( + self, + attribs: dict, + layout: GenericLayoutType, + bg_aci: Optional[int] = None, + bg_true_color: Optional[int] = None, + offset: float = 0, + text_frame: bool = False, + ): + super().__init__(attribs, layout) + self.solid_attribs = None + if bg_aci is not None: + self.solid_attribs = dict(attribs) + self.solid_attribs["color"] = bg_aci + elif bg_true_color is not None: + self.solid_attribs = dict(attribs) + self.solid_attribs["true_color"] = bg_true_color + self.offset = offset # background border offset + self.has_text_frame = text_frame + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Optional[Matrix44] = None, + ) -> None: + # Important: this is not a clipping box, it is possible to + # render anything outside of the given borders! + offset = self.offset + left -= offset + right += offset + top += offset + bottom -= offset + if self.solid_attribs is not None: + solid = self.layout.add_solid( + # SOLID! swap last two vertices: + [(left, top), (right, top), (left, bottom), (right, bottom)], + dxfattribs=self.solid_attribs, + ) + if m: + solid.transform(m) + if self.has_text_frame: + super().render(left, bottom, right, top, m) + + +class TextRenderer(FrameRenderer): + """Text content renderer.""" + + def __init__( + self, + text: str, + text_attribs: dict, + line_attribs: dict, + layout: GenericLayoutType, + ): + super().__init__(line_attribs, layout) + self.text = text + self.text_attribs = text_attribs + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Optional[Matrix44] = None, + ): + """Create/render the text content""" + text = self.layout.add_text(self.text, dxfattribs=self.text_attribs) + text.set_placement((left, bottom), align=TextEntityAlignment.LEFT) + if m: + text.transform(m) + + +# todo: replace by fonts.get_entity_font_face() +def get_font_face(entity: DXFGraphic, doc=None) -> fonts.FontFace: + """Returns the :class:`~ezdxf.tools.fonts.FontFace` defined by the + associated text style. Returns the default font face if the `entity` does + not have or support the DXF attribute "style". + + Pass a DXF document as argument `doc` to resolve text styles for virtual + entities which are not assigned to a DXF document. The argument `doc` + always overrides the DXF document to which the `entity` is assigned to. + + """ + if entity.doc and doc is None: + doc = entity.doc + assert doc is not None, "valid DXF document required" + + style_name = "" + # This works also for entities which do not support "style", + # where style_name = entity.dxf.get("style") would fail. + if entity.dxf.is_supported("style"): + style_name = entity.dxf.style + + font_face = fonts.FontFace() + if style_name and doc is not None: + style = cast(Textstyle, doc.styles.get(style_name)) + family, italic, bold = style.get_extended_font_data() + if family: + text_style = "Italic" if italic else "Regular" + text_weight = 700 if bold else 400 + font_face = fonts.FontFace( + family=family, style=text_style, weight=text_weight + ) + else: + ttf = style.dxf.font + if ttf: + font_face = fonts.get_font_face(ttf) + return font_face + + +def get_color_attribs(ctx: MTextContext) -> dict: + attribs = {"color": ctx.aci} + if ctx.rgb is not None: + attribs["true_color"] = ezdxf.rgb2int(ctx.rgb) + return attribs + + +def make_bg_renderer(mtext: MText, layout: GenericLayoutType): + attribs = get_base_attribs(mtext) + dxf = mtext.dxf + bg_fill = dxf.get("bg_fill", 0) + + bg_aci = None + bg_true_color = None + has_text_frame = False + offset = 0 + if bg_fill: + # The fill scale is a multiple of the initial char height and + # a scale of 1, fits exact the outer border + # of the column -> offset = 0 + offset = dxf.char_height * (dxf.get("box_fill_scale", 1.5) - 1) + if bg_fill & ezdxf.const.MTEXT_BG_COLOR: + if dxf.hasattr("bg_fill_color"): + bg_aci = dxf.bg_fill_color + + if dxf.hasattr("bg_fill_true_color"): + bg_aci = None + bg_true_color = dxf.bg_fill_true_color + + if (bg_fill & 3) == 3: # canvas color = bit 0 and 1 set + # can not detect canvas color from DXF document! + # do not draw any background: + bg_aci = None + bg_true_color = None + + if bg_fill & ezdxf.const.MTEXT_TEXT_FRAME: + has_text_frame = True + + return ColumnBackgroundRenderer( + attribs, + layout, + bg_aci=bg_aci, + bg_true_color=bg_true_color, + offset=offset, + text_frame=has_text_frame, + ) + + +def get_base_attribs(mtext: MText) -> dict: + dxf = mtext.dxf + attribs = { + "layer": dxf.layer, + "color": dxf.color, + } + return attribs + + +class MTextExplode(AbstractMTextRenderer): + """The :class:`MTextExplode` class is a tool to disassemble MTEXT entities + into single line TEXT entities and additional LINE entities if required to + emulate strokes. + + The `layout` argument defines the target layout for "exploded" parts of the + MTEXT entity. Use argument `doc` if the target layout has no DXF document assigned + like virtual layouts. The `spacing_factor` argument is an advanced tuning parameter + to scale the size of space chars. + + """ + + def __init__( + self, + layout: GenericLayoutType, + doc: Optional[Drawing] = None, + spacing_factor: float = 1.0, + ): + super().__init__() + self.layout: GenericLayoutType = layout + self._doc = doc + # scale the width of spaces by this factor: + self._spacing_factor = float(spacing_factor) + self._required_text_styles: dict[str, fonts.FontFace] = {} + self.current_base_attribs: dict[str, Any] = dict() + + # Implementation of required AbstractMTextRenderer methods and overrides: + + def layout_engine(self, mtext: MText) -> tl.Layout: + self.current_base_attribs = get_base_attribs(mtext) + return super().layout_engine(mtext) + + def word(self, text: str, ctx: MTextContext) -> tl.ContentCell: + line_attribs = dict(self.current_base_attribs or {}) + line_attribs.update(get_color_attribs(ctx)) + text_attribs = dict(line_attribs) + text_attribs.update(self.get_text_attribs(ctx)) + return tl.Text( + width=self.get_font(ctx).text_width(text), + height=ctx.cap_height, + valign=tl.CellAlignment(ctx.align), + stroke=self.get_stroke(ctx), + renderer=TextRenderer(text, text_attribs, line_attribs, self.layout), + ) + + def fraction(self, data: tuple, ctx: MTextContext) -> tl.ContentCell: + upr, lwr, type_ = data + if type_: + return tl.Fraction( + top=self.word(upr, ctx), + bottom=self.word(lwr, ctx), + stacking=self.get_stacking(type_), + # renders just the divider line: + renderer=FrameRenderer(self.current_base_attribs, self.layout), + ) + else: + return self.word(upr, ctx) + + def get_font_face(self, mtext: MText) -> fonts.FontFace: + return get_font_face(mtext) + + def make_bg_renderer(self, mtext: MText) -> tl.ContentRenderer: + return make_bg_renderer(mtext, self.layout) + + # Implementation details of MTextExplode: + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.finalize() + + def mtext_exploded_text_style(self, font_face: fonts.FontFace) -> str: + style = 0 + if font_face.is_bold: + style += 1 + if font_face.is_italic: + style += 2 + style_str = str(style) if style > 0 else "" + # BricsCAD naming convention for exploded MTEXT styles: + text_style = f"MtXpl_{font_face.family}" + style_str + self._required_text_styles[text_style] = font_face + return text_style + + def get_font(self, ctx: MTextContext) -> fonts.AbstractFont: + ttf = fonts.find_font_file_name(ctx.font_face) + key = (ttf, ctx.cap_height, ctx.width_factor) + font = self._font_cache.get(key) + if font is None: + font = fonts.make_font(ttf, ctx.cap_height, ctx.width_factor) + self._font_cache[key] = font + return font + + def get_text_attribs(self, ctx: MTextContext) -> dict: + attribs = { + "height": ctx.cap_height, + "style": self.mtext_exploded_text_style(ctx.font_face), + } + if not math.isclose(ctx.width_factor, 1.0): + attribs["width"] = ctx.width_factor + if abs(ctx.oblique) > 1e-6: + attribs["oblique"] = ctx.oblique + return attribs + + def explode(self, mtext: MText, destroy=True): + """Explode `mtext` and destroy the source entity if argument `destroy` + is ``True``. + """ + align = tl.LayoutAlignment(mtext.dxf.attachment_point) + layout_engine = self.layout_engine(mtext) + layout_engine.place(align=align) + layout_engine.render(mtext.ucs().matrix) + if destroy: + mtext.destroy() + + def finalize(self): + """Create required text styles. This method is called automatically if + the class is used as context manager. This method does not work with virtual + layouts if no document was assigned at initialization! + """ + + doc = self._doc + if doc is None: + doc = self.layout.doc + if doc is None: + raise ezdxf.DXFValueError( + "DXF document required, finalize() does not work with virtual layouts " + "if no document was assigned at initialization." + ) + text_styles = doc.styles + for style in self.make_required_style_table_entries(): + try: + text_styles.add_entry(style) + except ezdxf.DXFTableEntryError: + pass + + def make_required_style_table_entries(self) -> list[Textstyle]: + def ttf_path(font_face: fonts.FontFace) -> str: + ttf = font_face.filename + if not ttf: + ttf = fonts.find_font_file_name(font_face) + else: + # remapping SHX replacement fonts to SHX fonts, + # like "txt_____.ttf" to "TXT.SHX": + shx = fonts.map_ttf_to_shx(ttf) + if shx: + ttf = shx + return ttf + + text_styles: list[Textstyle] = [] + for name, font_face in self._required_text_styles.items(): + ttf = ttf_path(font_face) + style = Textstyle.new(dxfattribs={ + "name": name, + "font": ttf, + }) + if not ttf.endswith(".SHX"): + style.set_extended_font_data( + font_face.family, + italic=font_face.is_italic, + bold=font_face.is_bold, + ) + text_styles.append(style) + return text_styles diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/odafc.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/odafc.py new file mode 100644 index 0000000..9559a7d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/odafc.py @@ -0,0 +1,507 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +# type: ignore +from __future__ import annotations +from typing import Optional +import logging +import os +import platform +import shutil +import subprocess +import tempfile +import time +from contextlib import contextmanager +from pathlib import Path + +import ezdxf +from ezdxf.document import Drawing +from ezdxf.lldxf.validator import ( + is_dxf_file, + dxf_info, + is_binary_dxf_file, + dwg_version, +) + +logger = logging.getLogger("ezdxf") +win_exec_path = ezdxf.options.get("odafc-addon", "win_exec_path").strip('"') +unix_exec_path = ezdxf.options.get("odafc-addon", "unix_exec_path").strip('"') + + +class ODAFCError(IOError): + pass + + +class UnknownODAFCError(ODAFCError): + pass + + +class ODAFCNotInstalledError(ODAFCError): + pass + + +class UnsupportedFileFormat(ODAFCError): + pass + + +class UnsupportedPlatform(ODAFCError): + pass + + +class UnsupportedVersion(ODAFCError): + pass + + +VERSION_MAP = { + "R12": "ACAD12", + "R13": "ACAD13", + "R14": "ACAD14", + "R2000": "ACAD2000", + "R2004": "ACAD2004", + "R2007": "ACAD2007", + "R2010": "ACAD2010", + "R2013": "ACAD2013", + "R2018": "ACAD2018", + "AC1004": "ACAD9", + "AC1006": "ACAD10", + "AC1009": "ACAD12", + "AC1012": "ACAD13", + "AC1014": "ACAD14", + "AC1015": "ACAD2000", + "AC1018": "ACAD2004", + "AC1021": "ACAD2007", + "AC1024": "ACAD2010", + "AC1027": "ACAD2013", + "AC1032": "ACAD2018", +} + +VALID_VERSIONS = { + "ACAD9", + "ACAD10", + "ACAD12", + "ACAD13", + "ACAD14", + "ACAD2000", + "ACAD2004", + "ACAD2007", + "ACAD2010", + "ACAD2013", + "ACAD2018", +} + +WINDOWS = "Windows" +LINUX = "Linux" +DARWIN = "Darwin" + + +def is_installed() -> bool: + """Returns ``True`` if the ODAFileConverter is installed.""" + if platform.system() in (LINUX, DARWIN): + if unix_exec_path and Path(unix_exec_path).is_file(): + return True + return shutil.which("ODAFileConverter") is not None + # Windows: + return os.path.exists(win_exec_path) + + +def map_version(version: str) -> str: + return VERSION_MAP.get(version.upper(), version.upper()) + + +def readfile( + filename: str | os.PathLike, version: Optional[str] = None, *, audit: bool = False +) -> Drawing: + """Uses an installed `ODA File Converter`_ to convert a DWG/DXB/DXF file + into a temporary DXF file and load this file by `ezdxf`. + + Args: + filename: file to load by ODA File Converter + version: load file as specific DXF version, by default the same version + as the source file or if not detectable the latest by `ezdxf` + supported version. + audit: audit source file before loading + + Raises: + FileNotFoundError: source file not found + odafc.UnknownODAFCError: conversion failed for unknown reasons + odafc.UnsupportedVersion: invalid DWG version specified + odafc.UnsupportedFileFormat: unsupported file extension + odafc.ODAFCNotInstalledError: ODA File Converter not installed + + """ + infile = Path(filename).absolute() + if not infile.is_file(): + raise FileNotFoundError(f"No such file: '{infile}'") + if isinstance(version, str): + version = map_version(version) + else: + version = _detect_version(filename) + + with tempfile.TemporaryDirectory(prefix="odafc_") as tmp_dir: + args = _odafc_arguments( + infile.name, + str(infile.parent), + tmp_dir, + output_format="DXF", + version=version, + audit=audit, + ) + _execute_odafc(args) + out_file = Path(tmp_dir) / infile.with_suffix(".dxf").name + if out_file.exists(): + doc = ezdxf.readfile(str(out_file)) + doc.filename = str(infile.with_suffix(".dxf")) + return doc + raise UnknownODAFCError("Failed to convert file: Unknown Error") + + +def export_dwg( + doc: Drawing, + filename: str | os.PathLike, + version: Optional[str] = None, + *, + audit: bool = False, + replace: bool = False, +) -> None: + """Uses an installed `ODA File Converter`_ to export the DXF document `doc` + as a DWG file. + + A temporary DXF file will be created and converted to DWG by the + ODA File Converter. If `version` is not specified the DXF version of the + source document is used. + + Args: + doc: `ezdxf` DXF document as :class:`~ezdxf.drawing.Drawing` object + filename: output DWG filename, the extension will be set to ".dwg" + version: DWG version to export, by default the same version as + the source document. + audit: audit source file by ODA File Converter at exporting + replace: replace existing DWG file if ``True`` + + Raises: + FileExistsError: target file already exists, and argument `replace` is + ``False`` + FileNotFoundError: parent directory of target file does not exist + odafc.UnknownODAFCError: exporting DWG failed for unknown reasons + odafc.ODAFCNotInstalledError: ODA File Converter not installed + + """ + if version is None: + version = doc.dxfversion + export_version = VERSION_MAP[version] + dwg_file = Path(filename).absolute() + out_folder = Path(dwg_file.parent) + if dwg_file.exists(): + if replace: + dwg_file.unlink() + else: + raise FileExistsError(f"File already exists: {dwg_file}") + if out_folder.exists(): + with tempfile.TemporaryDirectory(prefix="odafc_") as tmp_dir: + dxf_file = Path(tmp_dir) / dwg_file.with_suffix(".dxf").name + + # Save DXF document + old_filename = doc.filename + doc.saveas(dxf_file) + doc.filename = old_filename + + arguments = _odafc_arguments( + dxf_file.name, + tmp_dir, + str(out_folder), + output_format="DWG", + version=export_version, + audit=audit, + ) + _execute_odafc(arguments) + else: + raise FileNotFoundError(f"No such file or directory: '{str(out_folder)}'") + + +def convert( + source: str | os.PathLike, + dest: str | os.PathLike = "", + *, + version="R2018", + audit=True, + replace=False, +): + """Convert `source` file to `dest` file. + + The file extension defines the target format + e.g. :code:`convert("test.dxf", "Test.dwg")` converts the source file to a + DWG file. + If `dest` is an empty string the conversion depends on the source file + format and is DXF to DWG or DWG to DXF. + To convert DXF to DXF an explicit destination filename is required: + :code:`convert("r12.dxf", "r2013.dxf", version="R2013")` + + Args: + source: source file + dest: destination file, an empty string uses the source filename with + the extension of the target format e.g. "test.dxf" -> "test.dwg" + version: output DXF/DWG version e.g. "ACAD2018", "R2018", "AC1032" + audit: audit files + replace: replace existing destination file + + Raises: + FileNotFoundError: source file or destination folder does not exist + FileExistsError: destination file already exists and argument `replace` + is ``False`` + odafc.UnsupportedVersion: invalid DXF version specified + odafc.UnsupportedFileFormat: unsupported file extension + odafc.UnknownODAFCError: conversion failed for unknown reasons + odafc.ODAFCNotInstalledError: ODA File Converter not installed + + """ + version = map_version(version) + if version not in VALID_VERSIONS: + raise UnsupportedVersion(f"Invalid version: '{version}'") + src_path = Path(source).expanduser().absolute() + if not src_path.exists(): + raise FileNotFoundError(f"Source file not found: '{source}'") + if dest: + dest_path = Path(dest) + else: + ext = src_path.suffix.lower() + if ext == ".dwg": + dest_path = src_path.with_suffix(".dxf") + elif ext == ".dxf": + dest_path = src_path.with_suffix(".dwg") + else: + raise UnsupportedFileFormat(f"Unsupported file format: '{ext}'") + if dest_path.exists() and not replace: + raise FileExistsError(f"Target file already exists: '{dest_path}'") + parent_dir = dest_path.parent + if not parent_dir.exists() or not parent_dir.is_dir(): + # Cannot copy result to destination folder! + raise FileNotFoundError(f"Destination folder does not exist: '{parent_dir}'") + ext = dest_path.suffix + fmt = ext.upper()[1:] + if fmt not in ("DXF", "DWG"): + raise UnsupportedFileFormat(f"Unsupported file format: '{ext}'") + + with tempfile.TemporaryDirectory(prefix="odafc_") as tmp_dir: + arguments = _odafc_arguments( + src_path.name, + in_folder=str(src_path.parent), + out_folder=str(tmp_dir), + output_format=fmt, + version=version, + audit=audit, + ) + _execute_odafc(arguments) + result = list(Path(tmp_dir).iterdir()) + if result: + try: + shutil.move(result[0], dest_path) + except IOError: + shutil.copy(result[0], dest_path) + else: + UnknownODAFCError(f"Unknown error: no {fmt} file was created") + + +def _detect_version(path: str) -> str: + """Returns the DXF/DWG version of file `path` as ODAFC compatible version + string. + + Raises: + odafc.UnsupportedVersion: unknown or unsupported DWG version + odafc.UnsupportedFileFormat; unsupported file extension + + """ + version = "ACAD2018" + ext = os.path.splitext(path)[1].lower() + if ext == ".dxf": + if is_binary_dxf_file(path): + pass + elif is_dxf_file(path): + with open(path, "rt") as fp: + info = dxf_info(fp) + version = VERSION_MAP[info.version] + elif ext == ".dwg": + version = dwg_version(path) + if version is None: + raise UnsupportedVersion("Unknown or unsupported DWG version.") + else: + raise UnsupportedFileFormat(f"Unsupported file format: '{ext}'") + + return map_version(version) + + +def _odafc_arguments( + filename: str, + in_folder: str, + out_folder: str, + output_format: str = "DXF", + version: str = "ACAD2013", + audit: bool = False, +) -> list[str]: + """ODA File Converter command line format: + + ODAFileConverter "Input Folder" "Output Folder" version type recurse audit [filter] + + - version: output version: "ACAD9" - "ACAD2018" + - type: output file type: "DWG", "DXF", "DXB" + - recurse: recurse Input Folder: "0" or "1" + - audit: audit each file: "0" or "1" + - optional Input files filter: default "*.DWG,*.DXF" + + """ + recurse = "0" + audit_str = "1" if audit else "0" + return [ + in_folder, + out_folder, + version, + output_format, + recurse, + audit_str, + filename, + ] + + +def _get_odafc_path(system: str) -> str: + """Get ODAFC application path. + + Raises: + odafc.ODAFCNotInstalledError: ODA File Converter not installed + + """ + # on Linux and Darwin check if UNIX_EXEC_PATH is set and exist and + # return this path as exec path. + # This may help if the "which" command can not find the "ODAFileConverter" + # command and also adds support for AppImages provided by ODA. + if system != WINDOWS and unix_exec_path: + if Path(unix_exec_path).is_file(): + return unix_exec_path + else: + logger.warning( + f"command '{unix_exec_path}' not found, using 'ODAFileConverter'" + ) + + path = shutil.which("ODAFileConverter") + if not path and system == WINDOWS: + path = win_exec_path + if not Path(path).is_file(): + path = None + + if not path: + raise ODAFCNotInstalledError( + f"Could not find ODAFileConverter in the path. " + f"Install application from https://www.opendesign.com/guestfiles/oda_file_converter" + ) + return path + + +@contextmanager +def _linux_dummy_display(): + """See xvbfwrapper library for a more feature complete xvfb interface.""" + if shutil.which("Xvfb"): + display = ":123" # arbitrary choice + proc = subprocess.Popen( + ["Xvfb", display, "-screen", "0", "800x600x24"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + time.sleep(0.1) + yield display + try: + proc.terminate() + proc.wait() + except OSError: + pass + else: + logger.warning(f"Install xvfb to prevent the ODAFileConverter GUI from opening") + yield os.environ["DISPLAY"] + + +def _run_with_no_gui( + system: str, command: str, arguments: list[str] +) -> subprocess.Popen: + """Execute ODAFC application without launching the GUI. + + Args: + system: "Linux", "Windows" or "Darwin" + command: application to execute + arguments: ODAFC argument list + + Raises: + odafc.UnsupportedPlatform: for unsupported platforms + odafc.ODAFCNotInstalledError: ODA File Converter not installed + + """ + if system == LINUX: + with _linux_dummy_display() as display: + env = os.environ.copy() + env["DISPLAY"] = display + proc = subprocess.run([command] + arguments, text=True, capture_output=True, env=env) + + elif system == DARWIN: + # TODO: unknown how to prevent the GUI from appearing on macOS + proc = subprocess.run([command] + arguments, text=True, capture_output=True) + + elif system == WINDOWS: + # New code from George-Jiang to solve the GUI pop-up problem + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags = ( + subprocess.CREATE_NEW_CONSOLE | subprocess.STARTF_USESHOWWINDOW + ) + startupinfo.wShowWindow = subprocess.SW_HIDE + proc = subprocess.Popen( + [command] + arguments, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + startupinfo=startupinfo, + ) + proc.wait() + else: + # The OpenDesign Alliance only provides executables for Linux, macOS + # and Windows: + raise UnsupportedPlatform(f"Unsupported platform: {system}") + return proc + + +def _odafc_failed(system: str, returncode: int, stderr: str) -> bool: + # changed v0.18.1, see https://github.com/mozman/ezdxf/issues/707 + stderr = stderr.strip() + if system == LINUX: + # ODAFileConverter *always* crashes on Linux even if the output was successful + return stderr != "" and stderr != "Quit (core dumped)" + elif returncode != 0: + return True + else: + return stderr != "" + + +def _execute_odafc(arguments: list[str]) -> Optional[bytes]: + """Execute ODAFC application. + + Args: + arguments: ODAFC argument list + + Raises: + odafc.ODAFCNotInstalledError: ODA File Converter not installed + odafc.UnknownODAFCError: execution failed for unknown reasons + odafc.UnsupportedPlatform: for unsupported platforms + + """ + logger.debug(f"Running ODAFileConverter with arguments: {arguments}") + system = platform.system() + oda_fc = _get_odafc_path(system) + proc = _run_with_no_gui(system, oda_fc, arguments) + returncode = proc.returncode + if system == WINDOWS: + stdout = proc.stdout.read().decode("utf-8") + stderr = proc.stderr.read().decode("utf-8") + else: + stdout = proc.stdout + stderr = proc.stderr + + if _odafc_failed(system, returncode, stderr): + msg = ( + f"ODA File Converter failed: return code = {returncode}.\n" + f"stdout: {stdout}\nstderr: {stderr}" + ) + logger.debug(msg) + raise UnknownODAFCError(msg) + return stdout diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/openscad.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/openscad.py new file mode 100644 index 0000000..962409a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/openscad.py @@ -0,0 +1,317 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, Iterable, Sequence, Optional +from pathlib import Path +import enum +import platform +import shutil +import subprocess +from uuid import uuid4 +import tempfile + +import ezdxf +from ezdxf.math import Matrix44, UVec, Vec3, Vec2 +from ezdxf.render import MeshBuilder, MeshTransformer +from ezdxf.addons import meshex + + +DEFAULT_WIN_OPENSCAD_PATH = ezdxf.options.get( + "openscad-addon", "win_exec_path" +).strip('"') +CMD = "openscad" + + +class Operation(enum.Enum): + union = 0 + difference = 1 + intersection = 2 + + +UNION = Operation.union +DIFFERENCE = Operation.difference +INTERSECTION = Operation.intersection + + +def get_openscad_path() -> str: + if platform.system() in ("Linux", "Darwin"): + return CMD + else: + return DEFAULT_WIN_OPENSCAD_PATH + + +def is_installed() -> bool: + r"""Returns ``True`` if OpenSCAD is installed. On Windows only the + default install path 'C:\\Program Files\\OpenSCAD\\openscad.exe' is checked. + """ + if platform.system() in ("Linux", "Darwin"): + return shutil.which(CMD) is not None + return Path(DEFAULT_WIN_OPENSCAD_PATH).exists() + + +def run(script: str, exec_path: Optional[str] = None) -> MeshTransformer: + """Executes the given `script` by OpenSCAD and returns the result mesh as + :class:`~ezdxf.render.MeshTransformer`. + + Args: + script: the OpenSCAD script as string + exec_path: path to the executable as string or ``None`` to use the + default installation path + + """ + if exec_path is None: + exec_path = get_openscad_path() + + workdir = Path(tempfile.gettempdir()) + uuid = str(uuid4()) + # The OFF format is more compact than the default STL format + off_path = workdir / f"ezdxf_{uuid}.off" + scad_path = workdir / f"ezdxf_{uuid}.scad" + + scad_path.write_text(script) + subprocess.call( + [ + exec_path, + "--quiet", + "-o", + str(off_path), + str(scad_path), + ] + ) + # Remove the OpenSCAD temp file: + scad_path.unlink(missing_ok=True) + + new_mesh = MeshTransformer() + # Import the OpenSCAD result from OFF file: + if off_path.exists(): + new_mesh = meshex.off_loads(off_path.read_text()) + + # Remove the OFF temp file: + off_path.unlink(missing_ok=True) + return new_mesh + + +def str_matrix44(m: Matrix44) -> str: + # OpenSCAD uses column major order! + import numpy as np + + def cleanup(values: Iterable) -> Iterable: + for value in values: + if isinstance(value, np.float64): + yield float(value) + else: + yield value + + s = ", ".join([str(list(cleanup(c))) for c in m.columns()]) + return f"[{s}]" + + +def str_polygon( + path: Iterable[UVec], + holes: Optional[Sequence[Iterable[UVec]]] = None, +) -> str: + """Returns a ``polygon()`` command as string. This is a 2D command, all + z-axis values of the input vertices are ignored and all paths and holes + are closed automatically. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem#polygon + + Args: + path: exterior path + holes: a sequences of one or more holes as vertices + + """ + + def add_vertices(vertices): + index = len(points) + indices = [] + vlist = Vec2.list(vertices) + if not vlist[0].isclose(vlist[-1]): + vlist.append(vlist[0]) + + for v in vlist: + indices.append(index) + points.append(f" [{v.x:g}, {v.y:g}],") + index += 1 + return indices + + points: list[str] = [] + paths = [add_vertices(path)] + if holes is not None: + for hole in holes: + paths.append(add_vertices(hole)) + lines = ["polygon(points = ["] + lines.extend(points) + lines.append("],") + if holes is not None: + lines.append("paths = [") + for indices in paths: + lines.append(f" {str(indices)},") + lines.append("],") + lines.append("convexity = 10);") + return "\n".join(lines) + + +class Script: + def __init__(self) -> None: + self.data: list[str] = [] + + def add(self, data: str) -> None: + """Add a string.""" + self.data.append(data) + + def add_polyhedron(self, mesh: MeshBuilder) -> None: + """Add `mesh` as ``polyhedron()`` command. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#polyhedron + + """ + self.add(meshex.scad_dumps(mesh)) + + def add_polygon( + self, + path: Iterable[UVec], + holes: Optional[Sequence[Iterable[UVec]]] = None, + ) -> None: + """Add a ``polygon()`` command. This is a 2D command, all + z-axis values of the input vertices are ignored and all paths and holes + are closed automatically. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem#polygon + + Args: + path: exterior path + holes: a sequence of one or more holes as vertices, or ``None`` for no holes + + """ + self.add(str_polygon(path, holes)) + + def add_multmatrix(self, m: Matrix44) -> None: + """Add a transformation matrix of type :class:`~ezdxf.math.Matrix44` as + ``multmatrix()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#multmatrix + + """ + self.add(f"multmatrix(m = {str_matrix44(m)})") # no pending ";" + + def add_translate(self, v: UVec) -> None: + """Add a ``translate()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#translate + + Args: + v: translation vector + + """ + vec = Vec3(v) + self.add(f"translate(v = [{vec.x:g}, {vec.y:g}, {vec.z:g}])") + + def add_rotate(self, ax: float, ay: float, az: float) -> None: + """Add a ``rotation()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#rotate + + Args: + ax: rotation about the x-axis in degrees + ay: rotation about the y-axis in degrees + az: rotation about the z-axis in degrees + + """ + self.add(f"rotate(a = [{ax:g}, {ay:g}, {az:g}])") + + def add_rotate_about_axis(self, a: float, v: UVec) -> None: + """Add a ``rotation()`` operation about the given axis `v`. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#rotate + + Args: + a: rotation angle about axis `v` in degrees + v: rotation axis as :class:`ezdxf.math.UVec` object + + """ + vec = Vec3(v) + self.add(f"rotate(a = {a:g}, v = [{vec.x:g}, {vec.y:g}, {vec.z:g}])") + + def add_scale(self, sx: float, sy: float, sz: float) -> None: + """Add a ``scale()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#scale + + Args: + sx: scaling factor for the x-axis + sy: scaling factor for the y-axis + sz: scaling factor for the z-axis + + """ + self.add(f"scale(v = [{sx:g}, {sy:g}, {sz:g}])") + + def add_resize( + self, + nx: float, + ny: float, + nz: float, + auto: Optional[Union[bool, tuple[bool, bool, bool]]] = None, + ) -> None: + """Add a ``resize()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#resize + + Args: + nx: new size in x-axis + ny: new size in y-axis + nz: new size in z-axis + auto: If the `auto` argument is set to ``True``, the operation + auto-scales any 0-dimensions to match. Set the `auto` argument + as a 3-tuple of bool values to auto-scale individual axis. + + """ + main = f"resize(newsize = [{nx:g}, {ny:g}, {nz:g}]" + if auto is None: + self.add(main + ")") + return + elif isinstance(auto, bool): + flags = str(auto).lower() + else: + flags = ", ".join([str(a).lower() for a in auto]) + flags = f"[{flags}]" + self.add(main + f", auto = {flags})") + + def add_mirror(self, v: UVec) -> None: + """Add a ``mirror()`` operation. + + OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#mirror + + Args: + v: the normal vector of a plane intersecting the origin through + which to mirror the object + + """ + n = Vec3(v).normalize() + self.add(f"mirror(v = [{n.x:g}, {n.y:g}, {n.z:g}])") + + def get_string(self) -> str: + """Returns the OpenSCAD build script.""" + return "\n".join(self.data) + + +def boolean_operation( + op: Operation, mesh1: MeshBuilder, mesh2: MeshBuilder +) -> str: + """Returns an `OpenSCAD`_ script to apply the given boolean operation to the + given meshes. + + The supported operations are: + + - UNION + - DIFFERENCE + - INTERSECTION + + """ + assert isinstance(op, Operation), "enum of type Operation expected" + script = Script() + script.add(f"{op.name}() {{") + script.add_polyhedron(mesh1) + script.add_polyhedron(mesh2) + script.add("}") + return script.get_string() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/pycsg.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/pycsg.py new file mode 100644 index 0000000..ac08f64 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/pycsg.py @@ -0,0 +1,444 @@ +# License +# Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license. +# Python port Copyright (c) 2012 Tim Knip (http://www.floorplanner.com), under the MIT license. +# Additions by Alex Pletzer (Pennsylvania State University) +# Integration as ezdxf add-on, Copyright (c) 2020, Manfred Moitzi, MIT License. +from __future__ import annotations +from typing import Optional +from ezdxf.math import Vec3, best_fit_normal, normal_vector_3p +from ezdxf.render import MeshVertexMerger, MeshBuilder, MeshTransformer + +# Implementation Details +# ---------------------- +# +# All CSG operations are implemented in terms of two functions, clip_to() and +# invert(), which remove parts of a BSP tree inside another BSP tree and swap +# solid and empty space, respectively. To find the union of a and b, we +# want to remove everything in a inside b and everything in b inside a, +# then combine polygons from a and b into one solid: +# +# a.clip_to(b) +# b.clip_to(a) +# a.build(b.all_polygons()) +# +# The only tricky part is handling overlapping coplanar polygons in both trees. +# The code above keeps both copies, but we need to keep them in one tree and +# remove them in the other tree. To remove them from b we can clip the +# inverse of b against a. The code for union now looks like this: +# +# a.clip_to(b) +# b.clip_to(a) +# b.invert() +# b.clip_to(a) +# b.invert() +# a.build(b.all_polygons()) +# +# Subtraction and intersection naturally follow from set operations. If +# union is A | B, subtraction is A - B = ~(~A | B) and intersection is +# A & B = ~(~A | ~B) where '~' is the complement operator. + +__all__ = ["CSG"] + +COPLANAR = 0 # all the vertices are within EPSILON distance from plane +FRONT = 1 # all the vertices are in front of the plane +BACK = 2 # all the vertices are at the back of the plane +SPANNING = 3 # some vertices are in front, some in the back +PLANE_EPSILON = 1e-5 # Tolerance used by split_polygon() to decide if a point is on the plane. + + +class Plane: + """Represents a plane in 3D space.""" + + __slots__ = ("normal", "w") + + def __init__(self, normal: Vec3, w: float): + self.normal = normal + # w is the (perpendicular) distance of the plane from (0, 0, 0) + self.w = w + + @classmethod + def from_points(cls, a: Vec3, b: Vec3, c: Vec3) -> Plane: + n = normal_vector_3p(a, b, c) + return Plane(n, n.dot(a)) + + def clone(self) -> Plane: + return Plane(self.normal, self.w) + + def flip(self) -> None: + self.normal = -self.normal + self.w = -self.w + + def __repr__(self) -> str: + return f"Plane({self.normal}, {self.w})" + + def split_polygon( + self, + polygon: "Polygon", + coplanar_front: list[Polygon], + coplanar_back: list[Polygon], + front: list[Polygon], + back: list[Polygon], + ) -> None: + """ + Split `polygon` by this plane if needed, then put the polygon or polygon + fragments in the appropriate lists. Coplanar polygons go into either + `coplanarFront` or `coplanarBack` depending on their orientation with + respect to this plane. Polygons in front or in back of this plane go into + either `front` or `back` + """ + polygon_type = 0 + vertex_types = [] + vertices = polygon.vertices + meshid = polygon.meshid # mesh ID of the associated mesh + + # Classify each point as well as the entire polygon into one of four classes: + # COPLANAR, FRONT, BACK, SPANNING = FRONT + BACK + for vertex in vertices: + distance = self.normal.dot(vertex) - self.w + if distance < -PLANE_EPSILON: + vertex_type = BACK + elif distance > PLANE_EPSILON: + vertex_type = FRONT + else: + vertex_type = COPLANAR + polygon_type |= vertex_type + vertex_types.append(vertex_type) + + # Put the polygon in the correct list, splitting it when necessary. + if polygon_type == COPLANAR: + if self.normal.dot(polygon.plane.normal) > 0: + coplanar_front.append(polygon) + else: + coplanar_back.append(polygon) + elif polygon_type == FRONT: + front.append(polygon) + elif polygon_type == BACK: + back.append(polygon) + elif polygon_type == SPANNING: + front_vertices = [] + back_vertices = [] + len_vertices = len(vertices) + for index in range(len_vertices): + next_index = (index + 1) % len_vertices + vertex_type = vertex_types[index] + next_vertex_type = vertex_types[next_index] + vertex = vertices[index] + next_vertex = vertices[next_index] + if vertex_type != BACK: # FRONT or COPLANAR + front_vertices.append(vertex) + if vertex_type != FRONT: # BACK or COPLANAR + back_vertices.append(vertex) + if (vertex_type | next_vertex_type) == SPANNING: + interpolation_weight = ( + self.w - self.normal.dot(vertex) + ) / self.normal.dot(next_vertex - vertex) + plane_intersection_point = vertex.lerp( + next_vertex, interpolation_weight + ) + front_vertices.append(plane_intersection_point) + back_vertices.append(plane_intersection_point) + if len(front_vertices) >= 3: + front.append(Polygon(front_vertices, meshid=meshid)) + if len(back_vertices) >= 3: + back.append(Polygon(back_vertices, meshid=meshid)) + + +class Polygon: + """ + Represents a convex polygon. The vertices used to initialize a polygon must + be coplanar and form a convex loop, the `meshid` argument associates a polygon + to a mesh. + + Args: + vertices: polygon vertices as :class:`Vec3` objects + meshid: id associated mesh + + """ + + __slots__ = ("vertices", "plane", "meshid") + + def __init__(self, vertices: list[Vec3], meshid: int = 0): + self.vertices = vertices + try: + normal = normal_vector_3p(vertices[0], vertices[1], vertices[2]) + except ZeroDivisionError: # got three colinear vertices + normal = best_fit_normal(vertices) + self.plane = Plane(normal, normal.dot(vertices[0])) + # number of mesh, this polygon is associated to + self.meshid = meshid + + def clone(self) -> Polygon: + return Polygon(list(self.vertices), meshid=self.meshid) + + def flip(self) -> None: + self.vertices.reverse() + self.plane.flip() + + def __repr__(self) -> str: + v = ", ".join(repr(v) for v in self.vertices) + return f"Polygon([{v}], mesh={self.meshid})" + + +class BSPNode: + """ + Holds a node in a BSP tree. A BSP tree is built from a collection of polygons + by picking a polygon to split along. That polygon (and all other coplanar + polygons) are added directly to that node and the other polygons are added to + the front and/or back subtrees. This is not a leafy BSP tree since there is + no distinction between internal and leaf nodes. + """ + + __slots__ = ("plane", "front", "back", "polygons") + + def __init__(self, polygons: Optional[list[Polygon]] = None): + self.plane: Optional[Plane] = None + self.front: Optional[BSPNode] = None + self.back: Optional[BSPNode] = None + self.polygons: list[Polygon] = [] + if polygons: + self.build(polygons) + + def clone(self) -> BSPNode: + node = BSPNode() + if self.plane: + node.plane = self.plane.clone() + if self.front: + node.front = self.front.clone() + if self.back: + node.back = self.back.clone() + node.polygons = [p.clone() for p in self.polygons] + return node + + def invert(self) -> None: + """Convert solid space to empty space and empty space to solid space.""" + for poly in self.polygons: + poly.flip() + assert self.plane is not None + self.plane.flip() + if self.front: + self.front.invert() + if self.back: + self.back.invert() + self.front, self.back = self.back, self.front + + def clip_polygons(self, polygons: list[Polygon]) -> list[Polygon]: + """Recursively remove all polygons in `polygons` that are inside this + BSP tree. + + """ + if self.plane is None: + return polygons[:] + + front: list[Polygon] = [] + back: list[Polygon] = [] + for polygon in polygons: + self.plane.split_polygon(polygon, front, back, front, back) + + if self.front: + front = self.front.clip_polygons(front) + + if self.back: + back = self.back.clip_polygons(back) + else: + back = [] + + front.extend(back) + return front + + def clip_to(self, bsp: BSPNode) -> None: + """Remove all polygons in this BSP tree that are inside the other BSP + tree `bsp`. + """ + self.polygons = bsp.clip_polygons(self.polygons) + if self.front: + self.front.clip_to(bsp) + if self.back: + self.back.clip_to(bsp) + + def all_polygons(self) -> list[Polygon]: + """Return a list of all polygons in this BSP tree.""" + polygons = self.polygons[:] + if self.front: + polygons.extend(self.front.all_polygons()) + if self.back: + polygons.extend(self.back.all_polygons()) + return polygons + + def build(self, polygons: list[Polygon]) -> None: + """ + Build a BSP tree out of `polygons`. When called on an existing tree, the + new polygons are filtered down to the bottom of the tree and become new + nodes there. Each set of polygons is partitioned using the first polygon + (no heuristic is used to pick a good split). + """ + if len(polygons) == 0: + return + if self.plane is None: + # do a wise choice and pick the first polygon as split-plane ;) + self.plane = polygons[0].plane.clone() + # add first polygon to this node + self.polygons.append(polygons[0]) + front: list[Polygon] = [] + back: list[Polygon] = [] + # split all other polygons at the split plane + for poly in polygons[1:]: + # coplanar front and back polygons go into self.polygons + self.plane.split_polygon( + poly, self.polygons, self.polygons, front, back + ) + # recursively build the BSP tree + if len(front) > 0: + if self.front is None: + self.front = BSPNode() + self.front.build(front) + if len(back) > 0: + if self.back is None: + self.back = BSPNode() + self.back.build(back) + + +class CSG: + """ + Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean + operations like union and intersection to combine 3D solids. This class + implements CSG operations on meshes. + + New 3D solids are created from :class:`~ezdxf.render.MeshBuilder` objects + and results can be exported as :class:`~ezdxf.render.MeshTransformer` objects + to `ezdxf` by method :meth:`mesh`. + + Args: + mesh: :class:`ezdxf.render.MeshBuilder` or inherited object + meshid: individual mesh ID to separate result meshes, ``0`` is default + + """ + + def __init__(self, mesh: Optional[MeshBuilder] = None, meshid: int = 0): + if mesh is None: + self.polygons: list[Polygon] = [] + else: + mesh_copy = mesh.copy() + mesh_copy.normalize_faces() + self.polygons = [ + Polygon(face, meshid) for face in mesh_copy.faces_as_vertices() + ] + + @classmethod + def from_polygons(cls, polygons: list[Polygon]) -> CSG: + csg = CSG() + csg.polygons = polygons + return csg + + def mesh(self, meshid: int = 0) -> MeshTransformer: + """ + Returns a :class:`ezdxf.render.MeshTransformer` object. + + Args: + meshid: individual mesh ID, ``0`` is default + + """ + mesh = MeshVertexMerger() + for face in self.polygons: + if meshid == face.meshid: + mesh.add_face(face.vertices) + return MeshTransformer.from_builder(mesh) + + def clone(self) -> CSG: + return self.from_polygons([p.clone() for p in self.polygons]) + + def union(self, other: CSG) -> CSG: + """ + Return a new CSG solid representing space in either this solid or in the + solid `other`. Neither this solid nor the solid `other` are modified:: + + A.union(B) + + +-------+ +-------+ + | | | | + | A | | | + | +--+----+ = | +----+ + +----+--+ | +----+ | + | B | | | + | | | | + +-------+ +-------+ + """ + a = BSPNode(self.clone().polygons) + b = BSPNode(other.clone().polygons) + a.clip_to(b) + b.clip_to(a) + b.invert() + b.clip_to(a) + b.invert() + a.build(b.all_polygons()) + return CSG.from_polygons(a.all_polygons()) + + __add__ = union + + def subtract(self, other: CSG) -> CSG: + """ + Return a new CSG solid representing space in this solid but not in the + solid `other`. Neither this solid nor the solid `other` are modified:: + + A.subtract(B) + + +-------+ +-------+ + | | | | + | A | | | + | +--+----+ = | +--+ + +----+--+ | +----+ + | B | + | | + +-------+ + """ + a = BSPNode(self.clone().polygons) + b = BSPNode(other.clone().polygons) + a.invert() + a.clip_to(b) + b.clip_to(a) + b.invert() + b.clip_to(a) + b.invert() + a.build(b.all_polygons()) + a.invert() + return CSG.from_polygons(a.all_polygons()) + + __sub__ = subtract + + def intersect(self, other: CSG) -> CSG: + """ + Return a new CSG solid representing space both this solid and in the + solid `other`. Neither this solid nor the solid `other` are modified:: + + A.intersect(B) + + +-------+ + | | + | A | + | +--+----+ = +--+ + +----+--+ | +--+ + | B | + | | + +-------+ + """ + a = BSPNode(self.clone().polygons) + b = BSPNode(other.clone().polygons) + a.invert() + b.clip_to(a) + b.invert() + a.clip_to(b) + b.clip_to(a) + a.build(b.all_polygons()) + a.invert() + return CSG.from_polygons(a.all_polygons()) + + __mul__ = intersect + + def inverse(self) -> CSG: + """ + Return a new CSG solid with solid and empty space switched. This solid is + not modified. + """ + csg = self.clone() + for p in csg.polygons: + p.flip() + return csg diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/r12export.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/r12export.py new file mode 100644 index 0000000..e9a6b0e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/r12export.py @@ -0,0 +1,636 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +""" +Module to export any DXF document as DXF version R12 without modifying the source +document. + +.. versionadded:: 1.1 + +To get the best result use the ODA File Converter add-on:: + + from ezdxf.addons import odafc + + odafc.convert("any.dxf", "r12.dxf", version="R12") + +""" + +from __future__ import annotations +from typing import TYPE_CHECKING, TextIO, Callable, Optional +import os +from io import StringIO +import logging + +import ezdxf +from ezdxf import const, proxygraphic, path +from ezdxf.document import Drawing +from ezdxf.entities import ( + BlockRecord, + DXFEntity, + DXFTagStorage, + Ellipse, + Hatch, + Insert, + LWPolyline, + MPolygon, + MText, + Mesh, + Polyface, + Polyline, + Spline, + Textstyle, +) +from ezdxf.entities.polygon import DXFPolygon +from ezdxf.addons import MTextExplode +from ezdxf.entitydb import EntitySpace +from ezdxf.layouts import BlockLayout, VirtualLayout +from ezdxf.lldxf.tagwriter import TagWriter, AbstractTagWriter +from ezdxf.lldxf.types import DXFTag, TAG_STRING_FORMAT +from ezdxf.math import Z_AXIS, Vec3, NULLVEC +from ezdxf.r12strict import R12NameTranslator +from ezdxf.render import MeshBuilder +from ezdxf.sections.table import TextstyleTable + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +__all__ = ["R12Exporter", "convert", "saveas", "write"] + +MAX_SAGITTA = 0.01 +logger = logging.getLogger("ezdxf") + + +def convert(doc: Drawing, *, max_sagitta: float = MAX_SAGITTA) -> Drawing: + """Export and reload DXF document as DXF version R12. + + Writes the DXF document into a temporary file at the file-system and reloads this + file by the :func:`ezdxf.readfile` function. + """ + stream = StringIO() + exporter = R12Exporter(doc, max_sagitta=max_sagitta) + exporter.write(stream) + stream.seek(0) + return ezdxf.read(stream) + + +def write(doc: Drawing, stream: TextIO, *, max_sagitta: float = MAX_SAGITTA) -> None: + """Write a DXF document as DXF version R12 to a text stream. The `max_sagitta` + argument determines the accuracy of the curve flatting for SPLINE and ELLIPSE + entities. + + Args: + doc: DXF document to export + stream: output stream, use :attr:`doc.encoding` as encoding + max_sagitta: maximum distance from the center of the curve to the + center of the line segment between two approximation points to + determine if a segment should be subdivided. + + """ + exporter = R12Exporter(doc, max_sagitta=max_sagitta) + exporter.write(stream) + + +def saveas( + doc: Drawing, filepath: str | os.PathLike, *, max_sagitta: float = MAX_SAGITTA +) -> None: + """Write a DXF document as DXF version R12 to a file. The `max_sagitta` + argument determines the accuracy of the curve flatting for SPLINE and ELLIPSE + entities. + + Args: + doc: DXF document to export + filepath: output filename + max_sagitta: maximum distance from the center of the curve to the + center of the line segment between two approximation points to + determine if a segment should be subdivided. + + """ + with open(filepath, "wt", encoding=doc.encoding, errors="dxfreplace") as stream: + write( + doc, + stream, + max_sagitta=max_sagitta, + ) + + +def spline_to_polyline( + spline: Spline, max_sagitta: float, min_segments: int +) -> Polyline: + polyline = Polyline.new( + dxfattribs={ + "layer": spline.dxf.layer, + "linetype": spline.dxf.linetype, + "color": spline.dxf.color, + "flags": const.POLYLINE_3D_POLYLINE, + } + ) + + polyline.append_vertices(points=spline.flattening(max_sagitta, min_segments)) + polyline.new_seqend() + return polyline + + +def ellipse_to_polyline( + ellipse: Ellipse, max_sagitta: float, min_segments: int +) -> Polyline: + polyline = Polyline.new( + dxfattribs={ + "layer": ellipse.dxf.layer, + "linetype": ellipse.dxf.linetype, + "color": ellipse.dxf.color, + "flags": const.POLYLINE_3D_POLYLINE, + } + ) + polyline.append_vertices(points=ellipse.flattening(max_sagitta, min_segments)) + polyline.new_seqend() + return polyline + + +def lwpolyline_to_polyline(lwpolyline: LWPolyline) -> Polyline: + polyline = Polyline.new( + dxfattribs={ + "layer": lwpolyline.dxf.layer, + "linetype": lwpolyline.dxf.linetype, + "color": lwpolyline.dxf.color, + } + ) + polyline.new_seqend() + polyline.append_formatted_vertices(lwpolyline.get_points(), format="xyseb") + if lwpolyline.is_closed: + polyline.close() + if lwpolyline.dxf.hasattr("const_width"): + width = lwpolyline.dxf.const_width + polyline.dxf.default_start_width = width + polyline.dxf.default_end_width = width + extrusion = Vec3(lwpolyline.dxf.extrusion) + if not extrusion.isclose(Z_AXIS): + polyline.dxf.extrusion = extrusion + elevation = lwpolyline.dxf.elevation + polyline.dxf.elevation = Vec3(0, 0, elevation) + # Set z-axis of VERTEX.location to elevation? + + return polyline + + +def mesh_to_polyface_mesh(mesh: Mesh) -> Polyface: + builder = MeshBuilder.from_mesh(mesh) + return builder.render_polyface( + VirtualLayout(), + dxfattribs={ + "layer": mesh.dxf.layer, + "linetype": mesh.dxf.linetype, + "color": mesh.dxf.color, + }, + ) + + +def get_xpl_block_name(entity: DXFEntity) -> str: + assert entity.dxf.handle is not None + return f"EZDXF_XPL_{entity.dxftype()}_{entity.dxf.handle}" + + +def export_lwpolyline(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity, LWPolyline) + polyline = lwpolyline_to_polyline(entity) + if len(polyline.vertices): + polyline.export_dxf(exporter.tagwriter()) + + +def export_mesh(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity, Mesh) + polyface_mesh = mesh_to_polyface_mesh(entity) + if len(polyface_mesh.vertices): + polyface_mesh.export_dxf(exporter.tagwriter()) + + +def export_spline(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity, Spline) + polyline = spline_to_polyline( + entity, exporter.max_sagitta, exporter.min_spline_segments + ) + if len(polyline.vertices): + polyline.export_dxf(exporter.tagwriter()) + + +def export_ellipse(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity, Ellipse) + polyline = ellipse_to_polyline( + entity, exporter.max_sagitta, exporter.min_ellipse_segments + ) + if len(polyline.vertices): + polyline.export_dxf(exporter.tagwriter()) + + +def make_insert(name: str, entity: DXFEntity, location=NULLVEC) -> Insert: + return Insert.new( + dxfattribs={ + "name": name, + "layer": entity.dxf.layer, + "linetype": entity.dxf.linetype, + "color": entity.dxf.color, + "insert": location, + } + ) + + +def export_proxy_graphic(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity.proxy_graphic, bytes) + pg = proxygraphic.ProxyGraphic(entity.proxy_graphic) + try: + entities = EntitySpace(pg.virtual_entities()) + except proxygraphic.ProxyGraphicError: + return + exporter.export_entity_space(entities) + + +def export_mtext(exporter: R12Exporter, entity: DXFEntity): + assert isinstance(entity, MText) + layout = VirtualLayout() + exporter.explode_mtext(entity, layout) + exporter.export_entity_space(layout.entity_space) + + +def export_virtual_entities(exporter: R12Exporter, entity: DXFEntity): + layout = VirtualLayout() + try: + for e in entity.virtual_entities(): # type: ignore + layout.add_entity(e) + except Exception: + return + exporter.export_entity_space(layout.entity_space) + + +def export_pattern_fill(entity: DXFEntity, block: BlockLayout) -> None: + assert isinstance(entity, DXFPolygon) + dxfattribs = { + "layer": entity.dxf.layer, + "color": entity.dxf.color, + } + for start, end in entity.render_pattern_lines(): + block.add_line(start, end, dxfattribs=dxfattribs) + + +def export_solid_fill( + entity: DXFPolygon, + block: BlockLayout, + max_sagitta: float, + min_segments: int, +) -> None: + dxfattribs = { + "layer": entity.dxf.layer, + "color": entity.dxf.color, + } + + extrusion = Vec3(entity.dxf.extrusion) + if not extrusion.is_null and not extrusion.isclose(Z_AXIS): + dxfattribs["extrusion"] = extrusion + + # triangulation in OCS coordinates, including elevation and offset values: + for vertices in entity.triangulate(max_sagitta, min_segments): + block.add_solid(vertices, dxfattribs=dxfattribs) + + +def export_hatch(exporter: R12Exporter, entity: DXFEntity) -> None: + assert isinstance(entity, Hatch) + # export hatch into an anonymous block + block = exporter.new_block(entity) + insert = make_insert(block.name, entity) + insert.export_dxf(exporter.tagwriter()) + + if entity.has_pattern_fill: + export_pattern_fill(entity, block) + else: + export_solid_fill( + entity, block, exporter.max_sagitta, exporter.min_spline_segments + ) + + +def export_mpolygon(exporter: R12Exporter, entity: DXFEntity) -> None: + assert isinstance(entity, MPolygon) + # export mpolygon into an anonymous block + block = exporter.new_block(entity) + insert = make_insert(block.name, entity) + insert.export_dxf(exporter.tagwriter()) + + # elevation is the z-axis of the vertices + path.render_polylines2d( + block, + path.from_hatch_ocs(entity, offset=Vec3(entity.dxf.offset)), + distance=exporter.max_sagitta, + segments=exporter.min_spline_segments, + extrusion=Vec3(entity.dxf.extrusion), + dxfattribs={ + "layer": entity.dxf.layer, + "linetype": entity.dxf.linetype, + "color": entity.dxf.color, + }, + ) + if entity.has_pattern_fill: + export_pattern_fill(entity, block) + else: + export_solid_fill( + entity, block, exporter.max_sagitta, exporter.min_spline_segments + ) + + +def export_acad_table(exporter: R12Exporter, entity: DXFEntity) -> None: + from ezdxf.entities.acad_table import AcadTableBlockContent + + assert isinstance(entity, AcadTableBlockContent) + table: AcadTableBlockContent = entity + location = table.get_insert_location() + block_name = table.get_block_name() + if not block_name.startswith("*T"): + return + try: + acdb_entity = table.xtags.get_subclass("AcDbEntity") + except const.DXFIndexError: + return + layer = acdb_entity.get_first_value(8, "0") + insert = Insert.new( + dxfattribs={"name": block_name, "layer": layer, "insert": location} + ) + insert.export_dxf(exporter.tagwriter()) + + +# Planned features: explode complex newer entity types into DXF primitives. +# currently skipped entity types: +# - ACAD_TABLE: graphic as geometry block is available +# -------------------------------------------------------------------------------------- +# - all ACIS based entities: tessellated meshes could be exported, but very much work +# and beyond my current knowledge +# - IMAGE and UNDERLAY: no support possible +# - XRAY and XLINE: no support possible (infinite lines) + +# Possible name tags to translate: +# 1 The primary text value for an entity - never a name +# 2 A name: Attribute tag, Block name, and so on. Also used to identify a DXF section or +# table name +# 3 Other textual or name values - only in DIMENSION a name +# 4 Other textual values - never a name! +# 5 Entity handle expressed as a hexadecimal string (fixed) +# 6 Line type name (fixed) +# 7 Text style name (fixed) +# 8 Layer name (fixed) +# 1001: AppID +# 1003: layer name in XDATA (fixed) +NAME_TAG_CODES = {2, 3, 6, 7, 8, 1001, 1003} + + +class R12TagWriter(TagWriter): + def __init__(self, stream: TextIO): + super().__init__(stream, dxfversion=const.DXF12, write_handles=False) + self.skip_xdata = False + self.current_entity = "" + self.translator = R12NameTranslator() + + def set_stream(self, stream: TextIO) -> None: + self._stream = stream + + def write_tag(self, tag: DXFTag) -> None: + code, value = tag + if code == 0: + self.current_entity = str(value) + if code > 999 and self.skip_xdata: + return + if code in NAME_TAG_CODES: + self._stream.write( + TAG_STRING_FORMAT % (code, self.sanitize_name(code, value)) + ) + else: + self._stream.write(tag.dxfstr()) + + def write_tag2(self, code: int, value) -> None: + if code > 999 and self.skip_xdata: + return + if code == 0: + self.current_entity = str(value) + if code in NAME_TAG_CODES: + value = self.sanitize_name(code, value) + self._stream.write(TAG_STRING_FORMAT % (code, value)) + + def sanitize_name(self, code: int, name: str) -> str: + # sanitize group code 3 + 4 + # LTYPE - has group code - not a table name + # STYLE - has group code (3) - not a table name + # STYLE - has group code (4) - not a table name + # DIMSTYLE - has group code e.g. "<> mm" (3) - not a table name + # DIMSTYLE - has group code (4) - not a table name + # ATTDEF - has group code (3) - not a table name + # DIMENSION - has group code (3) - is a table name! + if code == 3 and self.current_entity != "DIMENSION": + return name + return self.translator.translate(name) + + +class SpecialStyleTable: + def __init__(self, styles: TextstyleTable, extra_styles: TextstyleTable): + self.styles = styles + self.extra_styles = extra_styles + + def get_text_styles(self) -> list[Textstyle]: + entries = list(self.styles.entries.values()) + for name, extra_style in self.extra_styles.entries.items(): + if not self.styles.has_entry(name): + entries.append(extra_style) + return entries + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + text_styles = self.get_text_styles() + tagwriter.write_tag2(0, "TABLE") + tagwriter.write_tag2(2, "STYLE") + tagwriter.write_tag2(70, len(text_styles)) + for style in text_styles: + style.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDTAB") + + +EOF_STR = "0\nEOF\n" + + +def detect_max_block_number(names: list[str]) -> int: + max_number = 0 + for name in names: + name = name.upper() + if not name.startswith("*"): + continue + try: # *U10 + number = int(name[2:]) + except ValueError: + continue + max_number = max(max_number, number) + return max_number + 1 + + +class R12Exporter: + def __init__(self, doc: Drawing, max_sagitta: float = 0.01): + assert isinstance(doc, Drawing) + self._doc = doc + self._tagwriter = R12TagWriter(StringIO()) + self.max_sagitta = float(max_sagitta) # flattening SPLINE, ELLIPSE + self.min_spline_segments: int = 4 # flattening SPLINE + self.min_ellipse_segments: int = 8 # flattening ELLIPSE + self._extra_doc = ezdxf.new("R12") + self._next_block_number = detect_max_block_number( + [br.dxf.name for br in doc.block_records] + ) + # Exporters are required to convert newer entity types into DXF R12 types. + # All newer entity types without an exporter will be ignored. + self.exporters: dict[str, Callable[[R12Exporter, DXFEntity], None]] = { + "LWPOLYLINE": export_lwpolyline, + "MESH": export_mesh, + "SPLINE": export_spline, + "ELLIPSE": export_ellipse, + "MTEXT": export_mtext, + "LEADER": export_virtual_entities, + "MLEADER": export_virtual_entities, + "MULTILEADER": export_virtual_entities, + "MLINE": export_virtual_entities, + "HATCH": export_hatch, + "MPOLYGON": export_mpolygon, + "ACAD_TABLE": export_acad_table, + } + + def disable_exporter(self, entity_type: str): + del self.exporters[entity_type] + + @property + def doc(self) -> Drawing: + return self._doc + + def tagwriter(self, stream: Optional[TextIO] = None) -> R12TagWriter: + if stream is not None: + self._tagwriter.set_stream(stream) + return self._tagwriter + + def write(self, stream: TextIO) -> None: + """Write DXF document to text stream.""" + stream.write(self.to_string()) + + def to_string(self) -> str: + """Export DXF document as string.""" + # export layouts before blocks: may create new anonymous blocks + entities = self.export_layouts_to_string() + # export blocks before HEADER and TABLES sections: may create new text styles + blocks = self.export_blocks_to_string() + + return "".join( + ( + self.export_header_to_string(), + self.export_tables_to_string(), + blocks, + entities, + EOF_STR, + ) + ) + + def next_block_name(self, char: str) -> str: + name = f"*{char}{self._next_block_number}" + self._next_block_number += 1 + return name + + def new_block(self, entity: DXFEntity) -> BlockLayout: + name = self.next_block_name("U") + return self._extra_doc.blocks.new( + name, + dxfattribs={ + "layer": entity.dxf.get("layer", "0"), + "flags": const.BLK_ANONYMOUS, + }, + ) + + def export_header_to_string(self) -> str: + in_memory_stream = StringIO() + self.doc.header.export_dxf(self.tagwriter(in_memory_stream)) + return in_memory_stream.getvalue() + + def export_tables_to_string(self) -> str: + # DXF R12 does not support XDATA in tables according Autodesk DWG TrueView + in_memory_stream = StringIO() + tables = self.doc.tables + preserve_table = tables.styles + tables.styles = SpecialStyleTable(self.doc.styles, self._extra_doc.styles) # type: ignore + + tagwriter = self.tagwriter(in_memory_stream) + tagwriter.skip_xdata = True + tables.export_dxf(tagwriter) + tables.styles = preserve_table + tagwriter.skip_xdata = False + return in_memory_stream.getvalue() + + def export_blocks_to_string(self) -> str: + in_memory_stream = StringIO() + self._tagwriter.set_stream(in_memory_stream) + + self._write_section_header("BLOCKS") + for block_record in self.doc.block_records: + if block_record.is_any_paperspace and not block_record.is_active_paperspace: + continue + name = block_record.dxf.name.lower() + if name in ("$model_space", "$paper_space"): + # These block names collide with the translated names of the *Model_Space + # and the *Paper_Space blocks. + continue + self._export_block_record(block_record) + + extra_blocks = self.get_extra_blocks() + while len(extra_blocks): + for block_record in extra_blocks: + self._export_block_record(block_record) + self.discard_extra_block(block_record.dxf.name) + # block record export can create further blocks + extra_blocks = self.get_extra_blocks() + + self._write_endsec() + return in_memory_stream.getvalue() + + def discard_extra_block(self, name: str) -> None: + self._extra_doc.block_records.discard(name) + + def get_extra_blocks(self) -> list[BlockRecord]: + return [ + br for br in self._extra_doc.block_records if br.dxf.name.startswith("*U") + ] + + def explode_mtext(self, mtext: MText, layout: GenericLayoutType): + with MTextExplode(layout, self._extra_doc) as xpl: + xpl.explode(mtext, destroy=False) + + def export_layouts_to_string(self) -> str: + in_memory_stream = StringIO() + self._tagwriter.set_stream(in_memory_stream) + + self._write_section_header("ENTITIES") + self.export_entity_space(self.doc.modelspace().entity_space) + self.export_entity_space(self.doc.paperspace().entity_space) + self._write_endsec() + return in_memory_stream.getvalue() + + def _export_block_record(self, block_record: BlockRecord): + tagwriter = self._tagwriter + assert block_record.block is not None + block_record.block.export_dxf(tagwriter) + if not block_record.is_any_layout: + self.export_entity_space(block_record.entity_space) + assert block_record.endblk is not None + block_record.endblk.export_dxf(tagwriter) + + def export_entity_space(self, space: EntitySpace): + tagwriter = self._tagwriter + for entity in space: + if entity.MIN_DXF_VERSION_FOR_EXPORT > const.DXF12 or isinstance( + entity, DXFTagStorage + ): + exporter = self.exporters.get(entity.dxftype()) + if exporter: + exporter(self, entity) + continue + if entity.proxy_graphic: + export_proxy_graphic(self, entity) + else: + entity.export_dxf(tagwriter) + + def _write_section_header(self, name: str) -> None: + self._tagwriter.write_str(f" 0\nSECTION\n 2\n{name}\n") + + def _write_endsec(self) -> None: + self._tagwriter.write_tag2(0, "ENDSEC") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/r12writer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/r12writer.py new file mode 100644 index 0000000..dc06df0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/r12writer.py @@ -0,0 +1,1233 @@ +# Copyright (c) 2016-2022, Manfred Moitzi +# License: MIT License +# Purpose: fast & simple but restricted DXF R12 writer, with no in-memory +# drawing, and without dependencies to other ezdxf modules. +# The created DXF file contains no HEADER, TABLES or BLOCKS section only the +# ENTITIES section is present. +from __future__ import annotations +from typing import ( + TextIO, + BinaryIO, + Union, + Sequence, + Iterable, + cast, + Iterator, + Optional, +) +from contextlib import contextmanager +from functools import partial +from io import StringIO +from pathlib import Path +from ezdxf.lldxf.tagwriter import BinaryTagWriter + +Vertex = Sequence[float] +rnd = partial(round, ndigits=6) + +TEXT_ALIGN_FLAGS = { + "LEFT": (0, 0), + "CENTER": (1, 0), + "RIGHT": (2, 0), + "BOTTOM_LEFT": (0, 1), + "BOTTOM_CENTER": (1, 1), + "BOTTOM_RIGHT": (2, 1), + "MIDDLE_LEFT": (0, 2), + "MIDDLE_CENTER": (1, 2), + "MIDDLE_RIGHT": (2, 2), + "TOP_LEFT": (0, 3), + "TOP_CENTER": (1, 3), + "TOP_RIGHT": (2, 3), +} + +VERTEX_GROUP_CODES = {"x": 10, "y": 20, "s": 40, "e": 41, "b": 42} + + +class BinaryDXFWriter: + def __init__(self, stream: BinaryIO): + self._stream = stream + self._tagwriter = BinaryTagWriter( + self._stream, + dxfversion="AC1009", + write_handles=False, + encoding="cp1252", + ) + self._tagwriter.write_signature() + + def write(self, s: str) -> None: + self._tagwriter.write_str(s) + + +@contextmanager +def r12writer( + stream: Union[TextIO, BinaryIO, str, Path], + fixed_tables: bool = False, + fmt: str = "asc", +) -> Iterator[R12FastStreamWriter]: + """Context manager for writing DXF entities to a stream/file. `stream` can + be any file like object with a :func:`write` method or just a string for + writing DXF entities to the file system. If `fixed_tables` is ``True``, a + standard TABLES section is written in front of the ENTITIES + section and some predefined text styles and line types can be used. + + Set argument `fmt` to "asc" to write ASCII DXF file (default) or "bin" to + write Binary DXF files. ASCII DXF require a :class:`TextIO` stream and + Binary DXF require a :class:`BinaryIO` stream. + + """ + _stream: Union[TextIO, BinaryIO, None] = None + + if fmt.startswith("asc"): + if isinstance(stream, (str, Path)): + _stream = open(stream, "wt", encoding="cp1252") + stream = _stream + elif fmt.startswith("bin"): + if isinstance(stream, (str, Path)): + _stream = open(stream, "wb") + stream = cast(TextIO, BinaryDXFWriter(_stream)) + else: + stream = cast(TextIO, BinaryDXFWriter(cast(BinaryIO, stream))) + + else: + raise ValueError(f"Unknown format '{fmt}'.") + writer = R12FastStreamWriter(cast(TextIO, stream), fixed_tables) + try: + yield writer + finally: + writer.close() + if _stream: + _stream.close() + + +class R12FastStreamWriter: + """Fast stream writer to create simple DXF R12 drawings. + + Args: + stream: a file like object with a :func:`write` method. + fixed_tables: if `fixed_tables` is ``True``, a standard TABLES section + is written in front of the ENTITIES section and some predefined text + styles and line types can be used. + + """ + + def __init__(self, stream: TextIO, fixed_tables=False): + self.stream = stream + if fixed_tables: + stream.write(PREFACE) + stream.write("0\nSECTION\n2\nENTITIES\n") # write header + + def close(self) -> None: + """Writes the DXF tail. Call is not necessary when using the context + manager :func:`r12writer`. + """ + self.stream.write("0\nENDSEC\n0\nEOF\n") # write tail + + def add_line( + self, + start: Vertex, + end: Vertex, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a LINE entity from `start` to `end`. + + Args: + start: start vertex as ``(x, y[, z])`` tuple + end: end vertex as as ``(x, y[, z])`` tuple + layer: layer name as string, without a layer definition the assigned + color = ``7`` (black/white) and line type is ``'Continuous'``. + color: color as :ref:`ACI` in the range from ``0`` to ``256``, + ``0`` is `ByBlock` and ``256`` is `ByLayer`, default is `ByLayer` + which is always color = ``7`` (black/white) without a layer + definition. + linetype: line type as string, if FIXED-TABLES are written some + predefined line types are available, else line type is always + `ByLayer`, which is always ``'Continuous'`` without a LAYERS + table. + + """ + dxf = ["0\nLINE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_vertex(start, code=10)) + dxf.append(dxf_vertex(end, code=11)) + self.stream.write("".join(dxf)) + + def add_circle( + self, + center: Vertex, + radius: float, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a CIRCLE entity. + + Args: + center: circle center point as ``(x, y)`` tuple + radius: circle radius as float + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + dxf = ["0\nCIRCLE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_vertex(center)) + dxf.append(dxf_tag(40, str(rnd(radius)))) + self.stream.write("".join(dxf)) + + def add_arc( + self, + center: Vertex, + radius: float, + start: float = 0, + end: float = 360, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add an ARC entity. The arc goes counter-clockwise from `start` angle + to `end` angle. + + Args: + center: arc center point as ``(x, y)`` tuple + radius: arc radius as float + start: arc start angle in degrees as float + end: arc end angle in degrees as float + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + dxf = ["0\nARC\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_vertex(center)) + dxf.append(dxf_tag(40, str(rnd(radius)))) + dxf.append(dxf_tag(50, str(rnd(start)))) + dxf.append(dxf_tag(51, str(rnd(end)))) + self.stream.write("".join(dxf)) + + def add_point( + self, + location: Vertex, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """ + Add a POINT entity. + + Args: + location: point location as ``(x, y [,z])`` tuple + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + dxf = ["0\nPOINT\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_vertex(location)) + self.stream.write("".join(dxf)) + + def add_3dface( + self, + vertices: Iterable[Vertex], + invisible: int = 0, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a 3DFACE entity. 3DFACE is a spatial area with 3 or 4 vertices, + all vertices have to be in the same plane. + + Args: + vertices: iterable of 3 or 4 ``(x, y, z)`` vertices. + invisible: bit coded flag to define the invisible edges, + + 1. edge = 1 + 2. edge = 2 + 3. edge = 4 + 4. edge = 8 + + Add edge values to set multiple edges invisible, + 1. edge + 3. edge = 1 + 4 = 5, all edges = 15 + + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + self._add_quadrilateral( + "3DFACE", vertices, invisible, layer, color, linetype + ) + + def add_solid( + self, + vertices: Iterable[Vertex], + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a SOLID entity. SOLID is a solid filled area with 3 or 4 edges + and SOLID is a 2D entity. + + Args: + vertices: iterable of 3 or 4 ``(x, y[, z])`` tuples, z-axis will be + ignored. + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + self._add_quadrilateral("SOLID", vertices, 0, layer, color, linetype) + + def _add_quadrilateral( + self, + dxftype: str, + vertices: Iterable[Vertex], + flags: int, + layer: str, + color: Optional[int], + linetype: Optional[str], + ) -> None: + dxf = ["0\n%s\n" % dxftype] + dxf.append(dxf_attribs(layer, color, linetype)) + vertices = list(vertices) + if len(vertices) < 3: + raise ValueError("%s needs 3 or 4 vertices." % dxftype) + elif len(vertices) == 3: + vertices.append(vertices[-1]) # double last vertex + dxf.extend( + dxf_vertex(vertex, code) + for code, vertex in enumerate(vertices, start=10) + ) + if flags: + dxf.append(dxf_tag(70, str(flags))) + self.stream.write("".join(dxf)) + + def add_polyline( + self, + vertices: Iterable[Vertex], + closed: bool = False, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a 3D POLYLINE entity. + + Args: + vertices: iterable of ``(x, y[, z])`` tuples, z-axis is ``0`` by + default + closed: ``True`` creates a closed polyline + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + dxf = ["0\nPOLYLINE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_tag(66, 1)) # entities follow + dxf.append(dxf_tag(70, 8 + int(closed))) # bit 1 is the closed state + self.stream.write("".join(dxf)) + + vertex_template = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, 32) + for vertex in vertices: + self.stream.write(vertex_template) + vertex = tuple(vertex) + len_vertex = len(vertex) + if len_vertex < 2: + raise ValueError("Vertices require at least a x- and a y-axis.") + elif len_vertex == 2: + vertex = (vertex[0], vertex[1], 0) + self.stream.write(dxf_vertex(vertex[:3])) + self.stream.write("0\nSEQEND\n") + + def add_polyline_2d( + self, + points: Iterable[Sequence], + format: str = "xy", + closed: bool = False, + start_width: float = 0, + end_width: float = 0, + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a 2D POLYLINE entity with start width, end width and bulge value + support. + + Format codes: + + === ================================= + x x-coordinate + y y-coordinate + s start width + e end width + b bulge value + v (x, y) tuple (z-axis is ignored) + === ================================= + + Args: + points: iterable of (x, y, [start_width, [end_width, [bulge]]]) + tuple, value order according to the `format` string, unset + values default to ``0`` + format: format: format string, default is ``'xy'`` + closed: ``True`` creates a closed polyline + start_width: default start width, default is ``0`` + end_width: default end width, default is ``0`` + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + + def vertex_attribs(data: Sequence) -> dict: + attribs = dict() + for code, value in zip(format, data): + if code == "v": + location = tuple(value) + attribs["x"] = location[0] + attribs["y"] = location[1] + else: + attribs[code] = value + return attribs + + dxf = ["0\nPOLYLINE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_tag(66, 1)) # entities follow + dxf.append(dxf_tag(70, int(closed))) # bit 1 is the closed state + if start_width: # default start width + dxf.append(dxf_tag(40, start_width)) + if end_width: # default end width + dxf.append(dxf_tag(41, end_width)) + self.stream.write("".join(dxf)) + + vertex_template = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, 0) + for point in points: + self.stream.write(vertex_template) + attribs = vertex_attribs(point) + for format_code in format: + value = attribs.get(format_code, 0) + if value == 0 and format_code in "seb": + continue # do not write default values + self.stream.write( + dxf_tag(VERTEX_GROUP_CODES[format_code], value) + ) + self.stream.write("0\nSEQEND\n") + + def add_polyface( + self, + vertices: Iterable[Vertex], + faces: Iterable[Sequence[int]], + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a POLYFACE entity. The POLYFACE entity supports only faces of + maximum 4 vertices, more indices will be ignored. A simple square would + be:: + + v0 = (0, 0, 0) + v1 = (1, 0, 0) + v2 = (1, 1, 0) + v3 = (0, 1, 0) + dxf.add_polyface(vertices=[v0, v1, v2, v3], faces=[(0, 1, 2, 3)]) + + All 3D form functions of the :mod:`ezdxf.render.forms` module return + :class:`~ezdxf.render.MeshBuilder` objects, which provide the required + vertex and face lists. + + See sphere example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py + + Args: + vertices: iterable of ``(x, y, z)`` tuples + faces: iterable of 3 or 4 vertex indices, indices have to be 0-based + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + + def write_polyline(flags: int = 64) -> None: + dxf = ["0\nPOLYLINE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_tag(66, 1)) # entities follow + dxf.append(dxf_tag(70, flags)) + dxf.append(dxf_tag(71, vertex_count)) + dxf.append(dxf_tag(72, face_count)) + self.stream.write("".join(dxf)) + + def write_vertices(flags: int = 64 + 128): + buf = StringIO() + count = 0 + s = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, flags) + for vertex in vertices: + count += 1 + buf.write(s) + buf.write(dxf_vertex(vertex)) + s = buf.getvalue() + buf.close() + return count, s + + def write_faces(flags: int = 128): + buf = StringIO() + count = 0 + s = ( + "0\nVERTEX\n" + + dxf_attribs(layer, color) + + dxf_tag(70, flags) + + dxf_vertex((0, 0, 0)) + ) + for face in faces: + count += 1 + buf.write(s) + for code, index in zip((71, 72, 73, 74), face): + buf.write(dxf_tag(code, index + 1)) + s = buf.getvalue() + buf.close() + return count, s + + vertex_count, vertex_str = write_vertices() + face_count, face_str = write_faces() + write_polyline() + self.stream.write(vertex_str) + self.stream.write(face_str) + self.stream.write("0\nSEQEND\n") + + def add_polymesh( + self, + vertices: Iterable[Vertex], + size: tuple[int, int], + closed=(False, False), + layer: str = "0", + color: Optional[int] = None, + linetype: Optional[str] = None, + ) -> None: + """Add a POLYMESH entity. A POLYMESH is a mesh of m rows and n columns, + each mesh vertex has its own x-, y- and z coordinates. The mesh can be + closed in m- and/or n-direction. The vertices have to be in column + order: (m0, n0), (m0, n1), (m0, n2), (m1, n0), (m1, n1), (m1, n2), ... + + See example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py + + Args: + vertices: iterable of ``(x, y, z)`` tuples, in column order + size: mesh dimension as (m, n)-tuple, requirement: + ``len(vertices) == m*n`` + closed: (m_closed, n_closed) tuple, for closed mesh in m and/or n + direction + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + linetype: line type as string see :meth:`add_line` + + """ + m, n = size + m_closed, n_closed = closed + + def write_polyline(flags: int = 16) -> None: + if m_closed: + flags += 1 + if n_closed: + flags += 32 + + dxf = ["0\nPOLYLINE\n"] + dxf.append(dxf_attribs(layer, color, linetype)) + dxf.append(dxf_tag(66, 1)) # entities follow + dxf.append(dxf_tag(70, flags)) + dxf.append(dxf_tag(71, m)) + dxf.append(dxf_tag(72, n)) + self.stream.write("".join(dxf)) + + def write_vertices(flags: int = 64) -> int: + count = 0 + s = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, flags) + for vertex in vertices: + count += 1 + self.stream.write(s) + self.stream.write(dxf_vertex(vertex)) + return count + + write_polyline() + count = write_vertices() + if m * n != count: + raise ValueError("Invalid mesh dimensions.") + + self.stream.write("0\nSEQEND\n") + + def add_text( + self, + text: str, + insert: Vertex = (0, 0), + height: float = 1.0, + width: float = 1.0, + align: str = "LEFT", + rotation: float = 0.0, + oblique: float = 0.0, + style: str = "STANDARD", + layer: str = "0", + color: Optional[int] = None, + ) -> None: + """Add a one line TEXT entity. + + Args: + text: the text as string + insert: insert location as ``(x, y)`` tuple + height: text height in drawing units + width: text width as factor + align: text alignment, see table below + rotation: text rotation in degrees as float + oblique: oblique in degrees as float, vertical = ``0`` (default) + style: text style name as string, if FIXED-TABLES are written some + predefined text styles are available, else text style is + always ``'STANDARD'``. + layer: layer name as string see :meth:`add_line` + color: color as :ref:`ACI` see :meth:`add_line` + + ============ =============== ================= ===== + Vert/Horiz Left Center Right + ============ =============== ================= ===== + Top ``TOP_LEFT`` ``TOP_CENTER`` ``TOP_RIGHT`` + Middle ``MIDDLE_LEFT`` ``MIDDLE_CENTER`` ``MIDDLE_RIGHT`` + Bottom ``BOTTOM_LEFT`` ``BOTTOM_CENTER`` ``BOTTOM_RIGHT`` + Baseline ``LEFT`` ``CENTER`` ``RIGHT`` + ============ =============== ================= ===== + + The special alignments ``ALIGNED`` and ``FIT`` are not available. + + """ + # text style is always STANDARD without a TABLES section + dxf = ["0\nTEXT\n"] + dxf.append(dxf_attribs(layer, color)) + dxf.append(dxf_vertex(insert, code=10)) + dxf.append(dxf_tag(1, str(text))) + dxf.append(dxf_tag(40, str(rnd(height)))) + if width != 1.0: + dxf.append(dxf_tag(41, str(rnd(width)))) + if rotation != 0.0: + dxf.append(dxf_tag(50, str(rnd(rotation)))) + if oblique != 0.0: + dxf.append(dxf_tag(51, str(rnd(oblique)))) + if style != "STANDARD": + dxf.append(dxf_tag(7, str(style))) + halign, valign = TEXT_ALIGN_FLAGS[align.upper()] + dxf.append(dxf_tag(72, str(halign))) + dxf.append(dxf_tag(73, str(valign))) + dxf.append(dxf_vertex(insert, code=11)) # align point + self.stream.write("".join(dxf)) + + +def dxf_attribs( + layer: str, color: Optional[int] = None, linetype: Optional[str] = None +) -> str: + dxf = ["8\n%s\n" % layer] # layer is required + if linetype is not None: + dxf.append("6\n%s\n" % linetype) + if color is not None: + if 0 <= int(color) < 257: + dxf.append("62\n%d\n" % color) + else: + raise ValueError( + "color has to be an integer in the range from 0 to 256." + ) + return "".join(dxf) + + +def dxf_vertex(vertex: Vertex, code=10) -> str: + dxf = [] + for c in vertex: + dxf.append("%d\n%s\n" % (code, str(rnd(c)))) + code += 10 + return "".join(dxf) + + +def dxf_tag(code: int, value) -> str: + return "%d\n%s\n" % (code, value) + + +FORMAT_CODES = frozenset("xysebv") + +PREFACE = """ 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1009 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +LTYPE + 5 +431 + 70 +20 + 0 +LTYPE + 5 +40F + 2 +CONTINUOUS + 70 +0 + 3 +Solid line + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +410 + 2 +CENTER + 70 +0 + 3 +Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ + 72 +65 + 73 +4 + 40 +2.0 + 49 +1.25 + 49 +-0.25 + 49 +0.25 + 49 +-0.25 + 0 +LTYPE + 5 +411 + 2 +DASHED + 70 +0 + 3 +Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _ + 72 +65 + 73 +2 + 40 +0.75 + 49 +0.5 + 49 +-0.25 + 0 +LTYPE + 5 +412 + 2 +PHANTOM + 70 +0 + 3 +Phantom ______ __ __ ______ __ __ ______ + 72 +65 + 73 +6 + 40 +2.5 + 49 +1.25 + 49 +-0.25 + 49 +0.25 + 49 +-0.25 + 49 +0.25 + 49 +-0.25 + 0 +LTYPE + 5 +413 + 2 +HIDDEN + 70 +0 + 3 +Hidden __ __ __ __ __ __ __ __ __ __ __ __ __ __ + 72 +65 + 73 +2 + 40 +9.525 + 49 +6.345 + 49 +-3.175 + 0 +LTYPE + 5 +43B + 2 +CENTERX2 + 70 +0 + 3 +Center (2x) ________ __ ________ __ ________ + 72 +65 + 73 +4 + 40 +3.5 + 49 +2.5 + 49 +-0.25 + 49 +0.5 + 49 +-0.25 + 0 +LTYPE + 5 +43C + 2 +CENTER2 + 70 +0 + 3 +Center (.5x) ____ _ ____ _ ____ _ ____ _ ____ + 72 +65 + 73 +4 + 40 +1.0 + 49 +0.625 + 49 +-0.125 + 49 +0.125 + 49 +-0.125 + 0 +LTYPE + 5 +43D + 2 +DASHEDX2 + 70 +0 + 3 +Dashed (2x) ____ ____ ____ ____ ____ ____ + 72 +65 + 73 +2 + 40 +1.2 + 49 +1.0 + 49 +-0.2 + 0 +LTYPE + 5 +43E + 2 +DASHED2 + 70 +0 + 3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 +65 + 73 +2 + 40 +0.3 + 49 +0.25 + 49 +-0.05 + 0 +LTYPE + 5 +43F + 2 +PHANTOMX2 + 70 +0 + 3 +Phantom (2x)____________ ____ ____ ____________ + 72 +65 + 73 +6 + 40 +4.25 + 49 +2.5 + 49 +-0.25 + 49 +0.5 + 49 +-0.25 + 49 +0.5 + 49 +-0.25 + 0 +LTYPE + 5 +440 + 2 +PHANTOM2 + 70 +0 + 3 +Phantom (.5x) ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___ + 72 +65 + 73 +6 + 40 +1.25 + 49 +0.625 + 49 +-0.125 + 49 +0.125 + 49 +-0.125 + 49 +0.125 + 49 +-0.125 + 0 +LTYPE + 5 +441 + 2 +DASHDOT + 70 +0 + 3 +Dash dot __ . __ . __ . __ . __ . __ . __ . __ + 72 +65 + 73 +4 + 40 +1.4 + 49 +1.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 0 +LTYPE + 5 +442 + 2 +DASHDOTX2 + 70 +0 + 3 +Dash dot (2x) ____ . ____ . ____ . ____ + 72 +65 + 73 +4 + 40 +2.4 + 49 +2.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 0 +LTYPE + 5 +443 + 2 +DASHDOT2 + 70 +0 + 3 +Dash dot (.5x) _ . _ . _ . _ . _ . _ . _ . _ + 72 +65 + 73 +4 + 40 +0.7 + 49 +0.5 + 49 +-0.1 + 49 +0.0 + 49 +-0.1 + 0 +LTYPE + 5 +444 + 2 +DOT + 70 +0 + 3 +Dot . . . . . . . . . . . . . . . . + 72 +65 + 73 +2 + 40 +0.2 + 49 +0.0 + 49 +-0.2 + 0 +LTYPE + 5 +445 + 2 +DOTX2 + 70 +0 + 3 +Dot (2x) . . . . . . . . + 72 +65 + 73 +2 + 40 +0.4 + 49 +0.0 + 49 +-0.4 + 0 +LTYPE + 5 +446 + 2 +DOT2 + 70 +0 + 3 +Dot (.5) . . . . . . . . . . . . . . . . . . . + 72 +65 + 73 +2 + 40 +0.1 + 49 +0.0 + 49 +-0.1 + 0 +LTYPE + 5 +447 + 2 +DIVIDE + 70 +0 + 3 +Divide __ . . __ . . __ . . __ . . __ . . __ + 72 +65 + 73 +6 + 40 +1.6 + 49 +1.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 0 +LTYPE + 5 +448 + 2 +DIVIDEX2 + 70 +0 + 3 +Divide (2x) ____ . . ____ . . ____ . . ____ + 72 +65 + 73 +6 + 40 +2.6 + 49 +2.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 49 +0.0 + 49 +-0.2 + 0 +LTYPE + 5 +449 + 2 +DIVIDE2 + 70 +0 + 3 +Divide(.5x) _ . _ . _ . _ . _ . _ . _ . _ + 72 +65 + 73 +6 + 40 +0.8 + 49 +0.5 + 49 +-0.1 + 49 +0.0 + 49 +-0.1 + 49 +0.0 + 49 +-0.1 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +433 + 70 +18 + 0 +STYLE + 5 +417 + 2 +STANDARD + 70 +0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 +0 + 42 +0.2 + 3 +txt + 4 + + 0 +STYLE + 5 +44A + 2 +OpenSans + 70 +0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 +0 + 42 +1.0 + 3 +OpenSans-Regular.ttf + 4 + + 0 +STYLE + 5 +44F + 2 +OpenSansCondensed-Light + 70 +0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 +0 + 42 +1.0 + 3 +OpenSansCondensed-Light.ttf + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +434 + 70 +0 + 0 +ENDTAB + 0 +ENDSEC +""" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/sierpinski_pyramid.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/sierpinski_pyramid.py new file mode 100644 index 0000000..f39147b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/sierpinski_pyramid.py @@ -0,0 +1,235 @@ +# Purpose: create sierpinski pyramid geometry +# Copyright (c) 2016-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Sequence, Iterator, Optional +import math +from ezdxf.math import Vec3, UVec, Matrix44, UCS +from ezdxf.render.mesh import MeshVertexMerger, MeshTransformer + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +HEIGHT4 = 1.0 / math.sqrt(2.0) # pyramid4 height (* length) +HEIGHT3 = math.sqrt(6.0) / 3.0 # pyramid3 height (* length) + +DY1_FACTOR = math.tan(math.pi / 6.0) / 2.0 # inner circle radius +DY2_FACTOR = 0.5 / math.cos(math.pi / 6.0) # outer circle radius + + +class SierpinskyPyramid: + """ + Args: + location: location of base center as (x, y, z) tuple + length: side length + level: subdivide level + sides: sides of base geometry + + """ + + def __init__( + self, + location: UVec = (0.0, 0.0, 0.0), + length: float = 1.0, + level: int = 1, + sides: int = 4, + ): + self.sides = sides + self.pyramid_definitions = sierpinsky_pyramid( + location=location, length=length, level=level, sides=sides + ) + + def vertices(self) -> Iterator[list[Vec3]]: + """Yields the pyramid vertices as list of :class:`ezdxf.math.Vec3`.""" + for location, length in self.pyramid_definitions: + yield self._calc_vertices(location, length) + + __iter__ = vertices + + def _calc_vertices( + self, location: UVec, length: float + ) -> list[Vec3]: + """ + Calculates the pyramid vertices. + + Args: + location: location of the pyramid as center point of the base + length: pyramid side length + + Returns: list of :class:`ezdxf.math.Vec3` + + """ + len2 = length / 2.0 + x, y, z = location + if self.sides == 4: + return [ + Vec3(x - len2, y - len2, z), + Vec3(x + len2, y - len2, z), + Vec3(x + len2, y + len2, z), + Vec3(x - len2, y + len2, z), + Vec3(x, y, z + length * HEIGHT4), + ] + elif self.sides == 3: + dy1 = length * DY1_FACTOR + dy2 = length * DY2_FACTOR + return [ + Vec3(x - len2, y - dy1, z), + Vec3(x + len2, y - dy1, z), + Vec3(x, y + dy2, z), + Vec3(x, y, z + length * HEIGHT3), + ] + else: + raise ValueError("sides has to be 3 or 4.") + + def faces(self) -> list[Sequence[int]]: + """Returns list of pyramid faces. All pyramid vertices have the same + order, so one faces list fits them all. + + """ + if self.sides == 4: + return [(3, 2, 1, 0), (0, 1, 4), (1, 2, 4), (2, 3, 4), (3, 0, 4)] + elif self.sides == 3: + return [(2, 1, 0), (0, 1, 3), (1, 2, 3), (2, 0, 3)] + else: + raise ValueError("sides has to be 3 or 4.") + + def render( + self, + layout: GenericLayoutType, + merge: bool = False, + dxfattribs=None, + matrix: Optional[Matrix44] = None, + ucs: Optional[UCS] = None, + ) -> None: + """Renders the sierpinsky pyramid into layout, set `merge` to ``True`` + for rendering the whole sierpinsky pyramid into one MESH entity, set + `merge` to ``False`` for individual pyramids as MESH entities. + + Args: + layout: DXF target layout + merge: ``True`` for one MESH entity, ``False`` for individual MESH + entities per pyramid + dxfattribs: DXF attributes for the MESH entities + matrix: apply transformation matrix at rendering + ucs: apply UCS at rendering + + """ + if merge: + mesh = self.mesh() + mesh.render_mesh( + layout, dxfattribs=dxfattribs, matrix=matrix, ucs=ucs + ) + else: + for pyramid in self.pyramids(): + pyramid.render_mesh(layout, dxfattribs, matrix=matrix, ucs=ucs) + + def pyramids(self) -> Iterable[MeshTransformer]: + """Yields all pyramids of the sierpinsky pyramid as individual + :class:`MeshTransformer` objects. + """ + faces = self.faces() + for vertices in self: + mesh = MeshTransformer() + mesh.add_mesh(vertices=vertices, faces=faces) + yield mesh + + def mesh(self) -> MeshTransformer: + """Returns geometry as one :class:`MeshTransformer` object.""" + faces = self.faces() + mesh = MeshVertexMerger() + for vertices in self: + mesh.add_mesh(vertices=vertices, faces=faces) + return MeshTransformer.from_builder(mesh) + + +def sierpinsky_pyramid( + location=(0.0, 0.0, 0.0), + length: float = 1.0, + level: int = 1, + sides: int = 4, +) -> list[tuple[Vec3, float]]: + """Build a Sierpinski pyramid. + + Args: + location: base center point of the pyramid + length: base length of the pyramid + level: recursive building levels, has to 1 or bigger + sides: 3 or 4 sided pyramids supported + + Returns: list of pyramid vertices + + """ + location = Vec3(location) + level = int(level) + if level < 1: + raise ValueError("level has to be 1 or bigger.") + pyramids = _sierpinsky_pyramid(location, length, sides) + for _ in range(level - 1): + next_level_pyramids = [] + for location, length in pyramids: + next_level_pyramids.extend( + _sierpinsky_pyramid(location, length, sides) + ) + pyramids = next_level_pyramids + return pyramids + + +def _sierpinsky_pyramid( + location: Vec3, length: float = 1.0, sides: int = 4 +) -> list[tuple[Vec3, float]]: + if sides == 3: + return sierpinsky_pyramid_3(location, length) + elif sides == 4: + return sierpinsky_pyramid_4(location, length) + else: + raise ValueError("sides has to be 3 or 4.") + + +def sierpinsky_pyramid_4( + location: Vec3, length: float = 1.0 +) -> list[tuple[Vec3, float]]: + """Build a 4-sided Sierpinski pyramid. Pyramid height = length of the base + square! + + Args: + location: base center point of the pyramid + length: base length of the pyramid + + Returns: list of (location, length) tuples, representing the sierpinski pyramid + + """ + len2 = length / 2 + len4 = length / 4 + x, y, z = location + return [ + (Vec3(x - len4, y - len4, z), len2), + (Vec3(x + len4, y - len4, z), len2), + (Vec3(x - len4, y + len4, z), len2), + (Vec3(x + len4, y + len4, z), len2), + (Vec3(x, y, z + len2 * HEIGHT4), len2), + ] + + +def sierpinsky_pyramid_3( + location: Vec3, length: float = 1.0 +) -> list[tuple[Vec3, float]]: + """Build a 3-sided Sierpinski pyramid (tetraeder). + + Args: + location: base center point of the pyramid + length: base length of the pyramid + + Returns: list of (location, length) tuples, representing the sierpinski pyramid + + """ + dy1 = length * DY1_FACTOR * 0.5 + dy2 = length * DY2_FACTOR * 0.5 + len2 = length / 2 + len4 = length / 4 + x, y, z = location + return [ + (Vec3(x - len4, y - dy1, z), len2), + (Vec3(x + len4, y - dy1, z), len2), + (Vec3(x, y + dy2, z), len2), + (Vec3(x, y, z + len2 * HEIGHT3), len2), + ] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/tablepainter.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/tablepainter.py new file mode 100644 index 0000000..11f45fb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/tablepainter.py @@ -0,0 +1,927 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Any, + Callable, + Iterable, + Iterator, + Optional, + Sequence, + TYPE_CHECKING, + TypeVar, +) +from copy import deepcopy + +from ezdxf.lldxf import const +from ezdxf.enums import ( + MTextEntityAlignment, + MAP_MTEXT_ALIGN_TO_FLAGS, +) +from ezdxf.addons import MTextSurrogate +from ezdxf.math import UVec, Vec2 + +if TYPE_CHECKING: + from ezdxf.layouts import BlockLayout + from ezdxf.eztypes import GenericLayoutType + +DEFAULT_TABLE_BG_LAYER = "TABLEBACKGROUND" +DEFAULT_TABLE_FG_LAYER = "TABLECONTENT" +DEFAULT_TABLE_GRID_LAYER = "TABLEGRID" +DEFAULT_TEXT_STYLE = "STANDARD" +DEFAULT_CELL_HEIGHT = 1.0 +DEFAULT_CELL_WIDTH = 2.5 +DEFAULT_CELL_CHAR_HEIGHT = 0.7 +DEFAULT_CELL_LINE_SPACING = 1.5 +DEFAULT_CELL_X_SCALE = 1.0 +DEFAULT_CELL_Y_SCALE = 1.0 +DEFAULT_CELL_TEXTCOLOR = const.BYLAYER +DEFAULT_CELL_BG_COLOR = None +DEFAULT_CELL_X_MARGIN = 0.1 +DEFAULT_CELL_Y_MARGIN = 0.1 +DEFAULT_BORDER_COLOR = 5 +DEFAULT_BORDER_LINETYPE = "BYLAYER" +DEFAULT_BORDER_STATUS = True +DEFAULT_BORDER_PRIORITY = 50 + + +T = TypeVar("T", bound="Cell") + + +class TablePainter: + """The TablePainter class renders tables build from DXF primitives. + + The TablePainter instance contains all the data cells. + + Args: + insert: insert location as or :class:`~ezdxf.math.UVec` + nrows: row count + ncols: column count + cell_width: default cell width in drawing units + cell_height: default cell height in drawing units + default_grid: draw a grid of solid lines if ``True``, otherwise + draw only explicit defined borders, the default grid has a + priority of 50. + + """ + + def __init__( + self, + insert: UVec, + nrows: int, + ncols: int, + cell_width=DEFAULT_CELL_WIDTH, + cell_height=DEFAULT_CELL_HEIGHT, + default_grid=True, + ): + self.insert = Vec2(insert) + self.nrows: int = nrows + self.ncols: int = ncols + self.row_heights: list[float] = [cell_height] * nrows + self.col_widths: list[float] = [cell_width] * ncols + self.bg_layer_name: str = DEFAULT_TABLE_BG_LAYER + self.fg_layer_name: str = DEFAULT_TABLE_FG_LAYER + self.grid_layer_name: str = DEFAULT_TABLE_GRID_LAYER + self.styles: dict[str, CellStyle] = {"default": CellStyle()} + if not default_grid: + default_style = self.get_cell_style("default") + default_style.set_border_status(False, False, False, False) + + self._cells: dict[tuple[int, int], Cell] = {} # data cells + self.frames: list[Frame] = [] # border frame objects + self.empty_cell = Cell(self) # represents all empty cells + + def set_col_width(self, index: int, value: float): + """Set column width in drawing units of the given column index. + + Args: + index: zero based column index + value: new column width in drawing units + + """ + self.col_widths[index] = float(value) + + def set_row_height(self, index: int, value: float): + """Set row height in drawing units of the given row index. + + Args: + index: zero based row index + value: new row height in drawing units + """ + self.row_heights[index] = float(value) + + def text_cell( + self, + row: int, + col: int, + text: str, + span: tuple[int, int] = (1, 1), + style="default", + ) -> TextCell: + """Factory method to create a new text cell at location (row, col), + with `text` as content, the `text` can be a line breaks ``'\\n'``. + The final cell can spread over several cells defined by the argument + `span`. + + """ + cell = TextCell(self, text, style=style, span=span) + return self.set_cell(row, col, cell) + + def block_cell( + self, + row: int, + col: int, + blockdef: BlockLayout, + span: tuple[int, int] = (1, 1), + attribs=None, + style="default", + ) -> BlockCell: + """Factory method to Create a new block cell at position (row, col). + + Content is a block reference inserted by an INSERT entity, + attributes will be added if the block definition contains ATTDEF. + Assignments are defined by attribs-key to attdef-tag association. + + Example: attribs = {'num': 1} if an ATTDEF with tag=='num' in + the block definition exists, an attrib with text=str(1) will be + created and added to the insert entity. + + The cell spans over 'span' cells and has the cell style with the + name 'style'. + """ + if attribs is None: + attribs = {} + cell = BlockCell( + self, blockdef, style=style, attribs=attribs, span=span + ) + return self.set_cell(row, col, cell) + + @property + def table_width(self) -> float: + """Returns the total table width.""" + return sum(self.col_widths) + + @property + def table_height(self) -> float: + """Returns the total table height.""" + return sum(self.row_heights) + + def set_cell(self, row: int, col: int, cell: T) -> T: + """Insert a cell at position (row, col).""" + row, col = self.validate_index(row, col) + self._cells[row, col] = cell + return cell + + def get_cell(self, row: int, col: int) -> Cell: + """Get cell at location (row, col).""" + row, col = self.validate_index(row, col) + try: + return self._cells[row, col] + except KeyError: + return self.empty_cell # empty cell with default style + + def validate_index(self, row: int, col: int) -> tuple[int, int]: + row = int(row) + col = int(col) + if row < 0 or row >= self.nrows or col < 0 or col >= self.ncols: + raise IndexError("cell index out of range") + return row, col + + def frame( + self, + row: int, + col: int, + width: int = 1, + height: int = 1, + style="default", + ) -> Frame: + """Creates a frame around the give cell area, starting at (row, col) and + covering `width` columns and `height` rows. The `style` argument is the + name of a :class:`CellStyle`. + """ + frame = Frame(self, pos=(row, col), span=(height, width), style=style) + self.frames.append(frame) + return frame + + def new_cell_style(self, name: str, **kwargs) -> CellStyle: + """Factory method to create a new :class:`CellStyle` object, overwrites + an already existing cell style. + + Args: + name: style name as string + kwargs: see attributes of class :class:`CellStyle` + + """ + assert ( + isinstance(name, str) and name != "" + ), "name has to be a non-empty string" + style: CellStyle = deepcopy(self.get_cell_style("default")) + style.update(kwargs) + self.styles[name] = style + return style + + @staticmethod + def new_border_style( + color: int = const.BYLAYER, + status=True, + priority: int = 100, + linetype: str = "BYLAYER", + lineweight: int = const.LINEWEIGHT_BYLAYER, + ) -> BorderStyle: + """Factory method to create a new border style. + + Args: + status: ``True`` for visible, ``False`` for invisible + color: :ref:`ACI` + linetype: linetype name, default is "BYLAYER" + lineweight: lineweight as int, default is by layer + priority: drawing priority, higher priorities cover lower priorities + + """ + border_style = BorderStyle() + border_style.color = color + border_style.linetype = linetype + border_style.lineweight = lineweight + border_style.status = status + border_style.priority = priority + return border_style + + def get_cell_style(self, name: str) -> CellStyle: + """Get cell style by name.""" + return self.styles[name] + + def iter_visible_cells( + self, visibility_map: VisibilityMap + ) -> Iterator[tuple[int, int, Cell]]: + """Iterate over all visible cells""" + return ( + (row, col, self.get_cell(row, col)) for row, col in visibility_map + ) + + def render(self, layout: GenericLayoutType, insert: Optional[UVec] = None): + """Render table to layout.""" + insert_backup = self.insert + if insert is not None: + self.insert = Vec2(insert) + visibility_map = VisibilityMap(self) + grid = Grid(self) + for row, col, cell in self.iter_visible_cells(visibility_map): + grid.render_cell_background(layout, row, col, cell) + grid.render_cell_content(layout, row, col, cell) + grid.render_lines(layout, visibility_map) + self.insert = insert_backup + + +class VisibilityMap: + """Stores the visibility of the table cells.""" + + def __init__(self, table: TablePainter): + """Create the visibility map for table.""" + self.table: TablePainter = table + self._hidden_cells: set[tuple[int, int]] = set() + self._create_visibility_map() + + def _create_visibility_map(self): + """Set visibility for all existing cells.""" + for row, col in iter(self): + cell = self.table.get_cell(row, col) + self._set_span_visibility(row, col, cell.span) + + def _set_span_visibility(self, row: int, col: int, span: tuple[int, int]): + """Set the visibility of the given cell. + + The cell itself is visible, all other cells in the span-range + (tuple: width, height) are invisible, they are covered by the + main cell (row, col). + """ + + if span != (1, 1): + nrows, ncols = span + for rowx in range(nrows): + for colx in range(ncols): + # switch all cells in span range to invisible + self.hide(row + rowx, col + colx) + # switch content cell visible + self.show(row, col) + + def show(self, row: int, col: int): + """Show cell (row, col).""" + try: + self._hidden_cells.remove((row, col)) + except KeyError: + pass + + def hide(self, row: int, col: int) -> None: + """Hide cell (row, col).""" + self._hidden_cells.add((row, col)) + + def iter_all_cells(self) -> Iterator[tuple[int, int]]: + """Iterate over all cell indices, yields (row, col) tuples.""" + for row in range(self.table.nrows): + for col in range(self.table.ncols): + yield row, col + + def is_visible_cell(self, row: int, col: int) -> bool: + """True if cell (row, col) is visible, else False.""" + return (row, col) not in self._hidden_cells + + def __iter__(self) -> Iterator[tuple[int, int]]: + """Iterate over all visible cells.""" + return ( + (row, col) + for (row, col) in self.iter_all_cells() + if self.is_visible_cell(row, col) + ) + + +class CellStyle: + """Cell style object. + + .. important:: + + Always instantiate new styles by the factory method: + :meth:`TablePainter.new_cell_style` + + """ + + def __init__(self, data: Optional[dict[str, Any]] = None): + # text style is ignored by block cells + self.text_style = "STANDARD" + # text height in drawing units, ignored by block cells + self.char_height = DEFAULT_CELL_CHAR_HEIGHT + # line spacing in percent = char_height * line_spacing, ignored by block cells + self.line_spacing = DEFAULT_CELL_LINE_SPACING + # text stretching factor (width factor) or block reference x-scaling factor + self.scale_x = DEFAULT_CELL_X_SCALE + # block reference y-axis scaling factor, ignored by text cells + self.scale_y = DEFAULT_CELL_Y_SCALE + # dxf color index, ignored by block cells + self.text_color = DEFAULT_CELL_TEXTCOLOR + # text or block rotation in degrees + self.rotation = 0.0 + # Letters are stacked top-to-bottom, but not rotated + self.stacked = False + # text and block alignment, see ezdxf.enums.MTextEntityAlignment + self.align = MTextEntityAlignment.TOP_CENTER + # left and right cell margin in drawing units + self.margin_x = DEFAULT_CELL_X_MARGIN + # top and bottom cell margin in drawing units + self.margin_y = DEFAULT_CELL_Y_MARGIN + # background color, dxf color index, ignored by block cells + self.bg_color = DEFAULT_CELL_BG_COLOR + # left border style + self.left = BorderStyle() + # top border style + self.top = BorderStyle() + # right border style + self.right = BorderStyle() + # bottom border style + self.bottom = BorderStyle() + if data: + self.update(data) + + def __getitem__(self, k: str) -> Any: + return self.__dict__[k] + + def __setitem__(self, k: str, v: Any): + if k in self.__dict__: + self.__dict__.__setitem__(k, v) + else: + raise KeyError(f"invalid attribute name: {k}") + + def update(self, data: dict[str, Any]): + for k, v in data.items(): + self.__setitem__(k, v) + assert isinstance( + self.align, MTextEntityAlignment + ), "enum ezdxf.enums.MTextEntityAlignment for text alignments required" + + def set_border_status(self, left=True, right=True, top=True, bottom=True): + """Set status of all cell borders at once.""" + self.left.status = left + self.right.status = right + self.top.status = top + self.bottom.status = bottom + + def set_border_style( + self, style: BorderStyle, left=True, right=True, top=True, bottom=True + ): + """Set border styles of all cell borders at once.""" + for border, status in ( + ("left", left), + ("right", right), + ("top", top), + ("bottom", bottom), + ): + if status: + self[border] = style + + @staticmethod + def get_default_border_style() -> BorderStyle: + return BorderStyle() + + def get_text_align_flags(self) -> tuple[int, int]: + return MAP_MTEXT_ALIGN_TO_FLAGS[self.align] + + +class BorderStyle: + """Border style class. + + .. important:: + + Always instantiate new border styles by the factory method: + :meth:`TablePainter.new_border_style` + + """ + + def __init__( + self, + status: bool = DEFAULT_BORDER_STATUS, + color: int = DEFAULT_BORDER_COLOR, + linetype: str = DEFAULT_BORDER_LINETYPE, + lineweight=const.LINEWEIGHT_BYLAYER, + priority: int = DEFAULT_BORDER_PRIORITY, + ): + # border status, True for visible, False for hidden + self.status = status + # ACI + self.color = color + # linetype name, BYLAYER if None + self.linetype = linetype + # lineweight + self.lineweight = lineweight + # drawing priority, higher values cover lower values + self.priority = priority + + +class Grid: + """Grid contains the graphical representation of the table.""" + + def __init__(self, table: TablePainter): + self.table: TablePainter = table + # contains the x-axis coords of the grid lines between the data columns. + self.col_pos: list[float] = self._calc_col_pos() + # contains the y-axis coords of the grid lines between the data rows. + self.row_pos: list[float] = self._calc_row_pos() + + # _x_borders contains the horizontal border elements, list of border styles + # get index with _border_index(row, col), which means the border element + # above row, col, and row-indices are [0 .. nrows+1], nrows+1 for the + # grid line below the last row; list contains only the border style with + # the highest priority. + self._x_borders: list[BorderStyle] = [] # created in _init_borders + + # _y_borders: same as _x_borders but for the vertical borders, + # col-indices are [0 .. ncols+1], ncols+1 for the last grid line right + # of the last column + self._y_borders: list[BorderStyle] = [] # created in _init_borders + # border style to delete borders inside of merged cells + self.no_border = BorderStyle( + status=False, priority=999, linetype="BYLAYER", color=0 + ) + + def _init_borders(self, x_border: BorderStyle, y_border: BorderStyle): + """Init the _hborders with and _vborders with .""" + # has more elements than necessary, but it unifies the + # index calculation for _vborders and _hborders. + # exact values are: + # x_border_count = ncols * (nrows+1), hindex = ncols * + + # y_border_count = nrows * (ncols+1), vindex = (ncols+1) * + + border_count: int = (self.table.nrows + 1) * (self.table.ncols + 1) + self._x_borders = [x_border] * border_count + self._y_borders = [y_border] * border_count + + def _border_index(self, row: int, col: int) -> int: + """Calculate linear index for border arrays _x_borders and _y_borders.""" + return row * (self.table.ncols + 1) + col + + def set_x_border(self, row: int, col: int, border_style: BorderStyle): + """Set for the horizontal border element above + , . + """ + return self._set_border_style(self._x_borders, row, col, border_style) + + def set_y_border(self, row: int, col: int, border_style: BorderStyle): + """Set for the vertical border element left of + , . + """ + return self._set_border_style(self._y_borders, row, col, border_style) + + def _set_border_style( + self, + borders: list[BorderStyle], + row: int, + col: int, + border_style: BorderStyle, + ): + """Set for , in .""" + border_index = self._border_index(row, col) + actual_borderstyle = borders[border_index] + if border_style.priority >= actual_borderstyle.priority: + borders[border_index] = border_style + + def get_x_border(self, row: int, col: int) -> BorderStyle: + """Get the horizontal border element above , . + Last grid line (below ) is the element above of . + """ + return self._get_border(self._x_borders, row, col) + + def get_y_border(self, row: int, col: int) -> BorderStyle: + """Get the vertical border element left of , . + Last grid line (right of ) is the element left of . + """ + return self._get_border(self._y_borders, row, col) + + def _get_border( + self, borders: list[BorderStyle], row: int, col: int + ) -> BorderStyle: + """Get border element at , from .""" + return borders[self._border_index(row, col)] + + def _calc_col_pos(self) -> list[float]: + """Calculate the x-axis coords of the grid lines between the columns.""" + col_pos: list[float] = [] + start_x: float = self.table.insert.x + sum_fields(start_x, self.table.col_widths, col_pos.append) + return col_pos + + def _calc_row_pos(self) -> list[float]: + """Calculate the y-axis coords of the grid lines between the rows.""" + row_pos: list[float] = [] + start_y: float = self.table.insert.y + sum_fields(start_y, self.table.row_heights, row_pos.append, -1.0) + return row_pos + + def cell_coords( + self, row: int, col: int, span: tuple[int, int] + ) -> tuple[float, float, float, float]: + """Get the coordinates of the cell , as absolute drawing units. + + :return: a tuple (left, right, top, bottom) + """ + top = self.row_pos[row] + bottom = self.row_pos[row + span[0]] + left = self.col_pos[col] + right = self.col_pos[col + span[1]] + return left, right, top, bottom + + def render_cell_background( + self, layout: GenericLayoutType, row: int, col: int, cell: Cell + ): + """Render the cell background for (row, col) as SOLID entity.""" + style = cell.style + if style.bg_color is None: + return + # get cell coords in absolute drawing units + left, right, top, bottom = self.cell_coords(row, col, cell.span) + layout.add_solid( + points=((left, top), (left, bottom), (right, top), (right, bottom)), + dxfattribs={ + "color": style.bg_color, + "layer": self.table.bg_layer_name, + }, + ) + + def render_cell_content( + self, layout: GenericLayoutType, row: int, col: int, cell: Cell + ): + """Render the cell content for , into layout object.""" + # get cell coords in absolute drawing units + coords = self.cell_coords(row, col, cell.span) + cell.render(layout, coords, self.table.fg_layer_name) + + def render_lines(self, layout: GenericLayoutType, vm: VisibilityMap): + """Render all grid lines into layout object.""" + # Init borders with default_style top- and left border. + default_style = self.table.get_cell_style("default") + x_border = default_style.top + y_border = default_style.left + self._init_borders(x_border, y_border) + self._set_frames(self.table.frames) + self._set_borders(self.table.iter_visible_cells(vm)) + self._render_borders(layout, self.table) + + def _set_borders(self, visible_cells: Iterable[tuple[int, int, Cell]]): + """Set borders of the visible cells.""" + for row, col, cell in visible_cells: + bottom_row = row + cell.span[0] + right_col = col + cell.span[1] + self._set_rect_borders(row, bottom_row, col, right_col, cell.style) + self._set_inner_borders( + row, bottom_row, col, right_col, self.no_border + ) + + def _set_inner_borders( + self, + top_row: int, + bottom_row: int, + left_col: int, + right_col: int, + border_style: BorderStyle, + ): + """Set `border_style` to the inner borders of the rectangle (top_row, + bottom_row, ...) + """ + if bottom_row - top_row > 1: + for col in range(left_col, right_col): + for row in range(top_row + 1, bottom_row): + self.set_x_border(row, col, border_style) + if right_col - left_col > 1: + for row in range(top_row, bottom_row): + for col in range(left_col + 1, right_col): + self.set_y_border(row, col, border_style) + + def _set_rect_borders( + self, + top_row: int, + bottom_row: int, + left_col: int, + right_col: int, + style: CellStyle, + ): + """Set border `style` to the rectangle (top_row, bottom_row, ...) + + The values describing the grid lines between the cells, see doc-strings + for methods set_x_border() and set_y_border() and see comments for + self._x_borders and self._y_borders. + """ + for col in range(left_col, right_col): + self.set_x_border(top_row, col, style.top) + self.set_x_border(bottom_row, col, style.bottom) + for row in range(top_row, bottom_row): + self.set_y_border(row, left_col, style.left) + self.set_y_border(row, right_col, style.right) + + def _set_frames(self, frames: Iterable[Frame]): + """Set borders for all defined frames.""" + for frame in frames: + top_row = frame.pos[0] + left_col = frame.pos[1] + bottom_row = top_row + frame.span[0] + right_col = left_col + frame.span[1] + self._set_rect_borders( + top_row, bottom_row, left_col, right_col, frame.style + ) + + def _render_borders(self, layout: GenericLayoutType, table: TablePainter): + """Render the grid lines as LINE entities into layout object.""" + + def render_line(start: Vec2, end: Vec2, style: BorderStyle): + """Render the LINE entity into layout object.""" + if style.status: + layout.add_line( + start=start, + end=end, + dxfattribs={ + "layer": layer, + "color": style.color, + "linetype": style.linetype, + "lineweight": style.lineweight, + }, + ) + + def render_x_borders(): + """Draw the horizontal grid lines.""" + for row in range(table.nrows + 1): + y = self.row_pos[row] + for col in range(table.ncols): + left = self.col_pos[col] + right = self.col_pos[col + 1] + style = self.get_x_border(row, col) + render_line(Vec2(left, y), Vec2(right, y), style) + + def render_y_borders(): + """Draw the vertical grid lines.""" + for col in range(table.ncols + 1): + x = self.col_pos[col] + for row in range(table.nrows): + top = self.row_pos[row] + bottom = self.row_pos[row + 1] + style = self.get_y_border(row, col) + render_line(Vec2(x, top), Vec2(x, bottom), style) + + layer = table.grid_layer_name + render_x_borders() + render_y_borders() + + +class Frame: + """Represent a rectangle cell area enclosed by borderlines. + + Args: + table: the assigned data table + pos: tuple (row, col), border goes left and top of pos + span: count of cells that Frame covers, border goes right and below of this cells + style: style name as string + """ + + def __init__( + self, + table: TablePainter, + pos: tuple[int, int] = (0, 0), + span: tuple[int, int] = (1, 1), + style="default", + ): + self.table = table + self.pos = pos + self.span = span + self.stylename = style + + @property + def style(self) -> CellStyle: + return self.table.get_cell_style(self.stylename) + + +class Cell: + """Base class for table cells. + + Args: + table: assigned data table + style: style name as string + span: tuple(spanrows, spancols), count of cells that cell covers + + A cell doesn't know its own position in the data table, because a cell can + be used multiple times in the same or in different tables, therefore the + cell itself can not determine if the cell-range reaches beyond the table + borders. + """ + + def __init__( + self, + table: TablePainter, + style="default", + span: tuple[int, int] = (1, 1), + ): + self.table = table + self.stylename = style + # span values has to be >= 1 + self.span = span + + @property + def span(self) -> tuple[int, int]: + """Get/set table span parameters.""" + return self._span + + @span.setter + def span(self, value: tuple[int, int]): + """Ensures that span values are >= 1 in each direction.""" + self._span = (max(1, value[0]), max(1, value[1])) + + @property + def style(self) -> CellStyle: + """Returns the associated :class:`CellStyle`.""" + return self.table.get_cell_style(self.stylename) + + def render( + self, layout: GenericLayoutType, coords: Sequence[float], layer: str + ): + """Renders the cell content into the given `layout`.""" + pass + + def get_workspace_coords(self, coords: Sequence[float]) -> Sequence[float]: + """Reduces the cell-coords about the margin_x and the margin_y values.""" + margin_x = self.style.margin_x + margin_y = self.style.margin_y + return ( + coords[0] + margin_x, # left + coords[1] - margin_x, # right + coords[2] - margin_y, # top + coords[3] + margin_y, # bottom + ) + + +CustomCell = Cell + + +class TextCell(Cell): + """Implements a cell type containing a multi-line text. Uses the + :class:`~ezdxf.addons.MTextSurrogate` add-on to render the multi-line + text, therefore the content of these cells is compatible to DXF R12. + + Args: + table: assigned data table + text: multi line text, lines separated by the new line character ``"\\n"`` + style: cell style name as string + span: tuple(rows, cols) area of cells to cover + + """ + + def __init__( + self, + table: TablePainter, + text: str, + style="default", + span: tuple[int, int] = (1, 1), + ): + super(TextCell, self).__init__(table, style, span) + self.text = text + + def render( + self, layout: GenericLayoutType, coords: Sequence[float], layer: str + ): + """Text cell. + + Args: + layout: target layout + coords: tuple of border-coordinates: left, right, top, bottom + layer: target layer name as string + + """ + if not len(self.text): + return + + left, right, top, bottom = self.get_workspace_coords(coords) + style = self.style + h_align, v_align = style.get_text_align_flags() + rotated = self.style.rotation + text = self.text + if style.stacked: + rotated = 0.0 + text = "\n".join((char for char in self.text.replace("\n", " "))) + xpos = (left, float(left + right) / 2.0, right)[h_align] + ypos = (bottom, float(bottom + top) / 2.0, top)[v_align - 1] + mtext = MTextSurrogate( + text, + (xpos, ypos), + line_spacing=self.style.line_spacing, + style=self.style.text_style, + char_height=self.style.char_height, + rotation=rotated, + width_factor=self.style.scale_x, + align=style.align, + color=self.style.text_color, + layer=layer, + ) + mtext.render(layout) + + +class BlockCell(Cell): + """Implements a cell type containing a block reference. + + Args: + table: table object + blockdef: :class:`ezdxf.layouts.BlockLayout` instance + attribs: BLOCK attributes as (tag, value) dictionary + style: cell style name as string + span: tuple(rows, cols) area of cells to cover + + """ + + def __init__( + self, + table: TablePainter, + blockdef: BlockLayout, + style="default", + attribs=None, + span: tuple[int, int] = (1, 1), + ): + if attribs is None: + attribs = {} + super(BlockCell, self).__init__(table, style, span) + self.block_name = blockdef.name # dxf block name! + self.attribs = attribs + + def render( + self, layout: GenericLayoutType, coords: Sequence[float], layer: str + ): + """Create the cell content as INSERT-entity with trailing ATTRIB-Entities. + + Args: + layout: target layout + coords: tuple of border-coordinates : left, right, top, bottom + layer: target layer name as string + + """ + left, right, top, bottom = self.get_workspace_coords(coords) + style = self.style + h_align, v_align = style.get_text_align_flags() + xpos = (left, float(left + right) / 2.0, right)[h_align] + ypos = (bottom, float(bottom + top) / 2.0, top)[v_align - 1] + layout.add_auto_blockref( + name=self.block_name, + insert=(xpos, ypos), + values=self.attribs, + dxfattribs={ + "xscale": style.scale_x, + "yscale": style.scale_y, + "rotation": style.rotation, + "layer": layer, + }, + ) + + +def sum_fields( + start_value: float, + fields: list[float], + append: Callable[[float], None], + sign: float = 1.0, +): + """Adds step-by-step the fields-values, starting with , + and appends the resulting values to another object with the + append-method. + """ + position = start_value + append(position) + for element in fields: + position += element * sign + append(position) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/text2path.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/text2path.py new file mode 100644 index 0000000..b4a9a67 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/text2path.py @@ -0,0 +1,358 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union +import enum + +from ezdxf.entities import Text, Attrib, Hatch, DXFGraphic +from ezdxf.lldxf import const +from ezdxf.enums import TextEntityAlignment, MAP_TEXT_ENUM_TO_ALIGN_FLAGS +from ezdxf.math import Matrix44, BoundingBox +from ezdxf import path +from ezdxf.path import Path +from ezdxf.fonts import fonts +from ezdxf.query import EntityQuery + +__all__ = [ + "make_path_from_str", + "make_paths_from_str", + "make_hatches_from_str", + "make_path_from_entity", + "make_paths_from_entity", + "make_hatches_from_entity", + "virtual_entities", + "explode", + "Kind", +] + +AnyText = Union[Text, Attrib] +VALID_TYPES = ("TEXT", "ATTRIB") + + +def make_path_from_str( + s: str, + font: fonts.FontFace, + size: float = 1.0, + align=TextEntityAlignment.LEFT, + length: float = 0, + m: Matrix44 = None, +) -> Path: + """Convert a single line string `s` into a :term:`Multi-Path` object. + The text `size` is the height of the uppercase letter "X" (cap height). + The paths are aligned about the insertion point at (0, 0). + BASELINE means the bottom of the letter "X". + + Args: + s: text to convert + font: font face definition as :class:`~ezdxf.tools.fonts.FontFace` object + size: text size (cap height) in drawing units + align: alignment as :class:`ezdxf.enums.TextEntityAlignment`, + default is :attr:`LEFT` + length: target length for the :attr:`ALIGNED` and :attr:`FIT` alignments + m: transformation :class:`~ezdxf.math.Matrix44` + + """ + if len(s) == 0: + return Path() + abstract_font = get_font(font) + # scale font rendering units to drawing units: + p = _str_to_path(s, abstract_font, size) + bbox = path.bbox([p], fast=True) + + # Text is rendered in drawing units, + # therefore do alignment in drawing units: + draw_units_fm = abstract_font.measurements.scale_from_baseline(size) + matrix = alignment_transformation(draw_units_fm, bbox, align, length) + if m is not None: + matrix *= m + return p.transform(matrix) + + +def make_paths_from_str( + s: str, + font: fonts.FontFace, + size: float = 1.0, + align=TextEntityAlignment.LEFT, + length: float = 0, + m: Matrix44 = None, +) -> list[Path]: + """Convert a single line string `s` into a list of + :class:`~ezdxf.path.Path` objects. All paths are returned as a list of + :term:`Single-Path` objects. + The text `size` is the height of the uppercase letter "X" (cap height). + The paths are aligned about the insertion point at (0, 0). + BASELINE means the bottom of the letter "X". + + Args: + s: text to convert + font: font face definition as :class:`~ezdxf.tools.fonts.FontFace` object + size: text size (cap height) in drawing units + align: alignment as :class:`ezdxf.enums.TextEntityAlignment`, + default is :attr:`LEFT` + length: target length for the :attr:`ALIGNED` and :attr:`FIT` alignments + m: transformation :class:`~ezdxf.math.Matrix44` + + """ + if len(s) == 0: + return [] + p = make_path_from_str(s, font, size, align, length, m) + return list(p.sub_paths()) + + +def get_font(font: fonts.FontFace) -> fonts.AbstractFont: + font_name = fonts.font_manager.find_font_name(font) + return fonts.make_font(font_name, cap_height=1.0) + + +def _str_to_path(s: str, render_engine: fonts.AbstractFont, size: float = 1.0) -> Path: + return render_engine.text_path_ex(s, cap_height=size).to_path() + + +def alignment_transformation( + fm: fonts.FontMeasurements, + bbox: BoundingBox, + align: TextEntityAlignment, + length: float, +) -> Matrix44: + """Returns the alignment transformation matrix to transform a basic + text path at location (0, 0) and alignment :attr:`LEFT` into the final text + path of the given alignment. + For the alignments :attr:`FIT` and :attr:`ALIGNED` defines the argument + `length` the total length of the final text path. The given bounding box + defines the rendering borders of the basic text path. + + """ + halign, valign = MAP_TEXT_ENUM_TO_ALIGN_FLAGS[align] + matrix = basic_alignment_transformation(fm, bbox, halign, valign) + + stretch_x = 1.0 + stretch_y = 1.0 + if align == TextEntityAlignment.ALIGNED: + stretch_x = length / bbox.size.x + stretch_y = stretch_x + elif align == TextEntityAlignment.FIT: + stretch_x = length / bbox.size.x + if stretch_x != 1.0: + matrix *= Matrix44.scale(stretch_x, stretch_y, 1.0) + return matrix + + +def basic_alignment_transformation( + fm: fonts.FontMeasurements, bbox: BoundingBox, halign: int, valign: int +) -> Matrix44: + if halign == const.LEFT: + shift_x = 0.0 + elif halign == const.RIGHT: + assert bbox.extmax is not None, "invalid empty bounding box" + shift_x = -bbox.extmax.x + elif halign == const.CENTER or halign > 2: # ALIGNED, MIDDLE, FIT + assert bbox.center is not None, "invalid empty bounding box" + shift_x = -bbox.center.x + else: + raise ValueError(f"invalid halign argument: {halign}") + cap_height = fm.cap_height + descender_height = fm.descender_height + if valign == const.BASELINE: + shift_y = 0.0 + elif valign == const.TOP: + shift_y = -cap_height + elif valign == const.MIDDLE: + shift_y = -cap_height / 2 + elif valign == const.BOTTOM: + shift_y = descender_height + else: + raise ValueError(f"invalid valign argument: {valign}") + if halign == 4: # MIDDLE + shift_y = -cap_height + fm.total_height / 2.0 + return Matrix44.translate(shift_x, shift_y, 0) + + +def make_hatches_from_str( + s: str, + font: fonts.FontFace, + size: float = 1.0, + align=TextEntityAlignment.LEFT, + length: float = 0, + dxfattribs=None, + m: Matrix44 = None, +) -> list[Hatch]: + """Convert a single line string `s` into a list of virtual + :class:`~ezdxf.entities.Hatch` entities. + The text `size` is the height of the uppercase letter "X" (cap height). + The paths are aligned about the insertion point at (0, 0). + The HATCH entities are aligned to this insertion point. BASELINE means the + bottom of the letter "X". + + .. important:: + + Returns an empty list for .shx, .shp and .lff fonts a.k.a. stroke fonts. + + Args: + s: text to convert + font: font face definition as :class:`~ezdxf.tools.fonts.FontFace` object + size: text size (cap height) in drawing units + align: alignment as :class:`ezdxf.enums.TextEntityAlignment`, + default is :attr:`LEFT` + length: target length for the :attr:`ALIGNED` and :attr:`FIT` alignments + dxfattribs: additional DXF attributes + m: transformation :class:`~ezdxf.math.Matrix44` + + """ + font_ = get_font(font) + if font_.font_render_type is fonts.FontRenderType.STROKE: + return [] + + # HATCH is an OCS entity, transforming just the polyline paths + # is not correct! The Hatch has to be created in the xy-plane! + paths = make_paths_from_str(s, font, size, align, length) + dxfattribs = dict(dxfattribs or {}) + dxfattribs.setdefault("solid_fill", 1) + dxfattribs.setdefault("pattern_name", "SOLID") + dxfattribs.setdefault("color", const.BYLAYER) + hatches = path.to_hatches(paths, edge_path=True, dxfattribs=dxfattribs) + if m is not None: + # Transform HATCH entities as a unit: + return [hatch.transform(m) for hatch in hatches] # type: ignore + else: + return list(hatches) + + +def check_entity_type(entity): + if entity is None: + raise TypeError("entity is None") + elif not entity.dxftype() in VALID_TYPES: + raise TypeError(f"unsupported entity type: {entity.dxftype()}") + + +def make_path_from_entity(entity: AnyText) -> Path: + """Convert text content from DXF entities TEXT and ATTRIB into a + :term:`Multi-Path` object. + The paths are located at the location of the source entity. + """ + + check_entity_type(entity) + text = entity.plain_text() + p = make_path_from_str( + text, + fonts.get_font_face(entity.font_name()), + size=entity.dxf.height, # cap height in drawing units + align=entity.get_align_enum(), + length=entity.fit_length(), + ) + m = entity.wcs_transformation_matrix() + return p.transform(m) + + +def make_paths_from_entity(entity: AnyText) -> list[Path]: + """Convert text content from DXF entities TEXT and ATTRIB into a + list of :class:`~ezdxf.path.Path` objects. All paths are returned as a + list of :term:`Single-Path` objects. + The paths are located at the location of the source entity. + + """ + return list(make_path_from_entity(entity).sub_paths()) + + +def make_hatches_from_entity(entity: AnyText) -> list[Hatch]: + """Convert text content from DXF entities TEXT and ATTRIB into a + list of virtual :class:`~ezdxf.entities.Hatch` entities. + The hatches are placed at the same location as the source entity and have + the same DXF attributes as the source entity. + + """ + check_entity_type(entity) + extrusion = entity.dxf.extrusion + attribs = entity.graphic_properties() + paths = make_paths_from_entity(entity) + return list( + path.to_hatches( + paths, + edge_path=True, + extrusion=extrusion, + dxfattribs=attribs, + ) + ) + + +@enum.unique +class Kind(enum.IntEnum): + """The :class:`Kind` enum defines the DXF types to create as bit flags, + e.g. 1+2 to get HATCHES as filling and SPLINES and POLYLINES as outline: + + === =========== ============================== + Int Enum Description + === =========== ============================== + 1 HATCHES :class:`~ezdxf.entities.Hatch` entities as filling + 2 SPLINES :class:`~ezdxf.entities.Spline` and 3D :class:`~ezdxf.entities.Polyline` + entities as outline + 4 LWPOLYLINES :class:`~ezdxf.entities.LWPolyline` entities as approximated + (flattened) outline + === =========== ============================== + + """ + + HATCHES = 1 + SPLINES = 2 + LWPOLYLINES = 4 + + +def virtual_entities(entity: AnyText, kind: int = Kind.HATCHES) -> EntityQuery: + """Convert the text content of DXF entities TEXT and ATTRIB into virtual + SPLINE and 3D POLYLINE entities or approximated LWPOLYLINE entities + as outlines, or as HATCH entities as fillings. + + Returns the virtual DXF entities as an :class:`~ezdxf.query.EntityQuery` + object. + + Args: + entity: TEXT or ATTRIB entity + kind: kind of entities to create as bit flags, see enum :class:`Kind` + + """ + check_entity_type(entity) + extrusion = entity.dxf.extrusion + attribs = entity.graphic_properties() + entities: list[DXFGraphic] = [] + + if kind & Kind.HATCHES: + entities.extend(make_hatches_from_entity(entity)) + if kind & (Kind.SPLINES + Kind.LWPOLYLINES): + paths = make_paths_from_entity(entity) + if kind & Kind.SPLINES: + entities.extend(path.to_splines_and_polylines(paths, dxfattribs=attribs)) + if kind & Kind.LWPOLYLINES: + entities.extend( + path.to_lwpolylines(paths, extrusion=extrusion, dxfattribs=attribs) + ) + + return EntityQuery(entities) + + +def explode(entity: AnyText, kind: int = Kind.HATCHES, target=None) -> EntityQuery: + """Explode the text `entity` into virtual entities, + see :func:`virtual_entities`. The source entity will be destroyed. + + The target layout is given by the `target` argument, if `target` is ``None``, + the target layout is the source layout of the text entity. + + Returns the created DXF entities as an :class:`~ezdxf.query.EntityQuery` + object. + + Args: + entity: TEXT or ATTRIB entity to explode + kind: kind of entities to create as bit flags, see enum :class:`Kind` + target: target layout for new created DXF entities, ``None`` for the + same layout as the source entity. + + """ + entities = virtual_entities(entity, kind) + + # Explicit check for None is required, because empty layouts are also False + if target is None: + target = entity.get_layout() + entity.destroy() + + if target is not None: + for e in entities: + target.add_entity(e) + return EntityQuery(entities) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/xplayer.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/xplayer.py new file mode 100644 index 0000000..38fa3ca --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/xplayer.py @@ -0,0 +1,90 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +"""xplayer = cross backend player.""" +from __future__ import annotations +from typing import Callable +from ezdxf.math import Vec2 +from ezdxf.colors import RGB + +from ezdxf.addons.drawing.backend import BackendInterface, BkPath2d +from ezdxf.addons.drawing.properties import BackendProperties +from ezdxf.addons.hpgl2 import api as hpgl2 +from ezdxf.addons.hpgl2.backend import ( + Properties as HPGL2Properties, + RecordType as HPGL2RecordType, +) + + +def hpgl2_to_drawing( + player: hpgl2.Player, + backend: BackendInterface, + bg_color: str = "#ffffff", + override: Callable[[BackendProperties], BackendProperties] | None = None, +) -> None: + """Replays the recordings of the HPGL2 Recorder on a backend of the drawing add-on.""" + if bg_color: + backend.set_background(bg_color) + for record_type, properties, record_data in player.recordings(): + backend_properties = _make_drawing_backend_properties(properties) + if override: + backend_properties = override(backend_properties) + if record_type == HPGL2RecordType.POLYLINE: + points: list[Vec2] = record_data.vertices() + size = len(points) + if size == 1: + backend.draw_point(points[0], backend_properties) + elif size == 2: + backend.draw_line(points[0], points[1], backend_properties) + else: + backend.draw_path(BkPath2d.from_vertices(points), backend_properties) + elif record_type == HPGL2RecordType.FILLED_PATHS: + backend.draw_filled_paths(record_data, backend_properties) + elif record_type == HPGL2RecordType.OUTLINE_PATHS: + for p in record_data: + backend.draw_path(p, backend_properties) + backend.finalize() + + +def _make_drawing_backend_properties(properties: HPGL2Properties) -> BackendProperties: + """Make BackendProperties() for the drawing add-on.""" + return BackendProperties( + color=properties.pen_color.to_hex(), + lineweight=properties.pen_width, + layer="0", + pen=properties.pen_index, + handle="", + ) + + +def map_color(color: str) -> Callable[[BackendProperties], BackendProperties]: + def _map_color(properties: BackendProperties) -> BackendProperties: + return BackendProperties( + color=color, + lineweight=properties.lineweight, + layer=properties.layer, + pen=properties.pen, + handle=properties.handle, + ) + + return _map_color + + +def map_monochrome(dark_mode=True) -> Callable[[BackendProperties], BackendProperties]: + def to_gray(color: str) -> str: + gray = round(RGB.from_hex(color).luminance * 255) + if dark_mode: + gray = 255 - gray + return RGB(gray, gray, gray).to_hex() + + def _map_color(properties: BackendProperties) -> BackendProperties: + color = properties.color + alpha = color[7:9] + return BackendProperties( + color=to_gray(color[:7]) + alpha, + lineweight=properties.lineweight, + layer=properties.layer, + pen=properties.pen, + handle=properties.handle, + ) + + return _map_color diff --git a/.venv/lib/python3.12/site-packages/ezdxf/addons/xqt.py b/.venv/lib/python3.12/site-packages/ezdxf/addons/xqt.py new file mode 100644 index 0000000..5cf95c0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/addons/xqt.py @@ -0,0 +1,86 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +# mypy: ignore_errors=True +from ezdxf._options import DRAWING_ADDON, options + +# Qt compatibility layer: all Qt imports from ezdxf.addons.xqt +PYSIDE6 = False +TRY_PYSIDE6 = options.get_bool(DRAWING_ADDON, "try_pyside6", True) +PYQT5 = False +TRY_PYQT5 = options.get_bool(DRAWING_ADDON, "try_pyqt5", True) + +if TRY_PYSIDE6: + try: + from PySide6 import QtGui, QtCore, QtWidgets + from PySide6.QtWidgets import ( + QFileDialog, + QInputDialog, + QMessageBox, + QTableView, + QTreeView, + QListView, + ) + from PySide6.QtCore import ( + QAbstractTableModel, + QStringListModel, + QFileSystemWatcher, + QModelIndex, + QPointF, + QSettings, + QSize, + Qt, + Signal, + Slot, + ) + from PySide6.QtGui import ( + QAction, + QColor, + QPainterPath, + QStandardItem, + QStandardItemModel, + ) + + PYSIDE6 = True + print("using Qt binding: PySide6") + except ImportError: + pass + +# PyQt5 is just a fallback +if TRY_PYQT5 and not PYSIDE6: + try: + from PyQt5 import QtGui, QtCore, QtWidgets + from PyQt5.QtCore import pyqtSignal as Signal + from PyQt5.QtCore import pyqtSlot as Slot + from PyQt5.QtWidgets import ( + QAction, + QFileDialog, + QInputDialog, + QMessageBox, + QTableView, + QTreeView, + QListView, + ) + from PyQt5.QtCore import ( + QAbstractTableModel, + QStringListModel, + QFileSystemWatcher, + QModelIndex, + QPointF, + QSettings, + QSize, + Qt, + ) + from PyQt5.QtGui import ( + QColor, + QPainterPath, + QStandardItem, + QStandardItemModel, + ) + + PYQT5 = True + print("using Qt binding: PyQt5") + except ImportError: + pass + +if not (PYSIDE6 or PYQT5): + raise ImportError("no Qt binding found, tried PySide6 and PyQt5") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/appsettings.py b/.venv/lib/python3.12/site-packages/ezdxf/appsettings.py new file mode 100644 index 0000000..61b7c9e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/appsettings.py @@ -0,0 +1,141 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +# module to set application specific data +from __future__ import annotations +from typing import TYPE_CHECKING + +from ezdxf.lldxf import const, validator +from ezdxf.math import BoundingBox +from ezdxf import bbox +from ezdxf.enums import EndCaps, JoinStyle + +if TYPE_CHECKING: + from ezdxf.document import Drawing + +CURRENT_LAYER = "$CLAYER" +CURRENT_COLOR = "$CECOLOR" +CURRENT_LINETYPE = "$CELTYPE" +CURRENT_LINEWEIGHT = "$CELWEIGHT" +CURRENT_LINETYPE_SCALE = "$CELTSCALE" +CURRENT_TEXTSTYLE = "$TEXTSTYLE" +CURRENT_DIMSTYLE = "$DIMSTYLE" +EXTMIN = "$EXTMIN" +EXTMAX = "$EXTMAX" + + +def set_current_layer(doc: Drawing, name: str): + """Set current layer.""" + if name not in doc.layers: + raise const.DXFValueError(f'undefined layer: "{name}"') + doc.header[CURRENT_LAYER] = name + + +def set_current_color(doc: Drawing, color: int): + """Set current :ref:`ACI`.""" + if not validator.is_valid_aci_color(color): + raise const.DXFValueError(f'invalid ACI color value: "{color}"') + doc.header[CURRENT_COLOR] = color + + +def set_current_linetype(doc: Drawing, name: str): + """Set current linetype.""" + if name not in doc.linetypes: + raise const.DXFValueError(f'undefined linetype: "{name}"') + doc.header[CURRENT_LINETYPE] = name + + +def set_current_lineweight(doc: Drawing, lineweight: int): + """Set current lineweight, see :ref:`lineweights` reference for valid + values. + """ + if not validator.is_valid_lineweight(lineweight): + raise const.DXFValueError(f'invalid lineweight value: "{lineweight}"') + doc.header[CURRENT_LINEWEIGHT] = lineweight + + +def set_current_linetype_scale(doc: Drawing, scale: float): + """Set current linetype scale.""" + if scale <= 0.0: + raise const.DXFValueError(f'invalid linetype scale: "{scale}"') + doc.header[CURRENT_LINETYPE_SCALE] = scale + + +def set_current_textstyle(doc: Drawing, name: str): + """Set current text style.""" + if name not in doc.styles: + raise const.DXFValueError(f'undefined textstyle: "{name}"') + doc.header[CURRENT_TEXTSTYLE] = name + + +def set_current_dimstyle(doc: Drawing, name: str): + """Set current dimstyle.""" + if name not in doc.dimstyles: + raise const.DXFValueError(f'undefined dimstyle: "{name}"') + doc.header[CURRENT_DIMSTYLE] = name + + +def set_current_dimstyle_attribs(doc: Drawing, name: str): + """Set current dimstyle and copy all dimstyle attributes to the HEADER section.""" + set_current_dimstyle(doc, name) + dimstyle = doc.dimstyles.get(name) + dimstyle.copy_to_header(doc) + + +def restore_wcs(doc: Drawing): + """Restore the UCS settings in the HEADER section to the :ref:`WCS` and + reset all active viewports to the WCS. + """ + doc.header.reset_wcs() + for vport in doc.viewports.get_config("*Active"): + vport.reset_wcs() + + +def update_extents(doc: Drawing) -> BoundingBox: + """Calculate the extents of the model space, update the HEADER variables + $EXTMIN and $EXTMAX and returns the result as :class:`ezdxf.math.BoundingBox`. + Note that this function uses the :mod:`ezdxf.bbox` module to calculate the + extent of the model space. This module is not very fast and not very + accurate for text and ignores all :term:`ACIS` based entities. + + The function updates only the values in the HEADER section, to zoom the + active viewport to this extents, use this recipe:: + + import ezdxf + from ezdxf import zoom, appsettings + + doc = ezdxf.readfile("your.dxf") + extents = appsettings.update_extents(doc) + zoom.center(doc.modelspace(), extents.center, extents.size) + + .. seealso:: + + - the :mod:`ezdxf.bbox` module to understand the limitations of the + extent calculation + - the :mod:`ezdxf.zoom` module + + """ + msp = doc.modelspace() + extents = bbox.extents(msp, fast=True) + if extents.has_data: + msp.dxf.extmin = extents.extmin + msp.dxf.extmax = extents.extmax + doc.header[EXTMIN] = extents.extmin + doc.header[EXTMAX] = extents.extmax + return extents + + +def show_lineweight(doc: Drawing, state=True) -> None: + """The CAD application or DXF viewer should show lines and curves with + "thickness" (lineweight) if `state` is ``True``. + """ + doc.header["$LWDISPLAY"] = int(state) + + +def set_lineweight_display_style( + doc: Drawing, end_caps: EndCaps, join_style: JoinStyle +) -> None: + """Set the style of end caps and joints for linear entities when displaying + line weights. These settings only affect objects created afterwards. + """ + doc.header["$ENDCAPS"] = int(end_caps) + doc.header["$JOINSTYLE"] = int(join_style) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/audit.py b/.venv/lib/python3.12/site-packages/ezdxf/audit.py new file mode 100644 index 0000000..baf679b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/audit.py @@ -0,0 +1,545 @@ +# Copyright (c) 2017-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + TextIO, + Any, + Optional, + Callable, +) +import sys +from enum import IntEnum +from ezdxf.lldxf import const, validator +from ezdxf.entities import factory, DXFEntity +from ezdxf.math import NULLVEC + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFGraphic + from ezdxf.sections.blocks import BlocksSection + + +__all__ = ["Auditor", "AuditError", "audit", "BlockCycleDetector"] + + +class AuditError(IntEnum): + # DXF structure errors: + MISSING_REQUIRED_ROOT_DICT_ENTRY = 1 + DUPLICATE_TABLE_ENTRY_NAME = 2 + POINTER_TARGET_NOT_EXIST = 3 + TABLE_NOT_FOUND = 4 + MISSING_SECTION_TAG = 5 + MISSING_SECTION_NAME_TAG = 6 + MISSING_ENDSEC_TAG = 7 + FOUND_TAG_OUTSIDE_SECTION = 8 + REMOVED_UNSUPPORTED_SECTION = 9 + REMOVED_UNSUPPORTED_TABLE = 10 + REMOVED_INVALID_GRAPHIC_ENTITY = 11 + REMOVED_INVALID_DXF_OBJECT = 12 + REMOVED_STANDALONE_ATTRIB_ENTITY = 13 + MISPLACED_ROOT_DICT = 14 + ROOT_DICT_NOT_FOUND = 15 + REMOVED_ENTITY_WITH_INVALID_OWNER_HANDLE = 16 + + UNDEFINED_LINETYPE = 100 + UNDEFINED_DIMENSION_STYLE = 101 + UNDEFINED_TEXT_STYLE = 102 + UNDEFINED_BLOCK = 103 + INVALID_BLOCK_REFERENCE_CYCLE = 104 + REMOVE_EMPTY_GROUP = 105 + GROUP_ENTITIES_IN_DIFFERENT_LAYOUTS = 106 + MISSING_REQUIRED_SEQEND = 107 + ORPHANED_LAYOUT_ENTITY = 108 + ORPHANED_PAPER_SPACE_BLOCK_RECORD_ENTITY = 109 + INVALID_TABLE_HANDLE = 110 + DECODING_ERROR = 111 + CREATED_MISSING_OBJECT = 112 + RESET_MLINE_STYLE = 113 + INVALID_GROUP_ENTITIES = 114 + UNDEFINED_BLOCK_NAME = 115 + INVALID_INTEGER_VALUE = 116 + INVALID_FLOATING_POINT_VALUE = 117 + MISSING_PERSISTENT_REACTOR = 118 + BLOCK_NAME_MISMATCH = 119 + + # DXF entity property errors: + INVALID_ENTITY_HANDLE = 201 + INVALID_OWNER_HANDLE = 202 + INVALID_LAYER_NAME = 203 + INVALID_COLOR_INDEX = 204 + INVALID_LINEWEIGHT = 205 + INVALID_MLINESTYLE_HANDLE = 206 + INVALID_DIMSTYLE = 207 + + # DXF entity geometry or content errors: + INVALID_EXTRUSION_VECTOR = 210 + INVALID_MAJOR_AXIS = 211 + INVALID_VERTEX_COUNT = 212 + INVALID_DICTIONARY_ENTRY = 213 + INVALID_CHARACTER = 214 + INVALID_MLINE_VERTEX = 215 + INVALID_MLINESTYLE_ELEMENT_COUNT = 216 + INVALID_SPLINE_DEFINITION = 217 + INVALID_SPLINE_CONTROL_POINT_COUNT = 218 + INVALID_SPLINE_FIT_POINT_COUNT = 219 + INVALID_SPLINE_KNOT_VALUE_COUNT = 220 + INVALID_SPLINE_WEIGHT_COUNT = 221 + INVALID_DIMENSION_GEOMETRY_LOCATION = 222 + INVALID_TRANSPARENCY = 223 + INVALID_CREASE_VALUE_COUNT = 224 + INVALID_ELLIPSE_RATIO = 225 + INVALID_HATCH_BOUNDARY_PATH = 226 + + +REQUIRED_ROOT_DICT_ENTRIES = ("ACAD_GROUP", "ACAD_PLOTSTYLENAME") + + +class ErrorEntry: + def __init__( + self, + code: int, + message: str = "", + dxf_entity: Optional[DXFEntity] = None, + data: Any = None, + ): + self.code: int = code # error code AuditError() + self.entity: Optional[DXFEntity] = dxf_entity # source entity of error + self.message: str = message # error message + self.data: Any = data # additional data as an arbitrary object + +# pylint: disable=too-many-public-methods +class Auditor: + def __init__(self, doc: Drawing) -> None: + assert doc is not None and doc.rootdict is not None and doc.entitydb is not None + self.doc = doc + self._rootdict_handle = doc.rootdict.dxf.handle + self.errors: list[ErrorEntry] = [] + self.fixes: list[ErrorEntry] = [] + self._trashcan = doc.entitydb.new_trashcan() + self._post_audit_jobs: list[Callable[[], None]] = [] + + def reset(self) -> None: + self.errors.clear() + self.fixes.clear() + self.empty_trashcan() + + def __len__(self) -> int: + """Returns count of unfixed errors.""" + return len(self.errors) + + def __bool__(self) -> bool: + """Returns ``True`` if any unfixed errors exist.""" + return self.__len__() > 0 + + def __iter__(self) -> Iterable[ErrorEntry]: + """Iterate over all unfixed errors.""" + return iter(self.errors) + + @property + def entitydb(self): + if self.doc: + return self.doc.entitydb + else: + return None + + @property + def has_errors(self) -> bool: + """Returns ``True`` if any unrecoverable errors were detected.""" + return bool(self.errors) + + @property + def has_fixes(self) -> bool: + """Returns ``True`` if any recoverable errors were fixed while auditing.""" + return bool(self.fixes) + + @property + def has_issues(self) -> bool: + """Returns ``True`` if the DXF document has any errors or fixes.""" + return self.has_fixes or self.has_errors + + def print_error_report( + self, + errors: Optional[list[ErrorEntry]] = None, + stream: Optional[TextIO] = None, + ) -> None: + def entity_str(count, code, entity): + if entity is not None and entity.is_alive: + return f"{count:4d}. Error [{code}] in {str(entity)}." + else: + return f"{count:4d}. Error [{code}]." + + if errors is None: + errors = self.errors + else: + errors = list(errors) + + if stream is None: + stream = sys.stdout + + if len(errors) == 0: + stream.write("No unrecoverable errors found.\n\n") + else: + stream.write(f"{len(errors)} errors found.\n\n") + for count, error in enumerate(errors): + stream.write(entity_str(count + 1, error.code, error.entity) + "\n") + stream.write(" " + error.message + "\n\n") + + def print_fixed_errors(self, stream: Optional[TextIO] = None) -> None: + def entity_str(count, code, entity): + if entity is not None and entity.is_alive: + return f"{count:4d}. Issue [{code}] fixed in {str(entity)}." + else: + return f"{count:4d}. Issue [{code}] fixed." + + if stream is None: + stream = sys.stdout + + if len(self.fixes) == 0: + stream.write("No issues fixed.\n\n") + else: + stream.write(f"{len(self.fixes)} issues fixed.\n\n") + for count, error in enumerate(self.fixes): + stream.write(entity_str(count + 1, error.code, error.entity) + "\n") + stream.write(" " + error.message + "\n\n") + + def add_error( + self, + code: int, + message: str = "", + dxf_entity: Optional[DXFEntity] = None, + data: Any = None, + ) -> None: + self.errors.append(ErrorEntry(code, message, dxf_entity, data)) + + def fixed_error( + self, + code: int, + message: str = "", + dxf_entity: Optional[DXFEntity] = None, + data: Any = None, + ) -> None: + self.fixes.append(ErrorEntry(code, message, dxf_entity, data)) + + def purge(self, codes: set[int]): + """Remove error messages defined by integer error `codes`. + + This is useful to remove errors which are not important for a specific + file usage. + + """ + self.errors = [err for err in self.errors if err.code in codes] + + def run(self) -> list[ErrorEntry]: + if not self.check_root_dict(): + # no root dict found: abort audit process + return self.errors + self.doc.entitydb.audit(self) + self.check_root_dict_entries() + self.check_tables() + self.doc.objects.audit(self) + self.doc.blocks.audit(self) + self.doc.groups.audit(self) + self.doc.layouts.audit(self) + self.audit_all_database_entities() + self.check_block_reference_cycles() + self.empty_trashcan() + self.doc.objects.purge() + return self.errors + + def empty_trashcan(self): + if self.has_trashcan: + self._trashcan.clear() + + def trash(self, entity: DXFEntity) -> None: + if entity is None or not entity.is_alive: + return + if self.has_trashcan and entity.dxf.handle is not None: + self._trashcan.add(entity.dxf.handle) + else: + entity.destroy() + + @property + def has_trashcan(self) -> bool: + return self._trashcan is not None + + def add_post_audit_job(self, job: Callable): + self._post_audit_jobs.append(job) + + def check_root_dict(self) -> bool: + rootdict = self.doc.rootdict + if rootdict.dxftype() != "DICTIONARY": + self.add_error( + AuditError.ROOT_DICT_NOT_FOUND, + f"Critical error - first object in OBJECTS section is not the expected " + f"root dictionary, found {str(rootdict)}.", + ) + return False + if rootdict.dxf.get("owner") != "0": + rootdict.dxf.owner = "0" + self.fixed_error( + code=AuditError.INVALID_OWNER_HANDLE, + message=f"Fixed invalid owner handle in root {str(rootdict)}.", + ) + return True + + def check_root_dict_entries(self) -> None: + rootdict = self.doc.rootdict + if rootdict.dxftype() != "DICTIONARY": + return + for name in REQUIRED_ROOT_DICT_ENTRIES: + if name not in rootdict: + self.add_error( + code=AuditError.MISSING_REQUIRED_ROOT_DICT_ENTRY, + message=f"Missing rootdict entry: {name}", + dxf_entity=rootdict, + ) + + def check_tables(self) -> None: + table_section = self.doc.tables + table_section.viewports.audit(self) + table_section.linetypes.audit(self) + table_section.layers.audit(self) + table_section.styles.audit(self) + table_section.views.audit(self) + table_section.ucs.audit(self) + table_section.appids.audit(self) + table_section.dimstyles.audit(self) + table_section.block_records.audit(self) + + def audit_all_database_entities(self) -> None: + """Audit all entities stored in the entity database.""" + # Destruction of entities can occur while auditing. + # Best practice to delete entities is to move them into the trashcan: + # Auditor.trash(entity) + db = self.doc.entitydb + db.locked = True + # To create new entities while auditing, add a post audit job by calling + # Auditor.app_post_audit_job() with a callable object or function as argument. + self._post_audit_jobs = [] + for entity in db.values(): + if entity.is_alive: + entity.audit(self) + db.locked = False + self.empty_trashcan() + self.exec_post_audit_jobs() + + def exec_post_audit_jobs(self): + for call in self._post_audit_jobs: + call() + self._post_audit_jobs = [] + + def check_entity_linetype(self, entity: DXFEntity) -> None: + """Check for usage of undefined line types. AutoCAD does not load + DXF files with undefined line types. + """ + assert self.doc is entity.doc, "Entity from different DXF document." + if not entity.dxf.hasattr("linetype"): + return + linetype = validator.make_table_key(entity.dxf.linetype) + # No table entry in linetypes required: + if linetype in ("bylayer", "byblock"): + return + + if linetype not in self.doc.linetypes: + # Defaults to 'BYLAYER' + entity.dxf.discard("linetype") + self.fixed_error( + code=AuditError.UNDEFINED_LINETYPE, + message=f"Removed undefined linetype {linetype} in {str(entity)}", + dxf_entity=entity, + data=linetype, + ) + + def check_text_style(self, entity: DXFEntity) -> None: + """Check for usage of undefined text styles.""" + assert self.doc is entity.doc, "Entity from different DXF document." + if not entity.dxf.hasattr("style"): + return + style = entity.dxf.style + if style not in self.doc.styles: + # Defaults to 'Standard' + entity.dxf.discard("style") + self.fixed_error( + code=AuditError.UNDEFINED_TEXT_STYLE, + message=f'Removed undefined text style "{style}" from {str(entity)}.', + dxf_entity=entity, + data=style, + ) + + def check_dimension_style(self, entity: DXFGraphic) -> None: + """Check for usage of undefined dimension styles.""" + assert self.doc is entity.doc, "Entity from different DXF document." + if not entity.dxf.hasattr("dimstyle"): + return + dimstyle = entity.dxf.dimstyle + if dimstyle not in self.doc.dimstyles: + # The dimstyle attribute is not optional: + entity.dxf.dimstyle = "Standard" + self.fixed_error( + code=AuditError.UNDEFINED_DIMENSION_STYLE, + message=f'Replaced undefined dimstyle "{dimstyle}" in ' + f'{str(entity)} by "Standard".', + dxf_entity=entity, + data=dimstyle, + ) + + def check_for_valid_layer_name(self, entity: DXFEntity) -> None: + """Check layer names for invalid characters: <>/\":;?*|='""" + name = entity.dxf.layer + if not validator.is_valid_layer_name(name): + # This error can't be fixed !? + self.add_error( + code=AuditError.INVALID_LAYER_NAME, + message=f'Invalid layer name "{name}" in {str(entity)}', + dxf_entity=entity, + data=name, + ) + + def check_entity_color_index(self, entity: DXFGraphic) -> None: + color = entity.dxf.color + # 0 == BYBLOCK + # 256 == BYLAYER + # 257 == BYOBJECT + if color < 0 or color > 257: + entity.dxf.discard("color") + self.fixed_error( + code=AuditError.INVALID_COLOR_INDEX, + message=f"Removed invalid color index of {str(entity)}.", + dxf_entity=entity, + data=color, + ) + + def check_entity_lineweight(self, entity: DXFGraphic) -> None: + weight = entity.dxf.lineweight + if weight not in const.VALID_DXF_LINEWEIGHT_VALUES: + entity.dxf.lineweight = validator.fix_lineweight(weight) + self.fixed_error( + code=AuditError.INVALID_LINEWEIGHT, + message=f"Fixed invalid lineweight of {str(entity)}.", + dxf_entity=entity, + ) + + def check_owner_exist(self, entity: DXFEntity) -> None: + assert self.doc is entity.doc, "Entity from different DXF document." + if not entity.dxf.hasattr("owner"): # important for recover mode + return + doc = self.doc + owner_handle = entity.dxf.owner + handle = entity.dxf.get("handle", "0") + if owner_handle == "0": + # Root-Dictionary or Table-Head: + if handle == self._rootdict_handle or entity.dxftype() == "TABLE": + return # '0' handle as owner is valid + if owner_handle not in doc.entitydb: + if handle == self._rootdict_handle: + entity.dxf.owner = "0" + self.fixed_error( + code=AuditError.INVALID_OWNER_HANDLE, + message=f"Fixed invalid owner handle in root {str(entity)}.", + ) + elif entity.dxftype() == "TABLE": + name = entity.dxf.get("name", "UNKNOWN") + entity.dxf.owner = "0" + self.fixed_error( + code=AuditError.INVALID_OWNER_HANDLE, + message=f"Fixed invalid owner handle for {name} table.", + ) + else: + self.fixed_error( + code=AuditError.INVALID_OWNER_HANDLE, + message=f"Deleted {str(entity)} entity with invalid owner " + f"handle #{owner_handle}.", + ) + self.trash(doc.entitydb.get(handle)) # type: ignore + + def check_extrusion_vector(self, entity: DXFEntity) -> None: + if NULLVEC.isclose(entity.dxf.extrusion): + entity.dxf.discard("extrusion") + self.fixed_error( + code=AuditError.INVALID_EXTRUSION_VECTOR, + message=f"Fixed extrusion vector for entity: {str(entity)}.", + dxf_entity=entity, + ) + + def check_transparency(self, entity: DXFEntity) -> None: + value = entity.dxf.transparency + if value is None: + return + if not validator.is_transparency(value): + entity.dxf.discard("transparency") + self.fixed_error( + code=AuditError.INVALID_TRANSPARENCY, + message=f"Fixed invalid transparency for entity: {str(entity)}.", + dxf_entity=entity, + ) + + def check_block_reference_cycles(self) -> None: + cycle_detector = BlockCycleDetector(self.doc) + for block in self.doc.blocks: + if cycle_detector.has_cycle(block.name): + self.add_error( + code=AuditError.INVALID_BLOCK_REFERENCE_CYCLE, + message=f"Invalid block reference cycle detected in " + f'block "{block.name}".', + dxf_entity=block.block_record, + ) + + +class BlockCycleDetector: + def __init__(self, doc: Drawing): + self.key = doc.blocks.key + self.blocks = self._build_block_ledger(doc.blocks) + + def _build_block_ledger(self, blocks: BlocksSection) -> dict[str, set[str]]: + ledger = {} + for block in blocks: + inserts = { + self.key(insert.dxf.get("name", "")) for insert in block.query("INSERT") + } + ledger[self.key(block.name)] = inserts + return ledger + + def has_cycle(self, block_name: str) -> bool: + def check(name): + # block 'name' does not exist: ignore this error, because it is not + # the task of this method to detect not existing block definitions + try: + inserts = self.blocks[name] + except KeyError: + return False # Not existing blocks can't create cycles. + path.append(name) + for n in inserts: + if n in path: + return True + elif check(n): + return True + path.pop() + return False + + path: list[str] = [] + block_name = self.key(block_name) + return check(block_name) + + +def audit(entity: DXFEntity, doc: Drawing) -> Auditor: + """Setup an :class:`Auditor` object, run the audit process for `entity` + and return result as :class:`Auditor` object. + + Args: + entity: DXF entity to validate + doc: bounded DXF document of `entity` + + """ + if not entity.is_alive: + raise TypeError("Entity is destroyed.") + + # Validation of unbound entities is possible, but it is not useful + # to validate entities against a different DXF document: + if entity.dxf.handle is not None and not factory.is_bound(entity, doc): + raise ValueError("Entity is bound to different DXF document.") + + auditor = Auditor(doc) + entity.audit(auditor) + return auditor diff --git a/.venv/lib/python3.12/site-packages/ezdxf/bbox.py b/.venv/lib/python3.12/site-packages/ezdxf/bbox.py new file mode 100644 index 0000000..1a7c560 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/bbox.py @@ -0,0 +1,175 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional + +import ezdxf +from ezdxf import disassemble +from ezdxf.math import BoundingBox + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + +MAX_FLATTENING_DISTANCE = disassemble.Primitive.max_flattening_distance + + +class Cache: + """Caching object for :class:`ezdxf.math.BoundingBox` objects. + + Args: + uuid: use UUIDs for virtual entities + + """ + + def __init__(self, uuid=False) -> None: + self._boxes: dict[str, BoundingBox] = dict() + self._use_uuid = bool(uuid) + self.hits: int = 0 + self.misses: int = 0 + + @property + def has_data(self) -> bool: + return bool(self._boxes) + + def __str__(self): + return ( + f"Cache(n={len(self._boxes)}, " + f"hits={self.hits}, " + f"misses={self.misses})" + ) + + def get(self, entity: DXFEntity) -> Optional[BoundingBox]: + assert entity is not None + key = self._get_key(entity) + if key is None: + self.misses += 1 + return None + box = self._boxes.get(key) + if box is None: + self.misses += 1 + else: + self.hits += 1 + return box + + def store(self, entity: DXFEntity, box: BoundingBox) -> None: + assert entity is not None + key = self._get_key(entity) + if key is None: + return + self._boxes[key] = box + + def invalidate(self, entities: Iterable[DXFEntity]) -> None: + """Invalidate cache entries for the given DXF `entities`. + + If entities are changed by the user, it is possible to invalidate + individual entities. Use with care - discarding the whole cache is + the safer workflow. + + Ignores entities which are not stored in cache. + + """ + for entity in entities: + try: + del self._boxes[self._get_key(entity)] # type: ignore + except KeyError: + pass + + def _get_key(self, entity: DXFEntity) -> Optional[str]: + if entity.dxftype() == "HATCH": + # Special treatment for multiple primitives for the same + # HATCH entity - all have the same handle: + # Do not store boundary path they are not distinguishable, + # which boundary path should be returned for the handle? + return None + + key = entity.dxf.handle + if key is None or key == "0": + return str(entity.uuid) if self._use_uuid else None + else: + return key + + +def multi_recursive( + entities: Iterable[DXFEntity], + *, + fast=False, + cache: Optional[Cache] = None, +) -> Iterable[BoundingBox]: + """Yields all bounding boxes for the given `entities` **or** all bounding + boxes for their sub entities. If an entity (INSERT) has sub entities, only + the bounding boxes of these sub entities will be yielded, **not** the + bounding box of the entity (INSERT) itself. + + If argument `fast` is ``True`` the calculation of Bézier curves is based on + their control points, this may return a slightly larger bounding box. + + """ + flat_entities = disassemble.recursive_decompose(entities) + primitives = disassemble.to_primitives(flat_entities) + for primitive in primitives: + if primitive.is_empty: + continue + + entity = primitive.entity + if cache is not None: + box = cache.get(entity) + if box is None: + box = primitive.bbox(fast=fast) + if box.has_data: + cache.store(entity, box) + else: + box = primitive.bbox(fast=fast) + + if box.has_data: + yield box + + +def extents( + entities: Iterable[DXFEntity], + *, + fast=False, + cache: Optional[Cache] = None, +) -> BoundingBox: + """Returns a single bounding box for all given `entities`. + + If argument `fast` is ``True`` the calculation of Bézier curves is based on + their control points, this may return a slightly larger bounding box. + + """ + _extends = BoundingBox() + for box in multi_flat(entities, fast=fast, cache=cache): + _extends.extend(box) + return _extends + + +def multi_flat( + entities: Iterable[DXFEntity], + *, + fast=False, + cache: Optional[Cache] = None, +) -> Iterable[BoundingBox]: + """Yields a bounding box for each of the given `entities`. + + If argument `fast` is ``True`` the calculation of Bézier curves is based on + their control points, this may return a slightly larger bounding box. + + """ + + def extends_(entities_: Iterable[DXFEntity]) -> BoundingBox: + _extends = BoundingBox() + for _box in multi_recursive(entities_, fast=fast, cache=cache): + _extends.extend(_box) + return _extends + + for entity in entities: + box = None + if cache: + box = cache.get(entity) + + if box is None: + box = extends_([entity]) + if cache: + cache.store(entity, box) + + if box.has_data: + yield box diff --git a/.venv/lib/python3.12/site-packages/ezdxf/blkrefs.py b/.venv/lib/python3.12/site-packages/ezdxf/blkrefs.py new file mode 100644 index 0000000..b5ef0e2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/blkrefs.py @@ -0,0 +1,209 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, Iterator +from collections import Counter + +from ezdxf.lldxf.types import POINTER_CODES +from ezdxf.protocols import referenced_blocks + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tags import Tags + from ezdxf.entities import DXFEntity, BlockRecord + +__all__ = ["BlockDefinitionIndex", "BlockReferenceCounter"] + +""" +Where are block references located: + +- HEADER SECTION: $DIMBLK, $DIMBLK1, $DIMBLK2, $DIMLDRBLK +- DIMENSION: arrows referenced in the associated anonymous BLOCK, covered by + the INSERT entities in that BLOCK +- ACAD_TABLE: has an anonymous BLOCK representation, covered by the + INSERT entities in that BLOCK +- LEADER: DIMSTYLE override "dimldrblk" is stored as handle in XDATA + +Entity specific block references, returned by the "ReferencedBlocks" protocol: +- INSERT: "name" +- DIMSTYLE: "dimblk", "dimblk1", "dimblk2", "dimldrblk" +- MLEADER: arrows, blocks - has no anonymous BLOCK representation +- MLEADERSTYLE: arrows +- DIMENSION: "geometry", the associated anonymous BLOCK +- ACAD_TABLE: currently managed as generic DXFTagStorage, that should return + the group code 343 "block_record" + +Possible unknown or undocumented block references: +- DXFTagStorage - all handle group codes +- XDATA - only group code 1005 +- APPDATA - all handle group codes +- XRECORD - all handle group codes + +Contains no block references as far as known: +- DICTIONARY: can only references DXF objects like XRECORD or DICTIONARYVAR +- Extension Dictionary is a DICTIONARY object +- REACTORS - used for object messaging, a reactor does not establish + a block reference + +Block references are stored as handles to the BLOCK_RECORD entity! + +Testing DXF documents with missing BLOCK definitions: + +- INSERT without an existing BLOCK definition does NOT crash AutoCAD/BricsCAD +- HEADER variables $DIMBLK, $DIMBLK2, $DIMBLK2 and $DIMLDRBLK can reference + non existing blocks without crashing AutoCAD/BricsCAD + +""" + + +class BlockDefinitionIndex: + """Index of all :class:`~ezdxf.entities.BlockRecord` entities representing + real BLOCK definitions, excluding all :class:`~ezdxf.entities.BlockRecord` + entities defining model space or paper space layouts. External references + (XREF) and XREF overlays are included. + + """ + def __init__(self, doc: Drawing): + self._doc = doc + # mapping: handle -> BlockRecord entity + self._handle_index: dict[str, BlockRecord] = dict() + # mapping: block name -> BlockRecord entity + self._name_index: dict[str, BlockRecord] = dict() + self.rebuild() + + @property + def block_records(self) -> Iterator[BlockRecord]: + """Returns an iterator of all :class:`~ezdxf.entities.BlockRecord` + entities representing BLOCK definitions. + """ + return iter(self._doc.tables.block_records) + + def rebuild(self): + """Rebuild index from scratch.""" + handle_index = self._handle_index + name_index = self._name_index + handle_index.clear() + name_index.clear() + for block_record in self.block_records: + if block_record.is_block_layout: + handle_index[block_record.dxf.handle] = block_record + name_index[block_record.dxf.name] = block_record + + def has_handle(self, handle: str) -> bool: + """Returns ``True`` if a :class:`~ezdxf.entities.BlockRecord` for the + given block record handle exist. + """ + return handle in self._handle_index + + def has_name(self, name: str) -> bool: + """Returns ``True`` if a :class:`~ezdxf.entities.BlockRecord` for the + given block name exist. + """ + return name in self._name_index + + def by_handle(self, handle: str) -> Optional[BlockRecord]: + """Returns the :class:`~ezdxf.entities.BlockRecord` for the given block + record handle or ``None``. + """ + return self._handle_index.get(handle) + + def by_name(self, name: str) -> Optional[BlockRecord]: + """Returns :class:`~ezdxf.entities.BlockRecord` for the given block name + or ``None``. + """ + return self._name_index.get(name) + + +class BlockReferenceCounter: + """ + Counts all block references in a DXF document. + + Check if a block is referenced by any entity or any resource (DIMSYTLE, + MLEADERSTYLE) in a DXF document:: + + import ezdxf + from ezdxf.blkrefs import BlockReferenceCounter + + doc = ezdxf.readfile("your.dxf") + counter = BlockReferenceCounter(doc) + count = counter.by_name("XYZ") + print(f"Block 'XYZ' if referenced {count} times.") + + """ + + def __init__(self, doc: Drawing, index: Optional[BlockDefinitionIndex] = None): + # mapping: handle -> BlockRecord entity + self._block_record_index = ( + index if index is not None else BlockDefinitionIndex(doc) + ) + + # mapping: handle -> reference count + self._counter = count_references( + doc.entitydb.values(), self._block_record_index + ) + self._counter.update(header_section_handles(doc)) + + def by_handle(self, handle: str) -> int: + """Returns the block reference count for a given + :class:`~ezdxf.entities.BlockRecord` handle. + """ + return self._counter[handle] + + def by_name(self, block_name: str) -> int: + """Returns the block reference count for a given block name.""" + handle = "" + block_record = self._block_record_index.by_name(block_name) + if block_record is not None: + handle = block_record.dxf.handle + return self._counter[handle] + + +def count_references( + entities: Iterable[DXFEntity], index: BlockDefinitionIndex +) -> Counter: + from ezdxf.entities import XRecord, DXFTagStorage + + def update(handles: Iterable[str]): + # only count references to existing blocks: + counter.update(h for h in handles if index.has_handle(h)) + + counter: Counter = Counter() + for entity in entities: + # add handles stored in XDATA and APP data + update(generic_handles(entity)) + # add entity specific block references + update(referenced_blocks(entity)) + # special entity types storing arbitrary raw DXF tags: + if isinstance(entity, XRecord): + update(all_pointer_handles(entity.tags)) + elif isinstance(entity, DXFTagStorage): + # XDATA and APP data is already done! + for tags in entity.xtags.subclasses[1:]: + update(all_pointer_handles(tags)) + # ignore embedded objects: special objects for MTEXT and ATTRIB + return counter + + +def generic_handles(entity: DXFEntity) -> Iterable[str]: + handles: list[str] = [] + if entity.xdata is not None: + for tags in entity.xdata.data.values(): + handles.extend(value for code, value in tags if code == 1005) + if entity.appdata is not None: + for tags in entity.appdata.data.values(): + handles.extend(all_pointer_handles(tags)) + return handles + + +def all_pointer_handles(tags: Tags) -> Iterable[str]: + return (value for code, value in tags if code in POINTER_CODES) + + +def header_section_handles(doc: "Drawing") -> Iterable[str]: + header = doc.header + for var_name in ("$DIMBLK", "$DIMBLK1", "$DIMBLK2", "$DIMLDRBLK"): + blk_name = header.get(var_name, None) + if blk_name is not None: + block = doc.blocks.get(blk_name, None) + if block is not None: + yield block.block_record.dxf.handle diff --git a/.venv/lib/python3.12/site-packages/ezdxf/colors.py b/.venv/lib/python3.12/site-packages/ezdxf/colors.py new file mode 100644 index 0000000..146a843 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/colors.py @@ -0,0 +1,804 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, NamedTuple, Sequence +from typing_extensions import Self +import math + + +class RGB(NamedTuple): + """Named tuple representing an RGB color value. + + Attributes: + r: red channel in range [0, 255] + g: green channel in range [0, 255] + b: blue channel in range [0, 255] + """ + + r: int + g: int + b: int + + def to_floats(self) -> tuple[float, float, float]: + """Returns the color value as a tuple of floats in range [0, 1].""" + return self.r / 255, self.g / 255, self.b / 255 + + @classmethod + def from_floats(cls, rgb: tuple[float, float, float]) -> Self: + """Returns an :class:`RGB` instance from floats in range [0, 1].""" + r = max(min(255, round(rgb[0] * 255)), 0) + g = max(min(255, round(rgb[1] * 255)), 0) + b = max(min(255, round(rgb[2] * 255)), 0) + return cls(r, g, b) + + def to_hex(self) -> str: + """Returns the color value as hex string "#RRGGBB".""" + return f"#{self.r:02x}{self.g:02x}{self.b:02x}" + + @classmethod + def from_hex(cls, color: str) -> Self: + """Returns an :class:`RGB` instance from a hex color string, the `color` string + is a hex string "RRGGBB" with an optional leading "#", an appended alpha + channel is ignore. + """ + hex_string = color.lstrip("#") + r = int(hex_string[0:2], 16) + g = int(hex_string[2:4], 16) + b = int(hex_string[4:6], 16) + return cls(r, g, b) + + @property + def luminance(self) -> float: + """Returns perceived luminance for an RGB color in range [0.0, 1.0] + from dark to light. + """ + return luminance(self) + + +class RGBA(NamedTuple): + """Named tuple representing an RGBA color value. + The default alpha channel is 255 (opaque). + + Attributes: + r: red channel in range [0, 255] + g: green channel in range [0, 255] + b: blue channel in range [0, 255] + a: alpha channel in range [0, 255], where 0 is transparent and 255 is opaque + """ + + r: int + g: int + b: int + a: int = 255 # default alpha channel is opaque + + def to_floats(self) -> tuple[float, float, float, float]: + """Returns the color value as a tuple of floats in range [0, 1].""" + return self.r / 255, self.g / 255, self.b / 255, self.a / 255 + + @classmethod + def from_floats(cls, values: Sequence[float]) -> Self: + """Returns an :class:`RGBA` instance from floats in range [0, 1]. + + The alpha channel is optional. + The default alpha channel is 255 (opaque). + """ + r = max(min(255, round(values[0] * 255)), 0) + g = max(min(255, round(values[1] * 255)), 0) + b = max(min(255, round(values[2] * 255)), 0) + try: + a = max(min(255, round(values[3] * 255)), 0) + except IndexError: + a = 255 # default to opaque == RGB(r, g, b) + return cls(r, g, b, a) + + def to_hex(self) -> str: + """Returns the color value as hex string "#RRGGBBAA".""" + return f"#{self.r:02x}{self.g:02x}{self.b:02x}{self.a:02x}" + + @classmethod + def from_hex(cls, color: str) -> Self: + """Returns an :class:`RGBA` instance from a hex color string, the `color` string + is a hex string "RRGGBBAA" with an optional leading "#". + The alpha channel is optional. + The default alpha channel is 255 (opaque). + """ + hex_string = color.lstrip("#") + r = int(hex_string[0:2], 16) + g = int(hex_string[2:4], 16) + b = int(hex_string[4:6], 16) + a = 255 + if len(hex_string) > 6: + a = int(hex_string[6:8], 16) + return cls(r, g, b, a) + + @property + def luminance(self) -> float: + """Returns perceived luminance for an RGB color in range [0.0, 1.0] + from dark to light. + """ + return luminance(self) + + +BYBLOCK = 0 +BYLAYER = 256 +BYOBJECT = 257 +RED = 1 +YELLOW = 2 +GREEN = 3 +CYAN = 4 +BLUE = 5 +MAGENTA = 6 +BLACK = 7 +WHITE = 7 +GRAY = 8 +LIGHT_GRAY = 9 + +# Flags for raw color int values: +# Take color from layer, ignore other bytes. +COLOR_TYPE_BY_LAYER = 0xC0 +# Take color from insertion, ignore other bytes +COLOR_TYPE_BY_BLOCK = 0xC1 +# RGB value, other bytes are R,G,B. +COLOR_TYPE_RGB = 0xC2 +# ACI, AutoCAD color index, other bytes are 0,0,index ??? +COLOR_TYPE_ACI = 0xC3 + +# Found in MLEADER text background color (group code 91) = -939524096 +# guess: use window background color +COLOR_TYPE_WINDOW_BG = 0xC8 + + +def decode_raw_color(value: int) -> tuple[int, Union[int, RGB]]: + """Decode :term:`raw-color` value as tuple(type, Union[aci, (r, g, b)]), the + true color value is a (r, g, b) tuple. + """ + data = decode_raw_color_int(value) + if data[0] == COLOR_TYPE_RGB: + return COLOR_TYPE_RGB, int2rgb(data[1]) + return data + + +def decode_raw_color_int(value: int) -> tuple[int, int]: + """Decode :term:`raw-color` value as tuple(type, int), the true color value + is a 24-bit int value. + """ + flags = (value >> 24) & 0xFF + if flags == COLOR_TYPE_BY_BLOCK: + return COLOR_TYPE_BY_BLOCK, BYBLOCK + elif flags == COLOR_TYPE_BY_LAYER: + return COLOR_TYPE_BY_LAYER, BYLAYER + elif flags == COLOR_TYPE_ACI: + return COLOR_TYPE_ACI, value & 0xFF + elif flags == COLOR_TYPE_RGB: + return COLOR_TYPE_RGB, value & 0xFFFFFF + elif flags == COLOR_TYPE_WINDOW_BG: + return COLOR_TYPE_WINDOW_BG, 0 + else: + raise ValueError(f"Unknown color type: 0x{flags:02x}") + + +BY_LAYER_RAW_VALUE = -1073741824 # -(-(0xc0 << 24) & 0xffffffff) +BY_BLOCK_RAW_VALUE = -1056964608 # -(-(0xc1 << 24) & 0xffffffff) +WINDOW_BG_RAW_VALUE = -939524096 + + +def encode_raw_color(value: Union[int, RGB]) -> int: + """Encode :term:`true-color` value or :ref:`ACI` color value into a :term: + `raw color` value. + """ + if isinstance(value, int): + if value == BYBLOCK: + return BY_BLOCK_RAW_VALUE + elif value == BYLAYER: + return BY_LAYER_RAW_VALUE + elif 0 < value < 256: + return -(-(COLOR_TYPE_ACI << 24) & 0xFFFFFFFF) | value + else: # BYOBJECT (257) -> resolve to object color + raise ValueError(f"Invalid color index: {value}") + else: + return -(-((COLOR_TYPE_RGB << 24) + rgb2int(value)) & 0xFFFFFFFF) + + +TRANSPARENCY_BYBLOCK = 0x1000000 +OPAQUE = 0x20000FF +TRANSPARENCY_10 = 0x20000E5 +TRANSPARENCY_20 = 0x20000CC +TRANSPARENCY_30 = 0x20000B2 +TRANSPARENCY_40 = 0x2000099 +TRANSPARENCY_50 = 0x200007F +TRANSPARENCY_60 = 0x2000066 +TRANSPARENCY_70 = 0x200004C +TRANSPARENCY_80 = 0x2000032 +TRANSPARENCY_90 = 0x2000019 + + +def float2transparency(value: float) -> int: + """ + Returns DXF transparency value as integer in the range from 0 to 255, + where 0 is 100% transparent and 255 is opaque. + + Args: + value: transparency value as float in the range from 0 to 1, where 0 is + opaque and 1 is 100% transparent. + + """ + return int((1.0 - float(value)) * 255) | 0x02000000 + + +def transparency2float(value: int) -> float: + """ + Returns transparency value as float from 0 to 1, 0 for no transparency + (opaque) and 1 for 100% transparency. + + Args: + value: DXF integer transparency value, 0 for 100% transparency and 255 + for opaque + + """ + # Transparency value 0x020000TT 0 = fully transparent / 255 = opaque + # 255 -> 0.0 + # 0 -> 1.0 + return 1.0 - float(int(value) & 0xFF) / 255.0 + + +def int2rgb(value: int) -> RGB: + """Split RGB integer `value` into (r, g, b) tuple.""" + return RGB( + (value >> 16) & 0xFF, # red + (value >> 8) & 0xFF, # green + value & 0xFF, # blue + ) + + +def rgb2int(rgb: RGB | tuple[int, int, int]) -> int: + """Combined integer value from (r, g, b) tuple.""" + r, g, b = rgb + return ((int(r) & 0xFF) << 16) | ((int(g) & 0xFF) << 8) | (int(b) & 0xFF) + + +def aci2rgb(index: int) -> RGB: + """Convert :ref:`ACI` into (r, g, b) tuple, based on default AutoCAD + colors. + """ + if index < 1: + raise IndexError(index) + return int2rgb(DXF_DEFAULT_COLORS[index]) + + +def luminance(color: Sequence[float]) -> float: + """Returns perceived luminance for an RGB color in the range [0.0, 1.0] + from dark to light. + """ + r = float(color[0]) / 255 + g = float(color[1]) / 255 + b = float(color[2]) / 255 + return round(math.sqrt(0.299 * r * r + 0.587 * g * g + 0.114 * b * b), 3) + + +# color codes are 1-indexed so an additional entry was put in the 0th position +# different plot styles may choose different colors for the same code +# from ftp://ftp.ecn.purdue.edu/jshan/86/help/html/import_export/dxf_colortable.htm +# alternative color tables can be found at: +# - http://www.temblast.com/songview/color3.htm +# - http://gohtx.com/acadcolors.php + +# modelspace color palette for AutoCAD 2020 +DXF_DEFAULT_COLORS = [ + 0x000000, # dummy value for index [0] + 0xFF0000, + 0xFFFF00, + 0x00FF00, + 0x00FFFF, + 0x0000FF, + 0xFF00FF, + 0xFFFFFF, + 0x808080, + 0xC0C0C0, + 0xFF0000, + 0xFF7F7F, + 0xA50000, + 0xA55252, + 0x7F0000, + 0x7F3F3F, + 0x4C0000, + 0x4C2626, + 0x260000, + 0x261313, + 0xFF3F00, + 0xFF9F7F, + 0xA52900, + 0xA56752, + 0x7F1F00, + 0x7F4F3F, + 0x4C1300, + 0x4C2F26, + 0x260900, + 0x261713, + 0xFF7F00, + 0xFFBF7F, + 0xA55200, + 0xA57C52, + 0x7F3F00, + 0x7F5F3F, + 0x4C2600, + 0x4C3926, + 0x261300, + 0x261C13, + 0xFFBF00, + 0xFFDF7F, + 0xA57C00, + 0xA59152, + 0x7F5F00, + 0x7F6F3F, + 0x4C3900, + 0x4C4226, + 0x261C00, + 0x262113, + 0xFFFF00, + 0xFFFF7F, + 0xA5A500, + 0xA5A552, + 0x7F7F00, + 0x7F7F3F, + 0x4C4C00, + 0x4C4C26, + 0x262600, + 0x262613, + 0xBFFF00, + 0xDFFF7F, + 0x7CA500, + 0x91A552, + 0x5F7F00, + 0x6F7F3F, + 0x394C00, + 0x424C26, + 0x1C2600, + 0x212613, + 0x7FFF00, + 0xBFFF7F, + 0x52A500, + 0x7CA552, + 0x3F7F00, + 0x5F7F3F, + 0x264C00, + 0x394C26, + 0x132600, + 0x1C2613, + 0x3FFF00, + 0x9FFF7F, + 0x29A500, + 0x67A552, + 0x1F7F00, + 0x4F7F3F, + 0x134C00, + 0x2F4C26, + 0x092600, + 0x172613, + 0x00FF00, + 0x7FFF7F, + 0x00A500, + 0x52A552, + 0x007F00, + 0x3F7F3F, + 0x004C00, + 0x264C26, + 0x002600, + 0x132613, + 0x00FF3F, + 0x7FFF9F, + 0x00A529, + 0x52A567, + 0x007F1F, + 0x3F7F4F, + 0x004C13, + 0x264C2F, + 0x002609, + 0x135817, + 0x00FF7F, + 0x7FFFBF, + 0x00A552, + 0x52A57C, + 0x007F3F, + 0x3F7F5F, + 0x004C26, + 0x264C39, + 0x002613, + 0x13581C, + 0x00FFBF, + 0x7FFFDF, + 0x00A57C, + 0x52A591, + 0x007F5F, + 0x3F7F6F, + 0x004C39, + 0x264C42, + 0x00261C, + 0x135858, + 0x00FFFF, + 0x7FFFFF, + 0x00A5A5, + 0x52A5A5, + 0x007F7F, + 0x3F7F7F, + 0x004C4C, + 0x264C4C, + 0x002626, + 0x135858, + 0x00BFFF, + 0x7FDFFF, + 0x007CA5, + 0x5291A5, + 0x005F7F, + 0x3F6F7F, + 0x00394C, + 0x26427E, + 0x001C26, + 0x135858, + 0x007FFF, + 0x7FBFFF, + 0x0052A5, + 0x527CA5, + 0x003F7F, + 0x3F5F7F, + 0x00264C, + 0x26397E, + 0x001326, + 0x131C58, + 0x003FFF, + 0x7F9FFF, + 0x0029A5, + 0x5267A5, + 0x001F7F, + 0x3F4F7F, + 0x00134C, + 0x262F7E, + 0x000926, + 0x131758, + 0x0000FF, + 0x7F7FFF, + 0x0000A5, + 0x5252A5, + 0x00007F, + 0x3F3F7F, + 0x00004C, + 0x26267E, + 0x000026, + 0x131358, + 0x3F00FF, + 0x9F7FFF, + 0x2900A5, + 0x6752A5, + 0x1F007F, + 0x4F3F7F, + 0x13004C, + 0x2F267E, + 0x090026, + 0x171358, + 0x7F00FF, + 0xBF7FFF, + 0x5200A5, + 0x7C52A5, + 0x3F007F, + 0x5F3F7F, + 0x26004C, + 0x39267E, + 0x130026, + 0x1C1358, + 0xBF00FF, + 0xDF7FFF, + 0x7C00A5, + 0x9152A5, + 0x5F007F, + 0x6F3F7F, + 0x39004C, + 0x42264C, + 0x1C0026, + 0x581358, + 0xFF00FF, + 0xFF7FFF, + 0xA500A5, + 0xA552A5, + 0x7F007F, + 0x7F3F7F, + 0x4C004C, + 0x4C264C, + 0x260026, + 0x581358, + 0xFF00BF, + 0xFF7FDF, + 0xA5007C, + 0xA55291, + 0x7F005F, + 0x7F3F6F, + 0x4C0039, + 0x4C2642, + 0x26001C, + 0x581358, + 0xFF007F, + 0xFF7FBF, + 0xA50052, + 0xA5527C, + 0x7F003F, + 0x7F3F5F, + 0x4C0026, + 0x4C2639, + 0x260013, + 0x58131C, + 0xFF003F, + 0xFF7F9F, + 0xA50029, + 0xA55267, + 0x7F001F, + 0x7F3F4F, + 0x4C0013, + 0x4C262F, + 0x260009, + 0x581317, + 0x000000, + 0x656565, + 0x666666, + 0x999999, + 0xCCCCCC, + 0xFFFFFF, +] + + +# paperspace color palette for AutoCAD 2020 +DXF_DEFAULT_PAPERSPACE_COLORS = [ + 0x000000, # dummy value for index [0] + 0xFF0000, + 0xFFFF00, + 0x00FF00, + 0x00FFFF, + 0x0000FF, + 0xFF00FF, + 0x000000, + 0x808080, + 0xC0C0C0, + 0xFF0000, + 0xFF7F7F, + 0xA50000, + 0xA55252, + 0x7F0000, + 0x7F3F3F, + 0x4C0000, + 0x4C2626, + 0x260000, + 0x261313, + 0xFF3F00, + 0xFF9F7F, + 0xA52900, + 0xA56752, + 0x7F1F00, + 0x7F4F3F, + 0x4C1300, + 0x4C2F26, + 0x260900, + 0x261713, + 0xFF7F00, + 0xFFBF7F, + 0xA55200, + 0xA57C52, + 0x7F3F00, + 0x7F5F3F, + 0x4C2600, + 0x4C3926, + 0x261300, + 0x261C13, + 0xFFBF00, + 0xFFDF7F, + 0xA57C00, + 0xA59152, + 0x7F5F00, + 0x7F6F3F, + 0x4C3900, + 0x4C4226, + 0x261C00, + 0x262113, + 0xFFFF00, + 0xFFFF7F, + 0xA5A500, + 0xA5A552, + 0x7F7F00, + 0x7F7F3F, + 0x4C4C00, + 0x4C4C26, + 0x262600, + 0x262613, + 0xBFFF00, + 0xDFFF7F, + 0x7CA500, + 0x91A552, + 0x5F7F00, + 0x6F7F3F, + 0x394C00, + 0x424C26, + 0x1C2600, + 0x212613, + 0x7FFF00, + 0xBFFF7F, + 0x52A500, + 0x7CA552, + 0x3F7F00, + 0x5F7F3F, + 0x264C00, + 0x394C26, + 0x132600, + 0x1C2613, + 0x3FFF00, + 0x9FFF7F, + 0x29A500, + 0x67A552, + 0x1F7F00, + 0x4F7F3F, + 0x134C00, + 0x2F4C26, + 0x092600, + 0x172613, + 0x00FF00, + 0x7FFF7F, + 0x00A500, + 0x52A552, + 0x007F00, + 0x3F7F3F, + 0x004C00, + 0x264C26, + 0x002600, + 0x132613, + 0x00FF3F, + 0x7FFF9F, + 0x00A529, + 0x52A567, + 0x007F1F, + 0x3F7F4F, + 0x004C13, + 0x264C2F, + 0x002609, + 0x132617, + 0x00FF7F, + 0x7FFFBF, + 0x00A552, + 0x52A57C, + 0x007F3F, + 0x3F7F5F, + 0x004C26, + 0x264C39, + 0x002613, + 0x13261C, + 0x00FFBF, + 0x7FFFDF, + 0x00A57C, + 0x52A591, + 0x007F5F, + 0x3F7F6F, + 0x004C39, + 0x264C42, + 0x00261C, + 0x132621, + 0x00FFFF, + 0x7FFFFF, + 0x00A5A5, + 0x52A5A5, + 0x007F7F, + 0x3F7F7F, + 0x004C4C, + 0x264C4C, + 0x002626, + 0x132626, + 0x00BFFF, + 0x7FDFFF, + 0x007CA5, + 0x5291A5, + 0x005F7F, + 0x3F6F7F, + 0x00394C, + 0x26424C, + 0x001C26, + 0x132126, + 0x007FFF, + 0x7FBFFF, + 0x0052A5, + 0x527CA5, + 0x003F7F, + 0x3F5F7F, + 0x00264C, + 0x26394C, + 0x001326, + 0x131C26, + 0x003FFF, + 0x7F9FFF, + 0x0029A5, + 0x5267A5, + 0x001F7F, + 0x3F4F7F, + 0x00134C, + 0x262F4C, + 0x000926, + 0x131726, + 0x0000FF, + 0x7F7FFF, + 0x0000A5, + 0x5252A5, + 0x00007F, + 0x3F3F7F, + 0x00004C, + 0x26264C, + 0x000026, + 0x131326, + 0x3F00FF, + 0x9F7FFF, + 0x2900A5, + 0x6752A5, + 0x1F007F, + 0x4F3F7F, + 0x13004C, + 0x2F264C, + 0x090026, + 0x171326, + 0x7F00FF, + 0xBF7FFF, + 0x5200A5, + 0x7C52A5, + 0x3F007F, + 0x5F3F7F, + 0x26004C, + 0x39264C, + 0x130026, + 0x1C1326, + 0xBF00FF, + 0xDF7FFF, + 0x7C00A5, + 0x9152A5, + 0x5F007F, + 0x6F3F7F, + 0x39004C, + 0x42264C, + 0x1C0026, + 0x211326, + 0xFF00FF, + 0xFF7FFF, + 0xA500A5, + 0xA552A5, + 0x7F007F, + 0x7F3F7F, + 0x4C004C, + 0x4C264C, + 0x260026, + 0x261326, + 0xFF00BF, + 0xFF7FDF, + 0xA5007C, + 0xA55291, + 0x7F005F, + 0x7F3F6F, + 0x4C0039, + 0x4C2642, + 0x26001C, + 0x261321, + 0xFF007F, + 0xFF7FBF, + 0xA50052, + 0xA5527C, + 0x7F003F, + 0x7F3F5F, + 0x4C0026, + 0x4C2639, + 0x260013, + 0x26131C, + 0xFF003F, + 0xFF7F9F, + 0xA50029, + 0xA55267, + 0x7F001F, + 0x7F3F4F, + 0x4C0013, + 0x4C262F, + 0x260009, + 0x261317, + 0x000000, + 0x2D2D2D, + 0x5B5B5B, + 0x898989, + 0xB7B7B7, + 0xB3B3B3, +] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/commands.py b/.venv/lib/python3.12/site-packages/ezdxf/commands.py new file mode 100644 index 0000000..4183963 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/commands.py @@ -0,0 +1,1062 @@ +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import pathlib +import tempfile +from typing import Callable, Optional, TYPE_CHECKING, Type, Sequence +import abc +import sys +import os +import glob +import signal +import time +import logging +from pathlib import Path + +# -------------------------------------------------------------------------------------- +# Only imports from the core package here - no add-ons! +# +# The command `ezdxf -V` must always work! +# +# Imports depending on additional packages like Pillow, Matplotlib, PySide6, ... +# have to be local imports, see 'draw' command as an example. +# -------------------------------------------------------------------------------------- +import ezdxf +from ezdxf import recover +from ezdxf.lldxf import const +from ezdxf.lldxf.validator import is_dxf_file, is_binary_dxf_file, dxf_info +from ezdxf.dwginfo import dwg_file_info + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic + from ezdxf.addons.drawing.properties import Properties, LayerProperties + +__all__ = ["get", "add_parsers"] + +logger = logging.getLogger("ezdxf") + + +def get(cmd: str) -> Optional[Callable]: + cls = _commands.get(cmd) + if cls: + return cls.run + return None + + +def add_parsers(subparsers) -> None: + for cmd in _commands.values(): # in order of registration + try: + cmd.add_parser(subparsers) + except ImportError: + logger.info(f"ImportError - '{cmd.NAME}' command not available") + + +def is_dxf_r12_file(filename: str) -> bool: + try: + with open(filename, "rt", errors="ignore") as fp: + info = dxf_info(fp) + except IOError: + return False + return info.version <= const.DXF12 + + +class Command: + """abstract base class for launcher commands""" + + NAME = "command" + + @staticmethod + @abc.abstractmethod + def add_parser(subparsers) -> None: + pass + + @staticmethod + @abc.abstractmethod + def run(args) -> None: + pass + + +_commands: dict[str, Type[Command]] = dict() + + +def register(cls: Type[Command]): + """Register a launcher sub-command.""" + _commands[cls.NAME] = cls + return cls + + +@register +class Audit(Command): + """Launcher sub-command: audit""" + + NAME = "audit" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser(Audit.NAME, help="audit and repair DXF files") + parser.add_argument( + "files", + metavar="FILE", + nargs="+", + help="audit DXF files", + ) + parser.add_argument( + "-s", + "--save", + action="store_true", + help='save recovered files with extension ".rec.dxf" ', + ) + parser.add_argument( + "-x", + "--explore", + action="store_true", + help="filters invalid DXF tags, this may load corrupted files but " + "data loss is very likely", + ) + + @staticmethod + def run(args): + def build_outname(name: str) -> str: + p = Path(name) + return str(p.parent / (p.stem + ".rec.dxf")) + + def log_fixes(auditor): + for error in auditor.fixes: + logger.info("fixed:" + error.message) + + def log_errors(auditor): + for error in auditor.errors: + logger.error(error.message) + + def _audit(filename: str) -> None: + msg = f"auditing file: {filename}" + print(msg) + logger.info(msg) + if args.explore: + logger.info("explore mode - skipping invalid tags") + loader = recover.explore if args.explore else recover.readfile + try: + doc, auditor = loader(filename) + except IOError: + msg = "Not a DXF file or a generic I/O error." + print(msg) + logger.error(msg) + return # keep on processing additional files + except const.DXFStructureError as e: + msg = f"Invalid or corrupted DXF file: {str(e)}" + print(msg) + logger.error(msg) + return # keep on processing additional files + + if auditor.has_errors: + auditor.print_error_report() + log_errors(auditor) + if auditor.has_fixes: + auditor.print_fixed_errors() + log_fixes(auditor) + + if auditor.has_errors is False and auditor.has_fixes is False: + print("No errors found.") + else: + print( + f"Found {len(auditor.errors)} errors, " + f"applied {len(auditor.fixes)} fixes" + ) + + if args.save: + outname = build_outname(filename) + try: + doc.saveas(outname) + except IOError as e: + print(f"Can not save recovered file '{outname}':\n{str(e)}") + else: + print(f"Saved recovered file as: '{outname}'") + + for pattern in args.files: + names = list(glob.glob(pattern)) + if len(names) == 0: + msg = f"File(s) '{pattern}' not found." + print(msg) + logger.error(msg) + continue + for filename in names: + if not os.path.exists(filename): + msg = f"File '{filename}' not found." + print(msg) + logger.error(msg) + continue + if not is_dxf_file(filename): + msg = f"File '{filename}' is not a DXF file." + print(msg) + logger.error(msg) + continue + _audit(filename) + + +def load_document(filename: str): + try: + doc, auditor = recover.readfile(filename) + except IOError: + msg = f'Not a DXF file or a generic I/O error: "{filename}"' + print(msg, file=sys.stderr) + sys.exit(2) + except const.DXFStructureError: + msg = f'Invalid or corrupted DXF file: "{filename}"' + print(msg, file=sys.stderr) + sys.exit(3) + + if auditor.has_errors: + # But is most likely good enough for rendering. + msg = f"Audit process found {len(auditor.errors)} unrecoverable error(s)." + print(msg) + logger.error(msg) + if auditor.has_fixes: + msg = f"Audit process fixed {len(auditor.fixes)} error(s)." + print(msg) + logger.info(msg) + return doc, auditor + + +HELP_LTYPE = ( + "select the line type rendering method, default is approximate. " + "Approximate uses the closest approximation available to the " + "backend, the accurate method renders as accurately as possible " + "but this approach is slower." +) +HELP_LWSCALE = ( + "set custom line weight scaling, default is 0 to disable line " "weights at all" +) + + +@register +class Draw(Command): + """Launcher sub-command: draw""" + + NAME = "draw" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser( + Draw.NAME, help="draw and save DXF as a bitmap or vector image" + ) + parser.add_argument( + "file", + metavar="FILE", + nargs="?", + help="DXF file to view or convert", + ) + parser.add_argument( + "--backend", + default="matplotlib", + choices=["matplotlib", "qt", "mupdf", "custom_svg"], + help="choose the backend to use for rendering", + ) + parser.add_argument( + "--formats", + action="store_true", + help="show all supported export formats and exit", + ) + parser.add_argument( + "-l", + "--layout", + default="Model", + help='select the layout to draw, default is "Model"', + ) + parser.add_argument( + "--background", + default="DEFAULT", + choices=[ + "DEFAULT", + "WHITE", + "BLACK", + "PAPERSPACE", + "MODELSPACE", + "OFF", + "CUSTOM", + ], + help="choose the background color to use", + ) + parser.add_argument( + "--all-layers-visible", + action="store_true", + help="draw all layers including the ones marked as invisible", + ) + parser.add_argument( + "--all-entities-visible", + action="store_true", + help="draw all entities including the ones marked as invisible " + "(some entities are individually marked as invisible even " + "if the layer is visible)", + ) + parser.add_argument( + "-o", + "--out", + required=False, + type=pathlib.Path, + help="output filename for export", + ) + parser.add_argument( + "--dpi", + type=int, + default=300, + help="target render resolution, default is 300", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + help="overwrite the destination if it already exists", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="give more output", + ) + + @staticmethod + def run(args): + try: + from ezdxf.addons.drawing import RenderContext, Frontend + from ezdxf.addons.drawing.config import Configuration, BackgroundPolicy + from ezdxf.addons.drawing.file_output import ( + open_file, + MatplotlibFileOutput, + PyQtFileOutput, + SvgFileOutput, + MuPDFFileOutput, + ) + except ImportError as e: + print(str(e)) + sys.exit(1) + + if args.backend == "matplotlib": + try: + file_output = MatplotlibFileOutput(args.dpi) + except ImportError as e: + print(str(e)) + sys.exit(1) + elif args.backend == "qt": + try: + file_output = PyQtFileOutput(args.dpi) + except ImportError as e: + print(str(e)) + sys.exit(1) + elif args.backend == "mupdf": + try: + file_output = MuPDFFileOutput(args.dpi) + except ImportError as e: + print(str(e)) + sys.exit(1) + elif args.backend == "custom_svg": + # has no additional dependencies + file_output = SvgFileOutput(args.dpi) + else: + raise ValueError(args.backend) + + verbose = args.verbose + if verbose: + logging.basicConfig(level=logging.INFO) + + if args.formats: + print(f"formats supported by {args.backend}:") + for extension, description in file_output.supported_formats(): + print(f" {extension}: {description}") + sys.exit(0) + + if args.file: + filename = args.file + else: + print("argument FILE is required") + sys.exit(1) + + print(f'loading file "{filename}"...') + doc, _ = load_document(filename) + + try: + layout = doc.layouts.get(args.layout) + except KeyError: + print( + f'Could not find layout "{args.layout}". ' + f"Valid layouts: {[l.name for l in doc.layouts]}" + ) + sys.exit(1) + + ctx = RenderContext(doc) + config = Configuration().with_changes( + background_policy=BackgroundPolicy[args.background] + ) + out = file_output.backend() + + if args.all_layers_visible: + def override_layer_properties(layer_properties: Sequence[LayerProperties]) -> None: + for properties in layer_properties: + properties.is_visible = True + + ctx.set_layer_properties_override(override_layer_properties) + + frontend = Frontend(ctx, out, config=config) + + if args.all_entities_visible: + def override_entity_properties(entity: DXFGraphic, properties: Properties) -> None: + properties.is_visible = True + frontend.push_property_override_function(override_entity_properties) + + t0 = time.perf_counter() + if verbose: + print(f"drawing layout '{layout.name}' ...") + frontend.draw_layout(layout, finalize=True) + t1 = time.perf_counter() + if verbose: + print(f"took {t1-t0:.4f} seconds") + + if args.out is not None: + if pathlib.Path(args.out).suffix not in { + f".{ext}" for ext, _ in file_output.supported_formats() + }: + print( + f'the format of the output path "{args.out}" ' + f"is not supported by the backend {args.backend}" + ) + sys.exit(1) + + if args.out.exists() and not args.force: + print(f'the destination "{args.out}" already exists. Not writing') + sys.exit(1) + else: + print(f'exporting to "{args.out}"...') + t0 = time.perf_counter() + file_output.save(args.out) + t1 = time.perf_counter() + if verbose: + print(f"took {t1 - t0:.4f} seconds") + + else: + print(f"exporting to temporary file...") + output_dir = pathlib.Path(tempfile.mkdtemp(prefix="ezdxf_draw")) + output_path = output_dir / f"output.{file_output.default_format()}" + file_output.save(output_path) + print(f'saved to "{output_path}"') + if verbose: + print("opening viewer...") + open_file(output_path) + + +@register +class View(Command): + """Launcher sub-command: view""" + + NAME = "view" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser( + View.NAME, help="view DXF files by the PyQt viewer" + ) + parser.add_argument( + "file", + metavar="FILE", + nargs="?", + help="DXF file to view", + ) + parser.add_argument( + "-l", + "--layout", + default="Model", + help='select the layout to draw, default is "Model"', + ) + # disable lineweight at all by default: + parser.add_argument( + "--lwscale", + type=float, + default=0, + help=HELP_LWSCALE, + ) + + @staticmethod + def run(args): + # Import on demand for a quicker startup: + try: + from ezdxf.addons.xqt import QtWidgets + except ImportError as e: + print(str(e)) + sys.exit(1) + from ezdxf.addons.drawing.qtviewer import CADViewer + from ezdxf.addons.drawing.config import Configuration + + config = Configuration( + lineweight_scaling=args.lwscale, + ) + + signal.signal(signal.SIGINT, signal.SIG_DFL) # handle Ctrl+C properly + app = QtWidgets.QApplication(sys.argv) + app.setStyle("Fusion") + set_app_icon(app) + viewer = CADViewer.from_config(config) + filename = args.file + if filename: + doc, auditor = load_document(filename) + viewer.set_document( + doc, + auditor, + layout=args.layout, + ) + sys.exit(app.exec()) + + +@register +class Browse(Command): + """Launcher sub-command: browse""" + + NAME = "browse" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser(Browse.NAME, help="browse DXF file structure") + parser.add_argument( + "file", + metavar="FILE", + nargs="?", + help="DXF file to browse", + ) + parser.add_argument( + "-l", "--line", type=int, required=False, help="go to line number" + ) + parser.add_argument( + "-g", + "--handle", + required=False, + help="go to entity by HANDLE, HANDLE has to be a hex value without " + "any prefix like 'fefe'", + ) + + @staticmethod + def run(args): + try: + from ezdxf.addons.xqt import QtWidgets + except ImportError as e: + print(str(e)) + sys.exit(1) + from ezdxf.addons import browser + + signal.signal(signal.SIGINT, signal.SIG_DFL) # handle Ctrl+C properly + app = QtWidgets.QApplication(sys.argv) + app.setStyle("Fusion") + set_app_icon(app) + main_window = browser.DXFStructureBrowser( + args.file, + line=args.line, + handle=args.handle, + resource_path=resources_path(), + ) + main_window.show() + sys.exit(app.exec()) + + +@register +class BrowseAcisData(Command): + """Launcher sub-command: browse-acis""" + + NAME = "browse-acis" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser( + BrowseAcisData.NAME, help="browse ACIS structures in DXF files" + ) + parser.add_argument( + "file", + metavar="FILE", + nargs="?", + help="DXF file to browse", + ) + parser.add_argument( + "-g", + "--handle", + required=False, + help="go to entity by HANDLE, HANDLE has to be a hex value without " + "any prefix like 'fefe'", + ) + + @staticmethod + def run(args): + try: + from ezdxf.addons.xqt import QtWidgets + except ImportError as e: + print(str(e)) + sys.exit(1) + from ezdxf.addons.acisbrowser.browser import AcisStructureBrowser + + signal.signal(signal.SIGINT, signal.SIG_DFL) # handle Ctrl+C properly + app = QtWidgets.QApplication(sys.argv) + app.setStyle("Fusion") + set_app_icon(app) + main_window = AcisStructureBrowser( + args.file, + handle=args.handle, + ) + main_window.show() + sys.exit(app.exec()) + + +@register +class Strip(Command): + """Launcher sub-command: strip""" + + NAME = "strip" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser(Strip.NAME, help="strip comments from DXF files") + parser.add_argument( + "file", + metavar="FILE", + nargs="+", + help='DXF file to process, wildcards "*" and "?" are supported', + ) + parser.add_argument( + "-b", + "--backup", + action="store_true", + required=False, + help='make a backup copy with extension ".bak" from the ' + "DXF file, overwrites existing backup files", + ) + parser.add_argument( + "-t", + "--thumbnail", + action="store_true", + required=False, + help="strip THUMBNAILIMAGE section", + ) + parser.add_argument( + "--handles", + action="store_true", + required=False, + help="remove handles from DXF R12 or older files", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + required=False, + help="give more output", + ) + + @staticmethod + def run(args): + from ezdxf.tools.strip import strip + + for pattern in args.file: + for filename in glob.glob(pattern): + codes = [999] + if args.handles: + if is_dxf_r12_file(filename): + codes.extend([5, 105]) + else: + print( + f"Cannot remove handles from DXF R13 or later: {filename}" + ) + strip( + filename, + backup=args.backup, + thumbnail=args.thumbnail, + verbose=args.verbose, + codes=codes, + ) + + +@register +class Config(Command): + """Launcher sub-command: config""" + + NAME = "config" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser(Config.NAME, help="manage config files") + parser.add_argument( + "-p", + "--print", + action="store_true", + help="print configuration", + ) + parser.add_argument( + "-w", + "--write", + metavar="FILE", + help="write configuration", + ) + parser.add_argument( + "--home", + action="store_true", + help="create config file 'ezdxf.ini' in the user home directory " + "'~/.config/ezdxf', $XDG_CONFIG_HOME is supported if set", + ) + parser.add_argument( + "--reset", + action="store_true", + help="factory reset, delete default config files 'ezdxf.ini'", + ) + + @staticmethod + def run(args): + from ezdxf import options + + action = False + if args.reset: + options.reset() + options.delete_default_config_files() + action = True + if args.home: + options.write_home_config() + action = True + if args.write: + action = True + filepath = Path(args.write).expanduser() + try: + options.write_file(str(filepath)) + print(f"configuration written to: {filepath}") + except IOError as e: + print(str(e)) + if args.print or action is False: + options.print() + + +def load_every_document(filename: str): + def io_error() -> str: + msg = f'Not a DXF file or a generic I/O error: "{filename}"' + print(msg, file=sys.stderr) + return msg + + def structure_error() -> str: + msg = f'Invalid or corrupted DXF file: "{filename}"' + print(msg, file=sys.stderr) + return msg + + binary_fmt = False + if is_binary_dxf_file(filename): + try: + doc = ezdxf.readfile(filename) + except IOError: + raise const.DXFLoadError(io_error()) + except const.DXFStructureError: + raise const.DXFLoadError(structure_error()) + auditor = doc.audit() + binary_fmt = True + else: + try: + doc, auditor = recover.readfile(filename) + except IOError: + raise const.DXFLoadError(io_error()) + except const.DXFStructureError: + dwginfo = dwg_file_info(filename) + if dwginfo.version != "invalid": + print( + f"This is a DWG file!!!\n" + f'Filename: "{filename}"\n' + f"Format: DWG\n" + f"Release: {dwginfo.release}\n" + f"DWG Version: {dwginfo.version}\n" + ) + raise const.DXFLoadError() + raise const.DXFLoadError(structure_error()) + return doc, auditor, binary_fmt + + +@register +class Info(Command): + """Launcher sub-command: info""" + + NAME = "info" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser( + Info.NAME, + help="show information and optional stats of DXF files as " + "loaded by ezdxf, this may not represent the original " + "content of the file, use the browse command to " + "see the original content", + ) + parser.add_argument( + "file", + metavar="FILE", + nargs="+", + help='DXF file to process, wildcards "*" and "?" are supported', + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + required=False, + help="give more output", + ) + parser.add_argument( + "-s", + "--stats", + action="store_true", + required=False, + help="show content stats", + ) + + @staticmethod + def run(args): + from ezdxf.document import info + + def process(fn: str): + try: + doc, auditor, binary_fmt = load_every_document(fn) + except const.DXFLoadError: + pass + else: + fmt = "Binary" if binary_fmt else "ASCII" + print( + "\n".join( + info( + doc, + verbose=args.verbose, + content=args.stats, + fmt=fmt, + ) + ) + ) + if auditor.has_fixes: + print(f"Audit process fixed {len(auditor.fixes)} error(s).") + if auditor.has_errors: + print( + f"Audit process found {len(auditor.errors)} unrecoverable error(s)." + ) + print() + + for pattern in args.file: + file_count = 0 + for filename in glob.glob(pattern): + if os.path.isdir(filename): + dir_pattern = os.path.join(filename, "*.dxf") + for filename2 in glob.glob(dir_pattern): + process(filename2) + file_count += 1 + else: + process(filename) + file_count += 1 + + if file_count == 0: + sys.stderr.write(f'No matching files for pattern: "{pattern}"\n') + + +@register +class HPGL(Command): + """Launcher sub-command: hpgl""" + + NAME = "hpgl" + + @staticmethod + def add_parser(subparsers): + parser = subparsers.add_parser( + HPGL.NAME, help=f"view and/or convert HPGL/2 plot files to various formats" + ) + parser.add_argument( + "file", + metavar="FILE", + nargs="?", + default="", + help=f"view and/or convert HPGL/2 plot files, wildcards (*, ?) supported in command line mode", + ) + parser.add_argument( + "-e", + "--export", + metavar="FORMAT", + required=False, + help=f"convert HPGL/2 plot file to SVG, PDF or DXF from the command line (no gui)", + ) + parser.add_argument( + "-r", + "--rotate", + type=int, + choices=(0, 90, 180, 270), + default=0, + required=False, + help="rotate page about 90, 180 or 270 degrees (no gui)", + ) + parser.add_argument( + "-x", + "--mirror_x", + action="store_true", + required=False, + help="mirror page in x-axis direction, (no gui)", + ) + parser.add_argument( + "-y", + "--mirror_y", + action="store_true", + required=False, + help="mirror page in y-axis direction, (no gui)", + ) + parser.add_argument( + "-m", + "--merge_control", + type=int, + required=False, + default=2, + choices=(0, 1, 2), + help="provides control over the order of filled polygons, 0=off (print order), " + "1=luminance (order by luminance), 2=auto (default)", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + required=False, + help="inserts the mandatory 'enter HPGL/2 mode' escape sequence into the data " + "stream; use this flag when no HPGL/2 data was found and you are sure the " + "file is a HPGL/2 plot file", + ) + parser.add_argument( + "--aci", + action="store_true", + required=False, + help="use pen numbers as ACI colors and assign colors by layer (DXF only)", + ) + parser.epilog = ( + "Note that plot files are intended to be plotted on white paper." + ) + parser.add_argument( + "--dpi", + type=int, + required=False, + default=96, + help="pixel density in dots per inch (PNG only)", + ) + parser.epilog = ( + "Note that plot files are intended to be plotted on white paper." + ) + + @staticmethod + def run(args): + if args.export: + if os.path.exists(args.file): + filenames = [args.file] + else: + filenames = glob.glob(args.file) + for filename in filenames: + export_hpgl2(Path(filename), args) + else: + launch_hpgl2_viewer(args.file, args.force) + + +def export_hpgl2(filepath: Path, args) -> None: + from ezdxf.addons.hpgl2 import api as hpgl2 + from ezdxf.addons.drawing.dxf import ColorMode + + fmt = args.export.upper() + start_msg = f"converting HPGL/2 plot file '{filepath.name}' to {fmt}" + try: + data = filepath.read_bytes() + except IOError as e: + print(str(e), file=sys.stderr) + return + if args.force: + data = b"%1B" + data + export_path = filepath.with_suffix(f".{fmt.lower()}") + if fmt == "DXF": + print(start_msg) + color_mode = ColorMode.ACI if args.aci else ColorMode.RGB + doc = hpgl2.to_dxf( + data, + rotation=args.rotate, + mirror_x=args.mirror_x, + mirror_y=args.mirror_y, + color_mode=color_mode, + merge_control=args.merge_control, + ) + try: + doc.saveas(export_path) + except IOError as e: + print(str(e), file=sys.stderr) + + elif fmt == "SVG": + print(start_msg) + svg_string = hpgl2.to_svg( + data, + rotation=args.rotate, + mirror_x=args.mirror_x, + mirror_y=args.mirror_y, + merge_control=args.merge_control, + ) + try: + export_path.write_text(svg_string) + except IOError as e: + print(str(e), file=sys.stderr) + elif fmt == "PDF": + print(start_msg) + pdf_bytes = hpgl2.to_pdf( + data, + rotation=args.rotate, + mirror_x=args.mirror_x, + mirror_y=args.mirror_y, + merge_control=args.merge_control, + ) + try: + export_path.write_bytes(pdf_bytes) + except IOError as e: + print(str(e), file=sys.stderr) + elif fmt == "PNG": + print(start_msg) + png_bytes = hpgl2.to_pixmap( + data, + rotation=args.rotate, + mirror_x=args.mirror_x, + mirror_y=args.mirror_y, + merge_control=args.merge_control, + fmt="png", + dpi=args.dpi, + ) + try: + export_path.write_bytes(png_bytes) + except IOError as e: + print(str(e), file=sys.stderr) + else: + print(f"invalid export format: {fmt}") + exit(1) + print(f"file '{export_path.name}' successfully written") + + +def launch_hpgl2_viewer(filename: str, force: bool) -> None: + try: + from ezdxf.addons.xqt import QtWidgets + except ImportError as e: + print(str(e)) + exit(1) + from ezdxf.addons.hpgl2.viewer import HPGL2Viewer + + signal.signal(signal.SIGINT, signal.SIG_DFL) # handle Ctrl+C properly + app = QtWidgets.QApplication(sys.argv) + app.setStyle("Fusion") + set_app_icon(app) + viewer = HPGL2Viewer() + viewer.show() + if filename and os.path.exists(filename): + viewer.load_plot_file(filename, force=force) + sys.exit(app.exec()) + + +def set_app_icon(app): + from ezdxf.addons.xqt import QtGui, QtCore + + app_icon = QtGui.QIcon() + p = resources_path() + app_icon.addFile(str(p / "16x16.png"), QtCore.QSize(16, 16)) + app_icon.addFile(str(p / "24x24.png"), QtCore.QSize(24, 24)) + app_icon.addFile(str(p / "32x32.png"), QtCore.QSize(32, 32)) + app_icon.addFile(str(p / "48x48.png"), QtCore.QSize(48, 48)) + app_icon.addFile(str(p / "64x64.png"), QtCore.QSize(64, 64)) + app_icon.addFile(str(p / "256x256.png"), QtCore.QSize(256, 256)) + app.setWindowIcon(app_icon) + + +def resources_path(): + from pathlib import Path + + return Path(__file__).parent / "resources" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/comments.py b/.venv/lib/python3.12/site-packages/ezdxf/comments.py new file mode 100644 index 0000000..730523d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/comments.py @@ -0,0 +1,43 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, TextIO, Iterable, Optional + +from ezdxf.lldxf.validator import is_dxf_file +from ezdxf.filemanagement import dxf_file_info +from ezdxf.lldxf.tagger import ascii_tags_loader + +if TYPE_CHECKING: + from ezdxf.lldxf.types import DXFTag + + +def from_stream(stream: TextIO, codes: Optional[set[int]] = None) -> Iterable[DXFTag]: + """ + Yields comment tags from text `stream` as :class:`~ezdxf.lldxf.types.DXFTag` objects. + + Args: + stream: input text stream + codes: set of group codes to yield additional DXF tags e.g. {5, 0} to also yield handle and structure tags + + """ + codes = codes or set() + codes.add(999) + return (tag for tag in ascii_tags_loader(stream, skip_comments=False) if tag.code in codes) + + +def from_file(filename: str, codes: Optional[set[int]] = None) -> Iterable[DXFTag]: + """ + Yields comment tags from file `filename` as :class:`~ezdxf.lldxf.types.DXFTag` objects. + + Args: + filename: filename as string + codes: yields also additional tags with specified group codes e.g. {5, 0} to also yield handle and + structure tags + + """ + if is_dxf_file(filename): + info = dxf_file_info(filename) + with open(filename, mode='rt', encoding=info.encoding) as fp: + yield from from_stream(fp, codes=codes) + else: + raise IOError(f'File "{filename}" is not a DXF file.') diff --git a/.venv/lib/python3.12/site-packages/ezdxf/disassemble.py b/.venv/lib/python3.12/site-packages/ezdxf/disassemble.py new file mode 100644 index 0000000..5f34137 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/disassemble.py @@ -0,0 +1,640 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional, cast, TYPE_CHECKING +import abc +import math +from ezdxf.entities import DXFEntity, Insert, get_font_name + +from ezdxf.lldxf import const +from ezdxf.enums import TextEntityAlignment +from ezdxf.math import Vec3, UCS, Z_AXIS, X_AXIS, BoundingBox +from ezdxf.path import Path, make_path, from_vertices, precise_bbox +from ezdxf.render import MeshBuilder, MeshVertexMerger, TraceBuilder +from ezdxf.protocols import SupportsVirtualEntities, virtual_entities + +from ezdxf.tools.text import ( + TextLine, + unified_alignment, + plain_text, + text_wrap, + estimate_mtext_content_extents, +) +from ezdxf.fonts import fonts + +if TYPE_CHECKING: + from ezdxf.entities import LWPolyline, Polyline, MText, Text + +__all__ = [ + "make_primitive", + "recursive_decompose", + "to_primitives", + "to_vertices", + "to_control_vertices", + "to_paths", + "to_meshes", +] + + +class Primitive(abc.ABC): + """It is not efficient to create the Path() or MeshBuilder() representation + by default. For some entities it's just not needed (LINE, POINT) and for + others the builtin flattening() method is more efficient or accurate than + using a Path() proxy object. (ARC, CIRCLE, ELLIPSE, SPLINE). + + The `max_flattening_distance` defines the max distance between the + approximation line and the original curve. Use argument + `max_flattening_distance` to override the default value, or set the value + by direct attribute access. + + """ + + max_flattening_distance: float = 0.01 + + def __init__( + self, entity: DXFEntity, max_flattening_distance: Optional[float] = None + ): + self.entity: DXFEntity = entity + # Path representation for linear entities: + self._path: Optional[Path] = None + # MeshBuilder representation for mesh based entities: + # PolygonMesh, PolyFaceMesh, Mesh + self._mesh: Optional[MeshBuilder] = None + if max_flattening_distance is not None: + self.max_flattening_distance = max_flattening_distance + + @property + def is_empty(self) -> bool: + """Returns `True` if represents an empty primitive which do not + yield any vertices. + + """ + if self._mesh: + return len(self._mesh.vertices) == 0 + return self.path is None # on demand calculations! + + @property + def path(self) -> Optional[Path]: + """:class:`~ezdxf.path.Path` representation or ``None``, + idiom to check if is a path representation (could be empty):: + + if primitive.path is not None: + process(primitive.path) + + """ + return None + + @property + def mesh(self) -> Optional[MeshBuilder]: + """:class:`~ezdxf.render.mesh.MeshBuilder` representation or ``None``, + idiom to check if is a mesh representation (could be empty):: + + if primitive.mesh is not None: + process(primitive.mesh) + + """ + return None + + @abc.abstractmethod + def vertices(self) -> Iterable[Vec3]: + """Yields all vertices of the path/mesh representation as + :class:`~ezdxf.math.Vec3` objects. + + """ + pass + + def bbox(self, fast=False) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` of the path/mesh + representation. Returns the precise bounding box for the path + representation if `fast` is ``False``, otherwise the bounding box for + Bézier curves is based on their control points. + + """ + if self.mesh: + return BoundingBox(self.vertices()) + path = self.path + if path: + if fast: + return BoundingBox(path.control_vertices()) + return precise_bbox(path) + return BoundingBox() + + +class EmptyPrimitive(Primitive): + @property + def is_empty(self) -> bool: + return True + + def vertices(self) -> Iterable[Vec3]: + return [] + + +class ConvertedPrimitive(Primitive): + """Base class for all DXF entities which store the path/mesh representation + at instantiation. + + """ + + def __init__(self, entity: DXFEntity): + super().__init__(entity) + self._convert_entity() + + @abc.abstractmethod + def _convert_entity(self): + """This method creates the path/mesh representation.""" + pass + + @property + def path(self) -> Optional[Path]: + return self._path + + @property + def mesh(self) -> Optional[MeshBuilder]: + return self._mesh + + def vertices(self) -> Iterable[Vec3]: + if self.path: + yield from self._path.flattening(self.max_flattening_distance) # type: ignore + elif self.mesh: + yield from self._mesh.vertices # type: ignore + + +class CurvePrimitive(Primitive): + @property + def path(self) -> Optional[Path]: + """Create path representation on demand.""" + if self._path is None: + self._path = make_path(self.entity) + return self._path + + def vertices(self) -> Iterable[Vec3]: + # Not faster but more precise, because cubic bezier curves do not + # perfectly represent elliptic arcs (CIRCLE, ARC, ELLIPSE). + # SPLINE: cubic bezier curves do not perfectly represent splines with + # degree != 3. + yield from self.entity.flattening(self.max_flattening_distance) # type: ignore + + +class LinePrimitive(Primitive): + # TODO: apply thickness if not 0 + @property + def path(self) -> Optional[Path]: + """Create path representation on demand.""" + if self._path is None: + self._path = make_path(self.entity) + return self._path + + def vertices(self) -> Iterable[Vec3]: + e = self.entity + yield e.dxf.start + yield e.dxf.end + + def bbox(self, fast=False) -> BoundingBox: + e = self.entity + return BoundingBox((e.dxf.start, e.dxf.end)) + + +class LwPolylinePrimitive(ConvertedPrimitive): + # TODO: apply thickness if not 0 + def _convert_entity(self) -> None: + e: LWPolyline = cast("LWPolyline", self.entity) + if e.has_width: # use a mesh representation: + # TraceBuilder operates in OCS! + ocs = e.ocs() + elevation = e.dxf.elevation + tb = TraceBuilder.from_polyline(e) + mb = MeshVertexMerger() # merges coincident vertices + for face in tb.faces_wcs(ocs, elevation): + mb.add_face(face) + self._mesh = MeshBuilder.from_builder(mb) + else: # use a path representation to support bulges! + self._path = make_path(e) + + +class PointPrimitive(Primitive): + @property + def path(self) -> Optional[Path]: + """Create path representation on demand. + + :class:`Path` can not represent a point, a :class:`Path` with only a + start point yields not vertices! + + """ + if self._path is None: + self._path = Path(self.entity.dxf.location) + return self._path + + def vertices(self) -> Iterable[Vec3]: + yield self.entity.dxf.location + + def bbox(self, fast=False) -> BoundingBox: + return BoundingBox((self.entity.dxf.location,)) + + +class MeshPrimitive(ConvertedPrimitive): + def _convert_entity(self): + self._mesh = MeshBuilder.from_mesh(self.entity) + + +class QuadrilateralPrimitive(ConvertedPrimitive): + # TODO: apply thickness if not 0 + def _convert_entity(self): + self._path = make_path(self.entity) + + +class PolylinePrimitive(ConvertedPrimitive): + # TODO: apply thickness if not 0 + def _convert_entity(self) -> None: + e: Polyline = cast("Polyline", self.entity) + if e.is_2d_polyline and e.has_width: + # TraceBuilder operates in OCS! + ocs = e.ocs() + elevation = e.dxf.elevation.z + tb = TraceBuilder.from_polyline(e) + mb = MeshVertexMerger() # merges coincident vertices + for face in tb.faces_wcs(ocs, elevation): + mb.add_face(face) + self._mesh = MeshBuilder.from_builder(mb) + elif e.is_2d_polyline or e.is_3d_polyline: + self._path = make_path(e) + else: + m = MeshVertexMerger.from_polyface(e) # type: ignore + self._mesh = MeshBuilder.from_builder(m) + + +class HatchPrimitive(ConvertedPrimitive): + def _convert_entity(self): + self._path = make_path(self.entity) + + +DESCENDER_FACTOR = 0.333 # from TXT SHX font - just guessing +X_HEIGHT_FACTOR = 0.666 # from TXT SHX font - just guessing + + +class TextLinePrimitive(ConvertedPrimitive): + def _convert_entity(self) -> None: + """Calculates the rough border path for a single line text. + + Calculation is based on a monospaced font and therefore the border + path is just an educated guess. + + Vertical text generation and oblique angle is ignored. + + """ + + def text_rotation(): + if fit_or_aligned and not p1.isclose(p2): + return (p2 - p1).angle + else: + return math.radians(text.dxf.rotation) + + def location(): + if fit_or_aligned: + return p1.lerp(p2, factor=0.5) + return p1 + + text = cast("Text", self.entity) + if text.dxftype() == "ATTDEF": + # ATTDEF outside of a BLOCK renders the tag rather than the value + content = text.dxf.tag + else: + content = text.dxf.text + + content = plain_text(content) + if len(content) == 0: + # empty path - does not render any vertices! + self._path = Path() + return + + font = fonts.make_font( + get_font_name(text), text.dxf.height, text.dxf.width + ) + text_line = TextLine(content, font) + alignment, p1, p2 = text.get_placement() + if p2 is None: + p2 = p1 + fit_or_aligned = ( + alignment == TextEntityAlignment.FIT + or alignment == TextEntityAlignment.ALIGNED + ) + if text.dxf.halign > 2: # ALIGNED=3, MIDDLE=4, FIT=5 + text_line.stretch(alignment, p1, p2) + halign, valign = unified_alignment(text) + mirror_x = -1 if text.is_backward else 1 + mirror_y = -1 if text.is_upside_down else 1 + oblique: float = math.radians(text.dxf.oblique) + corner_vertices = text_line.corner_vertices( + location(), + halign, + valign, + angle=text_rotation(), + scale=(mirror_x, mirror_y), + oblique=oblique, + ) + + ocs = text.ocs() + self._path = from_vertices( + ocs.points_to_wcs(corner_vertices), + close=True, + ) + + +class MTextPrimitive(ConvertedPrimitive): + def _convert_entity(self) -> None: + """Calculates the rough border path for a MTEXT entity. + + Calculation is based on a mono-spaced font and therefore the border + path is just an educated guess. + + Most special features of MTEXT is not supported. + + """ + + def get_content() -> list[str]: + text = mtext.plain_text(split=False) + return text_wrap(text, box_width, font.text_width) # type: ignore + + def get_max_str() -> str: + return max(content, key=lambda s: len(s)) + + def get_rect_width() -> float: + if box_width: + return box_width + s = get_max_str() + if len(s) == 0: + s = " " + return font.text_width(s) + + def get_rect_height() -> float: + line_height = font.measurements.total_height + cap_height = font.measurements.cap_height + # Line spacing factor: Percentage of default (3-on-5) line + # spacing to be applied. + + # thx to mbway: multiple of cap_height between the baseline of the + # previous line and the baseline of the next line + # 3-on-5 line spacing = 5/3 = 1.67 + line_spacing = cap_height * mtext.dxf.line_spacing_factor * 1.67 + spacing = line_spacing - line_height + line_count = len(content) + return line_height * line_count + spacing * (line_count - 1) + + def get_ucs() -> UCS: + """Create local coordinate system: + origin = insertion point + z-axis = extrusion vector + x-axis = text_direction or text rotation, text rotation requires + extrusion vector == (0, 0, 1) or treatment like an OCS? + + """ + origin = mtext.dxf.insert + z_axis = mtext.dxf.extrusion # default is Z_AXIS + x_axis = X_AXIS + if mtext.dxf.hasattr("text_direction"): + x_axis = mtext.dxf.text_direction + elif mtext.dxf.hasattr("rotation"): + # TODO: what if extrusion vector is not (0, 0, 1) + x_axis = Vec3.from_deg_angle(mtext.dxf.rotation) + z_axis = Z_AXIS + return UCS(origin=origin, ux=x_axis, uz=z_axis) + + def get_shift_factors(): + halign, valign = unified_alignment(mtext) + shift_x = 0 + shift_y = 0 + if halign == const.CENTER: + shift_x = -0.5 + elif halign == const.RIGHT: + shift_x = -1.0 + if valign == const.MIDDLE: + shift_y = 0.5 + elif valign == const.BOTTOM: + shift_y = 1.0 + return shift_x, shift_y + + def get_corner_vertices() -> Iterable[Vec3]: + """Create corner vertices in the local working plan, where + the insertion point is the origin. + """ + if columns: + rect_width = columns.total_width + rect_height = columns.total_height + if rect_width == 0.0 or rect_height == 0.0: + # Reliable sources like AutoCAD and BricsCAD do write + # correct total_width and total_height values! + w, h = _estimate_column_extents(mtext) + if rect_width == 0.0: + rect_width = w + if rect_height == 0.0: + rect_height = h + else: + rect_width = mtext.dxf.get("rect_width", get_rect_width()) + rect_height = mtext.dxf.get("rect_height", get_rect_height()) + # TOP LEFT alignment: + vertices = [ + Vec3(0, 0), + Vec3(rect_width, 0), + Vec3(rect_width, -rect_height), + Vec3(0, -rect_height), + ] + sx, sy = get_shift_factors() + shift = Vec3(sx * rect_width, sy * rect_height) + return (v + shift for v in vertices) + + mtext: MText = cast("MText", self.entity) + columns = mtext.columns + if columns is None: + box_width = mtext.dxf.get("width", 0) + font = fonts.make_font( + get_font_name(mtext), mtext.dxf.char_height, 1.0 + ) + content: list[str] = get_content() + if len(content) == 0: + # empty path - does not render any vertices! + self._path = Path() + return + ucs = get_ucs() + corner_vertices = get_corner_vertices() + self._path = from_vertices( + ucs.points_to_wcs(corner_vertices), + close=True, + ) + + +def _estimate_column_extents(mtext: MText): + columns = mtext.columns + assert columns is not None + _content = mtext.text + if columns.count > 1: + _columns_content = _content.split("\\N") + if len(_columns_content) > 1: + _content = max(_columns_content, key=lambda t: len(t)) + return estimate_mtext_content_extents( + content=_content, + font=fonts.MonospaceFont(mtext.dxf.char_height, 1.0), + column_width=columns.width, + line_spacing_factor=mtext.dxf.get_default("line_spacing_factor"), + ) + + +class ImagePrimitive(ConvertedPrimitive): + def _convert_entity(self): + self._path = make_path(self.entity) + + +class ViewportPrimitive(ConvertedPrimitive): + def _convert_entity(self): + vp = self.entity + if vp.dxf.status == 0: # Viewport is off + return # empty primitive + self._path = make_path(vp) + + +# SHAPE is not supported, could not create any SHAPE entities in BricsCAD +_PRIMITIVE_CLASSES = { + "3DFACE": QuadrilateralPrimitive, + "ARC": CurvePrimitive, + # TODO: ATTRIB and ATTDEF could contain embedded MTEXT, + # but this is not supported yet! + "ATTRIB": TextLinePrimitive, + "ATTDEF": TextLinePrimitive, + "CIRCLE": CurvePrimitive, + "ELLIPSE": CurvePrimitive, + "HATCH": HatchPrimitive, # multi-path object + "MPOLYGON": HatchPrimitive, # multi-path object + "HELIX": CurvePrimitive, + "IMAGE": ImagePrimitive, + "LINE": LinePrimitive, + "LWPOLYLINE": LwPolylinePrimitive, + "MESH": MeshPrimitive, + "MTEXT": MTextPrimitive, + "POINT": PointPrimitive, + "POLYLINE": PolylinePrimitive, + "SPLINE": CurvePrimitive, + "SOLID": QuadrilateralPrimitive, + "TEXT": TextLinePrimitive, + "TRACE": QuadrilateralPrimitive, + "VIEWPORT": ViewportPrimitive, + "WIPEOUT": ImagePrimitive, +} + + +def make_primitive( + entity: DXFEntity, max_flattening_distance=None +) -> Primitive: + """Factory to create path/mesh primitives. The `max_flattening_distance` + defines the max distance between the approximation line and the original + curve. Use `max_flattening_distance` to override the default value. + + Returns an **empty primitive** for unsupported entities. The `empty` state + of a primitive can be checked by the property :attr:`is_empty`. + The :attr:`path` and the :attr:`mesh` attributes of an empty primitive + are ``None`` and the :meth:`vertices` method yields no vertices. + + """ + cls = _PRIMITIVE_CLASSES.get(entity.dxftype(), EmptyPrimitive) + primitive = cls(entity) + if max_flattening_distance: + primitive.max_flattening_distance = max_flattening_distance + return primitive + + +def recursive_decompose(entities: Iterable[DXFEntity]) -> Iterable[DXFEntity]: + """Recursive decomposition of the given DXF entity collection into a flat + stream of DXF entities. All block references (INSERT) and entities which provide + a :meth:`virtual_entities` method will be disassembled into simple DXF + sub-entities, therefore the returned entity stream does not contain any + INSERT entity. + + Point entities will **not** be disassembled into DXF sub-entities, + as defined by the current point style $PDMODE. + + These entity types include sub-entities and will be decomposed into + simple DXF entities: + + - INSERT + - DIMENSION + - LEADER + - MLEADER + - MLINE + + Decomposition of XREF, UNDERLAY and ACAD_TABLE entities is not supported. + + This function does not apply the clipping path created by the XCLIP command. + The function returns all entities and ignores the clipping path polygon and no + entity is clipped. + + """ + for entity in entities: + if isinstance(entity, Insert): + # TODO: emit internal XCLIP marker entity? + if entity.mcount > 1: + yield from recursive_decompose(entity.multi_insert()) + else: + yield from entity.attribs + yield from recursive_decompose(virtual_entities(entity)) + # has a required __virtual_entities__() to be rendered? + elif isinstance(entity, SupportsVirtualEntities): + # could contain block references: + yield from recursive_decompose(virtual_entities(entity)) + else: + yield entity + + +def to_primitives( + entities: Iterable[DXFEntity], + max_flattening_distance: Optional[float] = None, +) -> Iterable[Primitive]: + """Yields all DXF entities as path or mesh primitives. Yields + unsupported entities as empty primitives, see :func:`make_primitive`. + + Args: + entities: iterable of DXF entities + max_flattening_distance: override the default value + + """ + for e in entities: + yield make_primitive(e, max_flattening_distance) + + +def to_vertices(primitives: Iterable[Primitive]) -> Iterable[Vec3]: + """Yields all vertices from the given `primitives`. Paths will be flattened + to create the associated vertices. See also :func:`to_control_vertices` to + collect only the control vertices from the paths without flattening. + + """ + for p in primitives: + yield from p.vertices() + + +def to_paths(primitives: Iterable[Primitive]) -> Iterable[Path]: + """Yields all :class:`~ezdxf.path.Path` objects from the given + `primitives`. Ignores primitives without a defined path. + + """ + for prim in primitives: + if prim.path is not None: # lazy evaluation! + yield prim.path + + +def to_meshes(primitives: Iterable[Primitive]) -> Iterable[MeshBuilder]: + """Yields all :class:`~ezdxf.render.MeshBuilder` objects from the given + `primitives`. Ignores primitives without a defined mesh. + + """ + for prim in primitives: + if prim.mesh is not None: + yield prim.mesh + + +def to_control_vertices(primitives: Iterable[Primitive]) -> Iterable[Vec3]: + """Yields all path control vertices and all mesh vertices from the given + `primitives`. Like :func:`to_vertices`, but without flattening. + + """ + for prim in primitives: + # POINT has only a start point and yields from vertices()! + if prim.path: + yield from prim.path.control_vertices() + else: + yield from prim.vertices() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/document.py b/.venv/lib/python3.12/site-packages/ezdxf/document.py new file mode 100644 index 0000000..28c34a4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/document.py @@ -0,0 +1,1477 @@ +# Copyright (c) 2011-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + TextIO, + BinaryIO, + Iterable, + Iterator, + Union, + Callable, + cast, + Optional, + Sequence, + Any, +) +import abc +import base64 +import io +import logging +import os +import pathlib +from datetime import datetime, timezone +from itertools import chain + +import ezdxf +from ezdxf.audit import Auditor +from ezdxf.entities.dxfgroups import GroupCollection +from ezdxf.entities.material import MaterialCollection +from ezdxf.entities.mleader import MLeaderStyleCollection +from ezdxf.entities.mline import MLineStyleCollection +from ezdxf.entitydb import EntityDB +from ezdxf.groupby import groupby +from ezdxf.layouts import Modelspace, Paperspace +from ezdxf.layouts.layouts import Layouts +from ezdxf.lldxf import const +from ezdxf.lldxf.const import ( + BLK_XREF, + BLK_EXTERNAL, + DXF13, + DXF14, + DXF2000, + DXF2007, + DXF12, + DXF2013, +) +from ezdxf.lldxf import loader +from ezdxf.lldxf.tagwriter import ( + AbstractTagWriter, + TagWriter, + BinaryTagWriter, + JSONTagWriter, +) +from ezdxf.query import EntityQuery +from ezdxf.render.dimension import DimensionRenderer +from ezdxf.sections.acdsdata import AcDsDataSection, new_acds_data_section +from ezdxf.sections.blocks import BlocksSection +from ezdxf.sections.classes import ClassesSection +from ezdxf.sections.entities import EntitySection, StoredSection +from ezdxf.sections.header import HeaderSection +from ezdxf.sections.objects import ObjectsSection +from ezdxf.sections.tables import TablesSection +from ezdxf.tools import guid +from ezdxf.tools.codepage import tocodepage, toencoding +from ezdxf.tools.juliandate import juliandate +from ezdxf.tools.text import safe_string, MAX_STR_LEN +from ezdxf import messenger, msgtypes + + +logger = logging.getLogger("ezdxf") + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity, Layer, VPort, Dictionary + from ezdxf.eztypes import GenericLayoutType + from ezdxf.layouts import Layout + from ezdxf.lldxf.tags import Tags + from ezdxf.lldxf.types import DXFTag + from ezdxf.sections.tables import ( + LayerTable, + LinetypeTable, + TextstyleTable, + DimStyleTable, + AppIDTable, + UCSTable, + ViewTable, + ViewportTable, + BlockRecordTable, + ) + +CONST_GUID = "{00000000-0000-0000-0000-000000000000}" +CONST_MARKER_STRING = "0.0 @ 2000-01-01T00:00:00.000000+00:00" +CREATED_BY_EZDXF = "CREATED_BY_EZDXF" +WRITTEN_BY_EZDXF = "WRITTEN_BY_EZDXF" +EZDXF_META = "EZDXF_META" + + +def _validate_handle_seed(seed: str) -> str: + from ezdxf.tools.handle import START_HANDLE + + if seed is None: + seed = START_HANDLE + try: + v = int(seed, 16) + if v < 1: + seed = START_HANDLE + except ValueError: + seed = START_HANDLE + return seed + + +class Drawing: + def __init__(self, dxfversion=DXF2013) -> None: + self.entitydb = EntityDB() + self.messenger = messenger.Messenger(self) + target_dxfversion = dxfversion.upper() + self._dxfversion: str = const.acad_release_to_dxf_version.get( + target_dxfversion, target_dxfversion + ) + if self._dxfversion not in const.versions_supported_by_new: + raise const.DXFVersionError(f'Unsupported DXF version "{self.dxfversion}".') + # Store original dxf version if loaded (and maybe converted R13/14) + # from file. + self._loaded_dxfversion: Optional[str] = None + + # Status flag which is True while loading content from a DXF file: + self.is_loading = False + self.encoding: str = "cp1252" # read/write + self.filename: Optional[str] = None + + # Reason for using "type: ignore". + # I won't use "Optional" for the following attributes because these + # objects are required, just not yet! Setting up an empty DXF Document + # is not necessary if the document is read from the file system, + # see class-methods new() and read(). + + # named objects dictionary + self.rootdict: Dictionary = None # type: ignore + + # DXF sections + self.header: HeaderSection = None # type: ignore + self.classes: ClassesSection = None # type: ignore + self.tables: TablesSection = None # type: ignore + self.blocks: BlocksSection = None # type: ignore + self.entities: EntitySection = None # type: ignore + self.objects: ObjectsSection = None # type: ignore + + # DXF R2013 and later + self.acdsdata: AcDsDataSection = None # type: ignore + + self.stored_sections: list[StoredSection] = [] + self.layouts: Layouts = None # type: ignore + self.groups: GroupCollection = None # type: ignore + self.materials: MaterialCollection = None # type: ignore + self.mleader_styles: MLeaderStyleCollection = None # type: ignore + self.mline_styles: MLineStyleCollection = None # type: ignore + + # Set to False if the generated DXF file will be incompatible to AutoCAD + self._acad_compatible = True + # Store reasons for AutoCAD incompatibility: + self._acad_incompatibility_reason: set[str] = set() + + # DIMENSION rendering engine can be replaced by a custom Dimension + # render: see property Drawing.dimension_renderer + self._dimension_renderer = DimensionRenderer() + + # Some fixes can't be applied while the DXF document is not fully + # initialized, store this fixes as callable object: + self._post_init_commands: list[Callable] = [] + # Don't create any new entities here: + # New created handles could collide with handles loaded from DXF file. + assert len(self.entitydb) == 0 + + @classmethod + def new(cls, dxfversion: str = DXF2013) -> Drawing: + """Create new drawing. Package users should use the factory function + :func:`ezdxf.new`. (internal API) + """ + doc = cls(dxfversion) + doc._setup() + doc._create_ezdxf_metadata() + return doc + + def _setup(self): + self.header = HeaderSection.new() + self.classes = ClassesSection(self) + self.tables = TablesSection(self) + self.blocks = BlocksSection(self) + self.entities = EntitySection(self) + self.objects = ObjectsSection(self) + self.acdsdata = new_acds_data_section(self) + self.rootdict = self.objects.rootdict + # Create missing tables: + self.objects.setup_object_management_tables(self.rootdict) + self.layouts = Layouts.setup(self) + self._finalize_setup() + + def _finalize_setup(self): + """Common setup tasks for new and loaded DXF drawings.""" + self.groups = GroupCollection(self) + self.materials = MaterialCollection(self) + + self.mline_styles = MLineStyleCollection(self) + # all required internal structures are ready + # now do the stuff to please AutoCAD + self._create_required_table_entries() + + # mleader_styles requires text styles + self.mleader_styles = MLeaderStyleCollection(self) + self._set_required_layer_attributes() + self._setup_metadata() + self._execute_post_init_commands() + + def _execute_post_init_commands(self): + for cmd in self._post_init_commands: + cmd() + del self._post_init_commands + + def _create_required_table_entries(self): + self._create_required_vports() + self._create_required_linetypes() + self._create_required_layers() + self._create_required_styles() + self._create_required_appids() + self._create_required_dimstyles() + + def _set_required_layer_attributes(self): + for layer in self.layers: + layer.set_required_attributes() + + def _create_required_vports(self): + if "*Active" not in self.viewports: + self.viewports.new("*Active") + + def _create_required_appids(self): + if "ACAD" not in self.appids: + self.appids.new("ACAD") + + def _create_required_linetypes(self): + linetypes = self.linetypes + for name in ("ByBlock", "ByLayer", "Continuous"): + if name not in linetypes: + linetypes.new(name) + + def _create_required_dimstyles(self): + if "Standard" not in self.dimstyles: + self.dimstyles.new("Standard") + + def _create_required_styles(self): + if "Standard" not in self.styles: + self.styles.new("Standard") + + def _create_required_layers(self): + layers = self.layers + if "0" not in layers: + layers.new("0") + if "Defpoints" not in layers: + layers.new("Defpoints", dxfattribs={"plot": 0}) # do not plot + else: + # AutoCAD requires a plot flag = 0 + layers.get("Defpoints").dxf.plot = 0 + + def _setup_metadata(self): + self.header["$ACADVER"] = self.dxfversion + self.header["$TDCREATE"] = juliandate(datetime.now()) + if self.header.get("$FINGERPRINTGUID", CONST_GUID) == CONST_GUID: + self.reset_fingerprint_guid() + if self.header.get("$VERSIONGUID", CONST_GUID) == CONST_GUID: + self.reset_version_guid() + + @property + def dxfversion(self) -> str: + """Get current DXF version.""" + return self._dxfversion + + @dxfversion.setter + def dxfversion(self, version: str) -> None: + """Set current DXF version.""" + self._dxfversion = self._validate_dxf_version(version) + self.header["$ACADVER"] = version + + @property + def loaded_dxfversion(self) -> Optional[str]: + return self._loaded_dxfversion + + @property + def output_encoding(self): + """Returns required output encoding for writing document to a text + streams. + """ + return "utf-8" if self.dxfversion >= DXF2007 else self.encoding + + @property + def units(self) -> int: + """Get and set the document/modelspace base units as enum, for more + information read this: :ref:`dxf units`. Requires DXF R2000 or newer. + + """ + return self.header.get("$INSUNITS", 0) + + @units.setter + def units(self, unit_enum: int) -> None: + if 0 <= unit_enum < 25: + if self.dxfversion < DXF2000: + logger.warning( + "Drawing units ($INSUNITS) are not exported for DXF R12." + ) + self.header["$INSUNITS"] = unit_enum + else: + raise ValueError(f"Invalid units enum: {unit_enum}") + + def _validate_dxf_version(self, version: str) -> str: + version = version.upper() + # translates 'R12' -> 'AC1009' + version = const.acad_release_to_dxf_version.get(version, version) + if version not in const.versions_supported_by_save: + raise const.DXFVersionError(f'Unsupported DXF version "{version}".') + if version == DXF12: + if self._dxfversion > DXF12: + logger.warning( + f"Downgrade from DXF {self.acad_release} to R12 may create " + f"an invalid DXF file." + ) + elif version < self._dxfversion: + logger.info( + f"Downgrade from DXF {self.acad_release} to " + f"{const.acad_release[version]} can cause lost of features." + ) + return version + + def get_abs_filepath(self) -> pathlib.Path: + """Returns the absolute filepath of the document.""" + if not self.filename: + return pathlib.Path(".") + return pathlib.Path(self.filename).resolve() + + @classmethod + def read(cls, stream: TextIO) -> Drawing: + """Open an existing drawing. Package users should use the factory + function :func:`ezdxf.read`. To preserve possible binary data in + XRECORD entities use :code:`errors='surrogateescape'` as error handler + for the import stream. + + Args: + stream: text stream yielding text (unicode) strings by readline() + + """ + from .lldxf.tagger import ascii_tags_loader + + tag_loader = ascii_tags_loader(stream) + return cls.load(tag_loader) + + @classmethod + def load(cls, tag_loader: Iterable[DXFTag]) -> Drawing: + """Load DXF document from a DXF tag loader, in general an external + untrusted source. + + Args: + tag_loader: DXF tag loader + + """ + from .lldxf.tagger import tag_compiler + + tag_loader = tag_compiler(tag_loader) # type: ignore + doc = cls() + doc._load(tag_loader) + return doc + + @classmethod + def from_tags(cls, compiled_tags: Iterable[DXFTag]) -> Drawing: + """Create new drawing from compiled tags. (internal API)""" + doc = cls() + doc._load(tagger=compiled_tags) + return doc + + def _load(self, tagger: Iterable[DXFTag]) -> None: + # 1st Loading stage: load complete DXF entity structure + self.is_loading = True + sections = loader.load_dxf_structure(tagger) + if "THUMBNAILIMAGE" in sections: + del sections["THUMBNAILIMAGE"] + self._load_section_dict(sections) + + def _load_section_dict(self, sections: loader.SectionDict) -> None: + """Internal API to load a DXF document from a section dict.""" + self.is_loading = True + # Create header section: + header_entities: list[Tags] = sections.get("HEADER", []) # type: ignore + if header_entities: + # All header tags are the first DXF structure entity + self.header = HeaderSection.load(header_entities[0]) + else: + # Create default header, files without header are by default DXF R12 + self.header = HeaderSection.new(dxfversion=DXF12) + self._dxfversion = self.header.get("$ACADVER", DXF12) + + # Store original DXF version of loaded file. + self._loaded_dxfversion = self._dxfversion + + # Content encoding: + self.encoding = toencoding(self.header.get("$DWGCODEPAGE", "ANSI_1252")) + + # Set handle seed: + seed: str = self.header.get("$HANDSEED", str(self.entitydb.handles)) + self.entitydb.handles.reset(_validate_handle_seed(seed)) + + # Store all necessary DXF entities in the entity database: + loader.load_and_bind_dxf_content(sections, self) + + # End of 1. loading stage, all entities of the DXF file are + # stored in the entity database. + + # Create sections: + self.classes = ClassesSection( + self, sections.get("CLASSES", None) # type: ignore + ) + self.tables = TablesSection(self, sections.get("TABLES", None)) # type: ignore + + # Create *Model_Space and *Paper_Space BLOCK_RECORDS + # BlockSection setup takes care about the rest: + self._create_required_block_records() + + # At this point all table entries are required: + self.blocks = BlocksSection(self, sections.get("BLOCKS", None)) # type: ignore + self.entities = EntitySection( + self, sections.get("ENTITIES", None) # type: ignore + ) + self.objects = ObjectsSection( + self, sections.get("OBJECTS", None) # type: ignore + ) + + # only DXF R2013+ + self.acdsdata = AcDsDataSection( + self, sections.get("ACDSDATA", None) # type: ignore + ) + + # Store unmanaged sections as raw tags: + for name, data in sections.items(): + if name not in const.MANAGED_SECTIONS: + self.stored_sections.append(StoredSection(data)) # type: ignore + + # Objects section is not initialized! + self._2nd_loading_stage() + + # DXF version upgrades: + if self.dxfversion < DXF12: + logger.info("DXF version upgrade to DXF R12.") + self.dxfversion = DXF12 + + if self.dxfversion == DXF12: + self.tables.create_table_handles() + + if self.dxfversion in (DXF13, DXF14): + logger.info("DXF version upgrade to DXF R2000.") + self.dxfversion = DXF2000 + self.create_all_arrow_blocks() + + # Objects section setup: + rootdict = self.objects.rootdict + if rootdict.DXFTYPE != "DICTIONARY": + raise const.DXFStructureError( + f"invalid root dictionary entity {str(rootdict)} " + ) + self.rootdict = rootdict + + # Create missing management tables (DICTIONARY): + self.objects.setup_object_management_tables(self.rootdict) + + # Setup modelspace- and paperspace layouts: + self.layouts = Layouts.load(self) + + # Additional work is common to the new and load process: + self.is_loading = False + self._finalize_setup() + + def _2nd_loading_stage(self): + """Load additional resources from entity database into DXF entities. + + e.g. convert handles into DXFEntity() objects + + """ + db = self.entitydb + for entity in db.values(): + # The post_load_hook() can return a callable, which should be + # executed, when the DXF document is fully initialized. + cmd = entity.post_load_hook(self) + if cmd is not None: + self._post_init_commands.append(cmd) + + def create_all_arrow_blocks(self): + """For upgrading DXF R12/13/14 files to R2000, it is necessary to + create all used arrow blocks before saving the DXF file, else $HANDSEED + is not the next available handle, which is a problem for AutoCAD. + + Create all known AutoCAD arrows to be on the safe side, because + references to arrow blocks can be in DIMSTYLE, DIMENSION override, + LEADER override and maybe other locations. + + """ + from ezdxf.render.arrows import ARROWS + + for arrow_name in ARROWS.__acad__: + ARROWS.create_block(self.blocks, arrow_name) + + def _create_required_block_records(self): + if "*Model_Space" not in self.block_records: + self.block_records.new("*Model_Space") + if "*Paper_Space" not in self.block_records: + self.block_records.new("*Paper_Space") + + def saveas( + self, + filename: Union[os.PathLike, str], + encoding: Optional[str] = None, + fmt: str = "asc", + ) -> None: + """Set :class:`Drawing` attribute :attr:`filename` to `filename` and + write drawing to the file system. Override file encoding by argument + `encoding`, handle with care, but this option allows you to create DXF + files for applications that handles file encoding different than + AutoCAD. + + Args: + filename: file name as string + encoding: override default encoding as Python encoding string like ``'utf-8'`` + fmt: ``'asc'`` for ASCII DXF (default) or ``'bin'`` for Binary DXF + + """ + self.filename = str(filename) + self.save(encoding=encoding, fmt=fmt) + + def save(self, encoding: Optional[str] = None, fmt: str = "asc") -> None: + """Write drawing to file-system by using the :attr:`filename` attribute + as filename. Override file encoding by argument `encoding`, handle with + care, but this option allows you to create DXF files for applications + that handle file encoding different from AutoCAD. + + Args: + encoding: override default encoding as Python encoding string like ``'utf-8'`` + fmt: ``'asc'`` for ASCII DXF (default) or ``'bin'`` for Binary DXF + + """ + # DXF R12, R2000, R2004 - ASCII encoding + # DXF R2007 and newer - UTF-8 encoding + # in ASCII mode, unknown characters will be escaped as \U+nnnn unicode + # characters. + + if encoding is None: + enc = self.output_encoding + else: + # override default encoding, for applications that handle encoding + # different than AutoCAD + enc = encoding + + if fmt.startswith("asc"): + fp = io.open( + self.filename, mode="wt", encoding=enc, errors="dxfreplace" # type: ignore + ) + elif fmt.startswith("bin"): + fp = open(self.filename, "wb") # type: ignore + else: + raise ValueError(f"Unknown output format: '{fmt}'.") + try: + self.write(fp, fmt=fmt) # type: ignore + finally: + fp.close() + + def encode(self, s: str) -> bytes: + """Encode string `s` with correct encoding and error handler.""" + return s.encode(encoding=self.output_encoding, errors="dxfreplace") + + def write(self, stream: Union[TextIO, BinaryIO], fmt: str = "asc") -> None: + """Write drawing as ASCII DXF to a text stream or as Binary DXF to a + binary stream. For DXF R2004 (AC1018) and prior open stream with + drawing :attr:`encoding` and :code:`mode='wt'`. For DXF R2007 (AC1021) + and later use :code:`encoding='utf-8'`, or better use the later added + :class:`Drawing` property :attr:`output_encoding` which returns the + correct encoding automatically. The correct and required error handler + is :code:`errors='dxfreplace'`! + + If writing to a :class:`StringIO` stream, use :meth:`Drawing.encode` to + encode the result string from :meth:`StringIO.get_value`:: + + binary = doc.encode(stream.get_value()) + + Args: + stream: output text stream or binary stream + fmt: "asc" for ASCII DXF (default) or "bin" for binary DXF + + """ + # These changes may alter the document content (create new entities, blocks ...) + # and have to be done before the export and the update of internal structures + # can be done. + self.commit_pending_changes() + + dxfversion = self.dxfversion + if dxfversion == DXF12: + handles = bool(self.header.get("$HANDLING", 0)) + else: + handles = True + if dxfversion > DXF12: + self.classes.add_required_classes(dxfversion) + + self.update_all() + if fmt.startswith("asc"): + tagwriter = TagWriter( + stream, # type: ignore + write_handles=handles, + dxfversion=dxfversion, + ) + elif fmt.startswith("bin"): + tagwriter = BinaryTagWriter( # type: ignore + stream, # type: ignore + write_handles=handles, + dxfversion=dxfversion, + encoding=self.output_encoding, + ) + tagwriter.write_signature() # type: ignore + else: + raise ValueError(f"Unknown output format: '{fmt}'.") + + self.export_sections(tagwriter) + + def encode_base64(self) -> bytes: + """Returns DXF document as base64 encoded binary data.""" + stream = io.StringIO() + self.write(stream) + # Create binary data: + binary_data = self.encode(stream.getvalue()) + # Create Windows line endings and do base64 encoding: + return base64.encodebytes(binary_data.replace(b"\n", b"\r\n")) + + def export_sections(self, tagwriter: AbstractTagWriter) -> None: + """DXF export sections. (internal API)""" + dxfversion = tagwriter.dxfversion + self.header.export_dxf(tagwriter) + if dxfversion > DXF12: + self.classes.export_dxf(tagwriter) + self.tables.export_dxf(tagwriter) + self.blocks.export_dxf(tagwriter) + self.entities.export_dxf(tagwriter) + if dxfversion > DXF12: + self.objects.export_dxf(tagwriter) + if self.acdsdata.is_valid: + self.acdsdata.export_dxf(tagwriter) + for section in self.stored_sections: + section.export_dxf(tagwriter) + + tagwriter.write_tag2(0, "EOF") + + def commit_pending_changes(self) -> None: + self.messenger.broadcast(msgtypes.COMMIT_PENDING_CHANGES) + + def update_all(self) -> None: + if self.dxfversion > DXF12: + self.classes.add_required_classes(self.dxfversion) + self._create_appids() + self._update_header_vars() + self.update_extents() + self.update_limits() + self._update_metadata() + + def update_extents(self): + msp = self.modelspace() + # many applications not maintain these values + extmin = msp.dxf.extmin + extmax = msp.dxf.extmax + if bool(extmin) and bool(extmax): + self.header["$EXTMIN"] = extmin + self.header["$EXTMAX"] = extmax + active_layout = self.active_layout() + self.header["$PEXTMIN"] = active_layout.dxf.extmin + self.header["$PEXTMAX"] = active_layout.dxf.extmax + + def update_limits(self): + msp = self.modelspace() + self.header["$LIMMIN"] = msp.dxf.limmin + self.header["$LIMMAX"] = msp.dxf.limmax + active_layout = self.active_layout() + self.header["$PLIMMIN"] = active_layout.dxf.limmin + self.header["$PLIMMAX"] = active_layout.dxf.limmax + + def _update_header_vars(self): + from ezdxf.lldxf.const import acad_maint_ver + + # set or correct $CMATERIAL handle + material = self.entitydb.get(self.header.get("$CMATERIAL", None)) + if material is None or material.dxftype() != "MATERIAL": + handle = "0" + if "ByLayer" in self.materials: + handle = self.materials.get("ByLayer").dxf.handle + elif "Global" in self.materials: + handle = self.materials.get("Global").dxf.handle + self.header["$CMATERIAL"] = handle + # set ACAD maintenance version - same values as used by BricsCAD + self.header["$ACADMAINTVER"] = acad_maint_ver.get(self.dxfversion, 0) + + def _update_metadata(self): + self._update_ezdxf_metadata() + if ezdxf.options.write_fixed_meta_data_for_testing: + fixed_date = juliandate(datetime(2000, 1, 1, 0, 0)) + self.header["$TDCREATE"] = fixed_date + self.header["$TDUCREATE"] = fixed_date + self.header["$TDUPDATE"] = fixed_date + self.header["$TDUUPDATE"] = fixed_date + self.header["$VERSIONGUID"] = CONST_GUID + self.header["$FINGERPRINTGUID"] = CONST_GUID + else: + now = datetime.now() + self.header["$TDUPDATE"] = juliandate(now) + self.reset_version_guid() + self.header["$HANDSEED"] = str(self.entitydb.handles) # next handle + self.header["$DWGCODEPAGE"] = tocodepage(self.encoding) + + def ezdxf_metadata(self) -> MetaData: + """Returns the *ezdxf* :class:`ezdxf.document.MetaData` object, which + manages *ezdxf* and custom metadata in DXF files. + For more information see: :ref:`ezdxf_metadata`. + + """ + return R12MetaData(self) if self.dxfversion <= DXF12 else R2000MetaData(self) + + def _create_ezdxf_metadata(self): + ezdxf_meta = self.ezdxf_metadata() + ezdxf_meta[CREATED_BY_EZDXF] = ezdxf_marker_string() + + def _update_ezdxf_metadata(self): + ezdxf_meta = self.ezdxf_metadata() + ezdxf_meta[WRITTEN_BY_EZDXF] = ezdxf_marker_string() + + def _create_appid_if_not_exist(self, name: str, flags: int = 0) -> None: + if name not in self.appids: + self.appids.new(name, {"flags": flags}) + + def _create_appids(self): + self._create_appid_if_not_exist("HATCHBACKGROUNDCOLOR", 0) + self._create_appid_if_not_exist("EZDXF", 0) + + @property + def acad_release(self) -> str: + """Returns the AutoCAD release abbreviation like "R12" or "R2000".""" + return const.acad_release.get(self.dxfversion, "unknown") + + @property + def layers(self) -> LayerTable: + return self.tables.layers + + @property + def linetypes(self) -> LinetypeTable: + return self.tables.linetypes + + @property + def styles(self) -> TextstyleTable: + return self.tables.styles + + @property + def dimstyles(self) -> DimStyleTable: + return self.tables.dimstyles + + @property + def ucs(self) -> UCSTable: + return self.tables.ucs + + @property + def appids(self) -> AppIDTable: + return self.tables.appids + + @property + def views(self) -> ViewTable: + return self.tables.views + + @property + def block_records(self) -> BlockRecordTable: + return self.tables.block_records + + @property + def viewports(self) -> ViewportTable: + return self.tables.viewports + + @property + def plotstyles(self) -> Dictionary: + return self.rootdict["ACAD_PLOTSTYLENAME"] # type: ignore + + @property + def dimension_renderer(self) -> DimensionRenderer: + return self._dimension_renderer + + @dimension_renderer.setter + def dimension_renderer(self, renderer: DimensionRenderer) -> None: + """ + Set your own dimension line renderer if needed. + + see also: ezdxf.render.dimension + + """ + self._dimension_renderer = renderer + + def modelspace(self) -> Modelspace: + r"""Returns the modelspace layout, displayed as "Model" tab in CAD + applications, defined by block record named "\*Model_Space". + """ + return self.layouts.modelspace() + + def layout(self, name: str = "") -> Layout: + """Returns paperspace layout `name` or the first layout in tab-order + if no name is given. + + Args: + name: paperspace name or empty string for the first paperspace in + tab-order + + Raises: + KeyError: layout `name` does not exist + + """ + return self.layouts.get(name) + + def paperspace(self, name: str = "") -> Paperspace: + """Returns paperspace layout `name` or the active paperspace if no + name is given. + + Args: + name: paperspace name or empty string for the active paperspace + + Raises: + KeyError: if the modelspace was acquired or layout `name` does not exist + + """ + if name: + psp = self.layouts.get(name) + if isinstance(psp, Paperspace): + return psp + raise KeyError("use method modelspace() to acquire the modelspace.") + else: + return self.active_layout() + + def active_layout(self) -> Paperspace: + r"""Returns the active paperspace layout, defined by block record name + "\*Paper_Space". + """ + return self.layouts.active_layout() + + def layout_names(self) -> Iterable[str]: + """Returns all layout names in arbitrary order.""" + return list(self.layouts.names()) + + def layout_names_in_taborder(self) -> Iterable[str]: + """Returns all layout names in tab-order, "Model" is always the first name.""" + return list(self.layouts.names_in_taborder()) + + def reset_fingerprint_guid(self): + """Reset fingerprint GUID.""" + self.header["$FINGERPRINTGUID"] = guid() + + def reset_version_guid(self): + """Reset version GUID.""" + self.header["$VERSIONGUID"] = guid() + + @property + def is_acad_compatible(self) -> bool: + """Returns ``True`` if the current state of the document is compatible to + AutoCAD. + """ + return self._acad_compatible + + @property + def acad_incompatibility_reasons(self) -> list[str]: + """Returns a list of reasons why this document is not compatible to AutoCAD.""" + return list(self._acad_incompatibility_reason) + + def add_acad_incompatibility_message(self, msg: str): + """Add a reason why this document is not compatible to AutoCAD. + (internal API) + """ + self._acad_compatible = False + if msg not in self._acad_incompatibility_reason: + self._acad_incompatibility_reason.add(msg) + logger.warning(f"DXF document is not compatible to AutoCAD! {msg}.") + + def query(self, query: str = "*") -> EntityQuery: + """Entity query over all layouts and blocks, excluding the OBJECTS section and + the resource tables of the TABLES section. + + Args: + query: query string + + .. seealso:: + + :ref:`entity query string` and :ref:`entity queries` + + """ + return EntityQuery(self.chain_layouts_and_blocks(), query) + + def groupby(self, dxfattrib="", key=None) -> dict: + """Groups DXF entities of all layouts and blocks (excluding the + OBJECTS section) by a DXF attribute or a key function. + + Args: + dxfattrib: grouping DXF attribute like "layer" + key: key function, which accepts a :class:`DXFEntity` as argument + and returns a hashable grouping key or ``None`` to ignore + this entity. + + .. seealso:: + + :func:`~ezdxf.groupby.groupby` documentation + + """ + return groupby(self.chain_layouts_and_blocks(), dxfattrib, key) + + def chain_layouts_and_blocks(self) -> Iterator[DXFEntity]: + """Chain entity spaces of all layouts and blocks. Yields an iterator + for all entities in all layouts and blocks. + """ + layouts = list(self.layouts_and_blocks()) + return chain.from_iterable(layouts) + + def layouts_and_blocks(self) -> Iterator[GenericLayoutType]: + """Iterate over all layouts (modelspace and paperspace) and all block definitions.""" + return iter(self.blocks) + + def delete_layout(self, name: str) -> None: + """Delete paper space layout `name` and all entities owned by this layout. + Available only for DXF R2000 or later, DXF R12 supports only one + paperspace, and it can't be deleted. + """ + if name not in self.layouts: + raise const.DXFValueError(f"Layout '{name}' does not exist.") + else: + self.layouts.delete(name) + + def new_layout(self, name, dxfattribs=None) -> Paperspace: + """Create a new paperspace layout `name`. Returns a :class:`~ezdxf.layouts.Paperspace` + object. DXF R12 (AC1009) supports only one paperspace layout, only the active + paperspace layout is saved, other layouts are dismissed. + + Args: + name: unique layout name + dxfattribs: additional DXF attributes for the + :class:`~ezdxf.entities.layout.DXFLayout` entity + + Raises: + DXFValueError: paperspace layout `name` already exist + + """ + if name in self.layouts: + raise const.DXFValueError(f"Layout '{name}' already exists.") + else: + return self.layouts.new(name, dxfattribs) + + def page_setup( + self, + name: str = "Layout1", + fmt: str = "ISO A3", + landscape=True, + ) -> Paperspace: + """Creates a new paperspace layout if `name` does not exist or reset the + existing layout. This method requires DXF R2000 or newer. + The paper format name `fmt` defines one of the following paper sizes, + measures in landscape orientation: + + =========== ======= ======= ======= + Name Units Width Height + =========== ======= ======= ======= + ISO A0 mm 1189 841 + ISO A1 mm 841 594 + ISO A2 mm 594 420 + ISO A3 mm 420 297 + ISO A4 mm 297 210 + ANSI A inch 11 8.5 + ANSI B inch 17 11 + ANSI C inch 22 17 + ANSI D inch 34 22 + ANSI E inch 44 34 + ARCH C inch 24 18 + ARCH D inch 36 24 + ARCH E inch 48 36 + ARCH E1 inch 42 30 + Letter inch 11 8.5 + Legal inch 14 8.5 + =========== ======= ======= ======= + + The layout uses the associated units of the paper format as drawing + units, has no margins or offset defined and the scale of the paperspace + layout is 1:1. + + Args: + name: paperspace layout name + fmt: paper format + landscape: ``True`` for landscape orientation, ``False`` for portrait + orientation + + """ + from ezdxf.tools.standards import PAGE_SIZES + + if self.acad_release == "R12": + raise const.DXFVersionError("method call no supported for DXF R12") + width: float + height: float + try: + units, width, height = PAGE_SIZES[fmt] + except KeyError: + raise ValueError(f"unknown paper format: {fmt}") + if not landscape: + width, height = height, width + try: + psp = self.paperspace(name) + except KeyError: + psp = self.new_layout(name) + + psp.page_setup(size=(width, height), margins=(0, 0, 0, 0), units=units) + return psp + + def acquire_arrow(self, name: str): + """For standard AutoCAD and ezdxf arrows create block definitions if + required, otherwise check if block `name` exist. (internal API) + + """ + from ezdxf.render.arrows import ARROWS + + if ARROWS.is_acad_arrow(name) or ARROWS.is_ezdxf_arrow(name): + ARROWS.create_block(self.blocks, name) + elif name not in self.blocks: + raise const.DXFValueError(f'Arrow block "{name}" does not exist.') + + def add_image_def(self, filename: str, size_in_pixel: tuple[int, int], name=None): + """Add an image definition to the objects section. + + Add an :class:`~ezdxf.entities.image.ImageDef` entity to the drawing + (objects section). `filename` is the image file name as relative or + absolute path and `size_in_pixel` is the image size in pixel as (x, y) + tuple. To avoid dependencies to external packages, `ezdxf` can not + determine the image size by itself. Returns a + :class:`~ezdxf.entities.image.ImageDef` entity which is needed to + create an image reference. `name` is the internal image name, if set to + ``None``, name is auto-generated. + + Absolute image paths works best for AutoCAD but not perfect, you + have to update external references manually in AutoCAD, which is not + possible in TrueView. If the drawing units differ from 1 meter, you + also have to use: :meth:`set_raster_variables`. + + Args: + filename: image file name (absolute path works best for AutoCAD) + size_in_pixel: image size in pixel as (x, y) tuple + name: image name for internal use, None for using filename as name + (best for AutoCAD) + + .. seealso:: + + :ref:`tut_image` + + """ + if "ACAD_IMAGE_VARS" not in self.rootdict: + self.objects.set_raster_variables(frame=0, quality=1, units="m") + if name is None: + name = filename + return self.objects.add_image_def(filename, size_in_pixel, name) + + def set_raster_variables(self, frame: int = 0, quality: int = 1, units: str = "m"): + """Set raster variables. + + Args: + frame: 0 = do not show image frame; 1 = show image frame + quality: 0 = draft; 1 = high + units: units for inserting images. This defines the real world unit + for one drawing unit for the purpose of inserting and scaling + images with an associated resolution. + + ===== =========================== + mm Millimeter + cm Centimeter + m Meter (ezdxf default) + km Kilometer + in Inch + ft Foot + yd Yard + mi Mile + ===== =========================== + + """ + self.objects.set_raster_variables(frame=frame, quality=quality, units=units) + + def set_wipeout_variables(self, frame=0): + """Set wipeout variables. + + Args: + frame: 0 = do not show image frame; 1 = show image frame + + """ + self.objects.set_wipeout_variables(frame=frame) + var_dict = self.rootdict.get_required_dict("AcDbVariableDictionary") + var_dict.set_or_add_dict_var("WIPEOUTFRAME", str(frame)) + + def add_underlay_def( + self, filename: str, fmt: str = "ext", name: Optional[str] = None + ): + """Add an :class:`~ezdxf.entities.underlay.UnderlayDef` entity to the drawing + (OBJECTS section). The `filename` is the underlay file name as relative or + absolute path and `fmt` as string (pdf, dwf, dgn). + The underlay definition is required to create an underlay reference. + + Args: + filename: underlay file name + fmt: file format as string "pdf"|"dwf"|"dgn" or "ext" + for getting file format from filename extension + name: pdf format = page number to display; dgn format = "default"; dwf: ???? + + .. seealso:: + + :ref:`tut_underlay` + + """ + if fmt == "ext": + fmt = filename[-3:] + return self.objects.add_underlay_def(filename, fmt, name) + + def add_xref_def( + self, filename: str, name: str, flags: int = BLK_XREF | BLK_EXTERNAL + ): + """Add an external reference (xref) definition to the blocks section. + + Args: + filename: external reference filename + name: name of the xref block + flags: block flags + + """ + self.blocks.new(name=name, dxfattribs={"flags": flags, "xref_path": filename}) + + def audit(self) -> Auditor: + """Checks document integrity and fixes all fixable problems, not + fixable problems are stored in :attr:`Auditor.errors`. + + If you are messing around with internal structures, call this method + before saving to be sure to export valid DXF documents, but be aware + this is a long-running task. + + """ + auditor = Auditor(self) + auditor.run() + return auditor + + def validate(self, print_report=True) -> bool: + """Simple way to run an audit process. Fixes all fixable problems, + return ``False`` if not fixable errors occurs. Prints a report of resolved and + unrecoverable errors, if requested. + + Args: + print_report: print report to stdout + + Returns: ``False`` if unrecoverable errors exist + + """ + auditor = self.audit() + if print_report: + auditor.print_fixed_errors() + auditor.print_error_report() + if not self.is_acad_compatible: + print("DXF document is not AutoCAD compatible:") + for msg in self.acad_incompatibility_reasons: + print(msg) + return len(auditor.errors) == 0 + + def set_modelspace_vport(self, height, center=(0, 0), *, dxfattribs=None) -> VPort: + r"""Set initial view/zoom location for the modelspace, this replaces + the current "\*Active" viewport configuration + (:class:`~ezdxf.entities.VPort`) and reset the coordinate system to the + :ref:`WCS`. + + Args: + height: modelspace area to view + center: modelspace location to view in the center of the CAD + application window. + dxfattribs: additional DXF attributes for the VPORT entity + + """ + self.viewports.delete_config("*Active") + dxfattribs = dict(dxfattribs or {}) + vport = cast("VPort", self.viewports.new("*Active", dxfattribs=dxfattribs)) + vport.dxf.center = center + vport.dxf.height = height + vport.reset_wcs() + self.header.reset_wcs() + return vport + + +class MetaData(abc.ABC): + """Manage ezdxf meta-data by dict-like interface. Values are limited to + strings with a maximum length of 254 characters. + """ + + @abc.abstractmethod + def __getitem__(self, key: str) -> str: + """Returns the value for self[`key`]. + + Raises: + KeyError: `key` does not exist + """ + ... + + def get(self, key: str, default: str = "") -> str: + """Returns the value for `key`. Returns `default` if `key` not exist.""" + try: + return self.__getitem__(key) + except KeyError: + return safe_string(default, MAX_STR_LEN) + + @abc.abstractmethod + def __setitem__(self, key: str, value: str) -> None: + """Set self[`key`] to `value`.""" + ... + + @abc.abstractmethod + def __delitem__(self, key: str) -> None: + """Delete self[`key`]. + + Raises: + KeyError: `key` does not exist + """ + ... + + @abc.abstractmethod + def __contains__(self, key: str) -> bool: + """Returns `key` ``in`` self.""" + ... + + def discard(self, key: str) -> None: + """Remove `key`, does **not** raise an exception if `key` not exist.""" + try: + self.__delitem__(key) + except KeyError: + pass + + +def ezdxf_marker_string(): + if ezdxf.options.write_fixed_meta_data_for_testing: + return CONST_MARKER_STRING + else: + now = datetime.now(tz=timezone.utc) + return ezdxf.__version__ + " @ " + now.isoformat() + + +class R12MetaData(MetaData): + """Manage ezdxf meta data for DXF version R12 as XDATA of layer "0". + + Layer "0" is mandatory and can not be deleted. + + """ + + def __init__(self, doc: Drawing): + # storing XDATA in layer 0 does not work (Autodesk!) + self._msp_block = doc.modelspace().block_record.block + self._data = self._load() + + def __contains__(self, key: str) -> bool: + return safe_string(key, MAX_STR_LEN) in self._data + + def __getitem__(self, key: str) -> str: + return self._data[safe_string(key, MAX_STR_LEN)] + + def __setitem__(self, key: str, value: str) -> None: + self._data[safe_string(key)] = safe_string(value, MAX_STR_LEN) + self._commit() + + def __delitem__(self, key: str) -> None: + del self._data[safe_string(key, MAX_STR_LEN)] + self._commit() + + def _commit(self) -> None: + # write all metadata as strings with group code 1000 + tags = [] + for key, value in self._data.items(): + tags.append((1000, str(key))) + tags.append((1000, str(value))) + self._msp_block.set_xdata("EZDXF", tags) # type: ignore + + def _load(self) -> dict: + data = dict() + if self._msp_block.has_xdata("EZDXF"): # type: ignore + xdata = self._msp_block.get_xdata("EZDXF") # type: ignore + index = 0 + count = len(xdata) - 1 + while index < count: + name = xdata[index].value + data[name] = xdata[index + 1].value + index += 2 + return data + + +class R2000MetaData(MetaData): + """Manage ezdxf metadata for DXF version R2000+ as DICTIONARY object in + the rootdict. + """ + + def __init__(self, doc: Drawing): + self._data: Dictionary = doc.rootdict.get_required_dict( + EZDXF_META, hard_owned=True + ) + + def __contains__(self, key: str) -> bool: + return safe_string(key, MAX_STR_LEN) in self._data + + def __getitem__(self, key: str) -> str: + v = self._data[safe_string(key, MAX_STR_LEN)] + return v.dxf.get("value", "") + + def __setitem__(self, key: str, value: str) -> None: + self._data.set_or_add_dict_var( + safe_string(key, MAX_STR_LEN), safe_string(value, MAX_STR_LEN) + ) + + def __delitem__(self, key: str) -> None: + self._data.remove(safe_string(key, MAX_STR_LEN)) + + +def info(doc: Drawing, verbose=False, content=False, fmt="ASCII") -> list[str]: + from ezdxf.units import unit_name + from collections import Counter + + def count(entities, indent=" ") -> Iterator[str]: + counter: Counter = Counter() + for e in entities: + counter[e.dxftype()] += 1 + for name in sorted(counter.keys()): + yield f"{indent}{name} ({counter[name]})" + + def append_container(table, name: str, container="table"): + indent = " " + data.append(f"{name} {container} entries: {len(table)}") + if verbose: + if name == "STYLE": + names: list[str] = [] + for entry in table: + name = entry.dxf.name + if name == "": + names.append(f'{indent}*shape-file: "{entry.dxf.font}"') + else: + names.append(f"{indent}{name}") + else: + names = [f"{indent}{entry.dxf.name}" for entry in table] + names.sort() + data.extend(names) + + def user_vars(kind: str, indent="") -> Iterator[str]: + for i in range(5): + name = f"{kind}{i+1}" + if name in header: + yield f"{indent}{name}={header[name]}" + + def append_header_var(name: str, indent=""): + data.append(f"{indent}{name}: {header.get(name, '').strip()}") + + header = doc.header + loaded_dxf_version = doc.loaded_dxfversion + if loaded_dxf_version is None: + loaded_dxf_version = doc.dxfversion + data: list[str] = [] + data.append(f'Filename: "{doc.filename}"') + data.append(f"Format: {fmt}") + if loaded_dxf_version != doc.dxfversion: + msg = f"Loaded content was upgraded from DXF Version {loaded_dxf_version}" + release = const.acad_release.get(loaded_dxf_version, "") + if release: + msg += f" ({release})" + data.append(msg) + data.append(f"Release: {doc.acad_release}") + data.append(f"DXF Version: {doc.dxfversion}") + if verbose: + data.append( + f"Maintenance Version: {header.get('$ACADMAINTVER', '')}" + ) + data.append(f"Codepage: {header.get('$DWGCODEPAGE', 'ANSI_1252')}") + data.append(f"Encoding: {doc.output_encoding}") + data.append("Layouts:") + data.extend([f" '{name}'" for name in doc.layout_names_in_taborder()]) + + measurement = "Metric" if header.get("$MEASUREMENT", 0) else "Imperial" + if verbose: + data.append(f"Unit system: {measurement}") + data.append(f"Modelspace units: {unit_name(doc.units)}") + append_header_var("$LASTSAVEDBY") + append_header_var("$HANDSEED") + append_header_var("$FINGERPRINTGUID") + append_header_var("$VERSIONGUID") + data.extend(user_vars(kind="$USERI")) + data.extend(user_vars(kind="$USERR")) + for name, value in header.custom_vars: + data.append(f'Custom property "{name}": "{value}"') + + ezdxf_metadata = doc.ezdxf_metadata() + if CREATED_BY_EZDXF in ezdxf_metadata: + data.append(f"Created by ezdxf: {ezdxf_metadata.get(CREATED_BY_EZDXF)}") + elif verbose: + data.append("File was not created by ezdxf >= 0.16.4") + if WRITTEN_BY_EZDXF in ezdxf_metadata: + data.append(f"Written by ezdxf: {ezdxf_metadata.get(WRITTEN_BY_EZDXF)}") + elif verbose: + data.append("File was not written by ezdxf >= 0.16.4") + if content: + data.append("Content stats:") + append_container(doc.layers, "LAYER") + append_container(doc.linetypes, "LTYPE") + append_container(doc.styles, "STYLE") + append_container(doc.dimstyles, "DIMSTYLE") + append_container(doc.appids, "APPID") + append_container(doc.ucs, "UCS") + append_container(doc.views, "VIEW") + append_container(doc.viewports, "VPORT") + append_container(doc.block_records, "BLOCK_RECORD") + if doc.dxfversion > DXF12: + append_container(list(doc.classes), "CLASS", container="section") + data.append(f"Entities in modelspace: {len(doc.modelspace())}") + if verbose: + data.extend(count(doc.modelspace())) + + data.append(f"Entities in OBJECTS section: {len(doc.objects)}") + if verbose: + data.extend(count(doc.objects)) + + unknown_entities = _get_unknown_entities(doc) + if len(unknown_entities): + data.append(f"Unknown/unsupported entities: {len(unknown_entities)}") + if verbose: + data.extend(count(unknown_entities)) + return data + + +def _get_unknown_entities(doc: Drawing) -> list[DXFEntity]: + from ezdxf.entities import DXFTagStorage, ACADProxyEntity, OLE2Frame + + data: list[DXFEntity] = [] + for entity in doc.entitydb.values(): + if isinstance(entity, (DXFTagStorage, ACADProxyEntity, OLE2Frame)): + data.append(entity) + return data + + +def custom_export(doc: Drawing, tagwriter: AbstractTagWriter): + """Export a DXF document via a custom tag writer.""" + dxfversion = doc.dxfversion + if dxfversion != DXF12: + tagwriter.write_handles = True + doc.update_all() + doc.export_sections(tagwriter) + + +def export_json_tags(doc: Drawing, compact=True) -> str: + """Export a DXF document as JSON formatted tags. + + The `compact` format is a list of ``[group-code, value]`` pairs where each pair is + a DXF tag. The group-code has to be an integer and the value has to be a string, + integer, float or list of floats for vertices. + + The `verbose` format (`compact` is ``False``) is a list of ``[group-code, value]`` + pairs where each pair is a 1:1 representation of a DXF tag. The group-code has to be + an integer and the value has to be a string. + + """ + stream = io.StringIO() + json_writer = JSONTagWriter(stream, dxfversion=doc.dxfversion, compact=compact) + custom_export(doc, json_writer) + return stream.getvalue() + + +def load_json_tags(data: Sequence[Any]) -> Drawing: + """Load DXF document from JSON formatted tags. + + The expected JSON format is a list of [group-code, value] pairs where each pair is + a DXF tag. The `compact` and the `verbose` format is supported. + + Args: + data: JSON data structure as a sequence of [group-code, value] pairs + + """ + from ezdxf.lldxf.tagger import json_tag_loader + + return Drawing.load(json_tag_loader(data)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/dwginfo.py b/.venv/lib/python3.12/site-packages/ezdxf/dwginfo.py new file mode 100644 index 0000000..e5dd11b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/dwginfo.py @@ -0,0 +1,27 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from typing import NamedTuple, Union +import os +from ezdxf.lldxf import const + + +class DWGInfo(NamedTuple): + version: str = "unknown" + release: str = "unknown" + + +def dwg_info(data: bytes) -> DWGInfo: + """Returns the version and release name of a DWG file.""" + if len(data) < 6: + return DWGInfo("invalid", "invalid") + version = data[:6].decode(errors="ignore") + if version[:4] != "AC10": + return DWGInfo("invalid", "invalid") + release = const.acad_release.get(version, "unknown") + return DWGInfo(version, release) + + +def dwg_file_info(file: Union[str, os.PathLike]) -> DWGInfo: + """Returns the version and release name of a DWG file.""" + with open(file, "rb") as fp: + return dwg_info(fp.read(6)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/dynblkhelper.py b/.venv/lib/python3.12/site-packages/ezdxf/dynblkhelper.py new file mode 100644 index 0000000..1a8c7c1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/dynblkhelper.py @@ -0,0 +1,70 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +""" +This module provides helper tools to work with dynamic blocks. + +The current state supports only reading information from dynamic blocks, it does not +support the creation of new dynamic blocks nor the modification of them. + +""" +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.entities import Insert +from ezdxf.lldxf import const + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.layouts import BlockLayout + from ezdxf.entities import BlockRecord + +AcDbDynamicBlockGUID = "AcDbDynamicBlockGUID" +AcDbBlockRepBTag = "AcDbBlockRepBTag" + + +def get_dynamic_block_definition( + insert: Insert, doc: Optional[Drawing] = None +) -> Optional[BlockLayout]: + """Returns the dynamic block definition if the given block reference is + referencing a dynamic block direct or indirect via an anonymous block. + Returns ``None`` otherwise. + """ + if doc is None: + doc = insert.doc + if doc is None: + return None + + block = doc.blocks.get(insert.dxf.name) + if block is None: + return None + + block_record = block.block_record + if is_dynamic_block_definition(block_record): + return block # direct dynamic block reference + + # is indirect dynamic block reference? + handle = get_dynamic_block_record_handle(block_record) + if not handle: + return None # lost reference to dynamic block definition + dyn_block_record = doc.entitydb.get(handle) + if dyn_block_record: + return doc.blocks.get(dyn_block_record.dxf.name) + return None + + +def is_dynamic_block_definition(block_record: BlockRecord) -> bool: + """Return ``True`` if the given block record is a dynamic block definition.""" + return block_record.has_xdata(AcDbDynamicBlockGUID) + + +def get_dynamic_block_record_handle(block_record: BlockRecord) -> str: + """Returns handle of the dynamic block record for an indirect dynamic block + reference. Returns an empty string if the block record do not reference a dynamic + block or the handle was not found. + + """ + try: # check for indirect dynamic block reference + xdata = block_record.get_xdata(AcDbBlockRepBTag) + except const.DXFValueError: + return "" # not a dynamic block reference + # get handle of dynamic block definition + return xdata.get_first_value(1005, "") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/edgeminer.py b/.venv/lib/python3.12/site-packages/ezdxf/edgeminer.py new file mode 100644 index 0000000..bad5f79 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/edgeminer.py @@ -0,0 +1,1181 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +""" +EdgeMiner +========= + +A module for detecting linked edges. + +The complementary module ezdxf.edgesmith can create entities from the output of this +module. + +Terminology +----------- + +I try to use the terminology of `Graph Theory`_ but there are differences where I think +a different term is better suited for this module like loop for cycle. + +Edge (in this module) + Edge is an immutable class: + - unique id + - 3D start point (vertex) + - 3D end point (vertex) + - optional length + - optional payload (arbitrary data) + + The geometry of an edge is not known. + Intersection points of edges are not known and cannot be calculated. + +Vertex + A connection point of two or more edges. + The degree of a vertex is the number of connected edges. + +Leaf + A leaf is a vertex of degree 1. + A leaf is a loose end of an edge, which is not connected to other edges. + +Junction + A junction is a vertex of degree greater 2. + A junction has more than two adjacent edges. + A junction is an ambiguity when searching for open chains or closed loops. + Graph Theory: multiple adjacency + +Chain + A chain has sequential connected edges. + The end point of an edge is connected to the start point of the following edge. + A chain has unique edges, each edge appears only once in the chain. + A chain can contain vertices of degree greater 2. + A solitary edge is also a chain. + Chains are represented as Sequence[Edge]. + Graph Theory: Trail - no edge is repeated, vertex is repeated + +Simple Chain (special to this module) + A simple chain contains only vertices of degree 2, except the start- and end vertex. + The start- and end vertices are leafs (degree of 1) or junctions (degree greater 2). + +Open Chain + An open chain is a chain which starts and ends at leaf. + A solitary edge is also an open chain. + Graph Theory: Path - no edge is repeated, no vertex is repeated, endings not connected + +Loop + A loop is a simple chain with connected start- and end vertices. + A loop has two or more edges. + A loop contains only vertices of degree 2. + Graph Theory: Cycle - no edge is repeated, no vertex is repeated, endings connected; + a loop in Graph Theory is something different + +Network + A network has two or more edges that are directly and indirectly connected. + The edges in a network have no order. + A network can contain vertices of degree greater 2 (junctions). + A solitary edge is not a network. + A chain with two or more edges is a network. + Networks are represented as Sequence[Edge]. + Graph Theory: multigraph; a network in Graph Theory is something different + +Gap Tolerance + Maximum vertex distance to consider two edges as connected + +Forward Connection + An edge is forward connected when the end point of the edge is connected to the + start point of the following edge. + +.. important:: + + THIS MODULE IS WORK IN PROGRESS (ALPHA VERSION), EVERYTHING CAN CHANGE UNTIL + THE RELEASE IN EZDXF V1.4. + +.. _Graph Theory: https://en.wikipedia.org/wiki/Glossary_of_graph_theory +.. _GeeksForGeeks: https://www.geeksforgeeks.org/graph-data-structure-and-algorithms/?ref=shm + +""" +from __future__ import annotations +from typing import Any, Sequence, Iterator, Iterable, Dict, Tuple, NamedTuple, Callable +from typing_extensions import Self, TypeAlias +from collections import Counter +import functools +import time +import math + +from ezdxf.math import UVec, Vec2, Vec3, distance_point_line_3d +from ezdxf.math import rtree + + +__all__ = [ + "Deposit", + "Edge", + "find_all_loops", + "find_all_open_chains", + "find_all_sequential_chains", + "find_all_simple_chains", + "find_loop", + "find_loop_by_edge", + "find_sequential_chain", + "flatten", + "is_chain", + "is_loop", + "length", + "longest_chain", + "shortest_chain", + "TimeoutError", + "unique_chains", +] +GAP_TOL = 1e-9 +ABS_TOl = 1e-9 +TIMEOUT = 60.0 # in seconds + + +class TimeoutError(Exception): # noqa + def __init__(self, msg: str, solutions: Sequence[Sequence[Edge]] = tuple()) -> None: + super().__init__(msg) + self.solutions = solutions + + +class Watchdog: + def __init__(self, timeout=TIMEOUT) -> None: + self.timeout: float = timeout + self.start_time: float = time.perf_counter() + + def start(self, timeout: float): + self.timeout = timeout + self.start_time = time.perf_counter() + + @property + def has_timed_out(self) -> bool: + return time.perf_counter() - self.start_time > self.timeout + + +class Edge(NamedTuple): + """Represents an immutable edge. + + The edge can represent any linear curve (line, arc, spline,...). + Therefore, the length of the edge must be specified if the length calculation for + a sequence of edges is to be possible. + + Intersection points between edges are not known and cannot be calculated + + .. Important:: + + Use only the :func:`make_edge` function to create new edges to get unique ids! + + Attributes: + id: unique id as int + start: start vertex as Vec3 + end: end vertex as Vec3 + is_reverse: flag to indicate that the edge is reversed compared to its initial state + length: length of the edge, default is the distance between start- and end vertex + payload: arbitrary data associated to the edge + """ + + id: int + start: Vec3 + end: Vec3 + is_reverse: bool = False + length: float = 1.0 + payload: Any = None + + def __eq__(self, other) -> bool: + """Return ``True`` if the ids of the edges are equal.""" + if isinstance(other, Edge): + return self.id == other.id + return False + + def __repr__(self) -> str: + payload = self.payload + if payload is None: + content = str(self.id) + elif isinstance(payload, EdgeWrapper): + content = "[" + (",".join(repr(e) for e in payload.edges)) + "]" + else: + content = str(payload) + return f"Edge({content})" + + def __hash__(self) -> int: + # edge and its reversed edge must have the same hash value! + return self.id + + def reversed(self) -> Self: + """Returns a reversed copy.""" + return self.__class__( # noqa + self.id, # edge and its reversed edge must have the same id! + self.end, + self.start, + not self.is_reverse, + self.length, + self.payload, + ) + + +def make_id_generator(start=0) -> Callable[[], int]: + next_edge_id = start + + def next_id() -> int: + nonlocal next_edge_id + next_edge_id += 1 + return next_edge_id + + return next_id + + +id_generator = make_id_generator() + + +def make_edge( + start: UVec, end: UVec, length: float = -1.0, *, payload: Any = None +) -> Edge: + """Creates a new :class:`Edge` with a unique id.""" + start = Vec3(start) + end = Vec3(end) + if length < 0.0: + length = start.distance(end) + return Edge(id_generator(), start, end, False, length, payload) + + +def isclose(a: Vec3, b: Vec3, gap_tol=GAP_TOL) -> bool: + """This function should be used to test whether two vertices are close to each other + to get consistent results. + """ + return a.distance(b) <= gap_tol + + +class Deposit: + """The edge deposit stores all available edges for further searches. + + The edges and the search index are immutable after instantiation. + The gap_tol value is mutable. + + """ + + def __init__(self, edges: Sequence[Edge], gap_tol=GAP_TOL) -> None: + self.gap_tol: float = gap_tol + self._edges: Sequence[Edge] = type_check(edges) + self._search_index = _SpatialSearchIndex(self._edges) + + @property + def edges(self) -> Sequence[Edge]: + return self._edges + + def degree_counter(self) -> Counter[int]: + """Returns a :class:`Counter` for the degree of all vertices. + + - Counter[degree] returns the count of vertices of this degree. + - Counter.keys() returns all existing degrees in this deposit + + A new counter will be created for every method call! + Different gap tolerances may yield different results. + + """ + # no caching: result depends on gap_tol, which is mutable + counter: Counter[int] = Counter() + search = functools.partial( + self._search_index.vertices_in_sphere, radius=self.gap_tol + ) + for edge in self.edges: + counter[len(search(edge.start))] += 1 + counter[len(search(edge.end))] += 1 + # remove duplicate counts: + return Counter({k: v // k for k, v in counter.items()}) + + @property + def max_degree(self) -> int: + """Returns the maximum degree of all vertices.""" + return max(self.degree_counter().keys()) + + def degree(self, vertex: UVec) -> int: + """Returns the degree of the given vertex. + + - degree of 0: not in this deposit + - degree of 1: one edge is connected to this vertex + - degree of 2: two edges are connected to this vertex + - degree of 3: three edges ... and so on + + + Check if a vertex exist in a deposit:: + + if deposit.degree(vertex): ... + """ + return len(self._search_index.vertices_in_sphere(Vec3(vertex), self.gap_tol)) + + def degrees(self, vertices: Iterable[UVec]) -> Sequence[int]: + """Returns the degree of the given vertices.""" + search = functools.partial( + self._search_index.vertices_in_sphere, radius=self.gap_tol + ) + return tuple(len(search(vertex)) for vertex in Vec3.generate(vertices)) + + def unique_vertices(self) -> set[Vec3]: + """Returns all unique vertices from this deposit. + + Ignores vertices that are close to another vertex (within the range of gap_tol). + It is not determined which of the close vertices is returned. + + e.g. if the vertices a, b are close together, you don't know if you get a or b, + but it's guaranteed that you only get one of them + """ + return filter_close_vertices(self._search_index.rtree, self.gap_tol) + + def edges_linked_to(self, vertex: UVec, radius: float = -1) -> Sequence[Edge]: + """Returns all edges linked to `vertex` in range of `radius`. + + Args: + vertex: 3D search location + radius: search range, default radius is :attr:`Deposit.gap_tol` + + """ + if radius < 0: + radius = self.gap_tol + vertices = self._search_index.vertices_in_sphere(Vec3(vertex), radius) + return tuple(v.edge for v in vertices) + + def find_nearest_edge(self, vertex: UVec) -> Edge | None: + """Return the nearest edge to the given vertex. + + The distance is measured to the connection line from start to end of the edge. + This is not correct for edges that represent arcs or splines. + """ + + def distance(edge: Edge) -> float: + try: + return distance_point_line_3d(vertex, edge.start, edge.end) + except ZeroDivisionError: + return edge.start.distance(vertex) + + vertex = Vec3(vertex) + si = self._search_index + nearest_vertex = si.nearest_vertex(vertex) + edges = self.edges_linked_to(nearest_vertex) + if edges: + return min(edges, key=distance) + return None + + def find_network(self, edge: Edge) -> set[Edge]: + """Returns the network of all edges that are directly and indirectly linked to + `edge`. A network has two or more edges, a solitary edge is not a network. + """ + + def process(vertex: Vec3) -> None: + linked_edges = set(self.edges_linked_to(vertex)) - network + if linked_edges: + network.update(linked_edges) + todo.extend(linked_edges) + + todo: list[Edge] = [edge] + network: set[Edge] = set(todo) + while todo: + edge = todo.pop() + process(edge.start) + process(edge.end) + if len(network) > 1: # a network requires two or more edges + return network + return set() + + def find_all_networks(self) -> Sequence[set[Edge]]: + """Returns all separated networks in this deposit in ascending order of edge + count. + """ + edges = set(self.edges) + networks: list[set[Edge]] = [] + while edges: + edge = edges.pop() + network = self.find_network(edge) + if len(network): + networks.append(network) + edges -= network + else: # solitary edge + edges.discard(edge) + + networks.sort(key=lambda n: len(n)) + return networks + + def find_leafs(self) -> Iterator[Edge]: + """Yields all edges that have at least one end point without connection to other + edges. + """ + for edge in self.edges: + if len(self.edges_linked_to(edge.start)) == 1: + yield edge + elif len(self.edges_linked_to(edge.end)) == 1: + yield edge + + +def is_forward_connected(a: Edge, b: Edge, gap_tol=GAP_TOL) -> bool: + """Returns ``True`` if the edges have a forward connection. + + Forward connection: distance from a.end to b.start <= gap_tol + + Args: + a: first edge + b: second edge + gap_tol: maximum vertex distance to consider two edges as connected + """ + return isclose(a.end, b.start, gap_tol) + + +def is_chain(edges: Sequence[Edge], gap_tol=GAP_TOL) -> bool: + """Returns ``True`` if all edges have a forward connection. + + Args: + edges: sequence of edges + gap_tol: maximum vertex distance to consider two edges as connected + """ + return all(is_forward_connected(a, b, gap_tol) for a, b in zip(edges, edges[1:])) + + +def is_loop(edges: Sequence[Edge], gap_tol=GAP_TOL) -> bool: + """Return ``True`` if the sequence of edges is a closed loop. + + Args: + edges: sequence of edges + gap_tol: maximum vertex distance to consider two edges as connected + """ + if not is_chain(edges, gap_tol): + return False + return isclose(edges[-1].end, edges[0].start, gap_tol) + + +def is_loop_fast(edges: Sequence[Edge], gap_tol=GAP_TOL) -> bool: + """Internal fast loop check.""" + return isclose(edges[-1].end, edges[0].start, gap_tol) + + +def length(edges: Sequence[Edge]) -> float: + """Returns the length of a sequence of edges.""" + return sum(e.length for e in edges) + + +def shortest_chain(chains: Iterable[Sequence[Edge]]) -> Sequence[Edge]: + """Returns the shortest chain of connected edges. + + .. note:: + + This function does not verify if the input sequences are connected edges! + + """ + sorted_chains = sorted(chains, key=length) + if sorted_chains: + return sorted_chains[0] + return tuple() + + +def longest_chain(chains: Iterable[Sequence[Edge]]) -> Sequence[Edge]: + """Returns the longest chain of connected edges. + + .. Note:: + + This function does not verify if the input sequences are connected edges! + + """ + sorted_chains = sorted(chains, key=length) + if sorted_chains: + return sorted_chains[-1] + return tuple() + + +def find_sequential_chain(edges: Sequence[Edge], gap_tol=GAP_TOL) -> Sequence[Edge]: + """Returns a simple chain beginning at the first edge. + + The search stops at the first edge without a forward connection from the previous + edge. Edges will be reversed if required to create connection. + + Args: + edges: edges to be examined + gap_tol: maximum vertex distance to consider two edges as connected + + Raises: + TypeError: invalid data in sequence `edges` + """ + edges = type_check(edges) + if len(edges) < 2: + return edges + chain = [edges[0]] + for edge in edges[1:]: + last = chain[-1] + if is_forward_connected(last, edge, gap_tol): + chain.append(edge) + continue + reversed_edge = edge.reversed() + if is_forward_connected(last, reversed_edge, gap_tol): + chain.append(reversed_edge) + continue + break + return chain + + +def find_all_sequential_chains( + edges: Sequence[Edge], gap_tol=GAP_TOL +) -> Iterator[Sequence[Edge]]: + """Yields all simple chains from sequence `edges`. + + The search progresses strictly in order of the input sequence. The search starts a + new chain at every edge without a forward connection from the previous edge. + Edges will be reversed if required to create connection. + Each chain has one or more edges. + + Args: + edges: sequence of edges + gap_tol: maximum vertex distance to consider two edges as connected + + Raises: + TypeError: invalid data in sequence `edges` + """ + while edges: + chain = find_sequential_chain(edges, gap_tol) + edges = edges[len(chain) :] + yield chain + + +def find_loop(deposit: Deposit, timeout=TIMEOUT) -> Sequence[Edge]: + """Returns the first closed loop found in edge `deposit`. + + Returns only simple loops, where all vertices have only two adjacent edges. + + .. note:: + + Recursive backtracking algorithm with time complexity of O(n!). + + Args: + deposit: edge deposit + timeout: timeout in seconds + + Raises: + TimeoutError: search process has timed out + """ + chains = find_all_simple_chains(deposit) + if not chains: + return tuple() + + gap_tol = deposit.gap_tol + packed_edges: list[Edge] = [] + for chain in chains: + if len(chain) > 1: + if is_loop_fast(chain, gap_tol): + return chain + packed_edges.append(_wrap_simple_chain(chain)) + else: + packed_edges.append(chain[0]) + deposit = Deposit(packed_edges, gap_tol) + if len(deposit.edges) < 2: + return tuple() + return tuple(flatten(_find_loop_in_deposit(deposit, timeout=timeout))) + + +def _find_loop_in_deposit(deposit: Deposit, timeout=TIMEOUT) -> Sequence[Edge]: + if len(deposit.edges) < 2: + return tuple() + + finder = LoopFinder(deposit, timeout=timeout) + loop = finder.find_any_loop() + if loop: + return loop + return tuple() + + +def find_all_loops(deposit: Deposit, timeout=TIMEOUT) -> Sequence[Sequence[Edge]]: + """Returns all closed loops from `deposit`. + + Returns only simple loops, where all vertices have a degree of 2 (only two adjacent + edges). The result does not include reversed solutions. + + .. note:: + + Recursive backtracking algorithm with time complexity of O(n!). + + Args: + deposit: edge deposit + timeout: timeout in seconds + + Raises: + TimeoutError: search process has timed out + """ + chains = find_all_simple_chains(deposit) + if not chains: + return tuple() + + gap_tol = deposit.gap_tol + solutions: list[Sequence[Edge]] = [] + packed_edges: list[Edge] = [] + for chain in chains: + if len(chain) > 1: + if is_loop_fast(chain, gap_tol): + # these loops have no ambiguities (junctions) + solutions.append(chain) + else: + packed_edges.append(_wrap_simple_chain(chain)) + else: + packed_edges.append(chain[0]) + + if not packed_edges: + return solutions + + deposit = Deposit(packed_edges, gap_tol) + if len(deposit.edges) < 2: + return tuple() + try: + result = _find_all_loops_in_deposit(deposit, timeout=timeout) + except TimeoutError as err: + if err.solutions: + solutions.extend(err.solutions) + err.solutions = solutions + raise + solutions.extend(result) + return _unwrap_simple_chains(solutions) + + +def _find_all_loops_in_deposit( + deposit: Deposit, timeout=TIMEOUT +) -> Sequence[Sequence[Edge]]: + solutions: list[Sequence[Edge]] = [] + finder = LoopFinder(deposit, timeout=timeout) + for edge in deposit.edges: + finder.search(edge) + solutions.extend(finder) + return solutions + + +def unique_chains(chains: Sequence[Sequence[Edge]]) -> Iterator[Sequence[Edge]]: + """Filter duplicate chains and yields only unique chains. + + Yields the first chain for chains which have the same set of edges. The order of the + edges is not important. + """ + seen: set[frozenset[int]] = set() + for chain in chains: + key = frozenset(edge.id for edge in chain) + if key not in seen: + yield chain + seen.add(key) + + +def type_check(edges: Sequence[Edge]) -> Sequence[Edge]: + for edge in edges: + if not isinstance(edge, Edge): + raise TypeError(f"expected type , got {str(type(edge))}") + return edges + + +class _Vertex(Vec3): + __slots__ = ("edge",) + # for unknown reasons super().__init__(location) doesn't work, therefor no + # _Vertex.__init__(self, location: Vec3, edge: Edge) constructor + edge: Edge + + +def make_edge_vertex(location: Vec3, edge: Edge) -> _Vertex: + vertex = _Vertex(location) + vertex.edge = edge + return vertex + + +class _SpatialSearchIndex: + """Spatial search index of all edge vertices. + + (internal class) + """ + + def __init__(self, edges: Sequence[Edge]) -> None: + vertices: list[_Vertex] = [] + for edge in edges: + vertices.append(make_edge_vertex(edge.start, edge)) + vertices.append(make_edge_vertex(edge.end, edge)) + self._search_tree = rtree.RTree(vertices) + + @property + def rtree(self) -> rtree.RTree[Vec3]: + return self._search_tree + + def vertices_in_sphere(self, center: Vec3, radius: float) -> Sequence[_Vertex]: + """Returns all vertices located around `center` with a max. distance of `radius`.""" + return tuple(self._search_tree.points_in_sphere(center, radius)) + + def nearest_vertex(self, location: Vec3) -> _Vertex: + """Returns the nearest vertex to the given location.""" + vertex, _ = self._search_tree.nearest_neighbor(location) + return vertex + + +SearchSolutions: TypeAlias = Dict[Tuple[int, ...], Sequence[Edge]] + + +class LoopFinder: + """Find closed loops in an EdgeDeposit by a recursive backtracking algorithm. + + Finds only simple loops, where all vertices have only two adjacent edges. + + (internal class) + """ + + def __init__(self, deposit: Deposit, timeout=TIMEOUT) -> None: + if len(deposit.edges) < 2: + raise ValueError("two or more edges required") + self._deposit = deposit + self._timeout = timeout + self._solutions: SearchSolutions = {} + + @property + def gap_tol(self) -> float: + return self._deposit.gap_tol + + def __iter__(self) -> Iterator[Sequence[Edge]]: + return iter(self._solutions.values()) + + def __len__(self) -> int: + return len(self._solutions) + + def find_any_loop(self, start: Edge | None = None) -> Sequence[Edge]: + """Returns the first loop found beginning with the given start edge or an + arbitrary edge if `start` is None. + """ + if start is None: + start = self._deposit.edges[0] + + self.search(start, stop_at_first_loop=True) + try: + return next(iter(self._solutions.values())) + except StopIteration: + return tuple() + + def search(self, start: Edge, stop_at_first_loop: bool = False) -> None: + """Searches for all loops that begin at the given start edge and contain + only vertices of degree 2. + + These are not all possible loops in the edge deposit! + + Raises: + TimeoutError: search process has timed out, intermediate results are attached + TimeoutError.data + + """ + deposit = self._deposit + gap_tol = self.gap_tol + start_point = start.start + watchdog = Watchdog(self._timeout) + todo: list[tuple[Edge, ...]] = [(start,)] # "unlimited" recursion stack + while todo: + if watchdog.has_timed_out: + raise TimeoutError( + "search process has timed out", + solutions=tuple(self._solutions.values()), # noqa + ) + chain = todo.pop() + last_edge = chain[-1] + end_point = last_edge.end + candidates = deposit.edges_linked_to(end_point, radius=gap_tol) + # edges must be unique in a loop + survivors = set(candidates) - set(chain) + for edge in survivors: + if isclose(end_point, edge.start, gap_tol): + next_edge = edge + else: + next_edge = edge.reversed() + last_point = next_edge.end + if isclose(last_point, start_point, gap_tol): + self.add_solution(chain + (next_edge,)) + if stop_at_first_loop: + return + # Add only chains to the stack that have vertices of max degree 2. + # If the new end point is in the chain, a vertex of degree 3 would be + # created. (loop check is done) + elif not any(isclose(last_point, e.end, gap_tol) for e in chain): + todo.append(chain + (next_edge,)) + + def add_solution(self, loop: Sequence[Edge]) -> None: + solutions = self._solutions + key = loop_key(loop) + if key in solutions or loop_key(loop, reverse=True) in solutions: + return + solutions[key] = loop + + +def loop_key(edges: Sequence[Edge], reverse=False) -> tuple[int, ...]: + """Returns a normalized key. + + The key is rotated to begin with the smallest edge id. + """ + if reverse: + ids = tuple(edge.id for edge in reversed(edges)) + else: + ids = tuple(edge.id for edge in edges) + index = ids.index(min(ids)) + if index: + ids = ids[index:] + ids[:index] + return ids + + +def find_all_simple_chains(deposit: Deposit) -> Sequence[Sequence[Edge]]: + """Returns all simple chains from `deposit`. + + Each chains starts and ends at a leaf (degree of 1) or a junction (degree greater 2). + All vertices between the start- and end vertex have a degree of 2. + The result doesn't include reversed solutions. + """ + if len(deposit.edges) < 1: + return tuple() + solutions: list[Sequence[Edge]] = [] + edges = set(deposit.edges) + while edges: + chain = find_simple_chain(deposit, edges.pop()) + solutions.append(chain) + edges -= set(chain) + return solutions + + +def find_simple_chain(deposit: Deposit, start: Edge) -> Sequence[Edge]: + """Returns a simple chain containing `start` edge. + + A simple chain start and ends at a leaf or a junction. + + All connected edges have vertices of degree 2, except the first and last vertex. + The first and the last vertex have a degree of 1 (leaf) or greater 2 (junction). + """ + forward_chain = _simple_forward_chain(deposit, start) + if is_loop_fast(forward_chain, deposit.gap_tol): + return forward_chain + backwards_chain = _simple_forward_chain(deposit, start.reversed()) + if len(backwards_chain) == 1: + return forward_chain + backwards_chain.reverse() + backwards_chain.pop() # reversed start + return [edge.reversed() for edge in backwards_chain] + forward_chain + + +def _simple_forward_chain(deposit: Deposit, edge: Edge) -> list[Edge]: + """Returns a simple chain beginning with `edge`. + + All connected edges have vertices of degree 2, expect for the last edge. + The last edge has an end-vertex of degree 1 (leaf) or greater 2 (junction). + """ + gap_tol = deposit.gap_tol + chain = [edge] + while True: + last = chain[-1] + linked = deposit.edges_linked_to(last.end, gap_tol) + if len(linked) != 2: # no junctions allowed! + return chain + if linked[0] == last: + edge = linked[1] + else: + edge = linked[0] + if isclose(last.end, edge.start, gap_tol): + chain.append(edge) + else: + chain.append(edge.reversed()) + if is_loop_fast(chain, gap_tol): + return chain + + +def is_wrapped_chain(edge: Edge) -> bool: + """Returns ``True`` if `edge` is a wrapper for linked edges.""" + return isinstance(edge.payload, EdgeWrapper) + + +def wrap_simple_chain(chain: Sequence[Edge], gap_tol=GAP_TOL) -> Edge: + """Wraps a sequence of linked edges (simple chain) into a single edge. + + Two or more linked edges required. Closed loops cannot be wrapped into a single + edge. + + Raises: + ValueError: less than two edges; not a chain; chain is a closed loop + + """ + if len(chain) < 2: + raise ValueError("two or more linked edges required") + if is_chain(chain, gap_tol): + if is_loop_fast(chain, gap_tol): + raise ValueError("closed loop cannot be wrapped into a single edge") + return _wrap_simple_chain(chain) + raise ValueError("edges are not connected") + + +def unwrap_simple_chain(edge: Edge) -> Sequence[Edge]: + """Unwraps a simple chain which is wrapped into a single edge.""" + if isinstance(edge.payload, EdgeWrapper): + return _unwrap_simple_chain(edge) + return (edge,) + + +class EdgeWrapper: + """Internal class to wrap a sequence of linked edges.""" + + __slots__ = ("edges",) + + def __init__(self, edges: Sequence[Edge]) -> None: + self.edges: Sequence[Edge] = tuple(edges) + + +def _wrap_simple_chain(edges: Sequence[Edge]) -> Edge: + return make_edge( + edges[0].start, edges[-1].end, length(edges), payload=EdgeWrapper(edges) + ) + + +def _unwrap_simple_chain(edge: Edge) -> Sequence[Edge]: + wrapper = edge.payload + assert isinstance(wrapper, EdgeWrapper) + if edge.is_reverse: + return tuple(e.reversed() for e in reversed(wrapper.edges)) + else: + return wrapper.edges + + +def _unwrap_simple_chains(chains: Iterable[Iterable[Edge]]) -> Sequence[Sequence[Edge]]: + return tuple(tuple(flatten(chain)) for chain in chains) + + +def flatten(edges: Edge | Iterable[Edge]) -> Iterator[Edge]: + """Yields all edges from any nested structure of edges as a flat stream of edges.""" + edge: Edge + if not isinstance(edges, Edge): + for edge in edges: + yield from flatten(edge) + else: + edge = edges + if is_wrapped_chain(edge): + yield from flatten(_unwrap_simple_chain(edge)) + else: + yield edge + + +def chain_key(edges: Sequence[Edge], reverse=False) -> tuple[int, ...]: + """Returns a normalized key.""" + if reverse: + return tuple(edge.id for edge in reversed(edges)) + else: + return tuple(edge.id for edge in edges) + + +def find_all_open_chains(deposit: Deposit, timeout=TIMEOUT) -> Sequence[Sequence[Edge]]: + """Returns all open chains from `deposit`. + + Returns only simple chains ending on both sides with a leaf. + A leaf is a vertex of degree 1 without further connections. + All vertices have a degree of 2 except for the leafs at the start and end. + The result does not include reversed solutions or closed loops. + + .. note:: + + Recursive backtracking algorithm with time complexity of O(n!). + + Args: + deposit: EdgeDeposit + timeout: timeout in seconds + + Raises: + TimeoutError: search process has timed out + """ + + finder = OpenChainFinder(deposit, timeout) + for edge in deposit.find_leafs(): + finder.search(edge) + solutions = finder.solutions + solutions.sort(key=lambda x: len(x)) + return solutions + + +class OpenChainFinder: + def __init__(self, deposit: Deposit, timeout=TIMEOUT): + self.deposit = deposit + self.solution_keys: set[tuple[int, ...]] = set() + self.solutions: list[Sequence[Edge]] = [] + self.watchdog = Watchdog(timeout) + + def search(self, edge: Edge) -> None: + forward_chains = self.forward_search(edge) + self.reverse_search(forward_chains) + + def forward_search(self, edge: Edge) -> list[tuple[Edge, ...]]: + deposit = self.deposit + gap_tol = deposit.gap_tol + watchdog = self.watchdog + + forward_chains: list[tuple[Edge, ...]] = [] + todo: list[tuple[Edge, ...]] = [(edge,)] + while todo: + if watchdog.has_timed_out: + raise TimeoutError("search has timed out") + chain = todo.pop() + start_point = chain[-1].end + candidates = deposit.edges_linked_to(start_point) + backwards_edges = set(candidates) - set(chain) + if backwards_edges: + for edge in backwards_edges: + if not isclose(start_point, edge.start, gap_tol): + edge = edge.reversed() + # Add only chains to the stack that have vertices of max degree 2. + # If the new end point is in the chain, a vertex of degree 3 would be + # created. (loop check is done) + last_point = edge.end + if not any(isclose(last_point, e.end, gap_tol) for e in chain): + todo.append(chain + (edge,)) + else: + forward_chains.append(chain) + return forward_chains + + def reverse_search(self, forward_chains: list[tuple[Edge, ...]]) -> None: + deposit = self.deposit + gap_tol = deposit.gap_tol + watchdog = self.watchdog + todo = forward_chains + while todo: + if watchdog.has_timed_out: + raise TimeoutError("search has timed out", solutions=self.solutions) + chain = todo.pop() + start_point = chain[0].start + candidates = deposit.edges_linked_to(start_point) + backwards_edges = set(candidates) - set(chain) + if backwards_edges: + for edge in backwards_edges: + if not isclose(start_point, edge.end, gap_tol): + edge = edge.reversed() + # Add only chains to the stack that have vertices of max degree 2. + # If the new end point is in the chain, a vertex of degree 3 would be + # created. + new_start_point = edge.start + if not any(isclose(new_start_point, e.end, gap_tol) for e in chain): + todo.append((edge,) + chain) + else: + self.add_solution(chain) + + def add_solution(self, solution: Sequence[Edge]) -> None: + keys = self.solution_keys + key = chain_key(solution) + if key in keys: + return + keys.add(key) + key = chain_key(solution, reverse=True) + if key in keys: + return + keys.add(key) + self.solutions.append(solution) + + +def count_checker(count: int): + def has_min_edge_count(edges: Sequence[Edge]) -> bool: + return len(edges) >= count + + return has_min_edge_count + + +def line_checker(abs_tol=ABS_TOl): + def is_congruent_line(a: Edge, b: Edge) -> bool: + return ( + a.start.isclose(b.start, abs_tol=abs_tol) + and a.end.isclose(b.end, abs_tol=abs_tol) + ) or ( + a.start.isclose(b.end, abs_tol=abs_tol) + and a.end.isclose(b.start, abs_tol=abs_tol) + ) + + return is_congruent_line + + +def filter_coincident_edges( + deposit: Deposit, eq_fn: Callable[[Edge, Edge], bool] = line_checker() +) -> Sequence[Edge]: + edges = set(deposit.edges) + unique_edges: list[Edge] = [] + while edges: + edge = edges.pop() + unique_edges.append(edge) + candidates = set(deposit.edges_linked_to(edge.start)) + candidates.update(deposit.edges_linked_to(edge.end)) + candidates.discard(edge) + for candidate in candidates: + if eq_fn(edge, candidate): + edges.discard(candidate) + return unique_edges + + +def filter_close_vertices(rt: rtree.RTree[Vec3], gap_tol: float) -> set[Vec3]: + """Returns all vertices from a :class:`RTree` and filters vertices that are closer + than radius `gap_tol` to another vertex. + + Vertice that are close to another vertex are filtered out, so none of the returned + vertices has another vertex within the range of `gap_tol`. It is not determined + which of close vertices is returned. + """ + # RTree cannot be empty! + todo = set(rt) + merged: set[Vec3] = set([todo.pop()]) + for vertex in todo: + for candidate in rt.points_in_sphere(vertex, gap_tol): + if candidate in merged: + continue + if not any(isclose(candidate, v, gap_tol) for v in merged): + merged.add(candidate) + return merged + + +def sort_edges_to_base( + edges: Iterable[Edge], base: Edge, gap_tol=GAP_TOL +) -> list[Edge]: + """Returns a list of `edges` sorted in counter-clockwise order in relation to the + `base` edge. + + The `base` edge represents zero radians. + All edges have to be connected to end-vertex of the `base` edge. + This is a pure 2D algorithm and ignores all z-axis values. + + Args: + edges: list of edges to sort + base: base edge for sorting, represents 0-radian + gap_tol: maximum vertex distance to consider two edges as connected + + Raises: + ValueError: edge is not connected to center + + """ + + def angle(edge: Edge) -> float: + s = Vec2(edge.start) + e = Vec2(edge.end) + if connection_point.distance(s) <= gap_tol: + edge_angle = (e - s).angle + elif connection_point.distance(e) <= gap_tol: + edge_angle = (s - e).angle + else: + raise ValueError(f"edge {edge!s} not connected to center") + return (edge_angle - base_angle) % math.tau + + connection_point = Vec2(base.end) + base_angle = (Vec2(base.start) - connection_point).angle + return sorted(edges, key=angle) + + +def find_loop_by_edge(deposit: Deposit, start: Edge, clockwise=True) -> Sequence[Edge]: + """Returns the first loop found including the given edge. + + Returns an empty sequence if no loop was found. + + """ + if len(deposit.edges) < 2: + return tuple() + gap_tol = deposit.gap_tol + chain = [start] + chain_set = set(chain) + start_point = start.start + + while True: + last_edge = chain[-1] + end_point = last_edge.end + candidates = deposit.edges_linked_to(end_point, radius=gap_tol) + # edges must be unique in a loop + survivors = set(candidates) - chain_set + count = len(survivors) + if count == 0: + return tuple() # dead end + if count > 1: + sorted_edges = sort_edges_to_base(survivors, last_edge, gap_tol) + if clockwise: + next_edge = sorted_edges[-1] # first clockwise edge + else: + next_edge = sorted_edges[0] # first counter-clockwise edge + else: + next_edge = survivors.pop() + if not isclose(next_edge.start, end_point, gap_tol): + next_edge = next_edge.reversed() + chain.append(next_edge) + if isclose(next_edge.end, start_point, gap_tol): + return chain # found a closed loop + chain_set.add(next_edge) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/edgesmith.py b/.venv/lib/python3.12/site-packages/ezdxf/edgesmith.py new file mode 100644 index 0000000..ba9e7e0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/edgesmith.py @@ -0,0 +1,341 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +""" +EdgeSmith +========= + +A module for creating entities like polylines and hatch boundary paths from linked edges. + +The complementary module to ezdxf.edgeminer. + +.. important:: + + THIS MODULE IS WORK IN PROGRESS (ALPHA VERSION), EVERYTHING CAN CHANGE UNTIL + THE RELEASE IN EZDXF V1.4. + +""" +from __future__ import annotations +from typing import Iterator, Iterable, Sequence, Any +from typing_extensions import TypeAlias +import math +import functools + +from ezdxf import edgeminer as em +from ezdxf import entities as et +from ezdxf.math import ( + Vec2, + Vec3, + arc_angle_span_deg, + ellipse_param_span, + bulge_from_arc_angle, +) + +__all__ = [ + "chain_vertices", + "edges_from_entities", + "is_closed_entity", + "lwpolyline_from_chain", + "make_edge", + "polyline2d_from_chain", +] +# Tolerances +LEN_TOL = 1e-9 # length and distance +DEG_TOL = 1e-9 # angles in degree +RAD_TOL = 1e-9 # angles in radians + + +# noinspection PyUnusedLocal +@functools.singledispatch +def is_closed_entity(entity: et.DXFEntity) -> bool: + """Returns ``True`` if the given entity represents a closed loop.""" + return False + + +@is_closed_entity.register(et.Arc) +def _is_closed_arc(entity: et.Arc) -> bool: + radius = abs(entity.dxf.radius) + start_angle = entity.dxf.start_angle + end_angle = entity.dxf.end_angle + angle_span = arc_angle_span_deg(start_angle, end_angle) + return abs(radius) > LEN_TOL and math.isclose(angle_span, 360.0, abs_tol=LEN_TOL) + + +@is_closed_entity.register(et.Circle) +def _is_closed_circle(entity: et.Circle) -> bool: + return abs(entity.dxf.radius) > LEN_TOL + + +@is_closed_entity.register(et.Ellipse) +def _is_closed_ellipse(entity: et.Ellipse) -> bool: + start_param = entity.dxf.start_param + end_param = entity.dxf.end_param + span = ellipse_param_span(start_param, end_param) + if not math.isclose(span, math.tau, abs_tol=RAD_TOL): + return False + return True + + +@is_closed_entity.register(et.Spline) +def _is_closed_spline(entity: et.Spline) -> bool: + try: + bspline = entity.construction_tool() + except ValueError: + return False + control_points = bspline.control_points + if len(control_points) < 3: + return False + start = control_points[0] + end = control_points[-1] + return start.isclose(end, abs_tol=LEN_TOL) + + +@is_closed_entity.register(et.LWPolyline) +def _is_closed_lwpolyline(entity: et.LWPolyline) -> bool: + if len(entity) < 1: + return False + if entity.closed is True: + return True + start = Vec2(entity.lwpoints[0][:2]) + end = Vec2(entity.lwpoints[-1][:2]) + return start.isclose(end, abs_tol=LEN_TOL) + + +@is_closed_entity.register(et.Polyline) +def _is_closed_polyline2d(entity: et.Polyline) -> bool: + if entity.is_2d_polyline or entity.is_3d_polyline: + # Note: does not check if all vertices of a 3D polyline are placed on a + # common plane. + vertices = entity.vertices + if len(vertices) < 2: + return False + if entity.is_closed: + return True + p0: Vec3 = vertices[0].dxf.location # type: ignore + p1: Vec3 = vertices[-1].dxf.location # type: ignore + if p0.isclose(p1, abs_tol=LEN_TOL): + return True + return False + + +def _validate_edge(edge: em.Edge, gap_tol: float) -> em.Edge | None: + if edge.start.distance(edge.end) < gap_tol: + return None + if edge.length < gap_tol: + return None + return edge + + +# noinspection PyUnusedLocal +@functools.singledispatch +def make_edge(entity: et.DXFEntity, gap_tol=em.GAP_TOL) -> em.Edge | None: + """Makes an :class:`Edge` instance from the following DXF entity types: + + - LINE + - ARC + - ELLIPSE + - SPLINE + - LWPOLYLINE + - 2D POLYLINE + + if the entity is an open linear curve. + + Returns ``None`` if the entity is a closed curve or cannot represent an edge. + """ + return None + + +@make_edge.register(et.Line) +def _edge_from_line(entity: et.Line, gap_tol=em.GAP_TOL) -> em.Edge | None: + start = Vec3(entity.dxf.start) + end = Vec3(entity.dxf.end) + length = start.distance(end) + return _validate_edge(em.make_edge(start, end, length, payload=entity), gap_tol) + + +@make_edge.register(et.Arc) +def _edge_from_arc(entity: et.Arc, gap_tol=em.GAP_TOL) -> em.Edge | None: + radius = abs(entity.dxf.radius) + if radius < LEN_TOL: + return None + start_angle = entity.dxf.start_angle + end_angle = entity.dxf.end_angle + span_deg = arc_angle_span_deg(start_angle, end_angle) + length = radius * span_deg / 180.0 * math.pi + sp, ep = entity.vertices((start_angle, end_angle)) + return _validate_edge(em.make_edge(sp, ep, length, payload=entity), gap_tol) + + +@make_edge.register(et.Ellipse) +def _edge_from_ellipse(entity: et.Ellipse, gap_tol=em.GAP_TOL) -> em.Edge | None: + try: + ct1 = entity.construction_tool() + except ValueError: + return None + if ct1.major_axis.magnitude < LEN_TOL or ct1.minor_axis.magnitude < LEN_TOL: + return None + span = ellipse_param_span(ct1.start_param, ct1.end_param) + num = max(3, round(span / 0.1745)) # resolution of ~1 deg + # length of elliptic arc is an approximation: + points = list(ct1.vertices(ct1.params(num))) + length = sum(a.distance(b) for a, b in zip(points, points[1:])) + return _validate_edge( + em.make_edge(Vec3(points[0]), Vec3(points[-1]), length, payload=entity), gap_tol + ) + + +@make_edge.register(et.Spline) +def _edge_from_spline(entity: et.Spline, gap_tol=em.GAP_TOL) -> em.Edge | None: + try: + ct2 = entity.construction_tool() + except ValueError: + return None + start = Vec3(ct2.control_points[0]) + end = Vec3(ct2.control_points[-1]) + points = list(ct2.control_points) + # length of B-spline is a very rough approximation: + length = sum(a.distance(b) for a, b in zip(points, points[1:])) + return _validate_edge(em.make_edge(start, end, length, payload=entity), gap_tol) + + +def edges_from_entities( + entities: Iterable[et.DXFEntity], gap_tol=em.GAP_TOL +) -> Iterator[em.Edge]: + """Yields all DXF entities as edges. + + Skips all entities which can not be represented as edge. + """ + for entity in entities: + edge = make_edge(entity, gap_tol) + if edge is not None: + yield edge + + +def chain_vertices(edges: Sequence[em.Edge], gap_tol=em.GAP_TOL) -> Sequence[Vec3]: + """Returns all vertices from a sequence of connected edges. + + Adds line segments between edges when the gap is bigger than `gap_tol`. + """ + if not edges: + return tuple() + vertices: list[Vec3] = [edges[0].start] + for edge in edges: + if not em.isclose(vertices[-1], edge.start, gap_tol): + vertices.append(edge.start) + vertices.append(edge.end) + return vertices + + +def lwpolyline_from_chain( + edges: Sequence[em.Edge], dxfattribs: Any = None +) -> et.LWPolyline: + """Returns a new virtual :class:`LWPolyline` entity. + + This function assumes the building blocks as simple DXF entities attached as payload + to the edges. The edges are processed in order of the input sequence. + + - LINE entities are added as line segments + - ARC entities are added as bulges + - ELLIPSE entities with a ratio of 1.0 are added as bulges + - LWPOLYLINE will be merged + - 2D POLYLINE will be merged + - Everything else will be added as line segment from Edge.start to Edge.end + - Gaps between edges are connected by line segments. + + """ + polyline = et.LWPolyline.new(dxfattribs=dxfattribs) + if len(edges) == 0: + return polyline + polyline.set_points(polyline_points(edges), format="vb") # type: ignore + return polyline + + +def polyline2d_from_chain( + edges: Sequence[em.Edge], dxfattribs: Any = None +) -> et.Polyline: + """Returns a new virtual :class:`Polyline` entity. + + This function assumes the building blocks as simple DXF entities attached as payload + to the edges. The edges are processed in order of the input sequence. + + - LINE entities are added as line segments + - ARC entities are added as bulges + - ELLIPSE entities with a ratio of 1.0 are added as bulges + - LWPOLYLINE will be merged + - 2D POLYLINE will be merged + - Everything else will be added as line segment from Edge.start to Edge.end + - Gaps between edges are connected by line segments. + + """ + polyline = et.Polyline.new(dxfattribs=dxfattribs) + if len(edges) == 0: + return polyline + polyline.append_formatted_vertices(polyline_points(edges), format="vb") + return polyline + + +BulgePoints: TypeAlias = list[tuple[Vec2, float]] + + +def polyline_points(edges: Sequence[em.Edge]) -> BulgePoints: + """Returns the polyline points to create a :class:`LWPolyline` or a + 2D :class.`Polyline` entity. + """ + + def extend(pts: BulgePoints) -> None: + if len(pts) < 2: + return + # ignore first vertex + first = pts[0] + bulges[-1] = first[1] + for pnt, bulge in pts[1:]: + points.append(pnt) + bulges.append(bulge) + + def reverse(pts: BulgePoints) -> BulgePoints: + if len(pts) < 2: + return pts + pts.reverse() + bulges = [pnt[1] for pnt in pts] + if any(bulges): + # shift bulge values to previous vertex + first = bulges.pop(0) + bulges.append(first) + return list(zip((pnt[0] for pnt in pts), bulges)) + return pts + + # bulge value is stored in the start vertex of the curved segment + points: list[Vec2] = [Vec2(edges[0].start)] + bulges: list[float] = [0.0] + for edge in edges: + current_end = points[-1] + if edge.start.distance(current_end) < LEN_TOL: + current_end = edge.start + points.append(Vec2(current_end)) + bulges.append(0.0) + entity = edge.payload + if isinstance(entity, et.Arc): + span = arc_angle_span_deg(entity.dxf.start_angle, entity.dxf.end_angle) + if span > DEG_TOL: + bulge = bulge_from_arc_angle(math.radians(span)) + bulges[-1] = -bulge if edge.is_reverse else bulge + elif isinstance(entity, et.Ellipse): + ratio = abs(entity.dxf.ratio) + span = ellipse_param_span(entity.dxf.start_param, entity.dxf.end_param) + if math.isclose(ratio, 1.0) and span > RAD_TOL: + bulge = bulge_from_arc_angle(span) + bulges[-1] = -bulge if edge.is_reverse else bulge + elif isinstance(entity, et.LWPolyline): + vertices: BulgePoints = list(entity.get_points(format="vb")) # type: ignore + if edge.is_reverse: + vertices = reverse(vertices) + extend(vertices) + continue + elif isinstance(entity, et.Polyline) and entity.is_2d_polyline: + vertices = [(Vec2(v.dxf.location), v.dxf.bulge) for v in entity.vertices] + if edge.is_reverse: + vertices = reverse(vertices) + extend(vertices) + continue + points.append(Vec2(edge.end)) + bulges.append(0.0) + return list(zip(points, bulges)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/__init__.py new file mode 100644 index 0000000..653a8b8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/__init__.py @@ -0,0 +1,111 @@ +# Copyright (c) 2011-2021 Manfred Moitzi +# License: MIT License + +from . import factory + +# basic classes +from .xdict import ExtensionDict +from .xdata import XData +from .appdata import AppData, Reactors +from .dxfentity import DXFEntity, DXFTagStorage +from .dxfgfx import DXFGraphic, SeqEnd, is_graphic_entity, get_font_name +from .dxfobj import DXFObject, is_dxf_object +from .dxfns import DXFNamespace, SubclassProcessor + +# register management structures +from .dxfclass import DXFClass +from .table import TableHead + +# register table entries +from .ltype import Linetype +from .layer import Layer, LayerOverrides +from .textstyle import Textstyle +from .dimstyle import DimStyle +from .view import View +from .vport import VPort +from .ucs import UCSTableEntry +from .appid import AppID +from .blockrecord import BlockRecord + +# register DXF objects R2000 +from .acad_proxy_entity import ACADProxyEntity +from .dxfobj import XRecord, Placeholder, VBAProject, SortEntsTable +from .dictionary import Dictionary, DictionaryVar, DictionaryWithDefault +from .layout import DXFLayout +from .idbuffer import IDBuffer +from .sun import Sun +from .material import Material, MaterialCollection +from .oleframe import OLE2Frame +from .spatial_filter import SpatialFilter + +# register DXF objects R2007 +from .visualstyle import VisualStyle + +# register entities R12 +from .line import Line +from .point import Point +from .circle import Circle +from .arc import Arc +from .shape import Shape +from .solid import Solid, Face3d, Trace +from .text import Text +from .subentity import LinkedEntities, entity_linker +from .insert import Insert +from .block import Block, EndBlk +from .polyline import Polyline, Polyface, Polymesh, MeshVertexCache +from .attrib import Attrib, AttDef, copy_attrib_as_text +from .dimension import * +from .dimstyleoverride import DimStyleOverride +from .viewport import Viewport + +# register graphical entities R2000 +from .lwpolyline import LWPolyline +from .ellipse import Ellipse +from .xline import XLine, Ray +from .mtext import MText +from .mtext_columns import * +from .spline import Spline +from .mesh import Mesh, MeshData +from .boundary_paths import * +from .gradient import * +from .pattern import * +from .hatch import * +from .mpolygon import MPolygon +from .image import Image, ImageDef, Wipeout +from .underlay import ( + Underlay, + UnderlayDefinition, + PdfUnderlay, + DgnUnderlay, + DwfUnderlay, +) +from .leader import Leader +from .tolerance import Tolerance +from .helix import Helix +from .acis import ( + Body, + Solid3d, + Region, + Surface, + ExtrudedSurface, + LoftedSurface, + RevolvedSurface, + SweptSurface, +) +from .mline import MLine, MLineVertex, MLineStyle, MLineStyleCollection +from .mleader import MLeader, MLeaderStyle, MLeaderStyleCollection, MultiLeader + +# register graphical entities R2004 + +# register graphical entities R2007 + +from .light import Light +from .acad_table import AcadTableBlockContent, acad_table_to_block + +# register graphical entities R2010 + +from .geodata import GeoData + +# register graphical entities R2013 + +# register graphical entities R2018 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..d32b260 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_proxy_entity.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_proxy_entity.cpython-312.pyc new file mode 100644 index 0000000..89948e2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_proxy_entity.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_table.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_table.cpython-312.pyc new file mode 100644 index 0000000..5dcefff Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_table.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_xrec_roundtrip.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_xrec_roundtrip.cpython-312.pyc new file mode 100644 index 0000000..9dad04e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acad_xrec_roundtrip.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acis.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acis.cpython-312.pyc new file mode 100644 index 0000000..1745938 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/acis.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appdata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appdata.cpython-312.pyc new file mode 100644 index 0000000..851804f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appdata.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appid.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appid.cpython-312.pyc new file mode 100644 index 0000000..36309ea Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/appid.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/arc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/arc.cpython-312.pyc new file mode 100644 index 0000000..4d42827 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/arc.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/attrib.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/attrib.cpython-312.pyc new file mode 100644 index 0000000..7cc6f01 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/attrib.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/block.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/block.cpython-312.pyc new file mode 100644 index 0000000..6ced294 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/block.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/blockrecord.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/blockrecord.cpython-312.pyc new file mode 100644 index 0000000..cb4bfab Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/blockrecord.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/boundary_paths.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/boundary_paths.cpython-312.pyc new file mode 100644 index 0000000..cf11c90 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/boundary_paths.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/circle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/circle.cpython-312.pyc new file mode 100644 index 0000000..587bfd0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/circle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/copy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/copy.cpython-312.pyc new file mode 100644 index 0000000..52efadc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/copy.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dictionary.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dictionary.cpython-312.pyc new file mode 100644 index 0000000..921e85b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dictionary.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimension.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimension.cpython-312.pyc new file mode 100644 index 0000000..97ee1ac Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimension.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyle.cpython-312.pyc new file mode 100644 index 0000000..9bce3ac Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyleoverride.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyleoverride.cpython-312.pyc new file mode 100644 index 0000000..9417b2f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dimstyleoverride.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfclass.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfclass.cpython-312.pyc new file mode 100644 index 0000000..1718221 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfclass.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfentity.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfentity.cpython-312.pyc new file mode 100644 index 0000000..ab70796 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfentity.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgfx.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgfx.cpython-312.pyc new file mode 100644 index 0000000..be952f7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgfx.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgroups.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgroups.cpython-312.pyc new file mode 100644 index 0000000..60eb0b0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfgroups.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfns.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfns.cpython-312.pyc new file mode 100644 index 0000000..1474bfa Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfns.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfobj.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfobj.cpython-312.pyc new file mode 100644 index 0000000..6730b9b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/dxfobj.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ellipse.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ellipse.cpython-312.pyc new file mode 100644 index 0000000..52e160b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ellipse.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/factory.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/factory.cpython-312.pyc new file mode 100644 index 0000000..61fb718 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/factory.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/geodata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/geodata.cpython-312.pyc new file mode 100644 index 0000000..f4099db Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/geodata.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/gradient.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/gradient.cpython-312.pyc new file mode 100644 index 0000000..58f4a76 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/gradient.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/hatch.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/hatch.cpython-312.pyc new file mode 100644 index 0000000..575b6fd Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/hatch.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/helix.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/helix.cpython-312.pyc new file mode 100644 index 0000000..ae781ca Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/helix.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/idbuffer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/idbuffer.cpython-312.pyc new file mode 100644 index 0000000..8660cce Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/idbuffer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/image.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/image.cpython-312.pyc new file mode 100644 index 0000000..21a91d2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/image.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/insert.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/insert.cpython-312.pyc new file mode 100644 index 0000000..0791967 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/insert.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layer.cpython-312.pyc new file mode 100644 index 0000000..6c9ca72 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layout.cpython-312.pyc new file mode 100644 index 0000000..38ab167 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/layout.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/leader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/leader.cpython-312.pyc new file mode 100644 index 0000000..676b5dc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/leader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/light.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/light.cpython-312.pyc new file mode 100644 index 0000000..df3d33e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/light.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/line.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/line.cpython-312.pyc new file mode 100644 index 0000000..8dfae1c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/line.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ltype.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ltype.cpython-312.pyc new file mode 100644 index 0000000..c3ca426 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ltype.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/lwpolyline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/lwpolyline.cpython-312.pyc new file mode 100644 index 0000000..dc9b501 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/lwpolyline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/material.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/material.cpython-312.pyc new file mode 100644 index 0000000..4f9f167 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/material.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mesh.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mesh.cpython-312.pyc new file mode 100644 index 0000000..d2d247d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mesh.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mleader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mleader.cpython-312.pyc new file mode 100644 index 0000000..b2b3c3a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mleader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mline.cpython-312.pyc new file mode 100644 index 0000000..f777566 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mpolygon.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mpolygon.cpython-312.pyc new file mode 100644 index 0000000..2218a9d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mpolygon.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext.cpython-312.pyc new file mode 100644 index 0000000..aa7b522 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext_columns.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext_columns.cpython-312.pyc new file mode 100644 index 0000000..d38834e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/mtext_columns.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/objectcollection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/objectcollection.cpython-312.pyc new file mode 100644 index 0000000..dc56bae Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/objectcollection.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/oleframe.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/oleframe.cpython-312.pyc new file mode 100644 index 0000000..dc0b803 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/oleframe.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/pattern.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/pattern.cpython-312.pyc new file mode 100644 index 0000000..997f0ef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/pattern.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/point.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/point.cpython-312.pyc new file mode 100644 index 0000000..aeae8f8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/point.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polygon.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polygon.cpython-312.pyc new file mode 100644 index 0000000..1195071 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polygon.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polyline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polyline.cpython-312.pyc new file mode 100644 index 0000000..9494eaf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/polyline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/shape.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/shape.cpython-312.pyc new file mode 100644 index 0000000..bb6a2eb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/shape.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/solid.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/solid.cpython-312.pyc new file mode 100644 index 0000000..5aa73d5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/solid.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spatial_filter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spatial_filter.cpython-312.pyc new file mode 100644 index 0000000..1fe26dc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spatial_filter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spline.cpython-312.pyc new file mode 100644 index 0000000..e4b3485 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/spline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/subentity.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/subentity.cpython-312.pyc new file mode 100644 index 0000000..1b90054 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/subentity.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/sun.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/sun.cpython-312.pyc new file mode 100644 index 0000000..152877b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/sun.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/table.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/table.cpython-312.pyc new file mode 100644 index 0000000..9935de3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/table.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/temporary_transform.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/temporary_transform.cpython-312.pyc new file mode 100644 index 0000000..72d4562 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/temporary_transform.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/text.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/text.cpython-312.pyc new file mode 100644 index 0000000..8c3c217 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/text.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/textstyle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/textstyle.cpython-312.pyc new file mode 100644 index 0000000..bd273b0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/textstyle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/tolerance.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/tolerance.cpython-312.pyc new file mode 100644 index 0000000..f6b88c6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/tolerance.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ucs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ucs.cpython-312.pyc new file mode 100644 index 0000000..f127a15 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/ucs.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/underlay.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/underlay.cpython-312.pyc new file mode 100644 index 0000000..ead0889 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/underlay.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/view.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/view.cpython-312.pyc new file mode 100644 index 0000000..b5da4ef Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/view.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/viewport.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/viewport.cpython-312.pyc new file mode 100644 index 0000000..ac324f8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/viewport.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/visualstyle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/visualstyle.cpython-312.pyc new file mode 100644 index 0000000..68ae2ee Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/visualstyle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/vport.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/vport.cpython-312.pyc new file mode 100644 index 0000000..ced99a4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/vport.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdata.cpython-312.pyc new file mode 100644 index 0000000..75ea9d4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdata.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdict.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdict.cpython-312.pyc new file mode 100644 index 0000000..2173448 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xdict.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xline.cpython-312.pyc new file mode 100644 index 0000000..fe47db2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/entities/__pycache__/xline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_proxy_entity.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_proxy_entity.py new file mode 100644 index 0000000..4a2aaf5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_proxy_entity.py @@ -0,0 +1,147 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Iterator +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags +from ezdxf.query import EntityQuery +from .dxfentity import SubclassProcessor +from .dxfgfx import DXFGraphic +from . import factory +from .copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import DXFNamespace + from ezdxf.layouts import BaseLayout + + +# Group Codes of AcDbProxyEntity +# https://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-89A690F9-E859-4D57-89EA-750F3FB76C6B +# 100 AcDbProxyEntity +# 90 Proxy entity class ID (always 498) +# 91 Application entity's class ID. Class IDs are based on the order of +# the class in the CLASSES section. The first class is given the ID of +# 500, the next is 501, and so on +# +# 92 Size of graphics data in bytes < R2010; R2010+ = 160 +# 310 Binary graphics data (multiple entries can appear) (optional) +# +# 96 Size of unknown data in bytes < R2010; R2010+ = 162 +# 311 Binary entity data (multiple entries can appear) (optional) +# +# 93 Size of entity data in bits None: + super().__init__() + self.acdb_proxy_entity: Optional[Tags] = None + + def copy(self, copy_strategy=default_copy): + raise CopyNotSupported(f"Copying of {self.dxftype()} not supported.") + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + self.acdb_proxy_entity = processor.subclass_by_index(2) + self.load_proxy_graphic() + return dxf + + def load_proxy_graphic(self) -> None: + if self.acdb_proxy_entity is None: + return + for length_code in (92, 160): + proxy_graphic = load_proxy_data(self.acdb_proxy_entity, length_code, 310) + if proxy_graphic: + self.proxy_graphic = proxy_graphic + return + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + # Proxy graphic is stored in AcDbProxyEntity and not as usual in + # AcDbEntity! + preserve_proxy_graphic = self.proxy_graphic + self.proxy_graphic = None + super().export_dxf(tagwriter) + self.proxy_graphic = preserve_proxy_graphic + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + # Base class and AcDbEntity export is done by parent class + super().export_entity(tagwriter) + if self.acdb_proxy_entity is not None: + tagwriter.write_tags(self.acdb_proxy_entity) + # XDATA export is done by the parent class + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + from ezdxf.proxygraphic import ProxyGraphic + + if self.proxy_graphic: + for e in ProxyGraphic(self.proxy_graphic, doc=self.doc).virtual_entities(): + e.set_source_of_copy(self) + yield e + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields proxy graphic as "virtual" entities.""" + return self.__virtual_entities__() + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explodes the proxy graphic for the ACAD_PROXY_ENTITY into the target layout, + if target layout is ``None``, the layout of the ACAD_PROXY_ENTITY will be used. + This method destroys the source ACAD_PROXY_ENTITY entity. + + Args: + target_layout: target layout for exploded entities, ``None`` for + same layout as the source ACAD_PROXY_ENTITY. + + Returns: + :class:`~ezdxf.query.EntityQuery` container referencing all exploded + DXF entities. + + """ + if target_layout is None: + target_layout = self.get_layout() + if target_layout is None: + raise const.DXFStructureError( + "ACAD_PROXY_ENTITY without layout assignment, specify target layout" + ) + entities: list[DXFGraphic] = list(self.__virtual_entities__()) + for e in entities: + target_layout.add_entity(e) + self.destroy() + return EntityQuery(entities) + + +def load_proxy_data( + tags: Tags, length_code: int, data_code: int = 310 +) -> Optional[bytes]: + try: + index = tags.tag_index(length_code) + except const.DXFValueError: + return None + binary_data = [] + for code, value in tags[index + 1 :]: + if code == data_code: + binary_data.append(value) + else: + break # at first tag with group code != data_code + return b"".join(binary_data) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_table.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_table.py new file mode 100644 index 0000000..b70b241 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_table.py @@ -0,0 +1,477 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, Iterator +from typing_extensions import Self +import copy +from ezdxf.math import Vec3, Matrix44 +from ezdxf.lldxf.tags import Tags, group_tags +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + group_code_mapping, +) +from ezdxf.lldxf import const +from ezdxf.entities import factory +from .dxfentity import base_class, SubclassProcessor, DXFEntity, DXFTagStorage +from .dxfgfx import DXFGraphic, acdb_entity +from .dxfobj import DXFObject +from .objectcollection import ObjectCollection +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.document import Drawing + +__all__ = [ + "AcadTable", + "AcadTableBlockContent", + "acad_table_to_block", + "read_acad_table_content", +] + + +acdb_block_reference = DefSubclass( + "AcDbBlockReference", + { + # Block name: an anonymous block begins with a *T value + "geometry": DXFAttr(2), + # Insertion point: + "insert": DXFAttr(10, xtype=XType.point3d, default=Vec3(0, 0, 0)), + }, +) +acdb_block_reference_group_codes = group_code_mapping(acdb_block_reference) + +acdb_table = DefSubclass( + "AcDbTable", + { + # Table data version number: 0 = 2010 + "version": DXFAttr(280), + # Hard of the TABLESTYLE object: + "table_style_id": DXFAttr(342), + # Handle of the associated anonymous BLOCK containing the graphical + # representation: + "block_record_handle": DXFAttr(343), + # Horizontal direction vector: + "horizontal_direction": DXFAttr(11), + # Flag for table value (unsigned integer): + "table_value": DXFAttr(90), + # Number of rows: + "n_rows": DXFAttr(91), + # Number of columns: + "n_cols": DXFAttr(92), + # Flag for an override: + "override_flag": DXFAttr(93), + # Flag for an override of border color: + "border_color_override_flag": DXFAttr(94), + # Flag for an override of border lineweight: + "border_lineweight_override_flag": DXFAttr(95), + # Flag for an override of border visibility: + "border_visibility_override_flag": DXFAttr(96), + # 141: Row height; this value is repeated, 1 value per row + # 142: Column height; this value is repeated, 1 value per column + # for every cell: + # 171: Cell type; this value is repeated, 1 value per cell: + # 1 = text type + # 2 = block type + # 172: Cell flag value; this value is repeated, 1 value per cell + # 173: Cell merged value; this value is repeated, 1 value per cell + # 174: Boolean flag indicating if the autofit option is set for the + # cell; this value is repeated, 1 value per cell + # 175: Cell border width (applicable only for merged cells); this + # value is repeated, 1 value per cell + # 176: Cell border height (applicable for merged cells); this value + # is repeated, 1 value per cell + # 91: Cell override flag; this value is repeated, 1 value per cell + # (from AutoCAD 2007) + # 178: Flag value for a virtual edge + # 145: Rotation value (real; applicable for a block-type cell and + # a text-type cell) + # 344: Hard pointer ID of the FIELD object. This applies only to a + # text-type cell. If the text in the cell contains one or more + # fields, only the ID of the FIELD object is saved. + # The text string (group codes 1 and 3) is ignored + # 1: Text string in a cell. If the string is shorter than 250 + # characters, all characters appear in code 1. + # If the string is longer than 250 characters, it is divided + # into chunks of 250 characters. + # The chunks are contained in one or more code 2 codes. + # If code 2 codes are used, the last group is a code 1 and is + # shorter than 250 characters. + # This value applies only to text-type cells and is repeated, + # 1 value per cell + # 2: Text string in a cell, in 250-character chunks; optional. + # This value applies only to text-type cells and is repeated, + # 1 value per cell + # 340: Hard-pointer ID of the block table record. + # This value applies only to block-type cells and is repeated, + # 1 value per cell + # 144: Block scale (real). This value applies only to block-type + # cells and is repeated, 1 value per cell + # 176: Number of attribute definitions in the block table record + # (applicable only to a block-type cell) + # for every ATTDEF: + # 331: Soft pointer ID of the attribute definition in the + # block table record, referenced by group code 179 + # (applicable only for a block-type cell). This value is + # repeated once per attribute definition + # 300: Text string value for an attribute definition, repeated + # once per attribute definition and applicable only for + # a block-type cell + # 7: Text style name (string); override applied at the cell level + # 140: Text height value; override applied at the cell level + # 170: Cell alignment value; override applied at the cell level + # 64: Value for the color of cell content; override applied at the + # cell level + # 63: Value for the background (fill) color of cell content; + # override applied at the cell level + # 69: True color value for the top border of the cell; + # override applied at the cell level + # 65: True color value for the right border of the cell; + # override applied at the cell level + # 66: True color value for the bottom border of the cell; + # override applied at the cell level + # 68: True color value for the left border of the cell; + # override applied at the cell level + # 279: Lineweight for the top border of the cell; + # override applied at the cell level + # 275: Lineweight for the right border of the cell; + # override applied at the cell level + # 276: Lineweight for the bottom border of the cell; + # override applied at the cell level + # 278: Lineweight for the left border of the cell; + # override applied at the cell level + # 283: Boolean flag for whether the fill color is on; + # override applied at the cell level + # 289: Boolean flag for the visibility of the top border of the cell; + # override applied at the cell level + # 285: Boolean flag for the visibility of the right border of the cell; + # override applied at the cell level + # 286: Boolean flag for the visibility of the bottom border of the cell; + # override applied at the cell level + # 288: Boolean flag for the visibility of the left border of the cell; + # override applied at the cell level + # 70: Flow direction; + # override applied at the table entity level + # 40: Horizontal cell margin; + # override applied at the table entity level + # 41: Vertical cell margin; + # override applied at the table entity level + # 280: Flag for whether the title is suppressed; + # override applied at the table entity level + # 281: Flag for whether the header row is suppressed; + # override applied at the table entity level + # 7: Text style name (string); + # override applied at the table entity level. + # There may be one entry for each cell type + # 140: Text height (real); + # override applied at the table entity level. + # There may be one entry for each cell type + # 170: Cell alignment (integer); + # override applied at the table entity level. + # There may be one entry for each cell type + # 63: Color value for cell background or for the vertical, left + # border of the table; override applied at the table entity + # level. There may be one entry for each cell type + # 64: Color value for cell content or for the horizontal, top + # border of the table; override applied at the table entity + # level. There may be one entry for each cell type + # 65: Color value for the horizontal, inside border lines; + # override applied at the table entity level + # 66: Color value for the horizontal, bottom border lines; + # override applied at the table entity level + # 68: Color value for the vertical, inside border lines; + # override applied at the table entity level + # 69: Color value for the vertical, right border lines; + # override applied at the table entity level + # 283: Flag for whether background color is enabled (default = 0); + # override applied at the table entity level. + # There may be one entry for each cell type: 0/1 = Disabled/Enabled + # 274-279: Lineweight for each border type of the cell (default = kLnWtByBlock); + # override applied at the table entity level. + # There may be one group for each cell type + # 284-289: Flag for visibility of each border type of the cell (default = 1); + # override applied at the table entity level. + # There may be one group for each cell type: 0/1 = Invisible/Visible + # 97: Standard/title/header row data type + # 98: Standard/title/header row unit type + # 4: Standard/title/header row format string + # + # AutoCAD 2007 and before: + # 177: Cell override flag value (before AutoCAD 2007) + # 92: Extended cell flags (from AutoCAD 2007), COLLISION: group code + # also used by n_cols + # 301: Text string in a cell. If the string is shorter than 250 + # characters, all characters appear in code 302. + # If the string is longer than 250 characters, it is divided into + # chunks of 250 characters. + # The chunks are contained in one or more code 303 codes. + # If code 393 codes are used, the last group is a code 1 and is + # shorter than 250 characters. + # --- WRONG: The text is divided into chunks of group code 2 and the last + # chuck has group code 1. + # This value applies only to text-type cells and is repeated, + # 1 value per cell (from AutoCAD 2007) + # 302: Text string in a cell, in 250-character chunks; optional. + # This value applies only to text-type cells and is repeated, + # 302 value per cell (from AutoCAD 2007) + # --- WRONG: 302 contains all the text as a long string, tested with more + # than 66000 characters + # BricsCAD writes long text in cells with both methods: 302 & (2, 2, 2, ..., 1) + # + # REMARK from Autodesk: + # Group code 178 is a flag value for a virtual edge. A virtual edge is + # used when a grid line is shared by two cells. + # For example, if a table contains one row and two columns and it + # contains cell A and cell B, the central grid line + # contains the right edge of cell A and the left edge of cell B. + # One edge is real, and the other edge is virtual. + # The virtual edge points to the real edge; both edges have the same + # set of properties, including color, lineweight, and visibility. + }, +) +acdb_table_group_codes = group_code_mapping(acdb_table) + + +# todo: implement ACAD_TABLE +class AcadTable(DXFGraphic): + """DXF ACAD_TABLE entity""" + + DXFTYPE = "ACAD_TABLE" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_block_reference, acdb_table + ) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2007 + + def __init__(self): + super().__init__() + self.data = None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy data.""" + assert isinstance(entity, AcadTable) + entity.data = copy.deepcopy(self.data) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_block_reference_group_codes, subclass=2 + ) + tags = processor.fast_load_dxfattribs( + dxf, acdb_table_group_codes, subclass=3, log=False + ) + self.load_table(tags) + return dxf + + def load_table(self, tags: Tags): + pass + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_block_reference.name) + self.dxf.export_dxf_attribs(tagwriter, ["geometry", "insert"]) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_table.name) + self.export_table(tagwriter) + + def export_table(self, tagwriter: AbstractTagWriter): + pass + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for "ReferencedBlocks" protocol.""" + if self.doc: + block_record_handle = self.dxf.get("block_record_handle", None) + if block_record_handle: + return (block_record_handle,) + return tuple() + + +acdb_table_style = DefSubclass( + "AcDbTableStyle", + { + # Table style version: 0 = 2010 + "version": DXFAttr(280), + # Table style description (string; 255 characters maximum): + "name": DXFAttr(3), + # FlowDirection (integer): + # 0 = Down + # 1 = Up + "flow_direction": DXFAttr(7), + # Flags (bit-coded) + "flags": DXFAttr(7), + # Horizontal cell margin (real; default = 0.06) + "horizontal_cell_margin": DXFAttr(40), + # Vertical cell margin (real; default = 0.06) + "vertical_cell_margin": DXFAttr(41), + # Flag for whether the title is suppressed: + # 0/1 = not suppressed/suppressed + "suppress_title": DXFAttr(280), + # Flag for whether the column heading is suppressed: + # 0/1 = not suppressed/suppressed + "suppress_column_header": DXFAttr(281), + # The following group codes are repeated for every cell in the table + # 7: Text style name (string; default = STANDARD) + # 140: Text height (real) + # 170: Cell alignment (integer) + # 62: Text color (integer; default = BYBLOCK) + # 63: Cell fill color (integer; default = 7) + # 283: Flag for whether background color is enabled (default = 0): + # 0/1 = disabled/enabled + # 90: Cell data type + # 91: Cell unit type + # 274-279: Lineweight associated with each border type of the cell + # (default = kLnWtByBlock) + # 284-289: Flag for visibility associated with each border type of the cell + # (default = 1): 0/1 = Invisible/Visible + # 64-69: Color value associated with each border type of the cell + # (default = BYBLOCK) + }, +) + + +# todo: implement TABLESTYLE +class TableStyle(DXFObject): + """DXF TABLESTYLE entity + + Every ACAD_TABLE has its own table style. + + Requires DXF version AC1021/R2007 + """ + + DXFTYPE = "TABLESTYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_table_style) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2007 + + +class TableStyleManager(ObjectCollection[TableStyle]): + def __init__(self, doc: Drawing): + super().__init__(doc, dict_name="ACAD_TABLESTYLE", object_type="TABLESTYLE") + + +@factory.register_entity +class AcadTableBlockContent(DXFTagStorage): + DXFTYPE = "ACAD_TABLE" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_block_reference, acdb_table + ) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_block_reference_group_codes, subclass=2 + ) + processor.fast_load_dxfattribs( + dxf, acdb_table_group_codes, subclass=3, log=False + ) + return dxf + + def proxy_graphic_content(self) -> Iterable[DXFGraphic]: + return super().__virtual_entities__() + + def _block_content(self) -> Iterator[DXFGraphic]: + block_name: str = self.get_block_name() + return self.doc.blocks.get(block_name, []) # type: ignore + + def get_block_name(self) -> str: + return self.dxf.get("geometry", "") + + def get_insert_location(self) -> Vec3: + return self.dxf.get("insert", Vec3()) + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + insert: Vec3 = Vec3(self.get_insert_location()) + m: Optional[Matrix44] = None + if insert: + # TODO: OCS transformation (extrusion) is ignored yet + m = Matrix44.translate(insert.x, insert.y, insert.z) + + for entity in self._block_content(): + try: + clone = entity.copy() + except const.DXFTypeError: + continue + if m is not None: + try: + clone.transform(m) + except: # skip entity at any transformation issue + continue + yield clone + + +def acad_table_to_block(table: DXFEntity) -> None: + """Converts the given ACAD_TABLE entity to a block references (INSERT entity). + + The original ACAD_TABLE entity will be destroyed. + + .. versionadded:: 1.1 + + """ + if not isinstance(table, AcadTableBlockContent): + return + doc = table.doc + owner = table.dxf.owner + block_name = table.get_block_name() + if doc is None or block_name == "" or owner is None: + return + try: + layout = doc.layouts.get_layout_by_key(owner) + except const.DXFKeyError: + return + # replace ACAD_TABLE entity by INSERT entity + layout.add_blockref( + block_name, + insert=table.get_insert_location(), + dxfattribs={"layer": table.dxf.get("layer", "0")}, + ) + layout.delete_entity(table) # type: ignore + + +def read_acad_table_content(table: DXFTagStorage) -> list[list[str]]: + """Returns the content of an ACAD_TABLE entity as list of table rows. + + If the count of table rows or table columns is missing the complete content is + stored in the first row. + """ + if table.dxftype() != "ACAD_TABLE": + raise const.DXFTypeError(f"Expected ACAD_TABLE entity, got {str(table)}") + acdb_table = table.xtags.get_subclass("AcDbTable") + + nrows = acdb_table.get_first_value(91, 0) + ncols = acdb_table.get_first_value(92, 0) + split_code = 171 # DXF R2004 + if acdb_table.has_tag(302): + split_code = 301 # DXF R2007 and later + values = _load_table_values(acdb_table, split_code) + if nrows * ncols == 0: + return [values] + content: list[list[str]] = [] + for index in range(nrows): + start = index * ncols + content.append(values[start : start + ncols]) + return content + + +def _load_table_values(tags: Tags, split_code: int) -> list[str]: + values: list[str] = [] + for group in group_tags(tags, splitcode=split_code): + g_tags = Tags(group) + if g_tags.has_tag(302): # DXF R2007 and later + # contains all text as one long string, with more than 66000 chars tested + values.append(g_tags.get_first_value(302)) + else: + # DXF R2004 + # Text is divided into chunks (2, 2, 2, ..., 1) or (3, 3, 3, ..., 1) + # DXF reference says group code 2, BricsCAD writes group code 3 + s = "".join(tag.value for tag in g_tags if 1 <= tag.code <= 3) + values.append(s) + return values diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_xrec_roundtrip.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_xrec_roundtrip.py new file mode 100644 index 0000000..cf9b7d6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/acad_xrec_roundtrip.py @@ -0,0 +1,99 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +from ezdxf.entities import XRecord +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import DXFTag + +__all__ = ["RoundtripXRecord"] + +SECTION_MARKER_CODE = 102 +NOT_FOUND = -1 + +class RoundtripXRecord: + """Helper class for ACAD Roundtrip Data. + + The data is stored in an XRECORD, in sections separated by tags + (102, "ACAD_SECTION_NAME"). + + Example for inverted clipping path of SPATIAL_FILTER objects: + + ... + 100 + AcDbXrecord + 280 + 1 + 102 + ACAD_INVERTEDCLIP_ROUNDTRIP + 10 + 399.725563048036 + 20 + 233.417786599994 + 30 + 0.0 + ... + 102 + ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE + 10 + 399.725563048036 + 20 + 233.417786599994 + ... + + """ + + def __init__(self, xrecord: XRecord | None = None) -> None: + if xrecord is None: + xrecord = XRecord() + self.xrecord = xrecord + + def has_section(self, key: str) -> bool: + """Returns True if an entry section for key is present.""" + for code, value in self.xrecord.tags: + if code == SECTION_MARKER_CODE and value == key: + return True + return False + + def set_section(self, key: str, tags: Tags) -> None: + """Set content of section `key` to `tags`. Replaces the content of an existing section.""" + xrecord_tags = self.xrecord.tags + start, end = find_section(xrecord_tags, key) + if start == NOT_FOUND: + xrecord_tags.append(DXFTag(SECTION_MARKER_CODE, key)) + xrecord_tags.extend(tags) + else: + xrecord_tags[start + 1 : end] = tags + + def get_section(self, key: str) -> Tags: + """Returns the content of section `key`.""" + xrecord_tags = self.xrecord.tags + start, end = find_section(xrecord_tags, key) + if start != NOT_FOUND: + return xrecord_tags[start + 1 : end] + return Tags() + + def discard(self, key: str) -> None: + """Removes section `key`, section `key` doesn't have to exist.""" + xrecord_tags = self.xrecord.tags + start, end = find_section(xrecord_tags, key) + if start != NOT_FOUND: + del xrecord_tags[start:end] + + +def find_section(tags: Tags, key: str) -> tuple[int, int]: + """Returns the start- and end index of section `key`. + + Returns (-1, -1) if the section does not exist. + """ + start = NOT_FOUND + for index, tag in enumerate(tags): + if tag.code != 102: + continue + if tag.value == key: + start = index + elif start != NOT_FOUND: + return start, index + if start != NOT_FOUND: + return start, len(tags) + return NOT_FOUND, NOT_FOUND diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/acis.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/acis.py new file mode 100644 index 0000000..e540dc8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/acis.py @@ -0,0 +1,837 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Union, Optional, Sequence, Any +from typing_extensions import Self, override +import logging + +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + group_code_mapping, +) +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags, DXFTag +from ezdxf.math import Matrix44 +from ezdxf.tools import crypt, guid +from ezdxf import msgtypes + +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .copy import default_copy +from .temporary_transform import TransformByBlockReference + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + + +__all__ = [ + "Body", + "Solid3d", + "Region", + "Surface", + "ExtrudedSurface", + "LoftedSurface", + "RevolvedSurface", + "SweptSurface", +] + +logger = logging.getLogger("ezdxf") +acdb_modeler_geometry = DefSubclass( + "AcDbModelerGeometry", + { + "version": DXFAttr(70, default=1), + "flags": DXFAttr(290, dxfversion=const.DXF2013), + "uid": DXFAttr(2, dxfversion=const.DXF2013), + }, +) +acdb_modeler_geometry_group_codes = group_code_mapping(acdb_modeler_geometry) + +# with R2013/AC1027 Modeler Geometry of ACIS data is stored in the ACDSDATA +# section as binary encoded information detection: +# group code 70, 1, 3 is missing +# group code 290, 2 present +# +# 0 +# ACDSRECORD +# 90 +# 1 +# 2 +# AcDbDs::ID +# 280 +# 10 +# 320 +# 19B <<< handle of associated 3DSOLID entity in model space +# 2 +# ASM_Data +# 280 +# 15 +# 94 +# 7197 <<< size in bytes ??? +# 310 +# 414349532042696E61727946696C6... + + +@register_entity +class Body(DXFGraphic): + """DXF BODY entity - container entity for embedded ACIS data.""" + + DXFTYPE = "BODY" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_modeler_geometry) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def __init__(self) -> None: + super().__init__() + # Store SAT data as immutable sequence of strings, so the data can be shared + # across multiple copies of an ACIS entity. + self._sat: Sequence[str] = tuple() + self._sab: bytes = b"" + self._update = False + self._temporary_transformation = TransformByBlockReference() + + @property + def acis_data(self) -> Union[bytes, Sequence[str]]: + """Returns :term:`SAT` data for DXF R2000 up to R2010 and :term:`SAB` + data for DXF R2013 and later + """ + if self.has_binary_data: + return self.sab + return self.sat + + @property + def sat(self) -> Sequence[str]: + """Get/Set :term:`SAT` data as sequence of strings.""" + return self._sat + + @sat.setter + def sat(self, data: Sequence[str]) -> None: + """Set :term:`SAT` data as sequence of strings.""" + self._sat = tuple(data) + + @property + def sab(self) -> bytes: + """Get/Set :term:`SAB` data as bytes.""" + if ( # load SAB data on demand + self.doc is not None and self.has_binary_data and len(self._sab) == 0 + ): + self._sab = self.doc.acdsdata.get_acis_data(self.dxf.handle) + return self._sab + + @sab.setter + def sab(self, data: bytes) -> None: + """Set :term:`SAB` data as bytes.""" + self._update = True + self._sab = data + + @property + def has_binary_data(self): + """Returns ``True`` if the entity contains :term:`SAB` data and + ``False`` if the entity contains :term:`SAT` data. + """ + if self.doc: + return self.doc.dxfversion >= const.DXF2013 + else: + return False + + @override + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, Body) + entity.sat = self.sat + entity.sab = self.sab # load SAB on demand + entity.dxf.uid = guid() + entity._temporary_transformation = self._temporary_transformation + + @override + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + super().map_resources(clone, mapping) + clone.convert_acis_data() + + def convert_acis_data(self) -> None: + if self.doc is None: + return + msg = "" + dxfversion = self.doc.dxfversion + if dxfversion < const.DXF2013: + if self._sab: + self._sab = b"" + msg = "DXF version mismatch, can't convert ACIS data from SAB to SAT, SAB data removed." + else: + if self._sat: + self._sat = tuple() + msg = "DXF version mismatch, can't convert ACIS data from SAT to SAB, SAT data removed." + if msg: + logger.info(msg) + + @override + def notify(self, message_type: int, data: Any = None) -> None: + if message_type == msgtypes.COMMIT_PENDING_CHANGES: + self._temporary_transformation.apply_transformation(self) + + @override + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + msg = "" + if tagwriter.dxfversion < const.DXF2013: + valid = len(self.sat) > 0 + if not valid: + msg = f"{str(self)} doesn't have SAT data, skipping DXF export" + else: + valid = len(self.sab) > 0 + if not valid: + msg = f"{str(self)} doesn't have SAB data, skipping DXF export" + if not valid: + logger.info(msg) + if valid and self._temporary_transformation.get_matrix() is not None: + logger.warning(f"{str(self)} has unapplied temporary transformations.") + return valid + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_modeler_geometry_group_codes, 2, log=False + ) + if not self.has_binary_data: + self.load_sat_data(processor.subclasses[2]) + return dxf + + def load_sat_data(self, tags: Tags): + """Loading interface. (internal API)""" + text_lines = tags2textlines(tag for tag in tags if tag.code in (1, 3)) + self._sat = tuple(crypt.decode(text_lines)) + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_modeler_geometry.name) + if tagwriter.dxfversion >= const.DXF2013: + # ACIS data is stored in the ACDSDATA section as SAB + if self.doc and self._update: + # write back changed SAB data into AcDsDataSection or create + # a new ACIS record: + self.doc.acdsdata.set_acis_data(self.dxf.handle, self.sab) + if self.dxf.hasattr("version"): + tagwriter.write_tag2(70, self.dxf.version) + self.dxf.export_dxf_attribs(tagwriter, ["flags", "uid"]) + else: + # DXF R2000 - R2010 stores the ACIS data as SAT in the entity + self.dxf.export_dxf_attribs(tagwriter, "version") + self.export_sat_data(tagwriter) + + def export_sat_data(self, tagwriter: AbstractTagWriter) -> None: + """Export ACIS data as DXF tags. (internal API)""" + + def cleanup(lines): + for line in lines: + yield line.rstrip().replace("\n", "") + + tags = Tags(textlines2tags(crypt.encode(cleanup(self.sat)))) + tagwriter.write_tags(tags) + + def tostring(self) -> str: + """Returns ACIS :term:`SAT` data as a single string if the entity has + SAT data. + """ + if self.has_binary_data: + return "" + else: + return "\n".join(self.sat) + + @override + def destroy(self) -> None: + if self.has_binary_data: + self.doc.acdsdata.del_acis_data(self.dxf.handle) # type: ignore + super().destroy() + + @override + def transform(self, m: Matrix44) -> Self: + self._temporary_transformation.add_matrix(m) + return self + + def temporary_transformation(self) -> TransformByBlockReference: + return self._temporary_transformation + + +def tags2textlines(tags: Iterable) -> Iterable[str]: + """Yields text lines from code 1 and 3 tags, code 1 starts a line following + code 3 tags are appended to the line. + """ + line = None + for code, value in tags: + if code == 1: + if line is not None: + yield line + line = value + elif code == 3: + line += value + if line is not None: + yield line + + +def textlines2tags(lines: Iterable[str]) -> Iterable[DXFTag]: + """Yields text lines as DXFTags, splitting long lines (>255) int code 1 + and code 3 tags. + """ + for line in lines: + text = line[:255] + tail = line[255:] + yield DXFTag(1, text) + while len(tail): + text = tail[:255] + tail = tail[255:] + yield DXFTag(3, text) + + +@register_entity +class Region(Body): + """DXF REGION entity - container entity for embedded ACIS data.""" + + DXFTYPE = "REGION" + + +acdb_3dsolid = DefSubclass( + "AcDb3dSolid", + { + "history_handle": DXFAttr(350, default="0"), + }, +) +acdb_3dsolid_group_codes = group_code_mapping(acdb_3dsolid) + + +@register_entity +class Solid3d(Body): + """DXF 3DSOLID entity - container entity for embedded ACIS data.""" + + DXFTYPE = "3DSOLID" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_modeler_geometry, acdb_3dsolid + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_3dsolid_group_codes, 3) + return dxf + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + if tagwriter.dxfversion > const.DXF2004: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_3dsolid.name) + self.dxf.export_dxf_attribs(tagwriter, "history_handle") + + +def load_matrix(subclass: Tags, code: int) -> Matrix44: + values = [tag.value for tag in subclass.find_all(code)] + if len(values) != 16: + raise const.DXFStructureError("Invalid transformation matrix.") + return Matrix44(values) + + +def export_matrix(tagwriter: AbstractTagWriter, code: int, matrix: Matrix44) -> None: + for value in list(matrix): + tagwriter.write_tag2(code, value) + + +acdb_surface = DefSubclass( + "AcDbSurface", + { + "u_count": DXFAttr(71), + "v_count": DXFAttr(72), + }, +) +acdb_surface_group_codes = group_code_mapping(acdb_surface) + + +@register_entity +class Surface(Body): + """DXF SURFACE entity - container entity for embedded ACIS data.""" + + DXFTYPE = "SURFACE" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_modeler_geometry, acdb_surface + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_surface_group_codes, 3) + return dxf + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_surface.name) + self.dxf.export_dxf_attribs(tagwriter, ["u_count", "v_count"]) + + +acdb_extruded_surface = DefSubclass( + "AcDbExtrudedSurface", + { + "class_id": DXFAttr(90), + "sweep_vector": DXFAttr(10, xtype=XType.point3d), + # 16x group code 40: Transform matrix of extruded entity (16 floats; + # row major format; default = identity matrix) + "draft_angle": DXFAttr(42, default=0.0), # in radians + "draft_start_distance": DXFAttr(43, default=0.0), + "draft_end_distance": DXFAttr(44, default=0.0), + "twist_angle": DXFAttr(45, default=0.0), # in radians? + "scale_factor": DXFAttr(48, default=0.0), + "align_angle": DXFAttr(49, default=0.0), # in radians + # 16x group code 46: Transform matrix of sweep entity (16 floats; + # row major format; default = identity matrix) + # 16x group code 47: Transform matrix of path entity (16 floats; + # row major format; default = identity matrix) + "solid": DXFAttr(290, default=0), # bool + # 0=No alignment; 1=Align sweep entity to path: + "sweep_alignment_flags": DXFAttr(70, default=0), + "unknown1": DXFAttr(71, default=0), + # 2=Translate sweep entity to path; 3=Translate path to sweep entity: + "align_start": DXFAttr(292, default=0), # bool + "bank": DXFAttr(293, default=0), # bool + "base_point_set": DXFAttr(294, default=0), # bool + "sweep_entity_transform_computed": DXFAttr(295, default=0), # bool + "path_entity_transform_computed": DXFAttr(296, default=0), # bool + "reference_vector_for_controlling_twist": DXFAttr(11, xtype=XType.point3d), + }, +) +acdb_extruded_surface_group_codes = group_code_mapping(acdb_extruded_surface) + + +@register_entity +class ExtrudedSurface(Surface): + """DXF EXTRUDEDSURFACE entity - container entity for embedded ACIS data.""" + + DXFTYPE = "EXTRUDEDSURFACE" + DXFATTRIBS = DXFAttributes( + base_class, + acdb_entity, + acdb_modeler_geometry, + acdb_surface, + acdb_extruded_surface, + ) + + def __init__(self): + super().__init__() + self.transformation_matrix_extruded_entity = Matrix44() + self.sweep_entity_transformation_matrix = Matrix44() + self.path_entity_transformation_matrix = Matrix44() + + @override + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, ExtrudedSurface) + super().copy_data(entity, copy_strategy) + entity.transformation_matrix_extruded_entity = ( + self.transformation_matrix_extruded_entity.copy() + ) + entity.sweep_entity_transformation_matrix = ( + self.sweep_entity_transformation_matrix.copy() + ) + entity.path_entity_transformation_matrix = ( + self.path_entity_transformation_matrix.copy() + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_extruded_surface_group_codes, 4, log=False + ) + self.load_matrices(processor.subclasses[4]) + return dxf + + def load_matrices(self, tags: Tags): + self.transformation_matrix_extruded_entity = load_matrix(tags, code=40) + self.sweep_entity_transformation_matrix = load_matrix(tags, code=46) + self.path_entity_transformation_matrix = load_matrix(tags, code=47) + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_extruded_surface.name) + self.dxf.export_dxf_attribs(tagwriter, ["class_id", "sweep_vector"]) + export_matrix( + tagwriter, + code=40, + matrix=self.transformation_matrix_extruded_entity, + ) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "draft_angle", + "draft_start_distance", + "draft_end_distance", + "twist_angle", + "scale_factor", + "align_angle", + ], + ) + export_matrix( + tagwriter, code=46, matrix=self.sweep_entity_transformation_matrix + ) + export_matrix(tagwriter, code=47, matrix=self.path_entity_transformation_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "solid", + "sweep_alignment_flags", + "unknown1", + "align_start", + "bank", + "base_point_set", + "sweep_entity_transform_computed", + "path_entity_transform_computed", + "reference_vector_for_controlling_twist", + ], + ) + + +acdb_lofted_surface = DefSubclass( + "AcDbLoftedSurface", + { + # 16x group code 40: Transform matrix of loft entity (16 floats; + # row major format; default = identity matrix) + "plane_normal_lofting_type": DXFAttr(70), + "start_draft_angle": DXFAttr(41, default=0.0), # in radians + "end_draft_angle": DXFAttr(42, default=0.0), # in radians + "start_draft_magnitude": DXFAttr(43, default=0.0), + "end_draft_magnitude": DXFAttr(44, default=0.0), + "arc_length_parameterization": DXFAttr(290, default=0), # bool + "no_twist": DXFAttr(291, default=1), # true/false + "align_direction": DXFAttr(292, default=1), # bool + "simple_surfaces": DXFAttr(293, default=1), # bool + "closed_surfaces": DXFAttr(294, default=0), # bool + "solid": DXFAttr(295, default=0), # true/false + "ruled_surface": DXFAttr(296, default=0), # bool + "virtual_guide": DXFAttr(297, default=0), # bool + }, +) +acdb_lofted_surface_group_codes = group_code_mapping(acdb_lofted_surface) + + +@register_entity +class LoftedSurface(Surface): + """DXF LOFTEDSURFACE entity - container entity for embedded ACIS data.""" + + DXFTYPE = "LOFTEDSURFACE" + DXFATTRIBS = DXFAttributes( + base_class, + acdb_entity, + acdb_modeler_geometry, + acdb_surface, + acdb_lofted_surface, + ) + + def __init__(self): + super().__init__() + self.transformation_matrix_lofted_entity = Matrix44() + + @override + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, LoftedSurface) + super().copy_data(entity, copy_strategy) + entity.transformation_matrix_lofted_entity = ( + self.transformation_matrix_lofted_entity.copy() + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_lofted_surface_group_codes, 4, log=False + ) + self.load_matrices(processor.subclasses[4]) + return dxf + + def load_matrices(self, tags: Tags): + self.transformation_matrix_lofted_entity = load_matrix(tags, code=40) + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_lofted_surface.name) + export_matrix( + tagwriter, code=40, matrix=self.transformation_matrix_lofted_entity + ) + self.dxf.export_dxf_attribs(tagwriter, acdb_lofted_surface.attribs.keys()) + + +acdb_revolved_surface = DefSubclass( + "AcDbRevolvedSurface", + { + "class_id": DXFAttr(90, default=0.0), + "axis_point": DXFAttr(10, xtype=XType.point3d), + "axis_vector": DXFAttr(11, xtype=XType.point3d), + "revolve_angle": DXFAttr(40), # in radians + "start_angle": DXFAttr(41), # in radians + # 16x group code 42: Transform matrix of revolved entity (16 floats; + # row major format; default = identity matrix) + "draft_angle": DXFAttr(43), # in radians + "start_draft_distance": DXFAttr(44, default=0), + "end_draft_distance": DXFAttr(45, default=0), + "twist_angle": DXFAttr(46, default=0), # in radians + "solid": DXFAttr(290, default=0), # bool + "close_to_axis": DXFAttr(291, default=0), # bool + }, +) +acdb_revolved_surface_group_codes = group_code_mapping(acdb_revolved_surface) + + +@register_entity +class RevolvedSurface(Surface): + """DXF REVOLVEDSURFACE entity - container entity for embedded ACIS data.""" + + DXFTYPE = "REVOLVEDSURFACE" + DXFATTRIBS = DXFAttributes( + base_class, + acdb_entity, + acdb_modeler_geometry, + acdb_surface, + acdb_revolved_surface, + ) + + def __init__(self): + super().__init__() + self.transformation_matrix_revolved_entity = Matrix44() + + @override + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, RevolvedSurface) + super().copy_data(entity, copy_strategy) + entity.transformation_matrix_revolved_entity = ( + self.transformation_matrix_revolved_entity.copy() + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_revolved_surface_group_codes, 4, log=False + ) + self.load_matrices(processor.subclasses[4]) + return dxf + + def load_matrices(self, tags: Tags): + self.transformation_matrix_revolved_entity = load_matrix(tags, code=42) + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_revolved_surface.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "class_id", + "axis_point", + "axis_vector", + "revolve_angle", + "start_angle", + ], + ) + export_matrix( + tagwriter, + code=42, + matrix=self.transformation_matrix_revolved_entity, + ) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "draft_angle", + "start_draft_distance", + "end_draft_distance", + "twist_angle", + "solid", + "close_to_axis", + ], + ) + + +acdb_swept_surface = DefSubclass( + "AcDbSweptSurface", + { + "swept_entity_id": DXFAttr(90), + # 90: size of binary data (lost on saving) + # 310: binary data (lost on saving) + "path_entity_id": DXFAttr(91), + # 90: size of binary data (lost on saving) + # 310: binary data (lost on saving) + # 16x group code 40: Transform matrix of sweep entity (16 floats; + # row major format; default = identity matrix) + # 16x group code 41: Transform matrix of path entity (16 floats; + # row major format; default = identity matrix) + "draft_angle": DXFAttr(42), # in radians + "draft_start_distance": DXFAttr(43, default=0), + "draft_end_distance": DXFAttr(44, default=0), + "twist_angle": DXFAttr(45, default=0), # in radians + "scale_factor": DXFAttr(48, default=1), + "align_angle": DXFAttr(49, default=0), # in radians + # don't know the meaning of this matrices + # 16x group code 46: Transform matrix of sweep entity (16 floats; + # row major format; default = identity matrix) + # 16x group code 47: Transform matrix of path entity (16 floats; + # row major format; default = identity matrix) + "solid": DXFAttr(290, default=0), # in radians + # 0=No alignment; 1= align sweep entity to path: + "sweep_alignment": DXFAttr(70, default=0), + "unknown1": DXFAttr(71, default=0), + # 2=Translate sweep entity to path; 3=Translate path to sweep entity: + "align_start": DXFAttr(292, default=0), # bool + "bank": DXFAttr(293, default=0), # bool + "base_point_set": DXFAttr(294, default=0), # bool + "sweep_entity_transform_computed": DXFAttr(295, default=0), # bool + "path_entity_transform_computed": DXFAttr(296, default=0), # bool + "reference_vector_for_controlling_twist": DXFAttr(11, xtype=XType.point3d), + }, +) +acdb_swept_surface_group_codes = group_code_mapping(acdb_swept_surface) + + +@register_entity +class SweptSurface(Surface): + """DXF SWEPTSURFACE entity - container entity for embedded ACIS data.""" + + DXFTYPE = "SWEPTSURFACE" + DXFATTRIBS = DXFAttributes( + base_class, + acdb_entity, + acdb_modeler_geometry, + acdb_surface, + acdb_swept_surface, + ) + + def __init__(self): + super().__init__() + self.transformation_matrix_sweep_entity = Matrix44() + self.transformation_matrix_path_entity = Matrix44() + self.sweep_entity_transformation_matrix = Matrix44() + self.path_entity_transformation_matrix = Matrix44() + + @override + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, SweptSurface) + super().copy_data(entity, copy_strategy) + entity.transformation_matrix_sweep_entity = ( + self.transformation_matrix_sweep_entity.copy() + ) + entity.transformation_matrix_path_entity = ( + self.transformation_matrix_path_entity.copy() + ) + entity.sweep_entity_transformation_matrix = ( + self.sweep_entity_transformation_matrix.copy() + ) + entity.path_entity_transformation_matrix = ( + self.path_entity_transformation_matrix.copy() + ) + + @override + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_swept_surface_group_codes, 4, log=False + ) + self.load_matrices(processor.subclasses[4]) + return dxf + + def load_matrices(self, tags: Tags): + self.transformation_matrix_sweep_entity = load_matrix(tags, code=40) + self.transformation_matrix_path_entity = load_matrix(tags, code=41) + self.sweep_entity_transformation_matrix = load_matrix(tags, code=46) + self.path_entity_transformation_matrix = load_matrix(tags, code=47) + + @override + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # base class export is done by parent class + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbModelerGeometry export is done by parent class + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_swept_surface.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "swept_entity_id", + "path_entity_id", + ], + ) + export_matrix( + tagwriter, code=40, matrix=self.transformation_matrix_sweep_entity + ) + export_matrix(tagwriter, code=41, matrix=self.transformation_matrix_path_entity) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "draft_angle", + "draft_start_distance", + "draft_end_distance", + "twist_angle", + "scale_factor", + "align_angle", + ], + ) + + export_matrix( + tagwriter, code=46, matrix=self.sweep_entity_transformation_matrix + ) + export_matrix(tagwriter, code=47, matrix=self.path_entity_transformation_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "solid", + "sweep_alignment", + "unknown1", + "align_start", + "bank", + "base_point_set", + "sweep_entity_transform_computed", + "path_entity_transform_computed", + "reference_vector_for_controlling_twist", + ], + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/appdata.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/appdata.py new file mode 100644 index 0000000..eec32ab --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/appdata.py @@ -0,0 +1,149 @@ +# Copyright (c) 2019-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Sequence, Optional, Iterator +from ezdxf.lldxf.types import dxftag, uniform_appid +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.const import DXFKeyError, DXFStructureError +from ezdxf.lldxf.const import ( + ACAD_REACTORS, + REACTOR_HANDLE_CODE, + APP_DATA_MARKER, +) + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["AppData", "Reactors"] + +ERR_INVALID_DXF_ATTRIB = "Invalid DXF attribute for entity {}" +ERR_DXF_ATTRIB_NOT_EXITS = "DXF attribute {} does not exist" + + +class AppData: + def __init__(self) -> None: + self.data: dict[str, Tags] = dict() + + def __contains__(self, appid: str) -> bool: + """Returns ``True`` if application-defined data exist for `appid`.""" + return uniform_appid(appid) in self.data + + def __len__(self) -> int: + """Returns the count of AppData.""" + return len(self.data) + + def tags(self) -> Iterable[Tags]: + return self.data.values() + + def get(self, appid: str) -> Tags: + """Get application-defined data for `appid` as + :class:`~ezdxf.lldxf.tags.Tags` container. + The first tag is always (102, "{APPID"). + The last tag is always (102, "}"). + """ + try: + return self.data[uniform_appid(appid)] + except KeyError: + raise DXFKeyError(appid) + + def set(self, tags: Tags) -> None: + """Store raw application-defined data tags. + The first tag has to be (102, "{APPID"). + The last tag has to be (102, "}"). + """ + if len(tags): + appid = tags[0].value + self.data[appid] = tags + + def add(self, appid: str, data: Iterable[Sequence]) -> None: + """Add application-defined tags for `appid`. + Adds first tag (102, "{APPID") if not exist. + Adds last tag (102, "}" if not exist. + """ + data = Tags(dxftag(code, value) for code, value in data) + appid = uniform_appid(appid) + if data[0] != (APP_DATA_MARKER, appid): + data.insert(0, dxftag(APP_DATA_MARKER, appid)) + if data[-1] != (APP_DATA_MARKER, "}"): + data.append(dxftag(APP_DATA_MARKER, "}")) + self.set(data) + + def discard(self, appid: str): + """Delete application-defined data for `appid` without raising and error + if `appid` doesn't exist. + """ + _appid = uniform_appid(appid) + if _appid in self.data: + del self.data[_appid] + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + for data in self.data.values(): + tagwriter.write_tags(data) + + +class Reactors: + """Handle storage for related reactors. + + Reactors are other objects related to the object that contains this + Reactor() instance. + + """ + + def __init__(self, handles: Optional[Iterable[str]] = None): + self.reactors: set[str] = set(handles or []) + + def __len__(self) -> int: + """Returns count of registered handles.""" + return len(self.reactors) + + def __contains__(self, handle: str) -> bool: + """Returns ``True`` if `handle` is registered.""" + return handle in self.reactors + + def __iter__(self) -> Iterator[str]: + """Returns an iterator for all registered handles.""" + return iter(self.get()) + + def copy(self) -> Reactors: + """Returns a copy.""" + return Reactors(self.reactors) + + @classmethod + def from_tags(cls, tags: Optional[Tags] = None) -> Reactors: + """Create Reactors() instance from tags. + + Expected DXF structure: + [(102, '{ACAD_REACTORS'), (330, handle), ..., (102, '}')] + + Args: + tags: list of DXFTags() + + """ + if tags is None: + return cls(None) + + if len(tags) < 2: # no reactors are valid + raise DXFStructureError("ACAD_REACTORS error") + return cls((handle.value for handle in tags[1:-1])) + + def get(self) -> list[str]: + """Returns all registered handles as sorted list.""" + return sorted(self.reactors, key=lambda x: int(x, base=16)) + + def set(self, handles: Optional[Iterable[str]]) -> None: + """Reset all handles.""" + self.reactors = set(handles or []) + + def add(self, handle: str) -> None: + """Add a single `handle`.""" + self.reactors.add(handle) + + def discard(self, handle: str): + """Discard a single `handle`.""" + self.reactors.discard(handle) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(APP_DATA_MARKER, ACAD_REACTORS) + for handle in self.get(): + tagwriter.write_tag2(REACTOR_HANDLE_CODE, handle) + tagwriter.write_tag2(APP_DATA_MARKER, "}") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/appid.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/appid.py new file mode 100644 index 0000000..15020ef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/appid.py @@ -0,0 +1,62 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging + +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from ezdxf.lldxf.validator import is_valid_table_name +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["AppID"] +logger = logging.getLogger("ezdxf") + +acdb_appid = DefSubclass( + "AcDbRegAppTableRecord", + { + "name": DXFAttr(2, validator=is_valid_table_name), + "flags": DXFAttr(70, default=0), + }, +) + +acdb_appid_group_codes = group_code_mapping(acdb_appid) + + +@register_entity +class AppID(DXFEntity): + """DXF APPID entity""" + + DXFTYPE = "APPID" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_appid) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_appid_group_codes, subclass=2 + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_appid.name) + + # for all DXF versions + self.dxf.export_dxf_attribs(tagwriter, ["name", "flags"]) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/arc.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/arc.py new file mode 100644 index 0000000..3aaaf23 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/arc.py @@ -0,0 +1,148 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator +import math +import numpy as np + +from ezdxf.math import ( + Vec3, + Matrix44, + ConstructionArc, + arc_angle_span_deg, +) +from ezdxf.math.transformtools import OCSTransform + +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from .dxfentity import base_class +from .dxfgfx import acdb_entity +from .circle import acdb_circle, Circle, merged_circle_group_codes +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Arc"] + +acdb_arc = DefSubclass( + "AcDbArc", + { + "start_angle": DXFAttr(50, default=0), + "end_angle": DXFAttr(51, default=360), + }, +) + +acdb_arc_group_codes = group_code_mapping(acdb_arc) +merged_arc_group_codes = merge_group_code_mappings( + merged_circle_group_codes, acdb_arc_group_codes +) + + +@register_entity +class Arc(Circle): + """DXF ARC entity""" + + DXFTYPE = "ARC" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_circle, acdb_arc) + MERGED_GROUP_CODES = merged_arc_group_codes + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + # AcDbCircle export is done by parent class + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_arc.name) + self.dxf.export_dxf_attribs(tagwriter, ["start_angle", "end_angle"]) + + @property + def start_point(self) -> Vec3: + """Returns the start point of the arc in :ref:`WCS`, takes the :ref:`OCS` into + account. + """ + v = list(self.vertices([self.dxf.start_angle])) + return v[0] + + @property + def end_point(self) -> Vec3: + """Returns the end point of the arc in :ref:`WCS`, takes the :ref:`OCS` into + account. + """ + v = list(self.vertices([self.dxf.end_angle])) + return v[0] + + def angles(self, num: int) -> Iterator[float]: + """Yields `num` angles from start- to end angle in degrees in counter-clockwise + orientation. All angles are normalized in the range from [0, 360). + """ + if num < 2: + raise ValueError("num >= 2") + start = self.dxf.start_angle % 360 + stop = self.dxf.end_angle % 360 + if stop <= start: + stop += 360 + for angle in np.linspace(start, stop, num=num, endpoint=True): + yield angle % 360 + + def flattening(self, sagitta: float) -> Iterator[Vec3]: + """Approximate the arc by vertices in :ref:`WCS`, the argument `sagitta`_ + defines the maximum distance from the center of an arc segment to the center of + its chord. + + .. _sagitta: https://en.wikipedia.org/wiki/Sagitta_(geometry) + """ + arc = self.construction_tool() + ocs = self.ocs() + elevation = Vec3(self.dxf.center).z + if ocs.transform: + to_wcs = ocs.points_to_wcs + else: + to_wcs = Vec3.generate + + yield from to_wcs(Vec3(p.x, p.y, elevation) for p in arc.flattening(sagitta)) + + def transform(self, m: Matrix44) -> Arc: + """Transform ARC entity by transformation matrix `m` inplace. + Raises ``NonUniformScalingError()`` for non-uniform scaling. + """ + ocs = OCSTransform(self.dxf.extrusion, m) + super()._transform(ocs) + s: float = self.dxf.start_angle + e: float = self.dxf.end_angle + if not math.isclose(arc_angle_span_deg(s, e), 360.0): + ( + self.dxf.start_angle, + self.dxf.end_angle, + ) = ocs.transform_ccw_arc_angles_deg(s, e) + self.post_transform(m) + return self + + def construction_tool(self) -> ConstructionArc: + """Returns the 2D construction tool :class:`ezdxf.math.ConstructionArc` but the + extrusion vector is ignored. + """ + dxf = self.dxf + return ConstructionArc( + dxf.center, + dxf.radius, + dxf.start_angle, + dxf.end_angle, + ) + + def apply_construction_tool(self, arc: ConstructionArc) -> Arc: + """Set ARC data from the construction tool :class:`ezdxf.math.ConstructionArc` + but the extrusion vector is ignored. + """ + dxf = self.dxf + dxf.center = Vec3(arc.center) + dxf.radius = arc.radius + dxf.start_angle = arc.start_angle + dxf.end_angle = arc.end_angle + return self # floating interface diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/attrib.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/attrib.py new file mode 100644 index 0000000..130ea74 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/attrib.py @@ -0,0 +1,710 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +import copy +from ezdxf.lldxf import validator +from ezdxf.math import NULLVEC, Vec3, Z_AXIS, OCS, Matrix44 +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf import const +from ezdxf.lldxf.types import EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR +from ezdxf.enums import MAP_MTEXT_ALIGN_TO_FLAGS, TextHAlign, TextVAlign +from ezdxf.tools import set_flag_state +from ezdxf.tools.text import ( + load_mtext_content, + fast_plain_mtext, + plain_mtext, +) + +from .dxfns import SubclassProcessor, DXFNamespace +from .dxfentity import base_class +from .dxfgfx import acdb_entity, elevation_to_z_axis +from .text import Text, acdb_text, acdb_text_group_codes +from .mtext import ( + acdb_mtext_group_codes, + MText, + export_mtext_content, + acdb_mtext, +) +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.tags import Tags + from ezdxf.entities import DXFEntity + from ezdxf import xref + + +__all__ = ["AttDef", "Attrib", "copy_attrib_as_text", "BaseAttrib"] + +# Where is it valid to place an ATTRIB entity: +# - YES: attached to an INSERT entity +# - NO: stand-alone entity in model space - ignored by BricsCAD and TrueView +# - NO: stand-alone entity in paper space - ignored by BricsCAD and TrueView +# - NO: stand-alone entity in block layout - ignored by BricsCAD and TrueView +# +# The RECOVER command of BricsCAD removes the stand-alone ATTRIB entities: +# "Invalid subentity type AcDbAttribute()" +# +# IMPORTANT: placing ATTRIB at an invalid layout does NOT create an invalid DXF file! +# +# Where is it valid to place an ATTDEF entity: +# - NO: attached to an INSERT entity +# - YES: stand-alone entity in a BLOCK layout - BricsCAD and TrueView render the +# TAG in the block editor and does not render the ATTDEF as block content +# for the INSERT entity. +# - YES: stand-alone entity in model space - BricsCAD and TrueView render the +# TAG not the default text - the model space is also a block content +# (XREF, see also INSERT entity) +# - YES: stand-alone entity in paper space - same as model space, although a +# paper space can not be used as XREF. + +# DXF Reference for ATTRIB is a total mess and incorrect, the AcDbText subclass +# for the ATTRIB entity is the same as for the TEXT entity, but the valign field +# from the 2nd AcDbText subclass of the TEXT entity is stored in the +# AcDbAttribute subclass: +attrib_fields = { + # "version": DXFAttr(280, default=0, dxfversion=const.DXF2010), + # The "version" tag has the same group code as the lock_position tag!!!!! + # Version number: 0 = 2010 + # This tag is not really used (at least by BricsCAD) but there exists DXF files + # which do use this tag: "dxftest\attrib\attrib_with_mtext_R2018.dxf" + # ezdxf stores the last group code 280 as "lock_position" attribute and does + # not export a version tag for any DXF version. + # Tag string (cannot contain spaces): + "tag": DXFAttr( + 2, + default="", + validator=validator.is_valid_attrib_tag, + fixer=validator.fix_attrib_tag, + ), + # 1 = Attribute is invisible (does not appear) + # 2 = This is a constant attribute + # 4 = Verification is required on input of this attribute + # 8 = Attribute is preset (no prompt during insertion) + "flags": DXFAttr(70, default=0), + # Field length (optional) (not currently used) + "field_length": DXFAttr(73, default=0, optional=True), + # Vertical text justification type (optional); see group code 73 in TEXT + "valign": DXFAttr( + 74, + default=0, + optional=True, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Lock position flag. Locks the position of the attribute within the block + # reference, example of double use of group codes in one sub class + "lock_position": DXFAttr( + 280, + default=0, + dxfversion=const.DXF2007, # tested with BricsCAD 2023/TrueView 2023 + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Attribute type: + # 1 = single line + # 2 = multiline ATTRIB + # 4 = multiline ATTDEF + "attribute_type": DXFAttr( + 71, + default=1, + dxfversion=const.DXF2018, + optional=True, + validator=validator.is_one_of({1, 2, 4}), + fixer=RETURN_DEFAULT, + ), +} + +# ATTDEF has an additional field: 'prompt' +# DXF attribute definitions are immutable, a shallow copy is sufficient: +attdef_fields = dict(attrib_fields) +attdef_fields["prompt"] = DXFAttr( + 3, + default="", + validator=validator.is_valid_one_line_text, + fixer=validator.fix_one_line_text, +) + +acdb_attdef = DefSubclass("AcDbAttributeDefinition", attdef_fields) +acdb_attdef_group_codes = group_code_mapping(acdb_attdef) +acdb_attrib = DefSubclass("AcDbAttribute", attrib_fields) +acdb_attrib_group_codes = group_code_mapping(acdb_attrib) + +# -------------------------------------------------------------------------------------- +# Does subclass AcDbXrecord really exist? Only the documentation in the DXF reference +# exists, no real world examples seen so far - it wouldn't be the first error or misleading +# information in the DXF reference. +# -------------------------------------------------------------------------------------- +# For XRECORD the tag order is important and group codes appear multiple times, +# therefore this attribute definition needs a special treatment! +acdb_attdef_xrecord = DefSubclass( + "AcDbXrecord", + [ # type: ignore + # Duplicate record cloning flag (determines how to merge duplicate entries): + # 1 = Keep existing + ("cloning", DXFAttr(280, default=1)), + # MText flag: + # 2 = multiline attribute + # 4 = constant multiline attribute definition + ("mtext_flag", DXFAttr(70, default=0)), + # isReallyLocked flag: + # 0 = unlocked + # 1 = locked + ( + "really_locked", + DXFAttr( + 70, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + ), + # Number of secondary attributes or attribute definitions: + ("secondary_attribs_count", DXFAttr(70, default=0)), + # Hard-pointer id of secondary attribute(s) or attribute definition(s): + ("secondary_attribs_handle", DXFAttr(340, default="0")), + # Alignment point of attribute or attribute definition: + ("align_point", DXFAttr(10, xtype=XType.point3d, default=NULLVEC)), + ("current_annotation_scale", DXFAttr(40, default=0)), + # attribute or attribute definition tag string + ( + "tag", + DXFAttr( + 2, + default="", + validator=validator.is_valid_attrib_tag, + fixer=validator.fix_attrib_tag, + ), + ), + ], +) + + +# Just for documentation: +# The "attached" MTEXT feature most likely does not exist! +# +# A special MTEXT entity can follow the ATTDEF and ATTRIB entity, which starts +# as a usual DXF entity with (0, 'MTEXT'), so processing can't be done here, +# because for ezdxf is this a separated Entity. +# +# The attached MTEXT entity: owner is None and handle is None +# Linked as attribute `attached_mtext`. +# I don't have seen this combination of entities in real world examples and is +# ignored by ezdxf for now. +# +# No DXF files available which uses this feature - misleading DXF Reference!? + +# Attrib and Attdef can have embedded MTEXT entities located in the +# subclass, see issue #258 + + +class BaseAttrib(Text): + XRECORD_DEF = acdb_attdef_xrecord + + def __init__(self) -> None: + super().__init__() + # Does subclass AcDbXrecord really exist? + self._xrecord: Optional[Tags] = None + self._embedded_mtext: Optional[EmbeddedMText] = None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy entity data, xrecord data and embedded MTEXT are not stored + in the entity database. + """ + assert isinstance(entity, BaseAttrib) + entity._xrecord = copy.deepcopy(self._xrecord) + entity._embedded_mtext = copy.deepcopy(self._embedded_mtext) + + def load_embedded_mtext(self, processor: SubclassProcessor) -> None: + if not processor.embedded_objects: + return + embedded_object = processor.embedded_objects[0] + if embedded_object: + mtext = EmbeddedMText() + mtext.load_dxf_tags(processor) + self._embedded_mtext = mtext + + def export_dxf_r2018_features(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(71, self.dxf.attribute_type) + tagwriter.write_tag2(72, 0) # unknown tag + if self.dxf.hasattr("align_point"): + # duplicate align point - why? + tagwriter.write_vertex(11, self.dxf.align_point) + + if self._xrecord: + tagwriter.write_tags(self._xrecord) + if self._embedded_mtext: + self._embedded_mtext.export_dxf_tags(tagwriter) + + @property + def is_const(self) -> bool: + """This is a constant attribute if ``True``.""" + return bool(self.dxf.flags & const.ATTRIB_CONST) + + @is_const.setter + def is_const(self, state: bool) -> None: + self.dxf.flags = set_flag_state(self.dxf.flags, const.ATTRIB_CONST, state) + + @property + def is_invisible(self) -> bool: + """Attribute is invisible if ``True``.""" + return bool(self.dxf.flags & const.ATTRIB_INVISIBLE) + + @is_invisible.setter + def is_invisible(self, state: bool) -> None: + self.dxf.flags = set_flag_state(self.dxf.flags, const.ATTRIB_INVISIBLE, state) + + @property + def is_verify(self) -> bool: + """Verification is required on input of this attribute. (interactive CAD + application feature) + """ + return bool(self.dxf.flags & const.ATTRIB_VERIFY) + + @is_verify.setter + def is_verify(self, state: bool) -> None: + self.dxf.flags = set_flag_state(self.dxf.flags, const.ATTRIB_VERIFY, state) + + @property + def is_preset(self) -> bool: + """No prompt during insertion. (interactive CAD application feature)""" + return bool(self.dxf.flags & const.ATTRIB_IS_PRESET) + + @is_preset.setter + def is_preset(self, state: bool) -> None: + self.dxf.flags = set_flag_state(self.dxf.flags, const.ATTRIB_IS_PRESET, state) + + @property + def has_embedded_mtext_entity(self) -> bool: + """Returns ``True`` if the entity has an embedded MTEXT entity for multi-line + support. + """ + return bool(self._embedded_mtext) + + def virtual_mtext_entity(self) -> MText: + """Returns the embedded MTEXT entity as a regular but virtual + :class:`MText` entity with the same graphical properties as the + host entity. + """ + if not self._embedded_mtext: + raise TypeError("no embedded MTEXT entity exist") + mtext = self._embedded_mtext.virtual_mtext_entity() + mtext.update_dxf_attribs(self.graphic_properties()) + return mtext + + def plain_mtext(self, fast=True) -> str: + """Returns the embedded MTEXT content without formatting codes. + Returns an empty string if no embedded MTEXT entity exist. + + The `fast` mode is accurate if the DXF content was created by + reliable (and newer) CAD applications like AutoCAD or BricsCAD. + The `accurate` mode is for some rare cases where the content was + created by older CAD applications or unreliable DXF libraries and CAD + applications. + + The `accurate` mode is **much** slower than the `fast` mode. + + Args: + fast: uses the `fast` mode to extract the plain MTEXT content if + ``True`` or the `accurate` mode if set to ``False`` + + """ + if self._embedded_mtext: + text = self._embedded_mtext.text + if fast: + return fast_plain_mtext(text, split=False) # type: ignore + else: + return plain_mtext(text, split=False) # type: ignore + return "" + + def set_mtext(self, mtext: MText, graphic_properties=True) -> None: + """Set multi-line properties from a :class:`MText` entity. + + The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an + ordinary single line ATTRIB/ATTDEF entity will be exported. + + Args: + mtext: source :class:`MText` entity + graphic_properties: copy graphic properties (color, layer, ...) from + source MTEXT if ``True`` + + """ + if self._embedded_mtext is None: + self._embedded_mtext = EmbeddedMText() + self._embedded_mtext.set_mtext(mtext) + _update_content_from_mtext(self, mtext) + _update_location_from_mtext(self, mtext) + # misc properties + self.dxf.style = mtext.dxf.style + self.dxf.height = mtext.dxf.char_height + self.dxf.discard("width") # controlled in MTEXT by inline codes! + self.dxf.discard("oblique") # controlled in MTEXT by inline codes! + self.dxf.discard("text_generation_flag") + if graphic_properties: + self.update_dxf_attribs(mtext.graphic_properties()) + + def embed_mtext(self, mtext: MText, graphic_properties=True) -> None: + """Set multi-line properties from a :class:`MText` entity and destroy the + source entity afterwards. + + The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an + ordinary single line ATTRIB/ATTDEF entity will be exported. + + Args: + mtext: source :class:`MText` entity + graphic_properties: copy graphic properties (color, layer, ...) from + source MTEXT if ``True`` + + """ + self.set_mtext(mtext, graphic_properties) + mtext.destroy() + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + if self._embedded_mtext: + self._embedded_mtext.register_resources(registry) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, BaseAttrib) + super().map_resources(clone, mapping) + if self._embedded_mtext and clone._embedded_mtext: + self._embedded_mtext.map_resources(clone._embedded_mtext, mapping) + # todo: map handles in embedded XRECORD if a real world example shows up + + def transform(self, m: Matrix44) -> Self: + if self._embedded_mtext is None: + super().transform(m) + else: + mtext = self._embedded_mtext.virtual_mtext_entity() + mtext.transform(m) + self.set_mtext(mtext, graphic_properties=False) + self.post_transform(m) + return self + + +def _update_content_from_mtext(text: Text, mtext: MText) -> None: + content = mtext.plain_text(split=True, fast=True) + if content: + # In contrast to AutoCAD, just set the first line as single line + # ATTRIB content. AutoCAD concatenates all lines into a single + # "Line1\PLine2\P...", which (imho) is not very useful. + text.dxf.text = content[0] + + +def _update_location_from_mtext(text: Text, mtext: MText) -> None: + # TEXT is an OCS entity, MTEXT is a WCS entity + dxf = text.dxf + insert = Vec3(mtext.dxf.insert) + extrusion = Vec3(mtext.dxf.extrusion) + text_direction = mtext.get_text_direction() + if extrusion.isclose(Z_AXIS): # most common case + dxf.rotation = text_direction.angle_deg + else: + ocs = OCS(extrusion) + insert = ocs.from_wcs(insert) + dxf.extrusion = extrusion.normalize() + dxf.rotation = ocs.from_wcs(text_direction).angle_deg + + dxf.insert = insert + dxf.align_point = insert # the same point for all MTEXT alignments! + dxf.halign, dxf.valign = MAP_MTEXT_ALIGN_TO_FLAGS.get( + mtext.dxf.attachment_point, (TextHAlign.LEFT, TextVAlign.TOP) + ) + + +@register_entity +class AttDef(BaseAttrib): + """DXF ATTDEF entity""" + + DXFTYPE = "ATTDEF" + # Don't add acdb_attdef_xrecord here: + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_text, acdb_attdef) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super(Text, self).load_dxf_attribs(processor) + # Do not call Text loader. + if processor: + processor.fast_load_dxfattribs(dxf, acdb_text_group_codes, 2, recover=True) + processor.fast_load_dxfattribs( + dxf, acdb_attdef_group_codes, 3, recover=True + ) + self._xrecord = processor.find_subclass(self.XRECORD_DEF.name) # type: ignore + self.load_embedded_mtext(processor) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("insert", "align_point")) + + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + # Text() writes 2x AcDbText which is not suitable for AttDef() + self.export_acdb_entity(tagwriter) + self.export_acdb_text(tagwriter) + self.export_acdb_attdef(tagwriter) + if tagwriter.dxfversion >= const.DXF2018: + self.dxf.attribute_type = 4 if self.has_embedded_mtext_entity else 1 + self.export_dxf_r2018_features(tagwriter) + + def export_acdb_attdef(self, tagwriter: AbstractTagWriter) -> None: + if tagwriter.dxfversion > const.DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_attdef.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + # write version tag (280, 0) here, if required in the future + "prompt", + "tag", + "flags", + "field_length", + "valign", + "lock_position", + ], + ) + + +@register_entity +class Attrib(BaseAttrib): + """DXF ATTRIB entity""" + + DXFTYPE = "ATTRIB" + # Don't add acdb_attdef_xrecord here: + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_text, acdb_attrib) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super(Text, self).load_dxf_attribs(processor) + # Do not call Text loader. + if processor: + processor.fast_load_dxfattribs(dxf, acdb_text_group_codes, 2, recover=True) + processor.fast_load_dxfattribs( + dxf, acdb_attrib_group_codes, 3, recover=True + ) + self._xrecord = processor.find_subclass(self.XRECORD_DEF.name) # type: ignore + self.load_embedded_mtext(processor) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("insert", "align_point")) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + # Text() writes 2x AcDbText which is not suitable for AttDef() + self.export_acdb_entity(tagwriter) + self.export_acdb_attrib_text(tagwriter) + self.export_acdb_attrib(tagwriter) + if tagwriter.dxfversion >= const.DXF2018: + self.dxf.attribute_type = 2 if self.has_embedded_mtext_entity else 1 + self.export_dxf_r2018_features(tagwriter) + + def export_acdb_attrib_text(self, tagwriter: AbstractTagWriter) -> None: + # Despite the similarities to TEXT, it is different to + # Text.export_acdb_text(): + if tagwriter.dxfversion > const.DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_text.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "insert", + "height", + "text", + "thickness", + "rotation", + "oblique", + "style", + "width", + "halign", + "align_point", + "text_generation_flag", + "extrusion", + ], + ) + + def export_acdb_attrib(self, tagwriter: AbstractTagWriter) -> None: + if tagwriter.dxfversion > const.DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_attrib.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + # write version tag (280, 0) here, if required in the future + "tag", + "flags", + "field_length", + "valign", + "lock_position", + ], + ) + + +IGNORE_FROM_ATTRIB = { + "handle", + "owner", + "version", + "prompt", + "tag", + "flags", + "field_length", + "lock_position", +} + + +def copy_attrib_as_text(attrib: BaseAttrib): + """Returns the content of the ATTRIB/ATTDEF entity as a new virtual TEXT or + MTEXT entity. + + """ + if attrib.has_embedded_mtext_entity: + return attrib.virtual_mtext_entity() + dxfattribs = attrib.dxfattribs(drop=IGNORE_FROM_ATTRIB) + return Text.new(dxfattribs=dxfattribs, doc=attrib.doc) + + +class EmbeddedMTextNS(DXFNamespace): + _DXFATTRIBS = DXFAttributes(acdb_mtext) + + @property + def dxfattribs(self) -> DXFAttributes: + return self._DXFATTRIBS + + @property + def dxftype(self) -> str: + return "Embedded MText" + + +class EmbeddedMText: + """Representation of the embedded MTEXT object in ATTRIB and ATTDEF. + + Introduced in DXF R2018? The DXF reference of the `MTEXT`_ entity + documents only the attached MTEXT entity. The ODA DWG specs includes all + MTEXT attributes of MTEXT starting at group code 10 + + Stores the required parameters to be shown as as MTEXT. + The AcDbText subclass contains the first line of the embedded MTEXT as + plain text content as group code 1, but this tag seems not to be maintained + if the ATTRIB entity is copied. + + Some DXF attributes are duplicated and maintained by the CAD application: + + - textstyle: same group code 7 (AcDbText, EmbeddedObject) + - text (char) height: same group code 40 (AcDbText, EmbeddedObject) + + .. _MTEXT: https://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-7DD8B495-C3F8-48CD-A766-14F9D7D0DD9B + + """ + + def __init__(self) -> None: + # Attribute "dxf" contains the DXF attributes defined in subclass + # "AcDbMText" + self.dxf = EmbeddedMTextNS() + self.text: str = "" + + def copy(self) -> EmbeddedMText: + copy_ = EmbeddedMText() + copy_.dxf = copy.deepcopy(self.dxf) + return copy_ + + __copy__ = copy + + def load_dxf_tags(self, processor: SubclassProcessor) -> None: + tags = processor.fast_load_dxfattribs( + self.dxf, + group_code_mapping=acdb_mtext_group_codes, + subclass=processor.embedded_objects[0], + recover=False, + ) + self.text = load_mtext_content(tags) + + def virtual_mtext_entity(self) -> MText: + """Returns the embedded MTEXT entity as regular but virtual MTEXT + entity. This entity does not have the graphical attributes of the host + entity (ATTRIB/ATTDEF). + + """ + mtext = MText.new(dxfattribs=self.dxf.all_existing_dxf_attribs()) + mtext.text = self.text + return mtext + + def set_mtext(self, mtext: MText) -> None: + """Set embedded MTEXT attributes from given `mtext` entity.""" + self.text = mtext.text + dxf = self.dxf + for k, v in mtext.dxf.all_existing_dxf_attribs().items(): + if dxf.is_supported(k): + dxf.set(k, v) + + def set_required_dxf_attributes(self): + # These attributes are always present in DXF files created by Autocad: + dxf = self.dxf + for key, default in ( + ("insert", NULLVEC), + ("char_height", 2.5), + ("width", 0.0), + ("defined_height", 0.0), + ("attachment_point", 1), + ("flow_direction", 5), + ("style", "Standard"), + ("line_spacing_style", 1), + ("line_spacing_factor", 1.0), + ): + if not dxf.hasattr(key): + dxf.set(key, default) + + def export_dxf_tags(self, tagwriter: AbstractTagWriter) -> None: + """Export embedded MTEXT as "Embedded Object".""" + tagwriter.write_tag2(EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR) + self.set_required_dxf_attributes() + self.dxf.export_dxf_attribs( + tagwriter, + [ + "insert", + "char_height", + "width", + "defined_height", + "attachment_point", + "flow_direction", + ], + ) + export_mtext_content(self.text, tagwriter) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "style", + "extrusion", + "text_direction", + "rect_width", + "rect_height", + "rotation", + "line_spacing_style", + "line_spacing_factor", + "box_fill_scale", + "bg_fill", + "bg_fill_color", + "bg_fill_true_color", + "bg_fill_color_name", + "bg_fill_transparency", + ], + ) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + if self.dxf.hasattr("style"): + registry.add_text_style(self.dxf.style) + + def map_resources(self, clone: EmbeddedMText, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + if clone.dxf.hasattr("style"): + clone.dxf.style = mapping.get_text_style(clone.dxf.style) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/block.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/block.py new file mode 100644 index 0000000..ec94e7d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/block.py @@ -0,0 +1,242 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXF12, + DXF2000, + MODEL_SPACE_R12, + PAPER_SPACE_R12, + MODEL_SPACE_R2000, + PAPER_SPACE_R2000, +) +from ezdxf.math import NULLVEC +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .factory import register_entity +from ezdxf.audit import Auditor, AuditError + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["Block", "EndBlk"] + +acdb_entity = DefSubclass( + "AcDbEntity", + { + # No auto fix for invalid layer names! + "layer": DXFAttr(8, default="0", validator=validator.is_valid_layer_name), + "paperspace": DXFAttr( + 67, + default=0, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_entity_group_codes = group_code_mapping(acdb_entity) + +acdb_block_begin = DefSubclass( + "AcDbBlockBegin", + { + "name": DXFAttr(2, validator=validator.is_valid_block_name), + # The 2nd name with group code 3 is handled internally, and is not an + # explicit DXF attribute. + "description": DXFAttr(4, default="", dxfversion=DXF2000, optional=True), + # Flags: + # 0 = Indicates none of the following flags apply + # 1 = This is an anonymous block generated by hatching, associative + # dimensioning, other internal operations, or an application + # 2 = This block has non-constant attribute definitions (this bit is not set + # if the block has any attribute definitions that are constant, or has + # no attribute definitions at all) + # 4 = This block is an external reference (xref) + # 8 = This block is an xref overlay + # 16 = This block is externally dependent + # 32 = This is a resolved external reference, or dependent of an external + # reference (ignored on input) + # 64 = This definition is a referenced external reference (ignored on input) + "flags": DXFAttr(70, default=0), + "base_point": DXFAttr(10, xtype=XType.any_point, default=NULLVEC), + "xref_path": DXFAttr(1, default=""), + }, +) +acdb_block_begin_group_codes = group_code_mapping(acdb_block_begin) +merged_block_begin_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_block_begin_group_codes +) + +MODEL_SPACE_R2000_LOWER = MODEL_SPACE_R2000.lower() +MODEL_SPACE_R12_LOWER = MODEL_SPACE_R12.lower() +PAPER_SPACE_R2000_LOWER = PAPER_SPACE_R2000.lower() +PAPER_SPACE_R12_LOWER = PAPER_SPACE_R12.lower() + + +@register_entity +class Block(DXFEntity): + """DXF BLOCK entity""" + + DXFTYPE = "BLOCK" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_block_begin) + + # Block entity flags: + # This is an anonymous block generated by hatching, associative + # dimensioning, other internal operations, or an application: + ANONYMOUS = 1 + + # This block has non-constant attribute definitions (this bit is not set + # if the block has any attribute definitions that are constant, or has no + # attribute definitions at all): + NON_CONSTANT_ATTRIBUTES = 2 + + # This block is an external reference: + XREF = 4 + + # This block is an xref overlay: + XREF_OVERLAY = 8 + + # This block is externally dependent: + EXTERNAL = 16 + + # This is a resolved external reference, or dependent of an external reference: + RESOLVED = 32 + + # This definition is a referenced external reference: + REFERENCED = 64 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + dxf = super().load_dxf_attribs(processor) + if processor is None: + return dxf + processor.simple_dxfattribs_loader(dxf, merged_block_begin_group_codes) + if processor.r12: + if dxf.name is None: + dxf.name = "" + name = dxf.name.lower() + if name == MODEL_SPACE_R12_LOWER: + dxf.name = MODEL_SPACE_R2000 + elif name == PAPER_SPACE_R12_LOWER: + dxf.name = PAPER_SPACE_R2000 + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_entity.name) + if self.dxf.hasattr("paperspace"): + tagwriter.write_tag2(67, 1) + self.dxf.export_dxf_attribs(tagwriter, "layer") + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_block_begin.name) + + name = self.dxf.name + if tagwriter.dxfversion == DXF12: + # export modelspace and paperspace with leading '$' instead of '*' + if name.lower() == MODEL_SPACE_R2000_LOWER: + name = MODEL_SPACE_R12 + elif name.lower() == PAPER_SPACE_R2000_LOWER: + name = PAPER_SPACE_R12 + + tagwriter.write_tag2(2, name) + self.dxf.export_dxf_attribs(tagwriter, ["flags", "base_point"]) + tagwriter.write_tag2(3, name) + self.dxf.export_dxf_attribs(tagwriter, ["xref_path", "description"]) + + @property + def is_layout_block(self) -> bool: + """Returns ``True`` if this is a :class:`~ezdxf.layouts.Modelspace` or + :class:`~ezdxf.layouts.Paperspace` block definition. + """ + name = self.dxf.name.lower() + return name.startswith("*model_space") or name.startswith("*paper_space") + + @property + def is_anonymous(self) -> bool: + """Returns ``True`` if this is an anonymous block generated by + hatching, associative dimensioning, other internal operations, or an + application. + + """ + return self.get_flag_state(Block.ANONYMOUS) + + @property + def is_xref(self) -> bool: + """Returns ``True`` if bock is an external referenced file.""" + return self.get_flag_state(Block.XREF) + + @property + def is_xref_overlay(self) -> bool: + """Returns ``True`` if bock is an external referenced overlay file.""" + return self.get_flag_state(Block.XREF_OVERLAY) + + def audit(self, auditor: Auditor): + owner_handle = self.dxf.get("owner") + if owner_handle is None: # invalid owner handle - IGNORE + return + owner = auditor.entitydb.get(owner_handle) + if owner is None: # invalid owner entity - IGNORE + return + owner_name = owner.dxf.get("name", "").upper() + block_name = self.dxf.get("name", "").upper() + if owner_name != block_name: + auditor.add_error( + AuditError.BLOCK_NAME_MISMATCH, + f"{str(self)} name '{block_name}' and {str(owner)} name '{owner_name}' mismatch", + ) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, Block) + super().map_resources(clone, mapping) + clone.dxf.name = mapping.get_block_name(self.dxf.name) + + +acdb_block_end = DefSubclass("AcDbBlockEnd", {}) + + +@register_entity +class EndBlk(DXFEntity): + """DXF ENDBLK entity""" + + DXFTYPE = "ENDBLK" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_block_end) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_entity_group_codes) # type: ignore + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_entity.name) + if self.dxf.hasattr("paperspace"): + tagwriter.write_tag2(67, 1) + self.dxf.export_dxf_attribs(tagwriter, "layer") + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_block_end.name) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/blockrecord.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/blockrecord.py new file mode 100644 index 0000000..4281a1b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/blockrecord.py @@ -0,0 +1,315 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +import logging + +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + DXF12, + SUBCLASS_MARKER, + DXF2007, + DXFInternalEzdxfError, +) +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFGraphic, Block, EndBlk + from ezdxf.entities import DXFNamespace + from ezdxf.entitydb import EntitySpace + from ezdxf.layouts import BlockLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["BlockRecord"] +logger = logging.getLogger("ezdxf") + +acdb_blockrec = DefSubclass( + "AcDbBlockTableRecord", + { + "name": DXFAttr(2, validator=validator.is_valid_block_name), + # handle to associated DXF LAYOUT object + "layout": DXFAttr(340, default="0"), + # 0 = can not explode; 1 = can explode + "explode": DXFAttr( + 280, + default=1, + dxfversion=DXF2007, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 0 = scale non uniformly; 1 = scale uniformly + "scale": DXFAttr( + 281, + default=0, + dxfversion=DXF2007, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # see ezdxf/units.py + "units": DXFAttr( + 70, + default=0, + dxfversion=DXF2007, + validator=validator.is_in_integer_range(0, 25), + fixer=RETURN_DEFAULT, + ), + # 310: Binary data for bitmap preview (optional) - removed (ignored) by ezdxf + }, +) +acdb_blockrec_group_codes = group_code_mapping(acdb_blockrec) + +# optional handles to existing block references in DXF2000+ +# 2: name +# 340: explode +# 102: "{BLKREFS" +# 331: handle to INSERT +# ... +# 102: "}" + + +# optional XDATA for all DXF versions +# 1000: "ACAD" +# 1001: "DesignCenter Data" (optional) +# 1002: "{" +# 1070: Autodesk Design Center version number +# 1070: Insert units: like 'units' +# 1002: "}" + + +@register_entity +class BlockRecord(DXFEntity): + """DXF BLOCK_RECORD table entity + + BLOCK_RECORD is the hard owner of all entities in BLOCK definitions, this + means owner tag of entities is handle of BLOCK_RECORD. + + """ + + DXFTYPE = "BLOCK_RECORD" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_blockrec) + + def __init__(self) -> None: + from ezdxf.entitydb import EntitySpace + + super().__init__() + # Store entities in the block_record instead of BlockLayout and Layout, + # because BLOCK_RECORD is also the hard owner of all the entities. + self.entity_space = EntitySpace() + self.block: Optional[Block] = None + self.endblk: Optional[EndBlk] = None + # stores also the block layout structure + self.block_layout: Optional[BlockLayout] = None + + def set_block(self, block: Block, endblk: EndBlk): + self.block = block + self.endblk = endblk + self.block.dxf.owner = self.dxf.handle + self.endblk.dxf.owner = self.dxf.handle + + def set_entity_space(self, entity_space: EntitySpace) -> None: + self.entity_space = entity_space + + def rename(self, name: str) -> None: + assert self.block is not None + self.dxf.name = name + self.block.dxf.name = name + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_blockrec_group_codes) # type: ignore + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion == DXF12: + raise DXFInternalEzdxfError("Exporting BLOCK_RECORDS for DXF R12.") + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_blockrec.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "layout", + "units", + "explode", + "scale", + ], + ) + + def export_block_definition(self, tagwriter: AbstractTagWriter) -> None: + """Exports the BLOCK entity, followed by all content entities and finally the + ENDBLK entity, except for the *Model_Space and *Paper_Space blocks, their + entities are stored in the ENTITIES section. + + """ + assert self.block is not None + assert self.endblk is not None + if self.block_layout is not None: + self.block_layout.update_block_flags() + self.block.export_dxf(tagwriter) + if not (self.is_modelspace or self.is_active_paperspace): + self.entity_space.export_dxf(tagwriter) + self.endblk.export_dxf(tagwriter) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + assert self.doc is not None, "BLOCK_RECORD entity must be assigned to document" + assert self.doc.entitydb is not None, "entity database required" + super().register_resources(registry) + key = self.dxf.handle + assert key in self.doc.entitydb, "invalid BLOCK_RECORD handle" + + if self.block is not None: + registry.add_entity(self.block, block_key=key) + else: + raise DXFInternalEzdxfError( + f"BLOCK entity in BLOCK_RECORD #{key} is invalid" + ) + if self.endblk is not None: + registry.add_entity(self.endblk, block_key=key) + else: + raise DXFInternalEzdxfError( + f"ENDBLK entity in BLOCK_RECORD #{key} is invalid" + ) + for e in self.entity_space: + registry.add_entity(e, block_key=key) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, BlockRecord) + super().map_resources(clone, mapping) + + assert self.block is not None + mapping.map_resources_of_copy(self.block) + + assert self.endblk is not None + mapping.map_resources_of_copy(self.endblk) + + for entity in self.entity_space: + mapping.map_resources_of_copy(entity) + + def destroy(self): + """Destroy associated data: + + - BLOCK + - ENDBLK + - all entities stored in this block definition + + Does not destroy the linked LAYOUT entity, this is the domain of the + :class:`Layouts` object, which also should initiate the destruction of + 'this' BLOCK_RECORD. + + """ + if not self.is_alive: + return + + self.block.destroy() + self.endblk.destroy() + for entity in self.entity_space: + entity.destroy() + + # remove attributes to find invalid access after death + del self.block + del self.endblk + del self.block_layout + super().destroy() + + @property + def is_active_paperspace(self) -> bool: + """``True`` if is "active" paperspace layout.""" + return self.dxf.name.lower() == "*paper_space" + + @property + def is_any_paperspace(self) -> bool: + """``True`` if is any kind of paperspace layout.""" + return self.dxf.name.lower().startswith("*paper_space") + + @property + def is_modelspace(self) -> bool: + """``True`` if is the modelspace layout.""" + return self.dxf.name.lower() == "*model_space" + + @property + def is_any_layout(self) -> bool: + """``True`` if is any kind of modelspace or paperspace layout.""" + return self.is_modelspace or self.is_any_paperspace + + @property + def is_block_layout(self) -> bool: + """``True`` if not any kind of modelspace or paperspace layout, just a + regular block definition. + """ + return not self.is_any_layout + + @property + def is_xref(self) -> bool: + """``True`` if represents an XREF (external reference) or XREF_OVERLAY.""" + if self.block is not None: + return bool(self.block.dxf.flags & 12) + return False + + def add_entity(self, entity: DXFGraphic) -> None: + """Add an existing DXF entity to BLOCK_RECORD. + + Args: + entity: :class:`DXFGraphic` + + """ + # assign layout + try: + entity.set_owner(self.dxf.handle, paperspace=int(self.is_any_paperspace)) + except AttributeError: + logger.debug(f"Unexpected DXF entity {str(entity)} in {str(self.block)}") + # Add unexpected entities also to the entity space - auditor should fix + # errors! + self.entity_space.add(entity) + + def unlink_entity(self, entity: DXFGraphic) -> None: + """Unlink `entity` from BLOCK_RECORD. + + Removes `entity` just from entity space but not from the drawing + database. + + Args: + entity: :class:`DXFGraphic` + + """ + if entity.is_alive: + self.entity_space.remove(entity) + try: + entity.set_owner(None) + except AttributeError: + pass # unsupported entities as DXFTagStorage + + def delete_entity(self, entity: DXFGraphic) -> None: + """Delete `entity` from BLOCK_RECORD entity space and drawing database. + + Args: + entity: :class:`DXFGraphic` + + """ + self.unlink_entity(entity) # 1. unlink from entity space + entity.destroy() + + def audit(self, auditor: Auditor) -> None: + """Validity check. (internal API)""" + if not self.is_alive: + return + super().audit(auditor) + self.entity_space.audit(auditor) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/boundary_paths.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/boundary_paths.py new file mode 100644 index 0000000..5726e26 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/boundary_paths.py @@ -0,0 +1,1388 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, Iterable, Sequence, Optional, TYPE_CHECKING +import abc +import enum +import math + +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags, group_tags +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + OCS, + bulge_to_arc, + ConstructionEllipse, + ConstructionArc, + BSpline, + NonUniformScalingError, + open_uniform_knot_vector, + global_bspline_interpolation, + arc_angle_span_deg, + angle_to_param, + param_to_angle, +) +from ezdxf.math.transformtools import OCSTransform + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = [ + "BoundaryPaths", + "PolylinePath", + "EdgePath", + "LineEdge", + "ArcEdge", + "EllipseEdge", + "SplineEdge", + "EdgeType", + "BoundaryPathType", + "AbstractEdge", + "AbstractBoundaryPath", +] + + +@enum.unique +class BoundaryPathType(enum.IntEnum): + POLYLINE = 1 + EDGE = 2 + + +@enum.unique +class EdgeType(enum.IntEnum): + LINE = 1 + ARC = 2 + ELLIPSE = 3 + SPLINE = 4 + + +class AbstractBoundaryPath(abc.ABC): + type: BoundaryPathType + path_type_flags: int + source_boundary_objects: list[str] + + @abc.abstractmethod + def clear(self) -> None: ... + + @classmethod + @abc.abstractmethod + def load_tags(cls, tags: Tags) -> AbstractBoundaryPath: ... + + @abc.abstractmethod + def export_dxf(self, tagwriter: AbstractTagWriter, dxftype: str) -> None: ... + + @abc.abstractmethod + def transform(self, ocs: OCSTransform, elevation: float) -> None: ... + + @abc.abstractmethod + def is_valid(self) -> bool: ... + +class AbstractEdge(abc.ABC): + type: EdgeType + + @property + @abc.abstractmethod + def start_point(self) -> Vec2: ... + + @property + @abc.abstractmethod + def end_point(self) -> Vec2: ... + + @abc.abstractmethod + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: ... + + @abc.abstractmethod + def transform(self, ocs: OCSTransform, elevation: float) -> None: ... + + @abc.abstractmethod + def is_valid(self) -> bool: ... + + +class BoundaryPaths: + def __init__(self, paths: Optional[list[AbstractBoundaryPath]] = None): + self.paths: list[AbstractBoundaryPath] = paths or [] + + def __len__(self): + return len(self.paths) + + def __getitem__(self, item): + return self.paths[item] + + def __iter__(self): + return iter(self.paths) + + def is_valid(self) -> bool: + return all(p.is_valid() for p in self.paths) + + @classmethod + def load_tags(cls, tags: Tags) -> BoundaryPaths: + paths = [] + assert tags[0].code == 92 + grouped_path_tags = group_tags(tags, splitcode=92) + for path_tags in grouped_path_tags: + path_type_flags = path_tags[0].value + is_polyline_path = bool(path_type_flags & 2) + path: AbstractBoundaryPath = ( + PolylinePath.load_tags(path_tags) + if is_polyline_path + else EdgePath.load_tags(path_tags) + ) + path.path_type_flags = path_type_flags + paths.append(path) + return cls(paths) + + @property + def has_edge_paths(self) -> bool: + return any(p.type == BoundaryPathType.EDGE for p in self.paths) + + def clear(self) -> None: + """Remove all boundary paths.""" + self.paths = [] + + def external_paths(self) -> Iterable[AbstractBoundaryPath]: + """Iterable of external paths, could be empty.""" + for b in self.paths: + if b.path_type_flags & const.BOUNDARY_PATH_EXTERNAL: + yield b + + def outermost_paths(self) -> Iterable[AbstractBoundaryPath]: + """Iterable of outermost paths, could be empty.""" + for b in self.paths: + if b.path_type_flags & const.BOUNDARY_PATH_OUTERMOST: + yield b + + def default_paths(self) -> Iterable[AbstractBoundaryPath]: + """Iterable of default paths, could be empty.""" + not_default = ( + const.BOUNDARY_PATH_OUTERMOST + const.BOUNDARY_PATH_EXTERNAL + ) + for b in self.paths: + if bool(b.path_type_flags & not_default) is False: + yield b + + def rendering_paths( + self, hatch_style: int = const.HATCH_STYLE_NESTED + ) -> Iterable[AbstractBoundaryPath]: + """Iterable of paths to process for rendering, filters unused + boundary paths according to the given hatch style: + + - NESTED: use all boundary paths + - OUTERMOST: use EXTERNAL and OUTERMOST boundary paths + - IGNORE: ignore all paths except EXTERNAL boundary paths + + Yields paths in order of EXTERNAL, OUTERMOST and DEFAULT. + + """ + + def path_type_enum(flags) -> int: + if flags & const.BOUNDARY_PATH_EXTERNAL: + return 0 + elif flags & const.BOUNDARY_PATH_OUTERMOST: + return 1 + return 2 + + paths = sorted( + (path_type_enum(p.path_type_flags), i, p) + for i, p in enumerate(self.paths) + ) + ignore = 1 # EXTERNAL only + if hatch_style == const.HATCH_STYLE_NESTED: + ignore = 3 + elif hatch_style == const.HATCH_STYLE_OUTERMOST: + ignore = 2 + return (p for path_type, _, p in paths if path_type < ignore) + + def add_polyline_path( + self, + path_vertices: Iterable[tuple[float, ...]], + is_closed: bool = True, + flags: int = 1, + ) -> PolylinePath: + """Create and add a new :class:`PolylinePath` object. + + Args: + path_vertices: iterable of polyline vertices as (x, y) or + (x, y, bulge)-tuples. + is_closed: 1 for a closed polyline else 0 + flags: external(1) or outermost(16) or default (0) + + """ + new_path = PolylinePath.from_vertices(path_vertices, is_closed, flags) + self.paths.append(new_path) + return new_path + + def add_edge_path(self, flags: int = 1) -> EdgePath: + """Create and add a new :class:`EdgePath` object. + + Args: + flags: external(1) or outermost(16) or default (0) + + """ + new_path = EdgePath() + new_path.path_type_flags = flags + self.paths.append(new_path) + return new_path + + def export_dxf(self, tagwriter: AbstractTagWriter, dxftype: str) -> None: + tagwriter.write_tag2(91, len(self.paths)) + for path in self.paths: + path.export_dxf(tagwriter, dxftype) + + def transform(self, ocs: OCSTransform, elevation: float = 0) -> None: + """Transform HATCH boundary paths. + + These paths are 2d elements, placed in the OCS of the HATCH. + + """ + if not ocs.scale_uniform: + self.polyline_to_edge_paths(just_with_bulge=True) + self.arc_edges_to_ellipse_edges() + + for path in self.paths: + path.transform(ocs, elevation=elevation) + + def polyline_to_edge_paths(self, just_with_bulge=True) -> None: + """Convert polyline paths including bulge values to line- and arc edges. + + Args: + just_with_bulge: convert only polyline paths including bulge + values if ``True`` + + """ + + def _edges(points) -> Iterable[Union[LineEdge, ArcEdge]]: + prev_point = None + prev_bulge = None + for x, y, bulge in points: + point = Vec3(x, y) + if prev_point is None: + prev_point = point + prev_bulge = bulge + continue + + if prev_bulge != 0: + arc = ArcEdge() + # bulge_to_arc returns always counter-clockwise oriented + # start- and end angles: + ( + arc.center, + start_angle, + end_angle, + arc.radius, + ) = bulge_to_arc(prev_point, point, prev_bulge) + chk_point = arc.center + Vec2.from_angle( + start_angle, arc.radius + ) + arc.ccw = chk_point.isclose(prev_point, abs_tol=1e-9) + arc.start_angle = math.degrees(start_angle) % 360.0 + arc.end_angle = math.degrees(end_angle) % 360.0 + if math.isclose( + arc.start_angle, arc.end_angle + ) and math.isclose(arc.start_angle, 0): + arc.end_angle = 360.0 + yield arc + else: + line = LineEdge() + line.start = (prev_point.x, prev_point.y) + line.end = (point.x, point.y) + yield line + + prev_point = point + prev_bulge = bulge + + def to_edge_path(polyline_path) -> EdgePath: + edge_path = EdgePath() + vertices: list = list(polyline_path.vertices) + if polyline_path.is_closed: + vertices.append(vertices[0]) + edge_path.edges = list(_edges(vertices)) + return edge_path + + for path_index, path in enumerate(self.paths): + if isinstance(path, PolylinePath): + if just_with_bulge and not path.has_bulge(): + continue + self.paths[path_index] = to_edge_path(path) + + def edge_to_polyline_paths(self, distance: float, segments: int = 16): + """Convert all edge paths to simple polyline paths without bulges. + + Args: + distance: maximum distance from the center of the curve to the + center of the line segment between two approximation points to + determine if a segment should be subdivided. + segments: minimum segment count per curve + + """ + converted = [] + for path in self.paths: + if path.type == BoundaryPathType.EDGE: + path = flatten_to_polyline_path(path, distance, segments) + converted.append(path) + self.paths = converted + + def arc_edges_to_ellipse_edges(self) -> None: + """Convert all arc edges to ellipse edges.""" + + def to_ellipse(arc: ArcEdge) -> EllipseEdge: + ellipse = EllipseEdge() + ellipse.center = arc.center + ellipse.ratio = 1.0 + ellipse.major_axis = (arc.radius, 0.0) + ellipse.start_angle = arc.start_angle + ellipse.end_angle = arc.end_angle + ellipse.ccw = arc.ccw + return ellipse + + for path in self.paths: + if isinstance(path, EdgePath): + edges = path.edges + for edge_index, edge in enumerate(edges): + if isinstance(edge, ArcEdge): + edges[edge_index] = to_ellipse(edge) + + def ellipse_edges_to_spline_edges(self, num: int = 32) -> None: + """ + Convert all ellipse edges to spline edges (approximation). + + Args: + num: count of control points for a **full** ellipse, partial + ellipses have proportional fewer control points but at least 3. + + """ + + def to_spline_edge(e: EllipseEdge) -> SplineEdge: + # No OCS transformation needed, source ellipse and target spline + # reside in the same OCS. + ellipse = ConstructionEllipse( + center=e.center, + major_axis=e.major_axis, + ratio=e.ratio, + start_param=e.start_param, + end_param=e.end_param, + ) + count = max(int(float(num) * ellipse.param_span / math.tau), 3) + tool = BSpline.ellipse_approximation(ellipse, count) + spline = SplineEdge() + spline.degree = tool.degree + if not e.ccw: + tool = tool.reverse() + + spline.control_points = Vec2.list(tool.control_points) + spline.knot_values = tool.knots() # type: ignore + spline.weights = tool.weights() # type: ignore + return spline + + for path_index, path in enumerate(self.paths): + if isinstance(path, EdgePath): + edges = path.edges + for edge_index, edge in enumerate(edges): + if isinstance(edge, EllipseEdge): + edges[edge_index] = to_spline_edge(edge) + + def spline_edges_to_line_edges(self, factor: int = 8) -> None: + """Convert all spline edges to line edges (approximation). + + Args: + factor: count of approximation segments = count of control + points x factor + + """ + + def to_line_edges(spline_edge: SplineEdge): + weights = spline_edge.weights + if len(spline_edge.control_points): + bspline = BSpline( + control_points=spline_edge.control_points, + order=spline_edge.degree + 1, + knots=spline_edge.knot_values, + weights=weights if len(weights) else None, + ) + elif len(spline_edge.fit_points): + bspline = BSpline.from_fit_points( + spline_edge.fit_points, spline_edge.degree + ) + else: + raise const.DXFStructureError( + "SplineEdge() without control points or fit points." + ) + segment_count = (max(len(bspline.control_points), 3) - 1) * factor + vertices = list(bspline.approximate(segment_count)) + for v1, v2 in zip(vertices[:-1], vertices[1:]): + edge = LineEdge() + edge.start = v1.vec2 + edge.end = v2.vec2 + yield edge + + for path in self.paths: + if isinstance(path, EdgePath): + new_edges = [] + for edge in path.edges: + if isinstance(edge, SplineEdge): + new_edges.extend(to_line_edges(edge)) + else: + new_edges.append(edge) + path.edges = new_edges + + def ellipse_edges_to_line_edges(self, num: int = 64) -> None: + """Convert all ellipse edges to line edges (approximation). + + Args: + num: count of control points for a **full** ellipse, partial + ellipses have proportional fewer control points but at least 3. + + """ + + def to_line_edges(edge): + # Start- and end params are always stored in counter clockwise order! + ellipse = ConstructionEllipse( + center=edge.center, + major_axis=edge.major_axis, + ratio=edge.ratio, + start_param=edge.start_param, + end_param=edge.end_param, + ) + segment_count = max( + int(float(num) * ellipse.param_span / math.tau), 3 + ) + params = ellipse.params(segment_count + 1) + + # Reverse path if necessary! + if not edge.ccw: + params = reversed(list(params)) + vertices = list(ellipse.vertices(params)) + for v1, v2 in zip(vertices[:-1], vertices[1:]): + line = LineEdge() + line.start = v1.vec2 + line.end = v2.vec2 + yield line + + for path in self.paths: + if isinstance(path, EdgePath): + new_edges = [] + for edge in path.edges: + if isinstance(edge, EllipseEdge): + new_edges.extend(to_line_edges(edge)) + else: + new_edges.append(edge) + path.edges = new_edges + + def all_to_spline_edges(self, num: int = 64) -> None: + """Convert all bulge, arc and ellipse edges to spline edges + (approximation). + + Args: + num: count of control points for a **full** circle/ellipse, partial + circles/ellipses have proportional fewer control points but at + least 3. + + """ + self.polyline_to_edge_paths(just_with_bulge=True) + self.arc_edges_to_ellipse_edges() + self.ellipse_edges_to_spline_edges(num) + + def all_to_line_edges(self, num: int = 64, spline_factor: int = 8) -> None: + """Convert all bulge, arc and ellipse edges to spline edges and + approximate this splines by line edges. + + Args: + num: count of control points for a **full** circle/ellipse, partial + circles/ellipses have proportional fewer control points but at + least 3. + spline_factor: count of spline approximation segments = count of + control points x spline_factor + + """ + self.polyline_to_edge_paths(just_with_bulge=True) + self.arc_edges_to_ellipse_edges() + self.ellipse_edges_to_line_edges(num) + self.spline_edges_to_line_edges(spline_factor) + + def has_critical_elements(self) -> bool: + """Returns ``True`` if any boundary path has bulge values or arc edges + or ellipse edges. + + """ + for path in self.paths: + if isinstance(path, PolylinePath): + return path.has_bulge() + elif isinstance(path, EdgePath): + for edge in path.edges: + if edge.type in {EdgeType.ARC, EdgeType.ELLIPSE}: + return True + else: + raise TypeError(type(path)) + return False + + +def flatten_to_polyline_path( + path: AbstractBoundaryPath, distance: float, segments: int = 16 +) -> PolylinePath: + import ezdxf.path # avoid cyclic imports + + # keep path in original OCS! + ez_path = ezdxf.path.from_hatch_boundary_path(path, ocs=OCS(), elevation=0) + vertices = ((v.x, v.y) for v in ez_path.flattening(distance, segments)) + return PolylinePath.from_vertices( + vertices, + flags=path.path_type_flags, + ) + + +def pop_source_boundary_objects_tags(path_tags: Tags) -> list[str]: + source_boundary_object_tags = [] + while len(path_tags): + if path_tags[-1].code in (97, 330): + last_tag = path_tags.pop() + if last_tag.code == 330: + source_boundary_object_tags.append(last_tag.value) + else: # code == 97 + # result list does not contain the length tag! + source_boundary_object_tags.reverse() + return source_boundary_object_tags + else: + break + # No source boundary objects found - entity is not valid for AutoCAD + return [] + + +def export_source_boundary_objects( + tagwriter: AbstractTagWriter, handles: Sequence[str] +): + tagwriter.write_tag2(97, len(handles)) + for handle in handles: + tagwriter.write_tag2(330, handle) + + +class PolylinePath(AbstractBoundaryPath): + type = BoundaryPathType.POLYLINE + + def __init__(self) -> None: + self.path_type_flags: int = const.BOUNDARY_PATH_POLYLINE + self.is_closed = False + # list of 2D coordinates with bulge values (x, y, bulge); + # bulge default = 0.0 + self.vertices: list[tuple[float, float, float]] = [] + # MPOLYGON does not support source boundary objects, the MPOLYGON is + # the source object! + self.source_boundary_objects: list[str] = [] # (330, handle) tags + + def is_valid(self) -> bool: + return True + + @classmethod + def from_vertices( + cls, + path_vertices: Iterable[tuple[float, ...]], + is_closed: bool = True, + flags: int = 1, + ) -> PolylinePath: + """Create a new :class:`PolylinePath` object from vertices. + + Args: + path_vertices: iterable of polyline vertices as (x, y) or + (x, y, bulge)-tuples. + is_closed: 1 for a closed polyline else 0 + flags: external(1) or outermost(16) or default (0) + + """ + + new_path = PolylinePath() + new_path.set_vertices(path_vertices, is_closed) + new_path.path_type_flags = flags | const.BOUNDARY_PATH_POLYLINE + return new_path + + @classmethod + def load_tags(cls, tags: Tags) -> PolylinePath: + path = PolylinePath() + path.source_boundary_objects = pop_source_boundary_objects_tags(tags) + for tag in tags: + code, value = tag + if code == 10: # vertex coordinates + # (x, y, bulge); bulge default = 0.0 + path.vertices.append((value[0], value[1], 0.0)) + elif code == 42: # bulge value + x, y, bulge = path.vertices.pop() + # Last coordinates with new bulge value + path.vertices.append((x, y, value)) + elif code == 72: + pass # ignore this value + elif code == 73: + path.is_closed = value + elif code == 92: + path.path_type_flags = value + elif code == 93: # number of polyline vertices + pass # ignore this value + return path + + def set_vertices( + self, vertices: Iterable[Sequence[float]], is_closed: bool = True + ) -> None: + """Set new `vertices` as new polyline path, a vertex has to be a + (x, y) or a (x, y, bulge)-tuple. + + """ + new_vertices = [] + for vertex in vertices: + if len(vertex) == 2: + x, y = vertex + bulge = 0.0 + elif len(vertex) == 3: + x, y, bulge = vertex + else: + raise const.DXFValueError( + "Invalid vertex format, expected (x, y) or (x, y, bulge)" + ) + new_vertices.append((x, y, bulge)) + self.vertices = new_vertices + self.is_closed = is_closed + + def clear(self) -> None: + """Removes all vertices and all handles to associated DXF objects + (:attr:`source_boundary_objects`). + """ + self.vertices = [] + self.is_closed = False + self.source_boundary_objects = [] + + def has_bulge(self) -> bool: + return any(bulge for x, y, bulge in self.vertices) + + def export_dxf(self, tagwriter: AbstractTagWriter, dxftype: str) -> None: + has_bulge = self.has_bulge() + write_tag = tagwriter.write_tag2 + + write_tag(92, int(self.path_type_flags)) + if dxftype == "HATCH": # great design :< + write_tag(72, int(has_bulge)) + write_tag(73, int(self.is_closed)) + elif dxftype == "MPOLYGON": + write_tag(73, int(self.is_closed)) + write_tag(72, int(has_bulge)) + else: + raise ValueError(f"unsupported DXF type {dxftype}") + write_tag(93, len(self.vertices)) + for x, y, bulge in self.vertices: + tagwriter.write_vertex(10, (float(x), float(y))) + if has_bulge: + write_tag(42, float(bulge)) + + if dxftype == "HATCH": + export_source_boundary_objects( + tagwriter, self.source_boundary_objects + ) + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + """Transform polyline path.""" + has_non_uniform_scaling = not ocs.scale_uniform + + def _transform(): + for x, y, bulge in self.vertices: + # PolylinePaths() with arcs should be converted to + # EdgePath(in BoundaryPath.transform()). + if bulge and has_non_uniform_scaling: + raise NonUniformScalingError( + "Polyline path with arcs does not support non-uniform " + "scaling" + ) + v = ocs.transform_vertex(Vec3(x, y, elevation)) + yield v.x, v.y, bulge + + if self.vertices: + self.vertices = list(_transform()) + + +class EdgePath(AbstractBoundaryPath): + type = BoundaryPathType.EDGE + + def __init__(self) -> None: + self.path_type_flags = const.BOUNDARY_PATH_DEFAULT + self.edges: list[AbstractEdge] = [] + self.source_boundary_objects = [] + + def __iter__(self): + return iter(self.edges) + + def is_valid(self) -> bool: + return all(e.is_valid() for e in self.edges) + + @classmethod + def load_tags(cls, tags: Tags) -> EdgePath: + edge_path = cls() + edge_path.source_boundary_objects = pop_source_boundary_objects_tags( + tags + ) + for edge_tags in group_tags(tags, splitcode=72): + if len(edge_tags) == 0: + continue + edge_type = edge_tags[0].value + if 0 < edge_type < 5: + edge_path.edges.append(EDGE_CLASSES[edge_type].load_tags(edge_tags[1:])) + return edge_path + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + """Transform edge boundary paths.""" + for edge in self.edges: + edge.transform(ocs, elevation=elevation) + + def add_line(self, start: UVec, end: UVec) -> LineEdge: + """Add a :class:`LineEdge` from `start` to `end`. + + Args: + start: start point of line, (x, y)-tuple + end: end point of line, (x, y)-tuple + + """ + line = LineEdge() + line.start = Vec2(start) + line.end = Vec2(end) + self.edges.append(line) + return line + + def add_arc( + self, + center: UVec, + radius: float = 1.0, + start_angle: float = 0.0, + end_angle: float = 360.0, + ccw: bool = True, + ) -> ArcEdge: + """Add an :class:`ArcEdge`. + + **Adding Clockwise Oriented Arcs:** + + Clockwise oriented :class:`ArcEdge` objects are sometimes necessary to + build closed loops, but the :class:`ArcEdge` objects are always + represented in counter-clockwise orientation. + To add a clockwise oriented :class:`ArcEdge` you have to swap the + start- and end angle and set the `ccw` flag to ``False``, + e.g. to add a clockwise oriented :class:`ArcEdge` from 180 to 90 degree, + add the :class:`ArcEdge` in counter-clockwise orientation with swapped + angles:: + + edge_path.add_arc(center, radius, start_angle=90, end_angle=180, ccw=False) + + Args: + center: center point of arc, (x, y)-tuple + radius: radius of circle + start_angle: start angle of arc in degrees (`end_angle` for a + clockwise oriented arc) + end_angle: end angle of arc in degrees (`start_angle` for a + clockwise oriented arc) + ccw: ``True`` for counter-clockwise ``False`` for + clockwise orientation + + """ + arc = ArcEdge() + arc.center = Vec2(center) + arc.radius = radius + # Start- and end angles always for counter-clockwise oriented arcs! + arc.start_angle = start_angle + arc.end_angle = end_angle + # Flag to export the counter-clockwise oriented arc in + # correct clockwise orientation: + arc.ccw = bool(ccw) + self.edges.append(arc) + return arc + + def add_ellipse( + self, + center: UVec, + major_axis: UVec = (1.0, 0.0), + ratio: float = 1.0, + start_angle: float = 0.0, + end_angle: float = 360.0, + ccw: bool = True, + ) -> EllipseEdge: + """Add an :class:`EllipseEdge`. + + **Adding Clockwise Oriented Ellipses:** + + Clockwise oriented :class:`EllipseEdge` objects are sometimes necessary + to build closed loops, but the :class:`EllipseEdge` objects are always + represented in counter-clockwise orientation. + To add a clockwise oriented :class:`EllipseEdge` you have to swap the + start- and end angle and set the `ccw` flag to ``False``, + e.g. to add a clockwise oriented :class:`EllipseEdge` from 180 to 90 + degree, add the :class:`EllipseEdge` in counter-clockwise orientation + with swapped angles:: + + edge_path.add_ellipse(center, major_axis, ratio, start_angle=90, end_angle=180, ccw=False) + + Args: + center: center point of ellipse, (x, y)-tuple + major_axis: vector of major axis as (x, y)-tuple + ratio: ratio of minor axis to major axis as float + start_angle: start angle of ellipse in degrees (`end_angle` for a + clockwise oriented ellipse) + end_angle: end angle of ellipse in degrees (`start_angle` for a + clockwise oriented ellipse) + ccw: ``True`` for counter-clockwise ``False`` for + clockwise orientation + + """ + + if ratio > 1.0: + raise const.DXFValueError("argument 'ratio' has to be <= 1.0") + ellipse = EllipseEdge() + ellipse.center = Vec2(center) + ellipse.major_axis = Vec2(major_axis) + ellipse.ratio = ratio + # Start- and end angles are always stored in counter-clockwise + # orientation! + ellipse.start_angle = start_angle + ellipse.end_angle = end_angle + # Flag to export the counter-clockwise oriented ellipse in + # correct clockwise orientation: + ellipse.ccw = bool(ccw) + self.edges.append(ellipse) + return ellipse + + def add_spline( + self, + fit_points: Optional[Iterable[UVec]] = None, + control_points: Optional[Iterable[UVec]] = None, + knot_values: Optional[Iterable[float]] = None, + weights: Optional[Iterable[float]] = None, + degree: int = 3, + periodic: int = 0, + start_tangent: Optional[UVec] = None, + end_tangent: Optional[UVec] = None, + ) -> SplineEdge: + """Add a :class:`SplineEdge`. + + Args: + fit_points: points through which the spline must go, at least 3 fit + points are required. list of (x, y)-tuples + control_points: affects the shape of the spline, mandatory and + AutoCAD crashes on invalid data. list of (x, y)-tuples + knot_values: (knot vector) mandatory and AutoCAD crashes on invalid + data. list of floats; `ezdxf` provides two tool functions to + calculate valid knot values: :func:`ezdxf.math.uniform_knot_vector`, + :func:`ezdxf.math.open_uniform_knot_vector` (default if ``None``) + weights: weight of control point, not mandatory, list of floats. + degree: degree of spline (int) + periodic: 1 for periodic spline, 0 for none periodic spline + start_tangent: start_tangent as 2d vector, optional + end_tangent: end_tangent as 2d vector, optional + + .. warning:: + + Unlike for the spline entity AutoCAD does not calculate the + necessary `knot_values` for the spline edge itself. On the contrary, + if the `knot_values` in the spline edge are missing or invalid + AutoCAD **crashes**. + + """ + spline = SplineEdge() + if fit_points is not None: + spline.fit_points = Vec2.list(fit_points) + if control_points is not None: + spline.control_points = Vec2.list(control_points) + if knot_values is not None: + spline.knot_values = list(knot_values) + else: + spline.knot_values = list( + open_uniform_knot_vector(len(spline.control_points), degree + 1) + ) + if weights is not None: + spline.weights = list(weights) + spline.degree = degree + spline.rational = int(bool(len(spline.weights))) + spline.periodic = int(periodic) + if start_tangent is not None: + spline.start_tangent = Vec2(start_tangent) + if end_tangent is not None: + spline.end_tangent = Vec2(end_tangent) + self.edges.append(spline) + return spline + + def add_spline_control_frame( + self, + fit_points: Iterable[tuple[float, float]], + degree: int = 3, + method: str = "distance", + ) -> SplineEdge: + bspline = global_bspline_interpolation( + fit_points=fit_points, degree=degree, method=method + ) + return self.add_spline( + fit_points=fit_points, + control_points=bspline.control_points, + knot_values=bspline.knots(), + ) + + def clear(self) -> None: + """Delete all edges.""" + self.edges = [] + + def export_dxf(self, tagwriter: AbstractTagWriter, dxftype: str) -> None: + tagwriter.write_tag2(92, int(self.path_type_flags)) + tagwriter.write_tag2(93, len(self.edges)) + for edge in self.edges: + edge.export_dxf(tagwriter) + export_source_boundary_objects(tagwriter, self.source_boundary_objects) + + +class LineEdge(AbstractEdge): + EDGE_TYPE = "LineEdge" # 2021-05-31: deprecated use type + type = EdgeType.LINE + + def __init__(self): + self.start = Vec2(0, 0) # OCS! + self.end = Vec2(0, 0) # OCS! + + def is_valid(self) -> bool: + return True + + @property + def start_point(self) -> Vec2: + return self.start + + @property + def end_point(self) -> Vec2: + return self.end + + @classmethod + def load_tags(cls, tags: Tags) -> LineEdge: + edge = cls() + for tag in tags: + code, value = tag + if code == 10: + edge.start = Vec2(value) + elif code == 11: + edge.end = Vec2(value) + return edge + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(72, 1) # edge type + + x, y, *_ = self.start + tagwriter.write_tag2(10, float(x)) + tagwriter.write_tag2(20, float(y)) + + x, y, *_ = self.end + tagwriter.write_tag2(11, float(x)) + tagwriter.write_tag2(21, float(y)) + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + self.start = ocs.transform_2d_vertex(self.start, elevation) + self.end = ocs.transform_2d_vertex(self.end, elevation) + + +class ArcEdge(AbstractEdge): + type = EdgeType.ARC # 2021-05-31: deprecated use type + EDGE_TYPE = "ArcEdge" + + def __init__(self) -> None: + self.center = Vec2(0.0, 0.0) + self.radius: float = 1.0 + # Start- and end angles are always stored in counter-clockwise order! + self.start_angle: float = 0.0 + self.end_angle: float = 360.0 + # Flag to preserve the required orientation for DXF export: + self.ccw: bool = True + + def is_valid(self) -> bool: + return True + + @property + def start_point(self) -> Vec2: + return self.construction_tool().start_point + + @property + def end_point(self) -> Vec2: + return self.construction_tool().end_point + + @classmethod + def load_tags(cls, tags: Tags) -> ArcEdge: + edge = cls() + start = 0.0 + end = 0.0 + for tag in tags: + code, value = tag + if code == 10: + edge.center = Vec2(value) + elif code == 40: + edge.radius = value + elif code == 50: + start = value + elif code == 51: + end = value + elif code == 73: + edge.ccw = bool(value) + + # The DXF format stores the clockwise oriented start- and end angles + # for HATCH arc- and ellipse edges as complementary angle (360-angle). + # This is a problem in many ways for processing clockwise oriented + # angles correct, especially rotation transformation won't work. + # Solution: convert clockwise angles into counter-clockwise angles + # and swap start- and end angle at loading and exporting, the ccw flag + # preserves the required orientation of the arc: + if edge.ccw: + edge.start_angle = start + edge.end_angle = end + else: + edge.start_angle = 360.0 - end + edge.end_angle = 360.0 - start + return edge + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(72, 2) # edge type + x, y, *_ = self.center + if self.ccw: + start = self.start_angle + end = self.end_angle + else: + # swap and convert to complementary angles: see ArcEdge.load_tags() + # for explanation + start = 360.0 - self.end_angle + end = 360.0 - self.start_angle + tagwriter.write_tag2(10, float(x)) + tagwriter.write_tag2(20, float(y)) + tagwriter.write_tag2(40, self.radius) + tagwriter.write_tag2(50, start) + tagwriter.write_tag2(51, end) + tagwriter.write_tag2(73, int(self.ccw)) + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + self.center = ocs.transform_2d_vertex(self.center, elevation) + self.radius = ocs.transform_length(Vec3(self.radius, 0, 0)) + if not math.isclose( + arc_angle_span_deg(self.start_angle, self.end_angle), 360.0 + ): # open arc + # The transformation of the ccw flag is not necessary for the current + # implementation of OCS transformations. The arc angles have always + # a counter clockwise orientation around the extrusion vector and + # this orientation is preserved even for mirroring, which flips the + # extrusion vector to (0, 0, -1) for entities in the xy-plane. + + self.start_angle = ocs.transform_deg_angle(self.start_angle) + self.end_angle = ocs.transform_deg_angle(self.end_angle) + else: # full circle + # Transform only start point to preserve the connection point to + # adjacent edges: + self.start_angle = ocs.transform_deg_angle(self.start_angle) + # ArcEdge is represented in counter-clockwise orientation: + self.end_angle = self.start_angle + 360.0 + + def construction_tool(self) -> ConstructionArc: + """Returns ConstructionArc() for the OCS representation.""" + return ConstructionArc( + center=self.center, + radius=self.radius, + start_angle=self.start_angle, + end_angle=self.end_angle, + ) + + +class EllipseEdge(AbstractEdge): + EDGE_TYPE = "EllipseEdge" # 2021-05-31: deprecated use type + type = EdgeType.ELLIPSE + + def __init__(self) -> None: + self.center = Vec2((0.0, 0.0)) + # Endpoint of major axis relative to center point (in OCS) + self.major_axis = Vec2((1.0, 0.0)) + self.ratio: float = 1.0 + # Start- and end angles are always stored in counter-clockwise order! + self.start_angle: float = 0.0 # start param, not a real angle + self.end_angle: float = 360.0 # end param, not a real angle + # Flag to preserve the required orientation for DXF export: + self.ccw: bool = True + + def is_valid(self) -> bool: + return True + + @property + def start_point(self) -> Vec2: + return self.construction_tool().start_point.vec2 + + @property + def end_point(self) -> Vec2: + return self.construction_tool().end_point.vec2 + + @property + def start_param(self) -> float: + return angle_to_param(self.ratio, math.radians(self.start_angle)) + + @start_param.setter + def start_param(self, param: float) -> None: + self.start_angle = math.degrees(param_to_angle(self.ratio, param)) + + @property + def end_param(self) -> float: + return angle_to_param(self.ratio, math.radians(self.end_angle)) + + @end_param.setter + def end_param(self, param: float) -> None: + self.end_angle = math.degrees(param_to_angle(self.ratio, param)) + + @classmethod + def load_tags(cls, tags: Tags) -> EllipseEdge: + edge = cls() + start = 0.0 + end = 0.0 + for tag in tags: + code, value = tag + if code == 10: + edge.center = Vec2(value) + elif code == 11: + edge.major_axis = Vec2(value) + elif code == 40: + edge.ratio = value + elif code == 50: + start = value + elif code == 51: + end = value + elif code == 73: + edge.ccw = bool(value) + + if edge.ccw: + edge.start_angle = start + edge.end_angle = end + else: + # The DXF format stores the clockwise oriented start- and end angles + # for HATCH arc- and ellipse edges as complementary angle (360-angle). + # This is a problem in many ways for processing clockwise oriented + # angles correct, especially rotation transformation won't work. + # Solution: convert clockwise angles into counter-clockwise angles + # and swap start- and end angle at loading and exporting, the ccw flag + # preserves the required orientation of the ellipse: + edge.start_angle = 360.0 - end + edge.end_angle = 360.0 - start + + return edge + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(72, 3) # edge type + x, y, *_ = self.center + tagwriter.write_tag2(10, float(x)) + tagwriter.write_tag2(20, float(y)) + x, y, *_ = self.major_axis + tagwriter.write_tag2(11, float(x)) + tagwriter.write_tag2(21, float(y)) + tagwriter.write_tag2(40, self.ratio) + if self.ccw: + start = self.start_angle + end = self.end_angle + else: + # swap and convert to complementary angles: see EllipseEdge.load_tags() + # for explanation + start = 360.0 - self.end_angle + end = 360.0 - self.start_angle + + tagwriter.write_tag2(50, start) + tagwriter.write_tag2(51, end) + tagwriter.write_tag2(73, int(self.ccw)) + + def construction_tool(self) -> ConstructionEllipse: + """Returns ConstructionEllipse() for the OCS representation.""" + return ConstructionEllipse( + center=Vec3(self.center), + major_axis=Vec3(self.major_axis), + extrusion=Vec3(0, 0, 1), + ratio=self.ratio, + # 1. ConstructionEllipse() is always in ccw orientation + # 2. Start- and end params are always stored in ccw orientation + start_param=self.start_param, + end_param=self.end_param, + ) + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + e = self.construction_tool() + + # Transform old OCS representation to WCS + ocs_to_wcs = ocs.old_ocs.to_wcs + e.center = ocs_to_wcs(e.center.replace(z=elevation)) + e.major_axis = ocs_to_wcs(e.major_axis) + e.extrusion = ocs.old_extrusion + + # Apply matrix transformation + e.transform(ocs.m) + + # Transform WCS representation to new OCS + wcs_to_ocs = ocs.new_ocs.from_wcs + self.center = wcs_to_ocs(e.center).vec2 + self.major_axis = wcs_to_ocs(e.major_axis).vec2 + self.ratio = e.ratio + + # ConstructionEllipse() is always in ccw orientation + # Start- and end params are always stored in ccw orientation + self.start_param = e.start_param + self.end_param = e.end_param + + # The transformation of the ccw flag is not necessary for the current + # implementation of OCS transformations. + # An ellipse as boundary edge is an OCS entity! + # The ellipse angles have always a counter clockwise orientation around + # the extrusion vector and this orientation is preserved even for + # mirroring, which flips the extrusion vector to (0, 0, -1) for + # entities in the xy-plane. + + # normalize angles in range 0 to 360 degrees + self.start_angle = self.start_angle % 360.0 + self.end_angle = self.end_angle % 360.0 + if math.isclose(self.end_angle, 0): + self.end_angle = 360.0 + + +class SplineEdge(AbstractEdge): + EDGE_TYPE = "SplineEdge" # 2021-05-31: deprecated use type + type = EdgeType.SPLINE + + def __init__(self) -> None: + self.degree: int = 3 # code = 94 + self.rational: int = 0 # code = 73 + self.periodic: int = 0 # code = 74 + self.knot_values: list[float] = [] + self.control_points: list[Vec2] = [] + self.fit_points: list[Vec2] = [] + self.weights: list[float] = [] + # do not set tangents by default to (0, 0) + self.start_tangent: Optional[Vec2] = None + self.end_tangent: Optional[Vec2] = None + + def is_valid(self) -> bool: + if len(self.control_points): + order = self.degree + 1 + count = len(self.control_points) + if order > count: + return False + required_knot_count = count + order + if len(self.knot_values) != required_knot_count: + return False + elif len(self.fit_points) < 2: + return False + return True + + @property + def start_point(self) -> Vec2: + return self.control_points[0] + + @property + def end_point(self) -> Vec2: + return self.control_points[-1] + + @classmethod + def load_tags(cls, tags: Tags) -> SplineEdge: + edge = cls() + for tag in tags: + code, value = tag + if code == 94: + edge.degree = value + elif code == 73: + edge.rational = value + elif code == 74: + edge.periodic = value + elif code == 40: + edge.knot_values.append(value) + elif code == 42: + edge.weights.append(value) + elif code == 10: + edge.control_points.append(Vec2(value)) + elif code == 11: + edge.fit_points.append(Vec2(value)) + elif code == 12: + edge.start_tangent = Vec2(value) + elif code == 13: + edge.end_tangent = Vec2(value) + return edge + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + def set_required_tangents(points: list[Vec2]): + if len(points) > 1: + if self.start_tangent is None: + self.start_tangent = points[1] - points[0] + if self.end_tangent is None: + self.end_tangent = points[-1] - points[-2] + + if len(self.weights): + if len(self.weights) == len(self.control_points): + self.rational = 1 + else: + raise const.DXFValueError( + "SplineEdge: count of control points and count of weights " + "mismatch" + ) + else: + self.rational = 0 + + write_tag = tagwriter.write_tag2 + write_tag(72, 4) # edge type + write_tag(94, int(self.degree)) + write_tag(73, int(self.rational)) + write_tag(74, int(self.periodic)) + write_tag(95, len(self.knot_values)) # number of knots + write_tag(96, len(self.control_points)) # number of control points + # build knot values list + # knot values have to be present and valid, otherwise AutoCAD crashes + if len(self.knot_values): + for value in self.knot_values: + write_tag(40, float(value)) + else: + raise const.DXFValueError( + "SplineEdge: missing required knot values" + ) + + # build control points + # control points have to be present and valid, otherwise AutoCAD crashes + cp = Vec2.list(self.control_points) + if self.rational: + for point, weight in zip(cp, self.weights): + write_tag(10, float(point.x)) + write_tag(20, float(point.y)) + write_tag(42, float(weight)) + else: + for x, y in cp: + write_tag(10, float(x)) + write_tag(20, float(y)) + + # build optional fit points + if len(self.fit_points) > 0: + set_required_tangents(cp) + write_tag(97, len(self.fit_points)) + for x, y, *_ in self.fit_points: + write_tag(11, float(x)) + write_tag(21, float(y)) + elif tagwriter.dxfversion >= const.DXF2010: + # (97, 0) len tag required by AutoCAD 2010+ + write_tag(97, 0) + + if self.start_tangent is not None: + x, y, *_ = self.start_tangent + write_tag(12, float(x)) + write_tag(22, float(y)) + + if self.end_tangent is not None: + x, y, *_ = self.end_tangent + write_tag(13, float(x)) + write_tag(23, float(y)) + + def transform(self, ocs: OCSTransform, elevation: float) -> None: + self.control_points = list( + ocs.transform_2d_vertex(v, elevation) for v in self.control_points + ) + self.fit_points = list( + ocs.transform_2d_vertex(v, elevation) for v in self.fit_points + ) + if self.start_tangent is not None: + t = Vec3(self.start_tangent).replace(z=elevation) + self.start_tangent = ocs.transform_direction(t).vec2 + if self.end_tangent is not None: + t = Vec3(self.end_tangent).replace(z=elevation) + self.end_tangent = ocs.transform_direction(t).vec2 + + def construction_tool(self) -> BSpline: + """Returns BSpline() for the OCS representation.""" + return BSpline( + control_points=self.control_points, + knots=self.knot_values, + order=self.degree + 1, + weights=self.weights, + ) + + +EDGE_CLASSES = [None, LineEdge, ArcEdge, EllipseEdge, SplineEdge] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/circle.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/circle.py new file mode 100644 index 0000000..1989802 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/circle.py @@ -0,0 +1,214 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, Iterator +import math +import numpy as np + +from ezdxf.lldxf import validator +from ezdxf.math import ( + Vec3, + Matrix44, + NULLVEC, + Z_AXIS, + arc_segment_count, +) +from ezdxf.math.transformtools import OCSTransform, NonUniformScalingError +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER, DXFValueError +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + add_entity, + replace_entity, + elevation_to_z_axis, + acdb_entity_group_codes, +) +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import Ellipse, Spline + +__all__ = ["Circle"] + +acdb_circle = DefSubclass( + "AcDbCircle", + { + "center": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # AutCAD/BricsCAD: Radius is <= 0 is valid + "radius": DXFAttr(40, default=1), + # Elevation is a legacy feature from R11 and prior, do not use this + # attribute, store the entity elevation in the z-axis of the vertices. + # ezdxf does not export the elevation attribute! + "elevation": DXFAttr(38, default=0, optional=True), + "thickness": DXFAttr(39, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) + +acdb_circle_group_codes = group_code_mapping(acdb_circle) +merged_circle_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_circle_group_codes +) + + +@register_entity +class Circle(DXFGraphic): + """DXF CIRCLE entity""" + + DXFTYPE = "CIRCLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_circle) + MERGED_GROUP_CODES = merged_circle_group_codes + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, self.MERGED_GROUP_CODES) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("center",)) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_circle.name) + self.dxf.export_dxf_attribs( + tagwriter, ["center", "radius", "thickness", "extrusion"] + ) + + def vertices(self, angles: Iterable[float]) -> Iterator[Vec3]: + """Yields the vertices of the circle of all given `angles` as + :class:`~ezdxf.math.Vec3` instances in :ref:`WCS`. + + Args: + angles: iterable of angles in :ref:`OCS` as degrees, angle goes + counter-clockwise around the extrusion vector, and the OCS x-axis + defines 0-degree. + + """ + ocs = self.ocs() + radius: float = abs(self.dxf.radius) # AutoCAD ignores the sign too + center = Vec3(self.dxf.center) + for angle in angles: + yield ocs.to_wcs(Vec3.from_deg_angle(angle, radius) + center) + + def flattening(self, sagitta: float) -> Iterator[Vec3]: + """Approximate the circle by vertices in :ref:`WCS` as :class:`~ezdxf.math.Vec3` + instances. The argument `sagitta`_ is the maximum distance from the center of an + arc segment to the center of its chord. Yields a closed polygon where the start + vertex is equal to the end vertex! + + .. _sagitta: https://en.wikipedia.org/wiki/Sagitta_(geometry) + """ + radius = abs(self.dxf.radius) + if radius > 0.0: + count = arc_segment_count(radius, math.tau, sagitta) + yield from self.vertices(np.linspace(0.0, 360.0, count + 1)) + + def transform(self, m: Matrix44) -> Circle: + """Transform the CIRCLE entity by transformation matrix `m` inplace. + Raises ``NonUniformScalingError()`` for non-uniform scaling. + """ + circle = self._transform(OCSTransform(self.dxf.extrusion, m)) + self.post_transform(m) + return circle + + def _transform(self, ocs: OCSTransform) -> Circle: + dxf = self.dxf + if ocs.scale_uniform: + dxf.extrusion = ocs.new_extrusion + dxf.center = ocs.transform_vertex(dxf.center) + # old_ocs has a uniform scaled xy-plane, direction of radius-vector + # in the xy-plane is not important, choose x-axis for no reason: + dxf.radius = ocs.transform_length((dxf.radius, 0, 0)) + if dxf.hasattr("thickness"): + # thickness vector points in the z-direction of the old_ocs, + # thickness can be negative + dxf.thickness = ocs.transform_thickness(dxf.thickness) + else: + # Caller has to catch this Exception and convert this + # CIRCLE/ARC into an ELLIPSE. + raise NonUniformScalingError( + "CIRCLE/ARC does not support non uniform scaling" + ) + + return self + + def translate(self, dx: float, dy: float, dz: float) -> Circle: + """Optimized CIRCLE/ARC translation about `dx` in x-axis, `dy` in + y-axis and `dz` in z-axis, returns `self` (floating interface). + """ + ocs = self.ocs() + self.dxf.center = ocs.from_wcs(Vec3(dx, dy, dz) + ocs.to_wcs(self.dxf.center)) + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self + + def to_ellipse(self, replace=True) -> Ellipse: + """Convert the CIRCLE/ARC entity to an :class:`~ezdxf.entities.Ellipse` entity. + + Adds the new ELLIPSE entity to the entity database and to the same layout as + the source entity. + + Args: + replace: replace (delete) source entity by ELLIPSE entity if ``True`` + + """ + from ezdxf.entities import Ellipse + + layout = self.get_layout() + if layout is None: + raise DXFValueError("valid layout required") + ellipse = Ellipse.from_arc(self) + if replace: + replace_entity(self, ellipse, layout) + else: + add_entity(ellipse, layout) + return ellipse + + def to_spline(self, replace=True) -> Spline: + """Convert the CIRCLE/ARC entity to a :class:`~ezdxf.entities.Spline` entity. + + Adds the new SPLINE entity to the entity database and to the same layout as the + source entity. + + Args: + replace: replace (delete) source entity by SPLINE entity if ``True`` + + """ + from ezdxf.entities import Spline + + layout = self.get_layout() + if layout is None: + raise DXFValueError("valid layout required") + spline = Spline.from_arc(self) + if replace: + replace_entity(self, spline, layout) + else: + add_entity(spline, layout) + return spline diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/copy.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/copy.py new file mode 100644 index 0000000..ad6fcdc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/copy.py @@ -0,0 +1,102 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, TypeVar, NamedTuple, Optional +from copy import deepcopy +import logging +from ezdxf.lldxf.const import DXFError + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + + +__all__ = ["CopyStrategy", "CopySettings", "CopyNotSupported", "default_copy"] + + +T = TypeVar("T", bound="DXFEntity") + + +class CopyNotSupported(DXFError): + pass + + +class CopySettings(NamedTuple): + reset_handles: bool = True + copy_extension_dict: bool = True + copy_xdata: bool = True + copy_appdata: bool = True + copy_reactors: bool = False + copy_proxy_graphic: bool = True + set_source_of_copy: bool = True + + # The processing of copy errors of linked entities has to be done in the + # copy_data() method by the entity itself! + ignore_copy_errors_in_linked_entities: bool = True + + +class LogMessage(NamedTuple): + message: str + level: int = logging.WARNING + entity: Optional[DXFEntity] = None + + +class CopyStrategy: + log: list[LogMessage] = [] + + def __init__(self, settings: CopySettings) -> None: + self.settings = settings + + def copy(self, entity: T) -> T: + """Entity copy for usage in the same document or as virtual entity. + + This copy is NOT stored in the entity database and does NOT reside in any + layout, block, table or objects section! + """ + settings = self.settings + clone = entity.__class__() + doc = entity.doc + clone.doc = doc + clone.dxf = entity.dxf.copy(clone) + if settings.reset_handles: + clone.dxf.reset_handles() + + if settings.copy_extension_dict: + xdict = entity.extension_dict + if xdict is not None and doc is not None and xdict.is_alive: + # Error handling of unsupported entities in the extension dictionary is + # done by the underlying DICTIONARY entity. + clone.extension_dict = xdict.copy(self) + + if settings.copy_reactors and entity.reactors is not None: + clone.reactors = entity.reactors.copy() + + if settings.copy_proxy_graphic: + clone.proxy_graphic = entity.proxy_graphic # immutable bytes + + # if appdata contains handles, they are treated as shared resources + if settings.copy_appdata: + clone.appdata = deepcopy(entity.appdata) + + # if xdata contains handles, they are treated as shared resources + if settings.copy_xdata: + clone.xdata = deepcopy(entity.xdata) + + if settings.set_source_of_copy: + clone.set_source_of_copy(entity) + + entity.copy_data(clone, copy_strategy=self) + return clone + + @classmethod + def add_log_message( + cls, msg: str, level: int = logging.WARNING, entity: Optional[DXFEntity] = None + ) -> None: + cls.log.append(LogMessage(msg, level, entity)) + + @classmethod + def clear_log_message(cls) -> None: + cls.log.clear() + + +# same strategy as DXFEntity.copy() of v1.1.3 +default_copy = CopyStrategy(CopySettings()) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dictionary.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dictionary.py new file mode 100644 index 0000000..9cac26f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dictionary.py @@ -0,0 +1,688 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Union, Optional +from typing_extensions import Self +import logging +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXFKeyError, + DXFValueError, + DXFTypeError, + DXFStructureError, +) +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.types import is_valid_handle +from ezdxf.audit import AuditError +from ezdxf.entities import factory, DXFGraphic +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .dxfobj import DXFObject +from .copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, XRecord + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.document import Drawing + from ezdxf.audit import Auditor + from ezdxf import xref + +__all__ = ["Dictionary", "DictionaryWithDefault", "DictionaryVar"] +logger = logging.getLogger("ezdxf") + +acdb_dictionary = DefSubclass( + "AcDbDictionary", + { + # If hard_owned is set to 1 the entries are owned by the DICTIONARY. + # The 1 state seems to be the default value, but is not documented by + # the DXF reference. + # BricsCAD creates the root DICTIONARY and the top level DICTIONARY entries + # without group code 280 tags, and they are all definitely hard owner of their + # entries, because their entries have the DICTIONARY handle as owner handle. + "hard_owned": DXFAttr( + 280, + default=1, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Duplicate record cloning flag (determines how to merge duplicate entries): + # 0 = not applicable + # 1 = keep existing + # 2 = use clone + # 3 = $0$ + # 4 = $0$ + # 5 = Unmangle name + "cloning": DXFAttr( + 281, + default=1, + validator=validator.is_in_integer_range(0, 6), + fixer=RETURN_DEFAULT, + ), + # 3: entry name + # 350: entry handle, some DICTIONARY objects have 360 as handle group code, + # this is accepted by AutoCAD but not documented by the DXF reference! + # ezdxf replaces group code 360 by 350. + # - group code 350 is a soft-owner handle + # - group code 360 is a hard-owner handle + }, +) +acdb_dictionary_group_codes = group_code_mapping(acdb_dictionary) +KEY_CODE = 3 +VALUE_CODE = 350 +# Some DICTIONARY use group code 360: +SEARCH_CODES = (VALUE_CODE, 360) + + +@factory.register_entity +class Dictionary(DXFObject): + """AutoCAD maintains items such as mline styles and group definitions as + objects in dictionaries. Other applications are free to create and use + their own dictionaries as they see fit. The prefix "ACAD_" is reserved + for use by AutoCAD applications. + + Dictionary entries are (key, DXFEntity) pairs. DXFEntity could be a string, + because at loading time not all objects are already stored in the EntityDB, + and have to be acquired later. + + """ + + DXFTYPE = "DICTIONARY" + DXFATTRIBS = DXFAttributes(base_class, acdb_dictionary) + + def __init__(self) -> None: + super().__init__() + self._data: dict[str, Union[str, DXFObject]] = dict() + self._value_code = VALUE_CODE + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy hard owned entities but do not store the copies in the entity + database, this is a second step (factory.bind), this is just real copying. + """ + assert isinstance(entity, Dictionary) + entity._value_code = self._value_code + if self.dxf.hard_owned: + # Reactors are removed from the cloned DXF objects. + data: dict[str, DXFEntity] = dict() + for key, ent in self.items(): + # ignore strings and None - these entities do not exist + # in the entity database + if isinstance(ent, DXFEntity): + try: # todo: follow CopyStrategy.ignore_copy_errors_in_linked entities + data[key] = ent.copy(copy_strategy=copy_strategy) + except CopyNotSupported: + if copy_strategy.settings.ignore_copy_errors_in_linked_entities: + logger.warning( + f"copy process ignored {str(ent)} - this may cause problems in AutoCAD" + ) + else: + raise + entity._data = data # type: ignore + else: + entity._data = dict(self._data) + + def get_handle_mapping(self, clone: Dictionary) -> dict[str, str]: + """Returns handle mapping for in-object copies.""" + handle_mapping: dict[str, str] = dict() + if not self.is_hard_owner: + return handle_mapping + + for key, entity in self.items(): + if not isinstance(entity, DXFEntity): + continue + copied_entry = clone.get(key) + if copied_entry: + handle_mapping[entity.dxf.handle] = copied_entry.dxf.handle + return handle_mapping + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, Dictionary) + super().map_resources(clone, mapping) + if self.is_hard_owner: + return + data = dict() + for key, entity in self.items(): + if not isinstance(entity, DXFEntity): + continue + entity_copy = mapping.get_reference_of_copy(entity.dxf.handle) + if entity_copy: + data[key] = entity + clone._data = data # type: ignore + + def del_source_of_copy(self) -> None: + super().del_source_of_copy() + for _, entity in self.items(): + if isinstance(entity, DXFEntity) and entity.is_alive: + entity.del_source_of_copy() + + def post_bind_hook(self) -> None: + """Called by binding a new or copied dictionary to the document, + bind hard owned sub-entities to the same document and add them to the + objects section. + """ + if not self.dxf.hard_owned: + return + + # copied or new dictionary: + doc = self.doc + assert doc is not None + object_section = doc.objects + owner_handle = self.dxf.handle + for _, entity in self.items(): + entity.dxf.owner = owner_handle + factory.bind(entity, doc) + # For a correct DXF export add entities to the objects section: + object_section.add_object(entity) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_dictionary_group_codes, 1, log=False + ) + self.load_dict(tags) + return dxf + + def load_dict(self, tags): + entry_handle = None + dict_key = None + value_code = VALUE_CODE + for code, value in tags: + if code in SEARCH_CODES: + # First store handles, because at this point, NOT all objects + # are stored in the EntityDB, at first access convert the handle + # to a DXFEntity object. + value_code = code + entry_handle = value + elif code == KEY_CODE: + dict_key = value + if dict_key and entry_handle: + # Store entity as handle string: + self._data[dict_key] = entry_handle + entry_handle = None + dict_key = None + # Use same value code as loaded: + self._value_code = value_code + + def post_load_hook(self, doc: Drawing) -> None: + super().post_load_hook(doc) + db = doc.entitydb + + def items(): + for key, handle in self.items(): + entity = db.get(handle) + if entity is not None and entity.is_alive: + yield key, entity + + if len(self): + for k, v in list(items()): + self.__setitem__(k, v) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_dictionary.name) + self.dxf.export_dxf_attribs(tagwriter, ["hard_owned", "cloning"]) + self.export_dict(tagwriter) + + def export_dict(self, tagwriter: AbstractTagWriter): + # key: dict key string + # value: DXFEntity or handle as string + # Ignore invalid handles at export, because removing can create an empty + # dictionary, which is more a problem for AutoCAD than invalid handles, + # and removing the whole dictionary is maybe also a problem. + for key, value in self._data.items(): + tagwriter.write_tag2(KEY_CODE, key) + # Value can be a handle string or a DXFEntity object: + if isinstance(value, DXFEntity): + if value.is_alive: + value = value.dxf.handle + else: + logger.debug( + f'Key "{key}" points to a destroyed entity ' + f'in {str(self)}, target replaced by "0" handle.' + ) + value = "0" + # Use same value code as loaded: + tagwriter.write_tag2(self._value_code, value) + + @property + def is_hard_owner(self) -> bool: + """Returns ``True`` if the dictionary is hard owner of entities. + Hard owned entities will be destroyed by deleting the dictionary. + """ + return bool(self.dxf.hard_owned) + + def keys(self): + """Returns a :class:`KeysView` of all dictionary keys.""" + return self._data.keys() + + def items(self): + """Returns an :class:`ItemsView` for all dictionary entries as + (key, entity) pairs. An entity can be a handle string if the entity + does not exist. + """ + for key in self.keys(): + yield key, self.get(key) # maybe handle -> DXFEntity + + def __getitem__(self, key: str) -> DXFEntity: + """Return self[`key`]. + + The returned value can be a handle string if the entity does not exist. + + Raises: + DXFKeyError: `key` does not exist + + """ + if key in self._data: + return self._data[key] # type: ignore + else: + raise DXFKeyError(key) + + def __setitem__(self, key: str, entity: DXFObject) -> None: + """Set self[`key`] = `entity`. + + Only DXF objects stored in the OBJECTS section are allowed as content + of :class:`Dictionary` objects. DXF entities stored in layouts are not + allowed. + + Raises: + DXFTypeError: invalid DXF type + + """ + return self.add(key, entity) + + def __delitem__(self, key: str) -> None: + """Delete self[`key`]. + + Raises: + DXFKeyError: `key` does not exist + + """ + return self.remove(key) + + def __contains__(self, key: str) -> bool: + """Returns `key` ``in`` self.""" + return key in self._data + + def __len__(self) -> int: + """Returns count of dictionary entries.""" + return len(self._data) + + count = __len__ + + def get(self, key: str, default: Optional[DXFObject] = None) -> Optional[DXFObject]: + """Returns the :class:`DXFEntity` for `key`, if `key` exist else + `default`. An entity can be a handle string if the entity + does not exist. + + """ + return self._data.get(key, default) # type: ignore + + def find_key(self, entity: DXFEntity) -> str: + """Returns the DICTIONARY key string for `entity` or an empty string if not + found. + """ + for key, entry in self._data.items(): + if entry is entity: + return key + return "" + + def add(self, key: str, entity: DXFObject) -> None: + """Add entry (key, value). + + If the DICTIONARY is hard owner of its entries, the :meth:`add` does NOT take + ownership of the entity automatically. + + Raises: + DXFValueError: invalid entity handle + DXFTypeError: invalid DXF type + + """ + if isinstance(entity, str): + if not is_valid_handle(entity): + raise DXFValueError(f"Invalid entity handle #{entity} for key {key}") + elif isinstance(entity, DXFGraphic): + if self.doc is not None and self.doc.is_loading: # type: ignore + # AutoCAD add-ons can store graphical entities in DICTIONARIES + # in the OBJECTS section and AutoCAD does not complain - so just + # preserve them! + # Example "ZJMC-288.dxf" in issue #585, add-on: "acdgnlsdraw.crx"? + logger.warning(f"Invalid entity {str(entity)} in {str(self)}") + else: + # Do not allow ezdxf users to add graphical entities to a + # DICTIONARY object! + raise DXFTypeError(f"Graphic entities not allowed: {entity.dxftype()}") + self._data[key] = entity + + def take_ownership(self, key: str, entity: DXFObject): + """Add entry (key, value) and take ownership.""" + self.add(key, entity) + entity.dxf.owner = self.dxf.handle + + def remove(self, key: str) -> None: + """Delete entry `key`. Raises :class:`DXFKeyError`, if `key` does not + exist. Destroys hard owned DXF entities. + + """ + data = self._data + if key not in data: + raise DXFKeyError(key) + + if self.is_hard_owner: + assert self.doc is not None + entity = self.__getitem__(key) + # Presumption: hard owned DXF objects always reside in the OBJECTS + # section. + self.doc.objects.delete_entity(entity) # type: ignore + del data[key] + + def discard(self, key: str) -> None: + """Delete entry `key` if exists. Does not raise an exception if `key` + doesn't exist and does not destroy hard owned DXF entities. + + """ + try: + del self._data[key] + except KeyError: + pass + + def clear(self) -> None: + """Delete all entries from the dictionary and destroys hard owned + DXF entities. + """ + if self.is_hard_owner: + self._delete_hard_owned_entries() + self._data.clear() + + def _delete_hard_owned_entries(self) -> None: + # Presumption: hard owned DXF objects always reside in the OBJECTS section + objects = self.doc.objects # type: ignore + for key, entity in self.items(): + if isinstance(entity, DXFEntity): + objects.delete_entity(entity) # type: ignore + + def add_new_dict(self, key: str, hard_owned: bool = False) -> Dictionary: + """Create a new sub-dictionary of type :class:`Dictionary`. + + Args: + key: name of the sub-dictionary + hard_owned: entries of the new dictionary are hard owned + + """ + dxf_dict = self.doc.objects.add_dictionary( # type: ignore + owner=self.dxf.handle, hard_owned=hard_owned + ) + self.add(key, dxf_dict) + return dxf_dict + + def add_dict_var(self, key: str, value: str) -> DictionaryVar: + """Add a new :class:`DictionaryVar`. + + Args: + key: entry name as string + value: entry value as string + + """ + new_var = self.doc.objects.add_dictionary_var( # type: ignore + owner=self.dxf.handle, value=value + ) + self.add(key, new_var) + return new_var + + def add_xrecord(self, key: str) -> XRecord: + """Add a new :class:`XRecord`. + + Args: + key: entry name as string + + """ + new_xrecord = self.doc.objects.add_xrecord( # type: ignore + owner=self.dxf.handle, + ) + self.add(key, new_xrecord) + return new_xrecord + + def set_or_add_dict_var(self, key: str, value: str) -> DictionaryVar: + """Set or add new :class:`DictionaryVar`. + + Args: + key: entry name as string + value: entry value as string + + """ + if key not in self: + dict_var = self.doc.objects.add_dictionary_var( # type: ignore + owner=self.dxf.handle, value=value + ) + self.add(key, dict_var) + else: + dict_var = self.get(key) + dict_var.dxf.value = str(value) # type: ignore + return dict_var + + def link_dxf_object(self, name: str, obj: DXFObject) -> None: + """Add `obj` and set owner of `obj` to this dictionary. + + Graphical DXF entities have to reside in a layout and therefore can not + be owned by a :class:`Dictionary`. + + Raises: + DXFTypeError: `obj` has invalid DXF type + + """ + if not isinstance(obj, DXFObject): + raise DXFTypeError(f"invalid DXF type: {obj.dxftype()}") + self.add(name, obj) + obj.dxf.owner = self.dxf.handle + + def get_required_dict(self, key: str, hard_owned=False) -> Dictionary: + """Get entry `key` or create a new :class:`Dictionary`, + if `Key` not exist. + """ + dxf_dict = self.get(key) + if dxf_dict is None: + dxf_dict = self.add_new_dict(key, hard_owned=hard_owned) + elif not isinstance(dxf_dict, Dictionary): + raise DXFStructureError( + f"expected a DICTIONARY entity, got {str(dxf_dict)} for key: {key}" + ) + return dxf_dict + + def audit(self, auditor: Auditor) -> None: + if not self.is_alive: + return + super().audit(auditor) + self._remove_keys_to_missing_entities(auditor) + + def _remove_keys_to_missing_entities(self, auditor: Auditor): + trash: list[str] = [] + append = trash.append + db = auditor.entitydb + for key, entry in self._data.items(): + if isinstance(entry, str): + if entry not in db: + append(key) + elif entry.is_alive: + if entry.dxf.handle not in db: + append(key) + continue + else: # entity is destroyed, remove key + append(key) + for key in trash: + del self._data[key] + auditor.fixed_error( + code=AuditError.INVALID_DICTIONARY_ENTRY, + message=f'Removed entry "{key}" with invalid handle in {str(self)}', + dxf_entity=self, + data=key, + ) + + def destroy(self) -> None: + if not self.is_alive: + return + + if self.is_hard_owner: + self._delete_hard_owned_entries() + super().destroy() + + +acdb_dict_with_default = DefSubclass( + "AcDbDictionaryWithDefault", + { + "default": DXFAttr(340), + }, +) +acdb_dict_with_default_group_codes = group_code_mapping(acdb_dict_with_default) + + +@factory.register_entity +class DictionaryWithDefault(Dictionary): + DXFTYPE = "ACDBDICTIONARYWDFLT" + DXFATTRIBS = DXFAttributes(base_class, acdb_dictionary, acdb_dict_with_default) + + def __init__(self) -> None: + super().__init__() + self._default: Optional[DXFObject] = None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + super().copy_data(entity, copy_strategy=copy_strategy) + assert isinstance(entity, DictionaryWithDefault) + entity._default = self._default + + def post_load_hook(self, doc: Drawing) -> None: + # Set _default to None if default object not exist - audit() replaces + # a not existing default object by a placeholder object. + # AutoCAD ignores not existing default objects! + self._default = doc.entitydb.get(self.dxf.default) # type: ignore + super().post_load_hook(doc) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_dict_with_default_group_codes, 2) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_dict_with_default.name) + self.dxf.export_dxf_attribs(tagwriter, "default") + + def __getitem__(self, key: str): + return self.get(key) + + def get(self, key: str, default: Optional[DXFObject] = None) -> Optional[DXFObject]: + # `default` argument is ignored, exist only for API compatibility, + """Returns :class:`DXFEntity` for `key` or the predefined dictionary + wide :attr:`dxf.default` entity if `key` does not exist or ``None`` + if default value also not exist. + + """ + return super().get(key, default=self._default) + + def set_default(self, default: DXFObject) -> None: + """Set dictionary wide default entry. + + Args: + default: default entry as :class:`DXFEntity` + + """ + self._default = default + self.dxf.default = self._default.dxf.handle + + def audit(self, auditor: Auditor) -> None: + def create_missing_default_object(): + placeholder = self.doc.objects.add_placeholder(owner=self.dxf.handle) + self.set_default(placeholder) + auditor.fixed_error( + code=AuditError.CREATED_MISSING_OBJECT, + message=f"Created missing default object in {str(self)}.", + ) + + if self._default is None or not self._default.is_alive: + if auditor.entitydb.locked: + auditor.add_post_audit_job(create_missing_default_object) + else: + create_missing_default_object() + super().audit(auditor) + + +acdb_dict_var = DefSubclass( + "DictionaryVariables", + { + "schema": DXFAttr(280, default=0), + # Object schema number (currently set to 0) + "value": DXFAttr(1, default=""), + }, +) +acdb_dict_var_group_codes = group_code_mapping(acdb_dict_var) + + +@factory.register_entity +class DictionaryVar(DXFObject): + """ + DICTIONARYVAR objects are used by AutoCAD as a means to store named values + in the database for setvar / getvar purposes without the need to add entries + to the DXF HEADER section. System variables that are stored as + DICTIONARYVAR objects are the following: + + - DEFAULTVIEWCATEGORY + - DIMADEC + - DIMASSOC + - DIMDSEP + - DRAWORDERCTL + - FIELDEVAL + - HALOGAP + - HIDETEXT + - INDEXCTL + - INDEXCTL + - INTERSECTIONCOLOR + - INTERSECTIONDISPLAY + - MSOLESCALE + - OBSCOLOR + - OBSLTYPE + - OLEFRAME + - PROJECTNAME + - SORTENTS + - UPDATETHUMBNAIL + - XCLIPFRAME + - XCLIPFRAME + + """ + + DXFTYPE = "DICTIONARYVAR" + DXFATTRIBS = DXFAttributes(base_class, acdb_dict_var) + + @property + def value(self) -> str: + """Get/set the value of the :class:`DictionaryVar` as string.""" + return self.dxf.get("value", "") + + @value.setter + def value(self, data: str) -> None: + self.dxf.set("value", str(data)) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_dict_var_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_dict_var.name) + self.dxf.export_dxf_attribs(tagwriter, ["schema", "value"]) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dimension.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimension.py new file mode 100644 index 0000000..498ade4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimension.py @@ -0,0 +1,1230 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Union, Iterable, Iterator +from typing_extensions import Self + +import math +import logging +from ezdxf.audit import AuditError +from ezdxf.lldxf import validator, const +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + DXF12, + SUBCLASS_MARKER, + DXF2010, + DXF2000, + DXF2007, + DXF2004, + DXFValueError, + DXFTableEntryError, + DXFTypeError, +) +from ezdxf.lldxf.types import get_xcode_for +from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS +from ezdxf.math.transformtools import OCSTransform, NonUniformScalingError +from ezdxf.tools import take2 +from ezdxf.render.arrows import ARROWS +from ezdxf.explode import explode_entity +from ezdxf.entitydb import EntitySpace +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .dimstyleoverride import DimStyleOverride +from .copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, DXFEntity, DimStyle + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.layouts import BaseLayout, BlockLayout + from ezdxf.audit import Auditor + from ezdxf.query import EntityQuery + from ezdxf.math import OCS + from ezdxf import xref + + +logger = logging.getLogger("ezdxf") +ADSK_CONSTRAINTS = "*ADSK_CONSTRAINTS" + +__all__ = [ + "Dimension", + "ArcDimension", + "RadialDimensionLarge", + "OverrideMixin", + "DXF_DIMENSION_TYPES", + "register_override_handles", +] + +DXF_DIMENSION_TYPES = {"DIMENSION", "ARC_DIMENSION", "LARGE_RADIAL_DIMENSION"} + +acdb_dimension = DefSubclass( + "AcDbDimension", + { + # Version number: 0 = 2010 + "version": DXFAttr(280, default=0, dxfversion=DXF2010), + # Name of the block that contains the entities that make up the dimension + # picture. Dimensions in block references share the same geometry block, + # therefore deleting the geometry block is very dangerous! + # Important: DIMENSION constraints do not have this group code 2: + "geometry": DXFAttr(2, validator=validator.is_valid_block_name), + # Dimension style name: + "dimstyle": DXFAttr( + 3, + default="Standard", + validator=validator.is_valid_table_name, + # Do not fix automatically, but audit fixes value as 'Standard' + ), + # definition point for all dimension types in WCS: + "defpoint": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Midpoint of dimension text in OCS: + "text_midpoint": DXFAttr(11, xtype=XType.point3d), + # Insertion point for clones of a dimension (Baseline and Continue?) (in OCS) + # located in AcDbDimension? Another error in the DXF reference? + "insert": DXFAttr(12, xtype=XType.point3d, default=NULLVEC, optional=True), + # Dimension type: + # Important: Dimensional constraints do not have group code 70 + # Values 0–6 are integer values that represent the dimension type. + # Values 32, 64, and 128 are bit values, which are added to the integer + # values (value 32 is always set in R13 and later releases) + # 0 = Rotated, horizontal, or vertical; + # 1 = Aligned + # 2 = Angular; + # 3 = Diameter; + # 4 = Radius + # 5 = Angular 3 point and ARC_DIMENSION < DXF R2018 + # 6 = Ordinate + # 8 = ARC_DIMENSION >= DXF R2018 + # 32 = Indicates that the block reference (group code 2) is referenced by + # this dimension only + # 64 = Ordinate type. This is a bit value (bit 7) used only with integer + # value 6. If set, ordinate is X-type; if not set, ordinate is Y-type + # 128 = This is a bit value (bit 8) added to the other group 70 values if + # the dimension text has been positioned at a user-defined location + # rather than at the default location. + "dimtype": DXFAttr(70, default=0), + # Attachment point: + # 1 = Top left + # 2 = Top center + # 3 = Top right + # 4 = Middle left + # 5 = Middle center + # 6 = Middle right + # 7 = Bottom left + # 8 = Bottom center + # 9 = Bottom right + "attachment_point": DXFAttr( + 71, + default=5, + dxfversion=DXF2000, + validator=validator.is_in_integer_range(0, 10), + fixer=RETURN_DEFAULT, + ), + # Dimension text line-spacing style + # 1 (or missing) = At least (taller characters will override) + # 2 = Exact (taller characters will not override) + "line_spacing_style": DXFAttr( + 72, + default=1, + dxfversion=DXF2000, + optional=True, + validator=validator.is_in_integer_range(1, 3), + fixer=RETURN_DEFAULT, + ), + # Dimension text-line spacing factor: + # Percentage of default (3-on-5) line spacing to be applied. Valid values + # range from 0.25 to 4.00 + "line_spacing_factor": DXFAttr( + 41, + dxfversion=DXF2000, + optional=True, + validator=validator.is_in_float_range(0.25, 4.00), + fixer=validator.fit_into_float_range(0.25, 4.00), + ), + # Actual measurement (optional; read-only value) + "actual_measurement": DXFAttr(42, dxfversion=DXF2000, optional=True), + "unknown1": DXFAttr(73, dxfversion=DXF2000, optional=True), + "flip_arrow_1": DXFAttr( + 74, + dxfversion=DXF2000, + optional=True, + validator=validator.is_integer_bool, + fixer=validator.fix_integer_bool, + ), + "flip_arrow_2": DXFAttr( + 75, + dxfversion=DXF2000, + optional=True, + validator=validator.is_integer_bool, + fixer=validator.fix_integer_bool, + ), + # Dimension text explicitly entered by the user + # default is the measurement. + # If null or "<>", the dimension measurement is drawn as the text, + # if " " (one blank space), the text is suppressed. + # Anything else is drawn as the text. + "text": DXFAttr(1, default="", optional=True), + # Linear dimension types with an oblique angle have an optional group + # code 52. When added to the rotation angle of the linear dimension (group + # code 50), it gives the angle of the extension lines + # DXF reference error: wrong subclass AcDbAlignedDimension + "oblique_angle": DXFAttr(52, default=0, optional=True), + # The optional group code 53 is the rotation angle of the dimension + # text away from its default orientation (the direction of the dimension + # line) + "text_rotation": DXFAttr(53, default=0, optional=True), + # All dimension types have an optional 51 group code, which + # indicates the horizontal direction for the dimension entity. + # The dimension entity determines the orientation of dimension text and + # lines for horizontal, vertical, and rotated linear dimensions. + # This group value is the negative of the angle between the OCS X axis and + # the UCS X axis. It is always in the XY plane of the OCS + "horizontal_direction": DXFAttr(51, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_dimension_group_codes = group_code_mapping(acdb_dimension) + +acdb_dimension_dummy = DefSubclass( + "AcDbDimensionDummy", + { + # Definition point for linear and angular dimensions (in WCS) + # 'defpoint' (10,20,30) specifies the dimension line location. + # 'text_midpoint' (11,21,31) specifies the midpoint of the dimension text. + # (13,23,33) specifies the start point of the first extension line: + "defpoint2": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + # (14,24,34) specifies the start point of the second extension line: + "defpoint3": DXFAttr(14, xtype=XType.point3d, default=NULLVEC), + # Angle of rotated, horizontal, or vertical dimensions: + "angle": DXFAttr(50, default=0), + # Definition point for diameter, radius, and angular dimensions (in WCS) + "defpoint4": DXFAttr(15, xtype=XType.point3d, default=NULLVEC), + # Leader length for radius and diameter dimensions + "leader_length": DXFAttr(40), + # Point defining dimension arc for angular dimensions (in OCS) + # 'defpoint2' (13,23,33) and 'defpoint3' (14,24,34) specify the endpoints + # of the line used to determine the first extension line. + # 'defpoint' (10,20,30) and 'defpoint4' (15,25,35) specify the endpoints of + # the line used to determine the second extension line. + # 'defpoint5' (16,26,36) specifies the location of the dimension line arc. + # 'text_midpoint' (11,21,31) specifies the midpoint of the dimension text. + "defpoint5": DXFAttr(16, xtype=XType.point3d, default=NULLVEC), + }, +) +acdb_dimension_dummy_group_codes = group_code_mapping(acdb_dimension_dummy) + + +# noinspection PyUnresolvedReferences +class OverrideMixin: + def get_dim_style(self) -> DimStyle: + """Returns the associated :class:`DimStyle` entity.""" + assert self.doc is not None, "valid DXF document required" # type: ignore + + dim_style_name = self.dxf.dimstyle # type: ignore + # raises ValueError if not exist, but all dim styles in use should + # exist! + return self.doc.dimstyles.get(dim_style_name) # type: ignore + + def dim_style_attributes(self) -> DXFAttributes: + """Returns all valid DXF attributes (internal API).""" + return self.get_dim_style().DXFATTRIBS + + def dim_style_attr_names_to_handles(self, data: dict, dxfversion: str) -> dict: + """`Ezdxf` uses internally only resource names for arrows, linetypes + and text styles, but DXF 2000 and later requires handles for these + resources, this method translates resource names into related handles. + (e.g. 'dimtxsty': 'FancyStyle' -> 'dimtxsty_handle', ) + + Args: + data: dictionary of overridden DimStyle attributes as names (ezdxf) + dxfversion: target DXF version + + Returns: dictionary with resource names replaced by handles + + Raises: + DXFTableEntry: text style or line type does not exist + DXFKeyError: referenced block does not exist + + (internal API) + + """ + data = dict(data) + blocks = self.doc.blocks # type: ignore + + def set_arrow_handle(attrib_name, block_name): + attrib_name += "_handle" + if block_name in ARROWS: + # Create all arrows on demand + block_name = ARROWS.create_block(blocks, block_name) + if block_name == "_CLOSEDFILLED": # special arrow + handle = "0" # set special #0 handle for closed filled arrow + else: + block = blocks[block_name] + handle = block.block_record_handle + data[attrib_name] = handle + + def set_linetype_handle(attrib_name, linetype_name): + try: + ltype = self.doc.linetypes.get(linetype_name) + except DXFTableEntryError: + logger.warning(f'Required line type "{linetype_name}" does not exist.') + else: + data[attrib_name + "_handle"] = ltype.dxf.handle + + if dxfversion > DXF12: + # transform block names into block record handles + for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"): + try: + block_name = data.pop(attrib_name) + except KeyError: + pass + else: + set_arrow_handle(attrib_name, block_name) + + # replace 'dimtxsty' attribute by 'dimtxsty_handle' + try: + dimtxsty = data.pop("dimtxsty") + except KeyError: + pass + else: + txtstyle = self.doc.styles.get(dimtxsty) # type: ignore + data["dimtxsty_handle"] = txtstyle.dxf.handle + + if dxfversion >= DXF2007: + # transform linetype names into LTYPE entry handles + for attrib_name in ("dimltype", "dimltex1", "dimltex2"): + try: + linetype_name = data.pop(attrib_name) + except KeyError: + pass + else: + set_linetype_handle(attrib_name, linetype_name) + return data + + def set_acad_dstyle(self, data: dict) -> None: + """Set XDATA section ACAD:DSTYLE, to override DIMSTYLE attributes for + this DIMENSION entity. + + Args: + data: ``dict`` with DIMSTYLE attribute names as keys. + + (internal API) + + """ + assert self.doc is not None, "valid DXF document required" # type: ignore + # ezdxf uses internally only resource names for arrows, line types and + # text styles, but DXF 2000 and later requires handles for these + # resources: + actual_dxfversion = self.doc.dxfversion # type: ignore + data = self.dim_style_attr_names_to_handles(data, actual_dxfversion) + tags = [] + dim_style_attributes = self.dim_style_attributes() + for key, value in data.items(): + if key not in dim_style_attributes: + logger.debug(f'Ignore unknown DIMSTYLE attribute: "{key}"') + continue + dxf_attr = dim_style_attributes.get(key) + # Skip internal and virtual tags: + if dxf_attr and dxf_attr.code > 0: + if dxf_attr.dxfversion > actual_dxfversion: + logger.debug( + f'Unsupported DIMSTYLE attribute "{key}" for ' + f"DXF version {self.doc.acad_release}" # type: ignore + ) + continue + code = dxf_attr.code + tags.append((1070, code)) + if code == 5: + # DimStyle 'dimblk' has group code 5 but is not a handle, only used + # for DXF R12 + tags.append((1000, value)) + else: + tags.append((get_xcode_for(code), value)) + + if len(tags): + self.set_xdata_list("ACAD", "DSTYLE", tags) # type: ignore + + def dim_style_attr_handles_to_names(self, data: dict) -> dict: + """`Ezdxf` uses internally only resource names for arrows, line types + and text styles, but DXF 2000 and later requires handles for these + resources, this method translates resource handles into related names. + (e.g. 'dimtxsty_handle', -> 'dimtxsty': 'FancyStyle') + + Args: + data: dictionary of overridden DimStyle attributes as handles, + requires DXF R2000+ + + Returns: dictionary with resource as handles replaced by names + + Raises: + DXFTableEntry: text style or line type does not exist + DXFKeyError: referenced block does not exist + + (internal API) + + """ + data = dict(data) + db = self.doc.entitydb # type: ignore + + def set_arrow_name(attrib_name: str, handle: str): + # Special handle for default arrow CLOSEDFILLED: + if handle == "0": + # Special name for default arrow CLOSEDFILLED: + data[attrib_name] = "" + return + try: + block_record = db[handle] + except KeyError: + logger.warning( + f"Required arrow block #{handle} does not exist, " + f"ignoring {attrib_name.upper()} override." + ) + return + name = block_record.dxf.name + # Translate block name into ACAD standard name _OPEN30 -> OPEN30 + if name.startswith("_"): + acad_arrow_name = name[1:] + if ARROWS.is_acad_arrow(acad_arrow_name): + name = acad_arrow_name + data[attrib_name] = name + + def set_ltype_name(attrib_name: str, handle: str): + try: + ltype = db[handle] + except KeyError: + logger.warning( + f"Required line type #{handle} does not exist, " + f"ignoring {attrib_name.upper()} override." + ) + else: + data[attrib_name] = ltype.dxf.name + + # transform block record handles into block names + for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"): + blkrec_handle = data.pop(attrib_name + "_handle", None) + if blkrec_handle: + set_arrow_name(attrib_name, blkrec_handle) + + # replace 'dimtxsty_handle' attribute by 'dimtxsty' + dimtxsty_handle = data.pop("dimtxsty_handle", None) + if dimtxsty_handle: + try: + txtstyle = db[dimtxsty_handle] + except KeyError: + logger.warning( + f"Required text style #{dimtxsty_handle} does not exist, " + f"ignoring DIMTXSTY override." + ) + else: + data["dimtxsty"] = txtstyle.dxf.name + + # transform linetype handles into LTYPE entry names + for attrib_name in ("dimltype", "dimltex1", "dimltex2"): + handle = data.pop(attrib_name + "_handle", None) + if handle: + set_ltype_name(attrib_name, handle) + return data + + def get_acad_dstyle(self, dim_style: DimStyle) -> dict: + """Get XDATA section ACAD:DSTYLE, to override DIMSTYLE attributes for + this DIMENSION entity. Returns a ``dict`` with DIMSTYLE attribute names + as keys. + + (internal API) + """ + try: + data = self.get_xdata_list("ACAD", "DSTYLE") # type: ignore + except DXFValueError: + return {} + attribs = {} + codes = dim_style.CODE_TO_DXF_ATTRIB + for code_tag, value_tag in take2(data): + group_code = code_tag.value + value = value_tag.value + if group_code in codes: + attribs[codes[group_code]] = value + return self.dim_style_attr_handles_to_names(attribs) + + +@register_entity +class Dimension(DXFGraphic, OverrideMixin): + """DXF DIMENSION entity""" + + DXFTYPE = "DIMENSION" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_dimension, acdb_dimension_dummy + ) + LINEAR = 0 + ALIGNED = 1 + ANGULAR = 2 + DIAMETER = 3 + RADIUS = 4 + ANGULAR_3P = 5 + ORDINATE = 6 + ARC = 8 + ORDINATE_TYPE = 64 + USER_LOCATION_OVERRIDE = 128 + + # WARNING for destroy() method: + # Do not destroy associated anonymous block, if DIMENSION is used in a + # block, the same geometry block maybe used by multiple block references. + def __init__(self) -> None: + super().__init__() + # store the content of the geometry block for virtual entities + self.virtual_block_content: Optional[EntitySpace] = None + + def copy(self, copy_strategy=default_copy) -> Dimension: + virtual_copy = super().copy(copy_strategy=copy_strategy) + # The new virtual copy can not reference the same geometry block as the + # original dimension entity: + virtual_copy.dxf.discard("geometry") + return virtual_copy + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, Dimension) + if self.virtual_block_content: + # another copy of a virtual entity: + virtual_content = EntitySpace( + copy_strategy.copy(e) for e in self.virtual_block_content + ) + else: + # entity is a new virtual copy of self and can not share the same + # geometry block to be independently transformable: + virtual_content = EntitySpace(self.virtual_entities()) + # virtual_entities() returns the entities already translated + # to the insert location: + entity.dxf.discard("insert") + entity.virtual_block_content = virtual_content + + def post_bind_hook(self): + """Called after binding a virtual dimension entity to a document. + + This method is not called at the loading stage and virtual dimension + entities do not exist at the loading stage! + + """ + doc = self.doc + if self.virtual_block_content and doc is not None: + # create a new geometry block: + block = doc.blocks.new_anonymous_block(type_char="D") + # move virtual block content to the new geometry block: + for entity in self.virtual_block_content: + block.add_entity(entity) + self.dxf.geometry = block.name + # unlink virtual block content: + self.virtual_block_content = None + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_dimension_group_codes, 2, recover=True + ) + processor.fast_load_dxfattribs( + dxf, acdb_dimension_dummy_group_codes, 3, log=False + ) + # Ignore possible 5. subclass AcDbRotatedDimension, which has no + # content. + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion == DXF12: + self.dxf.export_dxf_attribs( + tagwriter, + [ + "geometry", + "dimstyle", + "defpoint", + "text_midpoint", + "insert", + "dimtype", + "text", + "defpoint2", + "defpoint3", + "defpoint4", + "defpoint5", + "leader_length", + "angle", + "horizontal_direction", + "oblique_angle", + "text_rotation", + ], + ) + return + + # else DXF2000+ + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_dimension.name) + dim_type = self.dimtype + self.dxf.export_dxf_attribs( + tagwriter, + [ + "version", + "geometry", + "dimstyle", + "defpoint", + "text_midpoint", + "insert", + "dimtype", + "attachment_point", + "line_spacing_style", + "line_spacing_factor", + "actual_measurement", + "unknown1", + "flip_arrow_1", + "flip_arrow_2", + "text", + "oblique_angle", + "text_rotation", + "horizontal_direction", + "extrusion", + ], + ) + # Processing by dimtype works only for the original DIMENSION entity. + # Until DXF R2018 dimtype 5 was shared between ARC_DIMENSION and + # angular & angular3p DIMENSION, which have different subclass + # structures! + if self.dxftype() != "DIMENSION": + return + + if dim_type == 0: # linear + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbAlignedDimension") + self.dxf.export_dxf_attribs(tagwriter, ["defpoint2", "defpoint3", "angle"]) + # empty but required subclass + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbRotatedDimension") + elif dim_type == 1: # aligned + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbAlignedDimension") + self.dxf.export_dxf_attribs(tagwriter, ["defpoint2", "defpoint3", "angle"]) + elif dim_type == 2: # angular & angular3p + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDb2LineAngularDimension") + self.dxf.export_dxf_attribs( + tagwriter, ["defpoint2", "defpoint3", "defpoint4", "defpoint5"] + ) + elif dim_type == 3: # diameter + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbDiametricDimension") + self.dxf.export_dxf_attribs(tagwriter, ["defpoint4", "leader_length"]) + elif dim_type == 4: # radius + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbRadialDimension") + self.dxf.export_dxf_attribs(tagwriter, ["defpoint4", "leader_length"]) + elif dim_type == 5: # angular & angular3p + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDb3PointAngularDimension") + self.dxf.export_dxf_attribs( + tagwriter, ["defpoint2", "defpoint3", "defpoint4", "defpoint5"] + ) + elif dim_type == 6: # ordinate + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbOrdinateDimension") + self.dxf.export_dxf_attribs(tagwriter, ["defpoint2", "defpoint3"]) + + def register_resources(self, registry: xref.Registry) -> None: + assert self.doc is not None + super().register_resources(registry) + registry.add_dim_style(self.dxf.dimstyle) + geometry = self.dxf.geometry + if self.doc.block_records.has_entry(geometry): + registry.add_block_name(geometry) + + if not self.has_xdata_list("ACAD", "DSTYLE"): + return + + if self.doc.dxfversion > const.DXF12: + # overridden resources are referenced by handle + register_override_handles(self, registry) + else: + # overridden resources are referenced by name + self.override().register_resources_r12(registry) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + super().map_resources(clone, mapping) + clone.dxf.dimstyle = mapping.get_dim_style(self.dxf.dimstyle) + clone.dxf.geometry = mapping.get_block_name(self.dxf.geometry) + + # DXF R2000+ references overridden resources by group code 1005 handles in the + # XDATA section, which are automatically mapped by the parent class DXFEntity! + assert self.doc is not None + if self.doc.dxfversion > const.DXF12: + return + self_override = self.override() + if not self_override.dimstyle_attribs: + return # has no overrides + assert isinstance(clone, Dimension) + self_override.map_resources_r12(clone, mapping) + + @property + def dimtype(self) -> int: + """:attr:`dxf.dimtype` without binary flags (32, 62, 128).""" + # undocumented ARC_DIMENSION = 8 (DXF R2018) + return self.dxf.dimtype & 15 + + # Special DIMENSION - Dimensional constraints + # No information in the DXF reference: + # layer name is "*ADSK_CONSTRAINTS" + # missing group code 2 - geometry block name + # has reactor to ACDBASSOCDEPENDENCY object + # Autodesk example: architectural_example-imperial.dxf + @property + def is_dimensional_constraint(self) -> bool: + """Returns ``True`` if the DIMENSION entity is a dimensional + constraint object. + """ + dxf = self.dxf + return dxf.layer == ADSK_CONSTRAINTS and not dxf.hasattr("geometry") + + def get_geometry_block(self) -> Optional[BlockLayout]: + """Returns :class:`~ezdxf.layouts.BlockLayout` of associated anonymous + dimension block, which contains the entities that make up the dimension + picture. Returns ``None`` if block name is not set or the BLOCK itself + does not exist + + """ + block_name = self.dxf.get("geometry", "*") + return self.doc.blocks.get(block_name) # type: ignore + + def get_measurement(self) -> Union[float, Vec3]: + """Returns the actual dimension measurement in :ref:`WCS` units, no + scaling applied for linear dimensions. Returns angle in degrees for + angular dimension from 2 lines and angular dimension from 3 points. + Returns vector from origin to feature location for ordinate dimensions. + + """ + tool = MEASUREMENT_TOOLS.get(self.dimtype) + if tool: + return tool(self) + else: + raise TypeError(f"Unknown DIMENSION type {self.dimtype}.") + + def override(self) -> DimStyleOverride: + """Returns the :class:`~ezdxf.entities.DimStyleOverride` object.""" + return DimStyleOverride(self) + + def render(self) -> None: + """Renders the graphical representation of the DIMENSION entity as DXF + primitives (TEXT, LINE, ARC, ...) into an anonymous content BLOCK. + """ + if self.is_virtual: + raise DXFTypeError("can not render virtual entity") + # Do not delete existing anonymous block, it is maybe referenced + # by a dimension entity in another block reference! Dimensions in block + # references share the same geometry block! + self.override().render() + + def transform(self, m: Matrix44) -> Dimension: + """Transform the DIMENSION entity by transformation matrix `m` inplace. + + Raises ``NonUniformScalingError()`` for non uniform scaling. + + """ + + def transform_if_exist(name: str, func): + if dxf.hasattr(name): + dxf.set(name, func(dxf.get(name))) + + dxf = self.dxf + ocs = OCSTransform(self.dxf.extrusion, m) + + for vertex_name in ("text_midpoint", "defpoint5", "insert"): + transform_if_exist(vertex_name, ocs.transform_vertex) + + for angle_name in ("text_rotation", "horizontal_direction", "angle"): + transform_if_exist(angle_name, ocs.transform_deg_angle) + + for vertex_name in ("defpoint", "defpoint2", "defpoint3", "defpoint4"): + transform_if_exist(vertex_name, m.transform) + + dxf.extrusion = ocs.new_extrusion + + # ignore cloned geometry, this would transform the block content + # multiple times: + if not dxf.hasattr("insert"): + self._transform_block_content(m) + self.post_transform(m) + return self + + def _block_content(self) -> Iterable[DXFGraphic]: + if self.virtual_block_content or self.is_virtual: + content = self.virtual_block_content + else: + content = self.get_geometry_block() # type: ignore + return content or [] # type: ignore + + def _transform_block_content(self, m: Matrix44) -> None: + for entity in self._block_content(): + try: + entity.transform(m) + except (NotImplementedError, NonUniformScalingError): + pass # ignore transformation errors + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + + def ocs_to_wcs(e: DXFGraphic, elevation: float): + # - OCS entities have to get the extrusion vector and the + # elevation of the DIMENSION entity + # - WCS entities have to be transformed to the WCS + dxftype = e.dxftype() + dxf = e.dxf + if dxftype == "LINE": + dxf.start = ocs.to_wcs(dxf.start.replace(z=elevation)) + dxf.end = ocs.to_wcs(dxf.end.replace(z=elevation)) + elif dxftype == "MTEXT": + e.convert_rotation_to_text_direction() # type: ignore + dxf.extrusion = ocs.uz + dxf.text_direction = ocs.to_wcs(dxf.text_direction) + dxf.insert = ocs.to_wcs(dxf.insert.replace(z=elevation)) + elif dxftype == "POINT": + dxf.location = ocs.to_wcs(dxf.location.replace(z=elevation)) + else: # OCS entities + dxf.extrusion = ocs.uz + # set elevation: + if dxf.hasattr("insert"): # INSERT, TEXT + dxf.insert = dxf.insert.replace(z=elevation) + elif dxf.hasattr("center"): # ARC, CIRCLE + dxf.center = dxf.center.replace(z=elevation) + elif dxftype == "SOLID": + # AutoCAD uses the SOLID entity to render the "solid fill" + # arrow directly without using a block reference as usual. >:( + for vtx_name in const.VERTEXNAMES: + point = dxf.get(vtx_name, NULLVEC).replace(z=elevation) + dxf.set(vtx_name, point) + + ocs = self.ocs() + dim_elevation = self.dxf.text_midpoint.z + transform = False + insert = self.dxf.get("insert", None) + if insert: + transform = True + insert = Vec3(ocs.to_wcs(insert)) + m = Matrix44.translate(insert.x, insert.y, insert.z) + + for entity in self._block_content(): + try: + copy = entity.copy(copy_strategy=default_copy) + except CopyNotSupported: + continue + + if ocs.transform: + # All block content entities are located in the OCS defined by + # the DIMENSION entity, even the WCS entities LINE, MTEXT and + # POINT: + ocs_to_wcs(copy, dim_elevation) + + if transform: + copy.transform(m) + yield copy + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields the graphical representation of the anonymous content BLOCK as virtual + DXF primitives (LINE, ARC, TEXT, ...). + + These virtual entities are located at the original location of the DIMENSION entity, + but they are not stored in the entity database, have no handle and are not + assigned to any layout. + + """ + return self.__virtual_entities__() + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explodes the graphical representation of the DIMENSION entity as DXF + primitives (LINE, ARC, TEXT, ...) into the target layout, ``None`` for the same + layout as the source DIMENSION entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container containing all DXF + primitives. + + Args: + target_layout: target layout for the DXF primitives, ``None`` for same + layout as source DIMENSION entity. + + """ + return explode_entity(self, target_layout) + + def destroy(self) -> None: + # Let virtual content just go out of scope: + del self.virtual_block_content + super().destroy() + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for "ReferencedBlocks" protocol.""" + if self.doc: + block_name = self.dxf.get("geometry", None) + if block_name: + block = self.doc.blocks.get(block_name) + if block is not None: + return (block.block_record_handle,) + return tuple() + + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + doc = auditor.doc + dxf = self.dxf + + if ( + not self.is_dimensional_constraint + and dxf.get("geometry", "*") not in doc.blocks + ): + auditor.fixed_error( + code=AuditError.UNDEFINED_BLOCK, + message=f"Removed {str(self)} without valid geometry block.", + ) + auditor.trash(self) + return + + dimstyle = dxf.get("dimstyle", "Standard") + if not doc.dimstyles.has_entry(dimstyle): + auditor.fixed_error( + code=AuditError.INVALID_DIMSTYLE, + message=f"Replaced invalid DIMSTYLE '{dimstyle}' by 'Standard'.", + ) + dxf.discard("dimstyle") + # AutoCAD ignores invalid data in the XDATA section, no need to + # check or repair. Ezdxf also ignores invalid XDATA overrides. + + +def register_override_handles(entity: DXFEntity, registry: xref.Registry) -> None: + override_tags = entity.get_xdata_list("ACAD", "DSTYLE") + for code, value in override_tags: + if code == 1005: + registry.add_handle(value) + + +acdb_arc_dimension = DefSubclass( + "AcDbArcDimension", + { + # start point of the 1st extension line: + "defpoint2": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + # start point of the 2ndt extension line: + "defpoint3": DXFAttr(14, xtype=XType.point3d, default=NULLVEC), + # center of arc: + "defpoint4": DXFAttr(15, xtype=XType.point3d, default=NULLVEC), + "start_angle": DXFAttr(40), # radians, unknown meaning + "end_angle": DXFAttr(41), # radians, unknown meaning + "is_partial": DXFAttr(70, validator=validator.is_integer_bool), + "has_leader": DXFAttr(71, validator=validator.is_integer_bool), + "leader_point1": DXFAttr(16, xtype=XType.point3d, default=NULLVEC), + "leader_point2": DXFAttr(17, xtype=XType.point3d, default=NULLVEC), + }, +) +acdb_arc_dimension_group_codes = group_code_mapping(acdb_arc_dimension) + + +@register_entity +class ArcDimension(Dimension): + """DXF ARC_DIMENSION entity""" + + # dimtype is 5 for DXF version <= R2013 + # dimtype is 8 for DXF version >= R2018 + + DXFTYPE = "ARC_DIMENSION" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_dimension, acdb_arc_dimension + ) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + # Skip Dimension loader: + dxf = super(Dimension, self).load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_dimension_group_codes, 2, recover=True + ) + processor.fast_load_dxfattribs( + dxf, acdb_arc_dimension_group_codes, 3, recover=True + ) + return dxf + + def versioned_dimtype(self, dxfversion: str) -> int: + if dxfversion > const.DXF2013: + return (self.dxf.dimtype & 0xFFF0) | 8 + else: + return (self.dxf.dimtype & 0xFFF0) | 5 + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + dimtype = self.dxf.dimtype # preserve original dimtype + self.dxf.dimtype = self.versioned_dimtype(tagwriter.dxfversion) + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbArcDimension") + self.dxf.export_dxf_attribs( + tagwriter, + [ + "defpoint2", + "defpoint3", + "defpoint4", + "start_angle", + "end_angle", + "is_partial", + "has_leader", + "leader_point1", + "leader_point2", + ], + ) + self.dxf.dimtype = dimtype # restore original dimtype + + def transform(self, m: Matrix44) -> Self: + """Transform the ARC_DIMENSION entity by transformation matrix `m` inplace. + + Raises ``NonUniformScalingError()`` for non uniform scaling. + + """ + + def transform_if_exist(name: str, func): + if dxf.hasattr(name): + dxf.set(name, func(dxf.get(name))) + + dxf = self.dxf + super().transform(m) + for vertex_name in ("leader_point1", "leader_point2"): + transform_if_exist(vertex_name, m.transform) + + return self + + +acdb_radial_dimension_large = DefSubclass( + "AcDbRadialDimensionLarge", + { + # center_point = def_point from subclass AcDbDimension + "chord_point": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + "override_center": DXFAttr(14, xtype=XType.point3d, default=NULLVEC), + "jog_point": DXFAttr(15, xtype=XType.point3d, default=NULLVEC), + "unknown2": DXFAttr(40), + }, +) +acdb_radial_dimension_large_group_codes = group_code_mapping( + acdb_radial_dimension_large +) + + +# Undocumented DXF entity - OpenDesignAlliance DWG Specification: +# chapter 20.4.30 +@register_entity +class RadialDimensionLarge(Dimension): + """DXF LARGE_RADIAL_DIMENSION entity""" + + DXFTYPE = "LARGE_RADIAL_DIMENSION" + DXFATTRIBS = DXFAttributes( + base_class, acdb_entity, acdb_dimension, acdb_radial_dimension_large + ) + MIN_DXF_VERSION_FOR_EXPORT = DXF2004 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + # Skip Dimension loader: + dxf = super(Dimension, self).load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_dimension_group_codes, 2, recover=True + ) + processor.fast_load_dxfattribs( + dxf, acdb_radial_dimension_large_group_codes, 3, recover=True + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbRadialDimensionLarge") + self.dxf.export_dxf_attribs( + tagwriter, + ["chord_point", "override_center", "jog_point", "unknown2"], + ) + + def transform(self, m: Matrix44) -> Self: + """Transform the LARGE_RADIAL_DIMENSION entity by transformation matrix + `m` inplace. + + Raises ``NonUniformScalingError()`` for non uniform scaling. + + """ + + def transform_if_exist(name: str, func): + if dxf.hasattr(name): + dxf.set(name, func(dxf.get(name))) + + dxf = self.dxf + super().transform(m) + # todo: are these WCS points? + for vertex_name in ("chord_point", "override_center", "Jog_point"): + transform_if_exist(vertex_name, m.transform) + + return self + + +# XDATA extension - meaning unknown +# 1001, ACAD_DSTYLE_DIMRADIAL_EXTENSION +# 1070, 387 +# 1070, 1 +# 1070, 388 +# 1040, 0.0 +# 1070, 390 +# 1040, 0.0 + + +# todo: DIMASSOC +acdb_dim_assoc = DefSubclass( + "AcDbDimAssoc", + { + # Handle of dimension object: + "dimension": DXFAttr(330), + # Associativity flag (bit-coded) + # 1 = First point reference + # 2 = Second point reference + # 4 = Third point reference + # 8 = Fourth point reference + "point_flag": DXFAttr(90), + "trans_space": DXFAttr( + 70, + validator=validator.is_integer_bool, + fixer=validator.fix_integer_bool, + ), + # Rotated Dimension type (parallel, perpendicular) + # Autodesk gone crazy: subclass AcDbOsnapPointRef with group code 1!!!!! + # }), DefSubclass('AcDbOsnapPointRef', { + "rotated_dim_type": DXFAttr(71), + # Object Osnap type: + # 0 = None + # 1 = Endpoint + # 2 = Midpoint + # 3 = Center + # 4 = Node + # 5 = Quadrant + # 6 = Intersection + # 7 = Insertion + # 8 = Perpendicular + # 9 = Tangent + # 10 = Nearest + # 11 = Apparent intersection + # 12 = Parallel + # 13 = Start point + "osnap_type": DXFAttr( + 72, + validator=validator.is_in_integer_range(0, 14), + fixer=validator.fit_into_integer_range(0, 14), + ), + # ID of main object (geometry) + "object_id": DXFAttr(331), + # Subtype of main object (edge, face) + "object_subtype": DXFAttr(73), + # GsMarker of main object (index) + "object_gs_marker": DXFAttr(91), + # Handle (string) of Xref object + "object_xref_id": DXFAttr(301), + # Geometry parameter for Near Osnap + "near_param": DXFAttr(40), + # Osnap point in WCS + "osnap_point": DXFAttr(10, xtype=XType.point3d), + # ID of intersection object (geometry) + "intersect_id": DXFAttr(332), + # Subtype of intersection object (edge/face) + "intersect_subtype": DXFAttr(74), + # GsMarker of intersection object (index) + "intersect_gs_marker": DXFAttr(92), + # Handle (string) of intersection Xref object + "intersect_xref_id": DXFAttr(302), + # hasLastPointRef flag (true/false) + "has_last_point_ref": DXFAttr( + 75, + validator=validator.is_integer_bool, + fixer=validator.fix_integer_bool, + ), + }, +) + + +def measure_linear_distance(dim: Dimension) -> float: + dxf = dim.dxf + return linear_measurement( + dxf.defpoint2, + dxf.defpoint3, + math.radians(dxf.get("angle", 0)), + dim.ocs(), + ) + + +def measure_diameter_or_radius(dim: Dimension) -> float: + p1 = Vec3(dim.dxf.defpoint) + p2 = Vec3(dim.dxf.defpoint4) + return (p2 - p1).magnitude + + +def measure_angle_between_two_lines(dim: Dimension) -> float: + dxf = dim.dxf + p1 = Vec3(dxf.defpoint2) # 1. point of 1. extension line + p2 = Vec3(dxf.defpoint3) # 2. point of 1. extension line + p3 = Vec3(dxf.defpoint4) # 1. point of 2. extension line + p4 = Vec3(dxf.defpoint) # 2. point of 2. extension line + dir1 = p2 - p1 # direction of 1. extension line + dir2 = p4 - p3 # direction of 2. extension line + return angle_between(dir1, dir2) + + +def measure_angle_between_three_points(dim: Dimension) -> float: + dxf = dim.dxf + p1 = Vec3(dxf.defpoint4) # center + p2 = Vec3(dxf.defpoint2) # 1. extension line + p3 = Vec3(dxf.defpoint3) # 2. extension line + dir1 = p2 - p1 # direction of 1. extension line + dir2 = p3 - p1 # direction of 2. extension line + return angle_between(dir1, dir2) + + +def get_feature_location(dim: Dimension) -> Vec3: + origin = Vec3(dim.dxf.defpoint) + feature_location = Vec3(dim.dxf.defpoint2) + return feature_location - origin + + +def angle_between(v1: Vec3, v2: Vec3) -> float: + angle = v2.angle_deg - v1.angle_deg + return angle + 360 if angle < 0 else angle + + +def linear_measurement( + p1: Vec3, p2: Vec3, angle: float = 0, ocs: Optional[OCS] = None +) -> float: + """Returns distance from `p1` to `p2` projected onto ray defined by + `angle`, `angle` in radians in the xy-plane. + + """ + if ocs is not None and ocs.uz != (0, 0, 1): + p1 = ocs.to_wcs(p1) + p2 = ocs.to_wcs(p2) + # angle in OCS xy-plane + ocs_direction = Vec3.from_angle(angle) + measurement_direction = ocs.to_wcs(ocs_direction) + else: + # angle in WCS xy-plane + measurement_direction = Vec3.from_angle(angle) + + t1 = measurement_direction.project(p1) + t2 = measurement_direction.project(p2) + return (t2 - t1).magnitude + + +# TODO: add ARC_DIMENSION dimtype=8 support +MEASUREMENT_TOOLS = { + const.DIM_LINEAR: measure_linear_distance, + const.DIM_ALIGNED: measure_linear_distance, + const.DIM_ANGULAR: measure_angle_between_two_lines, + const.DIM_DIAMETER: measure_diameter_or_radius, + const.DIM_RADIUS: measure_diameter_or_radius, + const.DIM_ANGULAR_3P: measure_angle_between_three_points, + const.DIM_ORDINATE: get_feature_location, +} diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyle.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyle.py new file mode 100644 index 0000000..8f1933a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyle.py @@ -0,0 +1,959 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional +from typing_extensions import Self +import logging +from ezdxf.enums import MTextLineAlignment +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + VIRTUAL_TAG, + group_code_mapping, + RETURN_DEFAULT, +) +from ezdxf.lldxf import const +from ezdxf.lldxf.const import DXF12, DXF2007, DXF2000 +from ezdxf.lldxf import validator +from ezdxf.render.arrows import ARROWS +from .dxfentity import SubclassProcessor, DXFEntity, base_class +from .layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["DimStyle"] +logger = logging.getLogger("ezdxf") + +acdb_dimstyle = DefSubclass( + "AcDbDimStyleTableRecord", + { + "name": DXFAttr(2, default="Standard", validator=validator.is_valid_table_name), + "flags": DXFAttr(70, default=0), + "dimpost": DXFAttr(3, default=""), + "dimapost": DXFAttr(4, default=""), + # Arrow names are the base data -> handle (DXF2000) is set at export + "dimblk": DXFAttr(5, default=""), + "dimblk1": DXFAttr(6, default=""), + "dimblk2": DXFAttr(7, default=""), + "dimscale": DXFAttr(40, default=1), + # 0 has a special but unknown meaning, handle as 1.0 + "dimasz": DXFAttr(41, default=2.5), + "dimexo": DXFAttr(42, default=0.625), + "dimdli": DXFAttr(43, default=3.75), + "dimexe": DXFAttr(44, default=1.25), + "dimrnd": DXFAttr(45, default=0), + "dimdle": DXFAttr(46, default=0), # dimension line extension + "dimtp": DXFAttr(47, default=0), + "dimtm": DXFAttr(48, default=0), + # undocumented: length of extension line if fixed (dimfxlon = 1) + "dimfxl": DXFAttr(49, dxfversion=DXF2007, default=2.5), + # jog angle, Angle of oblique dimension line segment in jogged radius dimension + "dimjogang": DXFAttr(50, dxfversion=DXF2007, default=90, optional=True), + # measurement text height + "dimtxt": DXFAttr(140, default=2.5), + # center marks and center lines; 0 = off, <0 = center line, >0 = center mark + "dimcen": DXFAttr(141, default=2.5), + "dimtsz": DXFAttr(142, default=0), + "dimaltf": DXFAttr(143, default=0.03937007874), + # measurement length factor + "dimlfac": DXFAttr(144, default=1), + # text vertical position if dimtad=0 + "dimtvp": DXFAttr(145, default=0), + "dimtfac": DXFAttr(146, default=1), + # default gap around the measurement text + "dimgap": DXFAttr(147, default=0.625), + "dimaltrnd": DXFAttr(148, dxfversion=DXF2000, default=0), + # 0=None, 1=canvas color, 2=dimtfillclr + "dimtfill": DXFAttr(69, dxfversion=DXF2007, default=0), + # color index for dimtfill==2 + "dimtfillclr": DXFAttr(70, dxfversion=DXF2007, default=0), + "dimtol": DXFAttr(71, default=0), + "dimlim": DXFAttr(72, default=0), + # text inside horizontal + "dimtih": DXFAttr(73, default=0), + # text outside horizontal + "dimtoh": DXFAttr(74, default=0), + # suppress extension line 1 + "dimse1": DXFAttr(75, default=0), + # suppress extension line 2 + "dimse2": DXFAttr(76, default=0), + # text vertical location: 0=center; 1+2+3=above; 4=below + "dimtad": DXFAttr(77, default=1), + "dimzin": DXFAttr(78, default=8), + # dimazin: + # 0 = Displays all leading and trailing zeros + # 1 = Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000) + # 2 = Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) + # 3 = Suppresses leading and trailing zeros (for example, 0.5000 becomes .5) + "dimazin": DXFAttr(79, default=3, dxfversion=DXF2000), + # dimarcsym: show arc symbol + # 0 = preceding text + # 1 = above text + # 2 = disable + "dimarcsym": DXFAttr(90, dxfversion=DXF2000, optional=True), + "dimalt": DXFAttr(170, default=0), + "dimaltd": DXFAttr(171, default=3), + "dimtofl": DXFAttr(172, default=1), + "dimsah": DXFAttr(173, default=0), + # force dimension text inside + "dimtix": DXFAttr(174, default=0), + "dimsoxd": DXFAttr(175, default=0), + # dimension line color + "dimclrd": DXFAttr(176, default=0), + # extension line color + "dimclre": DXFAttr(177, default=0), + # text color + "dimclrt": DXFAttr(178, default=0), + "dimadec": DXFAttr(179, dxfversion=DXF2000, default=2), + "dimunit": DXFAttr(270), # obsolete + "dimdec": DXFAttr(271, dxfversion=DXF2000, default=2), + # can appear multiple times ??? + "dimtdec": DXFAttr(272, dxfversion=DXF2000, default=2), + "dimaltu": DXFAttr(273, dxfversion=DXF2000, default=2), + "dimalttd": DXFAttr(274, dxfversion=DXF2000, default=3), + # 0 = Decimal degrees + # 1 = Degrees/minutes/seconds + # 2 = Grad + # 3 = Radians + "dimaunit": DXFAttr( + 275, + dxfversion=DXF2000, + default=0, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + "dimfrac": DXFAttr(276, dxfversion=DXF2000, default=0), + "dimlunit": DXFAttr(277, dxfversion=DXF2000, default=2), + "dimdsep": DXFAttr(278, dxfversion=DXF2000, default=44), + # 0 = Moves the dimension line with dimension text + # 1 = Adds a leader when dimension text is moved + # 2 = Allows text to be moved freely without a leader + "dimtmove": DXFAttr(279, dxfversion=DXF2000, default=0), + # 0=center; 1=left; 2=right; 3=above ext1; 4=above ext2 + "dimjust": DXFAttr(280, dxfversion=DXF2000, default=0), + # suppress first part of the dimension line + "dimsd1": DXFAttr(281, dxfversion=DXF2000, default=0), + # suppress second part of the dimension line + "dimsd2": DXFAttr(282, dxfversion=DXF2000, default=0), + "dimtolj": DXFAttr(283, dxfversion=DXF2000, default=0), + "dimtzin": DXFAttr(284, dxfversion=DXF2000, default=8), + "dimaltz": DXFAttr(285, dxfversion=DXF2000, default=0), + "dimalttz": DXFAttr(286, dxfversion=DXF2000, default=0), + "dimfit": DXFAttr(287), # obsolete, now use DIMATFIT and DIMTMOVE + "dimupt": DXFAttr(288, dxfversion=DXF2000, default=0), + # Determines how dimension text and arrows are arranged when space is + # not sufficient to place both within the extension lines. + # 0 = Places both text and arrows outside extension lines + # 1 = Moves arrows first, then text + # 2 = Moves text first, then arrows + # 3 = Moves either text or arrows, whichever fits best + "dimatfit": DXFAttr(289, dxfversion=DXF2000, default=3), + # undocumented: 1 = fixed extension line length + "dimfxlon": DXFAttr(290, dxfversion=DXF2007, default=0), + # Virtual tags are transformed at DXF export - for DIMSTYLE the + # resource names are exported as _handle tags: + # virtual: set/get STYLE by name + "dimtxsty": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2000), + # virtual: set/get leader arrow by block name + "dimldrblk": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2000), + # virtual: set/get LINETYPE by name + "dimltype": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007), + # virtual: set/get referenced LINETYPE by name + "dimltex2": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007), + # virtual: set/get referenced LINETYPE by name + "dimltex1": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007), + # Entity handles are not used internally (see virtual tags above), + # these handles are set at DXF export: + # handle of referenced STYLE entry + "dimtxsty_handle": DXFAttr(340, dxfversion=DXF2000), + # handle of referenced BLOCK_RECORD + "dimblk_handle": DXFAttr(342, dxfversion=DXF2000), + # handle of referenced BLOCK_RECORD + "dimblk1_handle": DXFAttr(343, dxfversion=DXF2000), + # handle of referenced BLOCK_RECORD + "dimblk2_handle": DXFAttr(344, dxfversion=DXF2000), + # handle of referenced BLOCK_RECORD + "dimldrblk_handle": DXFAttr(341, dxfversion=DXF2000), + # handle of linetype for dimension line + "dimltype_handle": DXFAttr(345, dxfversion=DXF2007), + # handle of linetype for extension line 1 + "dimltex1_handle": DXFAttr(346, dxfversion=DXF2007), + # handle of linetype for extension line 2 + "dimltex2_handle": DXFAttr(347, dxfversion=DXF2007), + # dimension line lineweight enum value, default BYBLOCK + "dimlwd": DXFAttr(371, default=const.LINEWEIGHT_BYBLOCK, dxfversion=DXF2000), + # extension line lineweight enum value, default BYBLOCK + "dimlwe": DXFAttr(372, default=const.LINEWEIGHT_BYBLOCK, dxfversion=DXF2000), + }, +) +acdb_dimstyle_group_codes = group_code_mapping(acdb_dimstyle) + +EXPORT_MAP_R2007 = [ + "name", + "flags", + "dimscale", + "dimasz", + "dimexo", + "dimdli", + "dimexe", + "dimrnd", + "dimdle", + "dimtp", + "dimtm", + "dimfxl", + "dimjogang", + "dimtxt", + "dimcen", + "dimtsz", + "dimaltf", + "dimlfac", + "dimtvp", + "dimtfac", + "dimgap", + "dimaltrnd", + "dimtfill", + "dimtfillclr", + "dimtol", + "dimlim", + "dimtih", + "dimtoh", + "dimse1", + "dimse2", + "dimtad", + "dimzin", + "dimazin", + "dimarcsym", + "dimalt", + "dimaltd", + "dimtofl", + "dimsah", + "dimtix", + "dimsoxd", + "dimclrd", + "dimclre", + "dimclrt", + "dimadec", + "dimdec", + "dimtdec", + "dimaltu", + "dimalttd", + "dimaunit", + "dimfrac", + "dimlunit", + "dimdsep", + "dimtmove", + "dimjust", + "dimsd1", + "dimsd2", + "dimtolj", + "dimtzin", + "dimaltz", + "dimalttz", + "dimupt", + "dimatfit", + "dimfxlon", + "dimtxsty_handle", + "dimldrblk_handle", + "dimblk_handle", + "dimblk1_handle", + "dimblk2_handle", + "dimltype_handle", + "dimltex1_handle", + "dimltex2_handle", + "dimlwd", + "dimlwe", +] + +EXPORT_MAP_R2000 = [ + "name", + "flags", + "dimpost", + "dimapost", + "dimscale", + "dimasz", + "dimexo", + "dimdli", + "dimexe", + "dimrnd", + "dimdle", + "dimtp", + "dimtm", + "dimtxt", + "dimcen", + "dimtsz", + "dimaltf", + "dimlfac", + "dimtvp", + "dimtfac", + "dimgap", + "dimaltrnd", + "dimtol", + "dimlim", + "dimtih", + "dimtoh", + "dimse1", + "dimse2", + "dimtad", + "dimzin", + "dimazin", + "dimarcsym", + "dimalt", + "dimaltd", + "dimtofl", + "dimsah", + "dimtix", + "dimsoxd", + "dimclrd", + "dimclre", + "dimclrt", + "dimadec", + "dimdec", + "dimtdec", + "dimaltu", + "dimalttd", + "dimaunit", + "dimfrac", + "dimlunit", + "dimdsep", + "dimtmove", + "dimjust", + "dimsd1", + "dimsd2", + "dimtolj", + "dimtzin", + "dimaltz", + "dimalttz", + "dimupt", + "dimatfit", + "dimtxsty_handle", + "dimldrblk_handle", + "dimblk_handle", + "dimblk1_handle", + "dimblk2_handle", + "dimlwd", + "dimlwe", +] + +EXPORT_MAP_R12 = [ + "name", + "flags", + "dimpost", + "dimapost", + "dimblk", + "dimblk1", + "dimblk2", + "dimscale", + "dimasz", + "dimexo", + "dimdli", + "dimexe", + "dimrnd", + "dimdle", + "dimtp", + "dimtm", + "dimtxt", + "dimcen", + "dimtsz", + "dimaltf", + "dimlfac", + "dimtvp", + "dimtfac", + "dimgap", + "dimtol", + "dimlim", + "dimtih", + "dimtoh", + "dimse1", + "dimse2", + "dimtad", + "dimzin", + "dimalt", + "dimaltd", + "dimtofl", + "dimsah", + "dimtix", + "dimsoxd", + "dimclrd", + "dimclre", + "dimclrt", +] + +DIM_TEXT_STYLE_ATTR = "dimtxsty" +DIM_ARROW_HEAD_ATTRIBS = ("dimblk", "dimblk1", "dimblk2", "dimldrblk") +DIM_LINETYPE_ATTRIBS = ("dimltype", "dimltex1", "dimltex2") + + +def dim_filter(name: str) -> bool: + return name.startswith("dim") + + +@register_entity +class DimStyle(DXFEntity): + """DXF BLOCK_RECORD table entity""" + + DXFTYPE = "DIMSTYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_dimstyle) + CODE_TO_DXF_ATTRIB = dict(DXFATTRIBS.build_group_code_items(dim_filter)) + + @property + def dxfversion(self): + return self.doc.dxfversion + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + # group code 70 is used 2x, simple_dxfattribs_loader() can't be used! + processor.fast_load_dxfattribs(dxf, acdb_dimstyle_group_codes, 2) + return dxf + + def post_load_hook(self, doc: Drawing) -> None: + # 2nd Loading stage: resolve handles to names. + # ezdxf uses names for blocks, linetypes and text style as internal + # data, handles are set at export. + super().post_load_hook(doc) + db = doc.entitydb + for attrib_name in DIM_ARROW_HEAD_ATTRIBS: + if self.dxf.hasattr(attrib_name): + continue + block_record_handle = self.dxf.get(attrib_name + "_handle") + if block_record_handle and block_record_handle != "0": + try: + name = db[block_record_handle].dxf.name + except KeyError: + logger.info( + f"Replace undefined block reference " + f"#{block_record_handle} by default arrow." + ) + name = "" # default arrow name + else: + name = "" # default arrow name + self.dxf.set(attrib_name, name) + + style_handle = self.dxf.get("dimtxsty_handle", None) + if style_handle and style_handle != "0": + try: + self.dxf.dimtxsty = db[style_handle].dxf.name + except (KeyError, AttributeError): + logger.info(f"Ignore undefined text style #{style_handle}.") + + for attrib_name in DIM_LINETYPE_ATTRIBS: + lt_handle = self.dxf.get(attrib_name + "_handle", None) + if lt_handle and lt_handle != "0": + try: + name = db[lt_handle].dxf.name + except (KeyError, AttributeError): + logger.info(f"Ignore undefined line type #{lt_handle}.") + else: + self.dxf.set(attrib_name, name) + # Remove all handles, to be sure setting handles for resource names + # at export. + self.discard_handles() + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_dimstyle.name) + + if tagwriter.dxfversion > DXF12: + # Set handles from dimblk names: + self.set_handles() + + if tagwriter.dxfversion == DXF12: + attribs = EXPORT_MAP_R12 + elif tagwriter.dxfversion < DXF2007: + attribs = EXPORT_MAP_R2000 + else: + attribs = EXPORT_MAP_R2007 + self.dxf.export_dxf_attribs(tagwriter, attribs) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + assert self.doc is not None, "DIMSTYLE entity must be assigned to a document" + super().register_resources(registry) + # ezdxf uses names for blocks, linetypes and text style as internal data + # register text style + text_style_name = self.dxf.get(DIM_TEXT_STYLE_ATTR) + if text_style_name: + try: + style = self.doc.styles.get(text_style_name) + registry.add_entity(style) + except const.DXFTableEntryError: + pass + + # register linetypes + for attr_name in DIM_LINETYPE_ATTRIBS: + ltype_name = self.dxf.get(attr_name) + if ltype_name is None: + continue + try: + ltype = self.doc.linetypes.get(ltype_name) + registry.add_entity(ltype) + except const.DXFTableEntryError: + pass + + # Note: ACAD arrow head blocks are created automatically at export in set_blk_handle() + for attr_name in DIM_ARROW_HEAD_ATTRIBS: + arrow_name = self.dxf.get(attr_name) + if arrow_name is None: + continue + if not ARROWS.is_acad_arrow(arrow_name): + # user defined arrow head block + registry.add_block_name(arrow_name) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, DimStyle) + super().map_resources(clone, mapping) + # ezdxf uses names for blocks, linetypes and text style as internal data + # map text style + text_style = self.dxf.get(DIM_TEXT_STYLE_ATTR) + if text_style: + clone.dxf.dimtxsty = mapping.get_text_style(text_style) + # map linetypes + for attr_name in DIM_LINETYPE_ATTRIBS: + ltype_name = self.dxf.get(attr_name) + if ltype_name: + clone.dxf.set(attr_name, mapping.get_linetype(ltype_name)) + + # Note: ACAD arrow head blocks are created automatically at export in set_blk_handle() + for attr_name in DIM_ARROW_HEAD_ATTRIBS: + arrow_name = self.dxf.get(attr_name) + if arrow_name is None: + continue + if not ARROWS.is_acad_arrow(arrow_name): + # user defined arrow head block + arrow_name = mapping.get_block_name(arrow_name) + clone.dxf.set(attr_name, arrow_name) + + def set_handles(self): + style = self.dxf.get(DIM_TEXT_STYLE_ATTR) + if style: + self.dxf.dimtxsty_handle = self.doc.styles.get(style).dxf.handle + + for attr_name in DIM_ARROW_HEAD_ATTRIBS: + block_name = self.dxf.get(attr_name) + if block_name: + self.set_blk_handle(attr_name + "_handle", block_name) + + for attr_name in DIM_LINETYPE_ATTRIBS: + get_linetype = self.doc.linetypes.get + ltype_name = self.dxf.get(attr_name) + if ltype_name: + handle = get_linetype(ltype_name).dxf.handle + self.dxf.set(attr_name + "_handle", handle) + + def discard_handles(self): + for attr in ( + "dimblk", + "dimblk1", + "dimblk2", + "dimldrblk", + "dimltype", + "dimltex1", + "dimltex2", + "dimtxsty", + ): + self.dxf.discard(attr + "_handle") + + def set_blk_handle(self, attr: str, arrow_name: str) -> None: + if arrow_name == ARROWS.closed_filled: + # special arrow, no handle needed (is '0' if set) + # do not create block by default, this will be done if arrow is used + # and block record handle is not needed here + self.dxf.discard(attr) + return + assert self.doc is not None, "valid DXF document required" + blocks = self.doc.blocks + if ARROWS.is_acad_arrow(arrow_name): + # create block, because the block record handle is needed here + block_name = ARROWS.create_block(blocks, arrow_name) + else: + block_name = arrow_name + + blk = blocks.get(block_name) + if blk is not None: + self.set_dxf_attrib(attr, blk.block_record_handle) + else: + raise const.DXFValueError(f'Block "{arrow_name}" does not exist.') + + def get_arrow_block_name(self, name: str) -> str: + assert self.doc is not None, "valid DXF document required" + handle = self.get_dxf_attrib(name, None) + if handle in (None, "0"): + # unset handle or handle '0' is default closed filled arrow + return ARROWS.closed_filled + else: + block_name = get_block_name_by_handle(handle, self.doc) + # Returns standard arrow name or the user defined block name: + return ARROWS.arrow_name(block_name) + + def set_linetypes(self, dimline=None, ext1=None, ext2=None) -> None: + if self.dxfversion < DXF2007: + logger.debug("Linetype support requires DXF R2007+.") + + if dimline is not None: + self.dxf.dimltype = dimline + if ext1 is not None: + self.dxf.dimltex1 = ext1 + if ext2 is not None: + self.dxf.dimltex2 = ext2 + + def print_dim_attribs(self) -> None: + attdef = self.DXFATTRIBS.get + for name, value in self.dxfattribs().items(): + if name.startswith("dim"): + print(f"{name} ({attdef(name).code}) = {value}") # type: ignore + + def copy_to_header(self, doc: Drawing): + """Copy all dimension style variables to HEADER section of `doc`.""" + attribs = self.dxfattribs() + header = doc.header + header["$DIMSTYLE"] = self.dxf.name + for name, value in attribs.items(): + if name.startswith("dim"): + header_var = "$" + name.upper() + try: + header[header_var] = value + except const.DXFKeyError: + logger.debug(f"Unsupported header variable: {header_var}.") + + def set_arrows( + self, blk: str = "", blk1: str = "", blk2: str = "", ldrblk: str = "" + ) -> None: + """Set arrows by block names or AutoCAD standard arrow names, set + DIMTSZ to ``0`` which disables tick. + + Args: + blk: block/arrow name for both arrows, if DIMSAH is 0 + blk1: block/arrow name for first arrow, if DIMSAH is 1 + blk2: block/arrow name for second arrow, if DIMSAH is 1 + ldrblk: block/arrow name for leader + + """ + self.set_dxf_attrib("dimblk", blk) + self.set_dxf_attrib("dimblk1", blk1) + self.set_dxf_attrib("dimblk2", blk2) + self.set_dxf_attrib("dimldrblk", ldrblk) + self.set_dxf_attrib("dimtsz", 0) # use blocks + + # only existing BLOCK definitions allowed + if self.doc: + blocks = self.doc.blocks + for b in (blk, blk1, blk2, ldrblk): + if ARROWS.is_acad_arrow(b): # not real blocks + ARROWS.create_block(blocks, b) + continue + if b and b not in blocks: + raise const.DXFValueError(f'BLOCK "{blk}" does not exist.') + + def set_tick(self, size: float = 1) -> None: + """Set tick `size`, which also disables arrows, a tick is just an + oblique stroke as marker. + + Args: + size: arrow size in drawing units + + """ + self.set_dxf_attrib("dimtsz", size) + + def set_text_align( + self, + halign: Optional[str] = None, + valign: Optional[str] = None, + vshift: Optional[float] = None, + ) -> None: + """Set measurement text alignment, `halign` defines the horizontal + alignment (requires DXF R2000+), `valign` defines the vertical + alignment, `above1` and `above2` means above extension line 1 or 2 and + aligned with extension line. + + Args: + halign: "left", "right", "center", "above1", "above2", + requires DXF R2000+ + valign: "above", "center", "below" + vshift: vertical text shift, if `valign` is "center"; + >0 shift upward, + <0 shift downwards + + """ + if valign: + valign = valign.lower() + self.set_dxf_attrib("dimtad", const.DIMTAD[valign]) + if valign == "center" and vshift is not None: + self.set_dxf_attrib("dimtvp", vshift) + + if halign: + self.set_dxf_attrib("dimjust", const.DIMJUST[halign.lower()]) + + def set_text_format( + self, + prefix: str = "", + postfix: str = "", + rnd: Optional[float] = None, + dec: Optional[int] = None, + sep: Optional[str] = None, + leading_zeros: bool = True, + trailing_zeros: bool = True, + ): + """Set dimension text format, like prefix and postfix string, rounding + rule and number of decimal places. + + Args: + prefix: Dimension text prefix text as string + postfix: Dimension text postfix text as string + rnd: Rounds all dimensioning distances to the specified value, for + instance, if DIMRND is set to 0.25, all distances round to the + nearest 0.25 unit. If you set DIMRND to 1.0, all distances round + to the nearest integer. + dec: Sets the number of decimal places displayed for the primary + units of a dimension, requires DXF R2000+ + sep: "." or "," as decimal separator, requires DXF R2000+ + leading_zeros: Suppress leading zeros for decimal dimensions + if ``False`` + trailing_zeros: Suppress trailing zeros for decimal dimensions + if ``False`` + + """ + if prefix or postfix: + self.dxf.dimpost = prefix + "<>" + postfix + if rnd is not None: + self.dxf.dimrnd = rnd + + # works only with decimal dimensions not inch and feet, US user set dimzin directly + if leading_zeros is not None or trailing_zeros is not None: + dimzin = 0 + if leading_zeros is False: + dimzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dxf.dimzin = dimzin + + if dec is not None: + self.dxf.dimdec = dec + if sep is not None: + self.dxf.dimdsep = ord(sep) + + def set_dimline_format( + self, + color: Optional[int] = None, + linetype: Optional[str] = None, + lineweight: Optional[int] = None, + extension: Optional[float] = None, + disable1: Optional[bool] = None, + disable2: Optional[bool] = None, + ): + """Set dimension line properties + + Args: + color: color index + linetype: linetype as string, requires DXF R2007+ + lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm, + requires DXF R2000+ + extension: extension length + disable1: ``True`` to suppress first part of dimension line, + requires DXF R2000+ + disable2: ``True`` to suppress second part of dimension line, + requires DXF R2000+ + + """ + if color is not None: + self.dxf.dimclrd = color + if extension is not None: + self.dxf.dimdle = extension + + if lineweight is not None: + self.dxf.dimlwd = lineweight + if disable1 is not None: + self.dxf.dimsd1 = disable1 + if disable2 is not None: + self.dxf.dimsd2 = disable2 + if linetype is not None: + self.dxf.dimltype = linetype + + def set_extline_format( + self, + color: Optional[int] = None, + lineweight: Optional[int] = None, + extension: Optional[float] = None, + offset: Optional[float] = None, + fixed_length: Optional[float] = None, + ): + """Set common extension line attributes. + + Args: + color: color index + lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm + extension: extension length above dimension line + offset: offset from measurement point + fixed_length: set fixed length extension line, length below the + dimension line + + """ + if color is not None: + self.dxf.dimclre = color + if extension is not None: + self.dxf.dimexe = extension + if offset is not None: + self.dxf.dimexo = offset + if lineweight is not None: + self.dxf.dimlwe = lineweight + if fixed_length is not None: + self.dxf.dimfxlon = 1 + self.dxf.dimfxl = fixed_length + + def set_extline1(self, linetype: Optional[str] = None, disable=False): + """Set extension line 1 attributes. + + Args: + linetype: linetype for extension line 1, requires DXF R2007+ + disable: disable extension line 1 if ``True`` + + """ + if disable: + self.dxf.dimse1 = 1 + if linetype is not None: + self.dxf.dimltex1 = linetype + + def set_extline2(self, linetype: Optional[str] = None, disable=False): + """Set extension line 2 attributes. + + Args: + linetype: linetype for extension line 2, requires DXF R2007+ + disable: disable extension line 2 if ``True`` + + """ + if disable: + self.dxf.dimse2 = 1 + if linetype is not None: + self.dxf.dimltex2 = linetype + + def set_tolerance( + self, + upper: float, + lower: Optional[float] = None, + hfactor: float = 1.0, + align: Optional[MTextLineAlignment] = None, + dec: Optional[int] = None, + leading_zeros: Optional[bool] = None, + trailing_zeros: Optional[bool] = None, + ) -> None: + """Set tolerance text format, upper and lower value, text height + factor, number of decimal places or leading and trailing zero + suppression. + + Args: + upper: upper tolerance value + lower: lower tolerance value, if ``None`` same as upper + hfactor: tolerance text height factor in relation to the dimension + text height + align: tolerance text alignment enum :class:`ezdxf.enums.MTextLineAlignment` + requires DXF R2000+ + dec: Sets the number of decimal places displayed, + requires DXF R2000+ + leading_zeros: suppress leading zeros for decimal dimensions + if ``False``, requires DXF R2000+ + trailing_zeros: suppress trailing zeros for decimal dimensions + if ``False``, requires DXF R2000+ + + """ + # Exclusive tolerances mode, disable limits + self.dxf.dimtol = 1 + self.dxf.dimlim = 0 + self.dxf.dimtp = float(upper) + if lower is not None: + self.dxf.dimtm = float(lower) + else: + self.dxf.dimtm = float(upper) + if hfactor is not None: + self.dxf.dimtfac = float(hfactor) + + # Works only with decimal dimensions not inch and feet, US user set + # dimzin directly. + if leading_zeros is not None or trailing_zeros is not None: + dimtzin = 0 + if leading_zeros is False: + dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dxf.dimtzin = dimtzin + + if align is not None: + self.dxf.dimtolj = int() + if dec is not None: + self.dxf.dimtdec = int(dec) + + def set_limits( + self, + upper: float, + lower: float, + hfactor: float = 1.0, + dec: Optional[int] = None, + leading_zeros: Optional[bool] = None, + trailing_zeros: Optional[bool] = None, + ) -> None: + """Set limits text format, upper and lower limit values, text height + factor, number of decimal places or leading and trailing zero + suppression. + + Args: + upper: upper limit value added to measurement value + lower: lower limit value subtracted from measurement value + hfactor: limit text height factor in relation to the dimension + text height + dec: Sets the number of decimal places displayed, + requires DXF R2000+ + leading_zeros: suppress leading zeros for decimal dimensions + if ``False``, requires DXF R2000+ + trailing_zeros: suppress trailing zeros for decimal dimensions + if ``False``, requires DXF R2000+ + + """ + # Exclusive limits mode, disable tolerances + self.dxf.dimlim = 1 + self.dxf.dimtol = 0 + self.dxf.dimtp = float(upper) + self.dxf.dimtm = float(lower) + self.dxf.dimtfac = float(hfactor) + + # Works only with decimal dimensions not inch and feet, US user set + # dimzin directly. + if leading_zeros is not None or trailing_zeros is not None: + dimtzin = 0 + if leading_zeros is False: + dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dxf.dimtzin = dimtzin + self.dxf.dimtolj = 0 # set bottom as default + if dec is not None: + self.dxf.dimtdec = int(dec) + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for "ReferencedBlocks" protocol.""" + if self.doc: + blocks = self.doc.blocks + for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"): + name = self.dxf.get(attrib_name, None) + if name: + block = blocks.get(name, None) + if block is not None: + yield block.block_record.dxf.handle + + +def get_block_name_by_handle(handle, doc: Drawing, default="") -> str: + try: + entry = doc.entitydb[handle] + except const.DXFKeyError: + block_name = default + else: + block_name = entry.dxf.name + return block_name diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyleoverride.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyleoverride.py new file mode 100644 index 0000000..18c18f1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dimstyleoverride.py @@ -0,0 +1,583 @@ +# Copyright (c) 2019-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, TYPE_CHECKING, Optional +from typing_extensions import Protocol +import logging + +from ezdxf.enums import MTextLineAlignment +from ezdxf.lldxf import const +from ezdxf.lldxf.const import DXFAttributeError, DIMJUST, DIMTAD +from ezdxf.math import Vec3, UVec, UCS +from ezdxf.render.arrows import ARROWS + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DimStyle, Dimension + from ezdxf.render.dim_base import BaseDimensionRenderer + from ezdxf import xref + +logger = logging.getLogger("ezdxf") + + +class SupportsOverride(Protocol): + def override(self) -> DimStyleOverride: + ... + + +class DimStyleOverride: + def __init__(self, dimension: Dimension, override: Optional[dict] = None): + self.dimension = dimension + dim_style_name: str = dimension.get_dxf_attrib("dimstyle", "STANDARD") + self.dimstyle: DimStyle = self.doc.dimstyles.get(dim_style_name) + self.dimstyle_attribs: dict = self.get_dstyle_dict() + + # Special ezdxf attributes beyond the DXF reference, therefore not + # stored in the DSTYLE data. + # These are only rendering effects or data transfer objects + # user_location: Vec3 - user location override if not None + # relative_user_location: bool - user location override relative to + # dimline center if True + # text_shift_h: float - shift text in text direction, relative to + # standard text location + # text_shift_v: float - shift text perpendicular to text direction, + # relative to standard text location + self.update(override or {}) + + @property + def doc(self) -> Drawing: + """Drawing object (internal API)""" + return self.dimension.doc # type: ignore + + @property + def dxfversion(self) -> str: + """DXF version (internal API)""" + return self.doc.dxfversion + + def get_dstyle_dict(self) -> dict: + """Get XDATA section ACAD:DSTYLE, to override DIMSTYLE attributes for + this DIMENSION entity. + + Returns a ``dict`` with DIMSTYLE attribute names as keys. + + (internal API) + """ + return self.dimension.get_acad_dstyle(self.dimstyle) + + def get(self, attribute: str, default: Any = None) -> Any: + """Returns DIMSTYLE `attribute` from override dict + :attr:`dimstyle_attribs` or base :class:`DimStyle`. + + Returns `default` value for attributes not supported by DXF R12. This + is a hack to use the same algorithm to render DXF R2000 and DXF R12 + DIMENSION entities. But the DXF R2000 attributes are not stored in the + DXF R12 file! This method does not catch invalid attribute names! + Check debug log for ignored DIMSTYLE attributes. + + """ + if attribute in self.dimstyle_attribs: + result = self.dimstyle_attribs[attribute] + else: + try: + result = self.dimstyle.get_dxf_attrib(attribute, default) + except DXFAttributeError: + result = default + return result + + def pop(self, attribute: str, default: Any = None) -> Any: + """Returns DIMSTYLE `attribute` from override dict :attr:`dimstyle_attribs` and + removes this `attribute` from override dict. + """ + value = self.get(attribute, default) + # delete just from override dict + del self[attribute] + return value + + def update(self, attribs: dict) -> None: + """Update override dict :attr:`dimstyle_attribs`. + + Args: + attribs: ``dict`` of DIMSTYLE attributes + + """ + self.dimstyle_attribs.update(attribs) + + def __getitem__(self, key: str) -> Any: + """Returns DIMSTYLE attribute `key`, see also :meth:`get`.""" + return self.get(key) + + def __setitem__(self, key: str, value: Any) -> None: + """Set DIMSTYLE attribute `key` in :attr:`dimstyle_attribs`.""" + self.dimstyle_attribs[key] = value + + def __delitem__(self, key: str) -> None: + """Deletes DIMSTYLE attribute `key` from :attr:`dimstyle_attribs`, + ignores :class:`KeyErrors` silently. + """ + try: + del self.dimstyle_attribs[key] + except KeyError: # silent discard + pass + + def register_resources_r12(self, registry: xref.Registry) -> None: + # DXF R2000+ references overridden resources by group code 1005 handles in the + # XDATA section, which are automatically mapped by the parent class DXFEntity! + assert self.doc.dxfversion == const.DXF12 + # register arrow heads + for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"): + arrow_name = self.get(attrib_name, "") + if arrow_name: + # arrow head names will be renamed like user blocks + # e.g. "_DOT" -> "xref$0$_DOT" + registry.add_block_name(ARROWS.block_name(arrow_name)) + # linetype and text style attributes are not supported by DXF R12! + + def map_resources_r12( + self, copy: SupportsOverride, mapping: xref.ResourceMapper + ) -> None: + # DXF R2000+ references overridden resources by group code 1005 handles in the + # XDATA section, which are automatically mapped by the parent class DXFEntity! + assert self.doc.dxfversion == const.DXF12 + copy_override = copy.override() + # map arrow heads + for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"): + arrow_name = self.get(attrib_name, "") + if arrow_name: + block_name = mapping.get_block_name(ARROWS.block_name(arrow_name)) + copy_override[attrib_name] = ARROWS.arrow_name(block_name) + copy_override.commit() + # The linetype attributes dimltype, dimltex1 and dimltex2 and the text style + # attribute dimtxsty are not supported by DXF R12! + # + # Weired behavior for DXF R12 detected + # ------------------------------------ + # BricsCAD writes the handles of overridden linetype- and text style attributes + # into the ACAD-DSTYLE dictionary like for DXF R2000+, but exports the table + # entries without handles, so remapping of these handles is only possible if the + # application (which loads this DXF file) assigns internally the same handles + # as BricsCAD does and this also works with Autodesk TrueView (oO = wtf!). + # Ezdxf cannot remap these handles! + + def commit(self) -> None: + """Writes overridden DIMSTYLE attributes into ACAD:DSTYLE section of + XDATA of the DIMENSION entity. + + """ + self.dimension.set_acad_dstyle(self.dimstyle_attribs) + + def set_arrows( + self, + blk: Optional[str] = None, + blk1: Optional[str] = None, + blk2: Optional[str] = None, + ldrblk: Optional[str] = None, + size: Optional[float] = None, + ) -> None: + """Set arrows or user defined blocks and disable oblique stroke as tick. + + Args: + blk: defines both arrows at once as name str or user defined block + blk1: defines left arrow as name str or as user defined block + blk2: defines right arrow as name str or as user defined block + ldrblk: defines leader arrow as name str or as user defined block + size: arrow size in drawing units + + """ + + def set_arrow(dimvar: str, name: str) -> None: + self.dimstyle_attribs[dimvar] = name + + if size is not None: + self.dimstyle_attribs["dimasz"] = float(size) + if blk is not None: + set_arrow("dimblk", blk) + self.dimstyle_attribs["dimsah"] = 0 + self.dimstyle_attribs["dimtsz"] = 0.0 # use arrows + if blk1 is not None: + set_arrow("dimblk1", blk1) + self.dimstyle_attribs["dimsah"] = 1 + self.dimstyle_attribs["dimtsz"] = 0.0 # use arrows + if blk2 is not None: + set_arrow("dimblk2", blk2) + self.dimstyle_attribs["dimsah"] = 1 + self.dimstyle_attribs["dimtsz"] = 0.0 # use arrows + if ldrblk is not None: + set_arrow("dimldrblk", ldrblk) + + def get_arrow_names(self) -> tuple[str, str]: + """Get arrow names as strings like 'ARCHTICK' as tuple (dimblk1, dimblk2).""" + dimtsz = self.get("dimtsz", 0) + blk1, blk2 = "", "" + if dimtsz == 0.0: + if bool(self.get("dimsah")): + blk1 = self.get("dimblk1", "") + blk2 = self.get("dimblk2", "") + else: + blk = self.get("dimblk", "") + blk1 = blk + blk2 = blk + return blk1, blk2 + + def get_decimal_separator(self) -> str: + dimdsep: int = self.get("dimdsep", 0) + return "," if dimdsep == 0 else chr(dimdsep) + + def set_tick(self, size: float = 1) -> None: + """Use oblique stroke as tick, disables arrows. + + Args: + size: arrow size in daring units + + """ + self.dimstyle_attribs["dimtsz"] = float(size) + + def set_text_align( + self, + halign: Optional[str] = None, + valign: Optional[str] = None, + vshift: Optional[float] = None, + ) -> None: + """Set measurement text alignment, `halign` defines the horizontal + alignment, `valign` defines the vertical alignment, `above1` and + `above2` means above extension line 1 or 2 and aligned with extension + line. + + Args: + halign: `left`, `right`, `center`, `above1`, `above2`, + requires DXF R2000+ + valign: `above`, `center`, `below` + vshift: vertical text shift, if `valign` is `center`; + >0 shift upward, <0 shift downwards + + """ + if halign: + self.dimstyle_attribs["dimjust"] = DIMJUST[halign.lower()] + + if valign: + valign = valign.lower() + self.dimstyle_attribs["dimtad"] = DIMTAD[valign] + if valign == "center" and vshift is not None: + self.dimstyle_attribs["dimtvp"] = float(vshift) + + def set_tolerance( + self, + upper: float, + lower: Optional[float] = None, + hfactor: Optional[float] = None, + align: Optional[MTextLineAlignment] = None, + dec: Optional[int] = None, + leading_zeros: Optional[bool] = None, + trailing_zeros: Optional[bool] = None, + ) -> None: + """Set tolerance text format, upper and lower value, text height + factor, number of decimal places or leading and trailing zero + suppression. + + Args: + upper: upper tolerance value + lower: lower tolerance value, if None same as upper + hfactor: tolerance text height factor in relation to the dimension + text height + align: tolerance text alignment enum :class:`ezdxf.enums.MTextLineAlignment` + dec: Sets the number of decimal places displayed + leading_zeros: suppress leading zeros for decimal dimensions if ``False`` + trailing_zeros: suppress trailing zeros for decimal dimensions if ``False`` + + """ + self.dimstyle_attribs["dimtol"] = 1 + self.dimstyle_attribs["dimlim"] = 0 + self.dimstyle_attribs["dimtp"] = float(upper) + if lower is not None: + self.dimstyle_attribs["dimtm"] = float(lower) + else: + self.dimstyle_attribs["dimtm"] = float(upper) + if hfactor is not None: + self.dimstyle_attribs["dimtfac"] = float(hfactor) + if align is not None: + self.dimstyle_attribs["dimtolj"] = int(align) + if dec is not None: + self.dimstyle_attribs["dimtdec"] = dec + + # Works only with decimal dimensions not inch and feet, US user set + # dimzin directly + if leading_zeros is not None or trailing_zeros is not None: + dimtzin = 0 + if leading_zeros is False: + dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dimstyle_attribs["dimtzin"] = dimtzin + + def set_limits( + self, + upper: float, + lower: float, + hfactor: Optional[float] = None, + dec: Optional[int] = None, + leading_zeros: Optional[bool] = None, + trailing_zeros: Optional[bool] = None, + ) -> None: + """Set limits text format, upper and lower limit values, text + height factor, number of decimal places or leading and trailing zero + suppression. + + Args: + upper: upper limit value added to measurement value + lower: lower limit value subtracted from measurement value + hfactor: limit text height factor in relation to the dimension + text height + dec: Sets the number of decimal places displayed, + requires DXF R2000+ + leading_zeros: suppress leading zeros for decimal dimensions if + ``False``, requires DXF R2000+ + trailing_zeros: suppress trailing zeros for decimal dimensions if + ``False``, requires DXF R2000+ + + """ + # exclusive limits + self.dimstyle_attribs["dimlim"] = 1 + self.dimstyle_attribs["dimtol"] = 0 + self.dimstyle_attribs["dimtp"] = float(upper) + self.dimstyle_attribs["dimtm"] = float(lower) + if hfactor is not None: + self.dimstyle_attribs["dimtfac"] = float(hfactor) + + # Works only with decimal dimensions not inch and feet, US user set + # dimzin directly. + if leading_zeros is not None or trailing_zeros is not None: + dimtzin = 0 + if leading_zeros is False: + dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dimstyle_attribs["dimtzin"] = dimtzin + + if dec is not None: + self.dimstyle_attribs["dimtdec"] = int(dec) + + def set_text_format( + self, + prefix: str = "", + postfix: str = "", + rnd: Optional[float] = None, + dec: Optional[int] = None, + sep: Optional[str] = None, + leading_zeros: Optional[bool] = None, + trailing_zeros: Optional[bool] = None, + ) -> None: + """Set dimension text format, like prefix and postfix string, rounding + rule and number of decimal places. + + Args: + prefix: dimension text prefix text as string + postfix: dimension text postfix text as string + rnd: Rounds all dimensioning distances to the specified value, for + instance, if DIMRND is set to 0.25, all distances round to the + nearest 0.25 unit. If you set DIMRND to 1.0, all distances round + to the nearest integer. + dec: Sets the number of decimal places displayed for the primary + units of a dimension. requires DXF R2000+ + sep: "." or "," as decimal separator + leading_zeros: suppress leading zeros for decimal dimensions if ``False`` + trailing_zeros: suppress trailing zeros for decimal dimensions if ``False`` + + """ + if prefix or postfix: + self.dimstyle_attribs["dimpost"] = prefix + "<>" + postfix + if rnd is not None: + self.dimstyle_attribs["dimrnd"] = rnd + if dec is not None: + self.dimstyle_attribs["dimdec"] = dec + if sep is not None: + self.dimstyle_attribs["dimdsep"] = ord(sep) + # Works only with decimal dimensions not inch and feet, US user set + # dimzin directly. + if leading_zeros is not None or trailing_zeros is not None: + dimzin = 0 + if leading_zeros is False: + dimzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS + if trailing_zeros is False: + dimzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS + self.dimstyle_attribs["dimzin"] = dimzin + + def set_dimline_format( + self, + color: Optional[int] = None, + linetype: Optional[str] = None, + lineweight: Optional[int] = None, + extension: Optional[float] = None, + disable1: Optional[bool] = None, + disable2: Optional[bool] = None, + ): + """Set dimension line properties. + + Args: + color: color index + linetype: linetype as string + lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm + extension: extension length + disable1: True to suppress first part of dimension line + disable2: True to suppress second part of dimension line + + """ + if color is not None: + self.dimstyle_attribs["dimclrd"] = color + if linetype is not None: + self.dimstyle_attribs["dimltype"] = linetype + if lineweight is not None: + self.dimstyle_attribs["dimlwd"] = lineweight + if extension is not None: + self.dimstyle_attribs["dimdle"] = extension + if disable1 is not None: + self.dimstyle_attribs["dimsd1"] = disable1 + if disable2 is not None: + self.dimstyle_attribs["dimsd2"] = disable2 + + def set_extline_format( + self, + color: Optional[int] = None, + lineweight: Optional[int] = None, + extension: Optional[float] = None, + offset: Optional[float] = None, + fixed_length: Optional[float] = None, + ): + """Set common extension line attributes. + + Args: + color: color index + lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm + extension: extension length above dimension line + offset: offset from measurement point + fixed_length: set fixed length extension line, length below the + dimension line + """ + if color is not None: + self.dimstyle_attribs["dimclre"] = color + if lineweight is not None: + self.dimstyle_attribs["dimlwe"] = lineweight + if extension is not None: + self.dimstyle_attribs["dimexe"] = extension + if offset is not None: + self.dimstyle_attribs["dimexo"] = offset + if fixed_length is not None: + self.dimstyle_attribs["dimfxlon"] = 1 + self.dimstyle_attribs["dimfxl"] = fixed_length + + def set_extline1(self, linetype: Optional[str] = None, disable=False): + """Set attributes of the first extension line. + + Args: + linetype: linetype for the first extension line + disable: disable first extension line if ``True`` + + """ + if linetype is not None: + self.dimstyle_attribs["dimltex1"] = linetype + if disable: + self.dimstyle_attribs["dimse1"] = 1 + + def set_extline2(self, linetype: Optional[str] = None, disable=False): + """Set attributes of the second extension line. + + Args: + linetype: linetype for the second extension line + disable: disable the second extension line if ``True`` + + """ + if linetype is not None: + self.dimstyle_attribs["dimltex2"] = linetype + if disable: + self.dimstyle_attribs["dimse2"] = 1 + + def set_text(self, text: str = "<>") -> None: + """Set dimension text. + + - `text` = " " to suppress dimension text + - `text` = "" or "<>" to use measured distance as dimension text + - otherwise display `text` literally + + """ + self.dimension.dxf.text = text + + def shift_text(self, dh: float, dv: float) -> None: + """Set relative text movement, implemented as user location override + without leader. + + Args: + dh: shift text in text direction + dv: shift text perpendicular to text direction + + """ + self.dimstyle_attribs["text_shift_h"] = dh + self.dimstyle_attribs["text_shift_v"] = dv + + def set_location(self, location: UVec, leader=False, relative=False) -> None: + """Set text location by user, special version for linear dimensions, + behaves for other dimension types like :meth:`user_location_override`. + + Args: + location: user defined text location + leader: create leader from text to dimension line + relative: `location` is relative to default location. + + """ + self.user_location_override(location) + linear = self.dimension.dimtype < 2 + curved = self.dimension.dimtype in (2, 5, 8) + if linear or curved: + self.dimstyle_attribs["dimtmove"] = 1 if leader else 2 + self.dimstyle_attribs["relative_user_location"] = relative + + def user_location_override(self, location: UVec) -> None: + """Set text location by user, `location` is relative to the origin of + the UCS defined in the :meth:`render` method or WCS if the `ucs` + argument is ``None``. + + """ + self.dimension.set_flag_state( + self.dimension.USER_LOCATION_OVERRIDE, state=True, name="dimtype" + ) + self.dimstyle_attribs["user_location"] = Vec3(location) + + def get_renderer(self, ucs: Optional[UCS] = None): + """Get designated DIMENSION renderer. (internal API)""" + return self.doc.dimension_renderer.dispatch(self, ucs) + + def render(self, ucs: Optional[UCS] = None, discard=False) -> BaseDimensionRenderer: + """Starts the dimension line rendering process and also writes overridden + dimension style attributes into the DSTYLE XDATA section. The rendering process + "draws" the graphical representation of the DIMENSION entity as DXF primitives + (TEXT, LINE, ARC, ...) into an anonymous content BLOCK. + + You can discard the content BLOCK for a friendly CAD applications like BricsCAD, + because the rendering of the dimension entity is done automatically by BricsCAD + if the content BLOCK is missing, and the result is in most cases better than the + rendering done by `ezdxf`. + + AutoCAD does not render DIMENSION entities automatically, therefore I see + AutoCAD as an unfriendly CAD application. + + Args: + ucs: user coordinate system + discard: discard the content BLOCK created by `ezdxf`, this works for + BricsCAD, AutoCAD refuses to open DXF files containing DIMENSION + entities without a content BLOCK + + Returns: + The rendering object of the DIMENSION entity for analytics + + """ + + renderer = self.get_renderer(ucs) + if discard: + self.doc.add_acad_incompatibility_message( + "DIMENSION entity without geometry BLOCK (discard=True)" + ) + else: + block = self.doc.blocks.new_anonymous_block(type_char="D") + self.dimension.dxf.geometry = block.name + renderer.render(block) + renderer.finalize() + if len(self.dimstyle_attribs): + self.commit() + return renderer diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfclass.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfclass.py new file mode 100644 index 0000000..89249a3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfclass.py @@ -0,0 +1,123 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from .dxfns import SubclassProcessor, DXFNamespace +from .dxfentity import DXFEntity +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF2004, DXF2000 +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.extendedtags import ExtendedTags + +__all__ = ["DXFClass"] + +class_def = DefSubclass( + None, + { + # Class DXF record name; always unique + "name": DXFAttr(1), + # C++ class name. Used to bind with software that defines object class + # behavior; always unique + "cpp_class_name": DXFAttr(2), + # Application name. Posted in Alert box when a class definition listed in + # this section is not currently loaded + "app_name": DXFAttr(3), + # Proxy capabilities flag. Bit-coded value that indicates the capabilities + # of this object as a proxy: + # 0 = No operations allowed (0) + # 1 = Erase allowed (0x1) + # 2 = Transform allowed (0x2) + # 4 = Color change allowed (0x4) + # 8 = Layer change allowed (0x8) + # 16 = Linetype change allowed (0x10) + # 32 = Linetype scale change allowed (0x20) + # 64 = Visibility change allowed (0x40) + # 128 = Cloning allowed (0x80) + # 256 = Lineweight change allowed (0x100) + # 512 = Plot Style Name change allowed (0x200) + # 895 = All operations except cloning allowed (0x37F) + # 1023 = All operations allowed (0x3FF) + # 1024 = Disables proxy warning dialog (0x400) + # 32768 = R13 format proxy (0x8000) + "flags": DXFAttr(90, default=0), + # Instance count for a custom class + "instance_count": DXFAttr(91, dxfversion=DXF2004, default=0), + # Was-a-proxy flag. Set to 1 if class was not loaded when this DXF file was + # created, and 0 otherwise + "was_a_proxy": DXFAttr(280, default=0), + # Is-an-entity flag. Set to 1 if class was derived from the AcDbEntity class + # and can reside in the BLOCKS or ENTITIES section. If 0, instances may + # appear only in the OBJECTS section + "is_an_entity": DXFAttr(281, default=0), + }, +) +class_def_group_codes = group_code_mapping(class_def) + + +@register_entity +class DXFClass(DXFEntity): + DXFTYPE = "CLASS" + DXFATTRIBS = DXFAttributes(class_def) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + @classmethod + def new( + cls, + handle: Optional[str] = None, + owner: Optional[str] = None, + dxfattribs=None, + doc: Optional[Drawing] = None, + ) -> DXFClass: + """New CLASS constructor - has no handle, no owner and do not need + document reference . + """ + dxf_class = cls() + dxf_class.doc = doc + dxfattribs = dxfattribs or {} + dxf_class.update_dxf_attribs(dxfattribs) + return dxf_class + + def load_tags( + self, tags: ExtendedTags, dxfversion: Optional[str] = None + ) -> None: + """Called by load constructor. CLASS is special.""" + if tags: + # do not process base class!!! + self.dxf = DXFNamespace(entity=self) + processor = SubclassProcessor(tags) + processor.fast_load_dxfattribs( + self.dxf, class_def_group_codes, 0, log=False + ) + + def export_dxf(self, tagwriter: AbstractTagWriter): + """Do complete export here, because CLASS is special.""" + dxfversion = tagwriter.dxfversion + if dxfversion < DXF2000: + return + attribs = self.dxf + tagwriter.write_tag2(0, self.DXFTYPE) + attribs.export_dxf_attribs( + tagwriter, + [ + "name", + "cpp_class_name", + "app_name", + "flags", + "instance_count", + "was_a_proxy", + "is_an_entity", + ], + ) + + @property + def key(self) -> tuple[str, str]: + return self.dxf.name, self.dxf.cpp_class_name diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfentity.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfentity.py new file mode 100644 index 0000000..070c9ca --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfentity.py @@ -0,0 +1,1088 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +""" :class:`DXFEntity` is the super class of all DXF entities. + +The current entity system uses the features of the latest supported DXF version. + +The stored DXF version of the document is used to warn users if they use +unsupported DXF features of the current DXF version. + +The DXF version of the document can be changed at runtime or overridden by +exporting, but unsupported DXF features are just ignored by exporting. + +Ezdxf does no conversion between different DXF versions, this package is +still not a CAD application. + +""" +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Any, + Iterable, + Iterator, + Optional, + Type, + TypeVar, + Callable, +) +from typing_extensions import Self + +import logging +import uuid +from ezdxf import options +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import DXFTag +from ezdxf.lldxf.extendedtags import ExtendedTags +from ezdxf.lldxf.attributes import DXFAttr, DXFAttributes, DefSubclass +from ezdxf.tools import set_flag_state +from . import factory +from .appdata import AppData, Reactors +from .dxfns import DXFNamespace, SubclassProcessor +from .xdata import XData +from .xdict import ExtensionDict +from .copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFGraphic, Insert + from ezdxf.lldxf.attributes import DXFAttr + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + from ezdxf import xref + + +__all__ = ["DXFEntity", "DXFTagStorage", "base_class", "SubclassProcessor"] +logger = logging.getLogger("ezdxf") + +# Dynamic attributes created only at request: +# Source entity of a copy or None if not a copy: +DYN_SOURCE_OF_COPY_ATTRIBUTE = "_source_of_copy" +# UUID created on demand by uuid.uuid4() +DYN_UUID_ATTRIBUTE = "_uuid" +# Source block reference, which created the virtual entity, bound entities can +# not have such an attribute: +DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE = "_source_block_reference" + +base_class: DefSubclass = DefSubclass( + None, + { + "handle": DXFAttr(5), + # owner: Soft-pointer ID/handle to owner BLOCK_RECORD object + # This tag is not supported by DXF R12, but is used intern to unify entity + # handling between DXF R12 and DXF R2000+ + # Do not write this tag into DXF R12 files! + "owner": DXFAttr(330), + # Application defined data can only appear here: + # 102, {APPID ... multiple entries possible DXF R12? + # 102, {ACAD_REACTORS ... one entry DXF R2000+, optional + # 102, {ACAD_XDICTIONARY ... one entry DXF R2000+, optional + }, +) + +T = TypeVar("T", bound="DXFEntity") + + +class DXFEntity: + """Common super class for all DXF entities.""" + + DXFTYPE = "DXFENTITY" # storing as class var needs less memory + DXFATTRIBS = DXFAttributes(base_class) # DXF attribute definitions + + # Default DXF attributes are set at instantiating a new object, the + # difference to attribute default values is, that this attributes are + # really set, this means there is an real object in the dxf namespace + # defined, where default attribute values get returned on access without + # an existing object in the dxf namespace. + DEFAULT_ATTRIBS: dict[str, Any] = {} + MIN_DXF_VERSION_FOR_EXPORT = const.DXF12 + + def __init__(self) -> None: + """Default constructor. (internal API)""" + # Public attributes for package users + self.doc: Optional[Drawing] = None + self.dxf: DXFNamespace = DXFNamespace(entity=self) + + # None public attributes for package users + # create extended data only if needed: + self.appdata: Optional[AppData] = None + self.reactors: Optional[Reactors] = None + self.extension_dict: Optional[ExtensionDict] = None + self.xdata: Optional[XData] = None + self.proxy_graphic: Optional[bytes] = None + + # For documentation: + # Dynamic attributes, created only at request: + # DYN_SOURCE_OF_COPY_ATTRIBUTE + # DYN_UUID_ATTRIBUTE + # DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE + + @property + def uuid(self) -> uuid.UUID: + """Returns a UUID, which allows to distinguish even + virtual entities without a handle. + + Dynamic attribute: this UUID will be created at the first request. + + """ + uuid_ = getattr(self, DYN_UUID_ATTRIBUTE, None) + if uuid_ is None: + uuid_ = uuid.uuid4() + setattr(self, DYN_UUID_ATTRIBUTE, uuid_) + return uuid_ + + @classmethod + def new( + cls: Type[T], + handle: Optional[str] = None, + owner: Optional[str] = None, + dxfattribs=None, + doc: Optional[Drawing] = None, + ) -> T: + """Constructor for building new entities from scratch by ezdxf. + + NEW process: + + This is a trusted environment where everything is under control of + ezdxf respectively the package-user, it is okay to raise exception + to show implementation errors in ezdxf or usage errors of the + package-user. + + The :attr:`Drawing.is_loading` flag can be checked to distinguish the + NEW and the LOAD process. + + Args: + handle: unique DXF entity handle or None + owner: owner handle if entity has an owner else None or '0' + dxfattribs: DXF attributes + doc: DXF document + + (internal API) + """ + entity = cls() + entity.doc = doc + entity.dxf.handle = handle + entity.dxf.owner = owner + attribs = dict(cls.DEFAULT_ATTRIBS) + attribs.update(dxfattribs or {}) + entity.update_dxf_attribs(attribs) + # Only this method triggers the post_new_hook() + entity.post_new_hook() + return entity + + def post_new_hook(self): + """Post-processing and integrity validation after entity creation. + + Called only if created by ezdxf (see :meth:`DXFEntity.new`), + not if loaded from an external source. + + (internal API) + """ + pass + + def post_bind_hook(self): + """Post-processing and integrity validation after binding entity to a + DXF Document. This method is triggered by the :func:`factory.bind` + function only when the entity was created by ezdxf. + + If the entity was loaded in the 1st loading stage, the + :func:`factory.load` functions also calls the :func:`factory.bind` + to bind entities to the loaded document, but not all entities are + loaded at this time. To avoid problems this method will not be called + when loading content from DXF file, but :meth:`post_load_hook` will be + triggered for loaded entities at a later and safer point in time. + + (internal API) + """ + pass + + @classmethod + def load(cls: Type[T], tags: ExtendedTags, doc: Optional[Drawing] = None) -> T: + """Constructor to generate entities loaded from an external source. + + LOAD process: + + This is an untrusted environment where valid structure are not + guaranteed and errors should be fixed, because the package-user is not + responsible for the problems and also can't fix them, raising + exceptions should only be done for unrecoverable issues. + Log fixes for debugging! + + Be more like BricsCAD and not as mean as AutoCAD! + + The :attr:`Drawing.is_loading` flag can be checked to distinguish the + NEW and the LOAD process. + + Args: + tags: DXF tags as :class:`ExtendedTags` + doc: DXF Document + + (internal API) + """ + # This method does not trigger the post_new_hook() + entity = cls() + entity.doc = doc + dxfversion = doc.dxfversion if doc else None + entity.load_tags(tags, dxfversion=dxfversion) + return entity + + def load_tags(self, tags: ExtendedTags, dxfversion: Optional[str] = None) -> None: + """Generic tag loading interface, called if DXF document is loaded + from external sources. + + 1. Loading stage which set the basic DXF attributes, additional + resources (DXF objects) are not loaded yet. References to these + resources have to be stored as handles and can be resolved in the + 2. Loading stage: :meth:`post_load_hook`. + + (internal API) + """ + if tags: + if len(tags.appdata): + self.setup_app_data(tags.appdata) + if len(tags.xdata): + try: # the common case - fast path + self.xdata = XData(tags.xdata) + except const.DXFValueError: # contains invalid group codes + self.xdata = XData.safe_init(tags.xdata) + logger.debug(f"removed invalid XDATA from {tags.entity_name()}") + + processor = SubclassProcessor(tags, dxfversion=dxfversion) + self.dxf = self.load_dxf_attribs(processor) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Load DXF attributes into DXF namespace.""" + return DXFNamespace(processor, self) + + def post_load_hook(self, doc: Drawing) -> Optional[Callable]: + """The 2nd loading stage when loading DXF documents from an external + source, for the 1st loading stage see :meth:`load_tags`. + + This stage is meant to convert resource handles into :class:`DXFEntity` + objects. This is an untrusted environment where valid structure are not + guaranteed, raise exceptions only for unrecoverable structure errors + and fix everything else. Log fixes for debugging! + + Some fixes can not be applied at this stage, because some structures + like the OBJECTS section are not initialized, in this case return a + callable, which will be executed after the DXF document is fully + initialized, for an example see :class:`Image`. + + Triggered in method: :meth:`Drawing._2nd_loading_stage` + + Examples for two stage loading: + Image, Underlay, DXFGroup, Dictionary, Dimstyle, MText + + """ + if self.extension_dict is not None: + self.extension_dict.load_resources(doc) + return None + + @classmethod + def from_text(cls: Type[T], text: str, doc: Optional[Drawing] = None) -> T: + """Load constructor from text for testing. (internal API)""" + return cls.load(ExtendedTags.from_text(text), doc) + + @classmethod + def shallow_copy(cls: Type[T], other: DXFEntity) -> T: + """Copy constructor for type casting e.g. Polyface and Polymesh. + (internal API) + """ + entity = cls() + entity.doc = other.doc + entity.dxf = other.dxf + entity.extension_dict = other.extension_dict + entity.reactors = other.reactors + entity.appdata = other.appdata + entity.xdata = other.xdata + entity.proxy_graphic = other.proxy_graphic + entity.dxf.rewire(entity) + # Do not set copy state, this is not a real copy! + return entity + + def copy(self, copy_strategy=default_copy) -> Self: + """Internal entity copy for usage in the same document or as virtual entity. + + Returns a copy of `self` but without handle, owner and reactors. + This copy is NOT stored in the entity database and does NOT reside + in any layout, block, table or objects section! + The extension dictionary will be copied for entities bound to a valid + DXF document. The reactors are not copied. + + (internal API) + """ + return copy_strategy.copy(self) + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy entity data like vertices or attribs to the copy of the entity. + + This is the second stage of the copy process, see copy() method. + + (internal API) + """ + pass + + def set_source_of_copy(self, source: Optional[DXFEntity]): + """Set immediate source entity of a copy. + + Also used from outside to set the source of sub-entities + of disassembled entities (POLYLINE, LWPOLYLINE, ...). + + (Internal API) + """ + if isinstance(source, DXFEntity) and not source.is_alive: + source = None + # dynamic attribute: exist only in copies: + setattr(self, DYN_SOURCE_OF_COPY_ATTRIBUTE, source) + + def del_source_of_copy(self) -> None: + """Delete source of copy reference. + + (Internal API) + """ + if hasattr(self, DYN_SOURCE_OF_COPY_ATTRIBUTE): + delattr(self, DYN_SOURCE_OF_COPY_ATTRIBUTE) + + @property + def is_copy(self) -> bool: + """Is ``True`` if the entity is a copy.""" + return self.source_of_copy is not None + + @property + def source_of_copy(self) -> Optional[DXFEntity]: + """The immediate source entity if this entity is a copy else + ``None``. Never references a destroyed entity. + """ + # attribute only exist in copies: + source = getattr(self, DYN_SOURCE_OF_COPY_ATTRIBUTE, None) + if isinstance(source, DXFEntity) and not source.is_alive: + return None + return source + + @property + def origin_of_copy(self) -> Optional[DXFEntity]: + """The origin source entity if this entity is a copy else + ``None``. References the first non-virtual source entity and never + references a destroyed entity. + """ + source = self.source_of_copy + # follow source entities references until the first non-virtual entity: + while isinstance(source, DXFEntity) and source.is_alive and source.is_virtual: + source = source.source_of_copy + return source + + def update_dxf_attribs(self, dxfattribs: dict) -> None: + """Set DXF attributes by a ``dict`` like :code:`{'layer': 'test', + 'color': 4}`. + """ + setter = self.dxf.set + for key, value in dxfattribs.items(): + setter(key, value) + + def setup_app_data(self, appdata: list[Tags]) -> None: + """Setup data structures from APP data. (internal API)""" + for data in appdata: + code, appid = data[0] + if appid == const.ACAD_REACTORS: + self.reactors = Reactors.from_tags(data) + elif appid == const.ACAD_XDICTIONARY: + self.extension_dict = ExtensionDict.from_tags(data) + else: + self.set_app_data(appid, data) + + def update_handle(self, handle: str) -> None: + """Update entity handle. (internal API)""" + self.dxf.handle = handle + if self.extension_dict: + self.extension_dict.update_owner(handle) + + @property + def is_alive(self) -> bool: + """Is ``False`` if entity has been deleted.""" + return hasattr(self, "dxf") + + @property + def is_virtual(self) -> bool: + """Is ``True`` if entity is a virtual entity.""" + return self.doc is None or self.dxf.handle is None + + @property + def is_bound(self) -> bool: + """Is ``True`` if entity is bound to DXF document.""" + if self.is_alive and not self.is_virtual: + return factory.is_bound(self, self.doc) # type: ignore + return False + + @property + def has_source_block_reference(self) -> bool: + """Is ``True`` if this virtual entity was created by a block reference.""" + return hasattr(self, DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE) + + @property + def source_block_reference(self) -> Optional[Insert]: + """The source block reference (INSERT) which created + this virtual entity. The property is ``None`` if this entity was not + created by a block reference. + """ + blockref = getattr(self, DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE, None) + if blockref is not None and blockref.is_alive: + return blockref + return None + + def set_source_block_reference(self, blockref: Insert) -> None: + """Set the immediate source block reference which created this virtual + entity. + + The source block reference can only be set once by the immediate INSERT + entity and does not change if the entity is passed through multiple + nested INSERT entities. + + (Internal API) + """ + assert self.is_virtual, "instance has to be a virtual entity" + if self.has_source_block_reference: + return + setattr(self, DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE, blockref) + + def del_source_block_reference(self) -> None: + """Delete source block reference. + + (Internal API) + """ + if hasattr(self, DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE): + delattr(self, DYN_SOURCE_BLOCK_REFERENCE_ATTRIBUTE) + + def get_dxf_attrib(self, key: str, default: Any = None) -> Any: + """Get DXF attribute `key`, returns `default` if key doesn't exist, or + raise :class:`DXFValueError` if `default` is :class:`DXFValueError` + and no DXF default value is defined:: + + layer = entity.get_dxf_attrib("layer") + # same as + layer = entity.dxf.layer + + Raises :class:`DXFAttributeError` if `key` is not an supported DXF + attribute. + + """ + return self.dxf.get(key, default) + + def set_dxf_attrib(self, key: str, value: Any) -> None: + """Set new `value` for DXF attribute `key`:: + + entity.set_dxf_attrib("layer", "MyLayer") + # same as + entity.dxf.layer = "MyLayer" + + Raises :class:`DXFAttributeError` if `key` is not an supported DXF + attribute. + + """ + self.dxf.set(key, value) + + def del_dxf_attrib(self, key: str) -> None: + """Delete DXF attribute `key`, does not raise an error if attribute is + supported but not present. + + Raises :class:`DXFAttributeError` if `key` is not an supported DXF + attribute. + + """ + self.dxf.discard(key) + + def has_dxf_attrib(self, key: str) -> bool: + """Returns ``True`` if DXF attribute `key` really exist. + + Raises :class:`DXFAttributeError` if `key` is not an supported DXF + attribute. + + """ + return self.dxf.hasattr(key) + + dxf_attrib_exists = has_dxf_attrib + + def is_supported_dxf_attrib(self, key: str) -> bool: + """Returns ``True`` if DXF attrib `key` is supported by this entity. + Does not grant that attribute `key` really exist. + + """ + if key in self.DXFATTRIBS: + if self.doc: + return ( + self.doc.dxfversion + >= self.DXFATTRIBS.get(key).dxfversion # type: ignore + ) + else: + return True + else: + return False + + def dxftype(self) -> str: + """Get DXF type as string, like ``LINE`` for the line entity.""" + return self.DXFTYPE + + def __str__(self) -> str: + """Returns a simple string representation.""" + return "{}(#{})".format(self.dxftype(), self.dxf.handle) + + def __repr__(self) -> str: + """Returns a simple string representation including the class.""" + return str(self.__class__) + " " + str(self) + + def dxfattribs(self, drop: Optional[set[str]] = None) -> dict: + """Returns a ``dict`` with all existing DXF attributes and their + values and exclude all DXF attributes listed in set `drop`. + + """ + all_attribs = self.dxf.all_existing_dxf_attribs() + if drop: + return {k: v for k, v in all_attribs.items() if k not in drop} + else: + return all_attribs + + def set_flag_state( + self, flag: int, state: bool = True, name: str = "flags" + ) -> None: + """Set binary coded `flag` of DXF attribute `name` to 1 (on) + if `state` is ``True``, set `flag` to 0 (off) + if `state` is ``False``. + """ + flags = self.dxf.get(name, 0) + self.dxf.set(name, set_flag_state(flags, flag, state=state)) + + def get_flag_state(self, flag: int, name: str = "flags") -> bool: + """Returns ``True`` if any `flag` of DXF attribute is 1 (on), else + ``False``. Always check only one flag state at the time. + """ + return bool(self.dxf.get(name, 0) & flag) + + def remove_dependencies(self, other: Optional[Drawing] = None): + """Remove all dependencies from current document. + + Intended usage is to remove dependencies from the current document to + move or copy the entity to `other` DXF document. + + An error free call of this method does NOT guarantee that this entity + can be moved/copied to the `other` document, some entities like + DIMENSION have too many dependencies to a document to move or copy + them, but to check this is not the domain of this method! + + (internal API) + """ + if self.is_alive: + self.dxf.owner = None + self.dxf.handle = None + self.reactors = None + self.extension_dict = None + self.appdata = None + self.xdata = None + # remove dynamic attributes if exist: + self.del_source_of_copy() + self.del_source_block_reference() + + def destroy(self) -> None: + """Delete all data and references. Does not delete entity from + structures like layouts or groups. + + (internal API) + """ + if not self.is_alive: + return + + if self.extension_dict is not None: + self.extension_dict.destroy() + del self.extension_dict + del self.appdata + del self.reactors + del self.xdata + del self.doc + del self.dxf # check mark for is_alive + # Remove dynamic attributes, which reference other entities: + self.del_source_of_copy() + self.del_source_block_reference() + + def _silent_kill(self): # final - do not override this method! + """Delete entity but not the referenced content! + + DANGER! DON'T USE THIS METHOD! + + (internal API) + """ + if not self.is_alive: + return + del self.extension_dict + del self.appdata + del self.reactors + del self.xdata + del self.doc + del self.dxf # check mark for is_alive + + def notify(self, message_type: int, data: Any = None) -> None: + """Internal messaging system. (internal API)""" + pass + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + """Pre requirement check and pre-processing for export. + + Returns ``False`` if entity should not be exported at all. + + (internal API) + """ + return True + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF entity by `tagwriter`. + + This is the first key method for exporting DXF entities: + + - has to know the group codes for each attribute + - has to add subclass tags in correct order + - has to integrate extended data: ExtensionDict, Reactors, AppData + - has to maintain the correct tag order (because sometimes order matters) + + (internal API) + + """ + if tagwriter.dxfversion < self.MIN_DXF_VERSION_FOR_EXPORT: + return + if not self.preprocess_export(tagwriter): + return + # write handle, AppData, Reactors, ExtensionDict, owner + self.export_base_class(tagwriter) + + # this is the entity specific part + self.export_entity(tagwriter) + + # write xdata at the end of the entity + self.export_xdata(tagwriter) + + def export_base_class(self, tagwriter: AbstractTagWriter) -> None: + """Export base class DXF attributes and structures. (internal API)""" + dxftype = self.DXFTYPE + _handle_code = 105 if dxftype == "DIMSTYLE" else 5 + # 1. tag: (0, DXFTYPE) + tagwriter.write_tag2(const.STRUCTURE_MARKER, dxftype) + + if tagwriter.dxfversion >= const.DXF2000: + tagwriter.write_tag2(_handle_code, self.dxf.handle) + if self.appdata: + self.appdata.export_dxf(tagwriter) + if self.has_extension_dict: + self.extension_dict.export_dxf(tagwriter) # type: ignore + if self.reactors: + self.reactors.export_dxf(tagwriter) + tagwriter.write_tag2(const.OWNER_CODE, self.dxf.owner) + else: # DXF R12 + if tagwriter.write_handles: + tagwriter.write_tag2(_handle_code, self.dxf.handle) + # do not write owner handle - not supported by DXF R12 + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF entity specific data by `tagwriter`. + + This is the second key method for exporting DXF entities: + + - has to know the group codes for each attribute + - has to add subclass tags in correct order + - has to maintain the correct tag order (because sometimes order matters) + + (internal API) + """ + # base class (handle, appid, reactors, xdict, owner) export is done by parent class + pass + # xdata and embedded objects export is also done by parent + + def export_xdata(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF XDATA by `tagwriter`. (internal API)""" + if self.xdata: + self.xdata.export_dxf(tagwriter) + + def audit(self, auditor: Auditor) -> None: + """Validity check. (internal API)""" + # Important: do not check owner handle! -> DXFGraphic(), DXFObject() + # check app data + # check reactors + # check extension dict + # check XDATA + + @property + def has_extension_dict(self) -> bool: + """Returns ``True`` if entity has an attached + :class:`~ezdxf.entities.xdict.ExtensionDict` instance. + """ + xdict = self.extension_dict + # Don't use None check: bool(xdict) for an empty extension dict is False + if xdict is not None and xdict.is_alive: + return xdict.dictionary.is_alive + return False + + def get_extension_dict(self) -> ExtensionDict: + """Returns the existing :class:`~ezdxf.entities.xdict.ExtensionDict` + instance. + + Raises: + AttributeError: extension dict does not exist + + """ + if self.has_extension_dict: + return self.extension_dict # type: ignore + else: + raise AttributeError("Entity has no extension dictionary.") + + def new_extension_dict(self) -> ExtensionDict: + """Create a new :class:`~ezdxf.entities.xdict.ExtensionDict` instance.""" + assert self.doc is not None + xdict = ExtensionDict.new(self.dxf.handle, self.doc) + self.extension_dict = xdict + return xdict + + def discard_extension_dict(self) -> None: + """Delete :class:`~ezdxf.entities.xdict.ExtensionDict` instance.""" + if isinstance(self.extension_dict, ExtensionDict): + self.extension_dict.destroy() + self.extension_dict = None + + def discard_empty_extension_dict(self) -> None: + """Delete :class:`~ezdxf.entities.xdict.ExtensionDict` instance when empty.""" + if ( + isinstance(self.extension_dict, ExtensionDict) + and len(self.extension_dict) == 0 + ): + self.discard_extension_dict() + + def has_app_data(self, appid: str) -> bool: + """Returns ``True`` if application defined data for `appid` exist.""" + if self.appdata: + return appid in self.appdata + else: + return False + + def get_app_data(self, appid: str) -> Tags: + """Returns application defined data for `appid`. + + Args: + appid: application name as defined in the APPID table. + + Raises: + DXFValueError: no data for `appid` found + + """ + if self.appdata: + return Tags(self.appdata.get(appid)[1:-1]) + else: + raise const.DXFValueError(appid) + + def set_app_data(self, appid: str, tags: Iterable) -> None: + """Set application defined data for `appid` as iterable of tags. + + Args: + appid: application name as defined in the APPID table. + tags: iterable of (code, value) tuples or :class:`~ezdxf.lldxf.types.DXFTag` + + """ + if self.appdata is None: + self.appdata = AppData() + self.appdata.add(appid, tags) + + def discard_app_data(self, appid: str): + """Discard application defined data for `appid`. Does not raise an + exception if no data for `appid` exist. + """ + if self.appdata: + self.appdata.discard(appid) + + def has_xdata(self, appid: str) -> bool: + """Returns ``True`` if extended data for `appid` exist.""" + if self.xdata: + return appid in self.xdata + else: + return False + + def get_xdata(self, appid: str) -> Tags: + """Returns extended data for `appid`. + + Args: + appid: application name as defined in the APPID table. + + Raises: + DXFValueError: no extended data for `appid` found + + """ + if self.xdata: + return Tags(self.xdata.get(appid)[1:]) + else: + raise const.DXFValueError(appid) + + def set_xdata(self, appid: str, tags: Iterable) -> None: + """Set extended data for `appid` as iterable of tags. + + Args: + appid: application name as defined in the APPID table. + tags: iterable of (code, value) tuples or :class:`~ezdxf.lldxf.types.DXFTag` + + """ + if self.xdata is None: + self.xdata = XData() + self.xdata.add(appid, tags) + + def discard_xdata(self, appid: str) -> None: + """Discard extended data for `appid`. Does not raise an exception if + no extended data for `appid` exist. + """ + if self.xdata: + self.xdata.discard(appid) + + def has_xdata_list(self, appid: str, name: str) -> bool: + """Returns ``True`` if a tag list `name` for extended data `appid` + exist. + """ + if self.has_xdata(appid): + return self.xdata.has_xlist(appid, name) # type: ignore + else: + return False + + def get_xdata_list(self, appid: str, name: str) -> Tags: + """Returns tag list `name` for extended data `appid`. + + Args: + appid: application name as defined in the APPID table. + name: extended data list name + + Raises: + DXFValueError: no extended data for `appid` found or no data list `name` not found + + """ + if self.xdata: + return Tags(self.xdata.get_xlist(appid, name)) + else: + raise const.DXFValueError(appid) + + def set_xdata_list(self, appid: str, name: str, tags: Iterable) -> None: + """Set tag list `name` for extended data `appid` as iterable of tags. + + Args: + appid: application name as defined in the APPID table. + name: extended data list name + tags: iterable of (code, value) tuples or :class:`~ezdxf.lldxf.types.DXFTag` + + """ + if self.xdata is None: + self.xdata = XData() + self.xdata.set_xlist(appid, name, tags) + + def discard_xdata_list(self, appid: str, name: str) -> None: + """Discard tag list `name` for extended data `appid`. Does not raise + an exception if no extended data for `appid` or no tag list `name` + exist. + """ + if self.xdata: + self.xdata.discard_xlist(appid, name) + + def replace_xdata_list(self, appid: str, name: str, tags: Iterable) -> None: + """ + Replaces tag list `name` for existing extended data `appid` by `tags`. + Appends new list if tag list `name` do not exist, but raises + :class:`DXFValueError` if extended data `appid` do not exist. + + Args: + appid: application name as defined in the APPID table. + name: extended data list name + tags: iterable of (code, value) tuples or :class:`~ezdxf.lldxf.types.DXFTag` + + Raises: + DXFValueError: no extended data for `appid` found + + """ + assert self.xdata is not None + self.xdata.replace_xlist(appid, name, tags) + + def has_reactors(self) -> bool: + """Returns ``True`` if entity has reactors.""" + return bool(self.reactors) + + def get_reactors(self) -> list[str]: + """Returns associated reactors as list of handles.""" + return self.reactors.get() if self.reactors else [] + + def set_reactors(self, handles: Iterable[str]) -> None: + """Set reactors as list of handles.""" + if self.reactors is None: + self.reactors = Reactors() + self.reactors.set(handles) + + def append_reactor_handle(self, handle: str) -> None: + """Append `handle` to reactors.""" + if self.reactors is None: + self.reactors = Reactors() + self.reactors.add(handle) + + def discard_reactor_handle(self, handle: str) -> None: + """Discard `handle` from reactors. Does not raise an exception if + `handle` does not exist. + """ + if self.reactors: + self.reactors.discard(handle) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + if self.xdata: + for name in self.xdata.data.keys(): + registry.add_appid(name) + if self.appdata: # add hard owned entities + for tags in self.appdata.tags(): + for tag in tags.get_hard_owner_handles(): + registry.add_handle(tag.value) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + + def map_xdata_resources(): + for index, (code, value) in enumerate(tags): + if code == 1005: # map soft-pointer handles + tags[index] = DXFTag(code, mapping.get_handle(value)) + elif code == 1003: # map layer name + tags[index] = DXFTag(code, mapping.get_layer(value)) + + if clone.xdata: + for tags in clone.xdata.data.values(): + map_xdata_resources() + + if clone.appdata: + for tags in clone.appdata.tags(): + mapping.map_pointers(tags, new_owner_handle=clone.dxf.handle) + + if clone.extension_dict: + assert self.extension_dict is not None + self.extension_dict.dictionary.map_resources( + clone.extension_dict.dictionary, mapping + ) + # reactors are not copied automatically, clone.reactors is always None: + if self.reactors: + # reactors are soft-pointers (group code 330) + mapped_handles = [mapping.get_handle(h) for h in self.reactors.reactors] + mapped_handles = [h for h in mapped_handles if h != "0"] + if mapped_handles: + clone.set_reactors(mapped_handles) + + +@factory.set_default_class +class DXFTagStorage(DXFEntity): + """Just store all the tags as they are. (internal class)""" + + def __init__(self) -> None: + """Default constructor""" + super().__init__() + self.xtags = ExtendedTags() + self.embedded_objects: Optional[list[Tags]] = None + + def copy(self, copy_strategy=default_copy) -> Self: + raise CopyNotSupported( + f"Copying of tag storage {self.dxftype()} not supported." + ) + + def transform(self, m: Matrix44) -> Self: + raise NotImplementedError("cannot transform DXF tag storage") + + @property + def base_class(self): + return self.xtags.subclasses[0] + + @property + def is_graphic_entity(self) -> bool: + """Returns ``True`` if the entity has a graphical representations and + can reside in the model space, a paper space or a block layout, + otherwise the entity is a table or class entry or a DXF object from the + OBJECTS section. + """ + return self.xtags.has_subclass("AcDbEntity") + + def graphic_properties(self) -> dict[str, Any]: + """Returns the graphical properties like layer, color, linetype, ... as + `dxfattribs` dict if the :class:`TagStorage` object represents a graphical + entity otherwise returns an empty dictionary. + + These are all the DXF attributes which are stored in the ``AcDbEntity`` + subclass. + + """ + from ezdxf.entities.dxfgfx import acdb_entity_group_codes + + attribs: dict[str, Any] = dict() + try: + tags = self.xtags.get_subclass("AcDbEntity") + except const.DXFKeyError: + return attribs + + for code, value in tags: + attrib_name = acdb_entity_group_codes.get(code) + if isinstance(attrib_name, str): + attribs[attrib_name] = value + return attribs + + @classmethod + def load(cls, tags: ExtendedTags, doc: Optional[Drawing] = None) -> DXFTagStorage: + assert isinstance(tags, ExtendedTags) + entity = cls.new(doc=doc) + dxfversion = doc.dxfversion if doc else None + entity.load_tags(tags, dxfversion=dxfversion) + entity.store_tags(tags) + entity.store_embedded_objects(tags) + if options.load_proxy_graphics: + entity.load_proxy_graphic() + return entity + + def load_proxy_graphic(self) -> None: + try: + tags = self.xtags.get_subclass("AcDbEntity") + except const.DXFKeyError: + return + binary_data = [tag.value for tag in tags.find_all(310)] + if len(binary_data): + self.proxy_graphic = b"".join(binary_data) + + def store_tags(self, tags: ExtendedTags) -> None: + # store DXFTYPE, overrides class member + # 1. tag of 1. subclass is the structure tag (0, DXFTYPE) + self.xtags = tags + self.DXFTYPE = self.base_class[0].value + try: + acdb_entity = tags.get_subclass("AcDbEntity") + self.dxf.__dict__["paperspace"] = acdb_entity.get_first_value(67, 0) + except const.DXFKeyError: + # just fake it + self.dxf.__dict__["paperspace"] = 0 + + def store_embedded_objects(self, tags: ExtendedTags) -> None: + self.embedded_objects = tags.embedded_objects + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Write subclass tags as they are.""" + for subclass in self.xtags.subclasses[1:]: + tagwriter.write_tags(subclass) + + if self.embedded_objects: + for tags in self.embedded_objects: + tagwriter.write_tags(tags) + + def destroy(self) -> None: + if not self.is_alive: + return + + del self.xtags + super().destroy() + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + from ezdxf.proxygraphic import ProxyGraphic + + if self.proxy_graphic: + for e in ProxyGraphic(self.proxy_graphic, self.doc).virtual_entities(): + e.set_source_of_copy(self) + yield e + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields proxy graphic as "virtual" entities.""" + return self.__virtual_entities__() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgfx.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgfx.py new file mode 100644 index 0000000..bba8878 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgfx.py @@ -0,0 +1,728 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Iterable, Any +from typing_extensions import Self, TypeGuard + +from ezdxf.entities import factory +from ezdxf import options +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf import colors as clr +from ezdxf.lldxf import const +from ezdxf.lldxf.const import ( + DXF12, + DXF2000, + DXF2004, + DXF2007, + DXF2013, + SUBCLASS_MARKER, + TRANSPARENCY_BYBLOCK, +) +from ezdxf.math import OCS, Matrix44, UVec +from ezdxf.proxygraphic import load_proxy_graphic, export_proxy_graphic +from .dxfentity import DXFEntity, base_class, SubclassProcessor, DXFTagStorage + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace + from ezdxf.layouts import BaseLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = [ + "DXFGraphic", + "acdb_entity", + "acdb_entity_group_codes", + "SeqEnd", + "add_entity", + "replace_entity", + "elevation_to_z_axis", + "is_graphic_entity", + "get_font_name", +] + +GRAPHIC_PROPERTIES = { + "layer", + "linetype", + "color", + "lineweight", + "ltscale", + "true_color", + "color_name", + "transparency", +} + +acdb_entity: DefSubclass = DefSubclass( + "AcDbEntity", + { + # Layer name as string, no auto fix for invalid names! + "layer": DXFAttr(8, default="0", validator=validator.is_valid_layer_name), + # Linetype name as string, no auto fix for invalid names! + "linetype": DXFAttr( + 6, + default="BYLAYER", + optional=True, + validator=validator.is_valid_table_name, + ), + # ACI color index, BYBLOCK=0, BYLAYER=256, BYOBJECT=257: + "color": DXFAttr( + 62, + default=256, + optional=True, + validator=validator.is_valid_aci_color, + fixer=RETURN_DEFAULT, + ), + # modelspace=0, paperspace=1 + "paperspace": DXFAttr( + 67, + default=0, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Lineweight in mm times 100 (e.g. 0.13mm = 13). Smallest line weight is 13 + # and biggest line weight is 200, values outside this range prevents AutoCAD + # from loading the file. + # Special values: BYLAYER=-1, BYBLOCK=-2, DEFAULT=-3 + "lineweight": DXFAttr( + 370, + default=-1, + dxfversion=DXF2000, + optional=True, + validator=validator.is_valid_lineweight, + fixer=validator.fix_lineweight, + ), + "ltscale": DXFAttr( + 48, + default=1.0, + dxfversion=DXF2000, + optional=True, + validator=validator.is_positive, + fixer=RETURN_DEFAULT, + ), + # visible=0, invisible=1 + "invisible": DXFAttr(60, default=0, dxfversion=DXF2000, optional=True), + # True color as 0x00RRGGBB 24-bit value + # True color always overrides ACI "color"! + "true_color": DXFAttr(420, dxfversion=DXF2004, optional=True), + # Color name as string. Color books are stored in .stb config files? + "color_name": DXFAttr(430, dxfversion=DXF2004, optional=True), + # Transparency value 0x020000TT 0 = fully transparent / 255 = opaque + # Special value 0x01000000 == ByBlock + # unset value means ByLayer + "transparency": DXFAttr( + 440, + dxfversion=DXF2004, + optional=True, + validator=validator.is_transparency, + ), + # Shadow mode: + # 0 = Casts and receives shadows + # 1 = Casts shadows + # 2 = Receives shadows + # 3 = Ignores shadows + "shadow_mode": DXFAttr(284, dxfversion=DXF2007, optional=True), + "material_handle": DXFAttr(347, dxfversion=DXF2007, optional=True), + "visualstyle_handle": DXFAttr(348, dxfversion=DXF2007, optional=True), + # PlotStyleName type enum (AcDb::PlotStyleNameType). Stored and moved around + # as a 16-bit integer. Custom non-entity + "plotstyle_enum": DXFAttr(380, dxfversion=DXF2007, default=1, optional=True), + # Handle value of the PlotStyleName object, basically a hard pointer, but + # has a different range to make backward compatibility easier to deal with. + "plotstyle_handle": DXFAttr(390, dxfversion=DXF2007, optional=True), + # 92 or 160?: Number of bytes in the proxy entity graphics represented in + # the subsequent 310 groups, which are binary chunk records (optional) + # 310: Proxy entity graphics data (multiple lines; 256 characters max. per + # line) (optional), compiled by TagCompiler() to a DXFBinaryTag() objects + }, +) +acdb_entity_group_codes = group_code_mapping(acdb_entity) + + +def elevation_to_z_axis(dxf: DXFNamespace, names: Iterable[str]): + # The elevation group code (38) is only used for DXF R11 and prior and + # ignored for DXF R2000 and later. + # DXF R12 and later store the entity elevation in the z-axis of the + # vertices, but AutoCAD supports elevation for R12 if no z-axis is present. + # DXF types with legacy elevation support: + # SOLID, TRACE, TEXT, CIRCLE, ARC, TEXT, ATTRIB, ATTDEF, INSERT, SHAPE + + # The elevation is only used for DXF R12 if no z-axis is stored in the DXF + # file. This is a problem because ezdxf loads the vertices always as 3D + # vertex including a z-axis even if no z-axis is present in DXF file. + if dxf.hasattr("elevation"): + elevation = dxf.elevation + # ezdxf does not export the elevation attribute for any DXF version + dxf.discard("elevation") + if elevation == 0: + return + + for name in names: + v = dxf.get(name) + # Only use elevation value if z-axis is 0, this will not work for + # situations where an elevation and a z-axis=0 is present, but let's + # assume if the elevation group code is used the z-axis is not + # present if z-axis is 0. + if v is not None and v.z == 0: + dxf.set(name, v.replace(z=elevation)) + + +class DXFGraphic(DXFEntity): + """Common base class for all graphic entities, a subclass of + :class:`~ezdxf.entities.dxfentity.DXFEntity`. These entities resides in + entity spaces like modelspace, paperspace or block. + """ + + DXFTYPE = "DXFGFX" + DEFAULT_ATTRIBS: dict[str, Any] = {"layer": "0"} + DXFATTRIBS = DXFAttributes(base_class, acdb_entity) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Adds subclass processing for 'AcDbEntity', requires previous base + class processing by parent class. + + (internal API) + """ + # subclasses using simple_dxfattribs_loader() bypass this method!!! + dxf = super().load_dxf_attribs(processor) + if processor is None: + return dxf + r12 = processor.r12 + # It is valid to mix up the base class with AcDbEntity class. + processor.append_base_class_to_acdb_entity() + + # Load proxy graphic data if requested + if options.load_proxy_graphics: + # length tag has group code 92 until DXF R2010 + if processor.dxfversion and processor.dxfversion < DXF2013: + code = 92 + else: + code = 160 + self.proxy_graphic = load_proxy_graphic( + processor.subclasses[0 if r12 else 1], + length_code=code, + ) + processor.fast_load_dxfattribs(dxf, acdb_entity_group_codes, 1) + return dxf + + def post_new_hook(self) -> None: + """Post-processing and integrity validation after entity creation. + + (internal API) + """ + if self.doc: + if self.dxf.linetype not in self.doc.linetypes: + raise const.DXFInvalidLineType( + f'Linetype "{self.dxf.linetype}" not defined.' + ) + + @property + def rgb(self) -> tuple[int, int, int] | None: + """Returns RGB true color as (r, g, b) tuple or None if true_color is not set.""" + if self.dxf.hasattr("true_color"): + return clr.int2rgb(self.dxf.get("true_color")) + return None + + @rgb.setter + def rgb(self, rgb: clr.RGB | tuple[int, int, int]) -> None: + """Set RGB true color as (r, g , b) tuple e.g. (12, 34, 56). + + Raises: + TypeError: input value `rgb` has invalid type + """ + self.dxf.set("true_color", clr.rgb2int(rgb)) + + @rgb.deleter + def rgb(self) -> None: + """Delete RGB true color value.""" + self.dxf.discard("true_color") + + @property + def transparency(self) -> float: + """Get transparency as float value between 0 and 1, 0 is opaque and 1 + is 100% transparent (invisible). Transparency by block returns always 0. + """ + if self.dxf.hasattr("transparency"): + value = self.dxf.get("transparency") + if validator.is_transparency(value): + if value & TRANSPARENCY_BYBLOCK: # just check flag state + return 0.0 + return clr.transparency2float(value) + return 0.0 + + @transparency.setter + def transparency(self, transparency: float) -> None: + """Set transparency as float value between 0 and 1, 0 is opaque and 1 + is 100% transparent (invisible). + """ + self.dxf.set("transparency", clr.float2transparency(transparency)) + + @property + def is_transparency_by_layer(self) -> bool: + """Returns ``True`` if entity inherits transparency from layer.""" + return not self.dxf.hasattr("transparency") + + @property + def is_transparency_by_block(self) -> bool: + """Returns ``True`` if entity inherits transparency from block.""" + return self.dxf.get("transparency", 0) == TRANSPARENCY_BYBLOCK + + def graphic_properties(self) -> dict: + """Returns the important common properties layer, color, linetype, + lineweight, ltscale, true_color and color_name as `dxfattribs` dict. + """ + attribs = dict() + for key in GRAPHIC_PROPERTIES: + if self.dxf.hasattr(key): + attribs[key] = self.dxf.get(key) + return attribs + + def ocs(self) -> OCS: + """Returns object coordinate system (:ref:`ocs`) for 2D entities like + :class:`Text` or :class:`Circle`, returns a pass-through OCS for + entities without OCS support. + """ + # extrusion is only defined for 2D entities like Text, Circle, ... + if self.dxf.is_supported("extrusion"): + extrusion = self.dxf.get("extrusion", default=(0, 0, 1)) + return OCS(extrusion) + else: + return OCS() + + def set_owner(self, owner: Optional[str], paperspace: int = 0) -> None: + """Set owner attribute and paperspace flag. (internal API)""" + self.dxf.owner = owner + if paperspace: + self.dxf.paperspace = paperspace + else: + self.dxf.discard("paperspace") + + def link_entity(self, entity: DXFEntity) -> None: + """Store linked or attached entities. Same API for both types of + appended data, because entities with linked entities (POLYLINE, INSERT) + have no attached entities and vice versa. + + (internal API) + """ + pass + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + # Base class export is done by parent class. + self.export_acdb_entity(tagwriter) + # XDATA and embedded objects export is also done by the parent class. + + def export_acdb_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export subclass 'AcDbEntity' as DXF tags. (internal API)""" + # Full control over tag order and YES, sometimes order matters + not_r12 = tagwriter.dxfversion > DXF12 + if not_r12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_entity.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "paperspace", + "layer", + "linetype", + "material_handle", + "color", + "lineweight", + "ltscale", + "invisible", + "true_color", + "color_name", + "transparency", + "plotstyle_enum", + "plotstyle_handle", + "shadow_mode", + "visualstyle_handle", + ], + ) + + if self.proxy_graphic and not_r12 and options.store_proxy_graphics: + # length tag has group code 92 until DXF R2010 + export_proxy_graphic( + self.proxy_graphic, + tagwriter=tagwriter, + length_code=(92 if tagwriter.dxfversion < DXF2013 else 160), + ) + + def get_layout(self) -> Optional[BaseLayout]: + """Returns the owner layout or returns ``None`` if entity is not + assigned to any layout. + """ + if self.dxf.owner is None or self.doc is None: # unlinked entity + return None + try: + return self.doc.layouts.get_layout_by_key(self.dxf.owner) + except const.DXFKeyError: + pass + try: + return self.doc.blocks.get_block_layout_by_handle(self.dxf.owner) + except const.DXFTableEntryError: + return None + + def unlink_from_layout(self) -> None: + """ + Unlink entity from associated layout. Does nothing if entity is already + unlinked. + + It is more efficient to call the + :meth:`~ezdxf.layouts.BaseLayout.unlink_entity` method of the associated + layout, especially if you have to unlink more than one entity. + """ + if not self.is_alive: + raise TypeError("Can not unlink destroyed entity.") + + if self.doc is None: + # no doc -> no layout + self.dxf.owner = None + return + + layout = self.get_layout() + if layout: + layout.unlink_entity(self) + + def move_to_layout( + self, layout: BaseLayout, source: Optional[BaseLayout] = None + ) -> None: + """ + Move entity from model space or a paper space layout to another layout. + For block layout as source, the block layout has to be specified. Moving + between different DXF drawings is not supported. + + Args: + layout: any layout (model space, paper space, block) + source: provide source layout, faster for DXF R12, if entity is + in a block layout + + Raises: + DXFStructureError: for moving between different DXF drawings + """ + if source is None: + source = self.get_layout() + if source is None: + raise const.DXFValueError("Source layout for entity not found.") + source.move_to_layout(self, layout) + + def copy_to_layout(self, layout: BaseLayout) -> Self: + """ + Copy entity to another `layout`, returns new created entity as + :class:`DXFEntity` object. Copying between different DXF drawings is + not supported. + + Args: + layout: any layout (model space, paper space, block) + + Raises: + DXFStructureError: for copying between different DXF drawings + """ + if self.doc != layout.doc: + raise const.DXFStructureError( + "Copying between different DXF drawings is not supported." + ) + + new_entity = self.copy() + layout.add_entity(new_entity) + return new_entity + + def audit(self, auditor: Auditor) -> None: + """Audit and repair graphical DXF entities. + + .. important:: + + Do not delete entities while auditing process, because this + would alter the entity database while iterating, instead use:: + + auditor.trash(entity) + + to delete invalid entities after auditing automatically. + """ + assert self.doc is auditor.doc, "Auditor for different DXF document." + if not self.is_alive: + return + + super().audit(auditor) + auditor.check_owner_exist(self) + dxf = self.dxf + if dxf.hasattr("layer"): + auditor.check_for_valid_layer_name(self) + if dxf.hasattr("linetype"): + auditor.check_entity_linetype(self) + if dxf.hasattr("color"): + auditor.check_entity_color_index(self) + if dxf.hasattr("lineweight"): + auditor.check_entity_lineweight(self) + if dxf.hasattr("extrusion"): + auditor.check_extrusion_vector(self) + if dxf.hasattr("transparency"): + auditor.check_transparency(self) + + def transform(self, m: Matrix44) -> Self: + """Inplace transformation interface, returns `self` (floating interface). + + Args: + m: 4x4 transformation matrix (:class:`ezdxf.math.Matrix44`) + """ + raise NotImplementedError() + + def post_transform(self, m: Matrix44) -> None: + """Should be called if the main entity transformation was successful.""" + if self.xdata is not None: + self.xdata.transform(m) + + @property + def is_post_transform_required(self) -> bool: + """Check if post transform call is required.""" + return self.xdata is not None + + def translate(self, dx: float, dy: float, dz: float) -> Self: + """Translate entity inplace about `dx` in x-axis, `dy` in y-axis and + `dz` in z-axis, returns `self` (floating interface). + + Basic implementation uses the :meth:`transform` interface, subclasses + may have faster implementations. + """ + return self.transform(Matrix44.translate(dx, dy, dz)) + + def scale(self, sx: float, sy: float, sz: float) -> Self: + """Scale entity inplace about `dx` in x-axis, `dy` in y-axis and `dz` + in z-axis, returns `self` (floating interface). + """ + return self.transform(Matrix44.scale(sx, sy, sz)) + + def scale_uniform(self, s: float) -> Self: + """Scale entity inplace uniform about `s` in x-axis, y-axis and z-axis, + returns `self` (floating interface). + """ + return self.transform(Matrix44.scale(s)) + + def rotate_axis(self, axis: UVec, angle: float) -> Self: + """Rotate entity inplace about vector `axis`, returns `self` + (floating interface). + + Args: + axis: rotation axis as tuple or :class:`Vec3` + angle: rotation angle in radians + """ + return self.transform(Matrix44.axis_rotate(axis, angle)) + + def rotate_x(self, angle: float) -> Self: + """Rotate entity inplace about x-axis, returns `self` + (floating interface). + + Args: + angle: rotation angle in radians + """ + return self.transform(Matrix44.x_rotate(angle)) + + def rotate_y(self, angle: float) -> Self: + """Rotate entity inplace about y-axis, returns `self` + (floating interface). + + Args: + angle: rotation angle in radians + """ + return self.transform(Matrix44.y_rotate(angle)) + + def rotate_z(self, angle: float) -> Self: + """Rotate entity inplace about z-axis, returns `self` + (floating interface). + + Args: + angle: rotation angle in radians + """ + return self.transform(Matrix44.z_rotate(angle)) + + def has_hyperlink(self) -> bool: + """Returns ``True`` if entity has an attached hyperlink.""" + return bool(self.xdata) and ("PE_URL" in self.xdata) # type: ignore + + def set_hyperlink( + self, + link: str, + description: Optional[str] = None, + location: Optional[str] = None, + ): + """Set hyperlink of an entity.""" + xdata = [(1001, "PE_URL"), (1000, str(link))] + if description: + xdata.append((1002, "{")) + xdata.append((1000, str(description))) + if location: + xdata.append((1000, str(location))) + xdata.append((1002, "}")) + + self.discard_xdata("PE_URL") + self.set_xdata("PE_URL", xdata) + if self.doc and "PE_URL" not in self.doc.appids: + self.doc.appids.new("PE_URL") + return self + + def get_hyperlink(self) -> tuple[str, str, str]: + """Returns hyperlink, description and location.""" + link = "" + description = "" + location = "" + if self.xdata and "PE_URL" in self.xdata: + xdata = [tag.value for tag in self.get_xdata("PE_URL") if tag.code == 1000] + if len(xdata): + link = xdata[0] + if len(xdata) > 1: + description = xdata[1] + if len(xdata) > 2: + location = xdata[2] + return link, description, location + + def remove_dependencies(self, other: Optional[Drawing] = None) -> None: + """Remove all dependencies from current document. + + (internal API) + """ + if not self.is_alive: + return + + super().remove_dependencies(other) + # The layer attribute is preserved because layer doesn't need a layer + # table entry, the layer attributes are reset to default attributes + # like color is 7 and linetype is CONTINUOUS + has_linetype = other is not None and (self.dxf.linetype in other.linetypes) + if not has_linetype: + self.dxf.linetype = "BYLAYER" + self.dxf.discard("material_handle") + self.dxf.discard("visualstyle_handle") + self.dxf.discard("plotstyle_enum") + self.dxf.discard("plotstyle_handle") + + def _new_compound_entity(self, type_: str, dxfattribs) -> Self: + """Create and bind new entity with same layout settings as `self`. + + Used by INSERT & POLYLINE to create appended DXF entities, don't use it + to create new standalone entities. + + (internal API) + """ + dxfattribs = dxfattribs or {} + + # if layer is not deliberately set, set same layer as creator entity, + # at least VERTEX should have the same layer as the POLYGON entity. + # Don't know if that is also important for the ATTRIB & INSERT entity. + if "layer" not in dxfattribs: + dxfattribs["layer"] = self.dxf.layer + if self.doc: + entity = factory.create_db_entry(type_, dxfattribs, self.doc) + else: + entity = factory.new(type_, dxfattribs) + entity.dxf.owner = self.dxf.owner + entity.dxf.paperspace = self.dxf.paperspace + return entity # type: ignore + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + dxf = self.dxf + registry.add_layer(dxf.layer) + registry.add_linetype(dxf.linetype) + registry.add_handle(dxf.get("material_handle")) + # unsupported resource attributes: + # - visualstyle_handle + # - plotstyle_handle + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + super().map_resources(clone, mapping) + clone.dxf.layer = mapping.get_layer(self.dxf.layer) + attrib_exist = self.dxf.hasattr + if attrib_exist("linetype"): + clone.dxf.linetype = mapping.get_linetype(self.dxf.linetype) + if attrib_exist("material_handle"): + clone.dxf.material_handle = mapping.get_handle(self.dxf.material_handle) + + # unsupported attributes: + clone.dxf.discard("visualstyle_handle") + clone.dxf.discard("plotstyle_handle") + + +@factory.register_entity +class SeqEnd(DXFGraphic): + DXFTYPE = "SEQEND" + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_entity_group_codes) # type: ignore + return dxf + + +def add_entity(entity: DXFGraphic, layout: BaseLayout) -> None: + """Add `entity` entity to the entity database and to the given `layout`.""" + assert entity.dxf.handle is None + assert layout is not None + if layout.doc: + factory.bind(entity, layout.doc) + layout.add_entity(entity) + + +def replace_entity(source: DXFGraphic, target: DXFGraphic, layout: BaseLayout) -> None: + """Add `target` entity to the entity database and to the given `layout` + and replace the `source` entity by the `target` entity. + """ + assert target.dxf.handle is None + assert layout is not None + target.dxf.handle = source.dxf.handle + if source in layout: + layout.delete_entity(source) + if layout.doc: + factory.bind(target, layout.doc) + layout.add_entity(target) + else: + source.destroy() + + +def is_graphic_entity(entity: DXFEntity) -> TypeGuard[DXFGraphic]: + """Returns ``True`` if the `entity` has a graphical representations and + can reside in the model space, a paper space or a block layout, + otherwise the entity is a table or class entry or a DXF object from the + OBJECTS section. + """ + if isinstance(entity, DXFGraphic): + return True + if isinstance(entity, DXFTagStorage) and entity.is_graphic_entity: + return True + return False + + +def get_font_name(entity: DXFEntity) -> str: + """Returns the font name of any DXF entity. + + This function always returns a font name even if the entity doesn't support text + styles. The default font name is "txt". + """ + font_name = const.DEFAULT_TEXT_FONT + doc = entity.doc + if doc is None: + return font_name + try: + style_name = entity.dxf.get("style", const.DEFAULT_TEXT_STYLE) + except const.DXFAttributeError: + return font_name + try: + style = doc.styles.get(style_name) + return style.dxf.font + except const.DXFTableEntryError: + return font_name diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgroups.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgroups.py new file mode 100644 index 0000000..b8facbb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfgroups.py @@ -0,0 +1,455 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + cast, + Union, + Optional, +) +from contextlib import contextmanager +import logging +from ezdxf.lldxf import validator, const +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.audit import AuditError +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .dxfobj import DXFObject +from .factory import register_entity +from .objectcollection import ObjectCollection +from .copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, Dictionary + from ezdxf.entitydb import EntityDB + from ezdxf.layouts import Layouts + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["DXFGroup", "GroupCollection"] +logger = logging.getLogger("ezdxf") + +acdb_group = DefSubclass( + "AcDbGroup", + { + # Group description + "description": DXFAttr(300, default=""), + # 1 = Unnamed + # 0 = Named + "unnamed": DXFAttr( + 70, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 1 = Selectable + # 0 = Not selectable + "selectable": DXFAttr( + 71, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 340: Hard-pointer handle to entity in group (one entry per object) + }, +) +acdb_group_group_codes = group_code_mapping(acdb_group) +GROUP_ITEM_CODE = 340 + + +@register_entity +class DXFGroup(DXFObject): + """Groups are not allowed in block definitions, and each entity can only + reside in one group, so cloning of groups creates also new entities. + + """ + + DXFTYPE = "GROUP" + DXFATTRIBS = DXFAttributes(base_class, acdb_group) + + def __init__(self) -> None: + super().__init__() + self._handles: set[str] = set() # only needed at the loading stage + self._data: list[DXFEntity] = [] + + def copy(self, copy_strategy=default_copy): + raise CopyNotSupported("Copying of GROUP not supported.") + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_group_group_codes, 1, log=False + ) + self.load_group(tags) + return dxf + + def load_group(self, tags): + for code, value in tags: + if code == GROUP_ITEM_CODE: + # First store handles, because at this point, objects + # are not stored in the EntityDB: + self._handles.add(value) + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + # remove invalid entities + assert self.doc is not None + self.purge(self.doc) + # export GROUP only if all entities reside on the same layout + if not all_entities_on_same_layout(self._data): + raise const.DXFStructureError( + "All entities have to be in the same layout and are not allowed" + " to be in a block layout." + ) + return True + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_group.name) + self.dxf.export_dxf_attribs(tagwriter, ["description", "unnamed", "selectable"]) + self.export_group(tagwriter) + + def export_group(self, tagwriter: AbstractTagWriter): + for entity in self._data: + tagwriter.write_tag2(GROUP_ITEM_CODE, entity.dxf.handle) + + def __iter__(self) -> Iterator[DXFEntity]: + """Iterate over all DXF entities in :class:`DXFGroup` as instances of + :class:`DXFGraphic` or inherited (LINE, CIRCLE, ...). + + """ + return (e for e in self._data if e.is_alive) + + def __len__(self) -> int: + """Returns the count of DXF entities in :class:`DXFGroup`.""" + return len(self._data) + + def __getitem__(self, item): + """Returns entities by standard Python indexing and slicing.""" + return self._data[item] + + def __contains__(self, item: Union[str, DXFEntity]) -> bool: + """Returns ``True`` if item is in :class:`DXFGroup`. `item` has to be + a handle string or an object of type :class:`DXFEntity` or inherited. + + """ + handle = item if isinstance(item, str) else item.dxf.handle + return handle in set(self.handles()) + + def handles(self) -> Iterable[str]: + """Iterable of handles of all DXF entities in :class:`DXFGroup`.""" + return (entity.dxf.handle for entity in self) + + def post_load_hook(self, doc: "Drawing"): + super().post_load_hook(doc) + db_get = doc.entitydb.get + + def set_group_entities(): # post init command + name = str(self) + entities = filter_invalid_entities(self._data, self.doc, name) + if not all_entities_on_same_layout(entities): + self.clear() + logger.debug(f"Cleared {name}, had entities from different layouts.") + else: + self._data = entities + + def entities(): + for handle in self._handles: + entity = db_get(handle) + if entity and entity.is_alive: + yield entity + + # Filtering invalid DXF entities is not possible at this stage, just + # store entities as they are: + self._data = list(entities()) + del self._handles # all referenced entities are stored in data + return set_group_entities + + @contextmanager # type: ignore + def edit_data(self) -> list[DXFEntity]: # type: ignore + """Context manager which yields all the group entities as + standard Python list:: + + with group.edit_data() as data: + # add new entities to a group + data.append(modelspace.add_line((0, 0), (3, 0))) + # remove last entity from a group + data.pop() + + """ + data = list(self) + yield data + self.set_data(data) + + def _validate_entities(self, entities: Iterable[DXFEntity]) -> list[DXFEntity]: + assert self.doc is not None + entities = list(entities) + valid_entities = filter_invalid_entities(entities, self.doc, str(self)) + if len(valid_entities) != len(entities): + raise const.DXFStructureError("invalid entities found") + if not all_entities_on_same_layout(valid_entities): + raise const.DXFStructureError( + "All entities have to be in the same layout and are not allowed" + " to be in a block layout." + ) + return valid_entities + + def set_data(self, entities: Iterable[DXFEntity]) -> None: + """Set `entities` as new group content, entities should be an iterable of + :class:`DXFGraphic` (LINE, CIRCLE, ...). + + Raises: + DXFValueError: not all entities are located on the same layout (modelspace + or any paperspace layout but not block) + + """ + valid_entities = self._validate_entities(entities) + self.clear() + self._add_group_reactor(valid_entities) + self._data = valid_entities + + def extend(self, entities: Iterable[DXFEntity]) -> None: + """Add `entities` to :class:`DXFGroup`, entities should be an iterable of + :class:`DXFGraphic` (LINE, CIRCLE, ...). + + Raises: + DXFValueError: not all entities are located on the same layout (modelspace + or any paperspace layout but not block) + + """ + valid_entities = self._validate_entities(entities) + handles = set(self.handles()) + valid_entities = [e for e in valid_entities if e.dxf.handle not in handles] + self._add_group_reactor(valid_entities) + self._data.extend(valid_entities) + + def clear(self) -> None: + """Remove all entities from :class:`DXFGroup`, does not delete any + drawing entities referenced by this group. + + """ + # TODO: remove handle of GROUP entity from reactors of entities #1085 + self._remove_group_reactor(self._data) + self._data = [] + + def _add_group_reactor(self, entities: list[DXFEntity]) -> None: + group_handle = self.dxf.handle + for entity in entities: + entity.append_reactor_handle(group_handle) + + def _remove_group_reactor(self, entities: list[DXFEntity]) -> None: + group_handle = self.dxf.handle + for entity in entities: + entity.discard_reactor_handle(group_handle) + + def audit(self, auditor: Auditor) -> None: + """Remove invalid entities from :class:`DXFGroup`. + + Invalid entities are: + + - deleted entities + - all entities which do not reside in model- or paper space + - all entities if they do not reside in the same layout + + """ + entity_count = len(self) + assert auditor.doc is not None + # Remove destroyed or invalid entities: + self.purge(auditor.doc) + removed_entity_count = entity_count - len(self) + if removed_entity_count > 0: + auditor.fixed_error( + code=AuditError.INVALID_GROUP_ENTITIES, + message=f"Removed {removed_entity_count} invalid entities from {str(self)}", + ) + if not all_entities_on_same_layout(self._data): + auditor.fixed_error( + code=AuditError.GROUP_ENTITIES_IN_DIFFERENT_LAYOUTS, + message=f"Cleared {str(self)}, not all entities are located in " + f"the same layout.", + ) + self.clear() + + group_handle = self.dxf.handle + if not group_handle: + return + for entity in self._data: + if entity.reactors is None or group_handle not in entity.reactors: + auditor.fixed_error( + code=AuditError.MISSING_PERSISTENT_REACTOR, + message=f"Entity {entity} in group #{group_handle} does not have " + f"group as persistent reactor", + ) + entity.append_reactor_handle(group_handle) + + def purge(self, doc: Drawing) -> None: + """Remove invalid group entities.""" + self._data = filter_invalid_entities( + entities=self._data, doc=doc, group_name=str(self) + ) + + +def filter_invalid_entities( + entities: Iterable[DXFEntity], + doc: Drawing, + group_name: str = "", +) -> list[DXFEntity]: + assert doc is not None + db = doc.entitydb + valid_owner_handles = valid_layout_handles(doc.layouts) + valid_entities: list[DXFEntity] = [] + for entity in entities: + if entity.is_alive and _has_valid_owner( + entity.dxf.owner, db, valid_owner_handles + ): + valid_entities.append(entity) + elif group_name: + if entity.is_alive: + logger.debug(f"{str(entity)} in {group_name} has an invalid owner.") + else: + logger.debug(f"Removed deleted entity in {group_name}") + return valid_entities + + +def _has_valid_owner(owner: str, db: EntityDB, valid_owner_handles: set[str]) -> bool: + # no owner -> no layout association + if owner is None: + return False + # The check for owner.dxf.layout != "0" is not sufficient #521 + if valid_owner_handles and owner not in valid_owner_handles: + return False + layout = db.get(owner) + # owner layout does not exist or is destroyed -> no layout association + if layout is None or not layout.is_alive: + return False + # If "valid_owner_handles" is not empty, entities located on BLOCK + # layouts are already removed. + # DXF attribute block_record.layout is "0" if entity is located in a + # block definition, which is invalid: + return layout.dxf.layout != "0" + + +def all_entities_on_same_layout(entities: Iterable[DXFEntity]): + """Check if all entities are on the same layout (model space or any paper + layout but not block). + + """ + owners = set(entity.dxf.owner for entity in entities) + # 0 for no entities; 1 for all entities on the same layout + return len(owners) < 2 + + +def valid_layout_handles(layouts: Layouts) -> set[str]: + """Returns valid layout keys for group entities.""" + return set(layout.layout_key for layout in layouts if layout.is_any_layout) + + +class GroupCollection(ObjectCollection[DXFGroup]): + def __init__(self, doc: Drawing): + super().__init__(doc, dict_name="ACAD_GROUP", object_type="GROUP") + self._next_unnamed_number = 0 + + def groups(self) -> Iterator[DXFGroup]: + """Iterable of all existing groups.""" + for name, group in self: + yield group + + def next_name(self) -> str: + name = self._next_name() + while name in self: + name = self._next_name() + return name + + def _next_name(self) -> str: + self._next_unnamed_number += 1 + return f"*A{self._next_unnamed_number}" + + def new( + self, + name: Optional[str] = None, + description: str = "", + selectable: bool = True, + ) -> DXFGroup: + r"""Creates a new group. If `name` is ``None`` an unnamed group is + created, which has an automatically generated name like "\*Annnn". + Group names are case-insensitive. + + Args: + name: group name as string + description: group description as string + selectable: group is selectable if ``True`` + + """ + if name is not None and name in self: + raise const.DXFValueError(f"GROUP '{name}' already exists.") + + if name is None: + name = self.next_name() + unnamed = 1 + else: + unnamed = 0 + # The group name isn't stored in the group entity itself. + dxfattribs = { + "description": description, + "unnamed": unnamed, + "selectable": int(bool(selectable)), + } + return cast(DXFGroup, self._new(name, dxfattribs)) + + def delete(self, group: Union[DXFGroup, str]) -> None: + """Delete `group`, `group` can be an object of type :class:`DXFGroup` + or a group name as string. + + """ + entitydb = self.doc.entitydb + assert entitydb is not None + # Delete group by name: + if isinstance(group, str): + name = group + elif group.dxftype() == "GROUP": + name = get_group_name(group, entitydb) + else: + raise TypeError(group.dxftype()) + + if name in self: + super().delete(name) + else: + raise const.DXFValueError("GROUP not in group table registered.") + + def audit(self, auditor: Auditor) -> None: + """Removes empty groups and invalid handles from all groups.""" + trash = [] + for name, group in self: + group = cast(DXFGroup, group) + group.audit(auditor) + if not len(group): # remove empty group + # do not delete groups while iterating over groups! + trash.append(name) + + # now delete empty groups + for name in trash: + auditor.fixed_error( + code=AuditError.REMOVE_EMPTY_GROUP, + message=f'Removed empty group "{name}".', + ) + self.delete(name) + + +def get_group_name(group: DXFGroup, db: EntityDB) -> str: + """Get name of `group`.""" + group_table = cast("Dictionary", db[group.dxf.owner]) + for name, entity in group_table.items(): + if entity is group: + return name + return "" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfns.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfns.py new file mode 100644 index 0000000..e22a84d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfns.py @@ -0,0 +1,648 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, Optional, Union, Iterable, TYPE_CHECKING, Set +import logging +import itertools +from ezdxf import options +from ezdxf.lldxf import const +from ezdxf.lldxf.attributes import XType, DXFAttributes, DXFAttr +from ezdxf.lldxf.types import cast_value, dxftag +from ezdxf.lldxf.tags import Tags + +if TYPE_CHECKING: + from ezdxf.lldxf.extendedtags import ExtendedTags + from ezdxf.entities import DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + + +__all__ = ["DXFNamespace", "SubclassProcessor"] +logger = logging.getLogger("ezdxf") + +ERR_INVALID_DXF_ATTRIB = 'Invalid DXF attribute "{}" for entity {}' +ERR_DXF_ATTRIB_NOT_EXITS = 'DXF attribute "{}" does not exist' + +# supported event handler called by setting DXF attributes +# for usage, implement a method named like the dict-value, that accepts the new +# value as argument e.g.: +# Polyline.on_layer_change(name) -> changes also layers of all vertices + +SETTER_EVENTS = { + "layer": "on_layer_change", + "linetype": "on_linetype_change", + "style": "on_style_change", + "dimstyle": "on_dimstyle_change", +} +EXCLUDE_FROM_UPDATE = frozenset(["_entity", "handle", "owner"]) + + +class DXFNamespace: + """:class:`DXFNamespace` manages all named DXF attributes of an entity. + + The DXFNamespace.__dict__ is used as DXF attribute storage, therefore only + valid Python names can be used as attrib name. + + The namespace can only contain immutable objects: string, int, float, bool, + Vec3. Because of the immutability, copy and deepcopy are the same. + + (internal class) + """ + + def __init__( + self, + processor: Optional[SubclassProcessor] = None, + entity: Optional[DXFEntity] = None, + ): + if processor: + base_class = processor.base_class + handle_code = 105 if base_class[0].value == "DIMSTYLE" else 5 + # CLASS entities have no handle. + # TABLE entities have no handle if loaded from a DXF R12 file. + # Owner tag is None if loaded from a DXF R12 file + handle = None + owner = None + for tag in base_class: + group_code = tag.code + if group_code == handle_code: + handle = tag.value + if owner: + break + elif group_code == 330: + owner = tag.value + if handle: + break + self.rewire(entity, handle, owner) + else: + self.reset_handles() + self.rewire(entity) + + def copy(self, entity: DXFEntity): + namespace = self.__class__() + for k, v in self.__dict__.items(): + namespace.__dict__[k] = v + namespace.rewire(entity) + return namespace + + def __deepcopy__(self, memodict: Optional[dict] = None): + return self.copy(self._entity) + + def reset_handles(self): + """Reset handle and owner to None.""" + self.__dict__["handle"] = None + self.__dict__["owner"] = None + + def rewire( + self, + entity: Optional[DXFEntity], + handle: Optional[str] = None, + owner: Optional[str] = None, + ) -> None: + """Rewire DXF namespace with parent entity + + Args: + entity: new associated entity + handle: new handle or None + owner: new entity owner handle or None + + """ + # bypass __setattr__() + self.__dict__["_entity"] = entity + if handle is not None: + self.__dict__["handle"] = handle + if owner is not None: + self.__dict__["owner"] = owner + + def __getattr__(self, key: str) -> Any: + """Called if DXF attribute `key` does not exist, returns the DXF + default value or ``None``. + + Raises: + DXFAttributeError: attribute `key` is not supported + + """ + attrib_def: Optional[DXFAttr] = self.dxfattribs.get(key) + if attrib_def: + if attrib_def.xtype == XType.callback: + return attrib_def.get_callback_value(self._entity) + else: + return attrib_def.default + else: + raise const.DXFAttributeError( + ERR_INVALID_DXF_ATTRIB.format(key, self.dxftype) + ) + + def __setattr__(self, key: str, value: Any) -> None: + """Set DXF attribute `key` to `value`. + + Raises: + DXFAttributeError: attribute `key` is not supported + + """ + + def entity() -> str: + # DXFNamespace is maybe not assigned to the entity yet: + handle = self.get("handle") + _entity = self._entity + if _entity: + return _entity.dxftype() + f"(#{handle})" + else: + return f"#{handle}" + + def check(value): + value = cast_value(attrib_def.code, value) + if not attrib_def.is_valid_value(value): + if attrib_def.fixer: + value = attrib_def.fixer(value) + logger.debug( + f'Fixed invalid attribute "{key}" in entity' + f' {entity()} to "{str(value)}".' + ) + else: + raise const.DXFValueError( + f'Invalid value {str(value)} for attribute "{key}" in ' + f"entity {entity()}." + ) + return value + + attrib_def: Optional[DXFAttr] = self.dxfattribs.get(key) + if attrib_def: + if attrib_def.xtype == XType.callback: + attrib_def.set_callback_value(self._entity, value) + else: + self.__dict__[key] = check(value) + else: + raise const.DXFAttributeError( + ERR_INVALID_DXF_ATTRIB.format(key, self.dxftype) + ) + + if key in SETTER_EVENTS: + handler = getattr(self._entity, SETTER_EVENTS[key], None) + if handler: + handler(value) + + def __delattr__(self, key: str) -> None: + """Delete DXF attribute `key`. + + Raises: + DXFAttributeError: attribute `key` does not exist + + """ + if self.hasattr(key): + del self.__dict__[key] + else: + raise const.DXFAttributeError(ERR_DXF_ATTRIB_NOT_EXITS.format(key)) + + def get(self, key: str, default: Any = None) -> Any: + """Returns value of DXF attribute `key` or the given `default` value + not DXF default value for unset attributes. + + Raises: + DXFAttributeError: attribute `key` is not supported + + """ + # callback values should not exist as attribute in __dict__ + if self.hasattr(key): + # do not return the DXF default value + return self.__dict__[key] + attrib_def: Optional["DXFAttr"] = self.dxfattribs.get(key) + if attrib_def: + if attrib_def.xtype == XType.callback: + return attrib_def.get_callback_value(self._entity) + else: + return default # return give default + else: + raise const.DXFAttributeError( + ERR_INVALID_DXF_ATTRIB.format(key, self.dxftype) + ) + + def get_default(self, key: str) -> Any: + """Returns DXF default value for unset DXF attribute `key`.""" + value = self.get(key, None) + return self.dxf_default_value(key) if value is None else value + + def set(self, key: str, value: Any) -> None: + """Set DXF attribute `key` to `value`. + + Raises: + DXFAttributeError: attribute `key` is not supported + + """ + self.__setattr__(key, value) + + def unprotected_set(self, key: str, value: Any) -> None: + """Set DXF attribute `key` to `value` without any validity checks. + + Used for fast attribute setting without validity checks at loading time. + + (internal API) + """ + self.__dict__[key] = value + + def all_existing_dxf_attribs(self) -> dict: + """Returns all existing DXF attributes, except DXFEntity back-link.""" + attribs = dict(self.__dict__) + del attribs["_entity"] + return attribs + + def update( + self, + dxfattribs: dict[str, Any], + *, + exclude: Optional[Set[str]] = None, + ignore_errors=False, + ) -> None: + """Update DXF namespace attributes from a dict.""" + if exclude is None: + exclude = EXCLUDE_FROM_UPDATE # type: ignore + else: # always exclude "_entity" back-link + exclude = {"_entity"} | exclude + + set_attribute = self.__setattr__ + for k, v in dxfattribs.items(): + if k not in exclude: # type: ignore + try: + set_attribute(k, v) + except (AttributeError, ValueError): + if not ignore_errors: + raise + + def discard(self, key: str) -> None: + """Delete DXF attribute `key` silently without any exception.""" + try: + del self.__dict__[key] + except KeyError: + pass + + def is_supported(self, key: str) -> bool: + """Returns True if DXF attribute `key` is supported else False. + Does not grant that attribute `key` really exists and does not + check if the actual DXF version of the document supports this + attribute, unsupported attributes will be ignored at export. + + """ + return key in self.dxfattribs + + def hasattr(self, key: str) -> bool: + """Returns True if attribute `key` really exists else False.""" + return key in self.__dict__ + + @property + def dxftype(self) -> str: + """Returns the DXF entity type.""" + return self._entity.DXFTYPE + + @property + def dxfattribs(self) -> DXFAttributes: + """Returns the DXF attribute definition.""" + return self._entity.DXFATTRIBS + + def dxf_default_value(self, key: str) -> Any: + """Returns the default value as defined in the DXF standard.""" + attrib: Optional[DXFAttr] = self.dxfattribs.get(key) + if attrib: + return attrib.default + else: + return None + + def export_dxf_attribs( + self, tagwriter: AbstractTagWriter, attribs: Union[str, Iterable] + ) -> None: + """Exports DXF attribute `name` by `tagwriter`. Non-optional attributes + are forced and optional tags are only written if different to default + value. DXF version check is always on: does not export DXF attribs + which are not supported by tagwriter.dxfversion. + + Args: + tagwriter: tag writer object + attribs: DXF attribute name as string or an iterable of names + + """ + if isinstance(attribs, str): + self._export_dxf_attribute_optional(tagwriter, attribs) + else: + for name in attribs: + self._export_dxf_attribute_optional(tagwriter, name) + + def _export_dxf_attribute_optional( + self, tagwriter: AbstractTagWriter, name: str + ) -> None: + """Exports DXF attribute `name` by `tagwriter`. Optional tags are only + written if different to default value. + + Args: + tagwriter: tag writer object + name: DXF attribute name + + """ + export_dxf_version = tagwriter.dxfversion + not_force_optional = not tagwriter.force_optional + attrib: Optional[DXFAttr] = self.dxfattribs.get(name) + + if attrib: + optional = attrib.optional + default = attrib.default + value = self.get(name, None) + # Force default value e.g. layer + if value is None and not optional: + # Default value could be None + value = default + + # Do not export None values + if (value is not None) and ( + export_dxf_version >= attrib.dxfversion + ): + # Do not write explicit optional attribs if equal to default + # value + if ( + optional + and not_force_optional + and default is not None + and default == value + ): + return + # Just export x, y for 2D points, if value is a 3D point + if attrib.xtype == XType.point2d and len(value) > 2: + try: # Vec3 + value = (value.x, value.y) + except AttributeError: + value = value[:2] + + if isinstance(value, str): + assert "\n" not in value, "line break '\\n' not allowed" + assert "\r" not in value, "line break '\\r' not allowed" + tag = dxftag(attrib.code, value) + tagwriter.write_tag(tag) + else: + raise const.DXFAttributeError( + ERR_INVALID_DXF_ATTRIB.format(name, self.dxftype) + ) + + +BASE_CLASS_CODES = {0, 5, 102, 330} + + +class SubclassProcessor: + """Helper class for loading tags into entities. (internal class)""" + + def __init__(self, tags: ExtendedTags, dxfversion: Optional[str] = None): + if len(tags.subclasses) == 0: + raise ValueError("Invalid tags.") + self.subclasses: list[Tags] = list(tags.subclasses) # copy subclasses + self.embedded_objects: list[Tags] = tags.embedded_objects or [] + self.dxfversion: Optional[str] = dxfversion + # DXF R12 and prior have no subclass marker system, all tags of an + # entity in one flat list. + # Later DXF versions have at least 2 subclasses base_class and + # AcDbEntity. + # Exception: CLASS has also only one subclass and no subclass marker, + # handled as DXF R12 entity + self.r12: bool = (dxfversion == const.DXF12) or ( + len(self.subclasses) == 1 + ) + self.name: str = tags.dxftype() + self.handle: str + try: + self.handle = tags.get_handle() + except const.DXFValueError: + self.handle = "" + + @property + def base_class(self): + return self.subclasses[0] + + def log_unprocessed_tags( + self, + unprocessed_tags: Iterable, + subclass="", + handle: Optional[str] = None, + ) -> None: + if options.log_unprocessed_tags: + for tag in unprocessed_tags: + entity = "" + if handle: + entity = f" in entity #{handle}" + logger.info( + f"ignored {repr(tag)} in subclass {subclass}" + entity + ) + + def find_subclass(self, name: str) -> Optional[Tags]: + for subclass in self.subclasses: + if len(subclass) and subclass[0].value == name: + return subclass + return None + + def subclass_by_index(self, index: int) -> Optional[Tags]: + try: + return self.subclasses[index] + except IndexError: + return None + + def detect_implementation_version( + self, subclass_index: int, group_code: int, default: int + ) -> int: + subclass = self.subclass_by_index(subclass_index) + if subclass and len(subclass) > 1: + # the version tag has to be the 2nd tag after the subclass marker + tag = subclass[1] + if tag.code == group_code: + return tag.value + return default + + # TODO: rename to complex_dxfattribs_loader() + def fast_load_dxfattribs( + self, + dxf: DXFNamespace, + group_code_mapping: dict[int, Union[str, list]], + subclass: Union[int, str, Tags], + *, + recover=False, + log=True, + ) -> Tags: + """Load DXF attributes into the DXF namespace and returns the + unprocessed tags without leading subclass marker(100, AcDb...). + Bypasses the DXF attribute validity checks. + + Args: + dxf: entity DXF namespace + group_code_mapping: group code to DXF attribute name mapping, + callback attributes have to be marked with a leading "*" + subclass: subclass by index, by name or as Tags() + recover: recover graphic attributes + log: enable/disable logging of unprocessed tags + + """ + if self.r12: + tags = self.subclasses[0] + else: + if isinstance(subclass, int): + tags = self.subclass_by_index(subclass) # type: ignore + elif isinstance(subclass, str): + tags = self.find_subclass(subclass) # type: ignore + else: + tags = subclass + + unprocessed_tags = Tags() + if tags is None or len(tags) == 0: + return unprocessed_tags + + processed_names: set[str] = set() + # Localize attributes: + get_attrib_name = group_code_mapping.get + append_unprocessed_tag = unprocessed_tags.append + unprotected_set_attrib = dxf.unprotected_set + mark_attrib_as_processed = processed_names.add + + # Ignore (100, "AcDb...") or (0, "ENTITY") tag in case of DXF R12 + start = 1 if tags[0].code in (0, 100) else 0 + for tag in tags[start:]: + name = get_attrib_name(tag.code) + if isinstance(name, list): # process group code duplicates: + names = name + # If all existing attrib names are used, treat this tag + # like an unprocessed tag. + name = None + # The attribute names are processed in the order of their + # definition: + for name_ in names: + if name_ not in processed_names: + name = name_ + mark_attrib_as_processed(name_) + break + if name: + # Ignore callback attributes and group codes explicit marked + # as "*IGNORE": + if name[0] != "*": + unprotected_set_attrib( + name, cast_value(tag.code, tag.value) # type: ignore + ) + else: + append_unprocessed_tag(tag) + + if self.r12: + # R12 has always unprocessed tags, because there are all tags in one + # subclass and one subclass definition never covers all tags e.g. + # handle is processed in DXFEntity, so it is an unprocessed tag in + # AcDbEntity. + return unprocessed_tags + + # Only DXF R13+ + if recover and len(unprocessed_tags): + # TODO: maybe obsolete if simple_dxfattribs_loader() is used for + # most old DXF R12 entities + unprocessed_tags = recover_graphic_attributes(unprocessed_tags, dxf) + if len(unprocessed_tags) and log: + # First tag is the subclass specifier (100, "AcDb...") + name = tags[0].value + self.log_unprocessed_tags( + tags, subclass=name, handle=dxf.get("handle") + ) + return unprocessed_tags + + def append_base_class_to_acdb_entity(self) -> None: + """It is valid to mix up the base class with AcDbEntity class. + This method appends all none base class group codes to the + AcDbEntity class. + """ + # This is only needed for DXFEntity, so applying this method + # automatically to all entities is waste of runtime + # -> DXFGraphic.load_dxf_attribs() + # TODO: maybe obsolete if simple_dxfattribs_loader() is used for + # most old DXF R12 entities + if self.r12: + return + + acdb_entity_tags = self.subclasses[1] + if acdb_entity_tags[0] == (100, "AcDbEntity"): + acdb_entity_tags.extend( + tag + for tag in self.subclasses[0] + if tag.code not in BASE_CLASS_CODES + ) + + def simple_dxfattribs_loader( + self, dxf: DXFNamespace, group_code_mapping: dict[int, str] + ) -> None: + # tested in test suite 201 for the POINT entity + """Load DXF attributes from all subclasses into the DXF namespace. + + Can not handle same group codes in different subclasses, does not remove + processed tags or log unprocessed tags and bypasses the DXF attribute + validity checks. + + This method ignores the subclass structure and can load data from + very malformed DXF files, like such in issue #604. + This method works only for very simple DXF entities with unique group + codes in all subclasses, the old DXF R12 entities: + + - POINT + - LINE + - CIRCLE + - ARC + - INSERT + - SHAPE + - SOLID/TRACE/3DFACE + - TEXT (ATTRIB/ATTDEF bypasses TEXT loader) + - BLOCK/ENDBLK + - POLYLINE/VERTEX/SEQEND + - DIMENSION and subclasses + - all table entries: LAYER, LTYPE, ... + + And the newer DXF entities: + + - ELLIPSE + - RAY/XLINE + + The recover mode for graphical attributes is automatically included. + Logging of unprocessed tags is not possible but also not required for + this simple and well known entities. + + Args: + dxf: entity DXF namespace + group_code_mapping: group code name mapping for all DXF attributes + from all subclasses, callback attributes have to be marked with + a leading "*" + + """ + tags = itertools.chain.from_iterable(self.subclasses) + get_attrib_name = group_code_mapping.get + unprotected_set_attrib = dxf.unprotected_set + for tag in tags: + name = get_attrib_name(tag.code) + if isinstance(name, str) and not name.startswith("*"): + unprotected_set_attrib( + name, cast_value(tag.code, tag.value) + ) + + +GRAPHIC_ATTRIBUTES_TO_RECOVER = { + 8: "layer", + 6: "linetype", + 62: "color", + 67: "paperspace", + 370: "lineweight", + 48: "ltscale", + 60: "invisible", + 420: "true_color", + 430: "color_name", + 440: "transparency", + 284: "shadow_mode", + 347: "material_handle", + 348: "visualstyle_handle", + 380: "plotstyle_enum", + 390: "plotstyle_handle", +} + + +# TODO: maybe obsolete if simple_dxfattribs_loader() is used for +# most old DXF R12 entities +def recover_graphic_attributes(tags: Tags, dxf: DXFNamespace) -> Tags: + unprocessed_tags = Tags() + for tag in tags: + attrib_name = GRAPHIC_ATTRIBUTES_TO_RECOVER.get(tag.code) + # Don't know if the unprocessed tag is really a misplaced tag, + # so check if the attribute already exist! + if attrib_name and not dxf.hasattr(attrib_name): + dxf.set(attrib_name, tag.value) + else: + unprocessed_tags.append(tag) + return unprocessed_tags diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfobj.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfobj.py new file mode 100644 index 0000000..e3a7b70 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/dxfobj.py @@ -0,0 +1,400 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Union, Any, Optional +from typing_extensions import Self, TypeGuard +import logging +import array +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import DXF2000, DXFStructureError, SUBCLASS_MARKER +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import dxftag, DXFTag, DXFBinaryTag +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.tools import take2 +from .dxfentity import DXFEntity, base_class, SubclassProcessor, DXFTagStorage +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = [ + "DXFObject", + "Placeholder", + "XRecord", + "VBAProject", + "SortEntsTable", + "Field", + "is_dxf_object", +] +logger = logging.getLogger("ezdxf") + + +class DXFObject(DXFEntity): + """Non-graphical entities stored in the OBJECTS section.""" + + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + +@register_entity +class Placeholder(DXFObject): + DXFTYPE = "ACDBPLACEHOLDER" + + +acdb_xrecord = DefSubclass( + "AcDbXrecord", + { + # 0 = not applicable + # 1 = keep existing + # 2 = use clone + # 3 = $0$ + # 4 = $0$ + # 5 = Unmangle name + "cloning": DXFAttr( + 280, + default=1, + validator=validator.is_in_integer_range(0, 6), + fixer=RETURN_DEFAULT, + ), + }, +) + + +def totags(tags: Iterable) -> Iterable[DXFTag]: + for tag in tags: + if isinstance(tag, DXFTag): + yield tag + else: + yield dxftag(tag[0], tag[1]) + + +@register_entity +class XRecord(DXFObject): + """DXF XRECORD entity""" + + DXFTYPE = "XRECORD" + DXFATTRIBS = DXFAttributes(base_class, acdb_xrecord) + + def __init__(self): + super().__init__() + self.tags = Tags() + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, XRecord) + entity.tags = Tags(self.tags) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + try: + tags = processor.subclasses[1] + except IndexError: + raise DXFStructureError( + f"Missing subclass AcDbXrecord in XRecord (#{dxf.handle})" + ) + start_index = 1 + if len(tags) > 1: + # First tag is group code 280, but not for DXF R13/R14. + # SUT: doc may be None, but then doc also can not + # be R13/R14 - ezdxf does not create R13/R14 + if self.doc is None or self.doc.dxfversion >= DXF2000: + code, value = tags[1] + if code == 280: + dxf.cloning = value + start_index = 2 + else: # just log recoverable error + logger.info( + f"XRecord (#{dxf.handle}): expected group code 280 " + f"as first tag in AcDbXrecord" + ) + self.tags = Tags(tags[start_index:]) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_xrecord.name) + tagwriter.write_tag2(280, self.dxf.cloning) + tagwriter.write_tags(Tags(totags(self.tags))) + + def reset(self, tags: Iterable[Union[DXFTag, tuple[int, Any]]]) -> None: + """Reset DXF tags.""" + self.tags.clear() + self.tags.extend(totags(tags)) + + def extend(self, tags: Iterable[Union[DXFTag, tuple[int, Any]]]) -> None: + """Extend DXF tags.""" + self.tags.extend(totags(tags)) + + def clear(self) -> None: + """Remove all DXF tags.""" + self.tags.clear() + + +acdb_vba_project = DefSubclass( + "AcDbVbaProject", + { + # 90: Number of bytes of binary chunk data (contained in the group code + # 310 records that follow) + # 310: DXF: Binary object data (multiple entries containing VBA project + # data) + }, +) + + +@register_entity +class VBAProject(DXFObject): + """DXF VBA_PROJECT entity""" + + DXFTYPE = "VBA_PROJECT" + DXFATTRIBS = DXFAttributes(base_class, acdb_vba_project) + + def __init__(self): + super().__init__() + self.data = b"" + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, VBAProject) + entity.data = entity.data + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + self.load_byte_data(processor.subclasses[1]) + return dxf + + def load_byte_data(self, tags: Tags) -> None: + byte_array = array.array("B") + # Translation from String to binary data happens in tag_compiler(): + for byte_data in (tag.value for tag in tags if tag.code == 310): + byte_array.extend(byte_data) + self.data = byte_array.tobytes() + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_vba_project.name) + tagwriter.write_tag2(90, len(self.data)) + self.export_data(tagwriter) + + def export_data(self, tagwriter: AbstractTagWriter): + data = self.data + while data: + tagwriter.write_tag(DXFBinaryTag(310, data[:127])) + data = data[127:] + + def clear(self) -> None: + self.data = b"" + + +acdb_sort_ents_table = DefSubclass( + "AcDbSortentsTable", + { + # Soft-pointer ID/handle to owner (currently only the *MODEL_SPACE or + # *PAPER_SPACE blocks) in ezdxf the block_record handle for a layout is + # also called layout_key: + "block_record_handle": DXFAttr(330), + # 331: Soft-pointer ID/handle to an entity (zero or more entries may exist) + # 5: Sort handle (zero or more entries may exist) + }, +) +acdb_sort_ents_table_group_codes = group_code_mapping(acdb_sort_ents_table) + + +@register_entity +class SortEntsTable(DXFObject): + """DXF SORTENTSTABLE entity - sort entities table""" + + # should work with AC1015/R2000 but causes problems with TrueView/AutoCAD + # LT 2019: "expected was-a-zombie-flag" + # No problems with AC1018/R2004 and later + # + # If the header variable $SORTENTS Regen flag (bit-code value 16) is set, + # AutoCAD regenerates entities in ascending handle order. + # + # When the DRAWORDER command is used, a SORTENTSTABLE object is attached to + # the *Model_Space or *Paper_Space block's extension dictionary under the + # name ACAD_SORTENTS. The SORTENTSTABLE object related to this dictionary + # associates a different handle with each entity, which redefines the order + # in which the entities are regenerated. + # + # $SORTENTS (280): Controls the object sorting methods (bitcode): + # 0 = Disables SORTENTS + # 1 = Sorts for object selection + # 2 = Sorts for object snap + # 4 = Sorts for redraws; obsolete + # 8 = Sorts for MSLIDE command slide creation; obsolete + # 16 = Sorts for REGEN commands + # 32 = Sorts for plotting + # 64 = Sorts for PostScript output; obsolete + + DXFTYPE = "SORTENTSTABLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_sort_ents_table) + + def __init__(self) -> None: + super().__init__() + self.table: dict[str, str] = dict() + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, SortEntsTable) + entity.table = dict(entity.table) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_sort_ents_table_group_codes, 1, log=False + ) + self.load_table(tags) + return dxf + + def load_table(self, tags: Tags) -> None: + for handle, sort_handle in take2(tags): + if handle.code != 331: + raise DXFStructureError( + f"Invalid handle code {handle.code}, expected 331" + ) + if sort_handle.code != 5: + raise DXFStructureError( + f"Invalid sort handle code {handle.code}, expected 5" + ) + self.table[handle.value] = sort_handle.value + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_sort_ents_table.name) + tagwriter.write_tag2(330, self.dxf.block_record_handle) + self.export_table(tagwriter) + + def export_table(self, tagwriter: AbstractTagWriter): + for handle, sort_handle in self.table.items(): + tagwriter.write_tag2(331, handle) + tagwriter.write_tag2(5, sort_handle) + + def __len__(self) -> int: + return len(self.table) + + def __iter__(self) -> Iterable: + """Yields all redraw associations as (object_handle, sort_handle) + tuples. + + """ + return iter(self.table.items()) + + def append(self, handle: str, sort_handle: str) -> None: + """Append redraw association (handle, sort_handle). + + Args: + handle: DXF entity handle (uppercase hex value without leading '0x') + sort_handle: sort handle (uppercase hex value without leading '0x') + + """ + self.table[handle] = sort_handle + + def clear(self): + """Remove all handles from redraw order table.""" + self.table = dict() + + def set_handles(self, handles: Iterable[tuple[str, str]]) -> None: + """Set all redraw associations from iterable `handles`, after removing + all existing associations. + + Args: + handles: iterable yielding (object_handle, sort_handle) tuples + + """ + # The sort_handle doesn't have to be unique, same or all handles can + # share the same sort_handle and sort_handles can use existing handles + # too. + # + # The '0' handle can be used, but this sort_handle will be drawn as + # latest (on top of all other entities) and not as first as expected. + # Invalid entity handles will be ignored by AutoCAD. + self.table = dict(handles) + + def remove_invalid_handles(self) -> None: + """Remove all handles which do not exist in the drawing database.""" + if self.doc is None: + return + entitydb = self.doc.entitydb + self.table = { + handle: sort_handle + for handle, sort_handle in self.table.items() + if handle in entitydb + } + + def remove_handle(self, handle: str) -> None: + """Remove handle of DXF entity from redraw order table. + + Args: + handle: DXF entity handle (uppercase hex value without leading '0x') + + """ + try: + del self.table[handle] + except KeyError: + pass + + +acdb_field = DefSubclass( + "AcDbField", + { + "evaluator_id": DXFAttr(1), + "field_code": DXFAttr(2), + # Overflow of field code string + "field_code_overflow": DXFAttr(3), + # Number of child fields + "n_child_fields": DXFAttr(90), + # 360: Child field ID (AcDbHardOwnershipId); repeats for number of children + # 97: Number of object IDs used in the field code + # 331: Object ID used in the field code (AcDbSoftPointerId); repeats for + # the number of object IDs used in the field code + # 93: Number of the data set in the field + # 6: Key string for the field data; a key-field pair is repeated for the + # number of data sets in the field + # 7: Key string for the evaluated cache; this key is hard-coded + # as ACFD_FIELD_VALUE + # 90: Data type of field value + # 91: Long value (if data type of field value is long) + # 140: Double value (if data type of field value is double) + # 330: ID value, AcDbSoftPointerId (if data type of field value is ID) + # 92: Binary data buffer size (if data type of field value is binary) + # 310: Binary data (if data type of field value is binary) + # 301: Format string + # 9: Overflow of Format string + # 98: Length of format string + }, +) + + +# todo: implement FIELD +# register when done +class Field(DXFObject): + """DXF FIELD entity""" + + DXFTYPE = "FIELD" + DXFATTRIBS = DXFAttributes(base_class, acdb_field) + + +def is_dxf_object(entity: DXFEntity) -> TypeGuard[DXFObject]: + """Returns ``True`` if the `entity` is a DXF object from the OBJECTS section, + otherwise the entity is a table or class entry or a graphic entity which can + not reside in the OBJECTS section. + """ + if isinstance(entity, DXFObject): + return True + if isinstance(entity, DXFTagStorage) and not entity.is_graphic_entity: + return True + return False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/ellipse.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/ellipse.py new file mode 100644 index 0000000..4a6d73d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/ellipse.py @@ -0,0 +1,320 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional +import math +from ezdxf.audit import AuditError +from ezdxf.lldxf import validator +from ezdxf.math import ( + Vec3, + Matrix44, + NULLVEC, + X_AXIS, + Z_AXIS, + ellipse, + ConstructionEllipse, + OCS, +) +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000 +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + add_entity, + replace_entity, + acdb_entity_group_codes, +) +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import DXFNamespace, Spline + from ezdxf.audit import Auditor + + +__all__ = ["Ellipse"] + +MIN_RATIO = 1e-10 # tested with DWG TrueView 2022 +MAX_RATIO = 1.0 # tested with DWG TrueView 2022 +TOL = 1e-9 # arbitrary choice + + +def is_valid_ratio(ratio: float) -> bool: + """Check if axis-ratio is in valid range, takes an upper bound tolerance into + account for floating point imprecision. + """ + return MIN_RATIO <= abs(ratio) < (MAX_RATIO + TOL) + + +def clamp_axis_ratio(ratio: float) -> float: + """Clamp axis-ratio into valid range and remove possible floating point imprecision. + """ + sign = -1 if ratio < 0 else +1 + ratio = abs(ratio) + if ratio < MIN_RATIO: + return MIN_RATIO * sign + if ratio > MAX_RATIO: + return MAX_RATIO * sign + return ratio * sign + + +acdb_ellipse = DefSubclass( + "AcDbEllipse", + { + "center": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Major axis vector from 'center': + "major_axis": DXFAttr( + 11, + xtype=XType.point3d, + default=X_AXIS, + validator=validator.is_not_null_vector, + ), + # The extrusion vector does not establish an OCS, it is just the normal + # vector of the ellipse plane: + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Ratio has to be in the range: -1.0 ... -1e-10 and +1e-10 ... +1.0: + "ratio": DXFAttr( + 40, default=MAX_RATIO, validator=is_valid_ratio, fixer=clamp_axis_ratio + ), + # Start of ellipse, this value is 0.0 for a full ellipse: + "start_param": DXFAttr(41, default=0), + # End of ellipse, this value is 2π for a full ellipse: + "end_param": DXFAttr(42, default=math.tau), + }, +) +acdb_ellipse_group_code = group_code_mapping(acdb_ellipse) +merged_ellipse_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_ellipse_group_code # type: ignore +) + +HALF_PI = math.pi / 2.0 + + +@register_entity +class Ellipse(DXFGraphic): + """DXF ELLIPSE entity""" + + DXFTYPE = "ELLIPSE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_ellipse) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_ellipse_group_codes) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_ellipse.name) + # is_valid_ratio() takes floating point imprecision on the upper bound of + # +/- 1.0 into account: + assert is_valid_ratio( + self.dxf.ratio + ), f"axis-ratio out of range [{MIN_RATIO}, {MAX_RATIO}]" + self.dxf.ratio = clamp_axis_ratio(self.dxf.ratio) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "center", + "major_axis", + "extrusion", + "ratio", + "start_param", + "end_param", + ], + ) + + @property + def minor_axis(self) -> Vec3: + dxf = self.dxf + return ellipse.minor_axis(Vec3(dxf.major_axis), Vec3(dxf.extrusion), dxf.ratio) + + @property + def start_point(self) -> Vec3: + return list(self.vertices([self.dxf.start_param]))[0] + + @property + def end_point(self) -> Vec3: + return list(self.vertices([self.dxf.end_param]))[0] + + def construction_tool(self) -> ConstructionEllipse: + """Returns construction tool :class:`ezdxf.math.ConstructionEllipse`.""" + dxf = self.dxf + return ConstructionEllipse( + dxf.center, + dxf.major_axis, + dxf.extrusion, + dxf.ratio, + dxf.start_param, + dxf.end_param, + ) + + def apply_construction_tool(self, e: ConstructionEllipse) -> Ellipse: + """Set ELLIPSE data from construction tool + :class:`ezdxf.math.ConstructionEllipse`. + + """ + self.update_dxf_attribs(e.dxfattribs()) + return self # floating interface + + def params(self, num: int) -> Iterable[float]: + """Returns `num` params from start- to end param in counter-clockwise + order. + + All params are normalized in the range [0, 2π). + + """ + start = self.dxf.start_param % math.tau + end = self.dxf.end_param % math.tau + yield from ellipse.get_params(start, end, num) + + def vertices(self, params: Iterable[float]) -> Iterable[Vec3]: + """Yields vertices on ellipse for iterable `params` in WCS. + + Args: + params: param values in the range from 0 to 2π in radians, + param goes counter-clockwise around the extrusion vector, + major_axis = local x-axis = 0 rad. + + """ + yield from self.construction_tool().vertices(params) + + def flattening(self, distance: float, segments: int = 8) -> Iterable[Vec3]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments, if the distance from the center + of the approximation segment to the curve is bigger than `distance` the + segment will be subdivided. Returns a closed polygon for a full ellipse + where the start vertex has the same value as the end vertex. + + Args: + distance: maximum distance from the projected curve point onto the + segment chord. + segments: minimum segment count + + """ + return self.construction_tool().flattening(distance, segments) + + def swap_axis(self): + """Swap axis and adjust start- and end parameter.""" + e = self.construction_tool() + e.swap_axis() + self.update_dxf_attribs(e.dxfattribs()) + + @classmethod + def from_arc(cls, entity: DXFGraphic) -> Ellipse: + """Create a new virtual ELLIPSE entity from an ARC or a CIRCLE entity. + + The new entity has no owner, no handle, is not stored in the entity database nor + assigned to any layout! + + """ + assert entity.dxftype() in {"ARC", "CIRCLE"}, "ARC or CIRCLE entity required" + attribs = entity.dxfattribs(drop={"owner", "handle", "thickness"}) + e = ellipse.ConstructionEllipse.from_arc( + center=attribs.get("center", NULLVEC), + extrusion=attribs.get("extrusion", Z_AXIS), + # Remove all not ELLIPSE attributes: + radius=attribs.pop("radius", 1.0), + start_angle=attribs.pop("start_angle", 0), + end_angle=attribs.pop("end_angle", 360), + ) + attribs.update(e.dxfattribs()) + return cls.new(dxfattribs=attribs, doc=entity.doc) + + def transform(self, m: Matrix44) -> Ellipse: + """Transform the ELLIPSE entity by transformation matrix `m` inplace.""" + e = self.construction_tool() + e.transform(m) + self.update_dxf_attribs(e.dxfattribs()) + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> Ellipse: + """Optimized ELLIPSE translation about `dx` in x-axis, `dy` in y-axis + and `dz` in z-axis, returns `self` (floating interface). + + """ + self.dxf.center = Vec3(dx, dy, dz) + self.dxf.center + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self + + def to_spline(self, replace=True) -> Spline: + """Convert ELLIPSE to a :class:`~ezdxf.entities.Spline` entity. + + Adds the new SPLINE entity to the entity database and to the + same layout as the source entity. + + Args: + replace: replace (delete) source entity by SPLINE entity if ``True`` + + """ + from ezdxf.entities import Spline + + spline = Spline.from_arc(self) + layout = self.get_layout() + assert layout is not None, "valid layout required" + if replace: + replace_entity(self, spline, layout) + else: + add_entity(spline, layout) + return spline + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() + + def audit(self, auditor: Auditor) -> None: + if not self.is_alive: + return + super().audit(auditor) + entity = str(self) + major_axis = Vec3(self.dxf.major_axis) + if major_axis.is_null: + auditor.trash(self) + auditor.fixed_error( + code=AuditError.INVALID_MAJOR_AXIS, + message=f"Removed {entity} with invalid major axis: (0, 0, 0).", + ) + return + axis_ratio = self.dxf.ratio + if is_valid_ratio(axis_ratio): + # remove possible floating point imprecision: + self.dxf.ratio = clamp_axis_ratio(axis_ratio) + return + if abs(axis_ratio) > MAX_RATIO: + self.swap_axis() + auditor.fixed_error( + code=AuditError.INVALID_ELLIPSE_RATIO, + message=f"Fixed invalid axis-ratio in {entity} by swapping axis.", + ) + elif abs(axis_ratio) < MIN_RATIO: + self.dxf.ratio = clamp_axis_ratio(axis_ratio) + auditor.fixed_error( + code=AuditError.INVALID_ELLIPSE_RATIO, + message=f"Fixed invalid axis-ratio in {entity}, set to {MIN_RATIO}.", + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/factory.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/factory.py new file mode 100644 index 0000000..3314cc6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/factory.py @@ -0,0 +1,136 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity + from ezdxf.lldxf.extendedtags import ExtendedTags + + +__all__ = [ + "register_entity", + "ENTITY_CLASSES", + "replace_entity", + "new", + "cls", + "is_bound", + "create_db_entry", + "load", + "bind", +] +# Stores all registered classes: +ENTITY_CLASSES = {} +# use @set_default_class to register the default entity class: +DEFAULT_CLASS = None + + +def set_default_class(cls): + global DEFAULT_CLASS + DEFAULT_CLASS = cls + return cls + + +def replace_entity(cls): + name = cls.DXFTYPE + ENTITY_CLASSES[name] = cls + return cls + + +def register_entity(cls): + name = cls.DXFTYPE + if name in ENTITY_CLASSES: + raise TypeError(f"Double registration for DXF type {name}.") + ENTITY_CLASSES[name] = cls + return cls + + +def new( + dxftype: str, dxfattribs=None, doc: Optional[Drawing] = None +) -> DXFEntity: + """Create a new entity, does not require an instantiated DXF document.""" + entity = cls(dxftype).new( + handle=None, + owner=None, + dxfattribs=dxfattribs, + doc=doc, + ) + return entity.cast() if hasattr(entity, "cast") else entity + + +def create_db_entry(dxftype, dxfattribs, doc: Drawing) -> DXFEntity: + entity = new(dxftype=dxftype, dxfattribs=dxfattribs) + bind(entity, doc) + return entity + + +def load(tags: ExtendedTags, doc: Optional[Drawing] = None) -> DXFEntity: + entity = cls(tags.dxftype()).load(tags, doc) + return entity.cast() if hasattr(entity, "cast") else entity + + +def cls(dxftype: str) -> DXFEntity: + """Returns registered class for `dxftype`.""" + return ENTITY_CLASSES.get(dxftype, DEFAULT_CLASS) + + +def bind(entity: DXFEntity, doc: Drawing) -> None: + """Bind `entity` to the DXF document `doc`. + + The bind process stores the DXF `entity` in the entity database of the DXF + document. + + """ + assert entity.is_alive, "Can not bind destroyed entity." + assert doc.entitydb is not None, "Missing entity database." + entity.doc = doc + doc.entitydb.add(entity) + + # Do not call the post_bind_hook() while loading from external sources, + # not all entities and resources are loaded at this point of time! + if not doc.is_loading: # type: ignore + # bind extension dictionary + if entity.extension_dict is not None: + xdict = entity.extension_dict + if xdict.has_valid_dictionary: + xdict.update_owner(entity.dxf.handle) + dictionary = xdict.dictionary + if not is_bound(dictionary, doc): + bind(dictionary, doc) + doc.objects.add_object(dictionary) + entity.post_bind_hook() + + +def unbind(entity: DXFEntity): + """Unbind `entity` from document and layout, but does not destroy the + entity. + + Turns `entity` into a virtual entity: no handle, no owner, no document. + """ + if entity.is_alive and not entity.is_virtual: + doc = entity.doc + if entity.dxf.owner is not None: + try: + layout = doc.layouts.get_layout_for_entity(entity) # type: ignore + except KeyError: + pass + else: + layout.unlink_entity(entity) # type: ignore + + process_sub_entities = getattr(entity, "process_sub_entities", None) + if process_sub_entities: + process_sub_entities(lambda e: unbind(e)) + + doc.entitydb.discard(entity) # type: ignore + entity.doc = None + + +def is_bound(entity: DXFEntity, doc: Drawing) -> bool: + """Returns ``True`` if `entity`is bound to DXF document `doc`.""" + if not entity.is_alive: + return False + if entity.is_virtual or entity.doc is not doc: + return False + assert doc.entitydb, "Missing entity database." + return entity.dxf.handle in doc.entitydb diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/geodata.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/geodata.py new file mode 100644 index 0000000..ee24a20 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/geodata.py @@ -0,0 +1,623 @@ +# Copyright (c) 2019-2023, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Sequence, Iterable, Optional +from xml.etree import ElementTree +import math +import re +import logging + +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXFStructureError, + DXF2010, + DXFTypeError, + DXFValueError, + InvalidGeoDataException, +) +from ezdxf.lldxf.packedtags import VertexArray +from ezdxf.lldxf.tags import Tags, DXFTag +from ezdxf.math import NULLVEC, Z_AXIS, Y_AXIS, UVec, Vec3, Vec2, Matrix44 +from ezdxf.tools.text import split_mtext_string +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .factory import register_entity +from .copy import default_copy, CopyNotSupported +from .. import units + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["GeoData", "MeshVertices"] +logger = logging.getLogger("ezdxf") +acdb_geo_data = DefSubclass( + "AcDbGeoData", + { + # 1 = R2009, but this release has no DXF version, + # 2 = R2010 + "version": DXFAttr(90, default=2), + # Handle to host block table record + "block_record_handle": DXFAttr(330, default="0"), + # 0 = unknown + # 1 = local grid + # 2 = projected grid + # 3 = geographic (latitude/longitude) + "coordinate_type": DXFAttr( + 70, + default=3, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Design point, reference point in WCS coordinates: + "design_point": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Reference point in coordinate system coordinates, valid only when + # coordinate type is Local Grid: + "reference_point": DXFAttr(11, xtype=XType.point3d, default=NULLVEC), + # Horizontal unit scale, factor which converts horizontal design coordinates + # to meters by multiplication: + "horizontal_unit_scale": DXFAttr( + 40, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Horizontal units per UnitsValue enumeration. Will be kUnitsUndefined if + # units specified by horizontal unit scale is not supported by AutoCAD + # enumeration: + "horizontal_units": DXFAttr(91, default=1), + # Vertical unit scale, factor which converts vertical design coordinates + # to meters by multiplication: + "vertical_unit_scale": DXFAttr(41, default=1), + # Vertical units per UnitsValue enumeration. Will be kUnitsUndefined if + # units specified by vertical unit scale is not supported by AutoCAD + # enumeration: + "vertical_units": DXFAttr(92, default=1), + "up_direction": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # North direction vector (2D) + # In DXF R2009 the group code 12 is used for source mesh points! + "north_direction": DXFAttr( + 12, + xtype=XType.point2d, + default=Y_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Scale estimation methods: + # 1 = None + # 2 = User specified scale factor; + # 3 = Grid scale at reference point; + # 4 = Prismoidal + "scale_estimation_method": DXFAttr( + 95, + default=1, + validator=validator.is_in_integer_range(0, 5), + fixer=RETURN_DEFAULT, + ), + "user_scale_factor": DXFAttr( + 141, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Bool flag specifying whether to do sea level correction: + "sea_level_correction": DXFAttr( + 294, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "sea_level_elevation": DXFAttr(142, default=0), + "coordinate_projection_radius": DXFAttr(143, default=0), + # 303, 303, ..., 301: Coordinate system definition string + "geo_rss_tag": DXFAttr(302, default="", optional=True), + "observation_from_tag": DXFAttr(305, default="", optional=True), + "observation_to_tag": DXFAttr(306, default="", optional=True), + "observation_coverage_tag": DXFAttr(307, default="", optional=True), + # 93: Number of Geo-Mesh points + # mesh definition: + # source mesh point (12, 22) repeat, mesh_point_count? for version == 1 + # target mesh point (13, 14) repeat, mesh_point_count? for version == 1 + # source mesh point (13, 23) repeat, mesh_point_count? for version > 1 + # target mesh point (14, 24) repeat, mesh_point_count? for version > 1 + # 96: # Number of faces + # face index 97 repeat, faces_count + # face index 98 repeat, faces_count + # face index 99 repeat, faces_count + }, +) +acdb_geo_data_group_codes = group_code_mapping(acdb_geo_data) +EPSG_3395 = """ + + + +WORLD-MERCATOR + + +CSQuadrantSimplified +1 + + + + + + +-180.75 +180.75 +-80.75 +84.75 + + + + +WGS84 + + +1 +Easting +E +East + + +2 +Northing +N +North + + + + +Mercator (variant B) +Longitude of natural origin0 +Standard Parallel0 +Scaling factor for coord differences1 +False easting0 +False northing0 + + + + +WORLD-MERCATOR +EPSG Code + + + +WGS84 +Greenwich +WGS84 + + +WGS84 +EPSG Code + + + +WGS84 +6.37814e+06 + +6.35675e+06 + + + +WGS84 +EPSG Code + + + +""" + + +class MeshVertices(VertexArray): + VERTEX_SIZE = 2 + + +def mesh_group_codes(version: int) -> tuple[int, int]: + return (12, 13) if version < 2 else (13, 14) + + +@register_entity +class GeoData(DXFObject): + """DXF GEODATA entity""" + + DXFTYPE = "GEODATA" + DXFATTRIBS = DXFAttributes(base_class, acdb_geo_data) + MIN_DXF_VERSION_FOR_EXPORT = DXF2010 + + # coordinate_type const + UNKNOWN = 0 + LOCAL_GRID = 1 + PROJECTED_GRID = 2 + GEOGRAPHIC = 3 + + # scale_estimation_method const + NONE = 1 + USER_SCALE = 2 + GRID_SCALE = 3 + PRISMOIDEAL = 4 + + def __init__(self) -> None: + super().__init__() + self.source_vertices = MeshVertices() + self.target_vertices = MeshVertices() + self.faces: list[Sequence[int]] = [] + self.coordinate_system_definition = "" + + def copy(self, copy_strategy=default_copy): + raise CopyNotSupported(f"Copying of {self.DXFTYPE} not supported.") + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + version = processor.detect_implementation_version( + subclass_index=1, + group_code=90, + default=2, + ) + tags = processor.fast_load_dxfattribs( + dxf, acdb_geo_data_group_codes, 1, log=False + ) + tags = self.load_coordinate_system_definition(tags) # type: ignore + if version > 1: + self.load_mesh_data(tags, version) + else: + # version 1 is not really supported, because the group codes are + # totally messed up! + logger.warning( + "GEODATA version 1 found, perhaps loaded data is incorrect" + ) + dxf.discard("north_direction") # group code issue!!! + return dxf + + def load_coordinate_system_definition(self, tags: Tags) -> Iterable[DXFTag]: + # 303, 303, 301, Coordinate system definition string, always XML? + lines = [] + for tag in tags: + if tag.code in (301, 303): + lines.append(tag.value.replace("^J", "\n")) + else: + yield tag + if len(lines): + self.coordinate_system_definition = "".join(lines) + + def load_mesh_data(self, tags: Iterable[DXFTag], version: int = 2): + # group codes of version 1 and 2 differ, see DXF reference R2009 + src, target = mesh_group_codes(version) + face_indices = {97, 98, 99} + face: list[int] = [] + for code, value in tags: + if code == src: + self.source_vertices.append(value) + elif code == target: + self.target_vertices.append(value) + elif code in face_indices: + if code == 97 and len(face): + if len(face) != 3: + raise DXFStructureError( + f"GEODATA face definition error: invalid index " + f"count {len(face)}." + ) + self.faces.append(tuple(face)) + face.clear() + face.append(value) + if face: # collect last face + self.faces.append(tuple(face)) + if len(self.source_vertices) != len(self.target_vertices): + raise DXFStructureError( + "GEODATA mesh definition error: source and target point count " + "does not match." + ) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_geo_data.name) + if self.dxf.version < 2: + logger.warning( + "exporting unsupported GEODATA version 1, this may corrupt " + "the DXF file!" + ) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "version", + "block_record_handle", + "coordinate_type", + "design_point", + "reference_point", + "horizontal_unit_scale", + "horizontal_units", + "vertical_unit_scale", + "vertical_units", + "up_direction", + "north_direction", + "scale_estimation_method", + "user_scale_factor", + "sea_level_correction", + "sea_level_elevation", + "coordinate_projection_radius", + ], + ) + self.export_coordinate_system_definition(tagwriter) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "geo_rss_tag", + "observation_from_tag", + "observation_to_tag", + "observation_coverage_tag", + ], + ) + self.export_mesh_data(tagwriter) + + def export_mesh_data(self, tagwriter: AbstractTagWriter): + if len(self.source_vertices) != len(self.target_vertices): + raise DXFStructureError( + "GEODATA mesh definition error: source and target point count " + "does not match." + ) + src, target = mesh_group_codes(self.dxf.version) + + tagwriter.write_tag2(93, len(self.source_vertices)) + for s, t in zip(self.source_vertices, self.target_vertices): + tagwriter.write_vertex(src, s) + tagwriter.write_vertex(target, t) + + tagwriter.write_tag2(96, len(self.faces)) + for face in self.faces: + if len(face) != 3: + raise DXFStructureError( + f"GEODATA face definition error: invalid index " + f"count {len(face)}." + ) + f1, f2, f3 = face + tagwriter.write_tag2(97, f1) + tagwriter.write_tag2(98, f2) + tagwriter.write_tag2(99, f3) + + def export_coordinate_system_definition(self, tagwriter: AbstractTagWriter): + text = self.coordinate_system_definition.replace("\n", "^J") + chunks = split_mtext_string(text, size=255) + if len(chunks) == 0: + chunks.append("") + while len(chunks) > 1: + tagwriter.write_tag2(303, chunks.pop(0)) + tagwriter.write_tag2(301, chunks[0]) + + def decoded_units(self) -> tuple[Optional[str], Optional[str]]: + return units.decode(self.dxf.horizontal_units), units.decode( + self.dxf.vertical_units + ) + + def get_crs(self) -> tuple[int, bool]: + """Returns the EPSG index and axis-ordering, axis-ordering is ``True`` + if fist axis is labeled "E" or "W" and ``False`` if first axis is + labeled "N" or "S". + + If axis-ordering is ``False`` the CRS is not compatible with the + ``__geo_interface__`` or GeoJSON (see chapter 3.1.1). + + Raises: + InvalidGeoDataException: for invalid or unknown XML data + + The EPSG number is stored in a tag like: + + .. code:: + + + OSGB1936.NationalGrid + EPSG Code + + + The axis-ordering is stored in a tag like: + + .. code:: + + + + 1 + Easting + E + east + + + 2 + Northing + N + north + + + + """ + definition = self.coordinate_system_definition + try: + # Remove namespaces so that tags can be searched without prefixing + # their namespace: + definition = _remove_xml_namespaces(definition) + root = ElementTree.fromstring(definition) + except ElementTree.ParseError: + raise InvalidGeoDataException( + "failed to parse coordinate_system_definition as xml" + ) + + crs = None + for alias in root.findall("Alias"): + try: + namespace = alias.find("Namespace").text # type: ignore + except AttributeError: + namespace = "" + + if alias.get("type") == "CoordinateSystem" and namespace == "EPSG Code": + try: + crs = int(alias.get("id")) # type: ignore + except ValueError: + raise InvalidGeoDataException( + f'invalid epsg number: {alias.get("id")}' + ) + break + + xy_ordering = None + for axis in root.findall(".//CoordinateSystemAxis"): + try: + axis_order = axis.find("AxisOrder").text # type: ignore + except AttributeError: + axis_order = "" + + if axis_order == "1": + try: + first_axis = axis.find("AxisAbbreviation").text # type: ignore + except AttributeError: + raise InvalidGeoDataException("first axis not defined") + + if first_axis in ("E", "W"): + xy_ordering = True + elif first_axis in ("N", "S"): + xy_ordering = False + else: + raise InvalidGeoDataException(f"unknown first axis: {first_axis}") + break + + if crs is None: + raise InvalidGeoDataException("no EPSG code associated with CRS") + elif xy_ordering is None: + raise InvalidGeoDataException("could not determine axis ordering") + else: + return crs, xy_ordering + + def get_crs_transformation( + self, *, no_checks: bool = False + ) -> tuple[Matrix44, int]: + """Returns the transformation matrix and the EPSG index to transform + WCS coordinates into CRS coordinates. Because of the lack of proper + documentation this method works only for tested configurations, set + argument `no_checks` to ``True`` to use the method for untested geodata + configurations, but the results may be incorrect. + + Supports only "Local Grid" transformation! + + Raises: + InvalidGeoDataException: for untested geodata configurations + + """ + epsg, xy_ordering = self.get_crs() + + if not no_checks: + if ( + self.dxf.coordinate_type != GeoData.LOCAL_GRID + or self.dxf.scale_estimation_method != GeoData.NONE + or not math.isclose(self.dxf.user_scale_factor, 1.0) + or self.dxf.sea_level_correction != 0 + or not math.isclose(self.dxf.sea_level_elevation, 0) + or self.faces + or not self.dxf.up_direction.isclose((0, 0, 1)) + or self.dxf.observation_coverage_tag != "" + or self.dxf.observation_from_tag != "" + or self.dxf.observation_to_tag != "" + or not xy_ordering + ): + raise InvalidGeoDataException( + f"Untested geodata configuration: " + f"{self.dxf.all_existing_dxf_attribs()}.\n" + f"You can try with no_checks=True but the " + f"results may be incorrect." + ) + + source = self.dxf.design_point # in CAD WCS coordinates + target = self.dxf.reference_point # in the CRS of the geodata + north = self.dxf.north_direction + + # -pi/2 because north is at pi/2 so if the given north is at pi/2, no + # rotation is necessary: + theta = -(math.atan2(north.y, north.x) - math.pi / 2) + transformation = ( + Matrix44.translate(-source.x, -source.y, 0) + @ Matrix44.scale( + self.dxf.horizontal_unit_scale, self.dxf.vertical_unit_scale, 1 + ) + @ Matrix44.z_rotate(theta) + @ Matrix44.translate(target.x, target.y, 0) + ) + return transformation, epsg + + def setup_local_grid( + self, + *, + design_point: UVec, + reference_point: UVec, + north_direction: UVec = (0, 1), + crs: str = EPSG_3395, + ) -> None: + """Setup local grid coordinate system. This method is designed to setup + CRS similar to `EPSG:3395 World Mercator`, the basic features of the + CRS should fulfill these assumptions: + + - base unit of reference coordinates is 1 meter + - right-handed coordinate system: +Y=north/+X=east/+Z=up + + The CRS string is not validated nor interpreted! + + .. hint:: + + The reference point must be a 2D cartesian map coordinate and not + a globe (lon/lat) coordinate like stored in GeoJSON or GPS data. + + Args: + design_point: WCS coordinates of the CRS reference point + reference_point: CRS reference point in 2D cartesian coordinates + north_direction: north direction a 2D vertex, default is (0, 1) + crs: Coordinate Reference System definition XML string, default is + the definition string for `EPSG:3395 World Mercator` + + """ + doc = self.doc + if doc is None: + raise DXFValueError("Valid DXF document required.") + wcs_units = doc.units + if units == 0: + raise DXFValueError( + "DXF document requires units to be set, " 'current state is "unitless".' + ) + meter_factor = units.METER_FACTOR[wcs_units] + if meter_factor is None: + raise DXFValueError(f"Unsupported document units: {wcs_units}") + unit_factor = 1.0 / meter_factor + # Default settings: + self.dxf.up_direction = Z_AXIS + self.dxf.observation_coverage_tag = "" + self.dxf.observation_from_tag = "" + self.dxf.observation_to_tag = "" + self.dxf.scale_estimation_method = GeoData.NONE + self.dxf.coordinate_type = GeoData.LOCAL_GRID + self.dxf.sea_level_correction = 0 + self.dxf.horizontal_units = wcs_units + # Factor from WCS -> CRS (m) e.g. 0.01 for horizontal_units==5 (cm), + # 1cm = 0.01m + self.dxf.horizontal_unit_scale = unit_factor + self.dxf.vertical_units = wcs_units + self.dxf.vertical_unit_scale = unit_factor + + # User settings: + self.dxf.design_point = Vec3(design_point) + self.dxf.reference_point = Vec3(reference_point) + self.dxf.north_direction = Vec2(north_direction) + self.coordinate_system_definition = str(crs) + + +def _remove_xml_namespaces(xml_string: str) -> str: + return re.sub('xmlns="[^"]*"', "", xml_string) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/gradient.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/gradient.py new file mode 100644 index 0000000..4140fc9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/gradient.py @@ -0,0 +1,124 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Optional, TYPE_CHECKING +import enum +import math + +from ezdxf.colors import RGB, int2rgb, rgb2int +from ezdxf.lldxf.tags import Tags + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Gradient", "GradientType"] + +GRADIENT_CODES = {450, 451, 452, 453, 460, 461, 462, 463, 470, 421, 63} + + +class GradientType(enum.IntEnum): + NONE = 0 + LINEAR = 1 + CYLINDER = 2 + INVCYLINDER = 3 + SPHERICAL = 4 + INVSPHERICAL = 5 + HEMISPHERICAL = 6 + INVHEMISPHERICAL = 7 + CURVED = 8 + INVCURVED = 9 + + +gradient_names = [ + "", + "LINEAR", + "CYLINDER", + "INVCYLINDER", + "SPHERICAL", + "INVSPHERICAL", + "HEMISPHERICAL", + "INVHEMISPHERICAL", + "CURVED", + "INVCURVED", +] + + +class Gradient: + def __init__(self, kind: int = 1, num: int = 2, type=GradientType.LINEAR): + # 1 for gradient by default, 0 for Solid + self.kind: int = kind + self.number_of_colors: int = num + self.color1: RGB = RGB(0, 0, 0) + self.aci1: Optional[int] = None + self.color2: RGB = RGB(255, 255, 255) + self.aci2: Optional[int] = None + + # 1 = use a smooth transition between color1 and a specified tint + self.one_color: int = 0 + + # Use degree NOT radians for rotation, because there should be one + # system for all angles: + self.rotation: float = 0.0 + self.centered: float = 0.0 + self.tint: float = 0.0 + self.name: str = gradient_names[type] + + @classmethod + def load_tags(cls, tags: Tags) -> Gradient: + gdata = cls() + assert tags[0].code == 450 + gdata.kind = tags[0].value # 0 = solid; 1 = gradient + first_color_value = True + first_aci_value = True + for code, value in tags: + if code == 460: + gdata.rotation = math.degrees(value) + elif code == 461: + gdata.centered = value + elif code == 452: + gdata.one_color = value + elif code == 462: + gdata.tint = value + elif code == 470: + gdata.name = value + elif code == 453: + gdata.number_of_colors = value + elif code == 63: + if first_aci_value: + gdata.aci1 = value + first_aci_value = False + else: + gdata.aci2 = value + elif code == 421: + if first_color_value: + gdata.color1 = int2rgb(value) + first_color_value = False + else: + gdata.color2 = int2rgb(value) + return gdata + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + # Tag order matters! + write_tag = tagwriter.write_tag2 + write_tag(450, self.kind) # gradient or solid + write_tag(451, 0) # reserved for the future + + # rotation angle in radians: + write_tag(460, math.radians(self.rotation)) + write_tag(461, self.centered) + write_tag(452, self.one_color) + write_tag(462, self.tint) + write_tag(453, self.number_of_colors) + if self.number_of_colors > 0: + write_tag(463, 0) # first value, see DXF standard + if self.aci1 is not None: + # code 63 "color as ACI" could be left off + write_tag(63, self.aci1) + write_tag(421, rgb2int(self.color1)) # first color + if self.number_of_colors > 1: + write_tag(463, 1) # second value, see DXF standard + if self.aci2 is not None: + # code 63 "color as ACI" could be left off + write_tag(63, self.aci2) + write_tag(421, rgb2int(self.color2)) # second color + write_tag(470, self.name) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/hatch.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/hatch.py new file mode 100644 index 0000000..b2c6339 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/hatch.py @@ -0,0 +1,323 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional + +from ezdxf.lldxf import const +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags +from ezdxf.math import NULLVEC, Z_AXIS +from .boundary_paths import AbstractBoundaryPath +from .dxfentity import base_class +from .dxfgfx import acdb_entity +from .factory import register_entity +from .polygon import DXFPolygon + +if TYPE_CHECKING: + from ezdxf.colors import RGB + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + + +__all__ = ["Hatch"] + + +acdb_hatch = DefSubclass( + "AcDbHatch", + { + # This subclass can also represent a MPolygon, whatever this is, never seen + # such a MPolygon in the wild. + # x- and y-axis always equal 0, z-axis represents the elevation: + "elevation": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Hatch pattern name: + "pattern_name": DXFAttr(2, default="SOLID"), + # HATCH: Solid fill flag: + # 0 = pattern fill + # 1 = solid fill + "solid_fill": DXFAttr( + 70, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # HATCH: associativity flag + # 0 = non-associative + # 1 = associative + "associative": DXFAttr( + 71, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 91: Number of boundary paths (loops) + # following: Boundary path data. Repeats number of times specified by + # code 91. See Boundary Path Data + # Hatch style: + # 0 = Hatch “odd parity” area (Normal style) + # 1 = Hatch outermost area only (Outer style) + # 2 = Hatch through entire area (Ignore style) + "hatch_style": DXFAttr( + 75, + default=const.HATCH_STYLE_NESTED, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + # Hatch pattern type: + # 0 = User-defined + # 1 = Predefined + # 2 = Custom + "pattern_type": DXFAttr( + 76, + default=const.HATCH_TYPE_PREDEFINED, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + # Hatch pattern angle (pattern fill only) in degrees: + "pattern_angle": DXFAttr(52, default=0), + # Hatch pattern scale or spacing (pattern fill only): + "pattern_scale": DXFAttr( + 41, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Hatch pattern double flag (pattern fill only): + # 0 = not double + # 1 = double + "pattern_double": DXFAttr( + 77, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 78: Number of pattern definition lines + # following: Pattern line data. Repeats number of times specified by + # code 78. See Pattern Data + # Pixel size used to determine the density to perform various intersection + # and ray casting operations in hatch pattern computation for associative + # hatches and hatches created with the Flood method of hatching + "pixel_size": DXFAttr(47, optional=True), + # Number of seed points + "n_seed_points": DXFAttr( + 98, + default=0, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + # 10, 20: Seed point (in OCS) 2D point (multiple entries) + # 450 Indicates solid hatch or gradient; if solid hatch, the values for the + # remaining codes are ignored but must be present. Optional; + # + # if code 450 is in the file, then the following codes must be in the + # file: 451, 452, 453, 460, 461, 462, and 470. + # If code 450 is not in the file, then the following codes must not be + # in the file: 451, 452, 453, 460, 461, 462, and 470 + # + # 0 = Solid hatch + # 1 = Gradient + # + # 451 Zero is reserved for future use + # 452 Records how colors were defined and is used only by dialog code: + # + # 0 = Two-color gradient + # 1 = Single-color gradient + # + # 453 Number of colors: + # + # 0 = Solid hatch + # 2 = Gradient + # + # 460 Rotation angle in radians for gradients (default = 0, 0) + # 461 Gradient definition; corresponds to the Centered option on the + # Gradient Tab of the Boundary Hatch and Fill dialog box. Each gradient + # has two definitions, shifted and non-shifted. A Shift value describes + # the blend of the two definitions that should be used. A value of 0.0 + # means only the non-shifted version should be used, and a value of 1.0 + # means that only the shifted version should be used. + # + # 462 Color tint value used by dialog code (default = 0, 0; range is 0.0 to + # 1.0). The color tint value is a gradient color and controls the degree + # of tint in the dialog when the Hatch group code 452 is set to 1. + # + # 463 Reserved for future use: + # + # 0 = First value + # 1 = Second value + # + # 470 String (default = LINEAR) + }, +) +acdb_hatch_group_code = group_code_mapping(acdb_hatch) + + +@register_entity +class Hatch(DXFPolygon): + """DXF HATCH entity""" + + DXFTYPE = "HATCH" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_hatch) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + LOAD_GROUP_CODES = acdb_hatch_group_code + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_hatch.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "elevation", + "extrusion", + "pattern_name", + "solid_fill", + "associative", + ], + ) + self.paths.export_dxf(tagwriter, self.dxftype()) + self.dxf.export_dxf_attribs(tagwriter, ["hatch_style", "pattern_type"]) + if self.pattern: + self.dxf.export_dxf_attribs( + tagwriter, ["pattern_angle", "pattern_scale", "pattern_double"] + ) + self.pattern.export_dxf(tagwriter) + self.dxf.export_dxf_attribs(tagwriter, ["pixel_size"]) + self.export_seeds(tagwriter) + if self.gradient and tagwriter.dxfversion > const.DXF2000: + self.gradient.export_dxf(tagwriter) + + def load_seeds(self, tags: Tags) -> Tags: + try: + start_index = tags.tag_index(98) + except const.DXFValueError: + return tags + seed_data = tags.collect_consecutive_tags( + {98, 10, 20}, start=start_index + ) + + # Remove seed data from tags: + del tags[start_index : start_index + len(seed_data) + 1] + + # Just process vertices with group code 10 + self.seeds = [value for code, value in seed_data if code == 10] + return tags + + def export_seeds(self, tagwriter: AbstractTagWriter): + tagwriter.write_tag2(98, len(self.seeds)) + for seed in self.seeds: + tagwriter.write_vertex(10, seed[:2]) + + def remove_dependencies(self, other: Optional[Drawing] = None) -> None: + """Remove all dependencies from actual document. (internal API)""" + if not self.is_alive: + return + + super().remove_dependencies() + self.remove_association() + + def remove_association(self): + """Remove associated path elements.""" + if self.dxf.associative: + self.dxf.associative = 0 + for path in self.paths: + path.source_boundary_objects = [] + + def set_solid_fill( + self, color: int = 7, style: int = 1, rgb: Optional[RGB] = None + ): + """Set the solid fill mode and removes all gradient and pattern fill related + data. + + Args: + color: :ref:`ACI`, (0 = BYBLOCK; 256 = BYLAYER) + style: hatch style (0 = normal; 1 = outer; 2 = ignore) + rgb: true color value as (r, g, b)-tuple - has higher priority + than `color`. True color support requires DXF R2000. + + """ + # remove existing gradient and pattern fill + self.gradient = None + self.pattern = None + self.dxf.solid_fill = 1 + + # if true color is present, the color attribute is ignored + self.dxf.color = color + self.dxf.hatch_style = style + self.dxf.pattern_name = "SOLID" + self.dxf.pattern_type = const.HATCH_TYPE_PREDEFINED + if rgb is not None: + self.rgb = rgb + + def associate( + self, path: AbstractBoundaryPath, entities: Iterable[DXFEntity] + ): + """Set association from hatch boundary `path` to DXF geometry `entities`. + + A HATCH entity can be associative to a base geometry, this association + is **not** maintained nor verified by `ezdxf`, so if you modify the base + geometry the geometry of the boundary path is not updated and no + verification is done to check if the associated geometry matches + the boundary path, this opens many possibilities to create + invalid DXF files: USE WITH CARE! + + """ + # I don't see this as a time critical operation, do as much checks as + # needed to avoid invalid DXF files. + if not self.is_alive: + raise const.DXFStructureError("HATCH entity is destroyed") + + doc = self.doc + owner = self.dxf.owner + handle = self.dxf.handle + if doc is None or owner is None or handle is None: + raise const.DXFStructureError( + "virtual entity can not have associated entities" + ) + + for entity in entities: + if not entity.is_alive or entity.is_virtual: + raise const.DXFStructureError( + "associated entity is destroyed or a virtual entity" + ) + if doc is not entity.doc: + raise const.DXFStructureError( + "associated entity is from a different document" + ) + if owner != entity.dxf.owner: + raise const.DXFStructureError( + "associated entity is from a different layout" + ) + + path.source_boundary_objects.append(entity.dxf.handle) + entity.append_reactor_handle(handle) + self.dxf.associative = 1 if len(path.source_boundary_objects) else 0 + + def set_seed_points(self, points: Iterable[tuple[float, float]]) -> None: + """Set seed points, `points` is an iterable of (x, y)-tuples. + I don't know why there can be more than one seed point. + All points in :ref:`OCS` (:attr:`Hatch.dxf.elevation` is the Z value) + + """ + points = list(points) + if len(points) < 1: + raise const.DXFValueError( + "Argument points should be an iterable of 2D points and requires" + " at least one point." + ) + self.seeds = list(points) + self.dxf.n_seed_points = len(self.seeds) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/helix.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/helix.py new file mode 100644 index 0000000..642f5ce --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/helix.py @@ -0,0 +1,122 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER +from ezdxf.math import NULLVEC, X_AXIS, Z_AXIS +from .spline import Spline, acdb_spline +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import acdb_entity +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + +__all__ = ["Helix"] + +acdb_helix = DefSubclass( + "AcDbHelix", + { + "major_release_number": DXFAttr(90, default=29), + "maintenance_release_number": DXFAttr(91, default=63), + "axis_base_point": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "start_point": DXFAttr( + 11, + xtype=XType.point3d, + default=X_AXIS, + fixer=RETURN_DEFAULT, + ), + "axis_vector": DXFAttr( + 12, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # base radius = (start-point - axis_base_point).magnitude + "radius": DXFAttr(40, default=1), # top radius + "turns": DXFAttr(41, default=1), + "turn_height": DXFAttr(42, default=1), + # Handedness: + # 0 = left + # 1 = right + "handedness": DXFAttr( + 290, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Constrain type: + # 0 = Constrain turn height + # 1 = Constrain turns + # 2 = Constrain height + "constrain": DXFAttr( + 280, + default=1, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_helix_group_codes = group_code_mapping(acdb_helix) + + +@register_entity +class Helix(Spline): + """DXF HELIX entity""" + + DXFTYPE = "HELIX" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_spline, acdb_helix) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_helix_group_codes, 3, recover=True + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_helix.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "major_release_number", + "maintenance_release_number", + "axis_base_point", + "start_point", + "axis_vector", + "radius", + "turns", + "turn_height", + "handedness", + "constrain", + ], + ) + + def transform(self, m: Matrix44) -> Helix: + """Transform the HELIX entity by transformation matrix `m` inplace.""" + super().transform(m) + self.dxf.axis_base_point = m.transform(self.dxf.axis_base_point) + self.dxf.axis_vector = m.transform_direction(self.dxf.axis_vector) + self.dxf.start_point = m.transform(self.dxf.start_point) + self.dxf.radius = m.transform_direction( + (self.dxf.radius, 0, 0) + ).magnitude + self.post_transform(m) + return self diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/idbuffer.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/idbuffer.py new file mode 100644 index 0000000..9aeab8b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/idbuffer.py @@ -0,0 +1,139 @@ +# Copyright (c) 2019-2023, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXFStructureError +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + group_code_mapping, +) +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.tags import Tags + +__all__ = ["IDBuffer", "FieldList", "LayerFilter"] + +acdb_id_buffer = DefSubclass("AcDbIdBuffer", {}) + + +@register_entity +class IDBuffer(DXFObject): + """DXF IDBUFFER entity""" + + DXFTYPE = "IDBUFFER" + DXFATTRIBS = DXFAttributes(base_class, acdb_id_buffer) + + def __init__(self) -> None: + super().__init__() + self.handles: list[str] = [] + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy handles""" + assert isinstance(entity, IDBuffer) + entity.handles = list(self.handles) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + if len(processor.subclasses) < 2: + raise DXFStructureError( + f"Missing required subclass in IDBUFFER(#{dxf.handle})" + ) + self.load_handles(processor.subclasses[1]) + return dxf + + def load_handles(self, tags: Tags): + self.handles = [value for code, value in tags if code == 330] + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_id_buffer.name) + self.export_handles(tagwriter) + + def export_handles(self, tagwriter: AbstractTagWriter): + for handle in self.handles: + tagwriter.write_tag2(330, handle) + + +acdb_id_set = DefSubclass( + "AcDbIdSet", + { + "flags": DXFAttr(90, default=0), # not documented by Autodesk + }, +) +acdb_id_set_group_codes = group_code_mapping(acdb_id_set) +acdb_field_list = DefSubclass("AcDbFieldList", {}) + + +@register_entity +class FieldList(IDBuffer): + """DXF FIELDLIST entity""" + + DXFTYPE = "FIELDLIST" + DXFATTRIBS = DXFAttributes(base_class, acdb_id_set, acdb_field_list) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super(DXFObject, self).load_dxf_attribs(processor) + if processor: + if len(processor.subclasses) < 3: + raise DXFStructureError( + f"Missing required subclass in FIELDLIST(#{dxf.handle})" + ) + processor.fast_load_dxfattribs(dxf, acdb_id_set_group_codes, 1) + # Load field list: + self.load_handles(processor.subclasses[2]) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super(DXFObject, self).export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_id_set.name) + self.dxf.export_dxf_attribs(tagwriter, "flags") + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_field_list.name) + self.export_handles(tagwriter) + + +acdb_filter = DefSubclass("AcDbFilter", {}) +acdb_layer_filter = DefSubclass("AcDbLayerFilter", {}) + + +@register_entity +class LayerFilter(IDBuffer): + """DXF LAYER_FILTER entity""" + + DXFTYPE = "LAYER_FILTER" + DXFATTRIBS = DXFAttributes(base_class, acdb_filter, acdb_layer_filter) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super(DXFObject, self).load_dxf_attribs(processor) + if processor: + if len(processor.subclasses) < 3: + raise DXFStructureError( + f"Missing required subclass in LAYER_FILTER(#{dxf.handle})" + ) + # Load layer filter: + self.load_handles(processor.subclasses[2]) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super(DXFObject, self).export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_filter.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_layer_filter.name) + self.export_handles(tagwriter) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/image.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/image.py new file mode 100644 index 0000000..5abc3fb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/image.py @@ -0,0 +1,760 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import os +import pathlib +from typing import ( + TYPE_CHECKING, + Iterable, + cast, + Optional, + Callable, + Union, + Type, +) +from typing_extensions import Self + +import logging +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000, DXF2010 +from ezdxf.math import Vec3, Vec2, BoundingBox2d, UVec, Matrix44 +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .dxfobj import DXFObject +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFNamespace, DXFEntity, Dictionary + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.types import DXFTag + from ezdxf.document import Drawing + from ezdxf import xref + +__all__ = ["Image", "ImageDef", "ImageDefReactor", "RasterVariables", "Wipeout"] +logger = logging.getLogger("ezdxf") + + +class ImageBase(DXFGraphic): + """DXF IMAGE entity""" + + DXFTYPE = "IMAGEBASE" + _CLS_GROUP_CODES: dict[int, Union[str, list[str]]] = dict() + _SUBCLASS_NAME = "dummy" + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + SHOW_IMAGE = 1 + SHOW_IMAGE_WHEN_NOT_ALIGNED = 2 + USE_CLIPPING_BOUNDARY = 4 + USE_TRANSPARENCY = 8 + + def __init__(self) -> None: + super().__init__() + # Boundary/Clipping path coordinates: + # 0/0 is in the Left/Top corner of the image! + # x-coordinates increases in u_pixel vector direction + # y-coordinates increases against the v_pixel vector! + # see also WCS coordinate calculation + self._boundary_path: list[Vec2] = [] + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, ImageBase) + entity._boundary_path = list(self._boundary_path) + + def post_new_hook(self) -> None: + super().post_new_hook() + self.reset_boundary_path() + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + path_tags = processor.subclasses[2].pop_tags(codes=(14,)) + self.load_boundary_path(path_tags) + processor.fast_load_dxfattribs(dxf, self._CLS_GROUP_CODES, 2, recover=True) + if len(self.boundary_path) < 2: # something is wrong + self.dxf = dxf + self.reset_boundary_path() + return dxf + + def load_boundary_path(self, tags: Iterable[DXFTag]): + self._boundary_path = [Vec2(value) for code, value in tags if code == 14] + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, self._SUBCLASS_NAME) + self.dxf.count_boundary_points = len(self.boundary_path) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "class_version", + "insert", + "u_pixel", + "v_pixel", + "image_size", + "image_def_handle", + "flags", + "clipping", + "brightness", + "contrast", + "fade", + "image_def_reactor_handle", + "clipping_boundary_type", + "count_boundary_points", + ], + ) + self.export_boundary_path(tagwriter) + if tagwriter.dxfversion >= DXF2010: + self.dxf.export_dxf_attribs(tagwriter, "clip_mode") + + def export_boundary_path(self, tagwriter: AbstractTagWriter): + for vertex in self.boundary_path: + tagwriter.write_vertex(14, vertex) + + @property + def boundary_path(self): + """Returns the boundray path in raw form in pixel coordinates. + + A list of vertices as pixel coordinates, Two vertices describe a + rectangle, lower left corner is (-0.5, -0.5) and upper right corner + is (ImageSizeX-0.5, ImageSizeY-0.5), more than two vertices is a + polygon as clipping path. All vertices as pixel coordinates. (read/write) + """ + return self._boundary_path + + @boundary_path.setter + def boundary_path(self, vertices: Iterable[UVec]) -> None: + self.set_boundary_path(vertices) + + def set_boundary_path(self, vertices: Iterable[UVec]) -> None: + """Set boundary path to `vertices`. Two vertices describe a rectangle + (lower left and upper right corner), more than two vertices is a polygon + as clipping path. + """ + _vertices = Vec2.list(vertices) + if len(_vertices): + if len(_vertices) > 2 and not _vertices[-1].isclose(_vertices[0]): + # Close path, otherwise AutoCAD crashes + _vertices.append(_vertices[0]) + self._boundary_path = _vertices + self.set_flag_state(self.USE_CLIPPING_BOUNDARY, state=True) + self.dxf.clipping = 1 + self.dxf.clipping_boundary_type = 1 if len(_vertices) < 3 else 2 + self.dxf.count_boundary_points = len(self._boundary_path) + else: + self.reset_boundary_path() + + def reset_boundary_path(self) -> None: + """Reset boundary path to the default rectangle [(-0.5, -0.5), + (ImageSizeX-0.5, ImageSizeY-0.5)]. + """ + lower_left_corner = Vec2(-0.5, -0.5) + upper_right_corner = Vec2(self.dxf.image_size) + lower_left_corner + self._boundary_path = [lower_left_corner, upper_right_corner] + self.set_flag_state(Image.USE_CLIPPING_BOUNDARY, state=False) + self.dxf.clipping = 0 + self.dxf.clipping_boundary_type = 1 + self.dxf.count_boundary_points = 2 + + def transform(self, m: Matrix44) -> Self: + """Transform IMAGE entity by transformation matrix `m` inplace.""" + self.dxf.insert = m.transform(self.dxf.insert) + self.dxf.u_pixel = m.transform_direction(self.dxf.u_pixel) + self.dxf.v_pixel = m.transform_direction(self.dxf.v_pixel) + self.post_transform(m) + return self + + def get_wcs_transform(self) -> Matrix44: + m = Matrix44() + m.set_row(0, Vec3(self.dxf.u_pixel)) + m.set_row(1, Vec3(self.dxf.v_pixel)) + m.set_row(3, Vec3(self.dxf.insert)) + return m + + def pixel_boundary_path(self) -> list[Vec2]: + """Returns the boundary path as closed loop in pixel coordinates. Resolves the + simple form of two vertices as a rectangle. The image coordinate system has an + inverted y-axis and the top-left corner is (0, 0). + + .. versionchanged:: 1.2.0 + + renamed from :meth:`boundray_path_ocs()` + + """ + boundary_path = self.boundary_path + if len(boundary_path) == 2: # rectangle + p0, p1 = boundary_path + boundary_path = [p0, Vec2(p1.x, p0.y), p1, Vec2(p0.x, p1.y)] + if not boundary_path[0].isclose(boundary_path[-1]): + boundary_path.append(boundary_path[0]) + return boundary_path + + def boundary_path_wcs(self) -> list[Vec3]: + """Returns the boundary/clipping path in WCS coordinates. + + It's recommended to acquire the clipping path as :class:`~ezdxf.path.Path` object + by the :func:`~ezdxf.path.make_path` function:: + + from ezdxf.path import make_path + + image = ... # get image entity + clipping_path = make_path(image) + + """ + + u = Vec3(self.dxf.u_pixel) + v = Vec3(self.dxf.v_pixel) + origin = Vec3(self.dxf.insert) + origin += u * 0.5 - v * 0.5 + height = self.dxf.image_size.y + # Boundary/Clipping path origin 0/0 is in the Left/Top corner of the image! + vertices = [ + origin + (u * p.x) + (v * (height - p.y)) + for p in self.pixel_boundary_path() + ] + return vertices + + def destroy(self) -> None: + if not self.is_alive: + return + + del self._boundary_path + super().destroy() + + +acdb_image = DefSubclass( + "AcDbRasterImage", + { + "class_version": DXFAttr(90, dxfversion=DXF2000, default=0), + "insert": DXFAttr(10, xtype=XType.point3d), + # U-vector of a single pixel (points along the visual bottom of the image, + # starting at the insertion point) + "u_pixel": DXFAttr(11, xtype=XType.point3d), + # V-vector of a single pixel (points along the visual left side of the + # image, starting at the insertion point) + "v_pixel": DXFAttr(12, xtype=XType.point3d), + # Image size in pixels + "image_size": DXFAttr(13, xtype=XType.point2d), + # Hard reference to image def object + "image_def_handle": DXFAttr(340), + # Image display properties: + # 1 = Show image + # 2 = Show image when not aligned with screen + # 4 = Use clipping boundary + # 8 = Transparency is on + "flags": DXFAttr(70, default=3), + # Clipping state: + # 0 = Off + # 1 = On + "clipping": DXFAttr( + 280, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Brightness value (0-100; default = 50) + "brightness": DXFAttr( + 281, + default=50, + validator=validator.is_in_integer_range(0, 101), + fixer=validator.fit_into_integer_range(0, 101), + ), + # Contrast value (0-100; default = 50) + "contrast": DXFAttr( + 282, + default=50, + validator=validator.is_in_integer_range(0, 101), + fixer=validator.fit_into_integer_range(0, 101), + ), + # Fade value (0-100; default = 0) + "fade": DXFAttr( + 283, + default=0, + validator=validator.is_in_integer_range(0, 101), + fixer=validator.fit_into_integer_range(0, 101), + ), + # Hard reference to image def reactor object, not required by AutoCAD + "image_def_reactor_handle": DXFAttr(360), + # Clipping boundary type: + # 1 = Rectangular + # 2 = Polygonal + "clipping_boundary_type": DXFAttr( + 71, + default=1, + validator=validator.is_one_of({1, 2}), + fixer=RETURN_DEFAULT, + ), + # Number of clip boundary vertices that follow + "count_boundary_points": DXFAttr(91), + # Clip mode: + # 0 = outside + # 1 = inside mode + "clip_mode": DXFAttr( + 290, + dxfversion=DXF2010, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # boundary path coordinates are pixel coordinates NOT drawing units + }, +) +acdb_image_group_codes = group_code_mapping(acdb_image) + + +@register_entity +class Image(ImageBase): + """DXF IMAGE entity""" + + DXFTYPE = "IMAGE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_image) + _CLS_GROUP_CODES = acdb_image_group_codes + _SUBCLASS_NAME = acdb_image.name # type: ignore + DEFAULT_ATTRIBS = {"layer": "0", "flags": 3} + + def __init__(self) -> None: + super().__init__() + self._boundary_path: list[Vec2] = [] + self._image_def: Optional[ImageDef] = None + self._image_def_reactor: Optional[ImageDefReactor] = None + + @classmethod + def new( + cls: Type[Image], + handle: Optional[str] = None, + owner: Optional[str] = None, + dxfattribs: Optional[dict] = None, + doc: Optional[Drawing] = None, + ) -> Image: + dxfattribs = dxfattribs or {} + # 'image_def' is not a real DXF attribute (image_def_handle) + image_def = dxfattribs.pop("image_def", None) + image_size = (1, 1) + if image_def and image_def.is_alive: + image_size = image_def.dxf.image_size + dxfattribs.setdefault("image_size", image_size) + + image = cast("Image", super().new(handle, owner, dxfattribs, doc)) + image.image_def = image_def + return image + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, Image) + super().copy_data(entity, copy_strategy=copy_strategy) + # Each IMAGE has its own ImageDefReactor object, which will be created by + # binding the copy to the document. + entity.dxf.discard("image_def_reactor_handle") + entity._image_def_reactor = None + # shared IMAGE_DEF + entity._image_def = self._image_def + + def post_bind_hook(self) -> None: + # Document in LOAD process -> post_load_hook() + if self.doc.is_loading: # type: ignore + return + if self._image_def_reactor: # ImageDefReactor already exist + return + # The new Image was created by ezdxf and the ImageDefReactor + # object does not exist: + self._create_image_def_reactor() + + def post_load_hook(self, doc: Drawing) -> Optional[Callable]: + super().post_load_hook(doc) + db = doc.entitydb + self._image_def = db.get(self.dxf.get("image_def_handle", None)) # type: ignore + if self._image_def is None: + # unrecoverable structure error + self.destroy() + return None + + self._image_def_reactor = db.get( # type: ignore + self.dxf.get("image_def_reactor_handle", None) + ) + if self._image_def_reactor is None: + # Image and ImageDef exist - this is recoverable by creating + # an ImageDefReactor, but the objects section does not exist yet! + # Return a post init command: + return self._fix_missing_image_def_reactor + return None + + def _fix_missing_image_def_reactor(self): + try: + self._create_image_def_reactor() + except Exception as e: + logger.exception( + f"An exception occurred while executing fixing command for " + f"{str(self)}, destroying entity.", + exc_info=e, + ) + self.destroy() + return + logger.debug(f"Created missing ImageDefReactor for {str(self)}") + + def _create_image_def_reactor(self): + # ImageDef -> ImageDefReactor -> Image + image_def_reactor = self.doc.objects.add_image_def_reactor(self.dxf.handle) + reactor_handle = image_def_reactor.dxf.handle + # Link Image to ImageDefReactor: + self.dxf.image_def_reactor_handle = reactor_handle + self._image_def_reactor = image_def_reactor + # Link ImageDef to ImageDefReactor if in same document (XREF mapping!): + if self.doc is self._image_def.doc: + self._image_def.append_reactor_handle(reactor_handle) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + if isinstance(self.image_def, ImageDef): + registry.add_handle(self.image_def.dxf.handle) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, Image) + super().map_resources(clone, mapping) + source_image_def = self.image_def + if isinstance(source_image_def, ImageDef): + name = self.get_image_def_name() + name, clone_image_def = mapping.map_acad_dict_entry( + "ACAD_IMAGE_DICT", name, source_image_def + ) + if isinstance(clone_image_def, ImageDef): + clone.image_def = clone_image_def + if isinstance(clone._image_def_reactor, ImageDefReactor): + clone_image_def.append_reactor_handle( + clone._image_def_reactor.dxf.handle + ) + # Note: + # The IMAGEDEF_REACTOR was created automatically at binding the copy to + # a new document, but the handle of the IMAGEDEF_REACTOR was not add to the + # IMAGEDEF reactor handles, because at this point the IMAGE had still a reference + # to the IMAGEDEF of the source document. + + def get_image_def_name(self) -> str: + """Returns the name of the `image_def` entry in the ACAD_IMAGE_DICT.""" + if self.doc is None: + return "" + image_dict = self.doc.rootdict.get_required_dict("ACAD_IMAGE_DICT") + for name, entry in image_dict.items(): + if entry is self._image_def: + return name + return "" + + @property + def image_def(self) -> Optional[ImageDef]: + """Returns the associated IMAGEDEF entity, see :class:`ImageDef`.""" + return self._image_def + + @image_def.setter + def image_def(self, image_def: ImageDef) -> None: + if image_def and image_def.is_alive: + self.dxf.image_def_handle = image_def.dxf.handle + self._image_def = image_def + else: + self.dxf.discard("image_def_handle") + self._image_def = None + + @property + def image_def_reactor(self) -> Optional[ImageDefReactor]: + """Returns the associated IMAGEDEF_REACTOR entity.""" + return self._image_def_reactor + + def destroy(self) -> None: + if not self.is_alive: + return + + reactor = self._image_def_reactor + if reactor and reactor.is_alive: + image_def = self.image_def + if image_def and image_def.is_alive: + image_def.discard_reactor_handle(reactor.dxf.handle) + reactor.destroy() + super().destroy() + + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + + +# DXF reference error: Subclass marker (AcDbRasterImage) +acdb_wipeout = DefSubclass("AcDbWipeout", dict(acdb_image.attribs)) +acdb_wipeout_group_codes = group_code_mapping(acdb_wipeout) + + +@register_entity +class Wipeout(ImageBase): + """DXF WIPEOUT entity""" + + DXFTYPE = "WIPEOUT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_wipeout) + DEFAULT_ATTRIBS = { + "layer": "0", + "flags": 7, + "clipping": 1, + "brightness": 50, + "contrast": 50, + "fade": 0, + "image_size": (1, 1), + "image_def_handle": "0", # has no ImageDef() + "image_def_reactor_handle": "0", # has no ImageDefReactor() + "clip_mode": 0, + } + _CLS_GROUP_CODES = acdb_wipeout_group_codes + _SUBCLASS_NAME = acdb_wipeout.name # type: ignore + + def set_masking_area(self, vertices: Iterable[UVec]) -> None: + """Set a new masking area, the area is placed in the layout xy-plane.""" + self.update_dxf_attribs(self.DEFAULT_ATTRIBS) + vertices = Vec2.list(vertices) + bounds = BoundingBox2d(vertices) + x_size, y_size = bounds.size + + dxf = self.dxf + dxf.insert = Vec3(bounds.extmin) + dxf.u_pixel = Vec3(x_size, 0, 0) + dxf.v_pixel = Vec3(0, y_size, 0) + + def boundary_path(): + extmin = bounds.extmin + for vertex in vertices: + v = vertex - extmin + yield Vec2(v.x / x_size - 0.5, 0.5 - v.y / y_size) + + self.set_boundary_path(boundary_path()) + + def _reset_handles(self): + self.dxf.image_def_reactor_handle = "0" + self.dxf.image_def_handle = "0" + + def audit(self, auditor: Auditor) -> None: + self._reset_handles() + super().audit(auditor) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + self._reset_handles() + super().export_entity(tagwriter) + + +# About Image File Paths: +# See notes in knowledge graph: [[IMAGE File Paths]] +# https://ezdxf.mozman.at/notes/#/page/image%20file%20paths + +acdb_image_def = DefSubclass( + "AcDbRasterImageDef", + { + "class_version": DXFAttr(90, default=0), + # File name of image: + "filename": DXFAttr(1), + # Image size in pixels: + "image_size": DXFAttr(10, xtype=XType.point2d), + # Default size of one pixel in AutoCAD units: + "pixel_size": DXFAttr(11, xtype=XType.point2d, default=Vec2(0.01, 0.01)), + "loaded": DXFAttr(280, default=1), + # Resolution units - this enums differ from the usual drawing units, + # units.py, same as for RasterVariables.dxf.units, but only these 3 values + # are valid - confirmed by ODA Specs 20.4.81 IMAGEDEF: + # 0 = No units + # 2 = Centimeters + # 5 = Inch + "resolution_units": DXFAttr( + 281, + default=0, + validator=validator.is_one_of({0, 2, 5}), + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_image_def_group_codes = group_code_mapping(acdb_image_def) + + +@register_entity +class ImageDef(DXFObject): + """DXF IMAGEDEF entity""" + + DXFTYPE = "IMAGEDEF" + DXFATTRIBS = DXFAttributes(base_class, acdb_image_def) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_image_def_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_image_def.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "class_version", + "filename", + "image_size", + "pixel_size", + "loaded", + "resolution_units", + ], + ) + + +acdb_image_def_reactor = DefSubclass( + "AcDbRasterImageDefReactor", + { + "class_version": DXFAttr(90, default=2), + # Handle to image: + "image_handle": DXFAttr(330), + }, +) +acdb_image_def_reactor_group_codes = group_code_mapping(acdb_image_def_reactor) + + +@register_entity +class ImageDefReactor(DXFObject): + """DXF IMAGEDEF_REACTOR entity""" + + DXFTYPE = "IMAGEDEF_REACTOR" + DXFATTRIBS = DXFAttributes(base_class, acdb_image_def_reactor) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_image_def_reactor_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_image_def_reactor.name) + tagwriter.write_tag2(90, self.dxf.class_version) + tagwriter.write_tag2(330, self.dxf.image_handle) + + +acdb_raster_variables = DefSubclass( + "AcDbRasterVariables", + { + "class_version": DXFAttr(90, default=0), + # Frame: + # 0 = no frame + # 1 = show frame + "frame": DXFAttr( + 70, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Quality: + # 0 = draft + # 1 = high + "quality": DXFAttr( + 71, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Units: + # 0 = None + # 1 = mm + # 2 = cm + # 3 = m + # 4 = km + # 5 = in + # 6 = ft + # 7 = yd + # 8 = mi + "units": DXFAttr( + 72, + default=3, + validator=validator.is_in_integer_range(0, 9), + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_raster_variables_group_codes = group_code_mapping(acdb_raster_variables) + + +@register_entity +class RasterVariables(DXFObject): + """DXF RASTERVARIABLES entity""" + + DXFTYPE = "RASTERVARIABLES" + DXFATTRIBS = DXFAttributes(base_class, acdb_raster_variables) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_raster_variables_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_raster_variables.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "class_version", + "frame", + "quality", + "units", + ], + ) + + +acdb_wipeout_variables = DefSubclass( + "AcDbWipeoutVariables", + { + # Display-image-frame flag: + # 0 = No frame + # 1 = Display frame + "frame": DXFAttr( + 70, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_wipeout_variables_group_codes = group_code_mapping(acdb_wipeout_variables) + + +@register_entity +class WipeoutVariables(DXFObject): + """DXF WIPEOUTVARIABLES entity""" + + DXFTYPE = "WIPEOUTVARIABLES" + DXFATTRIBS = DXFAttributes(base_class, acdb_wipeout_variables) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_wipeout_variables_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_wipeout_variables.name) + self.dxf.export_dxf_attribs(tagwriter, "frame") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/insert.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/insert.py new file mode 100644 index 0000000..a259d30 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/insert.py @@ -0,0 +1,766 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + cast, + Union, + Optional, + Callable, +) +from typing_extensions import Self +import math +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import ( + DXF12, + SUBCLASS_MARKER, + DXFValueError, + DXFKeyError, + DXFStructureError, +) +from ezdxf.math import ( + Vec3, + UVec, + X_AXIS, + Y_AXIS, + Z_AXIS, + Matrix44, + UCS, + NULLVEC, +) +from ezdxf.math.transformtools import ( + InsertTransformationError, + InsertCoordinateSystem, +) +from ezdxf.explode import ( + explode_block_reference, + virtual_block_reference_entities, +) +from ezdxf.entities import factory +from ezdxf.query import EntityQuery +from ezdxf.audit import AuditError +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + elevation_to_z_axis, + acdb_entity_group_codes, +) +from .subentity import LinkedEntities +from .attrib import Attrib + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFNamespace, AttDef, DXFEntity + from ezdxf.layouts import BaseLayout, BlockLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["Insert"] + +ABS_TOL = 1e-9 + +# DXF files as XREF: +# The INSERT entity is used to attach XREFS. +# The model space is the block content, if the whole document is used as +# BLOCK (XREF), but this is only supported for the DWG format. +# AutoCAD does not support DXF files as XREFS, they are ignored, but the DXF +# file is valid! BricsCAD shows DXF files as XREFS, but does not allow to attach +# DXF files as XREFS by the application itself. + +# Multi-INSERT has subclass id AcDbMInsertBlock +acdb_block_reference = DefSubclass( + "AcDbBlockReference", + { + "attribs_follow": DXFAttr(66, default=0, optional=True), + "name": DXFAttr(2, validator=validator.is_valid_block_name), + "insert": DXFAttr(10, xtype=XType.any_point), + # Elevation is a legacy feature from R11 and prior, do not use this + # attribute, store the entity elevation in the z-axis of the vertices. + # ezdxf does not export the elevation attribute! + "elevation": DXFAttr(38, default=0, optional=True), + "xscale": DXFAttr( + 41, + default=1, + optional=True, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + "yscale": DXFAttr( + 42, + default=1, + optional=True, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + "zscale": DXFAttr( + 43, + default=1, + optional=True, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + "rotation": DXFAttr(50, default=0, optional=True), + "column_count": DXFAttr( + 70, + default=1, + optional=True, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + "row_count": DXFAttr( + 71, + default=1, + optional=True, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + "column_spacing": DXFAttr(44, default=0, optional=True), + "row_spacing": DXFAttr(45, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_block_reference_group_codes = group_code_mapping(acdb_block_reference) +merged_insert_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_block_reference_group_codes # type: ignore +) + + +# Notes to SEQEND: +# +# The INSERT entity requires only a SEQEND if ATTRIB entities are attached. +# So a loaded INSERT could have a missing SEQEND. +# +# A bounded INSERT needs a SEQEND to be valid at export if there are attached +# ATTRIB entities, but the LinkedEntities.post_bind_hook() method creates +# always a new SEQEND after binding the INSERT entity to a document. +# +# Nonetheless, the Insert.add_attrib() method also creates the required SEQEND entity if +# necessary. + + +@factory.register_entity +class Insert(LinkedEntities): + """DXF INSERT entity + + The INSERT entity is hard owner of its ATTRIB entities and the SEQEND entity: + + ATTRIB.dxf.owner == INSERT.dxf.handle + SEQEND.dxf.owner == INSERT.dxf.handle + + Note: + + The ATTDEF entity in block definitions is owned by the BLOCK_RECORD like + all graphical entities. + + """ + + DXFTYPE = "INSERT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_block_reference) + + @property + def attribs(self) -> list[Attrib]: + return self._sub_entities # type: ignore + + @property + def attribs_follow(self) -> bool: + return bool(len(self.attribs)) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_insert_group_codes) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("insert",)) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + if (self.dxf.column_count > 1) or (self.dxf.row_count > 1): + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbMInsertBlock") + else: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbBlockReference") + if self.attribs_follow: + tagwriter.write_tag2(66, 1) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "insert", + "xscale", + "yscale", + "zscale", + "rotation", + "column_count", + "row_count", + "column_spacing", + "row_spacing", + "extrusion", + ], + ) + + def export_dxf(self, tagwriter: AbstractTagWriter): + super().export_dxf(tagwriter) + # Do no export SEQEND if no ATTRIBS attached: + if self.attribs_follow: + self.process_sub_entities(lambda e: e.export_dxf(tagwriter)) + + def register_resources(self, registry: xref.Registry) -> None: + # The attached ATTRIB entities are registered by the parent class LinkedEntities + super().register_resources(registry) + registry.add_block_name(self.dxf.name) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + # The attached ATTRIB entities are mapped by the parent class LinkedEntities + super().map_resources(clone, mapping) + clone.dxf.name = mapping.get_block_name(self.dxf.name) + + @property + def has_scaling(self) -> bool: + """Returns ``True`` if scaling is applied to any axis.""" + if self.dxf.hasattr("xscale") and self.dxf.xscale != 1: + return True + if self.dxf.hasattr("yscale") and self.dxf.yscale != 1: + return True + if self.dxf.hasattr("zscale") and self.dxf.zscale != 1: + return True + return False + + @property + def has_uniform_scaling(self) -> bool: + """Returns ``True`` if the scale factor is uniform for x-, y- and z-axis, + ignoring reflections e.g. (1, 1, -1) is uniform scaling. + + """ + return abs(self.dxf.xscale) == abs(self.dxf.yscale) == abs(self.dxf.zscale) + + def set_scale(self, factor: float): + """Set a uniform scale factor.""" + if factor == 0: + raise ValueError("Invalid scale factor.") + self.dxf.xscale = factor + self.dxf.yscale = factor + self.dxf.zscale = factor + return self + + def block(self) -> Optional[BlockLayout]: + """Returns the associated :class:`~ezdxf.layouts.BlockLayout`.""" + if self.doc: + return self.doc.blocks.get(self.dxf.name) + return None + + def is_xref(self) -> bool: + """Return ``True`` if the INSERT entity represents a XREF or XREF_OVERLAY.""" + block = self.block() + if block is not None: + return block.block_record.is_xref + return False + + def place( + self, + insert: Optional[UVec] = None, + scale: Optional[tuple[float, float, float]] = None, + rotation: Optional[float] = None, + ) -> Insert: + """ + Set the location, scaling and rotation attributes. Arguments which are ``None`` + will be ignored. + + Args: + insert: insert location as (x, y [,z]) tuple + scale: (x-scale, y-scale, z-scale) tuple + rotation : rotation angle in degrees + + """ + if insert is not None: + self.dxf.insert = insert + if scale is not None: + if len(scale) != 3: + raise DXFValueError("Argument scale has to be a (x, y[, z]) tuple.") + x, y, z = scale + self.dxf.xscale = x + self.dxf.yscale = y + self.dxf.zscale = z + if rotation is not None: + self.dxf.rotation = rotation + return self + + def grid( + self, size: tuple[int, int] = (1, 1), spacing: tuple[float, float] = (1, 1) + ) -> Insert: + """Place block reference in a grid layout, grid `size` defines the + row- and column count, `spacing` defines the distance between two block + references. + + Args: + size: grid size as (row_count, column_count) tuple + spacing: distance between placing as (row_spacing, column_spacing) tuple + + """ + try: + rows, cols = size + except ValueError: + raise DXFValueError("Size has to be a (row_count, column_count) tuple.") + self.dxf.row_count = rows + self.dxf.column_count = cols + try: + row_spacing, col_spacing = spacing + except ValueError: + raise DXFValueError( + "Spacing has to be a (row_spacing, column_spacing) tuple." + ) + self.dxf.row_spacing = row_spacing + self.dxf.column_spacing = col_spacing + return self + + def get_attrib( + self, tag: str, search_const: bool = False + ) -> Optional[Union[Attrib, AttDef]]: + """Get an attached :class:`Attrib` entity with the given `tag`, + returns ``None`` if not found. Some applications do not attach constant + ATTRIB entities, set `search_const` to ``True``, to get at least the + associated :class:`AttDef` entity. + + Args: + tag: tag name of the ATTRIB entity + search_const: search also const ATTDEF entities + + """ + for attrib in self.attribs: + if tag == attrib.dxf.tag: + return attrib + if search_const and self.doc is not None: + block = self.doc.blocks[self.dxf.name] + for attdef in block.get_const_attdefs(): + if tag == attdef.dxf.tag: + return attdef + return None + + def get_attrib_text( + self, tag: str, default: str = "", search_const: bool = False + ) -> str: + """Get content text of an attached :class:`Attrib` entity with + the given `tag`, returns the `default` value if not found. + Some applications do not attach constant ATTRIB entities, set + `search_const` to ``True``, to get content text of the + associated :class:`AttDef` entity. + + Args: + tag: tag name of the ATTRIB entity + default: default value if ATTRIB `tag` is absent + search_const: search also const ATTDEF entities + + """ + attrib = self.get_attrib(tag, search_const) + if attrib is None: + return default + return attrib.dxf.text + + def has_attrib(self, tag: str, search_const: bool = False) -> bool: + """Returns ``True`` if the INSERT entity has an attached ATTRIB entity with the + given `tag`. Some applications do not attach constant ATTRIB entities, set + `search_const` to ``True``, to check for an associated :class:`AttDef` entity + with constant content. + + + Args: + tag: tag name fo the ATTRIB entity + search_const: search also const ATTDEF entities + + """ + return self.get_attrib(tag, search_const) is not None + + def add_attrib( + self, tag: str, text: str, insert: UVec = (0, 0), dxfattribs=None + ) -> Attrib: + """Attach an :class:`Attrib` entity to the block reference. + + Example for appending an attribute to an INSERT entity:: + + e.add_attrib('EXAMPLETAG', 'example text').set_placement( + (3, 7), align=TextEntityAlignment.MIDDLE_CENTER + ) + + Args: + tag: tag name of the ATTRIB entity + text: content text as string + insert: insert location as (x, y[, z]) tuple in :ref:`OCS` + dxfattribs: additional DXF attributes for the ATTRIB entity + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["tag"] = tag + dxfattribs["text"] = text + dxfattribs["insert"] = insert + attrib = cast("Attrib", self._new_compound_entity("ATTRIB", dxfattribs)) + self.attribs.append(attrib) + + # This case is only possible if the INSERT was read from a file without + # attached ATTRIB entities: + if self.seqend is None: + self.new_seqend() + return attrib + + def delete_attrib(self, tag: str, ignore=False) -> None: + """Delete an attached :class:`Attrib` entity from INSERT. Raises an + :class:`DXFKeyError` exception, if no ATTRIB for the given `tag` exist if + `ignore` is ``False``. + + Args: + tag: tag name of the ATTRIB entity + ignore: ``False`` for raising :class:`DXFKeyError` if ATTRIB `tag` + does not exist. + + Raises: + DXFKeyError: no ATTRIB for the given `tag` exist + + """ + for index, attrib in enumerate(self.attribs): + if attrib.dxf.tag == tag: + del self.attribs[index] + attrib.destroy() + return + if not ignore: + raise DXFKeyError(tag) + + def delete_all_attribs(self) -> None: + """Delete all :class:`Attrib` entities attached to the INSERT entity.""" + if not self.is_alive: + return + + for attrib in self.attribs: + attrib.destroy() + self._sub_entities = [] + + def transform(self, m: Matrix44) -> Insert: + """Transform INSERT entity by transformation matrix `m` inplace. + + Unlike the transformation matrix `m`, the INSERT entity can not + represent a non-orthogonal target coordinate system and an + :class:`InsertTransformationError` will be raised in that case. + + """ + dxf = self.dxf + source_system = InsertCoordinateSystem( + insert=Vec3(dxf.insert), + scale=(dxf.xscale, dxf.yscale, dxf.zscale), + rotation=dxf.rotation, + extrusion=dxf.extrusion, + ) + try: + target_system = source_system.transform(m, ABS_TOL) + except InsertTransformationError: + raise InsertTransformationError( + "INSERT entity can not represent a non-orthogonal target coordinate system." + ) + dxf.insert = target_system.insert + dxf.rotation = target_system.rotation + dxf.extrusion = target_system.extrusion + dxf.xscale = target_system.scale_factor_x + dxf.yscale = target_system.scale_factor_y + dxf.zscale = target_system.scale_factor_z + + for attrib in self.attribs: + attrib.transform(m) + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> Insert: + """Optimized INSERT translation about `dx` in x-axis, `dy` in y-axis + and `dz` in z-axis. + + """ + ocs = self.ocs() + self.dxf.insert = ocs.from_wcs(Vec3(dx, dy, dz) + ocs.to_wcs(self.dxf.insert)) + for attrib in self.attribs: + attrib.translate(dx, dy, dz) + return self + + def matrix44(self) -> Matrix44: + """Returns a transformation matrix to transform the block entities from the + block reference coordinate system into the :ref:`WCS`. + """ + dxf = self.dxf + sx = dxf.xscale + sy = dxf.yscale + sz = dxf.zscale + + ocs = self.ocs() + extrusion = ocs.uz + ux = Vec3(ocs.to_wcs(X_AXIS)) + uy = Vec3(ocs.to_wcs(Y_AXIS)) + m = Matrix44.ucs(ux=ux * sx, uy=uy * sy, uz=extrusion * sz) + # same as Matrix44.ucs(ux, uy, extrusion) * Matrix44.scale(sx, sy, sz) + + angle = math.radians(dxf.rotation) + if angle: + m *= Matrix44.axis_rotate(extrusion, angle) + + insert = ocs.to_wcs(dxf.get("insert", NULLVEC)) + + block_layout = self.block() + if block_layout is not None: + # transform block base point into WCS without translation + insert -= m.transform_direction(block_layout.block.dxf.base_point) # type: ignore + + # set translation + m.set_row(3, insert.xyz) + return m + + def ucs(self): + """Returns the block reference coordinate system as :class:`ezdxf.math.UCS` + object. + """ + m = self.matrix44() + ucs = UCS() + ucs.matrix = m + return ucs + + def reset_transformation(self) -> None: + """Reset block reference attributes location, rotation angle and + the extrusion vector but preserves the scale factors. + + """ + self.dxf.insert = NULLVEC + self.dxf.discard("rotation") + self.dxf.discard("extrusion") + + def explode( + self, target_layout: Optional[BaseLayout] = None, *, redraw_order=False + ) -> EntityQuery: + """Explodes the block reference entities into the target layout, if target + layout is ``None``, the layout of the block reference will be used. + This method destroys the source block reference entity. + + Transforms the block entities into the required :ref:`WCS` location by + applying the block reference attributes `insert`, `extrusion`, + `rotation` and the scale factors `xscale`, `yscale` and `zscale`. + + Attached ATTRIB entities are converted to TEXT entities, this is the + behavior of the BURST command of the AutoCAD Express Tools. + + .. warning:: + + **Non-uniform scale factors** may lead to incorrect results some entities + (TEXT, MTEXT, ATTRIB). + + Args: + target_layout: target layout for exploded entities, ``None`` for + same layout as source entity. + redraw_order: create entities in ascending redraw order if ``True`` + + Returns: + :class:`~ezdxf.query.EntityQuery` container referencing all exploded + DXF entities. + + """ + if target_layout is None: + target_layout = self.get_layout() + if target_layout is None: + raise DXFStructureError( + "INSERT without layout assignment, specify target layout" + ) + return explode_block_reference( + self, target_layout=target_layout, redraw_order=redraw_order + ) + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol. + + This protocol is for consistent internal usage and does not replace + the method :meth:`virtual_entities`! Ignores the redraw-order! + """ + return self.virtual_entities() + + def virtual_entities( + self, + *, + skipped_entity_callback: Optional[Callable[[DXFGraphic, str], None]] = None, + redraw_order=False, + ) -> Iterator[DXFGraphic]: + """ + Yields the transformed referenced block content as virtual entities. + + This method is meant to examine the block reference entities at the target + location without exploding the block reference. + These entities are not stored in the entity database, have no handle and + are not assigned to any layout. It is possible to convert these entities + into regular drawing entities by adding the entities to the entities + database and a layout of the same DXF document as the block reference:: + + doc.entitydb.add(entity) + msp = doc.modelspace() + msp.add_entity(entity) + + .. warning:: + + **Non-uniform scale factors** may return incorrect results for some entities + (TEXT, MTEXT, ATTRIB). + + This method does not resolve the MINSERT attributes, only the + sub-entities of the first INSERT will be returned. To resolve MINSERT + entities check if multi insert processing is required, that's the case + if the property :attr:`Insert.mcount` > 1, use the :meth:`Insert.multi_insert` + method to resolve the MINSERT entity into multiple INSERT entities. + + This method does not apply the clipping path created by the XCLIP command. + The method returns all entities and ignores the clipping path polygon and no + entity is clipped. + + The `skipped_entity_callback()` will be called for all entities which are not + processed, signature: + :code:`skipped_entity_callback(entity: DXFEntity, reason: str)`, + `entity` is the original (untransformed) DXF entity of the block definition, the + `reason` string is an explanation why the entity was skipped. + + Args: + skipped_entity_callback: called whenever the transformation of an + entity is not supported and so was skipped + redraw_order: yield entities in ascending redraw order if ``True`` + + """ + for e in virtual_block_reference_entities( + self, + skipped_entity_callback=skipped_entity_callback, + redraw_order=redraw_order, + ): + e.set_source_block_reference(self) + yield e + + @property + def mcount(self) -> int: + """Returns the multi-insert count, MINSERT (multi-insert) processing + is required if :attr:`mcount` > 1. + + """ + return (self.dxf.row_count if self.dxf.row_spacing else 1) * ( + self.dxf.column_count if self.dxf.column_spacing else 1 + ) + + def multi_insert(self) -> Iterator[Insert]: + """Yields a virtual INSERT entity for each grid element of a MINSERT + entity (multi-insert). + """ + + def transform_attached_attrib_entities(insert, offset): + for attrib in insert.attribs: + attrib.dxf.insert += offset + + def adjust_dxf_attribs(insert, offset): + dxf = insert.dxf + dxf.insert += offset + dxf.discard("row_count") + dxf.discard("column_count") + dxf.discard("row_spacing") + dxf.discard("column_spacing") + + done = set() + row_spacing = self.dxf.row_spacing + col_spacing = self.dxf.column_spacing + rotation = self.dxf.rotation + for row in range(self.dxf.row_count): + for col in range(self.dxf.column_count): + # All transformations in OCS: + offset = Vec3(col * col_spacing, row * row_spacing) + # If any spacing is 0, yield only unique locations: + if offset not in done: + done.add(offset) + if rotation: # Apply rotation to the grid. + offset = offset.rotate_deg(rotation) + # Do not apply scaling to the grid! + insert = self.copy() + adjust_dxf_attribs(insert, offset) + transform_attached_attrib_entities(insert, offset) + yield insert + + def add_auto_attribs(self, values: dict[str, str]) -> Insert: + """ + Attach for each :class:`~ezdxf.entities.Attdef` entity, defined in the + block definition, automatically an :class:`Attrib` entity to the block + reference and set ``tag/value`` DXF attributes of the ATTRIB entities + by the ``key/value`` pairs (both as strings) of the `values` dict. + The ATTRIB entities are placed relative to the insert location of the + block reference, which is identical to the block base point. + + This method avoids the wrapper block of the + :meth:`~ezdxf.layouts.BaseLayout.add_auto_blockref` method, but the + visual results may not match the results of CAD applications, especially + for non-uniform scaling. If the visual result is very important to you, + use the :meth:`add_auto_blockref` method. + + Args: + values: :class:`~ezdxf.entities.Attrib` tag values as ``tag/value`` + pairs + + """ + + def unpack(dxfattribs) -> tuple[str, str, UVec]: + tag = dxfattribs.pop("tag") + text = values.get(tag, "") + location = dxfattribs.pop("insert") + return tag, text, location + + def autofill() -> None: + for attdef in block_layout.attdefs(): # type: ignore + dxfattribs = attdef.dxfattribs(drop={"prompt", "handle"}) + tag, text, location = unpack(dxfattribs) + attrib = self.add_attrib(tag, text, location, dxfattribs) + attrib.transform(m) + + block_layout = self.block() + if block_layout is not None: + m = self.matrix44() + autofill() + return self + + def audit(self, auditor: Auditor) -> None: + """Validity check.""" + super().audit(auditor) + doc = auditor.doc + if doc and doc.blocks: + name = self.dxf.name + if name is None: + auditor.fixed_error( + code=AuditError.UNDEFINED_BLOCK_NAME, + message=f"Deleted entity {str(self)} without a BLOCK name", + ) + auditor.trash(self) + elif name not in doc.blocks: + auditor.fixed_error( + code=AuditError.UNDEFINED_BLOCK, + message=f"Deleted entity {str(self)} without required BLOCK" + f" definition.", + ) + auditor.trash(self) + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for the "ReferencedBlocks" protocol.""" + block = self.block() + if block is not None: + return (block.block_record_handle,) + return tuple() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/layer.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/layer.py new file mode 100644 index 0000000..08d4506 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/layer.py @@ -0,0 +1,794 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, cast, Any +from typing_extensions import Self +import logging +from dataclasses import dataclass +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf import colors as clr +from ezdxf.lldxf import const +from ezdxf.lldxf.const import ( + DXF12, + SUBCLASS_MARKER, + DXF2000, + DXF2007, + DXF2004, + INVALID_NAME_CHARACTERS, + DXFValueError, + LINEWEIGHT_BYBLOCK, + LINEWEIGHT_BYLAYER, + LINEWEIGHT_DEFAULT, +) +from ezdxf.audit import AuditError +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, Viewport, XRecord + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entitydb import EntityDB + from ezdxf import xref + from ezdxf.audit import Auditor + + +__all__ = ["Layer", "acdb_symbol_table_record", "LayerOverrides"] +logger = logging.getLogger("ezdxf") + + +def is_valid_layer_color_index(aci: int) -> bool: + # BYBLOCK or BYLAYER is not valid a layer color! + return (-256 < aci < 256) and aci != 0 + + +def fix_layer_color(aci: int) -> int: + return aci if is_valid_layer_color_index(aci) else 7 + + +def is_valid_layer_lineweight(lw: int) -> bool: + if validator.is_valid_lineweight(lw): + if lw not in (LINEWEIGHT_BYLAYER, LINEWEIGHT_BYBLOCK): + return True + return False + + +def fix_layer_lineweight(lw: int) -> int: + if lw in (LINEWEIGHT_BYLAYER, LINEWEIGHT_BYBLOCK): + return LINEWEIGHT_DEFAULT + else: + return validator.fix_lineweight(lw) + + +acdb_symbol_table_record: DefSubclass = DefSubclass("AcDbSymbolTableRecord", {}) + +acdb_layer_table_record = DefSubclass( + "AcDbLayerTableRecord", + { + # Layer name as string + "name": DXFAttr(2, validator=validator.is_valid_layer_name), + "flags": DXFAttr(70, default=0), + # ACI color index, color < 0 indicates layer status: off + "color": DXFAttr( + 62, + default=7, + validator=is_valid_layer_color_index, + fixer=fix_layer_color, + ), + # True color as 24 bit int value: 0x00RRGGBB + "true_color": DXFAttr(420, dxfversion=DXF2004, optional=True), + # Linetype name as string + "linetype": DXFAttr( + 6, default="Continuous", validator=validator.is_valid_table_name + ), + # 0 = don't plot layer; 1 = plot layer + "plot": DXFAttr( + 290, + default=1, + dxfversion=DXF2000, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Default lineweight 1/100 mm, min 0 = 0.0mm, max 211 = 2.11mm + "lineweight": DXFAttr( + 370, + default=LINEWEIGHT_DEFAULT, + dxfversion=DXF2000, + validator=is_valid_layer_lineweight, + fixer=fix_layer_lineweight, + ), + # Handle to PlotStyleName, group code 390 is required by AutoCAD + "plotstyle_handle": DXFAttr(390, dxfversion=DXF2000), + # Handle to Material object + "material_handle": DXFAttr(347, dxfversion=DXF2007), + # Handle to ??? + "unknown1": DXFAttr(348, dxfversion=DXF2007, optional=True), + }, +) +acdb_layer_table_record_group_codes = group_code_mapping(acdb_layer_table_record) +AcAecLayerStandard = "AcAecLayerStandard" +AcCmTransparency = "AcCmTransparency" + + +@register_entity +class Layer(DXFEntity): + """DXF LAYER entity""" + + DXFTYPE = "LAYER" + DXFATTRIBS = DXFAttributes( + base_class, acdb_symbol_table_record, acdb_layer_table_record + ) + DEFAULT_ATTRIBS = {"name": "0"} + FROZEN = 0b00000001 + THAW = 0b11111110 + LOCK = 0b00000100 + UNLOCK = 0b11111011 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader( + dxf, acdb_layer_table_record_group_codes # type: ignore + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_layer_table_record.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "flags", + "color", + "true_color", + "linetype", + "plot", + "lineweight", + "plotstyle_handle", + "material_handle", + "unknown1", + ], + ) + + def set_required_attributes(self): + assert self.doc is not None, "valid DXF document required" + if not self.dxf.hasattr("material_handle"): + global_ = self.doc.materials["Global"] + if isinstance(global_, DXFEntity): + handle = global_.dxf.handle + else: + handle = global_ + self.dxf.material_handle = handle + if not self.dxf.hasattr("plotstyle_handle"): + normal = self.doc.plotstyles["Normal"] + if isinstance(normal, DXFEntity): + handle = normal.dxf.handle + else: + handle = normal + self.dxf.plotstyle_handle = handle + + def is_frozen(self) -> bool: + """Returns ``True`` if layer is frozen.""" + return self.dxf.flags & Layer.FROZEN > 0 + + def freeze(self) -> None: + """Freeze layer.""" + self.dxf.flags = self.dxf.flags | Layer.FROZEN + + def thaw(self) -> None: + """Thaw layer.""" + self.dxf.flags = self.dxf.flags & Layer.THAW + + def is_locked(self) -> bool: + """Returns ``True`` if layer is locked.""" + return self.dxf.flags & Layer.LOCK > 0 + + def lock(self) -> None: + """Lock layer, entities on this layer are not editable - just important + in CAD applications. + """ + self.dxf.flags = self.dxf.flags | Layer.LOCK + + def unlock(self) -> None: + """Unlock layer, entities on this layer are editable - just important + in CAD applications. + """ + self.dxf.flags = self.dxf.flags & Layer.UNLOCK + + def is_off(self) -> bool: + """Returns ``True`` if layer is off.""" + return self.dxf.color < 0 + + def is_on(self) -> bool: + """Returns ``True`` if layer is on.""" + return not self.is_off() + + def on(self) -> None: + """Switch layer `on` (visible).""" + self.dxf.color = abs(self.dxf.color) + + def off(self) -> None: + """Switch layer `off` (invisible).""" + self.dxf.color = -abs(self.dxf.color) + + def get_color(self) -> int: + """Get layer color, safe method for getting the layer color, because + :attr:`dxf.color` is negative for layer status `off`. + """ + return abs(self.dxf.color) + + def set_color(self, color: int) -> None: + """Set layer color, safe method for setting the layer color, because + :attr:`dxf.color` is negative for layer status `off`. + """ + color = abs(color) if self.is_on() else -abs(color) + self.dxf.color = color + + @property + def rgb(self) -> Optional[tuple[int, int, int]]: + """Returns RGB true color as (r, g, b)-tuple or None if attribute + dxf.true_color is not set. + """ + if self.dxf.hasattr("true_color"): + return clr.int2rgb(self.dxf.get("true_color")) + else: + return None + + @rgb.setter + def rgb(self, rgb: tuple[int, int, int]) -> None: + """Set RGB true color as (r, g, b)-tuple e.g. (12, 34, 56).""" + self.dxf.set("true_color", clr.rgb2int(rgb)) + + @property + def color(self) -> int: + """Get layer color, safe method for getting the layer color, because + :attr:`dxf.color` is negative for layer status `off`. + """ + return self.get_color() + + @color.setter + def color(self, value: int) -> None: + """Set layer color, safe method for setting the layer color, because + :attr:`dxf.color` is negative for layer status `off`. + """ + self.set_color(value) + + @property + def description(self) -> str: + try: + xdata = self.get_xdata(AcAecLayerStandard) + except DXFValueError: + return "" + else: + if len(xdata) > 1: + # this is the usual case in BricsCAD + return xdata[1].value + else: + return "" + + @description.setter + def description(self, value: str) -> None: + # create AppID table entry if not present + if self.doc and AcAecLayerStandard not in self.doc.appids: + self.doc.appids.new(AcAecLayerStandard) + self.discard_xdata(AcAecLayerStandard) + self.set_xdata(AcAecLayerStandard, [(1000, ""), (1000, value)]) + + @property + def transparency(self) -> float: + try: + xdata = self.get_xdata(AcCmTransparency) + except DXFValueError: + return 0.0 + else: + t = xdata[0].value + if t & 0x2000000: # is this a real transparency value? + # Transparency BYBLOCK (0x01000000) make no sense for a layer!? + return clr.transparency2float(t) + return 0.0 + + @transparency.setter + def transparency(self, value: float) -> None: + # create AppID table entry if not present + if self.doc and AcCmTransparency not in self.doc.appids: + self.doc.appids.new(AcCmTransparency) + if 0 <= value <= 1: + self.discard_xdata(AcCmTransparency) + self.set_xdata(AcCmTransparency, [(1071, clr.float2transparency(value))]) + else: + raise ValueError("Value out of range [0, 1].") + + def rename(self, name: str) -> None: + """ + Rename layer and all known (documented) references to this layer. + + .. warning:: + + The DXF format is not consistent in storing layer references, the + layers are mostly referenced by their case-insensitive name, + some later introduced entities do reference layers by handle, which + is the safer way in the context of renaming layers. + + There is no complete overview of where layer references are + stored, third-party entities are black-boxes with unknown content + and layer names could be stored in the extended data section of any + DXF entity or in XRECORD entities. + Which means that in some rare cases references to the old layer name + can persist, at least this does not invalidate the DXF document. + + Args: + name: new layer name + + Raises: + ValueError: `name` contains invalid characters: <>/\\":;?*|=` + ValueError: layer `name` already exist + ValueError: renaming of layers ``'0'`` and ``'DEFPOINTS'`` not + possible + + """ + if not validator.is_valid_layer_name(name): + raise ValueError( + f"Name contains invalid characters: {INVALID_NAME_CHARACTERS}." + ) + assert self.doc is not None, "valid DXF document is required" + layers = self.doc.layers + if self.dxf.name.lower() in ("0", "defpoints"): + raise ValueError(f'Can not rename layer "{self.dxf.name}".') + if layers.has_entry(name): + raise ValueError(f'Layer "{name}" already exist.') + old = self.dxf.name + self.dxf.name = name + layers.replace(old, self) + self._rename_layer_references(old, name) + + def _rename_layer_references(self, old_name: str, new_name: str) -> None: + assert self.doc is not None, "valid DXF document is required" + key = self.doc.layers.key + old_key = key(old_name) + for e in self.doc.entitydb.values(): + if e.dxf.hasattr("layer") and key(e.dxf.layer) == old_key: + e.dxf.layer = new_name + entity_type = e.dxftype() + if entity_type == "VIEWPORT": + e.rename_frozen_layer(old_name, new_name) # type: ignore + elif entity_type == "LAYER_FILTER": + # todo: if LAYER_FILTER implemented, add support for + # renaming layers + logger.debug( + f'renaming layer "{old_name}" - document contains ' f"LAYER_FILTER" + ) + elif entity_type == "LAYER_INDEX": + # todo: if LAYER_INDEX implemented, add support for + # renaming layers + logger.debug( + f'renaming layer "{old_name}" - document contains ' f"LAYER_INDEX" + ) + + def get_vp_overrides(self) -> LayerOverrides: + """Returns the :class:`LayerOverrides` object for this layer.""" + return LayerOverrides(self) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + assert self.doc is not None, "LAYER entity must be assigned to a document" + super().register_resources(registry) + registry.add_linetype(self.dxf.linetype) + registry.add_handle(self.dxf.get("material_handle")) + # current plot style will be replaced by default plot style "Normal" + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, Layer) + super().map_resources(clone, mapping) + self.dxf.linetype = mapping.get_linetype(self.dxf.linetype) + + mapping.map_existing_handle(self, clone, "material_handle", optional=True) + # remove handles pointing to the source document: + clone.dxf.discard("plotstyle_handle") # replaced by plot style "Normal" + clone.dxf.discard("unknown1") + + # create required handles to resources in the target document + clone.set_required_attributes() + # todo: map layer overrides + # remove layer overrides + clone.discard_extension_dict() + + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + linetype = self.dxf.linetype + if auditor.doc.linetypes.has_entry(linetype): + return + self.dxf.linetype = "Continuous" + auditor.fixed_error( + code=AuditError.UNDEFINED_LINETYPE, + message=f"Replaced undefined linetype {linetype} in layer '{self.dxf.name}' by CONTINUOUS", + dxf_entity=self, + data=linetype, + ) + + +@dataclass +class OverrideAttributes: + aci: int + rgb: Optional[clr.RGB] + transparency: float + linetype: str + lineweight: int + + +class LayerOverrides: + """This object stores the layer attribute overridden in VIEWPORT entities, + where each VIEWPORT can have individual layer attribute overrides. + + Layer attributes which can be overridden: + + - ACI color + - true color (rgb) + - linetype + - lineweight + - transparency + + """ + + def __init__(self, layer: Layer): + assert layer.doc is not None, "valid DXF document required" + self._layer = layer + self._overrides = load_layer_overrides(layer) + + def has_overrides(self, vp_handle: Optional[str] = None) -> bool: + """Returns ``True`` if attribute overrides exist for the given + :class:`Viewport` handle. + Returns ``True`` if `any` attribute overrides exist if the given + handle is ``None``. + """ + if vp_handle is None: + return bool(self._overrides) + return vp_handle in self._overrides + + def commit(self) -> None: + """Write :class:`Viewport` overrides back into the :class:`Layer` entity. + Without a commit() all changes are lost! + """ + store_layer_overrides(self._layer, self._overrides) + + def _acquire_overrides(self, vp_handle: str) -> OverrideAttributes: + """Returns the OverrideAttributes() instance for `vp_handle`, creates a new + OverrideAttributes() instance if none exist. + """ + return self._overrides.setdefault( + vp_handle, + default_ovr_settings(self._layer), + ) + + def _get_overrides(self, vp_handle: str) -> OverrideAttributes: + """Returns the overrides for `vp_handle`, returns the default layer + settings if no Override() instance exist. + """ + try: + return self._overrides[vp_handle] + except KeyError: + return default_ovr_settings(self._layer) + + def set_color(self, vp_handle: str, value: int) -> None: + """Override the :ref:`ACI`. + + Raises: + ValueError: invalid color value + """ + # BYBLOCK or BYLAYER is not valid a layer color + if not is_valid_layer_color_index(value): + raise ValueError(f"invalid ACI value: {value}") + vp_overrides = self._acquire_overrides(vp_handle) + vp_overrides.aci = value + + def get_color(self, vp_handle: str) -> int: + """Returns the :ref:`ACI` override or the original layer value if no + override exist. + """ + vp_overrides = self._get_overrides(vp_handle) + return vp_overrides.aci + + def set_rgb(self, vp_handle: str, value: Optional[clr.RGB]): + """Set the RGB override as (red, gree, blue) tuple or ``None`` to remove + the true color setting. + + Raises: + ValueError: invalid RGB value + + """ + if value is not None and not validator.is_valid_rgb(value): + raise ValueError(f"invalid RGB value: {value}") + vp_overrides = self._acquire_overrides(vp_handle) + vp_overrides.rgb = value + + def get_rgb(self, vp_handle: str) -> Optional[clr.RGB]: + """Returns the RGB override or the original layer value if no + override exist. Returns ``None`` if no true color value is set. + """ + vp_overrides = self._get_overrides(vp_handle) + return vp_overrides.rgb + + def set_transparency(self, vp_handle: str, value: float) -> None: + """Set the transparency override. A transparency of 0.0 is opaque and + 1.0 is fully transparent. + + Raises: + ValueError: invalid transparency value + + """ + if not (0.0 <= value <= 1.0): + raise ValueError( + f"invalid transparency: {value}, has to be in the range [0, 1]" + ) + vp_overrides = self._acquire_overrides(vp_handle) + vp_overrides.transparency = value + + def get_transparency(self, vp_handle: str) -> float: + """Returns the transparency override or the original layer value if no + override exist. Returns 0.0 for opaque and 1.0 for fully transparent. + """ + vp_overrides = self._get_overrides(vp_handle) + return vp_overrides.transparency + + def set_linetype(self, vp_handle: str, value: str) -> None: + """Set the linetype override. + + Raises: + ValueError: linetype without a LTYPE table entry + """ + if value not in self._layer.doc.linetypes: # type: ignore + raise ValueError( + f"invalid linetype: {value}, a linetype table entry is required" + ) + vp_overrides = self._acquire_overrides(vp_handle) + vp_overrides.linetype = value + + def get_linetype(self, vp_handle: str) -> str: + """Returns the linetype override or the original layer value if no + override exist. + """ + vp_overrides = self._get_overrides(vp_handle) + return vp_overrides.linetype + + def get_lineweight(self, vp_handle: str) -> int: + """Returns the lineweight override or the original layer value if no + override exist. + """ + vp_overrides = self._get_overrides(vp_handle) + return vp_overrides.lineweight + + def set_lineweight(self, vp_handle: str, value: int) -> None: + """Set the lineweight override. + + Raises: + ValueError: invalid lineweight value + """ + if not is_valid_layer_lineweight(value): + raise ValueError( + f"invalid lineweight: {value}, a linetype table entry is required" + ) + vp_overrides = self._acquire_overrides(vp_handle) + vp_overrides.lineweight = value + + def discard(self, vp_handle: Optional[str] = None) -> None: + """Discard all attribute overrides for the given :class:`Viewport` + handle or for all :class:`Viewport` entities if the handle is ``None``. + """ + if vp_handle is None: + self._overrides.clear() + return + try: + del self._overrides[vp_handle] + except KeyError: + pass + + +def default_ovr_settings(layer) -> OverrideAttributes: + """Returns the default settings of the layer.""" + return OverrideAttributes( + aci=layer.color, + rgb=layer.rgb, + transparency=layer.transparency, + linetype=layer.dxf.linetype, + lineweight=layer.dxf.lineweight, + ) + + +def is_layer_frozen_in_vp(layer, vp_handle) -> bool: + """Returns ``True`` if layer is frozen in VIEWPORT defined by the vp_handle.""" + vp = cast("Viewport", layer.doc.entitydb.get(vp_handle)) + if vp is not None: + return layer.dxf.name in vp.frozen_layers + return False + + +def load_layer_overrides(layer: Layer) -> dict[str, OverrideAttributes]: + """Load all VIEWPORT overrides from the layer extension dictionary.""" + + def get_ovr(vp_handle: str): + ovr = overrides.get(vp_handle) + if ovr is None: + ovr = default_ovr_settings(layer) + overrides[vp_handle] = ovr + return ovr + + def set_alpha(vp_handle: str, value: int): + ovr = get_ovr(vp_handle) + ovr.transparency = clr.transparency2float(value) + + def set_color(vp_handle: str, value: int): + ovr = get_ovr(vp_handle) + type_, data = clr.decode_raw_color(value) + if type_ == clr.COLOR_TYPE_ACI: + ovr.aci = data + elif type_ == clr.COLOR_TYPE_RGB: + ovr.rgb = data + + def set_ltype(vp_handle: str, lt_handle: str): + ltype = entitydb.get(lt_handle) + if ltype is not None: + ovr = get_ovr(vp_handle) + ovr.linetype = ltype.dxf.name + + def set_lw(vp_handle: str, value: int): + ovr = get_ovr(vp_handle) + ovr.lineweight = value + + def set_xdict_state(): + xdict = layer.get_extension_dict() + for key, code, setter in [ + (const.OVR_ALPHA_KEY, const.OVR_ALPHA_CODE, set_alpha), + (const.OVR_COLOR_KEY, const.OVR_COLOR_CODE, set_color), + (const.OVR_LTYPE_KEY, const.OVR_LTYPE_CODE, set_ltype), + (const.OVR_LW_KEY, const.OVR_LW_CODE, set_lw), + ]: + xrec = cast("XRecord", xdict.get(key)) + if xrec is not None: + for vp_handle, value in _load_ovr_values(xrec, code): + setter(vp_handle, value) + + assert layer.doc is not None, "valid DXF document required" + entitydb: EntityDB = layer.doc.entitydb + assert entitydb is not None, "valid entity database required" + + overrides: dict[str, OverrideAttributes] = dict() + if not layer.has_extension_dict: + return overrides + + set_xdict_state() + return overrides + + +def _load_ovr_values(xrec: XRecord, group_code): + tags = xrec.tags + handles = [value for code, value in tags.find_all(const.OVR_VP_HANDLE_CODE)] + values = [value for code, value in tags.find_all(group_code)] + return zip(handles, values) + + +def store_layer_overrides( + layer: Layer, overrides: dict[str, OverrideAttributes] +) -> None: + """Store all VIEWPORT overrides in the layer extension dictionary. + Replaces all existing overrides! + """ + from ezdxf.lldxf.types import DXFTag + + def get_xdict(): + if layer.has_extension_dict: + return layer.get_extension_dict() + else: + return layer.new_extension_dict() + + def set_xdict_tags(key: str, tags: list[DXFTag]): + from ezdxf.entities import XRecord + + xdict = get_xdict() + xrec = xdict.get(key) + if not isinstance(xrec, XRecord) and xrec is not None: + logger.debug( + f"Found entity {str(xrec)} as override storage in {str(layer)} " + f"but expected XRECORD" + ) + xrec = None + if xrec is None: + xrec = xdict.add_xrecord(key) + xrec.dxf.cloning = 1 + xrec.reset(tags) + + def del_xdict_tags(key: str): + if not layer.has_extension_dict: + return + xdict = layer.get_extension_dict() + xrec = xdict.get(key) + if xrec is not None: + xrec.destroy() + xdict.discard(key) + + def make_tags(data: list[tuple[Any, str]], name: str, code: int) -> list[DXFTag]: + tags: list[DXFTag] = [] + for value, vp_handle in data: + tags.extend( + [ + DXFTag(102, name), + DXFTag(const.OVR_VP_HANDLE_CODE, vp_handle), + DXFTag(code, value), + DXFTag(102, "}"), + ] + ) + return tags + + def collect_alphas(): + for vp_handle, ovr in vp_exist.items(): + if ovr.transparency != default.transparency: + yield clr.float2transparency(ovr.transparency), vp_handle + + def collect_colors(): + for vp_handle, ovr in vp_exist.items(): + if ovr.aci != default.aci or ovr.rgb != default.rgb: + if ovr.rgb is None: + raw_color = clr.encode_raw_color(ovr.aci) + else: + raw_color = clr.encode_raw_color(ovr.rgb) + yield raw_color, vp_handle + + def collect_linetypes(): + for vp_handle, ovr in vp_exist.items(): + if ovr.linetype != default.linetype: + ltype = layer.doc.linetypes.get(ovr.linetype) + if ltype is not None: + yield ltype.dxf.handle, vp_handle + + def collect_lineweights(): + for vp_handle, ovr in vp_exist.items(): + if ovr.lineweight != default.lineweight: + yield ovr.lineweight, vp_handle + + assert layer.doc is not None, "valid DXF document required" + entitydb = layer.doc.entitydb + vp_exist = { + vp_handle: ovr + for vp_handle, ovr in overrides.items() + if (vp_handle in entitydb) and entitydb[vp_handle].is_alive + } + default = default_ovr_settings(layer) + alphas = list(collect_alphas()) + if alphas: + tags = make_tags(alphas, const.OVR_APP_ALPHA, const.OVR_ALPHA_CODE) + set_xdict_tags(const.OVR_ALPHA_KEY, tags) + else: + del_xdict_tags(const.OVR_ALPHA_KEY) + + colors = list(collect_colors()) + if colors: + tags = make_tags(colors, const.OVR_APP_COLOR, const.OVR_COLOR_CODE) + set_xdict_tags(const.OVR_COLOR_KEY, tags) + else: + del_xdict_tags(const.OVR_COLOR_KEY) + + linetypes = list(collect_linetypes()) + if linetypes: + tags = make_tags(linetypes, const.OVR_APP_LTYPE, const.OVR_LTYPE_CODE) + set_xdict_tags(const.OVR_LTYPE_KEY, tags) + else: + del_xdict_tags(const.OVR_LTYPE_KEY) + + lineweights = list(collect_lineweights()) + if lineweights: + tags = make_tags(lineweights, const.OVR_APP_LW, const.OVR_LW_CODE) + set_xdict_tags(const.OVR_LW_KEY, tags) + else: + del_xdict_tags(const.OVR_LW_KEY) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/layout.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/layout.py new file mode 100644 index 0000000..f782178 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/layout.py @@ -0,0 +1,394 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import SUBCLASS_MARKER +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.math import Vec3, Vec2, NULLVEC, X_AXIS, Y_AXIS +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .dxfobj import DXFObject +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities.dxfns import DXFNamespace + from ezdxf import xref + +__all__ = ["PlotSettings", "DXFLayout"] + +acdb_plot_settings = DefSubclass( + "AcDbPlotSettings", + { + # acdb_plot_settings is also part of LAYOUT and LAYOUT has a 'name' attribute + "page_setup_name": DXFAttr(1, default=""), + + # An optional empty string selects the default printer/plotter + "plot_configuration_file": DXFAttr(2, default="", optional=True), + "paper_size": DXFAttr(4, default="A3"), + "plot_view_name": DXFAttr(6, default=""), + "left_margin": DXFAttr(40, default=7.5), # in mm + "bottom_margin": DXFAttr(41, default=20), # in mm + "right_margin": DXFAttr(42, default=7.5), # in mm + "top_margin": DXFAttr(43, default=20), # in mm + "paper_width": DXFAttr(44, default=420), # in mm + "paper_height": DXFAttr(45, default=297), # in mm + "plot_origin_x_offset": DXFAttr(46, default=0.0), # in mm + "plot_origin_y_offset": DXFAttr(47, default=0.0), # in mm + "plot_window_x1": DXFAttr(48, default=0.0), + "plot_window_y1": DXFAttr(49, default=0.0), + "plot_window_x2": DXFAttr(140, default=0.0), + "plot_window_y2": DXFAttr(141, default=0.0), + # Numerator of custom print scale: real world (paper) units: + "scale_numerator": DXFAttr(142, default=1.0), + # Denominator of custom print scale: drawing units: + "scale_denominator": DXFAttr(143, default=1.0), + # Plot layout flags: + # 1 = plot viewport borders + # 2 = show plot-styles + # 4 = plot centered + # 8 = plot hidden == hide paperspace entities? + # 16 = use standard scale + # 32 = plot with plot-styles + # 64 = scale lineweights + # 128 = plot entity lineweights + # 512 = draw viewports first + # 1024 = model type + # 2048 = update paper + # 4096 = zoom to paper on update + # 8192 = initializing + # 16384 = prev plot-init + # the "Plot transparencies" option is stored in the XDATA section + "plot_layout_flags": DXFAttr(70, default=688), + # Plot paper units: + # 0 = Plot in inches + # 1 = Plot in millimeters + # 2 = Plot in pixels + "plot_paper_units": DXFAttr( + 72, + default=1, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + # Plot rotation: + # 0 = No rotation + # 1 = 90 degrees counterclockwise + # 2 = Upside-down + # 3 = 90 degrees clockwise + "plot_rotation": DXFAttr( + 73, + default=0, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Plot type: + # 0 = Last screen display + # 1 = Drawing extents + # 2 = Drawing limits + # 3 = View specified by code 6 + # 4 = Window specified by codes 48, 49, 140, and 141 + # 5 = Layout information + "plot_type": DXFAttr( + 74, + default=5, + validator=validator.is_in_integer_range(0, 6), + fixer=RETURN_DEFAULT, + ), + # Associated CTB-file + "current_style_sheet": DXFAttr(7, default=""), + # Standard scale type: + # 0 = Scaled to Fit + # 1 = 1/128"=1' + # 2 = 1/64"=1' + # 3 = 1/32"=1' + # 4 = 1/16"=1' + # 5 = 3/32"=1' + # 6 = 1/8"=1' + # 7 = 3/16"=1' + # 8 = 1/4"=1' + # 9 = 3/8"=1' + # 10 = 1/2"=1' + # 11 = 3/4"=1' + # 12 = 1"=1' + # 13 = 3"=1' + # 14 = 6"=1' + # 15 = 1'=1' + # 16 = 1:1 + # 17 = 1:2 + # 18 = 1:4 + # 19 = 1:8 + # 20 = 1:10 + # 21 = 1:16 + # 22 = 1:20 + # 23 = 1:30 + # 24 = 1:40 + # 25 = 1:50 + # 26 = 1:100 + # 27 = 2:1 + # 28 = 4:1 + # 29 = 8:1 + # 30 = 10:1 + # 31 = 100:1 + # 32 = 1000:1 + "standard_scale_type": DXFAttr( + 75, + default=16, + validator=validator.is_in_integer_range(0, 33), + fixer=RETURN_DEFAULT, + ), + # Shade plot mode: + # 0 = As Displayed + # 1 = Wireframe + # 2 = Hidden + # 3 = Rendered + "shade_plot_mode": DXFAttr( + 76, + default=0, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Shade plot resolution level: + # 0 = Draft + # 1 = Preview + # 2 = Normal + # 3 = Presentation + # 4 = Maximum + # 5 = Custom + "shade_plot_resolution_level": DXFAttr( + 77, + default=2, + validator=validator.is_in_integer_range(0, 6), + fixer=RETURN_DEFAULT, + ), + # Valid range: 100 to 32767, Only applied when the shade_plot_resolution + # level is set to 5 (Custom) + "shade_plot_custom_dpi": DXFAttr( + 78, + default=300, + validator=validator.is_in_integer_range(100, 32768), + fixer=validator.fit_into_integer_range(100, 32768), + ), + # Factor for unit conversion (mm -> inches) + # 147: DXF Reference error: 'A floating point scale factor that represents + # the standard scale value specified in code 75' + "unit_factor": DXFAttr( + 147, + default=1.0, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + "paper_image_origin_x": DXFAttr(148, default=0), + "paper_image_origin_y": DXFAttr(149, default=0), + "shade_plot_handle": DXFAttr(333, optional=True), + }, +) +acdb_plot_settings_group_codes = group_code_mapping(acdb_plot_settings) + +# The "Plot transparencies" option is stored in the XDATA section of the +# LAYOUT entity: +# 1001 +# PLOTTRANSPARENCY +# 1071 +# 1 + + +@register_entity +class PlotSettings(DXFObject): + DXFTYPE = "PLOTSETTINGS" + DXFATTRIBS = DXFAttributes(base_class, acdb_plot_settings) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_plot_settings_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_plot_settings.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "page_setup_name", + "plot_configuration_file", + "paper_size", + "plot_view_name", + "left_margin", + "bottom_margin", + "right_margin", + "top_margin", + "paper_width", + "paper_height", + "plot_origin_x_offset", + "plot_origin_y_offset", + "plot_window_x1", + "plot_window_y1", + "plot_window_x2", + "plot_window_y2", + "scale_numerator", + "scale_denominator", + "plot_layout_flags", + "plot_paper_units", + "plot_rotation", + "plot_type", + "current_style_sheet", + "standard_scale_type", + "shade_plot_mode", + "shade_plot_resolution_level", + "shade_plot_custom_dpi", + "unit_factor", + "paper_image_origin_x", + "paper_image_origin_y", + ], + ) + + def register_resources(self, registry: xref.Registry) -> None: + super().register_resources(registry) + registry.add_handle(self.dxf.get("shade_plot_handle")) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + super().map_resources(clone, mapping) + shade_plot_handle = self.dxf.get("shade_plot_handle") + if shade_plot_handle and shade_plot_handle != "0": + clone.dxf.shade_plot_handle = mapping.get_handle(shade_plot_handle) + else: + clone.dxf.discard("shade_plot_handle") + + +acdb_layout = DefSubclass( + "AcDbLayout", + { + # Layout name: + "name": DXFAttr(1, default="Layoutname"), + # Flag (bit-coded) to control the following: + # 1 = Indicates the PSLTSCALE value for this layout when this layout is current + # 2 = Indicates the LIMCHECK value for this layout when this layout is current + "layout_flags": DXFAttr(70, default=1), + # Tab order: This number is an ordinal indicating this layout's ordering in + # the tab control that is attached to the AutoCAD drawing frame window. + # Note that the "Model" tab always appears as the first tab regardless of + # its tab order. + "taborder": DXFAttr(71, default=1), + # Minimum limits: + "limmin": DXFAttr(10, xtype=XType.point2d, default=Vec2(0, 0)), + # Maximum limits: + "limmax": DXFAttr(11, xtype=XType.point2d, default=Vec2(420, 297)), + # Insertion base point for this layout: + "insert_base": DXFAttr(12, xtype=XType.point3d, default=NULLVEC), + # Minimum extents for this layout: + "extmin": DXFAttr(14, xtype=XType.point3d, default=Vec3(1e20, 1e20, 1e20)), + # Maximum extents for this layout: + "extmax": DXFAttr(15, xtype=XType.point3d, default=Vec3(-1e20, -1e20, -1e20)), + "elevation": DXFAttr(146, default=0.0), + "ucs_origin": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + "ucs_xaxis": DXFAttr( + 16, + xtype=XType.point3d, + default=X_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + "ucs_yaxis": DXFAttr( + 17, + xtype=XType.point3d, + default=Y_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Orthographic type of UCS: + # 0 = UCS is not orthographic + # 1 = Top + # 2 = Bottom + # 3 = Front + # 4 = Back + # 5 = Left + # 6 = Right + "ucs_type": DXFAttr( + 76, + default=1, + validator=validator.is_in_integer_range(0, 7), + fixer=RETURN_DEFAULT, + ), + # Handle of parent BLOCK_RECORD + "block_record_handle": DXFAttr(330), + # Handle to the viewport that was last active in this + # layout when the layout was current: + "viewport_handle": DXFAttr(331), + # Handle of AcDbUCSTableRecord if UCS is a named + # UCS. If not present, then UCS is unnamed + "ucs_handle": DXFAttr(345), + # Handle of AcDbUCSTableRecord of base UCS if UCS is + # orthographic (76 code is non-zero). If not present and + # 76 code is non-zero, then base UCS is taken to be WORLD + "base_ucs_handle": DXFAttr(346), + }, +) +acdb_layout_group_codes = group_code_mapping(acdb_layout) + + +@register_entity +class DXFLayout(PlotSettings): + DXFTYPE = "LAYOUT" + DXFATTRIBS = DXFAttributes(base_class, acdb_plot_settings, acdb_layout) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_layout_group_codes, 2) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + # Set correct model type flag + self.set_flag_state(1024, self.dxf.name.upper() == "MODEL", "plot_layout_flags") + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_layout.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "layout_flags", + "taborder", + "limmin", + "limmax", + "insert_base", + "extmin", + "extmax", + "elevation", + "ucs_origin", + "ucs_xaxis", + "ucs_yaxis", + "ucs_type", + "block_record_handle", + "viewport_handle", + "ucs_handle", + "base_ucs_handle", + ], + ) + + def register_resources(self, registry: xref.Registry) -> None: + super().register_resources(registry) + registry.add_handle(self.dxf.get("ucs_handle")) + registry.add_handle(self.dxf.get("base_ucs_handle")) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + super().map_resources(clone, mapping) + + # The content of paperspace layouts is not copied automatically and the + # associated BLOCK_RECORD is created and assigned in a special method. + mapping.map_existing_handle(self, clone, "ucs_handle", optional=True) + mapping.map_existing_handle(self, clone, "base_ucs_handle", optional=True) + mapping.map_existing_handle(self, clone, "viewport_handle", optional=True) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/leader.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/leader.py new file mode 100644 index 0000000..0e47c99 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/leader.py @@ -0,0 +1,360 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, Iterator +from typing_extensions import Self +import logging +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags, DXFTag +from ezdxf.lldxf import const + +from ezdxf.math import Vec3, UVec, X_AXIS, Z_AXIS, NULLVEC +from ezdxf.math.transformtools import transform_extrusion +from ezdxf.explode import explode_entity +from ezdxf.audit import AuditError +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .dimension import OverrideMixin, register_override_handles +from .dimstyleoverride import DimStyleOverride +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.layouts import BaseLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + from ezdxf.query import EntityQuery + from ezdxf import xref + +__all__ = ["Leader"] +logger = logging.getLogger("ezdxf") + +acdb_leader = DefSubclass( + "AcDbLeader", + { + "dimstyle": DXFAttr( + 3, + default="Standard", + validator=validator.is_valid_table_name, + # no fixer! + ), + # Arrowhead flag: 0/1 = no/yes + "has_arrowhead": DXFAttr( + 71, + default=1, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Leader path type: + # 0 = Straight line segments + # 1 = Spline + "path_type": DXFAttr( + 72, + default=0, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Annotation type or leader creation flag: + # 0 = Created with text annotation + # 1 = Created with tolerance annotation; + # 2 = Created with block reference annotation + # 3 = Created without any annotation + "annotation_type": DXFAttr( + 73, + default=3, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Hook line direction flag: + # 1 = Hook line (or end of tangent for a spline leader) is the opposite + # direction from the horizontal vector + # 0 = Hook line (or end of tangent for a spline leader) is the same + # direction as horizontal vector (see code 75) + # DXF reference error: swapped meaning of 1/0 + "hookline_direction": DXFAttr( + 74, + default=1, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Hook line flag: 0/1 = no/yes + "has_hookline": DXFAttr( + 75, + default=1, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Text annotation height: + "text_height": DXFAttr( + 40, + default=1, + optional=True, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # Text annotation width: + "text_width": DXFAttr( + 41, + default=1, + optional=True, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # 76: Number of vertices in leader (ignored for OPEN) + # 10, 20, 30: Vertex coordinates (one entry for each vertex) + # Color to use if leader's DIMCLRD = BYBLOCK + "block_color": DXFAttr( + 77, + default=7, + optional=True, + validator=validator.is_valid_aci_color, + fixer=RETURN_DEFAULT, + ), + # Hard reference to associated annotation: + # (mtext, tolerance, or insert entity) + "annotation_handle": DXFAttr(340, default="0", optional=True), + "normal_vector": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # 'horizontal' direction for leader + "horizontal_direction": DXFAttr( + 211, + xtype=XType.point3d, + default=X_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Offset of last leader vertex from block reference insertion point + "leader_offset_block_ref": DXFAttr( + 212, xtype=XType.point3d, default=NULLVEC, optional=True + ), + # Offset of last leader vertex from annotation placement point + "leader_offset_annotation_placement": DXFAttr( + 213, xtype=XType.point3d, default=NULLVEC, optional=True + ), + # Xdata belonging to the application ID "ACAD" follows a leader entity if + # any dimension overrides have been applied to this entity. See Dimension + # Style Overrides. + }, +) +acdb_leader_group_codes = group_code_mapping(acdb_leader) + + +@register_entity +class Leader(DXFGraphic, OverrideMixin): + """DXF LEADER entity""" + + DXFTYPE = "LEADER" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_leader) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def __init__(self) -> None: + super().__init__() + self.vertices: list[Vec3] = [] + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy vertices.""" + assert isinstance(entity, Leader) + entity.vertices = Vec3.list(self.vertices) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + if tags: + tags = Tags(self.load_vertices(tags)) + processor.fast_load_dxfattribs( + dxf, acdb_leader_group_codes, tags, recover=True + ) + else: + raise const.DXFStructureError( + f"missing 'AcDbLeader' subclass in LEADER(#{dxf.handle})" + ) + + return dxf + + def load_vertices(self, tags: Tags) -> Iterable[DXFTag]: + for tag in tags: + if tag.code == 10: + self.vertices.append(tag.value) + elif tag.code == 76: + # Number of vertices in leader (ignored for OPEN) + pass + else: + yield tag + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + if len(self.vertices) < 2: + logger.debug(f"Invalid {str(self)}: more than 1 vertex required.") + return False + else: + return True + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_leader.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "dimstyle", + "has_arrowhead", + "path_type", + "annotation_type", + "hookline_direction", + "has_hookline", + "text_height", + "text_width", + ], + ) + self.export_vertices(tagwriter) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "block_color", + "annotation_handle", + "normal_vector", + "horizontal_direction", + "leader_offset_block_ref", + "leader_offset_annotation_placement", + ], + ) + + def export_vertices(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tag2(76, len(self.vertices)) + for vertex in self.vertices: + tagwriter.write_vertex(10, vertex) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + assert self.doc is not None + super().register_resources(registry) + registry.add_dim_style(self.dxf.dimstyle) + + # The leader entity cannot register the annotation entity! + if not self.has_xdata_list("ACAD", "DSTYLE"): + return + + if self.doc.dxfversion > const.DXF12: + # overridden resources are referenced by handle + register_override_handles(self, registry) + else: + # overridden resources are referenced by name + self.override().register_resources_r12(registry) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + super().map_resources(clone, mapping) + if self.dxf.hasattr("annotation_handle"): + clone.dxf.annotation_handle = mapping.get_handle(self.dxf.annotation_handle) + + # DXF R2000+ references overridden resources by group code 1005 handles in the + # XDATA section, which are automatically mapped by the parent class DXFEntity! + assert self.doc is not None + if self.doc.dxfversion > const.DXF12: + return + self_override = self.override() + if not self_override.dimstyle_attribs: + return # has no overrides + + assert isinstance(clone, Leader) + self_override.map_resources_r12(clone, mapping) + + def override(self) -> DimStyleOverride: + """Returns the :class:`~ezdxf.entities.DimStyleOverride` object. + + .. warning:: + + The LEADER entity shares only the DIMSTYLE override infrastructure with the + DIMENSION entity but does not support any other features of the DIMENSION + entity! + + HANDLE WITH CARE! + + """ + return DimStyleOverride(self) # type: ignore + + def set_vertices(self, vertices: Iterable[UVec]): + """Set vertices of the leader, vertices is an iterable of + (x, y [,z]) tuples or :class:`~ezdxf.math.Vec3`. + + """ + self.vertices = [Vec3(v) for v in vertices] + + def transform(self, m: Matrix44) -> Leader: + """Transform LEADER entity by transformation matrix `m` inplace.""" + self.vertices = list(m.transform_vertices(self.vertices)) + self.dxf.normal_vector, _ = transform_extrusion( + self.dxf.normal_vector, m + ) # ??? + self.dxf.horizontal_direction = m.transform_direction( + self.dxf.horizontal_direction + ) + self.post_transform(m) + return self + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + from ezdxf.render.leader import virtual_entities + + for e in virtual_entities(self): + e.set_source_of_copy(self) + yield e + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields the DXF primitives the LEADER entity is build up as virtual entities. + + These entities are located at the original location, but are not stored + in the entity database, have no handle and are not assigned to any + layout. + """ + return self.__virtual_entities__() + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explode parts of the LEADER entity as DXF primitives into target layout, + if target layout is ``None``, the target layout is the layout of the LEADER + entity. This method destroys the source entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container referencing all + DXF primitives. + + Args: + target_layout: target layout for the created DXF primitives, ``None`` for + the same layout as the source entity. + + """ + return explode_entity(self, target_layout) + + def audit(self, auditor: Auditor) -> None: + """Validity check.""" + super().audit(auditor) + if len(self.vertices) < 2: + auditor.fixed_error( + code=AuditError.INVALID_VERTEX_COUNT, + message=f"Deleted entity {str(self)} with invalid vertex count " + f"= {len(self.vertices)}.", + dxf_entity=self, + ) + self.destroy() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/light.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/light.py new file mode 100644 index 0000000..a42d861 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/light.py @@ -0,0 +1,152 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2007 +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import acdb_entity, DXFGraphic +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + +__all__ = ["Light"] + +acdb_light = DefSubclass( + "AcDbLight", + { + "version": DXFAttr(90, default=0), + # Light name + "name": DXFAttr(1, default=""), + # Light type: + # 1 = distant + # 2 = point + # 3 = spot + "type": DXFAttr( + 70, + default=1, + validator=validator.is_in_integer_range(1, 4), + fixer=RETURN_DEFAULT, + ), + "status": DXFAttr( + 290, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "plot_glyph": DXFAttr( + 291, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "intensity": DXFAttr(40, default=1), + # Light position + "location": DXFAttr(10, xtype=XType.point3d), + # Target location + "target": DXFAttr(11, xtype=XType.point3d), + # Attenuation type: + # 0 = None + # 1 = Inverse Linear + # 2 = Inverse Square + "attenuation_type": DXFAttr( + 72, + default=2, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + "use_attenuation_limits": DXFAttr( + 292, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "attenuation_start_limits": DXFAttr(41), + "attenuation_end_limits": DXFAttr(42), + "hotspot_angle": DXFAttr(50), # in degrees + "falloff_angle": DXFAttr(51), # in degrees + "cast_shadows": DXFAttr( + 293, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Shadow Type: + # 0 = Ray traced shadows + # 1 = Shadow maps + "shadow_type": DXFAttr( + 73, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "shadow_map_size": DXFAttr(91), + "shadow_map_softness": DXFAttr(280), + }, +) +acdb_light_group_codes = group_code_mapping(acdb_light) + + +@register_entity +class Light(DXFGraphic): + """DXF LIGHT entity""" + + DXFTYPE = "LIGHT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_light) + MIN_DXF_VERSION_FOR_EXPORT = DXF2007 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_light_group_codes, 2, recover=True + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_light.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "version", + "name", + "type", + "status", + "plot_glyph", + "intensity", + "location", + "target", + "attenuation_type", + "use_attenuation_limits", + "attenuation_start_limits", + "attenuation_end_limits", + "hotspot_angle", + "falloff_angle", + "cast_shadows", + "shadow_type", + "shadow_map_size", + "shadow_map_softness", + ], + ) + + def transform(self, m: Matrix44) -> Light: + """Transform the LIGHT entity by transformation matrix `m` inplace.""" + self.dxf.location = m.transform(self.dxf.location) + self.dxf.target = m.transform(self.dxf.target) + self.post_transform(m) + return self diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/line.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/line.py new file mode 100644 index 0000000..b326564 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/line.py @@ -0,0 +1,110 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS, OCS +from ezdxf.math.transformtools import ( + transform_thickness_and_extrusion_without_ocs, +) +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity, acdb_entity_group_codes +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Line"] + +acdb_line = DefSubclass( + "AcDbLine", + { + "start": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "end": DXFAttr(11, xtype=XType.point3d, default=NULLVEC), + "thickness": DXFAttr(39, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) + +acdb_line_group_codes = group_code_mapping(acdb_line) +merged_line_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_line_group_codes # type: ignore +) + + +@register_entity +class Line(DXFGraphic): + """The LINE entity represents a 3D line from `start` to `end`""" + + DXFTYPE = "LINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_line) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_line_group_codes) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_line.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "start", + "end", + "thickness", + "extrusion", + ], + ) + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() + + def transform(self, m: Matrix44) -> Line: + """Transform the LINE entity by transformation matrix `m` inplace.""" + start, end = m.transform_vertices([self.dxf.start, self.dxf.end]) + self.dxf.start = start + self.dxf.end = end + transform_thickness_and_extrusion_without_ocs(self, m) + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> Line: + """Optimized LINE translation about `dx` in x-axis, `dy` in y-axis and + `dz` in z-axis. + + """ + vec = Vec3(dx, dy, dz) + self.dxf.start = vec + self.dxf.start + self.dxf.end = vec + self.dxf.end + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/ltype.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/ltype.py new file mode 100644 index 0000000..eed8883 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/ltype.py @@ -0,0 +1,270 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Union, + Iterable, + Sequence, + Optional, +) +from typing_extensions import Self +from copy import deepcopy +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.lldxf.types import DXFTag +from ezdxf.lldxf.tags import Tags +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from ezdxf.lldxf.validator import is_valid_table_name +from ezdxf.tools.complex_ltype import lin_compiler +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["Linetype", "compile_line_pattern", "CONTINUOUS_PATTERN"] + +acdb_linetype = DefSubclass( + "AcDbLinetypeTableRecord", + { + "name": DXFAttr(2, validator=is_valid_table_name), + "description": DXFAttr(3, default=""), + "flags": DXFAttr(70, default=0), + # 'length': DXFAttr(40), + # 'items': DXFAttr(73), + }, +) +acdb_linetype_group_codes = group_code_mapping(acdb_linetype) +CONTINUOUS_PATTERN: Sequence[float] = tuple() + + +class LinetypePattern: + def __init__(self, tags: Tags): + """For now just store tags""" + self.tags = tags + + def __len__(self): + return len(self.tags) + + def export_dxf(self, tagwriter: AbstractTagWriter): + if tagwriter.dxfversion <= DXF12: + self.export_r12_dxf(tagwriter) + else: + tagwriter.write_tags(self.tags) + + def export_r12_dxf(self, tagwriter: AbstractTagWriter): + tags49 = Tags(tag for tag in self.tags if tag.code == 49) + tagwriter.write_tag2(72, 65) + tagwriter.write_tag2(73, len(tags49)) + tagwriter.write_tag(self.tags.get_first_tag(40)) + if len(tags49): + tagwriter.write_tags(tags49) + + def is_complex_type(self): + return self.tags.has_tag(340) + + def get_style_handle(self): + return self.tags.get_first_value(340, "0") + + def set_style_handle(self, handle): + return self.tags.update(DXFTag(340, handle)) + + def compile(self) -> Sequence[float]: + """Returns the simplified dash-gap-dash... line pattern, + a dash-length of 0 represents a point. + """ + # complex line types with text and shapes are not supported + if self.is_complex_type(): + return CONTINUOUS_PATTERN + + pattern_length = 0.0 + elements = [] + for tag in self.tags: + if tag.code == 40: + pattern_length = tag.value + elif tag.code == 49: + elements.append(tag.value) + + if len(elements) < 2: + return CONTINUOUS_PATTERN + return compile_line_pattern(pattern_length, elements) + + +def _merge_dashes(elements: Sequence[float]) -> Iterable[float]: + """Merge multiple consecutive lines, gaps or points into a single element.""" + + def sign(v): + if v < 0: + return -1 + elif v > 0: + return +1 + return 0 + + buffer = elements[0] + prev_sign = sign(buffer) + for e in elements[1:]: + if sign(e) == prev_sign: + buffer += e + else: + yield buffer + buffer = e + prev_sign = sign(e) + yield buffer + + +def compile_line_pattern( + total_length: Optional[float], elements: Sequence[float] +) -> Sequence[float]: + """Returns the simplified dash-gap-dash... line pattern, + a dash-length of 0 represents a point. + """ + elements = list(_merge_dashes(elements)) + if total_length is None: + pass + elif len(elements) < 2 or total_length <= 0.0: + return CONTINUOUS_PATTERN + + sum_elements = sum(abs(e) for e in elements) + if total_length and total_length > sum_elements: # append a gap + elements.append(sum_elements - total_length) + + if elements[0] < 0: # start with a gap + e = elements.pop(0) + if elements[-1] < 0: # extend last gap + elements[-1] += e + else: # add last gap + elements.append(e) + # returns dash-gap-point + # possible: dash-point or point-dash - ignore this yet + # never: dash-dash or gap-gap or point-point + return tuple(abs(e) for e in elements) + + +@register_entity +class Linetype(DXFEntity): + """DXF LTYPE entity""" + + DXFTYPE = "LTYPE" + DXFATTRIBS = DXFAttributes( + base_class, acdb_symbol_table_record, acdb_linetype + ) + + def __init__(self): + """Default constructor""" + super().__init__() + self.pattern_tags = LinetypePattern(Tags()) + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy pattern_tags.""" + assert isinstance(entity, Linetype) + entity.pattern_tags = deepcopy(self.pattern_tags) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_linetype_group_codes, 2, log=False + ) + self.pattern_tags = LinetypePattern(tags) + return dxf + + def preprocess_export(self, tagwriter: AbstractTagWriter): + if len(self.pattern_tags) == 0: + return False + # Do not export complex linetypes for DXF12 + if tagwriter.dxfversion == DXF12: + return not self.pattern_tags.is_complex_type() + return True + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + # AcDbEntity export is done by parent class + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_linetype.name) + self.dxf.export_dxf_attribs(tagwriter, ["name", "flags", "description"]) + if self.pattern_tags: + self.pattern_tags.export_dxf(tagwriter) + + def setup_pattern( + self, pattern: Union[Sequence[float], str], length: float = 0 + ) -> None: + # The new() function gets no doc reference, therefore complex linetype + # setup has to be done later. See also: LinetypeTable.new_entry() + complex_line_type = True if isinstance(pattern, str) else False + if complex_line_type: # a .lin like line type definition string + tags = self._setup_complex_pattern(pattern, length) # type: ignore + else: + # pattern: [2.0, 1.25, -0.25, 0.25, -0.25] - 1. element is total + # pattern length pattern elements: >0 line, <0 gap, =0 point + tags = Tags( + [ + DXFTag(72, 65), # letter 'A' + DXFTag(73, len(pattern) - 1), + DXFTag(40, float(pattern[0])), + ] + ) + for element in pattern[1:]: + tags.append(DXFTag(49, float(element))) + tags.append(DXFTag(74, 0)) + self.pattern_tags = LinetypePattern(tags) + + def _setup_complex_pattern(self, pattern: str, length: float) -> Tags: + tokens = lin_compiler(pattern) + tags = Tags( + [ + DXFTag(72, 65), # letter 'A' + ] + ) + + tags2 = [DXFTag(73, 0), DXFTag(40, length)] # temp length of 0 + count = 0 + for token in tokens: + if isinstance(token, DXFTag): + if tags2[-1].code == 49: # useless 74 only after 49 :)) + tags2.append(DXFTag(74, 0)) + tags2.append(token) + count += 1 + else: # TEXT or SHAPE + tags2.extend(token.complex_ltype_tags(self.doc)) + tags2.append(DXFTag(74, 0)) # useless 74 at the end :)) + tags2[0] = DXFTag(73, count) + tags.extend(tags2) + return tags + + def simplified_line_pattern(self) -> Sequence[float]: + """Returns the simplified dash-gap-dash... line pattern, + a dash-length of 0 represents a point. Complex line types including text + or shapes are not supported and return a continuous line pattern. + """ + return self.pattern_tags.compile() + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + assert self.doc is not None, "LTYPE entity must be assigned to a document" + super().register_resources(registry) + # register text styles and shape files for complex linetypes + style_handle = self.pattern_tags.get_style_handle() + style = self.doc.styles.get_entry_by_handle(style_handle) + if style is not None: + registry.add_entity(style) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate registered resources from self to the copied entity.""" + assert isinstance(clone, Linetype) + super().map_resources(clone, mapping) + style_handle = self.pattern_tags.get_style_handle() + if style_handle != "0": + # map text style or shape file handle of complex linetype + clone.pattern_tags.set_style_handle(mapping.get_handle(style_handle)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/lwpolyline.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/lwpolyline.py new file mode 100644 index 0000000..cd6c123 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/lwpolyline.py @@ -0,0 +1,539 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Tuple, + Sequence, + Iterable, + Union, + Iterator, + Optional, +) +from typing_extensions import TypeAlias, Self +import array +import copy +from contextlib import contextmanager +from ezdxf.math import Vec3, Matrix44, Z_AXIS +from ezdxf.math.transformtools import OCSTransform, NonUniformScalingError +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXF2000, + LWPOLYLINE_CLOSED, + DXFStructureError, +) +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import DXFTag, DXFVertex +from ezdxf.lldxf.packedtags import VertexArray +from ezdxf.render.polyline import virtual_lwpolyline_entities +from ezdxf.explode import explode_entity +from ezdxf.query import EntityQuery +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, Line, Arc, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.layouts import BaseLayout + +__all__ = ["LWPolyline", "FORMAT_CODES"] + +LWPointType: TypeAlias = Tuple[float, float, float, float, float] + +FORMAT_CODES = frozenset("xysebv") +DEFAULT_FORMAT = "xyseb" +LWPOINTCODES = (10, 20, 40, 41, 42) + +# Order does matter: +# If tag 90 is not the first TAG, AutoCAD does not close the polyline, when the +# `close` flag is set. +acdb_lwpolyline = DefSubclass( + "AcDbPolyline", + { + # Count always returns the actual length: + "count": DXFAttr(90, xtype=XType.callback, getter="__len__"), + # Elevation: OCS z-axis value for all vertices: + "elevation": DXFAttr(38, default=0, optional=True), + # Thickness can be negative! + "thickness": DXFAttr(39, default=0, optional=True), + # Flags: + # 1 = Closed + # 128 = Plinegen + "flags": DXFAttr(70, default=0), + # Const width: DXF reference error - AutoCAD uses just const width if not 0, + # for all line segments. + "const_width": DXFAttr(43, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # 10, 20 : Vertex x, y + # 91: vertex identifier ??? + # 40, 41, 42: start width, end width, bulge + }, +) + +acdb_lwpolyline_group_codes = group_code_mapping(acdb_lwpolyline) + + +@register_entity +class LWPolyline(DXFGraphic): + """DXF LWPOLYLINE entity""" + + DXFTYPE = "LWPOLYLINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_lwpolyline) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def __init__(self): + super().__init__() + self.lwpoints = LWPolylinePoints() + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy lwpoints.""" + assert isinstance(entity, LWPolyline) + entity.lwpoints = copy.deepcopy(self.lwpoints) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """ + Adds subclass processing for AcDbPolyline, requires previous base class + and AcDbEntity processing by parent class. + """ + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + if tags: + tags = self.load_vertices(tags) + processor.fast_load_dxfattribs( + dxf, + acdb_lwpolyline_group_codes, + subclass=tags, + recover=True, + ) + else: + raise DXFStructureError( + f"missing 'AcDbPolyline' subclass in LWPOLYLINE(#{dxf.handle})" + ) + return dxf + + def load_vertices(self, tags: Tags) -> Tags: + self.lwpoints, unprocessed_tags = LWPolylinePoints.from_tags(tags) + return unprocessed_tags + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + # Returns True if entity should be exported + # Do not export polylines without vertices + return len(self.lwpoints) > 0 + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_lwpolyline.name) + self.dxf.export_dxf_attribs( + tagwriter, + ["count", "flags", "const_width", "elevation", "thickness"], + ) + tagwriter.write_tags(Tags(self.lwpoints.dxftags())) + self.dxf.export_dxf_attribs(tagwriter, "extrusion") + + @property + def closed(self) -> bool: + """Get/set closed state of polyline. A closed polyline has a connection + segment from the last vertex to the first vertex. + """ + return self.get_flag_state(LWPOLYLINE_CLOSED) + + @closed.setter + def closed(self, status: bool) -> None: + self.set_flag_state(LWPOLYLINE_CLOSED, status) + + @property + def is_closed(self) -> bool: + """Get closed state of LWPOLYLINE. + Compatibility interface to :class:`Polyline` + """ + return self.get_flag_state(LWPOLYLINE_CLOSED) + + def close(self, state: bool = True) -> None: + """Set closed state of LWPOLYLINE. + Compatibility interface to :class:`Polyline` + """ + self.closed = state + + @property + def has_arc(self) -> bool: + """Returns ``True`` if LWPOLYLINE has an arc segment.""" + return any(bool(b) for x, y, s, e, b in self.lwpoints) + + @property + def has_width(self) -> bool: + """Returns ``True`` if LWPOLYLINE has any segment with width attributes + or the DXF attribute const_width is not 0. + + """ + if self.dxf.hasattr("const_width"): + # 'const_width' overrides all individual start- or end width settings. + # The DXF reference claims the opposite, but that is simply not true. + return self.dxf.const_width != 0.0 + return any((s or e) for x, y, s, e, b in self.lwpoints) + + def __len__(self) -> int: + """Returns count of polyline points.""" + return len(self.lwpoints) + + def __iter__(self) -> Iterator[LWPointType]: + """Returns iterable of tuples (x, y, start_width, end_width, bulge).""" + return iter(self.lwpoints) + + def __getitem__(self, index: int) -> LWPointType: + """Returns point at position `index` as (x, y, start_width, end_width, + bulge) tuple. start_width, end_width and bulge is 0 if not present, + supports extended slicing. Point format is fixed as "xyseb". + + All coordinates in :ref:`OCS`. + + """ + return self.lwpoints[index] + + def __setitem__(self, index: int, value: Sequence[float]) -> None: + """ + Set point at position `index` as (x, y, [start_width, [end_width, + [bulge]]]) tuple. If start_width or end_width is 0 or left off the + default width value is used. If the bulge value is left off, bulge is 0 + by default (straight line). + Does NOT support extend slicing. Point format is fixed as "xyseb". + + All coordinates in :ref:`OCS`. + + Args: + index: point index + value: point value as (x, y, [start_width, [end_width, [bulge]]]) tuple + + """ + self.lwpoints[index] = compile_array(value) + + def __delitem__(self, index: int) -> None: + """Delete point at position `index`, supports extended slicing.""" + del self.lwpoints[index] + + def vertices(self) -> Iterator[tuple[float, float]]: + """ + Returns iterable of all polyline points as (x, y) tuples in :ref:`OCS` + (:attr:`dxf.elevation` is the z-axis value). + + """ + for point in self: + yield point[0], point[1] + + def vertices_in_wcs(self) -> Iterator[Vec3]: + """Returns iterable of all polyline points as Vec3(x, y, z) in :ref:`WCS`.""" + ocs = self.ocs() + elevation = self.get_dxf_attrib("elevation", default=0.0) + for x, y in self.vertices(): + yield ocs.to_wcs(Vec3(x, y, elevation)) + + def vertices_in_ocs(self) -> Iterator[Vec3]: + """Returns iterable of all polyline points as Vec3(x, y, z) in :ref:`OCS`.""" + elevation = self.get_dxf_attrib("elevation", default=0.0) + for x, y in self.vertices(): + yield Vec3(x, y, elevation) + + def append(self, point: Sequence[float], format: str = DEFAULT_FORMAT) -> None: + """Append `point` to polyline, `format` specifies a user defined + point format. + + All coordinates in :ref:`OCS`. + + Args: + point: (x, y, [start_width, [end_width, [bulge]]]) tuple + format: format string, default is "xyseb", see: `format codes`_ + + """ + self.lwpoints.append(point, format=format) + + def insert( + self, pos: int, point: Sequence[float], format: str = DEFAULT_FORMAT + ) -> None: + """Insert new point in front of positions `pos`, `format` specifies a + user defined point format. + + All coordinates in :ref:`OCS`. + + Args: + pos: insert position + point: point data + format: format string, default is "xyseb", see: `format codes`_ + + """ + data = compile_array(point, format=format) + self.lwpoints.insert(pos, data) + + def append_points( + self, points: Iterable[Sequence[float]], format: str = DEFAULT_FORMAT + ) -> None: + """ + Append new `points` to polyline, `format` specifies a user defined + point format. + + All coordinates in :ref:`OCS`. + + Args: + points: iterable of point, point is (x, y, [start_width, [end_width, + [bulge]]]) tuple + format: format string, default is "xyseb", see: `format codes`_ + + """ + for point in points: + self.lwpoints.append(point, format=format) + + @contextmanager + def points(self, format: str = DEFAULT_FORMAT) -> Iterator[list[Sequence[float]]]: + """Context manager for polyline points. Returns a standard Python list + of points, according to the format string. + + All coordinates in :ref:`OCS`. + + Args: + format: format string, see `format codes`_ + + """ + points = self.get_points(format=format) + yield points + self.set_points(points, format=format) + + def get_points(self, format: str = DEFAULT_FORMAT) -> list[Sequence[float]]: + """Returns all points as list of tuples, format specifies a user + defined point format. + + All points in :ref:`OCS` as (x, y) tuples (:attr:`dxf.elevation` is + the z-axis value). + + Args: + format: format string, default is "xyseb", see `format codes`_ + + """ + return [format_point(p, format=format) for p in self.lwpoints] + + def set_points( + self, points: Iterable[Sequence[float]], format: str = DEFAULT_FORMAT + ) -> None: + """Remove all points and append new `points`. + + All coordinates in :ref:`OCS`. + + Args: + points: iterable of point, point is (x, y, [start_width, [end_width, + [bulge]]]) tuple + format: format string, default is "xyseb", see `format codes`_ + + """ + self.lwpoints.clear() + self.append_points(points, format=format) + + def clear(self) -> None: + """Remove all points.""" + self.lwpoints.clear() + + def transform(self, m: Matrix44) -> LWPolyline: + """Transform the LWPOLYLINE entity by transformation matrix `m` inplace. + + A non-uniform scaling is not supported if the entity contains circular + arc segments (bulges). + + Args: + m: transformation :class:`~ezdxf.math.Matrix44` + + Raises: + NonUniformScalingError: for non-uniform scaling of entity containing + circular arc segments (bulges) + + """ + dxf = self.dxf + ocs = OCSTransform(self.dxf.extrusion, m) + if not ocs.scale_uniform and self.has_arc: + raise NonUniformScalingError( + "LWPOLYLINE containing arcs (bulges) does not support non uniform scaling" + ) + # The caller function has to catch this exception and explode the + # LWPOLYLINE into LINE and ELLIPSE entities. + vertices = list(ocs.transform_vertex(v) for v in self.vertices_in_ocs()) + lwpoints = [] + for v, p in zip(vertices, self.lwpoints): + _, _, start_width, end_width, bulge = p + # assume a uniform scaling! + start_width = ocs.transform_width(start_width) + end_width = ocs.transform_width(end_width) + lwpoints.append((v.x, v.y, start_width, end_width, bulge)) + self.set_points(lwpoints) + + # All new OCS vertices must have the same z-axis, which is the elevation + # of the polyline: + if vertices: + dxf.elevation = vertices[0].z + + if dxf.hasattr("const_width"): # assume a uniform scaling! + dxf.const_width = ocs.transform_width(dxf.const_width) + + if dxf.hasattr("thickness"): + dxf.thickness = ocs.transform_thickness(dxf.thickness) + dxf.extrusion = ocs.new_extrusion + self.post_transform(m) + return self + + def virtual_entities(self) -> Iterator[Union[Line, Arc]]: + """Yields the graphical representation of LWPOLYLINE as virtual DXF + primitives (LINE or ARC). + + These virtual entities are located at the original location, but are not + stored in the entity database, have no handle and are not assigned to + any layout. + + """ + for e in virtual_lwpolyline_entities(self): + e.set_source_of_copy(self) + yield e + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explode the LWPOLYLINE entity as DXF primitives (LINE or ARC) into + the target layout, if the target layout is ``None``, the target layout + is the layout of the source entity. This method destroys the source entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container referencing all DXF + primitives. + + Args: + target_layout: target layout for the DXF primitives, ``None`` for + same layout as the source entity. + + """ + return explode_entity(self, target_layout) + + +class LWPolylinePoints(VertexArray): + __slots__ = ("values",) + VERTEX_CODE = 10 + START_WIDTH_CODE = 40 + END_WIDTH_CODE = 41 + BULGE_CODE = 42 + VERTEX_SIZE = 5 + + @classmethod + def from_tags(cls, tags: Iterable[DXFTag]) -> tuple[Self, Tags]: # type: ignore + """Setup point array from tags.""" + + def build_vertex(point: list[float]) -> list[float]: + point.append(attribs.get(cls.START_WIDTH_CODE, 0)) + point.append(attribs.get(cls.END_WIDTH_CODE, 0)) + point.append(attribs.get(cls.BULGE_CODE, 0)) + return point + + unprocessed_tags = Tags() + vertices: list[Sequence[float]]= [] + point: list[float] | None = None + attribs: dict[int, float]= {} + for tag in tags: + if tag.code in LWPOINTCODES: + if tag.code == 10: + if point is not None: + vertices.append(build_vertex(point)) + # just use x- and y-axis + point = list(tag.value[0:2]) + attribs = {} + else: + attribs[tag.code] = tag.value + else: + unprocessed_tags.append(tag) + if point is not None: + vertices.append(build_vertex(point)) + return cls(data=vertices), unprocessed_tags + + def append(self, point: Sequence[float], format: str = DEFAULT_FORMAT) -> None: + super().append(compile_array(point, format=format)) + + def dxftags(self) -> Iterator[DXFTag]: + for point in self: + x, y, start_width, end_width, bulge = point + yield DXFVertex(self.VERTEX_CODE, (x, y)) + if start_width or end_width: + # Export always start- and end width together, + # required for BricsCAD but not AutoCAD! + yield DXFTag(self.START_WIDTH_CODE, start_width) + yield DXFTag(self.END_WIDTH_CODE, end_width) + if bulge: + yield DXFTag(self.BULGE_CODE, bulge) + + +def format_point(point: Sequence[float], format: str = "xyseb") -> Sequence[float]: + """Reformat point components. + + Format codes: + + - ``x`` = x-coordinate + - ``y`` = y-coordinate + - ``s`` = start width + - ``e`` = end width + - ``b`` = bulge value + - ``v`` = (x, y) as tuple + + Args: + point: list or tuple of (x, y, start_width, end_width, bulge) + format: format string, default is "xyseb" + + Returns: + Sequence[float]: tuple of selected components + + """ + x, y, s, e, b = point + v = (x, y) + vars = locals() + return tuple(vars[code] for code in format.lower() if code in FORMAT_CODES) + + +def compile_array(data: Sequence[float], format="xyseb") -> array.array: + """Gather point components from input data. + + Format codes: + + - ``x`` = x-coordinate + - ``y`` = y-coordinate + - ``s`` = start width + - ``e`` = end width + - ``b`` = bulge value + - ``v`` = (x, y [,z]) tuple (z-axis is ignored) + + Args: + data: list or tuple of point components + format: format string, default is "xyseb" + + Returns: + array.array: array.array('d', (x, y, start_width, end_width, bulge)) + + """ + a = array.array("d", (0.0, 0.0, 0.0, 0.0, 0.0)) + format = [code for code in format.lower() if code in FORMAT_CODES] + for code, value in zip(format, data): + if code not in FORMAT_CODES: + continue + if code == "v": + vertex = Vec3(value) + a[0] = vertex.x + a[1] = vertex.y + else: + a["xyseb".index(code)] = value + return a diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/material.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/material.py new file mode 100644 index 0000000..0ac1073 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/material.py @@ -0,0 +1,432 @@ +# Copyright (c) 2018-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +from ezdxf.lldxf.const import SUBCLASS_MARKER +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .factory import register_entity +from .objectcollection import ObjectCollection +from ezdxf.math import Matrix44 +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.document import Drawing + +__all__ = ["Material", "MaterialCollection"] + + +def fetch_matrix(tags: Tags, code: int) -> tuple[Tags, Optional[Matrix44]]: + values = [] + remaining = Tags() + for tag in tags: + if tag.code == code: + values.append(tag.value) + if len(values) == 16: + # enough values collected, code 43 is maybe used for two matrices + code = -1 + else: + remaining.append(tag) + if len(values) == 16: + # only if valid matrix + return remaining, Matrix44(values) + else: + return tags, None + + +def export_matrix(tagwriter: AbstractTagWriter, code: int, matrix: Matrix44) -> None: + if matrix is not None: + for value in matrix: + tagwriter.write_tag2(code, value) + + +acdb_material = DefSubclass( + "AcDbMaterial", + { + "name": DXFAttr(1), + "description": DXFAttr(2, default=""), + "ambient_color_method": DXFAttr( + 70, default=0 + ), # 0=use current color; 1=override current color + "ambient_color_factor": DXFAttr(40, default=1.0), # valid range is 0.0 to 1.0 + "ambient_color_value": DXFAttr(90), # integer representing an AcCmEntityColor + "diffuse_color_method": DXFAttr( + 71, default=0 + ), # 0=use current color; 1=override current color + "diffuse_color_factor": DXFAttr(41, default=1.0), # valid range is 0.0 to 1.0 + "diffuse_color_value": DXFAttr( + 91, default=-1023410177 + ), # integer representing an AcCmEntityColor + "diffuse_map_blend_factor": DXFAttr( + 42, default=1.0 + ), # valid range is 0.0 to 1.0 + "diffuse_map_source": DXFAttr(72, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "diffuse_map_file_name": DXFAttr(3, default=""), + "diffuse_map_projection_method": DXFAttr( + 73, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "diffuse_map_tiling_method": DXFAttr(74, default=1), # 1=Tile; 2=Crop; 3=Clamp + "diffuse_map_auto_transform_method": DXFAttr(75, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 43: Transform matrix of diffuse map mapper (16 reals; row major format; default = identity matrix) + "specular_gloss_factor": DXFAttr(44, default=0.5), # valid range is 0.0 to 1.0 + "specular_color_method": DXFAttr( + 73, default=0 + ), # 0=use current color; 1=override current color + "specular_color_factor": DXFAttr(45, default=1.0), # valid range is 0.0 to 1.0 + "specular_color_value": DXFAttr(92), # integer representing an AcCmEntityColor + "specular_map_blend_factor": DXFAttr( + 46, default=1.0 + ), # valid range is 0.0 to 1.0 + "specular_map_source": DXFAttr(77, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "specular_map_file_name": DXFAttr(4, default=""), + "specular_map_projection_method": DXFAttr( + 78, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "specular_map_tiling_method": DXFAttr(79, default=1), # 1=Tile; 2=Crop; 3=Clamp + "specular_map_auto_transform_method": DXFAttr(170, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 47: Transform matrix of specular map mapper (16 reals; row major format; default = identity matrix) + "reflection_map_blend_factor": DXFAttr( + 48, default=1.0 + ), # valid range is 0.0 to 1.0 + "reflection_map_source": DXFAttr(171, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "reflection_map_file_name": DXFAttr(6, default=""), + "reflection_map_projection_method": DXFAttr( + 172, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "reflection_map_tiling_method": DXFAttr( + 173, default=1 + ), # 1=Tile; 2=Crop; 3=Clamp + "reflection_map_auto_transform_method": DXFAttr(174, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 49: Transform matrix of reflection map mapper (16 reals; row major format; default = identity matrix) + "opacity": DXFAttr(140, default=1.0), # valid range is 0.0 to 1.0 + "opacity_map_blend_factor": DXFAttr( + 141, default=1.0 + ), # valid range is 0.0 to 1.0 + "opacity_map_source": DXFAttr(175, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "opacity_map_file_name": DXFAttr(7, default=""), + "opacity_map_projection_method": DXFAttr( + 176, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "opacity_map_tiling_method": DXFAttr(177, default=1), # 1=Tile; 2=Crop; 3=Clamp + "opacity_map_auto_transform_method": DXFAttr(178, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 142: Transform matrix of reflection map mapper (16 reals; row major format; default = identity matrix) + "bump_map_blend_factor": DXFAttr(143, default=1.0), # valid range is 0.0 to 1.0 + "bump_map_source": DXFAttr(179, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "bump_map_file_name": DXFAttr(8, default=""), + "bump_map_projection_method": DXFAttr( + 270, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "bump_map_tiling_method": DXFAttr(271, default=1), # 1=Tile; 2=Crop; 3=Clamp + "bump_map_auto_transform_method": DXFAttr(272, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 144: Transform matrix of bump map mapper (16 reals; row major format; default = identity matrix) + "refraction_index": DXFAttr(145, default=1.0), # valid range is 0.0 to 1.0 + "refraction_map_blend_factor": DXFAttr( + 146, default=1.0 + ), # valid range is 0.0 to 1.0 + "refraction_map_source": DXFAttr(273, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "refraction_map_file_name": DXFAttr(9, default=""), + "refraction_map_projection_method": DXFAttr( + 274, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "refraction_map_tiling_method": DXFAttr( + 275, default=1 + ), # 1=Tile; 2=Crop; 3=Clamp + "refraction_map_auto_transform_method": DXFAttr(276, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 147: Transform matrix of reflection map mapper (16 reals; row major format; default = identity matrix) + # normal map shares group codes with diffuse map + "normal_map_method": DXFAttr(271), + "normal_map_strength": DXFAttr(465), + "normal_map_blend_factor": DXFAttr( + 42, default=1.0 + ), # valid range is 0.0 to 1.0 + "normal_map_source": DXFAttr(72, default=1), + # 0=use current scene; 1=use image file (specified by file name; null file name specifies no map) + "normal_map_file_name": DXFAttr(3, default=""), + "normal_map_projection_method": DXFAttr( + 73, default=1 + ), # 1=Planar; 2=Box; 3=Cylinder; 4=Sphere + "normal_map_tiling_method": DXFAttr(74, default=1), # 1=Tile; 2=Crop; 3=Clamp + "normal_map_auto_transform_method": DXFAttr(75, default=1), # bitset; + # 1 = No auto transform + # 2 = Scale mapper to current entity extents; translate mapper to entity origin + # 4 = Include current block transform in mapper transform + # 16x group code 43: Transform matrix of reflection map mapper (16 reals; row major format; default = identity matrix) + "color_bleed_scale": DXFAttr(460), + "indirect_dump_scale": DXFAttr(461), + "reflectance_scale": DXFAttr(462), + "transmittance_scale": DXFAttr(463), + "two_sided_material": DXFAttr(290), + "luminance": DXFAttr(464), + "luminance_mode": DXFAttr(270), # multiple usage of group code 270 + "materials_anonymous": DXFAttr(293), + "global_illumination_mode": DXFAttr(272), + "final_gather_mode": DXFAttr(273), + "gen_proc_name": DXFAttr(300), + "gen_proc_val_bool": DXFAttr(291), + "gen_proc_val_int": DXFAttr(271), + "gen_proc_val_real": DXFAttr(469), + "gen_proc_val_text": DXFAttr(301), + "gen_proc_table_end": DXFAttr(292), + "gen_proc_val_color_index": DXFAttr(62), + "gen_proc_val_color_rgb": DXFAttr(420), + "gen_proc_val_color_name": DXFAttr(430), + "map_utile": DXFAttr(270), # multiple usage of group code 270 + "translucence": DXFAttr(148), + "self_illumination": DXFAttr(90), + "reflectivity": DXFAttr(468), + "illumination_model": DXFAttr(93), + "channel_flags": DXFAttr(94, default=63), + }, +) +acdb_material_group_codes = group_code_mapping(acdb_material) + + +@register_entity +class Material(DXFObject): + DXFTYPE = "MATERIAL" + DEFAULT_ATTRIBS = { + "diffuse_color_method": 1, + "diffuse_color_value": -1023410177, + } + DXFATTRIBS = DXFAttributes(base_class, acdb_material) + + def __init__(self) -> None: + super().__init__() + self.diffuse_mapper_matrix: Optional[Matrix44] = None # code 43 + self.specular_mapper_matrix: Optional[Matrix44] = None # code 47 + self.reflexion_mapper_matrix: Optional[Matrix44] = None # code 49 + self.opacity_mapper_matrix: Optional[Matrix44] = None # group 142 + self.bump_mapper_matrix: Optional[Matrix44] = None # group 144 + self.refraction_mapper_matrix: Optional[Matrix44] = None # code 147 + self.normal_mapper_matrix: Optional[Matrix44] = None # code 43 ??? + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy material mapper matrices""" + + def copy(matrix): + return None if matrix is None else matrix.copy() + + assert isinstance(entity, Material) + entity.diffuse_mapper_matrix = copy(self.diffuse_mapper_matrix) + entity.specular_mapper_matrix = copy(self.specular_mapper_matrix) + entity.reflexion_mapper_matrix = copy(self.reflexion_mapper_matrix) + entity.opacity_mapper_matrix = copy(self.opacity_mapper_matrix) + entity.bump_mapper_matrix = copy(self.bump_mapper_matrix) + entity.refraction_mapper_matrix = copy(self.refraction_mapper_matrix) + entity.normal_mapper_matrix = copy(self.normal_mapper_matrix) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_material_group_codes, 1, log=False + ) + self.load_matrices(tags) + return dxf + + def load_matrices(self, tags): + tags, matrix = fetch_matrix(tags, 43) + if matrix: + self.diffuse_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 47) + if matrix: + self.specular_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 49) + if matrix: + self.reflexion_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 142) + if matrix: + self.opacity_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 144) + if matrix: + self.bump_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 147) + if matrix: + self.refraction_mapper_matrix = matrix + tags, matrix = fetch_matrix(tags, 43) + if matrix: + self.normal_mapper_matrix = matrix + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_material.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "description", + "ambient_color_method", + "ambient_color_factor", + "ambient_color_value", + "diffuse_color_method", + "diffuse_color_factor", + "diffuse_color_value", + "diffuse_map_blend_factor", + "diffuse_map_source", + "diffuse_map_file_name", + "diffuse_map_projection_method", + "diffuse_map_tiling_method", + "diffuse_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 43, self.diffuse_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "specular_gloss_factor", + "specular_color_method", + "specular_color_factor", + "specular_color_value", + "specular_map_blend_factor", + "specular_map_source", + "specular_map_file_name", + "specular_map_projection_method", + "specular_map_tiling_method", + "specular_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 47, self.specular_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "reflection_map_blend_factor", + "reflection_map_source", + "reflection_map_file_name", + "reflection_map_projection_method", + "reflection_map_tiling_method", + "reflection_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 49, self.reflexion_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "opacity", + "opacity_map_blend_factor", + "opacity_map_source", + "opacity_map_file_name", + "opacity_map_projection_method", + "opacity_map_tiling_method", + "opacity_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 142, self.opacity_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "bump_map_blend_factor", + "bump_map_source", + "bump_map_file_name", + "bump_map_projection_method", + "bump_map_tiling_method", + "bump_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 144, self.bump_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "refraction_index", + "refraction_map_blend_factor", + "refraction_map_source", + "refraction_map_file_name", + "refraction_map_projection_method", + "refraction_map_tiling_method", + "refraction_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 147, self.refraction_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "normal_map_method", + "normal_map_strength", + "normal_map_blend_factor", + "normal_map_source", + "normal_map_file_name", + "normal_map_projection_method", + "normal_map_tiling_method", + "normal_map_auto_transform_method", + ], + ) + export_matrix(tagwriter, 43, self.normal_mapper_matrix) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "color_bleed_scale", + "indirect_dump_scale", + "reflectance_scale", + "transmittance_scale", + "two_sided_material", + "luminance", + "luminance_mode", + "materials_anonymous", + "global_illumination_mode", + "final_gather_mode", + "gen_proc_name", + "gen_proc_val_bool", + "gen_proc_val_int", + "gen_proc_val_real", + "gen_proc_val_text", + "gen_proc_table_end", + "gen_proc_val_color_index", + "gen_proc_val_color_rgb", + "gen_proc_val_color_name", + "map_utile", + "translucence", + "self_illumination", + "reflectivity", + "illumination_model", + "channel_flags", + ], + ) + + +class MaterialCollection(ObjectCollection[Material]): + def __init__(self, doc: Drawing): + super().__init__(doc, dict_name="ACAD_MATERIAL", object_type="MATERIAL") + self.create_required_entries() + + def create_required_entries(self) -> None: + for name in ("ByBlock", "ByLayer", "Global"): + if name not in self: + self.new(name) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mesh.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mesh.py new file mode 100644 index 0000000..2fa6836 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mesh.py @@ -0,0 +1,487 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Sequence, + Union, + Iterator, + Optional, +) +from typing_extensions import Self +import array +import copy +from itertools import chain +from contextlib import contextmanager + +from ezdxf.audit import AuditError +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXF2000, + DXFValueError, + DXFStructureError, + DXFIndexError, +) +from ezdxf.lldxf.packedtags import VertexArray, TagArray, TagList +from ezdxf.math import Matrix44, UVec, Vec3 +from ezdxf.tools import take2 +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.tags import Tags + from ezdxf.audit import Auditor + +__all__ = ["Mesh", "MeshData"] + +acdb_mesh = DefSubclass( + "AcDbSubDMesh", + { + "version": DXFAttr(71, default=2), + "blend_crease": DXFAttr( + 72, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # 0 is no smoothing + "subdivision_levels": DXFAttr( + 91, + default=0, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + # 92: Vertex count of level 0 + # 10: Vertex position, multiple entries + # 93: Size of face list of level 0 + # 90: Face list item, >=3 possible + # 90: length of face list + # 90: 1st vertex index + # 90: 2nd vertex index ... + # 94: Edge count of level 0 + # 90: Vertex index of 1st edge + # 90: Vertex index of 2nd edge + # 95: Edge crease count of level 0 + # 95 same as 94, or how is the 'edge create value' associated to edge index + # 140: Edge crease value + # + # Overriding properties: how does this work? + # 90: Count of sub-entity which property has been overridden + # 91: Sub-entity marker + # 92: Count of property was overridden + # 90: Property type + # 0 = Color + # 1 = Material + # 2 = Transparency + # 3 = Material mapper + }, +) +acdb_mesh_group_codes = group_code_mapping(acdb_mesh) + + +class EdgeArray(TagArray): + DTYPE = "L" + + def __len__(self) -> int: + return len(self.values) // 2 + + def __iter__(self) -> Iterator[tuple[int, int]]: + for edge in take2(self.values): + yield edge + + def set_data(self, edges: Iterable[tuple[int, int]]) -> None: + self.values = array.array(self.DTYPE, chain.from_iterable(edges)) + + def export_dxf(self, tagwriter: AbstractTagWriter): + # count = count of edges not tags! + tagwriter.write_tag2(94, len(self.values) // 2) + for index in self.values: + tagwriter.write_tag2(90, index) + + +class FaceList(TagList): + def __len__(self) -> int: + return len(self.values) + + def __iter__(self) -> Iterable[array.array]: + return iter(self.values) + + def export_dxf(self, tagwriter: AbstractTagWriter): + # count = count of tags not faces! + tagwriter.write_tag2(93, self.tag_count()) + for face in self.values: + tagwriter.write_tag2(90, len(face)) + for index in face: + tagwriter.write_tag2(90, index) + + def tag_count(self) -> int: + return len(self.values) + sum(len(f) for f in self.values) + + def set_data(self, faces: Iterable[Sequence[int]]) -> None: + _faces = [] + for face in faces: + _faces.append(face_to_array(face)) + self.values = _faces + + +def face_to_array(face: Sequence[int]) -> array.array: + max_index = max(face) + if max_index < 256: + dtype = "B" + elif max_index < 65536: + dtype = "I" + else: + dtype = "L" + return array.array(dtype, face) + + +def create_vertex_array(tags: Tags, start_index: int) -> VertexArray: + vertex_tags = tags.collect_consecutive_tags(codes=(10,), start=start_index) + return VertexArray(data=[t.value for t in vertex_tags]) + + +def create_face_list(tags: Tags, start_index: int) -> FaceList: + faces = FaceList() + faces_list = faces.values + face: list[int] = [] + counter = 0 + for tag in tags.collect_consecutive_tags(codes=(90,), start=start_index): + if not counter: + # leading counter tag + counter = tag.value + if face: + # group code 90 = 32 bit integer + faces_list.append(face_to_array(face)) + face = [] + else: + # followed by count face tags + counter -= 1 + face.append(tag.value) + + # add last face + if face: + # group code 90 = 32 bit integer + faces_list.append(face_to_array(face)) + + return faces + + +def create_edge_array(tags: Tags, start_index: int) -> EdgeArray: + return EdgeArray(data=collect_values(tags, start_index, code=90)) # int values + + +def collect_values( + tags: Tags, start_index: int, code: int +) -> Iterable[Union[float, int]]: + values = tags.collect_consecutive_tags(codes=(code,), start=start_index) + return (t.value for t in values) + + +def create_crease_array(tags: Tags, start_index: int) -> array.array: + return array.array("f", collect_values(tags, start_index, code=140)) # float values + + +COUNT_ERROR_MSG = "'MESH (#{}) without {} count.'" + + +@register_entity +class Mesh(DXFGraphic): + """DXF MESH entity""" + + DXFTYPE = "MESH" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mesh) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def __init__(self): + super().__init__() + self._vertices = VertexArray() # vertices stored as array.array('d') + self._faces = FaceList() # face lists data + self._edges = EdgeArray() # edge indices stored as array.array('L') + self._creases = array.array("f") # creases stored as array.array('f') + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy data: vertices, faces, edges, creases.""" + assert isinstance(entity, Mesh) + entity._vertices = copy.deepcopy(self._vertices) + entity._faces = copy.deepcopy(self._faces) + entity._edges = copy.deepcopy(self._edges) + entity._creases = copy.deepcopy(self._creases) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + if tags: + # Load mesh data and remove their tags from subclass + self.load_mesh_data(tags, dxf.handle) + # Load remaining data into name space + processor.fast_load_dxfattribs( + dxf, acdb_mesh_group_codes, 2, recover=True + ) + else: + raise DXFStructureError( + f"missing 'AcDbSubMesh' subclass in MESH(#{dxf.handle})" + ) + return dxf + + def load_mesh_data(self, mesh_tags: Tags, handle: str) -> None: + def process_vertices(): + try: + vertex_count_index = mesh_tags.tag_index(92) + except DXFValueError: + raise DXFStructureError(COUNT_ERROR_MSG.format(handle, "vertex")) + vertices = create_vertex_array(mesh_tags, vertex_count_index + 1) + # Remove vertex count tag and all vertex tags + end_index = vertex_count_index + 1 + len(vertices) + del mesh_tags[vertex_count_index:end_index] + return vertices + + def process_faces(): + try: + face_count_index = mesh_tags.tag_index(93) + except DXFValueError: + raise DXFStructureError(COUNT_ERROR_MSG.format(handle, "face")) + else: + # Remove face count tag and all face tags + faces = create_face_list(mesh_tags, face_count_index + 1) + end_index = face_count_index + 1 + faces.tag_count() + del mesh_tags[face_count_index:end_index] + return faces + + def process_edges(): + try: + edge_count_index = mesh_tags.tag_index(94) + except DXFValueError: + raise DXFStructureError(COUNT_ERROR_MSG.format(handle, "edge")) + else: + edges = create_edge_array(mesh_tags, edge_count_index + 1) + # Remove edge count tag and all edge tags + end_index = edge_count_index + 1 + len(edges.values) + del mesh_tags[edge_count_index:end_index] + return edges + + def process_creases(): + try: + crease_count_index = mesh_tags.tag_index(95) + except DXFValueError: + raise DXFStructureError(COUNT_ERROR_MSG.format(handle, "crease")) + else: + creases = create_crease_array(mesh_tags, crease_count_index + 1) + # Remove crease count tag and all crease tags + end_index = crease_count_index + 1 + len(creases) + del mesh_tags[crease_count_index:end_index] + return creases + + self._vertices = process_vertices() + self._faces = process_faces() + self._edges = process_edges() + self._creases = process_creases() + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_mesh.name) + self.dxf.export_dxf_attribs( + tagwriter, ["version", "blend_crease", "subdivision_levels"] + ) + self.export_mesh_data(tagwriter) + self.export_override_data(tagwriter) + + def export_mesh_data(self, tagwriter: AbstractTagWriter): + tagwriter.write_tag2(92, len(self.vertices)) + self._vertices.export_dxf(tagwriter, code=10) + self._faces.export_dxf(tagwriter) + self._edges.export_dxf(tagwriter) + + creases = self._fixed_crease_values() + tagwriter.write_tag2(95, len(self.creases)) + for crease_value in creases: + tagwriter.write_tag2(140, crease_value) + + def _fixed_crease_values(self) -> list[float]: + # The edge count has to match the crease count, otherwise its an invalid + # DXF file to AutoCAD! + edge_count = len(self._edges) + creases = list(self.creases) + crease_count = len(creases) + if edge_count < crease_count: + creases = creases[:edge_count] + while edge_count > len(creases): + creases.append(0.0) + return creases + + def export_override_data(self, tagwriter: AbstractTagWriter): + tagwriter.write_tag2(90, 0) + + @property + def creases(self) -> array.array: + """Creases as :class:`array.array`. (read/write)""" + return self._creases + + @creases.setter + def creases(self, values: Iterable[float]) -> None: + self._creases = array.array("f", values) + + @property + def vertices(self): + """Vertices as list like :class:`~ezdxf.lldxf.packedtags.VertexArray`. + (read/write) + """ + return self._vertices + + @vertices.setter + def vertices(self, points: Iterable[UVec]) -> None: + self._vertices = VertexArray(points) + + @property + def edges(self): + """Edges as list like :class:`~ezdxf.lldxf.packedtags.TagArray`. + (read/write) + """ + return self._edges + + @edges.setter + def edges(self, edges: Iterable[tuple[int, int]]) -> None: + self._edges.set_data(edges) + + @property + def faces(self): + """Faces as list like :class:`~ezdxf.lldxf.packedtags.TagList`. + (read/write) + """ + return self._faces + + @faces.setter + def faces(self, faces: Iterable[Sequence[int]]) -> None: + self._faces.set_data(faces) + + def get_data(self) -> MeshData: + return MeshData(self) + + def set_data(self, data: MeshData) -> None: + self.vertices = data.vertices + self._faces.set_data(data.faces) + self._edges.set_data(data.edges) + self.creases = array.array("f", data.edge_crease_values) + if len(self.edges) != len(self.creases): + raise DXFValueError("count of edges must match count of creases") + + @contextmanager + def edit_data(self) -> Iterator[MeshData]: + """Context manager for various mesh data, returns a :class:`MeshData` instance. + + Despite that vertices, edge and faces are accessible as packed data types, the + usage of :class:`MeshData` by context manager :meth:`edit_data` is still + recommended. + """ + data = self.get_data() + yield data + self.set_data(data) + + def transform(self, m: Matrix44) -> Mesh: + """Transform the MESH entity by transformation matrix `m` inplace.""" + self._vertices.transform(m) + self.post_transform(m) + return self + + def audit(self, auditor: Auditor) -> None: + if not self.is_alive: + return + super().audit(auditor) + if len(self.edges) != len(self.creases): + self.creases = self._fixed_crease_values() # type: ignore + auditor.fixed_error( + code=AuditError.INVALID_CREASE_VALUE_COUNT, + message=f"fixed invalid count of crease values in {str(self)}", + dxf_entity=self, + ) + + +class MeshData: + def __init__(self, mesh: Mesh) -> None: + self.vertices: list[Vec3] = Vec3.list(mesh.vertices) + self.faces: list[Sequence[int]] = list(mesh.faces) + self.edges: list[tuple[int, int]] = list(mesh.edges) + self.edge_crease_values: list[float] = list(mesh.creases) + + def add_face(self, vertices: Iterable[UVec]) -> Sequence[int]: + """Add a face by a list of vertices.""" + indices = tuple(self.add_vertex(vertex) for vertex in vertices) + self.faces.append(indices) + return indices + + def add_edge_crease(self, v1: int, v2: int, crease: float): + """Add an edge crease value, the edge is defined by the vertex indices + `v1` and `v2`. + + The crease value defines the amount of subdivision that will be applied + to this edge. A crease value of the subdivision level prevents the edge from + deformation and a value of 0.0 means no protection from subdividing. + + """ + if v1 < 0 or v1 > len(self.vertices): + raise DXFIndexError("vertex index `v1` out of range") + if v2 < 0 or v2 > len(self.vertices): + raise DXFIndexError("vertex index `v2` out of range") + self.edges.append((v1, v2)) + self.edge_crease_values.append(crease) + + def add_vertex(self, vertex: UVec) -> int: + if len(vertex) != 3: + raise DXFValueError("Parameter vertex has to be a 3-tuple (x, y, z).") + index = len(self.vertices) + self.vertices.append(Vec3(vertex)) + return index + + def optimize(self): + """Reduce vertex count by merging coincident vertices.""" + + def merge_coincident_vertices() -> dict[int, int]: + original_vertices = [ + (v.xyz, index, v) for index, v in enumerate(self.vertices) + ] + original_vertices.sort() + self.vertices = [] + index_map: dict[int, int] = {} + prev_vertex = sentinel = Vec3() + index = 0 + for _, original_index, vertex in original_vertices: + if prev_vertex is sentinel or not vertex.isclose(prev_vertex): + index = len(self.vertices) + self.vertices.append(vertex) + index_map[original_index] = index + prev_vertex = vertex + else: # this is a coincident vertex + index_map[original_index] = index + return index_map + + def remap_faces() -> None: + self.faces = remap_indices(self.faces) + + def remap_edges() -> None: + self.edges = remap_indices(self.edges) # type: ignore + + def remap_indices(indices: Sequence[Sequence[int]]) -> list[Sequence[int]]: + mapped_indices: list[Sequence[int]] = [] + for entry in indices: + mapped_indices.append(tuple(index_map[index] for index in entry)) + return mapped_indices + + index_map = merge_coincident_vertices() + remap_faces() + remap_edges() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mleader.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mleader.py new file mode 100644 index 0000000..d952900 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mleader.py @@ -0,0 +1,1462 @@ +# Copyright (c) 2018-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Union, Optional, Iterable, Any, Iterator +from typing_extensions import Self +import copy +import logging +import math +from collections import namedtuple + +from ezdxf.lldxf import const +from ezdxf.lldxf.types import cast_value +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.const import EXT_MAX_STR_LEN +from ezdxf.math import ( + Vec3, + NULLVEC, + X_AXIS, + Y_AXIS, + Z_AXIS, + Matrix44, + WCSTransform, + OCSTransform, + NonUniformScalingError, +) +from ezdxf import colors +from ezdxf.proxygraphic import ProxyGraphicError +from ezdxf.tools.text import safe_string, scale_mtext_inline_commands +from ezdxf.tools.handle import safe_handle + +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .dxfgfx import DXFGraphic, acdb_entity + +from .factory import register_entity +from .objectcollection import ObjectCollection +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.layouts import BaseLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.types import DXFTag + from ezdxf.query import EntityQuery + from ezdxf import xref + +__all__ = [ + "MultiLeader", + "MLeader", + "MLeaderStyle", + "MLeaderStyleCollection", + "MLeaderContext", + "MTextData", + "BlockData", + "LeaderData", + "LeaderLine", + "ArrowHeadData", + "AttribData", +] +logger = logging.getLogger("ezdxf") + + +# DXF Examples: +# "D:\source\dxftest\CADKitSamples\house design for two family with common staircasedwg.dxf" +# "D:\source\dxftest\CADKitSamples\house design.dxf" + +# How to render MLEADER: https://atlight.github.io/formats/dxf-leader.html +# DXF reference: +# http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-72D20B8C-0F5E-4993-BEB7-0FCF94F32BE0 + +acdb_mleader = DefSubclass( + "AcDbMLeader", + { + "version": DXFAttr(270, default=2), + "style_handle": DXFAttr(340), + # Theory: Take properties from MLEADERSTYLE, + # except explicit overridden here: + "property_override_flags": DXFAttr(90), + # Bit coded flags from ODA DWG specs pg.158: + # 1 << 0 = leader_type + # 1 << 1 = leader_line_color + # 1 << 2 = leader_linetype_handle + # 1 << 3 = leader_lineweight + # 1 << 4 = has_landing + # 1 << 5 = landing_gap_size ??? + # 1 << 6 = has_dogleg + # 1 << 7 = dogleg_length + # 1 << 8 = arrow_head_handle + # 1 << 9 = arrow_head_size + # 1 << 10 = content_type + # 1 << 11 = text_style_handle + # 1 << 12 = text_left_attachment_type (of MTEXT) + # 1 << 13 = text_angle_type (of MTEXT) + # 1 << 14 = text_alignment_type (of MTEXT) + # 1 << 15 = text_color (of MTEXT) + # 1 << 16 = ??? Text height (of MTEXT) ??? + # 1 << 17 = has_text_frame + # 1 << 18 = ??? Enable use of default MTEXT (from MLEADERSTYLE) + # 1 << 19 = block_record_handle + # 1 << 20 = block_color + # 1 << 21 = block_scale_vector + # 1 << 22 = block_rotation + # 1 << 23 = block_connection_type + # 1 << 24 = ??? Scale ??? + # 1 << 25 = text_right_attachment_type (of MTEXT) + # 1 << 26 = ??? Text switch alignment type (of MTEXT) ??? + # 1 << 27 = text_attachment_direction (of MTEXT) + # 1 << 28 = text_top_attachment_type (of MTEXT) + # 1 << 29 = Text_bottom_attachment_type (of MTEXT) + # leader_type: + # 0 = invisible + # 1 = straight line leader + # 2 = spline leader + "leader_type": DXFAttr(170, default=1), + "leader_line_color": DXFAttr(91, default=colors.BY_BLOCK_RAW_VALUE), + "leader_linetype_handle": DXFAttr(341), + "leader_lineweight": DXFAttr(171, default=const.LINEWEIGHT_BYBLOCK), + "has_landing": DXFAttr(290, default=1), + "has_dogleg": DXFAttr(291, default=1), + "dogleg_length": DXFAttr(41, default=8), # depend on $MEASUREMENT? + # no handle is default arrow 'closed filled': + "arrow_head_handle": DXFAttr(342), + # unscaled arrow head size: + "arrow_head_size": DXFAttr(42, default=4), # depend on $MEASUREMENT? + "content_type": DXFAttr(172, default=2), + # 0 = None + # 1 = Block content + # 2 = MTEXT content + # 3 = TOLERANCE content + # Text Content: + "text_style_handle": DXFAttr(343), + "text_left_attachment_type": DXFAttr(173, default=1), + # Values 0-8 are used for the left/right attachment + # point (attachment direction is horizontal) + # Attachment point is: + # 0 = top of top text line + # 1 = middle of top text line + # 2 = middle of whole text + # 3 = middle of bottom text line + # 4 = bottom of bottom text line + # 5 = bottom of bottom text line & underline bottom text line + # 6 = bottom of top text line & underline top text line + # 7 = bottom of top text line + # 8 = bottom of top text line & underline all text lines + "text_right_attachment_type": DXFAttr(95, default=1), # like 173 + "text_angle_type": DXFAttr(174, default=1), + # 0 = text angle is equal to last leader line segment angle + # 1 = text is horizontal + # 2 = text angle is equal to last leader line segment angle, but potentially + # rotated by 180 degrees so the right side is up for readability. + "text_alignment_type": DXFAttr(175, default=2), + "text_color": DXFAttr(92, default=colors.BY_BLOCK_RAW_VALUE), + "has_text_frame": DXFAttr(292, default=0), + # Block Content: + "block_record_handle": DXFAttr(344), + "block_color": DXFAttr(93, default=colors.BY_BLOCK_RAW_VALUE), # raw color + "block_scale_vector": DXFAttr(10, xtype=XType.point3d, default=Vec3(1, 1, 1)), + "block_rotation": DXFAttr(43, default=0), # in radians!!! + "block_connection_type": DXFAttr(176, default=0), + # 0 = center extents + # 1 = insertion point + "is_annotative": DXFAttr(293, default=0), + # REPEAT "arrow_heads": DXF R2007+ + # arrow_head_index: 94, ??? + # arrow_head_handle: 345 + # END "arrow heads" + # REPEAT "block attribs" (ATTDEF): DXF R2007+ + # attrib_handle: 330 + # attrib_index: 177, sequential index of the label in the collection + # attrib_width: 44 + # attrib_text: 302, collision with group code (302, "LEADER{") in context data + # END "block attribs" + # Text Content: + "is_text_direction_negative": DXFAttr(294, default=0, dxfversion=const.DXF2007), + "text_IPE_align": DXFAttr(178, default=0, dxfversion=const.DXF2007), + "text_attachment_point": DXFAttr(179, default=1, dxfversion=const.DXF2007), + # 1 = left + # 2 = center + # 3 = right + "scale": DXFAttr(45, default=1, dxfversion=const.DXF2007), + # This defines whether the leaders attach to the left/right of the content + # block/text, or attach to the top/bottom: + # 0 = horizontal + # 1 = vertical + "text_attachment_direction": DXFAttr(271, default=0, dxfversion=const.DXF2010), + # like 173, but + # 9 = center + # 10= underline and center + "text_bottom_attachment_type": DXFAttr( + 272, default=9, dxfversion=const.DXF2010 + ), + # like 173, but + # 9 = center + # 10= overline and center + "text_top_attachment_type": DXFAttr(273, default=9, dxfversion=const.DXF2010), + "leader_extend_to_text": DXFAttr(295, default=0, dxfversion=const.DXF2013), + }, +) +# The text frame shape is stored in XDATA except for the default rectangle: +# 1001 ACAD +# 1070 +# 2 = rounded rectangle +# 3 = parallelogram +# 4 = triangle +# 5 = square +# 6 = pentagon +# 7 = hexagon +# 8 = octagon +# 9 = circle +# 10= ellipse + +acdb_mleader_group_codes = group_code_mapping(acdb_mleader) +CONTEXT_STR = "CONTEXT_DATA{" +LEADER_STR = "LEADER{" +LEADER_LINE_STR = "LEADER_LINE{" +START_CONTEXT_DATA = 300 +END_CONTEXT_DATA = 301 +START_LEADER = 302 +END_LEADER = 303 +START_LEADER_LINE = 304 +END_LEADER_LINE = 305 + + +def compile_context_tags( + data: list[DXFTag], stop_code: int +) -> list[Union[DXFTag, list]]: + def build_structure(tag: DXFTag, stop: int) -> list[Union[DXFTag, list]]: + collector = [tag] + tag = next(tags) + while tag.code != stop: + if tag.code == START_LEADER: + collector.append(build_structure(tag, END_LEADER)) # type: ignore + # Group code 304 is used also for MTEXT content, therefore always + # test for group code and value string: + elif tag.code == START_LEADER_LINE and tag.value == LEADER_LINE_STR: + collector.append(build_structure(tag, END_LEADER_LINE)) # type: ignore + else: + collector.append(tag) + tag = next(tags) + return collector # type: ignore + + tags = iter(data) + return build_structure(next(tags), stop_code) + + +ArrowHeadData = namedtuple("ArrowHeadData", "index, handle") +AttribData = namedtuple("AttribData", "handle, index, width, text") + + +@register_entity +class MultiLeader(DXFGraphic): + DXFTYPE = "MULTILEADER" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mleader) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def __init__(self) -> None: + super().__init__() + self.context = MLeaderContext() + self.arrow_heads: list[ArrowHeadData] = [] + self.block_attribs: list[AttribData] = [] + + @property + def has_mtext_content(self) -> bool: + """``True`` if MULTILEADER has MTEXT content.""" + return self.context.mtext is not None + + def get_mtext_content(self) -> str: + """Get MTEXT content as string, return "" if MULTILEADER has + BLOCK content. + """ + mtext = self.context.mtext + if mtext is not None: + return mtext.default_content + return "" + + def set_mtext_content(self, text: str): + """Set MTEXT content as string, does nothing if MULTILEADER has + BLOCK content. + """ + mtext = self.context.mtext + if mtext is not None: + mtext.default_content = safe_string(text, EXT_MAX_STR_LEN) + + @property + def has_block_content(self) -> bool: + """``True`` if MULTILEADER has BLOCK content.""" + return self.context.block is not None + + def get_block_content(self) -> dict[str, str]: + """Get BLOCK attributes as dictionary of (tag, value) pairs. + Returns an empty dictionary if MULTILEADER has MTEXT content. + """ + assert self.doc is not None, "valid DXF document required" + entitydb = self.doc.entitydb + tags: dict[str, str] = dict() + for attr in self.block_attribs: + attdef = entitydb.get(attr.handle) + if attdef is not None: + tags[attdef.dxf.tag] = attr.text + return tags + + def set_block_content(self, content: dict[str, str]): + """Set BLOCK attributes by a dictionary of (tag, value) pairs. + Does nothing if MULTILEADER has MTEXT content. + """ + assert self.doc is not None, "valid DXF document required" + entitydb = self.doc.entitydb + tags: dict[str, str] = dict() + block_attribs = self.block_attribs + for index, attr in enumerate(block_attribs): + attdef = entitydb.get(attr.handle) + if attdef is not None: + tag = attdef.dxf.tag + new_text = safe_string(content.get(tag), EXT_MAX_STR_LEN) + if new_text is not None: + block_attribs[index] = attr._replace(text=new_text) + return tags + + def copy_data(self, entity: DXFEntity, copy_strategy=default_copy) -> None: + """Copy leaders""" + assert isinstance(entity, MultiLeader) + entity.context = copy.deepcopy(self.context) + entity.arrow_heads = copy.deepcopy(self.arrow_heads) + entity.block_attribs = copy.deepcopy(self.block_attribs) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor is None: + return dxf + tags = processor.subclass_by_index(2) + if tags: + context = self.extract_context_data(tags) + if context: + try: + self.context = self.load_context(context) + except const.DXFStructureError: + logger.info( + f"Context structure error in entity MULTILEADER(#{dxf.handle})" + ) + else: + raise const.DXFStructureError( + f"missing 'AcDbMLeader' subclass in MULTILEADER(#{dxf.handle})" + ) + + self.arrow_heads = self.extract_arrow_heads(tags) + self.block_attribs = self.extract_block_attribs(tags) + + processor.fast_load_dxfattribs( + dxf, acdb_mleader_group_codes, subclass=tags, recover=True + ) + return dxf + + @staticmethod + def extract_context_data(tags: Tags) -> list[DXFTag]: + start, end = None, None + context_data = [] + for index, tag in enumerate(tags): + if tag.code == START_CONTEXT_DATA: + start = index + elif tag.code == END_CONTEXT_DATA: + end = index + 1 + + if start and end: + context_data = tags[start:end] + # Remove context data! + del tags[start:end] + return context_data + + @staticmethod + def load_context(data: list[DXFTag]) -> MLeaderContext: + try: + context = compile_context_tags(data, END_CONTEXT_DATA) + except StopIteration: + raise const.DXFStructureError + else: + return MLeaderContext.load(context) + + @staticmethod + def extract_arrow_heads(data: Tags) -> list[ArrowHeadData]: + def store_head(): + heads.append( + ArrowHeadData( + collector.get(94, 0), # arrow head index + collector.get(345, "0"), # arrow head handle + ) + ) + collector.clear() + + heads: list[ArrowHeadData] = [] + try: + start = data.tag_index(94) + except const.DXFValueError: + return heads + + end = start + collector = dict() + for code, value in data.collect_consecutive_tags({94, 345}, start): + end += 1 + collector[code] = value + if code == 345: + store_head() + + # Remove processed tags: + del data[start:end] + return heads + + @staticmethod + def extract_block_attribs(data: Tags) -> list[AttribData]: + def store_attrib(): + attribs.append( + AttribData( + collector.get(330, "0"), # ATTDEF handle + collector.get(177, 0), # ATTDEF index + collector.get(44, 1.0), # ATTDEF width + collector.get(302, ""), # ATTDEF text (content) + ) + ) + collector.clear() + + attribs: list[AttribData] = [] + try: + start = data.tag_index(330) + except const.DXFValueError: + return attribs + + end = start + collector: dict[int, Any] = dict() + for code, value in data.collect_consecutive_tags({330, 177, 44, 302}, start): + end += 1 + if code == 330 and len(collector): + store_attrib() + collector[code] = value + if len(collector): + store_attrib() + + # Remove processed tags: + del data[start:end] + return attribs + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + if self.context.is_valid: + return True + else: + logger.debug(f"Ignore {str(self)} at DXF export, invalid context data.") + return False + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + def write_handle_if_exist(code: int, name: str): + handle = dxf.get(name) + if handle is not None: + write_tag2(code, handle) + + super().export_entity(tagwriter) + dxf = self.dxf + version = tagwriter.dxfversion + write_tag2 = tagwriter.write_tag2 + + write_tag2(100, acdb_mleader.name) + write_tag2(270, dxf.version) + self.context.export_dxf(tagwriter) + + # Export common MLEADER tags: + # Don't use dxf.export_dxf_attribs() - all attributes should be written + # even if equal to the default value: + write_tag2(340, dxf.style_handle) + write_tag2(90, dxf.property_override_flags) + write_tag2(170, dxf.leader_type) + write_tag2(91, dxf.leader_line_color) + write_tag2(341, dxf.leader_linetype_handle) + write_tag2(171, dxf.leader_lineweight) + write_tag2(290, dxf.has_landing) + write_tag2(291, dxf.has_dogleg) + write_tag2(41, dxf.dogleg_length) + # arrow_head_handle is None for default arrow 'closed filled': + write_handle_if_exist(342, "arrow_head_handle") + write_tag2(42, dxf.arrow_head_size) + write_tag2(172, dxf.content_type) + write_tag2(343, dxf.text_style_handle) # mandatory! + write_tag2(173, dxf.text_left_attachment_type) + write_tag2(95, dxf.text_right_attachment_type) + write_tag2(174, dxf.text_angle_type) + write_tag2(175, dxf.text_alignment_type) + write_tag2(92, dxf.text_color) + write_tag2(292, dxf.has_text_frame) + + write_handle_if_exist(344, "block_record_handle") + write_tag2(93, dxf.block_color) + tagwriter.write_vertex(10, dxf.block_scale_vector) + write_tag2(43, dxf.block_rotation) + write_tag2(176, dxf.block_connection_type) + write_tag2(293, dxf.is_annotative) + if version >= const.DXF2007: + self.export_arrow_heads(tagwriter) + self.export_block_attribs(tagwriter) + write_tag2(294, dxf.is_text_direction_negative) + write_tag2(178, dxf.text_IPE_align) + write_tag2(179, dxf.text_attachment_point) + write_tag2(45, dxf.scale) + + if version >= const.DXF2010: + write_tag2(271, dxf.text_attachment_direction) + write_tag2(272, dxf.text_bottom_attachment_type) + write_tag2(273, dxf.text_top_attachment_type) + + if version >= const.DXF2013: + write_tag2(295, dxf.leader_extend_to_text) + + def export_arrow_heads(self, tagwriter: AbstractTagWriter) -> None: + for index, handle in self.arrow_heads: + tagwriter.write_tag2(94, index) + tagwriter.write_tag2(345, handle) + + def export_block_attribs(self, tagwriter: AbstractTagWriter) -> None: + for attrib in self.block_attribs: + tagwriter.write_tag2(330, attrib.handle) + tagwriter.write_tag2(177, attrib.index) + tagwriter.write_tag2(44, attrib.width) + tagwriter.write_tag2(302, safe_string(attrib.text, EXT_MAX_STR_LEN)) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + dxf = self.dxf + registry.add_handle(dxf.style_handle) + registry.add_handle(dxf.leader_linetype_handle) + registry.add_handle(dxf.arrow_head_handle) + registry.add_handle(dxf.text_style_handle) + registry.add_handle(dxf.block_record_handle) + for arrow_head in self.arrow_heads: + registry.add_handle(arrow_head.handle) + # block attdef entities are included in the block definition! + self.context.register_resources(registry) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, MultiLeader) + super().map_resources(clone, mapping) + dxf = self.dxf + clone_dxf = clone.dxf + clone_dxf.style_handle = mapping.get_handle(dxf.style_handle) + clone_dxf.leader_linetype_handle = mapping.get_handle( + dxf.leader_linetype_handle + ) + clone_dxf.arrow_head_handle = mapping.get_handle(dxf.arrow_head_handle) + clone_dxf.text_style_handle = mapping.get_handle(dxf.text_style_handle) + clone_dxf.block_record_handle = mapping.get_handle(dxf.block_record_handle) + clone.map_arrow_head_handles(mapping) + clone.map_block_attrib_handles(mapping) + clone.context.map_resources(mapping) + + def map_arrow_head_handles(self, mapping: xref.ResourceMapper): + self.arrow_heads = [ + arrow._replace(handle=mapping.get_handle(arrow.handle)) + for arrow in self.arrow_heads + ] + + def map_block_attrib_handles(self, mapping: xref.ResourceMapper): + self.block_attribs = [ + attrib._replace(handle=mapping.get_handle(attrib.handle)) + for attrib in self.block_attribs + ] + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields the graphical representation of MULTILEADER as virtual DXF + primitives. + + These entities are located at the original location, but are not stored + in the entity database, have no handle and are not assigned to any + layout. + + """ + return self.__virtual_entities__() + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explode MULTILEADER as DXF primitives into target layout, + if target layout is ``None``, the target layout is the layout of the + source entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container with all DXF + primitives. + + Args: + target_layout: target layout for the DXF primitives, ``None`` for + same layout as the source entity. + + """ + from ezdxf.explode import explode_entity + + return explode_entity(self, target_layout) + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Support for "VirtualEntities" protocol.""" + from ezdxf.render import mleader + + try: + return mleader.virtual_entities(self, proxy_graphic=True) + except ProxyGraphicError: + return mleader.virtual_entities(self, proxy_graphic=False) + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for "ReferencedBlocks" protocol.""" + # 1. overridden MLEADERSTYLE attributes + for name in ("block_record_handle", "arrow_head_handle"): + handle = self.dxf.get(name, None) + if handle is not None: + yield handle + + # 2. arrows heads + for arrow_head in self.arrow_heads: + yield arrow_head.handle + + # 3. MLeader context + if self.context.block is not None: + handle = self.context.block.block_record_handle + if handle is not None: + yield handle + + def transform(self, m: Matrix44) -> MultiLeader: + """Transform the MULTILEADER entity by transformation matrix `m` inplace. + + Non-uniform scaling is not supported. + + Args: + m: transformation :class:`~ezdxf.math.Matrix44` + + Raises: + NonUniformScalingError: for non-uniform scaling + + """ + dxf = self.dxf + context = self.context + + wcs = WCSTransform(m) + if not wcs.has_uniform_xy_scaling: + # caller has to catch this exception and explode the MULTILEADER + raise NonUniformScalingError( + "MULTILEADER does not support non-uniform scaling" + ) + if abs(context.plane_x_axis.z) > 1e-12 or abs(context.plane_y_axis.z) > 1e-12: + # check only if not parallel to xy-plane + if not wcs.has_uniform_xyz_scaling: + # caller has to catch this exception and explode the MULTILEADER + raise NonUniformScalingError( + "MULTILEADER does not support non-uniform scaling" + ) + context.transform(wcs) + # copy redundant attributes from sub-structures: + dxf.arrow_head_size = context.arrow_head_size + dxf.scale = context.scale + dxf.dogleg_length *= wcs.uniform_scale + if context.block: + dxf.block_rotation = context.block.rotation + dxf.block_scale_vector = context.block.scale + + # ArrowHeadData: no transformation needed + # AttribData: no transformation needed + self.post_transform(m) + + # The proxy graphic is stored in absolute WCS coordinates and does not + # represent the new transformed geometry. + self.update_proxy_graphic() + return self + + def update_proxy_graphic(self): + # Maybe this is supported in the future - its very unlikeLy! + self.proxy_graphic = None + + +@register_entity +class MLeader(MultiLeader): # same entity different name + DXFTYPE = "MLEADER" + + +class MLeaderContext: + ATTRIBS = { + 40: "scale", + 10: "base_point", + 41: "char_height", + 140: "arrow_head_size", + 145: "landing_gap_size", + 174: "left_attachment", + 175: "right_attachment", + 176: "text_align_type", + 177: "attachment_type", + 110: "plane_origin", + 111: "plane_x_axis", + 112: "plane_y_axis", + 297: "plane_normal_reversed", + 272: "top_attachment", + 273: "bottom_attachment", + } + + def __init__(self) -> None: + self.leaders: list[LeaderData] = [] + self.scale: float = 1.0 # overall scale + + # MTEXT base point: is not the MTEXT insertion point! + # HORIZONTAL leader attachment: + # the "base_point" is always the start point of the leader on the LEFT side + # of the MTEXT, regardless of alignment and which side leaders are attached. + # VERTICAL leader attachment: + # the "base_point" is always the start point of the leader on the BOTTOM + # side of the MTEXT, regardless of alignment and which side leaders are + # attached. + + # BLOCK base point: is not the BLOCK insertion point! + # HORIZONTAL leader attachment: + # Strange results, setting the "base_point" to the left center of the BLOCK, + # regardless which side leaders are attached, seems to be reasonable. + # VERTICAL leader attachment: not supported by BricsCAD + self.base_point: Vec3 = NULLVEC + self.char_height = 4.0 # scaled char height! + self.arrow_head_size = 4.0 + self.landing_gap_size = 2.0 + self.left_attachment = 1 + self.right_attachment = 1 + self.text_align_type = 0 # 0=left, 1=center, 2=right + self.attachment_type = 0 # 0=content extents, 1=insertion point + self.mtext: Optional[MTextData] = None + self.block: Optional[BlockData] = None + self.plane_origin: Vec3 = NULLVEC + self.plane_x_axis: Vec3 = X_AXIS + self.plane_y_axis: Vec3 = Y_AXIS + self.plane_normal_reversed: int = 0 + self.top_attachment = 9 + self.bottom_attachment = 9 + + @classmethod + def load(cls, context: list[Union[DXFTag, list]]) -> MLeaderContext: + assert context[0] == (START_CONTEXT_DATA, CONTEXT_STR) + ctx = cls() + content = None + for tag in context: + if isinstance(tag, list): # Leader() + ctx.leaders.append(LeaderData.load(tag)) + continue + # parse context tags + code, value = tag + if content: + if content.parse(code, value): + continue + else: + content = None + + if code == 290 and value == 1: + content = MTextData() + ctx.mtext = content + elif code == 296 and value == 1: + content = BlockData() # type: ignore + ctx.block = content + else: + name = MLeaderContext.ATTRIBS.get(code) + if name: + ctx.__setattr__(name, cast_value(code, value)) + return ctx + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + if self.mtext is not None: + self.mtext.register_resources(registry) + if self.block is not None: + self.block.register_resources(registry) + + def map_resources(self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + if self.mtext is not None: + self.mtext.map_resources(mapping) + if self.block is not None: + self.block.map_resources(mapping) + + @property + def is_valid(self) -> bool: + return True + + @property + def plane_z_axis(self) -> Vec3: + z_axis = self.plane_x_axis.cross(self.plane_y_axis).normalize() + if self.plane_normal_reversed: + z_axis = -z_axis + return z_axis + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag2 = tagwriter.write_tag2 + write_vertex = tagwriter.write_vertex + write_tag2(START_CONTEXT_DATA, CONTEXT_STR) + # All MLeaderContext tags: + write_tag2(40, self.scale) + write_vertex(10, self.base_point) + write_tag2(41, self.char_height) + write_tag2(140, self.arrow_head_size) + write_tag2(145, self.landing_gap_size) + write_tag2(174, self.left_attachment) + write_tag2(175, self.right_attachment) + write_tag2(176, self.text_align_type) + write_tag2(177, self.attachment_type) + + if self.mtext: + write_tag2(290, 1) # has mtext content + self.mtext.export_dxf(tagwriter) + else: + write_tag2(290, 0) + + if self.block: + write_tag2(296, 1) # has block content + self.block.export_dxf(tagwriter) + else: + write_tag2(296, 0) + + write_vertex(110, self.plane_origin) + write_vertex(111, self.plane_x_axis) + write_vertex(112, self.plane_y_axis) + write_tag2(297, self.plane_normal_reversed) + + # Export Leader and LiederLine objects: + for leader in self.leaders: + leader.export_dxf(tagwriter) + + # Additional MLeaderContext tags: + if tagwriter.dxfversion >= const.DXF2010: + write_tag2(272, self.top_attachment) + write_tag2(273, self.bottom_attachment) + write_tag2(END_CONTEXT_DATA, "}") + + def transform(self, wcs: WCSTransform) -> None: + m = wcs.m + scale = wcs.uniform_scale + self.scale *= scale + self.base_point = m.transform(self.base_point) + self.char_height *= scale + self.arrow_head_size *= scale + self.landing_gap_size *= scale + self.plane_origin = m.transform(self.plane_origin) # confirmed by BricsCAD + self.plane_x_axis = m.transform_direction(self.plane_x_axis, normalize=True) + self.plane_y_axis = m.transform_direction(self.plane_y_axis, normalize=True) + self.plane_normal_reversed = 0 + z_axis = m.transform_direction(Z_AXIS, normalize=True) + if z_axis.isclose(-self.plane_z_axis): # reversed z-axis? + self.plane_normal_reversed = 1 + + for leader in self.leaders: + leader.transform(wcs) + if self.mtext is not None: + self.mtext.transform(wcs) + if self.block is not None: + self.block.transform(wcs) + + def set_scale(self, value: float): + try: + conversion_factor = value / self.scale + except ZeroDivisionError: + return + self.scale = value + self.char_height *= conversion_factor + self.arrow_head_size *= conversion_factor + self.landing_gap_size *= conversion_factor + + +class MTextData: + ATTRIBS = { + 304: "default_content", + 11: "extrusion", + 340: "style_handle", + 12: "insert", + 13: "text_direction", + 42: "rotation", + 43: "width", + 44: "defined_height", + 45: "line_spacing_factor", + 170: "line_spacing_style", + 90: "color", + 171: "alignment", + 172: "flow_direction", + 91: "bg_color", + 141: "bg_scale_factor", + 92: "bg_transparency", + 291: "use_window_bg_color", + 292: "has_bg_fill", + 173: "column_type", + 293: "use_auto_height", + 142: "column_width", + 143: "column_gutter_width", + 294: "column_flow_reversed", + 144: "column_sizes", # multiple values + 295: "use_word_break", + } + + def __init__(self) -> None: + self.default_content: str = "" + self.extrusion: Vec3 = Z_AXIS + self.style_handle: str = "0" # handle of TextStyle() table entry + self.insert: Vec3 = NULLVEC + self.text_direction: Vec3 = X_AXIS # text direction + self.rotation: float = 0.0 # in radians! + self.width: float = 0.0 # MTEXT width, not scaled + self.defined_height: float = 0.0 # defined column height, not scaled + self.line_spacing_factor: float = 1.0 + self.line_spacing_style: int = 1 # 1=at least, 2=exactly + self.color: int = colors.BY_BLOCK_RAW_VALUE + self.alignment: int = 1 # 1=left, 2=center, 3=right + self.flow_direction: int = 1 # 1=horiz, 3=vert, 6=by style + self.bg_color: int = colors.WINDOW_BG_RAW_VALUE + self.bg_scale_factor: float = 1.5 + self.bg_transparency: int = 0 + self.use_window_bg_color: int = 0 + self.has_bg_fill: int = 0 + self.column_type: int = 0 # unknown values + self.use_auto_height: int = 0 + self.column_width: float = 0.0 # not scaled + self.column_gutter_width: float = 0.0 # not scaled + self.column_flow_reversed: int = 0 + self.column_sizes: list[float] = [] # heights?, not scaled + self.use_word_break: int = 1 + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + registry.add_handle(self.style_handle) + + def map_resources(self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + self.style_handle = mapping.get_handle(self.style_handle) + + def parse(self, code: int, value) -> bool: + # return True if data belongs to mtext else False (end of mtext section) + if code == 144: + self.column_sizes.append(float(value)) + return True + attrib = MTextData.ATTRIBS.get(code) + if attrib: + self.__setattr__(attrib, cast_value(code, value)) + return bool(attrib) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag2 = tagwriter.write_tag2 + write_vertex = tagwriter.write_vertex + write_tag2(304, safe_string(self.default_content, EXT_MAX_STR_LEN)) + write_vertex(11, self.extrusion) + write_tag2(340, safe_handle(self.style_handle)) + write_vertex(12, self.insert) + write_vertex(13, self.text_direction) + write_tag2(42, self.rotation) + write_tag2(43, self.width) + write_tag2(44, self.defined_height) + write_tag2(45, self.line_spacing_factor) + write_tag2(170, self.line_spacing_style) + write_tag2(90, self.color) + write_tag2(171, self.alignment) + write_tag2(172, self.flow_direction) + write_tag2(91, self.bg_color) + write_tag2(141, self.bg_scale_factor) + write_tag2(92, self.bg_transparency) + write_tag2(291, self.use_window_bg_color) + write_tag2(292, self.has_bg_fill) + write_tag2(173, self.column_type) + write_tag2(293, self.use_auto_height) + write_tag2(142, self.column_width) + write_tag2(143, self.column_gutter_width) + write_tag2(294, self.column_flow_reversed) + for size in self.column_sizes: + write_tag2(144, size) + write_tag2(295, self.use_word_break) + + def transform(self, wcs: WCSTransform) -> None: + # MTEXT is not really an OCS entity! + m = wcs.m + ocs = OCSTransform(self.extrusion, m) # source extrusion! + self.extrusion = ocs.new_extrusion # process like an OCS entity! + self.insert = m.transform(self.insert) # WCS + self.text_direction = wcs.m.transform_direction( # WCS + self.text_direction, normalize=True + ) + # don't use rotation ;) + self.rotation = ocs.transform_angle(self.rotation) + scale = wcs.uniform_scale + if math.isclose(scale, 1.0) or abs(scale) <= 1e-12: + return + self.width *= scale + self.defined_height *= scale + self.column_width *= scale + self.column_gutter_width *= scale + self.column_sizes = [size * scale for size in self.column_sizes] + self.default_content = scale_mtext_inline_commands( + self.default_content, scale + ) + + def apply_conversion_factor(self, conversion_factor: float): + # conversion_factor: convert from an old scaling to a new scaling + if math.isclose(conversion_factor, 1.0) or abs(conversion_factor) <= 1e-12: + return + self.width *= conversion_factor + self.defined_height *= conversion_factor + self.column_width *= conversion_factor + self.column_gutter_width *= conversion_factor + self.column_sizes = [h * conversion_factor for h in self.column_sizes] + self.default_content = scale_mtext_inline_commands( + self.default_content, conversion_factor + ) + + +class BlockData: + ATTRIBS = { + 341: "block_record_handle", + 14: "extrusion", + 15: "insert", + 16: "scale", + 46: "rotation", + 93: "color", + } + + def __init__(self) -> None: + self.block_record_handle: Optional[str] = None + self.extrusion: Vec3 = Z_AXIS + self.insert: Vec3 = NULLVEC + self.scale: Vec3 = Vec3(1, 1, 1) + self.rotation: float = 0 # in radians! + self.color: int = colors.BY_BLOCK_RAW_VALUE + # The transformation matrix is stored in transposed order + # of ezdxf.math.Matrix44()! + self._matrix: list[float] = [] # group code 47 x 16 + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + registry.add_handle(self.block_record_handle) + + def map_resources(self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert self.block_record_handle is not None + self.block_record_handle = mapping.get_handle(self.block_record_handle) + + @property + def matrix44(self) -> Matrix44: + if len(self._matrix) == 16: + m = Matrix44(self._matrix) + else: + m = Matrix44() + m.transpose() + return m + + @matrix44.setter + def matrix44(self, m: Matrix44) -> None: + m = m.copy() + m.transpose() + self._matrix = list(m) + + def parse(self, code: int, value) -> bool: + attrib = BlockData.ATTRIBS.get(code) + if attrib: + self.__setattr__(attrib, cast_value(code, value)) + elif code == 47: + self._matrix.append(float(value)) + else: + return False + # return True if data belongs to block else False (end of block section) + return True + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag2 = tagwriter.write_tag2 + write_vertex = tagwriter.write_vertex + if self.block_record_handle: + write_tag2(341, self.block_record_handle) + else: + # Do not write None, but "0" is also not valid! + # DXF structure error should be detected before export. + write_tag2(341, "0") + write_vertex(14, self.extrusion) + write_vertex(15, self.insert) + write_vertex(16, self.scale) + write_tag2(46, self.rotation) + write_tag2(93, self.color) + m = self._matrix + if len(m) != 16: + # The content of this matrix is not used for block transformation, + # not by AutoCAD nor by BricsCAD, but BricsCAD gets irritated + # if this matrix is missing. AutoCAD is fine without the presence + # of this matrix. + m = list(Matrix44()) # identity matrix + for value in m: + write_tag2(47, value) + + def transform(self, wcs: WCSTransform) -> None: + # INSERT is an OCS entity, but the insert point is WCS!!! + m = wcs.m + ocs = OCSTransform(self.extrusion, m) # source extrusion! + self.extrusion = ocs.new_extrusion + self.insert = m.transform(self.insert) # WCS coordinates!!! + self.scale = ocs.transform_scale_vector(self.scale) + self.rotation = ocs.transform_angle(self.rotation) + self.matrix44 = self.matrix44 * m + + def apply_conversion_factor(self, conversion_factor: float): + # conversion_factor: convert from an old scaling to a new scaling + self.scale *= conversion_factor + + +class LeaderData: + def __init__(self) -> None: + self.lines: list[LeaderLine] = [] + # has_last_leader_line: + # in AutoCAD the leader is invisible if set to 0 + # BricsCAD ignores this flag + self.has_last_leader_line: int = 0 # group code 290, + self.has_dogleg_vector: int = 0 # group code 291 + self.last_leader_point: Vec3 = NULLVEC # group code (10, 20, 30) in WCS + self.dogleg_vector: Vec3 = X_AXIS # group code (11, 21, 31) in WCS + self.dogleg_length: float = 1.0 # group code 40 + self.index: int = 0 # group code 90 + + # 0=horizontal; 1=vertical + self.attachment_direction: int = 0 # group code 271, R2010+ + self.breaks: list[Vec3] = [] # group code 12, 13 - multiple breaks possible! + + @property + def has_horizontal_attachment(self) -> bool: + return not bool(self.attachment_direction) + + @classmethod + def load(cls, context: list[Union[DXFTag, list]]): + assert context[0] == (START_LEADER, LEADER_STR) + leader = cls() + for tag in context: + if isinstance(tag, list): # LeaderLine() + leader.lines.append(LeaderLine.load(tag)) + continue + + code, value = tag + if code == 290: + leader.has_last_leader_line = value + elif code == 291: + leader.has_dogleg_vector = value + elif code == 10: + leader.last_leader_point = Vec3(value) + elif code == 11: + leader.dogleg_vector = Vec3(value) + elif code == 40: + leader.dogleg_length = value + elif code == 90: + leader.index = value + elif code == 271: + leader.attachment_direction = value + elif code in (12, 13): + leader.breaks.append(Vec3(value)) + + return leader + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag2 = tagwriter.write_tag2 + write_vertex = tagwriter.write_vertex + + write_tag2(START_LEADER, LEADER_STR) + write_tag2(290, self.has_last_leader_line) + write_tag2(291, self.has_dogleg_vector) + write_vertex(10, self.last_leader_point) + write_vertex(11, self.dogleg_vector) + + code = 0 + for vertex in self.breaks: + # write alternate group code 12 and 13 + write_vertex(12 + code, vertex) + code = 1 - code + write_tag2(90, self.index) + write_tag2(40, self.dogleg_length) + + # Export leader lines: + for line in self.lines: + line.export_dxf(tagwriter) + + if tagwriter.dxfversion >= const.DXF2010: + write_tag2(271, self.attachment_direction) + write_tag2(END_LEADER, "}") + + def transform(self, wcs: WCSTransform) -> None: + m = wcs.m + self.last_leader_point = m.transform(self.last_leader_point) + try: + dog_leg = m.transform_direction( + self.dogleg_vector.normalize(self.dogleg_length) + ) + except ZeroDivisionError: # dogleg_vector is NULL + dog_leg = m.transform_direction(Vec3(self.dogleg_length, 0, 0)) + self.dogleg_vector = dog_leg.normalize() + self.dogleg_length = dog_leg.magnitude + self.breaks = list(m.transform_vertices(self.breaks)) + for leader_line in self.lines: + leader_line.transform(wcs) + + +class LeaderLine: + def __init__(self) -> None: + self.vertices: list[Vec3] = [] # WCS coordinates + self.breaks: list[Union[int, Vec3]] = [] + # Breaks: 90, 11, 12, [11, 12, ...] [, 90, 11, 12 [11, 12, ...]] + # group code 90 = break index + # group code 11 = start vertex of break + # group code 12 = end vertex of break + # multiple breaks per index possible + self.index: int = 0 # group code 91 + self.color: int = colors.BY_BLOCK_RAW_VALUE # group code 92 + # R2010+: override properties see ODA DWG pg. 214-215 + + @classmethod + def load(cls, tags: list[DXFTag]): + assert tags[0] == (START_LEADER_LINE, LEADER_LINE_STR) + line = LeaderLine() + vertices = line.vertices + breaks = [] + for code, value in tags: + if code == 10: + vertices.append(Vec3(value)) + elif code in (90, 11, 12): + breaks.append(cast_value(code, value)) + elif code == 91: + line.index = value + elif code == 92: + line.color = value + if breaks: + line.breaks = breaks + return line + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag2 = tagwriter.write_tag2 + write_vertex = tagwriter.write_vertex + + write_tag2(START_LEADER_LINE, LEADER_LINE_STR) + for vertex in self.vertices: + write_vertex(10, vertex) + if self.breaks: + code = 0 + for value in self.breaks: + if isinstance(value, int): + # break index + write_tag2(90, value) + else: + # 11 .. start vertex of break + # 12 .. end vertex of break + write_vertex(11 + code, value) + code = 1 - code + write_tag2(91, self.index) + write_tag2(92, self.color) + write_tag2(END_LEADER_LINE, "}") + + def transform(self, wcs: WCSTransform) -> None: + m = wcs.m + self.vertices = list(m.transform_vertices(self.vertices)) + if self.breaks: + breaks: list[Union[int, Vec3]] = [] + for value in self.breaks: + if isinstance(value, Vec3): + breaks.append(m.transform(value)) + else: # break index + breaks.append(value) + self.breaks = breaks + + +acdb_mleader_style = DefSubclass( + "AcDbMLeaderStyle", + { + "unknown1": DXFAttr(179, default=2), + "content_type": DXFAttr(170, default=2), + "draw_mleader_order_type": DXFAttr(171, default=1), + "draw_leader_order_type": DXFAttr(172, default=0), + "max_leader_segments_points": DXFAttr(90, default=2), + "first_segment_angle_constraint": DXFAttr(40, default=0.0), + "second_segment_angle_constraint": DXFAttr(41, default=0.0), + # leader_type: + # 0 = invisible + # 1 = straight line leader + # 2 = spline leader + "leader_type": DXFAttr(173, default=1), + "leader_line_color": DXFAttr(91, default=colors.BY_BLOCK_RAW_VALUE), + "leader_linetype_handle": DXFAttr(340), + "leader_lineweight": DXFAttr(92, default=-2), + "has_landing": DXFAttr(290, default=1), + "landing_gap_size": DXFAttr(42, default=2.0), + "has_dogleg": DXFAttr(291, default=1), + "dogleg_length": DXFAttr(43, default=8), + "name": DXFAttr(3, default="Standard"), # description text + # no handle is default arrow 'closed filled': + "arrow_head_handle": DXFAttr(341), + "arrow_head_size": DXFAttr(44, default=4), + "default_text_content": DXFAttr(300, default=""), + "text_style_handle": DXFAttr(342), + "text_left_attachment_type": DXFAttr(174, default=1), + "text_angle_type": DXFAttr(175, default=1), + "text_alignment_type": DXFAttr(176, default=0), + "text_right_attachment_type": DXFAttr(178, default=1), + "text_color": DXFAttr(93, default=colors.BY_BLOCK_RAW_VALUE), + "char_height": DXFAttr(45, default=4), + "has_text_frame": DXFAttr(292, default=0), + "text_align_always_left": DXFAttr(297, default=0), + "align_space": DXFAttr(46, default=4), + "has_block_scaling": DXFAttr(293), + "block_record_handle": DXFAttr(343), + "block_color": DXFAttr(94, default=colors.BY_BLOCK_RAW_VALUE), + "block_scale_x": DXFAttr(47, default=1), + "block_scale_y": DXFAttr(49, default=1), + "block_scale_z": DXFAttr(140, default=1), + "has_block_rotation": DXFAttr(294, default=1), + "block_rotation": DXFAttr(141, default=0), + "block_connection_type": DXFAttr(177, default=0), + "scale": DXFAttr(142, default=1), + "overwrite_property_value": DXFAttr(295, default=0), + "is_annotative": DXFAttr(296, default=0), + "break_gap_size": DXFAttr(143, default=3.75), + # 0 = Horizontal; 1 = Vertical: + "text_attachment_direction": DXFAttr(271, default=0), + # 9 = Center; 10 = Underline and Center: + "text_bottom_attachment_type": DXFAttr(272, default=9), + # 9 = Center; 10 = Overline and Center: + "text_top_attachment_type": DXFAttr(273, default=9), + "unknown2": DXFAttr(298, optional=True), # boolean flag ? + }, +) +acdb_mleader_style_group_codes = group_code_mapping(acdb_mleader_style) + +MLEADER_STYLE_HANDLE_ATTRIBS = ( + "leader_linetype_handle", + "arrow_head_handle", + "text_style_handle", + "block_record_handle", +) + + +@register_entity +class MLeaderStyle(DXFObject): + DXFTYPE = "MLEADERSTYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_mleader_style) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_mleader_style_group_codes, subclass=1 + ) + return dxf + + def register_resources(self, registry: xref.Registry) -> None: + super().register_resources(registry) + dxf = self.dxf + for attrib_name in MLEADER_STYLE_HANDLE_ATTRIBS: + registry.add_handle(dxf.get(attrib_name, "0")) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + super().map_resources(clone, mapping) + dxf = self.dxf + for attrib_name in MLEADER_STYLE_HANDLE_ATTRIBS: + if dxf.hasattr(attrib_name): + clone.dxf.set(attrib_name, mapping.get_handle(dxf.get(attrib_name))) + else: + clone.dxf.discard(attrib_name) + + def set_mtext_style(self, name: str) -> None: + assert self.doc is not None, "valid DXF document required" + style = self.doc.styles.get(name) + if style is not None: + self.dxf.text_style_handle = style.dxf.handle + else: + raise ValueError(f"text style '{name}' does not exist") + + def set_leader_properties( + self, + color: Union[int, colors.RGB] = colors.BYBLOCK, + linetype: str = "BYBLOCK", + lineweight: int = const.LINEWEIGHT_BYBLOCK, + leader_type: int = 1, + ): + assert self.doc is not None, "valid DXF document required" + self.dxf.leader_line_color = colors.encode_raw_color(color) + linetype_ = self.doc.linetypes.get(linetype) + if linetype_ is None: + raise ValueError(f"invalid linetype name '{linetype}'") + self.dxf.leader_linetype_handle = linetype_.dxf.handle + self.dxf.leader_lineweight = int(lineweight) + self.dxf.leader_type = int(leader_type) + + def set_arrow_head(self, name: str = ""): + from ezdxf.render.arrows import ARROWS + + assert self.doc is not None, "valid DXF document required" + if name: + self.dxf.arrow_head_handle = ARROWS.arrow_handle(self.doc.blocks, name) + else: + # empty string is the default "closed filled" arrow, + # no handle needed + del self.dxf.arrow_head_handle + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_mleader_style.name) + self.dxf.export_dxf_attribs(tagwriter, acdb_mleader_style.attribs.keys()) + + def __referenced_blocks__(self) -> Iterable[str]: + """Support for "ReferencedBlocks" protocol.""" + for name in ("block_record_handle", "arrow_head_handle"): + handle = self.dxf.get(name, None) + if handle is not None: + yield handle + + def audit(self, auditor: Auditor) -> None: + from ezdxf.audit import AuditError + + if not self.is_alive: + return + super().audit(auditor) + entitydb = auditor.entitydb + dxf = self.dxf + name = str(self) + handle = dxf.get("text_style_handle", None) + if handle is not None and handle not in entitydb: + standard = auditor.doc.styles.get("Standard") + if standard is not None: + self.dxf.text_style_handle = standard.dxf.handle + auditor.fixed_error( + AuditError.UNDEFINED_TEXT_STYLE, + f"{name}: text_style_handle={handle} is not valid, replaced by " + f"'Standard' text style", + self, + ) + else: + logger.warning("required text style 'Standard' does not exist") + self.dxf.discard("text_style_handle") + auditor.fixed_error( + AuditError.UNDEFINED_TEXT_STYLE, + f"{name}: removed invalid text_style_handle={handle}", + self, + ) + for attrib in ("arrow_head_handle", "block_record_handle"): + handle = dxf.get(attrib) + if handle is None or handle == "0": # legit "undefined values" + continue + if handle not in entitydb: + dxf.discard(attrib) + auditor.fixed_error( + AuditError.UNDEFINED_BLOCK, + f"{name}: removed invalid {attrib}={handle}", + self, + ) + + +class MLeaderStyleCollection(ObjectCollection[MLeaderStyle]): + def __init__(self, doc: Drawing): + super().__init__(doc, dict_name="ACAD_MLEADERSTYLE", object_type="MLEADERSTYLE") + self.create_required_entries() + + def create_required_entries(self) -> None: + if "Standard" not in self: + mleader_style = self.new("Standard") + # set standard text style + text_style = self.doc.styles.get("Standard") + mleader_style.dxf.text_style_handle = text_style.dxf.handle diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mline.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mline.py new file mode 100644 index 0000000..80350f1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mline.py @@ -0,0 +1,967 @@ +# Copyright (c) 2018-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Optional, + Sequence, + Iterator, +) +from typing_extensions import Self + +from collections import OrderedDict, namedtuple +import math + +from ezdxf.audit import AuditError +from ezdxf.entities.factory import register_entity +from ezdxf.lldxf import const, validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags, group_tags +from ezdxf.math import NULLVEC, X_AXIS, Y_AXIS, Z_AXIS, UVec, Vec3, UCS, OCS + +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .dxfgfx import DXFGraphic, acdb_entity +from .objectcollection import ObjectCollection +from .copy import default_copy +import logging + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.layouts import BaseLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + from ezdxf.query import EntityQuery + from ezdxf import xref + +__all__ = ["MLine", "MLineVertex", "MLineStyle", "MLineStyleCollection"] +logger = logging.getLogger("ezdxf") + +# Usage example: CADKitSamples\Lock-Off.dxf + + +def filter_close_vertices( + vertices: Iterable[Vec3], abs_tol: float = 1e-12 +) -> Iterable[Vec3]: + prev = None + for vertex in vertices: + if prev is None: + yield vertex + prev = vertex + else: + if not vertex.isclose(prev, abs_tol=abs_tol): + yield vertex + prev = vertex + + +acdb_mline = DefSubclass( + "AcDbMline", + OrderedDict( + { + "style_name": DXFAttr(2, default="Standard"), + "style_handle": DXFAttr(340), + "scale_factor": DXFAttr( + 40, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Justification + # 0 = Top (Right) + # 1 = Zero (Center) + # 2 = Bottom (Left) + "justification": DXFAttr( + 70, + default=0, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + # Flags (bit-coded values): + # 1 = Has at least one vertex (code 72 is greater than 0) + # 2 = Closed + # 4 = Suppress start caps + # 8 = Suppress end caps + "flags": DXFAttr(71, default=1), + # Number of MLINE vertices + "count": DXFAttr(72, xtype=XType.callback, getter="__len__"), + # Number of elements in MLINESTYLE definition + "style_element_count": DXFAttr(73, default=2), + # start location in WCS! + "start_location": DXFAttr( + 10, xtype=XType.callback, getter="start_location" + ), + # Normal vector of the entity plane, but all vertices in WCS! + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # MLine data: + # 11: vertex coordinates + # Multiple entries; one entry for each vertex. + # 12: Direction vector of segment starting at this vertex + # Multiple entries; one for each vertex. + # 13: Direction vector of miter at this vertex + # Multiple entries: one for each vertex. + # 74: Number of parameters for this element, + # repeats for each element in segment + # 41: Element parameters, + # repeats based on previous code 74 + # 75: Number of area fill parameters for this element, + # repeats for each element in segment + # 42: Area fill parameters, + # repeats based on previous code 75 + } + ), +) +acdb_mline_group_codes = group_code_mapping(acdb_mline) + + +# For information about line- and fill parametrization see comments in class +# MLineVertex(). +# +# The 2 group codes in mline entities and mlinestyle objects are redundant +# fields. These groups should not be modified under any circumstances, although +# it is safe to read them and use their values. The correct fields to modify +# are as follows: +# +# Mline +# The 340 group in the same object, which indicates the proper MLINESTYLE +# object. +# +# Mlinestyle +# The 3 group value in the MLINESTYLE dictionary, which precedes the 350 group +# that has the handle or entity name of +# the current mlinestyle. + +# Facts and assumptions not clearly defined by the DXF reference: +# - the reference line is defined by the group code 11 points (fact) +# - all line segments are parallel to the reference line (assumption) +# - all line vertices are located in the same plane, the orientation of the plane +# is defined by the extrusion vector (assumption) +# - the scale factor is applied to to all geometries +# - the start- and end angle (MLineStyle) is also applied to the first and last +# miter direction vector +# - the last two points mean: all geometries and direction vectors can be used +# as stored in the DXF file no additional scaling or rotation is necessary +# for the MLINE rendering. Disadvantage: minor changes of DXF attributes +# require a refresh of the MLineVertices. + +# Ezdxf does not support the creation of line-break (gap) features, but will be +# preserving this data if the MLINE stays unchanged. +# Editing the MLINE entity by ezdxf removes the line-break features (gaps). + + +class MLineVertex: + def __init__(self) -> None: + self.location: Vec3 = NULLVEC + self.line_direction: Vec3 = X_AXIS + self.miter_direction: Vec3 = Y_AXIS + + # Line parametrization (74/41) + # ---------------------------- + # The line parameterization is a list of float values. + # The list may contain zero or more items. + # + # The first value (miter-offset) is the distance from the vertex + # location along the miter direction vector to the point where the + # line element's path intersects the miter vector. + # + # The next value (line-start-offset) is the distance along the line + # direction from the miter/line path intersection point to the actual + # start of the line element. + # + # The next value (dash-length) is the distance from the start of the + # line element (dash) to the first break (or gap) in the line element. + # The successive values continue to list the start and stop points of + # the line element in this segment of the mline. + # Linetypes do not affect the line parametrization. + # + # + # 1. line element: [miter-offset, line-start-offset, dash, gap, dash, ...] + # 2. line element: [...] + # ... + self.line_params: list[Sequence[float]] = [] + """ The line parameterization is a list of float values. + The list may contain zero or more items. + """ + + # Fill parametrization (75/42) + # ---------------------------- + # + # The fill parameterization is also a list of float values. + # Similar to the line parametrization, it describes the + # parametrization of the fill area for this mline segment. + # The values are interpreted identically to the line parameters and when + # taken as a whole for all line elements in the mline segment, they + # define the boundary of the fill area for the mline segment. + # + # A common example of the use of the fill mechanism is when an + # unfilled mline crosses over a filled mline and "mledit" is used to + # cause the filled mline to appear unfilled in the crossing area. + # This would result in two fill parameters for each line element in the + # affected mline segment; one for the fill stop and one for the fill + # start. + # + # [dash-length, gap-length, ...]? + self.fill_params: list[Sequence[float]] = [] + + def __copy__(self) -> MLineVertex: + vtx = self.__class__() + vtx.location = self.location + vtx.line_direction = self.line_direction + vtx.miter_direction = self.miter_direction + vtx.line_params = list(self.line_params) + vtx.fill_params = list(self.fill_params) + return vtx + + copy = __copy__ + + @classmethod + def load(cls, tags: Tags) -> MLineVertex: + vtx = MLineVertex() + line_params: list[float] = [] + line_params_count = 0 + fill_params: list[float] = [] + fill_params_count = 0 + for code, value in tags: + if code == 11: + vtx.location = Vec3(value) + elif code == 12: + vtx.line_direction = Vec3(value) + elif code == 13: + vtx.miter_direction = Vec3(value) + elif code == 74: + line_params_count = value + if line_params_count == 0: + vtx.line_params.append(tuple()) + else: + line_params = [] + elif code == 41: + line_params.append(value) + line_params_count -= 1 + if line_params_count == 0: + vtx.line_params.append(tuple(line_params)) + line_params = [] + elif code == 75: + fill_params_count = value + if fill_params_count == 0: + vtx.fill_params.append(tuple()) + else: + fill_params = [] + elif code == 42: + fill_params.append(value) + fill_params_count -= 1 + if fill_params_count == 0: + vtx.fill_params.append(tuple(fill_params)) + return vtx + + def export_dxf(self, tagwriter: AbstractTagWriter): + tagwriter.write_vertex(11, self.location) + tagwriter.write_vertex(12, self.line_direction) + tagwriter.write_vertex(13, self.miter_direction) + for line_params, fill_params in zip(self.line_params, self.fill_params): + tagwriter.write_tag2(74, len(line_params)) + for param in line_params: + tagwriter.write_tag2(41, param) + tagwriter.write_tag2(75, len(fill_params)) + for param in fill_params: + tagwriter.write_tag2(42, param) + + @classmethod + def new( + cls, + start: UVec, + line_direction: UVec, + miter_direction: UVec, + line_params: Optional[Iterable[Sequence[float]]] = None, + fill_params: Optional[Iterable[Sequence[float]]] = None, + ) -> MLineVertex: + vtx = MLineVertex() + vtx.location = Vec3(start) + vtx.line_direction = Vec3(line_direction) + vtx.miter_direction = Vec3(miter_direction) + vtx.line_params = list(line_params or []) + vtx.fill_params = list(fill_params or []) + if len(vtx.line_params) != len(vtx.fill_params): + raise const.DXFValueError("Count mismatch of line- and fill parameters") + return vtx + + def transform(self, m: Matrix44) -> MLineVertex: + """Transform MLineVertex by transformation matrix `m` inplace.""" + self.location = m.transform(self.location) + self.line_direction = m.transform_direction(self.line_direction) + self.miter_direction = m.transform_direction(self.miter_direction) + return self + + +@register_entity +class MLine(DXFGraphic): + DXFTYPE = "MLINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mline) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + TOP = const.MLINE_TOP + ZERO = const.MLINE_ZERO + BOTTOM = const.MLINE_BOTTOM + HAS_VERTICES = const.MLINE_HAS_VERTICES + CLOSED = const.MLINE_CLOSED + SUPPRESS_START_CAPS = const.MLINE_SUPPRESS_START_CAPS + SUPPRESS_END_CAPS = const.MLINE_SUPPRESS_END_CAPS + + def __init__(self) -> None: + super().__init__() + # The MLINE geometry stored in vertices, is the final geometry, + # scaling factor, justification and MLineStyle settings are already + # applied. This is why the geometry has to be updated every time a + # change is applied. + self.vertices: list[MLineVertex] = [] + + def __len__(self): + """Count of MLINE vertices.""" + return len(self.vertices) + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, MLine) + entity.vertices = [v.copy() for v in self.vertices] + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_mline_group_codes, 2, log=False + ) + self.load_vertices(tags) + return dxf + + def load_vertices(self, tags: Tags) -> None: + self.vertices.extend( + MLineVertex.load(tags) for tags in group_tags(tags, splitcode=11) + ) + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + # Do not export MLines without vertices + return len(self.vertices) > 1 + # todo: check if line- and fill parametrization is compatible with + # MLINE style, requires same count of elements! + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + # ezdxf does not export MLINE entities without vertices, + # see method preprocess_export() + self.set_flag_state(self.HAS_VERTICES, True) + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_mline.name) + self.dxf.export_dxf_attribs(tagwriter, acdb_mline.attribs.keys()) + self.export_vertices(tagwriter) + + def export_vertices(self, tagwriter: AbstractTagWriter) -> None: + for vertex in self.vertices: + vertex.export_dxf(tagwriter) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + registry.add_handle(self.dxf.style_handle) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + super().map_resources(clone, mapping) + style = mapping.get_reference_of_copy(self.dxf.style_handle) + if not isinstance(style, MLineStyle): + assert clone.doc is not None + style = clone.doc.mline_styles.get("Standard") + if isinstance(style, MLineStyle): + clone.dxf.style_handle = style.dxf.handle + clone.dxf.style_name = style.dxf.name + else: + clone.dxf.style_handle = "0" + clone.dxf.style_name = "Standard" + + @property + def is_closed(self) -> bool: + """Returns ``True`` if MLINE is closed. + Compatibility interface to :class:`Polyline` + """ + return self.get_flag_state(self.CLOSED) + + def close(self, state: bool = True) -> None: + """Get/set closed state of MLINE and update geometry accordingly. + Compatibility interface to :class:`Polyline` + """ + state = bool(state) + if state != self.is_closed: + self.set_flag_state(self.CLOSED, state) + self.update_geometry() + + @property + def start_caps(self) -> bool: + """Get/Set start caps state. ``True`` to enable start caps and + ``False`` tu suppress start caps.""" + return not self.get_flag_state(self.SUPPRESS_START_CAPS) + + @start_caps.setter + def start_caps(self, value: bool) -> None: + """Set start caps state.""" + self.set_flag_state(self.SUPPRESS_START_CAPS, not bool(value)) + + @property + def end_caps(self) -> bool: + """Get/Set end caps state. ``True`` to enable end caps and + ``False`` tu suppress start caps.""" + return not self.get_flag_state(self.SUPPRESS_END_CAPS) + + @end_caps.setter + def end_caps(self, value: bool) -> None: + """Set start caps state.""" + self.set_flag_state(self.SUPPRESS_END_CAPS, not bool(value)) + + def set_scale_factor(self, value: float) -> None: + """Set the scale factor and update geometry accordingly.""" + value = float(value) + if not math.isclose(self.dxf.scale_factor, value): + self.dxf.scale_factor = value + self.update_geometry() + + def set_justification(self, value: int) -> None: + """Set MLINE justification and update geometry accordingly. + See :attr:`dxf.justification` for valid settings. + """ + value = int(value) + if self.dxf.justification != value: + self.dxf.justification = value + self.update_geometry() + + @property + def style(self) -> Optional[MLineStyle]: + """Get associated MLINESTYLE.""" + if self.doc is None: + return None + _style = self.doc.entitydb.get(self.dxf.style_handle) + if _style is None: + _style = self.doc.mline_styles.get(self.dxf.style_name) + return _style # type: ignore + + def set_style(self, name: str) -> None: + """Set MLINESTYLE by name and update geometry accordingly. + The MLINESTYLE definition must exist. + """ + if self.doc is None: + logger.debug("Can't change style of unbounded MLINE entity.") + return + try: + style = self.doc.mline_styles[name] + except const.DXFKeyError: + raise const.DXFValueError(f"Undefined MLINE style: {name}") + assert isinstance(style, MLineStyle) + # Line- and fill parametrization depends on the count of + # elements, a change in the number of elements triggers a + # reset of the parametrization: + old_style = self.style + new_element_count = len(style.elements) + reset = False + if old_style is not None: + # Do not trust the stored "style_element_count" value + reset = len(old_style.elements) != new_element_count + + self.dxf.style_name = name + self.dxf.style_handle = style.dxf.handle + self.dxf.style_element_count = new_element_count + if reset: + self.update_geometry() + + def start_location(self) -> Vec3: + """Returns the start location of the reference line. Callback function + for :attr:`dxf.start_location`. + """ + if len(self.vertices): + return self.vertices[0].location + else: + return NULLVEC + + def get_locations(self) -> list[Vec3]: + """Returns the vertices of the reference line.""" + return [v.location for v in self.vertices] + + def extend(self, vertices: Iterable[UVec]) -> None: + """Append multiple vertices to the reference line. + + It is possible to work with 3D vertices, but all vertices have to be in + the same plane and the normal vector of this plan is stored as + extrusion vector in the MLINE entity. + + """ + vertices = Vec3.list(vertices) + if not vertices: + return + all_vertices = [] + if len(self): + all_vertices.extend(self.get_locations()) + all_vertices.extend(vertices) + self.generate_geometry(all_vertices) + + def update_geometry(self) -> None: + """Regenerate the MLINE geometry based on current settings.""" + self.generate_geometry(self.get_locations()) + + def generate_geometry(self, vertices: list[Vec3]) -> None: + """Regenerate the MLINE geometry for new reference line defined by + `vertices`. + """ + vertices = list(filter_close_vertices(vertices, abs_tol=1e-6)) + if len(vertices) == 0: + self.clear() + return + elif len(vertices) == 1: + self.vertices = [MLineVertex.new(vertices[0], X_AXIS, Y_AXIS)] + return + + style = self.style + assert style is not None, "valid MLINE style required" + if len(style.elements) == 0: + raise const.DXFStructureError(f"No line elements defined in {str(style)}.") + + def miter(dir1: Vec3, dir2: Vec3): + return ((dir1 + dir2) * 0.5).normalize().orthogonal() + + ucs = UCS.from_z_axis_and_point_in_xz( + origin=vertices[0], + point=vertices[1], + axis=self.dxf.extrusion, + ) + # Transform given vertices into UCS and project them into the + # UCS-xy-plane by setting the z-axis to 0: + vertices = [v.replace(z=0.0) for v in ucs.points_from_wcs(vertices)] + start_angle = style.dxf.start_angle + end_angle = style.dxf.end_angle + + line_directions = [ + (v2 - v1).normalize() for v1, v2 in zip(vertices, vertices[1:]) + ] + + if self.is_closed: + line_directions.append((vertices[0] - vertices[-1]).normalize()) + closing_miter = miter(line_directions[0], line_directions[-1]) + miter_directions = [closing_miter] + else: + closing_miter = None + line_directions.append(line_directions[-1]) + miter_directions = [line_directions[0].rotate_deg(start_angle)] + + for d1, d2 in zip(line_directions, line_directions[1:]): + miter_directions.append(miter(d1, d2)) + + if closing_miter is None: + miter_directions.pop() + miter_directions.append(line_directions[-1].rotate_deg(end_angle)) + else: + miter_directions.append(closing_miter) + + self.vertices = [ + MLineVertex.new(v, d, m) + for v, d, m in zip(vertices, line_directions, miter_directions) + ] + self._update_parametrization() + + # reverse transformation into WCS + for v in self.vertices: + v.transform(ucs.matrix) + + def _update_parametrization(self): + scale = self.dxf.scale_factor + style = self.style + + justification = self.dxf.justification + offsets = [e.offset for e in style.elements] + min_offset = min(offsets) + max_offset = max(offsets) + shift = 0 + if justification == self.TOP: + shift = -max_offset + elif justification == self.BOTTOM: + shift = -min_offset + + for vertex in self.vertices: + angle = vertex.line_direction.angle_between(vertex.miter_direction) + try: + stretch = scale / math.sin(angle) + except ZeroDivisionError: + stretch = 1.0 + vertex.line_params = [ + ((element.offset + shift) * stretch, 0.0) for element in style.elements + ] + vertex.fill_params = [tuple() for _ in style.elements] + + def clear(self) -> None: + """Remove all MLINE vertices.""" + self.vertices.clear() + + def remove_dependencies(self, other: Optional[Drawing] = None) -> None: + """Remove all dependencies from current document. + + (internal API) + """ + if not self.is_alive: + return + + super().remove_dependencies(other) + self.dxf.style_handle = "0" + if other: + style = other.mline_styles.get(self.dxf.style_name) + if style: + self.dxf.style_handle = style.dxf.handle + return + self.dxf.style_name = "Standard" + + def transform(self, m: Matrix44) -> Self: + """Transform MLINE entity by transformation matrix `m` inplace.""" + for vertex in self.vertices: + vertex.transform(m) + self.dxf.extrusion = m.transform_direction(self.dxf.extrusion) + scale = self.dxf.scale_factor + scale_vec = m.transform_direction(Vec3(scale, scale, scale)) + if math.isclose(scale_vec.x, scale_vec.y, abs_tol=1e-6) and math.isclose( + scale_vec.y, scale_vec.z, abs_tol=1e-6 + ): + self.dxf.scale_factor = sum(scale_vec) / 3 # average error + # None uniform scaling will not be applied to the scale_factor! + self.update_geometry() + self.post_transform(m) + return self + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol. + + This protocol is for consistent internal usage and does not replace + the method :meth:`virtual_entities`! + """ + from ezdxf.render.mline import virtual_entities + + for e in virtual_entities(self): + e.set_source_of_copy(self) + yield e + + def virtual_entities(self) -> Iterator[DXFGraphic]: + """Yields virtual DXF primitives of the MLINE entity as LINE, ARC and HATCH + entities. + + These entities are located at the original positions, but are not stored + in the entity database, have no handle and are not assigned to any + layout. + + """ + return self.__virtual_entities__() + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explode the MLINE entity as LINE, ARC and HATCH entities into target + layout, if target layout is ``None``, the target layout is the layout + of the MLINE. This method destroys the source entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container referencing all DXF + primitives. + + Args: + target_layout: target layout for DXF primitives, ``None`` for same layout + as source entity. + """ + from ezdxf.explode import explode_entity + + return explode_entity(self, target_layout) + + def audit(self, auditor: Auditor) -> None: + """Validity check.""" + + def reset_mline_style(name="Standard"): + auditor.fixed_error( + code=AuditError.RESET_MLINE_STYLE, + message=f'Reset MLINESTYLE to "{name}" in {str(self)}.', + dxf_entity=self, + ) + self.dxf.style_name = name + style = doc.mline_styles.get(name) + self.dxf.style_handle = style.dxf.handle + + super().audit(auditor) + doc = auditor.doc + if doc is None: + return + + # Audit associated MLINESTYLE name and handle: + style = doc.entitydb.get(self.dxf.style_handle) + if not isinstance(style, MLineStyle): # handle is invalid, get style by name + style = doc.mline_styles.get(self.dxf.style_name, None) + if style is None: + reset_mline_style() + else: # fix MLINESTYLE handle: + auditor.fixed_error( + code=AuditError.INVALID_MLINESTYLE_HANDLE, + message=f"Fixed invalid style handle in {str(self)}.", + dxf_entity=self, + ) + self.dxf.style_handle = style.dxf.handle + else: # update MLINESTYLE name silently + self.dxf.style_name = style.dxf.name + + # Get current (maybe fixed) MLINESTYLE: + style = self.style + assert style is not None, "valid MLINE style required" + + # Update style element count silently: + element_count = len(style.elements) + self.dxf.style_element_count = element_count + + # Audit vertices: + for vertex in self.vertices: + if NULLVEC.isclose(vertex.line_direction): + break + if NULLVEC.isclose(vertex.miter_direction): + break + if len(vertex.line_params) != element_count: + break + # Ignore fill parameters. + else: # no break + return + + # Invalid vertices found: + auditor.fixed_error( + code=AuditError.INVALID_MLINE_VERTEX, + message=f"Execute geometry update for {str(self)}.", + dxf_entity=self, + ) + self.update_geometry() + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() + + +acdb_mline_style = DefSubclass( + "AcDbMlineStyle", + { + "name": DXFAttr(2, default="Standard"), + # Flags (bit-coded): + # 1 =Fill on + # 2 = Display miters + # 16 = Start square end (line) cap + # 32 = Start inner arcs cap + # 64 = Start round (outer arcs) cap + # 256 = End square (line) cap + # 512 = End inner arcs cap + # 1024 = End round (outer arcs) cap + "flags": DXFAttr(70, default=0), + # Style description (string, 255 characters maximum): + "description": DXFAttr(3, default=""), + # Fill color (integer, default = 256): + "fill_color": DXFAttr( + 62, + default=256, + validator=validator.is_valid_aci_color, + fixer=RETURN_DEFAULT, + ), + # Start angle (real, default is 90 degrees): + "start_angle": DXFAttr(51, default=90), + # End angle (real, default is 90 degrees): + "end_angle": DXFAttr(52, default=90), + # 71: Number of elements + # 49: Element offset (real, no default). + # Multiple entries can exist; one entry for each element + # 62: Element color (integer, default = 0). + # Multiple entries can exist; one entry for each element + # 6: Element linetype (string, default = BYLAYER). + # Multiple entries can exist; one entry for each element + }, +) +acdb_mline_style_group_codes = group_code_mapping(acdb_mline_style) +MLineStyleElement = namedtuple("MLineStyleElement", "offset color linetype") + + +class MLineStyleElements: + def __init__(self, tags: Optional[Tags] = None): + self.elements: list[MLineStyleElement] = [] + if tags: + for e in self.parse_tags(tags): + data = MLineStyleElement( + e.get("offset", 1.0), + e.get("color", 0), + e.get("linetype", "BYLAYER"), + ) + self.elements.append(data) + + def copy(self) -> MLineStyleElements: + elements = MLineStyleElements() + # new list of immutable data + elements.elements = list(self.elements) + return elements + + def __len__(self): + return len(self.elements) + + def __getitem__(self, item): + return self.elements[item] + + def __iter__(self): + return iter(self.elements) + + def export_dxf(self, tagwriter: AbstractTagWriter): + write_tag = tagwriter.write_tag2 + write_tag(71, len(self.elements)) + for offset, color, linetype in self.elements: + write_tag(49, offset) + write_tag(62, color) + write_tag(6, linetype) + + def append(self, offset: float, color: int = 0, linetype: str = "BYLAYER") -> None: + """Append a new line element. + + Args: + offset: normal offset from the reference line: if justification is + ``MLINE_ZERO``, positive values are above and negative values + are below the reference line. + color: :ref:`ACI` value + linetype: linetype name + + """ + self.elements.append( + MLineStyleElement(float(offset), int(color), str(linetype)) + ) + + @staticmethod + def parse_tags(tags: Tags) -> Iterator[dict]: + collector = None + for code, value in tags: + if code == 49: + if collector is not None: + yield collector + collector = {"offset": value} + elif code == 62: + collector["color"] = value # type: ignore + elif code == 6: + collector["linetype"] = value # type: ignore + if collector is not None: + yield collector + + def ordered_indices(self) -> list[int]: + offsets = [e.offset for e in self.elements] + return [offsets.index(value) for value in sorted(offsets)] + + +@register_entity +class MLineStyle(DXFObject): + DXFTYPE = "MLINESTYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_mline_style) + FILL = const.MLINESTYLE_FILL + MITER = const.MLINESTYLE_MITER + START_SQUARE = const.MLINESTYLE_START_SQUARE + START_INNER_ARC = const.MLINESTYLE_START_INNER_ARC + START_ROUND = const.MLINESTYLE_START_ROUND + END_SQUARE = const.MLINESTYLE_END_SQUARE + END_INNER_ARC = const.MLINESTYLE_END_INNER_ARC + END_ROUND = const.MLINESTYLE_END_ROUND + + def __init__(self): + super().__init__() + self.elements = MLineStyleElements() + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, MLineStyle) + entity.elements = self.elements.copy() + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(1) + if tags is None: + raise const.DXFStructureError( + f"missing 'AcDbMLine' subclass in MLINE(#{dxf.handle})" + ) + + try: + # Find index of the count tag: + index71 = tags.tag_index(71) + except const.DXFValueError: + # The count tag does not exist: DXF structure error? + pass + else: + self.elements = MLineStyleElements(tags[index71 + 1 :]) # type: ignore + # Remove processed tags: + del tags[index71:] + processor.fast_load_dxfattribs(dxf, acdb_mline_style_group_codes, tags) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_mline_style.name) + self.dxf.export_dxf_attribs(tagwriter, acdb_mline_style.attribs.keys()) + self.elements.export_dxf(tagwriter) + + def update_all(self): + """Update all MLINE entities using this MLINESTYLE. + + The update is required if elements were added or removed or the offset + of any element was changed. + + """ + if self.doc: + handle = self.dxf.handle + mlines = (e for e in self.doc.entitydb.values() if e.dxftype() == "MLINE") + for mline in mlines: + if mline.dxf.style_handle == handle: + mline.update_geometry() + + def ordered_indices(self) -> list[int]: + return self.elements.ordered_indices() + + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + if len(self.elements) == 0: + auditor.add_error( + code=AuditError.INVALID_MLINESTYLE_ELEMENT_COUNT, + message=f"No line elements defined in {str(self)}.", + dxf_entity=self, + ) + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + for element in self.elements: + registry.add_linetype(element.linetype) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, MLineStyle) + super().map_resources(clone, mapping) + self.elements.elements = [ + MLineStyleElement( + element.offset, + element.color, + mapping.get_linetype(element.linetype), + ) + for element in self.elements + ] + + +class MLineStyleCollection(ObjectCollection[MLineStyle]): + def __init__(self, doc: Drawing): + super().__init__(doc, dict_name="ACAD_MLINESTYLE", object_type="MLINESTYLE") + self.create_required_entries() + + def create_required_entries(self) -> None: + if "Standard" not in self: + entity: MLineStyle = self.new("Standard") + entity.elements.append(0.5, 256) + entity.elements.append(-0.5, 256) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mpolygon.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mpolygon.py new file mode 100644 index 0000000..aa3155f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mpolygon.py @@ -0,0 +1,241 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging +from ezdxf.lldxf import validator, const +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + RETURN_DEFAULT, + XType, + group_code_mapping, +) +from ezdxf.math import NULLVEC, Z_AXIS +from .dxfentity import base_class +from .dxfgfx import acdb_entity +from .factory import register_entity +from .polygon import DXFPolygon +from .gradient import Gradient, GradientType + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.colors import RGB + +__all__ = ["MPolygon"] +logger = logging.getLogger("ezdxf") + +acdb_mpolygon = DefSubclass( + "AcDbMPolygon", + { + # MPolygon: version + "version": DXFAttr( + 70, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # x- and y-axis always equal 0, z-axis represents the elevation: + "elevation": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Hatch pattern name: + "pattern_name": DXFAttr(2, default=""), + # Solid fill color as ACI + "fill_color": DXFAttr( + 63, + default=const.BYLAYER, + optional=True, + validator=validator.is_valid_aci_color, + fixer=RETURN_DEFAULT, + ), + # MPolygon: Solid-fill flag: + # 0 = lacks solid fill + # 1 = has solid fill + "solid_fill": DXFAttr( + 71, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Hatch style tag is not supported for MPOLYGON!? + # I don't know in which order this tag has to be exported. + # TrueView does not accept this tag in any place! + # BricsCAD supports this tag! + "hatch_style": DXFAttr( + 75, + default=const.HATCH_STYLE_NESTED, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + optional=True, + ), + # Hatch pattern type ... see HATCH + "pattern_type": DXFAttr( + 76, + default=const.HATCH_TYPE_PREDEFINED, + validator=validator.is_in_integer_range(0, 3), + fixer=RETURN_DEFAULT, + ), + # Hatch pattern angle (pattern fill only) in degrees: + "pattern_angle": DXFAttr(52, default=0), + # Hatch pattern scale or spacing (pattern fill only): + "pattern_scale": DXFAttr( + 41, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # MPolygon: Boundary annotation flag: + # 0 = boundary is not an annotated boundary + # 1 = boundary is an annotated boundary + "annotated_boundary": DXFAttr( + 73, + default=0, + optional=True, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Hatch pattern double flag (pattern fill only) .. see HATCH + "pattern_double": DXFAttr( + 77, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # see ... HATCH + "pixel_size": DXFAttr(47, optional=True), + "n_seed_points": DXFAttr( + 98, + default=0, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + # MPolygon: offset vector in OCS ??? + "offset_vector": DXFAttr(11, xtype=XType.point2d, default=(0, 0)), + # MPolygon: number of degenerate boundary paths (loops), where a + # degenerate boundary path is a border that is ignored by the hatch: + "degenerated_loops": DXFAttr(99, default=0), + }, +) +acdb_mpolygon_group_code = group_code_mapping(acdb_mpolygon) + + +@register_entity +class MPolygon(DXFPolygon): + """DXF MPOLYGON entity + + The MPOLYGON is not a core DXF entity, and requires a CLASS definition. + + """ + + DXFTYPE = "MPOLYGON" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mpolygon) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + LOAD_GROUP_CODES = acdb_mpolygon_group_code + + def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool: + if self.paths.has_edge_paths: + logger.warning( + "MPOLYGON including edge paths are not exported by ezdxf!" + ) + return False + return True + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_mpolygon.name) + dxf = self.dxf + dxf.export_dxf_attribs( + tagwriter, + [ # tag order is important! + "version", + "elevation", + "extrusion", + "pattern_name", + "solid_fill", + ], + ) + self.paths.export_dxf(tagwriter, self.dxftype()) + # hatch_style not supported? + dxf.export_dxf_attribs( + tagwriter, + [ + # "hatch_style", # not supported by MPolygon ??? + "pattern_type", + ], + ) + if dxf.solid_fill == 0: # export pattern + dxf.export_dxf_attribs( + tagwriter, ["pattern_angle", "pattern_scale", "pattern_double"] + ) + + dxf.export_dxf_attribs( + tagwriter, + [ + "annotated_boundary", + "pixel_size", + ], + ) + if dxf.solid_fill == 0: # export pattern + if self.pattern: + self.pattern.export_dxf(tagwriter, force=True) + else: # required pattern length tag! + tagwriter.write_tag2(78, 0) + if tagwriter.dxfversion > const.DXF2000: + dxf.export_dxf_attribs(tagwriter, "fill_color") + dxf.export_dxf_attribs(tagwriter, "offset_vector") + self.export_degenerated_loops(tagwriter) + self.export_gradient(tagwriter) + + def export_degenerated_loops(self, tagwriter: AbstractTagWriter): + self.dxf.export_dxf_attribs(tagwriter, "degenerated_loops") + + def export_gradient(self, tagwriter: AbstractTagWriter): + if tagwriter.dxfversion < const.DXF2004: + return + if self.gradient is None: + self.gradient = Gradient(kind=0, num=0, type=0) + self.gradient.export_dxf(tagwriter) + + def set_solid_fill( + self, color: int = 7, style: int = 1, rgb: Optional[RGB] = None + ): + """Set :class:`MPolygon` to solid fill mode and removes all gradient and + pattern fill related data. + + Args: + color: :ref:`ACI`, (0 = BYBLOCK; 256 = BYLAYER) + style: hatch style is not supported by MPOLYGON, just for symmetry + to HATCH + rgb: true color value as (r, g, b)-tuple - has higher priority + than `color`. True color support requires DXF R2004+ + + """ + # remove existing gradient and pattern fill + self.gradient = None + self.pattern = None + self.dxf.solid_fill = 1 + + # if a gradient is present, the solid fill_color is ignored + self.dxf.fill_color = color + self.dxf.pattern_name = "SOLID" + self.dxf.pattern_type = const.HATCH_TYPE_PREDEFINED + if rgb is not None: + self.set_solid_rgb_gradient(rgb) + + def set_solid_rgb_gradient(self, rgb: RGB): + """Set solid fill color as gradient of a single RGB color. + This disables pattern fill! + + (internal API) + """ + self.gradient = Gradient(kind=1, num=2, type=GradientType.LINEAR) + self.gradient.color1 = rgb + self.gradient.color2 = rgb diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext.py new file mode 100644 index 0000000..5c74e96 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext.py @@ -0,0 +1,1261 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Union, + Iterable, + Iterator, + Optional, + Callable, + cast, +) +from typing_extensions import Self +import enum +import math +import logging + +from ezdxf.lldxf import const, validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + VIRTUAL_TAG, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000, DXF2018 +from ezdxf.lldxf.types import DXFTag, dxftag +from ezdxf.lldxf.tags import ( + Tags, + find_begin_and_end_of_encoded_xdata_tags, + NotFoundException, +) + +from ezdxf.math import Vec3, Matrix44, OCS, UCS, NULLVEC, Z_AXIS, X_AXIS, UVec +from ezdxf.math.transformtools import transform_extrusion +from ezdxf.colors import rgb2int, RGB +from ezdxf.tools.text import ( + split_mtext_string, + escape_dxf_line_endings, + fast_plain_mtext, + plain_mtext, + scale_mtext_inline_commands, +) +from . import factory +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .xdata import XData +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entitydb import EntityDB + from ezdxf import xref + +__all__ = [ + "MText", + "MTextColumns", + "ColumnType", + "acdb_mtext", + "acdb_mtext_group_codes", + "export_mtext_content", +] +logger = logging.getLogger("ezdxf") + +BG_FILL_MASK = 1 + 2 + 16 + +acdb_mtext = DefSubclass( + "AcDbMText", + { + # virtual text attribute, the actual content is stored in + # multiple tags (1, 3, 3, ...) + "text": DXFAttr( + VIRTUAL_TAG, + xtype=XType.callback, + getter="_get_text", + setter="_set_text", + ), + "insert": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Nominal (initial) text height + "char_height": DXFAttr( + 40, + default=2.5, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # Reference column width + "width": DXFAttr(41, optional=True), + # Found in BricsCAD export: + "defined_height": DXFAttr(46, dxfversion="AC1021"), + # Attachment point: enum const.MTextEntityAlignment + # 1 = Top left + # 2 = Top center + # 3 = Top right + # 4 = Middle left + # 5 = Middle center + # 6 = Middle right + # 7 = Bottom left + # 8 = Bottom center + # 9 = Bottom right + "attachment_point": DXFAttr( + 71, + default=1, + validator=validator.is_in_integer_range(1, 10), + fixer=RETURN_DEFAULT, + ), + # Flow direction: enum MTextFlowDirection + # 1 = Left to right + # 3 = Top to bottom + # 5 = By style (the flow direction is inherited from the associated + # text style) + "flow_direction": DXFAttr( + 72, + default=1, + optional=True, + validator=validator.is_one_of({1, 3, 5}), + fixer=RETURN_DEFAULT, + ), + # Content text: + # group code 1: text + # group code 3: additional text (optional) + # Text style name: + "style": DXFAttr( + 7, + default="Standard", + optional=True, + validator=validator.is_valid_table_name, # do not fix! + ), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # x-axis direction vector (in WCS) + # If rotation and text_direction are present, text_direction wins + "text_direction": DXFAttr( + 11, + xtype=XType.point3d, + default=X_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Horizontal width of the characters that make up the mtext entity. + # This value will always be equal to or less than the value of *width*, + # (read-only, ignored if supplied) + "rect_width": DXFAttr(42, optional=True), + # Vertical height of the mtext entity (read-only, ignored if supplied) + "rect_height": DXFAttr(43, optional=True), + # Text rotation in degrees - Error in DXF reference, which claims radians + "rotation": DXFAttr(50, default=0, optional=True), + # Line spacing style (optional): enum const.MTextLineSpacing + # 1 = At least (taller characters will override) + # 2 = Exact (taller characters will not override) + "line_spacing_style": DXFAttr( + 73, + default=1, + optional=True, + validator=validator.is_one_of({1, 2}), + fixer=RETURN_DEFAULT, + ), + # Line spacing factor (optional): Percentage of default (3-on-5) line + # spacing to be applied. Valid values range from 0.25 to 4.00 + "line_spacing_factor": DXFAttr( + 44, + default=1, + optional=True, + validator=validator.is_in_float_range(0.25, 4.00), + fixer=validator.fit_into_float_range(0.25, 4.00), + ), + # Determines how much border there is around the text. + # (45) + (90) + (63) all three required, if one of them is used + "box_fill_scale": DXFAttr(45, dxfversion="AC1021"), + # background fill type flags: enum const.MTextBackgroundColor + # 0 = off + # 1 = color -> (63) < (421) or (431) + # 2 = drawing window color + # 3 = use background color (1 & 2) + # 16 = text frame ODA specification 20.4.46 + # 2021-05-14: text frame only is supported bg_fill = 16, + # but scaling is always 1.5 and tags 45 + 63 are not present + "bg_fill": DXFAttr( + 90, + dxfversion="AC1021", + validator=validator.is_valid_bitmask(BG_FILL_MASK), + fixer=validator.fix_bitmask(BG_FILL_MASK), + ), + # background fill color as ACI, required even true color is used + "bg_fill_color": DXFAttr( + 63, + dxfversion="AC1021", + validator=validator.is_valid_aci_color, + ), + # 420-429? : background fill color as true color value, (63) also required + # but ignored + "bg_fill_true_color": DXFAttr(421, dxfversion="AC1021"), + # 430-439? : background fill color as color name ???, (63) also required + # but ignored + "bg_fill_color_name": DXFAttr(431, dxfversion="AC1021"), + # background fill color transparency - not used by AutoCAD/BricsCAD + "bg_fill_transparency": DXFAttr(441, dxfversion="AC1021"), + }, +) +acdb_mtext_group_codes = group_code_mapping(acdb_mtext) + + +# ----------------------------------------------------------------------- +# For more information go to docs/source/dxfinternals/entities/mtext.rst +# ----------------------------------------------------------------------- + +# MTEXT column support: +# MTEXT columns have the same appearance and handling for all DXF versions +# as a single MTEXT entity like in DXF R2018. + + +class ColumnType(enum.IntEnum): + NONE = 0 + STATIC = 1 + DYNAMIC = 2 + + +class MTextColumns: + """The column count is not stored explicit in the columns definition for + DXF versions R2018+. + + If column_type is DYNAMIC and auto_height is True the column + count is defined by the content. The exact calculation of the column count + requires an accurate rendering of the MTEXT content like AutoCAD does! + + If the column count is not defined, ezdxf tries to calculate the column + count from total_width, width and gutter_width, if these attributes are set + properly. + + """ + + def __init__(self) -> None: + self.column_type: ColumnType = ColumnType.STATIC + # The embedded object in R2018 does not store the column count for + # column type DYNAMIC and auto_height is True! + # For DXF < R2018 the column count, may not match the count of linked + # MTEXT entities! + self.count: int = 1 + self.auto_height: bool = False + self.reversed_column_flow: bool = False + self.defined_height: float = 0.0 + self.width: float = 0.0 + self.gutter_width: float = 0.0 + self.total_width: float = 0.0 + self.total_height: float = 0.0 + # Storage for handles of linked MTEXT entities at loading stage: + self.linked_handles: Optional[list[str]] = None + # Storage for linked MTEXT entities for DXF versions < R2018: + self.linked_columns: list[MText] = [] + # R2018+: heights of all columns if auto_height is False + self.heights: list[float] = [] + + def deep_copy(self) -> MTextColumns: + columns = self.shallow_copy() + columns.linked_columns = [mtext.copy() for mtext in self.linked_columns] + return columns + + def shallow_copy(self) -> MTextColumns: + columns = MTextColumns() + columns.count = self.count + columns.column_type = self.column_type + columns.auto_height = self.auto_height + columns.reversed_column_flow = self.reversed_column_flow + columns.defined_height = self.defined_height + columns.width = self.width + columns.gutter_width = self.gutter_width + columns.total_width = self.total_width + columns.total_height = self.total_height + columns.linked_columns = list(self.linked_columns) + columns.heights = list(self.heights) + return columns + + @classmethod + def new_static_columns( + cls, count: int, width: float, gutter_width: float, height: float + ) -> MTextColumns: + columns = cls() + columns.column_type = ColumnType.STATIC + columns.count = int(count) + columns.width = float(width) + columns.gutter_width = float(gutter_width) + columns.defined_height = float(height) + columns.update_total_width() + columns.update_total_height() + return columns + + @classmethod + def new_dynamic_auto_height_columns( + cls, count: int, width: float, gutter_width: float, height: float + ) -> MTextColumns: + columns = cls() + columns.column_type = ColumnType.DYNAMIC + columns.auto_height = True + columns.count = int(count) + columns.width = float(width) + columns.gutter_width = float(gutter_width) + columns.defined_height = float(height) + columns.update_total_width() + columns.update_total_height() + return columns + + @classmethod + def new_dynamic_manual_height_columns( + cls, width: float, gutter_width: float, heights: Iterable[float] + ) -> MTextColumns: + columns = cls() + columns.column_type = ColumnType.DYNAMIC + columns.auto_height = False + columns.width = float(width) + columns.gutter_width = float(gutter_width) + columns.defined_height = 0.0 + columns.heights = list(heights) + columns.count = len(columns.heights) + columns.update_total_width() + columns.update_total_height() + return columns + + def update_total_width(self): + count = self.count + if count > 0: + self.total_width = count * self.width + (count - 1) * self.gutter_width + else: + self.total_width = 0.0 + + def update_total_height(self): + if self.has_dynamic_manual_height: + self.total_height = max(self.heights) + else: + self.total_height = self.defined_height + + @property + def has_dynamic_auto_height(self) -> bool: + return self.column_type == ColumnType.DYNAMIC and self.auto_height + + @property + def has_dynamic_manual_height(self) -> bool: + return self.column_type == ColumnType.DYNAMIC and not self.auto_height + + def link_columns(self, doc: Drawing): + # DXF R2018+ has no linked MTEXT entities. + if doc.dxfversion >= DXF2018 or not self.linked_handles: + return + db = doc.entitydb + assert db is not None, "entity database not initialized" + linked_columns = [] + for handle in self.linked_handles: + mtext = cast("MText", db.get(handle)) + if mtext: + linked_columns.append(mtext) + else: + logger.debug(f"Linked MTEXT column #{handle} does not exist.") + self.linked_handles = None + self.linked_columns = linked_columns + + def transform(self, m: Matrix44, hscale: float = 1, vscale: float = 1): + self.width *= hscale + self.gutter_width *= hscale + self.total_width *= hscale + self.total_height *= vscale + self.defined_height *= vscale + self.heights = [h * vscale for h in self.heights] + for mtext in self.linked_columns: + mtext.transform(m) + + def acad_mtext_column_info_xdata(self) -> Tags: + tags = Tags( + [ + DXFTag(1000, "ACAD_MTEXT_COLUMN_INFO_BEGIN"), + DXFTag(1070, 75), + DXFTag(1070, int(self.column_type)), + DXFTag(1070, 79), + DXFTag(1070, int(self.auto_height)), + DXFTag(1070, 76), + DXFTag(1070, self.count), + DXFTag(1070, 78), + DXFTag(1070, int(self.reversed_column_flow)), + DXFTag(1070, 48), + DXFTag(1040, self.width), + DXFTag(1070, 49), + DXFTag(1040, self.gutter_width), + ] + ) + if self.has_dynamic_manual_height: + tags.extend([DXFTag(1070, 50), DXFTag(1070, len(self.heights))]) + tags.extend(DXFTag(1040, height) for height in self.heights) + tags.append(DXFTag(1000, "ACAD_MTEXT_COLUMN_INFO_END")) + return tags + + def acad_mtext_columns_xdata(self) -> Tags: + tags = Tags( + [ + DXFTag(1000, "ACAD_MTEXT_COLUMNS_BEGIN"), + DXFTag(1070, 47), + DXFTag(1070, self.count), # incl. main MTEXT + ] + ) + tags.extend( # writes only (count - 1) handles! + DXFTag(1005, handle) for handle in self.mtext_handles() + ) + tags.append(DXFTag(1000, "ACAD_MTEXT_COLUMNS_END")) + return tags + + def mtext_handles(self) -> list[str]: + """Returns a list of all linked MTEXT handles.""" + if self.linked_handles: + return self.linked_handles + handles = [] + for column in self.linked_columns: + if column.is_alive: + handle = column.dxf.handle + if handle is None: + raise const.DXFStructureError("Linked MTEXT column has no handle.") + handles.append(handle) + else: + raise const.DXFStructureError("Linked MTEXT column deleted!") + return handles + + def acad_mtext_defined_height_xdata(self) -> Tags: + return Tags( + [ + DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_BEGIN"), + DXFTag(1070, 46), + DXFTag(1040, self.defined_height), + DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_END"), + ] + ) + + +def load_columns_from_embedded_object( + dxf: DXFNamespace, embedded_obj: Tags +) -> MTextColumns: + columns = MTextColumns() + insert = dxf.get("insert") # mandatory attribute, but what if ... + text_direction = dxf.get("text_direction") # optional attribute + reference_column_width = dxf.get("width") # optional attribute + for code, value in embedded_obj: + # Update duplicated attributes if MTEXT attributes are not set: + if code == 10 and text_direction is None: + dxf.text_direction = Vec3(value) + # rotation is not needed anymore: + dxf.discard("rotation") + elif code == 11 and insert is None: + dxf.insert = Vec3(value) + elif code == 40 and reference_column_width is None: + dxf.width = value + elif code == 41: + # Column height if auto height is True. + columns.defined_height = value + # Keep in sync with DXF attribute: + dxf.defined_height = value + elif code == 42: + columns.total_width = value + elif code == 43: + columns.total_height = value + elif code == 44: + # All columns have the same width. + columns.width = value + elif code == 45: + # All columns have the same gutter width = space between columns. + columns.gutter_width = value + elif code == 71: + columns.column_type = ColumnType(value) + elif code == 72: # column height count + # The column height count can be 0 in some cases (dynamic & auto + # height) in DXF version R2018+. + columns.count = value + elif code == 73: + columns.auto_height = bool(value) + elif code == 74: + columns.reversed_column_flow = bool(value) + elif code == 46: # column heights + # The last column height is 0; takes the rest? + columns.heights.append(value) + + # The column count is not defined explicit: + if columns.count == 0: + if columns.heights: # very unlikely + columns.count = len(columns.heights) + elif columns.total_width > 0: + # calculate column count from total_width + g = columns.gutter_width + wg = abs(columns.width + g) + if wg > 1e-6: + columns.count = int(round((columns.total_width + g) / wg)) + return columns + + +def load_mtext_column_info(tags: Tags) -> Optional[MTextColumns]: + try: # has column info? + start, end = find_begin_and_end_of_encoded_xdata_tags( + "ACAD_MTEXT_COLUMN_INFO", tags + ) + except NotFoundException: + return None + columns = MTextColumns() + height_count = 0 + group_code = None + for code, value in tags[start + 1 : end]: + if height_count: + if code == 1040: + columns.heights.append(value) + height_count -= 1 + continue + else: # error + logger.error("missing column heights in MTEXT entity") + height_count = 0 + + if group_code is None: + group_code = value + continue + + if group_code == 75: + columns.column_type = ColumnType(value) + elif group_code == 79: + columns.auto_height = bool(value) + elif group_code == 76: + # column count, may not match the count of linked MTEXT entities! + columns.count = int(value) + elif group_code == 78: + columns.reversed_column_flow = bool(value) + elif group_code == 48: + columns.width = value + elif group_code == 49: + columns.gutter_width = value + elif group_code == 50: + height_count = int(value) + group_code = None + return columns + + +def load_mtext_linked_column_handles(tags: Tags) -> list[str]: + handles: list[str] = [] + try: + start, end = find_begin_and_end_of_encoded_xdata_tags( + "ACAD_MTEXT_COLUMNS", tags + ) + except NotFoundException: + return handles + for code, value in tags[start:end]: + if code == 1005: + handles.append(value) + return handles + + +def load_mtext_defined_height(tags: Tags) -> float: + # The defined height stored in the linked MTEXT entities, is not required: + # + # If all columns have the same height (static & dynamic auto height), the + # "defined_height" is stored in the main MTEXT, but the linked MTEXT entities + # also have a "ACAD_MTEXT_DEFINED_HEIGHT" group in the ACAD section of XDATA. + # + # If the columns have different heights (dynamic manual height), these + # height values are only stored in the main MTEXT. The linked MTEXT + # entities do not have an ACAD section at all. + + height = 0.0 + try: + start, end = find_begin_and_end_of_encoded_xdata_tags( + "ACAD_MTEXT_DEFINED_HEIGHT", tags + ) + except NotFoundException: + return height + + for code, value in tags[start:end]: + if code == 1040: + height = value + return height + + +def load_columns_from_xdata(dxf: DXFNamespace, xdata: XData) -> Optional[MTextColumns]: + # The ACAD section in XDATA of the main MTEXT entity stores all column + # related information: + if "ACAD" in xdata: + acad = xdata.get("ACAD") + else: + return None + + name = f"MTEXT(#{dxf.get('handle')})" + try: + columns = load_mtext_column_info(acad) + except const.DXFStructureError: + logger.error(f"Invalid ACAD_MTEXT_COLUMN_INFO in {name}") + return None + + if columns is None: # no columns defined + return None + + try: + columns.linked_handles = load_mtext_linked_column_handles(acad) + except const.DXFStructureError: + logger.error(f"Invalid ACAD_MTEXT_COLUMNS in {name}") + + columns.update_total_width() + if columns.heights: # dynamic columns, manual heights + # This is correct even if the last column is the tallest, which height + # is not known. The height of last column is always stored as 0. + columns.total_height = max(columns.heights) + else: # all columns have the same "defined" height + try: + columns.defined_height = load_mtext_defined_height(acad) + except const.DXFStructureError: + logger.error(f"Invalid ACAD_MTEXT_DEFINED_HEIGHT in {name}") + columns.total_height = columns.defined_height + + return columns + + +def extract_mtext_text_frame_handles(xdata: XData) -> list[str]: + # Stores information about the text frame until DXF R2018. + # Newer CAD applications do not need that information nor the separated + # LWPOLYLINE as text frame entity. + handles: list[str] = [] + if "ACAD" in xdata: + acad = xdata.get("ACAD") + else: + return handles + + try: + start, end = find_begin_and_end_of_encoded_xdata_tags( + "ACAD_MTEXT_TEXT_BORDERS", acad + ) + except NotFoundException: + return handles + + for code, value in acad[start:end]: + # multiple handles to a LWPOLYLINE entity could be present: + if code == 1005: + handles.append(value) + + # remove MTEXT_TEXT_BORDERS data + del acad[start:end] + if len(acad) < 2: + xdata.discard("ACAD") + return handles + + +@factory.register_entity +class MText(DXFGraphic): + """DXF MTEXT entity""" + + DXFTYPE = "MTEXT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_mtext) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def __init__(self) -> None: + super().__init__() + self.text: str = "" + # Linked MText columns do not have a MTextColumns() object! + self._columns: Optional[MTextColumns] = None + + def _get_text(self): + """Getter for virtual Mtext.dxf.text attribute. + + The MText content is stored in multiple tags (1, 3, 3, ...) and cannot + be supported as a simple DXF tag. The virtual MText.dxf.text attribute + adds compatibility to other text based entities: TEXT, ATTRIB, ATTDEF + + """ + return self.text + + def _set_text(self, value): + """Setter for virtual Mtext.dxf.text attribute.""" + self.text = str(value) + + @property + def columns(self) -> Optional[MTextColumns]: + """Returns a copy of the column configuration.""" + # The column configuration is deliberately not editable. + # Can't prevent access to _columns, but you are on your own if do this! + return self._columns.shallow_copy() if self._columns else None + + @property + def has_columns(self) -> bool: + return self._columns is not None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, MText) + entity.text = self.text + if self.has_columns: + # copies also the linked MTEXT column entities! + entity._columns = self._columns.deep_copy() # type: ignore + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + if tags: + tags = Tags(self.load_mtext_content(tags)) + processor.fast_load_dxfattribs( + dxf, acdb_mtext_group_codes, subclass=tags, recover=True + ) + if processor.embedded_objects: + obj = processor.embedded_objects[0] + self._columns = load_columns_from_embedded_object(dxf, obj) + elif self.xdata: + self._columns = load_columns_from_xdata(dxf, self.xdata) + else: + raise const.DXFStructureError( + f"missing 'AcDbMText' subclass in MTEXT(#{dxf.handle})" + ) + return dxf + + def post_load_hook(self, doc: Drawing) -> Optional[Callable]: + def destroy_text_frame_entity(): + entitydb = doc.entitydb + if entitydb: + for handle in extract_mtext_text_frame_handles(self.xdata): + text_frame = entitydb.get(handle) + if text_frame: + text_frame.destroy() + + def unlink_mtext_columns_from_layout(): + """Unlinked MTEXT entities from layout entity space.""" + layout = self.get_layout() + if layout is not None: + for mtext in self._columns.linked_columns: + layout.unlink_entity(mtext) + else: + for mtext in self._columns.linked_columns: + mtext.dxf.owner = None + + super().post_load_hook(doc) + if self.xdata: + destroy_text_frame_entity() + + if self.has_columns: + # Link columns, one MTEXT entity for each column, to the main MTEXT + # entity (DXF version bool: + """Pre requirement check and pre-processing for export. + + Returns False if MTEXT should not be exported at all. + + (internal API) + """ + columns = self._columns + if columns and tagwriter.dxfversion < const.DXF2018: + if columns.count != len(columns.linked_columns) + 1: + logger.debug(f"{str(self)}: column count does not match linked columns") + # just log for debugging, because AutoCAD accept this! + if not all(column.is_alive for column in columns.linked_columns): + logger.debug(f"{str(self)}: contains destroyed linked columns") + return False + self.sync_common_attribs_of_linked_columns() + return True + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + super().export_dxf(tagwriter) + # Linked MTEXT entities are not stored in the layout entity space! + if self.has_columns and tagwriter.dxfversion < const.DXF2018: + self.export_linked_entities(tagwriter) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_mtext.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "insert", + "char_height", + "width", + "defined_height", + "attachment_point", + "flow_direction", + ], + ) + export_mtext_content(self.text, tagwriter) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "style", + "extrusion", + "text_direction", + "rect_width", + "rect_height", + "rotation", + "line_spacing_style", + "line_spacing_factor", + "box_fill_scale", + "bg_fill", + "bg_fill_color", + "bg_fill_true_color", + "bg_fill_color_name", + "bg_fill_transparency", + ], + ) + columns = self._columns + if columns is None or columns.column_type == ColumnType.NONE: + return + + if tagwriter.dxfversion >= DXF2018: + self.export_embedded_object(tagwriter) + else: + self.set_column_xdata() + self.set_linked_columns_xdata() + + def load_mtext_content(self, tags: Tags) -> Iterator[DXFTag]: + tail = "" + parts = [] + for tag in tags: + if tag.code == 1: + tail = tag.value + elif tag.code == 3: + parts.append(tag.value) + else: + yield tag + parts.append(tail) + self.text = escape_dxf_line_endings("".join(parts)) + + def export_embedded_object(self, tagwriter: AbstractTagWriter): + dxf = self.dxf + cols = self._columns + assert cols is not None + + tagwriter.write_tag2(101, "Embedded Object") + tagwriter.write_tag2(70, 1) # unknown meaning + tagwriter.write_tag(dxftag(10, dxf.text_direction)) + tagwriter.write_tag(dxftag(11, dxf.insert)) + tagwriter.write_tag2(40, dxf.width) # repeated reference column width + tagwriter.write_tag2(41, cols.defined_height) + tagwriter.write_tag2(42, cols.total_width) + tagwriter.write_tag2(43, cols.total_height) + tagwriter.write_tag2(71, int(cols.column_type)) + + if cols.has_dynamic_auto_height: + count = 0 + else: + count = cols.count + tagwriter.write_tag2(72, count) + + tagwriter.write_tag2(44, cols.width) + tagwriter.write_tag2(45, cols.gutter_width) + tagwriter.write_tag2(73, int(cols.auto_height)) + tagwriter.write_tag2(74, int(cols.reversed_column_flow)) + for height in cols.heights: + tagwriter.write_tag2(46, height) + + def export_linked_entities(self, tagwriter: AbstractTagWriter): + for mtext in self._columns.linked_columns: # type: ignore + if mtext.dxf.handle is None: + raise const.DXFStructureError("Linked MTEXT column has no handle.") + # Export linked columns as separated DXF entities: + mtext.export_dxf(tagwriter) + + def sync_common_attribs_of_linked_columns(self): + common_attribs = self.dxfattribs( + drop={"handle", "insert", "rect_width", "rect_height"} + ) + for mtext in self._columns.linked_columns: + mtext.update_dxf_attribs(common_attribs) + + def set_column_xdata(self): + if self.xdata is None: + self.xdata = XData() + cols = self._columns + acad = cols.acad_mtext_column_info_xdata() + acad.extend(cols.acad_mtext_columns_xdata()) + if not cols.has_dynamic_manual_height: + acad.extend(cols.acad_mtext_defined_height_xdata()) + + xdata = self.xdata + # Replace existing column data and therefore also removes + # ACAD_MTEXT_TEXT_BORDERS information! + xdata.discard("ACAD") + xdata.add("ACAD", acad) + + def set_linked_columns_xdata(self): + cols = self._columns + for column in cols.linked_columns: + column.discard_xdata("ACAD") + if not cols.has_dynamic_manual_height: + tags = cols.acad_mtext_defined_height_xdata() + for column in cols.linked_columns: + column.set_xdata("ACAD", tags) + + def get_rotation(self) -> float: + """Returns the text rotation in degrees.""" + if self.dxf.hasattr("text_direction"): + vector = self.dxf.text_direction + radians = math.atan2(vector[1], vector[0]) # ignores z-axis + rotation = math.degrees(radians) + else: + rotation = self.dxf.get("rotation", 0) + return rotation + + def set_rotation(self, angle: float) -> MText: + """Sets the attribute :attr:`rotation` to `angle` (in degrees) and deletes + :attr:`dxf.text_direction` if present. + """ + # text_direction has higher priority than rotation, therefore delete it + self.dxf.discard("text_direction") + self.dxf.rotation = angle + return self # fluent interface + + def set_location( + self, + insert: UVec, + rotation: Optional[float] = None, + attachment_point: Optional[int] = None, + ) -> MText: + """Sets the attributes :attr:`dxf.insert`, :attr:`dxf.rotation` and + :attr:`dxf.attachment_point`, ``None`` for :attr:`dxf.rotation` or + :attr:`dxf.attachment_point` preserves the existing value. + + """ + self.dxf.insert = Vec3(insert) + if rotation is not None: + self.set_rotation(rotation) + if attachment_point is not None: + self.dxf.attachment_point = attachment_point + return self # fluent interface + + def set_bg_color( + self, + color: Union[int, str, RGB, None], + scale: float = 1.5, + text_frame=False, + ): + """Sets the background color as :ref:`ACI` value, as name string or as + (r, g, b) tuple. + + Use the special color name ``canvas``, to set the background color to the canvas + background color. Remove the background filling by setting argument `color` to + ``None``. + + Args: + color: color as :ref:`ACI`, string, (r, g, b) tuple or ``None`` + scale: determines how much border there is around the text, the + value is based on the text height, and should be in the range + of [1, 5], where 1 fits exact the MText entity. + text_frame: draw a text frame in text color if ``True`` + + """ + if 1 <= scale <= 5: + self.dxf.box_fill_scale = scale + else: + raise ValueError("argument scale has to be in range from 1 to 5.") + + text_frame = const.MTEXT_TEXT_FRAME if text_frame else 0 + if color is None: + self.dxf.discard("bg_fill") + self.dxf.discard("box_fill_scale") + self.dxf.discard("bg_fill_color") + self.dxf.discard("bg_fill_true_color") + self.dxf.discard("bg_fill_color_name") + if text_frame: + # special case, text frame only with scaling factor = 1.5 + self.dxf.bg_fill = 16 + elif color == "canvas": # special case for use background color + self.dxf.bg_fill = const.MTEXT_BG_CANVAS_COLOR | text_frame + self.dxf.bg_fill_color = 0 # required but ignored + else: + self.dxf.bg_fill = const.MTEXT_BG_COLOR | text_frame + if isinstance(color, int): + self.dxf.bg_fill_color = color + elif isinstance(color, str): + self.dxf.bg_fill_color = 0 # required but ignored + self.dxf.bg_fill_color_name = color + elif isinstance(color, tuple): + self.dxf.bg_fill_color = 0 # required but ignored + self.dxf.bg_fill_true_color = rgb2int(color) + return self # fluent interface + + def __iadd__(self, text: str) -> MText: + """Append `text` to existing content (:attr:`text` attribute).""" + self.text += text + return self + + append = __iadd__ + + def get_text_direction(self) -> Vec3: + """Returns the horizontal text direction as :class:`~ezdxf.math.Vec3` + object, even if only the text rotation is defined. + + """ + dxf = self.dxf + # "text_direction" has higher priority than "rotation" + if dxf.hasattr("text_direction"): + return dxf.text_direction + if dxf.hasattr("rotation"): + # MTEXT is not an OCS entity, but I don't know how else to convert + # a rotation angle for an entity just defined by an extrusion vector. + # It's correct for the most common case: extrusion=(0, 0, 1) + return OCS(dxf.extrusion).to_wcs(Vec3.from_deg_angle(dxf.rotation)) + return X_AXIS + + def convert_rotation_to_text_direction(self): + """Convert text rotation into text direction and discard text rotation.""" + dxf = self.dxf + if dxf.hasattr("rotation"): + if not dxf.hasattr("text_direction"): + dxf.text_direction = self.get_text_direction() + dxf.discard("rotation") + + def ucs(self) -> UCS: + """Returns the :class:`~ezdxf.math.UCS` of the :class:`MText` entity, + defined by the insert location (origin), the text direction or rotation + (x-axis) and the extrusion vector (z-axis). + + """ + dxf = self.dxf + return UCS( + origin=dxf.insert, + ux=self.get_text_direction(), + uz=dxf.extrusion, + ) + + def transform(self, m: Matrix44) -> MText: + """Transform the MTEXT entity by transformation matrix `m` inplace.""" + dxf = self.dxf + old_extrusion = Vec3(dxf.extrusion) + new_extrusion, _ = transform_extrusion(old_extrusion, m) + self.convert_rotation_to_text_direction() + + old_text_direction = Vec3(dxf.text_direction) + new_text_direction = m.transform_direction(old_text_direction) + + old_vertical_direction = old_extrusion.cross(old_text_direction) + old_char_height = float(dxf.char_height) + old_char_height_vec = old_vertical_direction.normalize(old_char_height) + new_char_height_vec = m.transform_direction(old_char_height_vec) + oblique = new_text_direction.angle_between(new_char_height_vec) + new_char_height = new_char_height_vec.magnitude * math.sin(oblique) + dxf.char_height = new_char_height + if ( + not math.isclose(old_char_height, new_char_height) + and abs(old_char_height) > 1e-12 + ): + factor = new_char_height / old_char_height + # Column content is transformed by the sub-entities itself! + self.text = scale_mtext_inline_commands(self.text, factor) + + if dxf.hasattr("width"): + width_vec = old_text_direction.normalize(dxf.width) + dxf.width = m.transform_direction(width_vec).magnitude + + dxf.insert = m.transform(dxf.insert) + dxf.text_direction = new_text_direction + dxf.extrusion = new_extrusion + if self.has_columns: + hscale = m.transform_direction(old_text_direction.normalize()).magnitude + vscale = m.transform_direction(old_vertical_direction.normalize()).magnitude + self._columns.transform(m, hscale, vscale) # type: ignore + self.post_transform(m) + return self + + def plain_text(self, split=False, fast=True) -> Union[list[str], str]: + """Returns the text content without inline formatting codes. + + The "fast" mode is accurate if the DXF content was created by + reliable (and newer) CAD applications like AutoCAD or BricsCAD. + The "accurate" mode is for some rare cases where the content was + created by older CAD applications or unreliable DXF libraries and CAD + applications. + + Args: + split: split content text at line breaks if ``True`` and + returns a list of strings without line endings + fast: uses the "fast" mode to extract the plain MTEXT content if + ``True`` or the "accurate" mode if set to ``False`` + + """ + if fast: + return fast_plain_mtext(self.text, split=split) + else: + return plain_mtext(self.text, split=split) + + def all_columns_plain_text(self, split=False) -> Union[list[str], str]: + """Returns the text content of all columns without inline formatting + codes. + + Args: + split: split content text at line breaks if ``True`` and + returns a list of strings without line endings + + """ + + def merged_content(): + content = [fast_plain_mtext(self.text, split=False)] + if self.has_columns: + for c in self._columns.linked_columns: + content.append(c.plain_text(split=False)) + return "".join(content) + + def split_content(): + content = fast_plain_mtext(self.text, split=True) + if self.has_columns: + if content and content[-1] == "": + content.pop() + for c in self._columns.linked_columns: + content.extend(c.plain_text(split=True)) + if content and content[-1] == "": + content.pop() + return content + + if split: + return split_content() + else: + return merged_content() + + def all_columns_raw_content(self) -> str: + """Returns the text content of all columns as a single string + including the inline formatting codes. + + """ + content = [self.text] + if self.has_columns: + for column in self._columns.linked_columns: # type: ignore + content.append(column.text) + return "".join(content) + + def audit(self, auditor: Auditor): + """Validity check.""" + if not self.is_alive: + return + if self.dxf.owner is not None: + # Kills linked columns, because owner (None) does not exist! + super().audit(auditor) + else: # linked columns: owner is None + # TODO: special audit for linked columns + pass + auditor.check_text_style(self) + # TODO: audit column structure + + def destroy(self) -> None: + if not self.is_alive: + return + + if self.has_columns: + for column in self._columns.linked_columns: # type: ignore + column.destroy() + + del self._columns + super().destroy() + + # Linked MTEXT columns are not the same structure as + # POLYLINE & INSERT with sub-entities and SEQEND :( + def add_sub_entities_to_entitydb(self, db: EntityDB) -> None: + """Add linked columns (MTEXT) entities to entity database `db`, + called from EntityDB. (internal API) + + """ + if self.is_alive and self._columns: + doc = self.doc + for column in self._columns.linked_columns: + if column.is_alive and column.is_virtual: + column.doc = doc + db.add(column) + + def process_sub_entities(self, func: Callable[[DXFEntity], None]): + """Call `func` for linked columns. (internal API)""" + if self.is_alive and self._columns: + for entity in self._columns.linked_columns: + if entity.is_alive: + func(entity) + + def setup_columns(self, columns: MTextColumns, linked: bool = False) -> None: + assert columns.column_type != ColumnType.NONE + assert columns.count > 0, "one or more columns required" + assert columns.width > 0, "column width has to be > 0" + assert columns.gutter_width >= 0, "gutter width has to be >= 0" + + if self.has_columns: + raise const.DXFStructureError("Column setup already exist.") + self._columns = columns + self.dxf.width = columns.width + self.dxf.defined_height = columns.defined_height + if columns.total_height < 1e-6: + columns.total_height = columns.defined_height + if columns.total_width < 1e-6: + columns.update_total_width() + if linked: + self._create_linked_columns() + + def _create_linked_columns(self) -> None: + """Create linked MTEXT columns for DXF versions before R2018.""" + # creates virtual MTEXT entities + dxf = self.dxf + attribs = self.dxfattribs(drop={"handle", "owner"}) + doc = self.doc + cols = self._columns + assert cols is not None + + insert = dxf.get("insert", Vec3()) + default_direction = Vec3.from_deg_angle(dxf.get("rotation", 0)) + text_direction = Vec3(dxf.get("text_direction", default_direction)) + offset = text_direction.normalize(cols.width + cols.gutter_width) + linked_columns = cols.linked_columns + for _ in range(cols.count - 1): + insert += offset + column = MText.new(dxfattribs=attribs, doc=doc) + column.dxf.insert = insert + linked_columns.append(column) + + def remove_dependencies(self, other: Optional[Drawing] = None) -> None: + if not self.is_alive: + return + + super().remove_dependencies() + style_exist = bool(other) and self.dxf.style in other.styles # type: ignore + if not style_exist: + self.dxf.style = "Standard" + + if self.has_columns: + for column in self._columns.linked_columns: # type: ignore + column.remove_dependencies(other) + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + if self.dxf.hasattr("style"): + registry.add_text_style(self.dxf.style) + if self._columns: + for mtext in self._columns.linked_columns: + mtext.register_resources(registry) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, MText) + super().map_resources(clone, mapping) + + if clone.dxf.hasattr("style"): + clone.dxf.style = mapping.get_text_style(clone.dxf.style) + if self._columns and clone._columns: + for col_self, col_clone in zip( + self._columns.linked_columns, clone._columns.linked_columns + ): + col_self.map_resources(col_clone, mapping) + + +def export_mtext_content(text, tagwriter: AbstractTagWriter) -> None: + txt = escape_dxf_line_endings(text) + str_chunks = split_mtext_string(txt, size=250) + if len(str_chunks) == 0: + str_chunks.append("") + while len(str_chunks) > 1: + tagwriter.write_tag2(3, str_chunks.pop(0)) + tagwriter.write_tag2(1, str_chunks[0]) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext_columns.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext_columns.py new file mode 100644 index 0000000..200f68b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/mtext_columns.py @@ -0,0 +1,154 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Iterator, Sequence +from .mtext import MText, MTextColumns + +__all__ = [ + "make_static_columns_r2000", + "make_dynamic_auto_height_columns_r2000", + "make_dynamic_manual_height_columns_r2000", + "make_static_columns_r2018", + "make_dynamic_auto_height_columns_r2018", + "make_dynamic_manual_height_columns_r2018", +] + +COLUMN_BREAK = "\\N" + + +def add_column_breaks(content: Iterable[str]) -> Iterator[str]: + content = list(content) + for c in content[:-1]: + if not c.endswith(COLUMN_BREAK): + c += COLUMN_BREAK + yield c + yield content[-1] # last column without a column break + + +def make_static_columns_r2000( + content: Sequence[str], + width: float, + gutter_width: float, + height: float, + dxfattribs=None, +) -> MText: + if len(content) < 1: + raise ValueError("no content") + columns = MTextColumns.new_static_columns( + len(content), width, gutter_width, height + ) + mtext = MText.new(dxfattribs=dxfattribs) + mtext.setup_columns(columns, linked=True) + content = list(add_column_breaks(content)) + mtext.text = content[0] + for mt, c in zip(columns.linked_columns, content[1:]): + mt.text = c + return mtext + + +def make_dynamic_auto_height_columns_r2000( + content: str, + width: float, + gutter_width: float, + height: float, + count: int = 1, + dxfattribs=None, +) -> MText: + if not content: + raise ValueError("no content") + mtext = MText.new(dxfattribs=dxfattribs) + mtext.dxf.width = width + columns = MTextColumns.new_dynamic_auto_height_columns( + count, width, gutter_width, height + ) + set_dynamic_columns_content(content, mtext, columns) + return mtext + + +def make_dynamic_manual_height_columns_r2000( + content: str, + width: float, + gutter_width: float, + heights: Sequence[float], + dxfattribs=None, +) -> MText: + if not content: + raise ValueError("no content") + mtext = MText.new(dxfattribs=dxfattribs) + mtext.dxf.width = width + columns = MTextColumns.new_dynamic_manual_height_columns( + width, gutter_width, heights + ) + set_dynamic_columns_content(content, mtext, columns) + return mtext + + +def set_dynamic_columns_content( + content: str, mtext: MText, columns: MTextColumns +): + mtext.setup_columns(columns, linked=True) + # temp. hack: assign whole content to the main column + mtext.text = content + # for mt, c in zip(mtext.columns.linked_columns, content[1:]): + # mt.text = c + return mtext + + +# DXF version R2018 + + +def make_static_columns_r2018( + content: Sequence[str], + width: float, + gutter_width: float, + height: float, + dxfattribs=None, +) -> MText: + if len(content) < 1: + raise ValueError("no content") + columns = MTextColumns.new_static_columns( + len(content), width, gutter_width, height + ) + mtext = MText.new(dxfattribs=dxfattribs) + mtext.setup_columns(columns, linked=False) + mtext.text = "".join(add_column_breaks(content)) + return mtext + + +def make_dynamic_auto_height_columns_r2018( + content: str, + width: float, + gutter_width: float, + height: float, + count: int, + dxfattribs=None, +) -> MText: + columns = MTextColumns.new_dynamic_auto_height_columns( + count, width, gutter_width, height + ) + return _make_dynamic_columns_r2018(content, columns, dxfattribs or {}) + + +def make_dynamic_manual_height_columns_r2018( + content: str, + width: float, + gutter_width: float, + heights: Sequence[float], + dxfattribs=None, +) -> MText: + columns = MTextColumns.new_dynamic_manual_height_columns( + width, gutter_width, heights + ) + return _make_dynamic_columns_r2018(content, columns, dxfattribs or {}) + + +def _make_dynamic_columns_r2018( + content: str, columns: MTextColumns, dxfattribs +) -> MText: + if not content: + raise ValueError("no content") + # column count is not required for DXF R2018 + mtext = MText.new(dxfattribs=dxfattribs) + mtext.setup_columns(columns, linked=False) + mtext.text = content + return mtext diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/objectcollection.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/objectcollection.py new file mode 100644 index 0000000..c56c46e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/objectcollection.py @@ -0,0 +1,193 @@ +# Copyright (c) 2018-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterator, + cast, + Optional, + TypeVar, + Generic, +) +from ezdxf.lldxf.const import ( + DXFValueError, + DXFKeyError, + INVALID_NAME_CHARACTERS, +) +from ezdxf.lldxf.validator import make_table_key, is_valid_table_name + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFObject, Dictionary + + +def validate_name(name: str) -> str: + name = name[:255] + if not is_valid_table_name(name): + raise DXFValueError( + f"table name '{name}' contains invalid characters: {INVALID_NAME_CHARACTERS}" + ) + return name + + +T = TypeVar("T", bound="DXFObject") + + +class ObjectCollection(Generic[T]): + """ + Note: + ObjectCollections may contain entries where the name stored in the entity as + "name" attribute diverges from the key in the DICTIONARY object e.g. MLEADERSTYLE + collection may have entries for "Standard" and "Annotative" but both MLEADERSTYLE + objects have the name "Standard". + + """ + + def __init__( + self, + doc: Drawing, + dict_name: str = "ACAD_MATERIAL", + object_type: str = "MATERIAL", + ): + self.doc: Drawing = doc + self.object_dict_name = dict_name + self.object_type: str = object_type + self.object_dict: Dictionary = doc.rootdict.get_required_dict(dict_name) + + def update_object_dict(self) -> None: + self.object_dict = self.doc.rootdict.get_required_dict(self.object_dict_name) + + def create_required_entries(self) -> None: + pass + + def __iter__(self) -> Iterator[tuple[str, T]]: + return self.object_dict.items() + + def __len__(self) -> int: + return len(self.object_dict) + + def __contains__(self, name: str) -> bool: + return self.has_entry(name) + + def __getitem__(self, name: str) -> T: + entry = self.get(name) + if entry is None: + raise DXFKeyError(name) + return entry + + @property + def handle(self) -> str: + """Returns the DXF handle of the DICTIONARY object.""" + return self.object_dict.dxf.handle + + @property + def is_hard_owner(self) -> bool: + """Returns ``True`` if the collection is hard owner of entities. + Hard owned entities will be destroyed by deleting the dictionary. + """ + return self.object_dict.is_hard_owner + + def has_entry(self, name: str) -> bool: + return self.get(name) is not None + + def is_unique_name(self, name: str) -> bool: + name = make_table_key(name) + for entry_name in self.object_dict.keys(): + if make_table_key(entry_name) == name: + return False + return True + + def get(self, name: str, default: Optional[T] = None) -> Optional[T]: + """Get object by name. Object collection entries are case-insensitive. + + Args: + name: object name as string + default: default value + + """ + name = make_table_key(name) + for entry_name, obj in self.object_dict.items(): + if make_table_key(entry_name) == name: + return obj + return default + + def new(self, name: str) -> T: + """Create a new object of type `self.object_type` and store its handle + in the object manager dictionary. Object collection entry names are + case-insensitive and limited to 255 characters. + + Args: + name: name of new object as string + + Returns: + new object of type `self.object_type` + + Raises: + DXFValueError: if object name already exist or is invalid + + (internal API) + + """ + name = validate_name(name) + if not self.is_unique_name(name): + raise DXFValueError(f"{self.object_type} entry {name} already exists.") + return self._new(name, dxfattribs={"name": name}) + + def duplicate_entry(self, name: str, new_name: str) -> T: + """Returns a new table entry `new_name` as copy of `name`, + replaces entry `new_name` if already exist. + + Raises: + DXFValueError: `name` does not exist + + """ + entry = self.get(name) + if entry is None: + raise DXFValueError(f"entry '{name}' does not exist") + new_name = validate_name(new_name) + # remove existing entry + existing_entry = self.get(new_name) + if existing_entry is not None: + self.delete(new_name) + + entitydb = self.doc.entitydb + if entitydb: + new_entry = entitydb.duplicate_entity(entry) + else: # only for testing! + new_entry = entry.copy() + if new_entry.dxf.is_supported("name"): + new_entry.dxf.name = new_name + self.object_dict.add(new_name, new_entry) # type: ignore + owner_handle = self.object_dict.dxf.handle + new_entry.dxf.owner = owner_handle + new_entry.set_reactors([owner_handle]) + return new_entry # type: ignore + + def _new(self, name: str, dxfattribs: dict) -> T: + objects = self.doc.objects + assert objects is not None + + owner = self.object_dict.dxf.handle + dxfattribs["owner"] = owner + obj = objects.add_dxf_object_with_reactor( + self.object_type, dxfattribs=dxfattribs + ) + self.object_dict.add(name, obj) + return cast(T, obj) + + def delete(self, name: str) -> None: + objects = self.doc.objects + assert objects is not None + + obj = self.get(name) # case insensitive + if obj is not None: + # The underlying DICTIONARY is not case-insensitive implemented, + # get real object name if available + if obj.dxf.is_supported("name"): + name = obj.dxf.get("name", name) + self.object_dict.discard(name) + objects.delete_entity(obj) + + def clear(self) -> None: + """Delete all entries.""" + self.object_dict.clear() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/oleframe.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/oleframe.py new file mode 100644 index 0000000..e83086b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/oleframe.py @@ -0,0 +1,57 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import const +from . import factory +from .dxfgfx import DXFGraphic +from .dxfentity import SubclassProcessor +from .copy import default_copy, CopyNotSupported +from ezdxf.math import BoundingBox, Vec3 + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.tags import Tags + + +@factory.register_entity +class OLE2Frame(DXFGraphic): + DXFTYPE = "OLE2FRAME" + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def __init__(self) -> None: + super().__init__() + self.acdb_ole2frame: Optional[Tags] = None + + def copy(self, copy_strategy=default_copy) -> OLE2Frame: + raise CopyNotSupported(f"Copying of {self.dxftype()} not supported.") + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + self.acdb_ole2frame = processor.subclass_by_index(2) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + # Base class and AcDbEntity export is done by parent class + super().export_entity(tagwriter) + if self.acdb_ole2frame is not None: + tagwriter.write_tags(self.acdb_ole2frame) + # XDATA export is done by the parent class + + def bbox(self) -> BoundingBox: + if self.acdb_ole2frame is not None: + v10 = self.acdb_ole2frame.get_first_value(10, None) + v11 = self.acdb_ole2frame.get_first_value(11, None) + if v10 is not None and v11 is not None: + return BoundingBox([Vec3(v10), Vec3(v11)]) + return BoundingBox() + + def binary_data(self) -> bytes: + if self.acdb_ole2frame is not None: + return b"".join(value for code, value in self.acdb_ole2frame if code == 310) + return b"" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/pattern.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/pattern.py new file mode 100644 index 0000000..927f848 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/pattern.py @@ -0,0 +1,134 @@ +# Copyright (c) 2019-2021 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, TYPE_CHECKING, Optional + +from ezdxf.lldxf.tags import Tags, group_tags +from ezdxf.math import Vec2, UVec +from ezdxf.tools import pattern + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Pattern", "PatternLine"] + + +class Pattern: + def __init__(self, lines: Optional[Iterable[PatternLine]] = None): + self.lines: list[PatternLine] = list(lines) if lines else [] + + @classmethod + def load_tags(cls, tags: Tags) -> Pattern: + grouped_line_tags = group_tags(tags, splitcode=53) + return cls( + PatternLine.load_tags(line_tags) for line_tags in grouped_line_tags + ) + + def clear(self) -> None: + """Delete all pattern definition lines.""" + self.lines = [] + + def add_line( + self, + angle: float = 0, + base_point: UVec = (0, 0), + offset: UVec = (0, 0), + dash_length_items: Optional[Iterable[float]] = None, + ) -> None: + """Create a new pattern definition line and add the line to the + :attr:`Pattern.lines` attribute. + + """ + assert ( + dash_length_items is not None + ), "argument 'dash_length_items' is None" + self.lines.append( + PatternLine(angle, base_point, offset, dash_length_items) + ) + + def export_dxf(self, tagwriter: AbstractTagWriter, force=False) -> None: + if len(self.lines) or force: + tagwriter.write_tag2(78, len(self.lines)) + for line in self.lines: + line.export_dxf(tagwriter) + + def __str__(self) -> str: + return "[" + ",".join(str(line) for line in self.lines) + "]" + + def as_list(self) -> list: + return [line.as_list() for line in self.lines] + + def scale(self, factor: float = 1, angle: float = 0) -> None: + """Scale and rotate pattern. + + Be careful, this changes the base pattern definition, maybe better use + :meth:`Hatch.set_pattern_scale` or :meth:`Hatch.set_pattern_angle`. + + Args: + factor: scaling factor + angle: rotation angle in degrees + + """ + scaled_pattern = pattern.scale_pattern( + self.as_list(), factor=factor, angle=angle + ) + self.clear() + for line in scaled_pattern: + self.add_line(*line) + + +class PatternLine: + def __init__( + self, + angle: float = 0, + base_point: UVec = (0, 0), + offset: UVec = (0, 0), + dash_length_items: Optional[Iterable[float]] = None, + ): + self.angle: float = float(angle) # in degrees + self.base_point: Vec2 = Vec2(base_point) + self.offset: Vec2 = Vec2(offset) + self.dash_length_items: list[float] = ( + [] if dash_length_items is None else list(dash_length_items) + ) + # dash_length_items = [item0, item1, ...] + # item > 0 is line, < 0 is gap, 0.0 = dot; + + @staticmethod + def load_tags(tags: Tags) -> PatternLine: + p = {53: 0, 43: 0, 44: 0, 45: 0, 46: 0} + dash_length_items = [] + for tag in tags: + code, value = tag + if code == 49: + dash_length_items.append(value) + else: + p[code] = value + return PatternLine( + p[53], (p[43], p[44]), (p[45], p[46]), dash_length_items + ) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + write_tag = tagwriter.write_tag2 + write_tag(53, self.angle) + write_tag(43, self.base_point.x) + write_tag(44, self.base_point.y) + write_tag(45, self.offset.x) + write_tag(46, self.offset.y) + write_tag(79, len(self.dash_length_items)) + for item in self.dash_length_items: + write_tag(49, item) + + def __str__(self): + return ( + f"[{self.angle}, {self.base_point}, {self.offset}, " + f"{self.dash_length_items}]" + ) + + def as_list(self) -> list: + return [ + self.angle, + self.base_point, + self.offset, + self.dash_length_items, + ] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/point.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/point.py new file mode 100644 index 0000000..febf833 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/point.py @@ -0,0 +1,145 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS, OCS +from ezdxf.math.transformtools import ( + transform_thickness_and_extrusion_without_ocs, +) +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity, acdb_entity_group_codes +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Point"] + +# Point styling is a global setting, stored in the HEADER section as: +# $PDMODE: https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2019/ENU/AutoCAD-Core/files/GUID-82F9BB52-D026-4D6A-ABA6-BF29641F459B-htm.html +# One of these values +# 0 = center dot (.) +# 1 = none ( ) +# 2 = cross (+) +# 3 = x-cross (x) +# 4 = tick (') +# Combined with these bit values +# 32 = circle +# 64 = Square +# +# e.g. circle + square+center dot = 32 + 64 + 0 = 96 +# +# $PDSIZE: https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/AutoCAD-Core/files/GUID-826CA91D-704B-400B-B784-7FCC9619AFB9-htm.html?st=$PDSIZE +# 0 = 5% of draw area height +# <0 = Specifies a percentage of the viewport size +# >0 = Specifies an absolute size + +acdb_point = DefSubclass( + "AcDbPoint", + { + # Point location: + "location": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Thickness could be negative: + "thickness": DXFAttr(39, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # angle of the x-axis for the UCS in effect when the point was drawn; + # used when PDMODE is nonzero: + "angle": DXFAttr(50, default=0, optional=True), + }, +) +acdb_point_group_codes = group_code_mapping(acdb_point) +merged_point_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_point_group_codes # type: ignore +) + + +@register_entity +class Point(DXFGraphic): + """DXF POINT entity""" + + DXFTYPE = "POINT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_point) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_point_group_codes) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_point.name) + self.dxf.export_dxf_attribs( + tagwriter, ["location", "thickness", "extrusion", "angle"] + ) + + def transform(self, m: Matrix44) -> Point: + """Transform the POINT entity by transformation matrix `m` inplace.""" + self.dxf.location = m.transform(self.dxf.location) + transform_thickness_and_extrusion_without_ocs(self, m) + # ignore dxf.angle! + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> Point: + """Optimized POINT translation about `dx` in x-axis, `dy` in y-axis and + `dz` in z-axis. + """ + self.dxf.location = Vec3(dx, dy, dz) + self.dxf.location + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self + + def virtual_entities( + self, pdsize: float = 1, pdmode: int = 0 + ) -> Iterator[DXFGraphic]: + """Yields the graphical representation of POINT as virtual DXF + primitives (LINE and CIRCLE). + The dimensionless point is rendered as zero-length line! + + Check for this condition:: + + e.dxftype() == 'LINE' and e.dxf.start.isclose(e.dxf.end) + + if the rendering engine can't handle zero-length lines. + + Args: + pdsize: point size in drawing units + pdmode: point styling mode + + """ + from ezdxf.render import point + for e in point.virtual_entities(self, pdsize, pdmode): + e.set_source_of_copy(self) + yield e + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/polygon.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/polygon.py new file mode 100644 index 0000000..157410b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/polygon.py @@ -0,0 +1,463 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Optional, Union, TYPE_CHECKING, Iterator +from typing_extensions import Self +import abc +import copy + +from ezdxf.audit import Auditor, AuditError +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags +from ezdxf import colors +from ezdxf.tools import pattern +from ezdxf.math import Vec3, Matrix44 +from ezdxf.math.transformtools import OCSTransform +from .boundary_paths import BoundaryPaths +from .dxfns import SubclassProcessor, DXFNamespace +from .dxfgfx import DXFGraphic +from .gradient import Gradient +from .pattern import Pattern, PatternLine +from .dxfentity import DXFEntity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf import xref + +RGB = colors.RGB + +__all__ = ["DXFPolygon"] + +PATH_CODES = { + 10, + 11, + 12, + 13, + 40, + 42, + 50, + 51, + 42, + 72, + 73, + 74, + 92, + 93, + 94, + 95, + 96, + 97, + 330, +} +PATTERN_DEFINITION_LINE_CODES = {53, 43, 44, 45, 46, 79, 49} + + +class DXFPolygon(DXFGraphic): + """Base class for the HATCH and the MPOLYGON entity.""" + + LOAD_GROUP_CODES: dict[int, Union[str, list[str]]] = {} + + def __init__(self) -> None: + super().__init__() + self.paths = BoundaryPaths() + self.pattern: Optional[Pattern] = None + self.gradient: Optional[Gradient] = None + self.seeds: list[tuple[float, float]] = [] # not supported/exported by MPOLYGON + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy paths, pattern, gradient, seeds.""" + assert isinstance(entity, DXFPolygon) + entity.paths = copy.deepcopy(self.paths) + entity.pattern = copy.deepcopy(self.pattern) + entity.gradient = copy.deepcopy(self.gradient) + entity.seeds = copy.deepcopy(self.seeds) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + # Copy without subclass marker: + tags = Tags(processor.subclasses[2][1:]) + # Removes boundary path data from tags: + tags = self.load_paths(tags) + # Removes gradient data from tags: + tags = self.load_gradient(tags) + # Removes pattern from tags: + tags = self.load_pattern(tags) + # Removes seeds from tags: + tags = self.load_seeds(tags) + + # Load HATCH DXF attributes from remaining tags: + processor.fast_load_dxfattribs( + dxf, self.LOAD_GROUP_CODES, subclass=tags, recover=True + ) + return dxf + + def load_paths(self, tags: Tags) -> Tags: + # Find first group code 91 = count of loops, Spline data also contains + # group code 91! + try: + start_index = tags.tag_index(91) + except const.DXFValueError: + raise const.DXFStructureError( + f"{self.dxftype()}: Missing required DXF tag 'Number of " + f"boundary paths (loops)' (code=91)." + ) + + path_tags = tags.collect_consecutive_tags(PATH_CODES, start=start_index + 1) + if len(path_tags): + self.paths = BoundaryPaths.load_tags(path_tags) + end_index = start_index + len(path_tags) + 1 + del tags[start_index:end_index] + return tags + + def load_pattern(self, tags: Tags) -> Tags: + try: + # Group code 78 = Number of pattern definition lines + index = tags.tag_index(78) + except const.DXFValueError: + # No pattern definition lines found. + return tags + + pattern_tags = tags.collect_consecutive_tags( + PATTERN_DEFINITION_LINE_CODES, start=index + 1 + ) + self.pattern = Pattern.load_tags(pattern_tags) + + # Delete pattern data including length tag 78 + del tags[index : index + len(pattern_tags) + 1] + return tags + + def load_gradient(self, tags: Tags) -> Tags: + try: + index = tags.tag_index(450) + except const.DXFValueError: + # No gradient data present + return tags + + # Gradient data is always at the end of the AcDbHatch subclass. + self.gradient = Gradient.load_tags(tags[index:]) # type: ignore + # Remove gradient data from tags + del tags[index:] + return tags + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, DXFPolygon) + assert clone.doc is not None + + super().map_resources(clone, mapping) + db = clone.doc.entitydb + for path in clone.paths: + handles = [mapping.get_handle(h) for h in path.source_boundary_objects] + path.source_boundary_objects = [h for h in handles if h in db] + + def load_seeds(self, tags: Tags) -> Tags: + return tags + + @property + def has_solid_fill(self) -> bool: + """``True`` if entity has a solid fill. (read only)""" + return bool(self.dxf.solid_fill) + + @property + def has_pattern_fill(self) -> bool: + """``True`` if entity has a pattern fill. (read only)""" + return not bool(self.dxf.solid_fill) + + @property + def has_gradient_data(self) -> bool: + """``True`` if entity has a gradient fill. A hatch with gradient fill + has also a solid fill. (read only) + """ + return bool(self.gradient) + + @property + def bgcolor(self) -> Optional[RGB]: + """ + Set pattern fill background color as (r, g, b)-tuple, rgb values + in the range [0, 255] (read/write/del) + + usage:: + + r, g, b = entity.bgcolor # get pattern fill background color + entity.bgcolor = (10, 20, 30) # set pattern fill background color + del entity.bgcolor # delete pattern fill background color + + """ + try: + xdata_bgcolor = self.get_xdata("HATCHBACKGROUNDCOLOR") + except const.DXFValueError: + return None + color = xdata_bgcolor.get_first_value(1071, 0) + try: + return colors.int2rgb(int(color)) + except ValueError: # invalid data type + return RGB(0, 0, 0) + + @bgcolor.setter + def bgcolor(self, rgb: RGB) -> None: + color_value = ( + colors.rgb2int(rgb) | -0b111110000000000000000000000000 + ) # it's magic + + self.discard_xdata("HATCHBACKGROUNDCOLOR") + self.set_xdata("HATCHBACKGROUNDCOLOR", [(1071, color_value)]) + + @bgcolor.deleter + def bgcolor(self) -> None: + self.discard_xdata("HATCHBACKGROUNDCOLOR") + + def set_gradient( + self, + color1: RGB = RGB(0, 0, 0), + color2: RGB = RGB(255, 255, 255), + rotation: float = 0.0, + centered: float = 0.0, + one_color: int = 0, + tint: float = 0.0, + name: str = "LINEAR", + ) -> None: + """Sets the gradient fill mode and removes all pattern fill related data, requires + DXF R2004 or newer. A gradient filled hatch is also a solid filled hatch. + + Valid gradient type names are: + + - "LINEAR" + - "CYLINDER" + - "INVCYLINDER" + - "SPHERICAL" + - "INVSPHERICAL" + - "HEMISPHERICAL" + - "INVHEMISPHERICAL" + - "CURVED" + - "INVCURVED" + + Args: + color1: (r, g, b)-tuple for first color, rgb values as int in + the range [0, 255] + color2: (r, g, b)-tuple for second color, rgb values as int in + the range [0, 255] + rotation: rotation angle in degrees + centered: determines whether the gradient is centered or not + one_color: 1 for gradient from `color1` to tinted `color1` + tint: determines the tinted target `color1` for a one color + gradient. (valid range 0.0 to 1.0) + name: name of gradient type, default "LINEAR" + + """ + if self.doc is not None and self.doc.dxfversion < const.DXF2004: + raise const.DXFVersionError("Gradient support requires DXF R2004") + if name and name not in const.GRADIENT_TYPES: + raise const.DXFValueError(f"Invalid gradient type name: {name}") + + self.pattern = None + self.dxf.solid_fill = 1 + self.dxf.pattern_name = "SOLID" + self.dxf.pattern_type = const.HATCH_TYPE_PREDEFINED + + gradient = Gradient() + gradient.color1 = color1 + gradient.color2 = color2 + gradient.one_color = one_color + gradient.rotation = rotation + gradient.centered = centered + gradient.tint = tint + gradient.name = name + self.gradient = gradient + + def set_pattern_fill( + self, + name: str, + color: int = 7, + angle: float = 0.0, + scale: float = 1.0, + double: int = 0, + style: int = 1, + pattern_type: int = 1, + definition=None, + ) -> None: + """Sets the pattern fill mode and removes all gradient related data. + + The pattern definition should be designed for a scale factor 1 and a rotation + angle of 0 degrees. The predefined hatch pattern like "ANSI33" are scaled + according to the HEADER variable $MEASUREMENT for ISO measurement (m, cm, ... ), + or imperial units (in, ft, ...), this replicates the behavior of BricsCAD. + + Args: + name: pattern name as string + color: pattern color as :ref:`ACI` + angle: pattern rotation angle in degrees + scale: pattern scale factor + double: double size flag + style: hatch style (0 = normal; 1 = outer; 2 = ignore) + pattern_type: pattern type (0 = user-defined; + 1 = predefined; 2 = custom) + definition: list of definition lines and a definition line is a + 4-tuple [angle, base_point, offset, dash_length_items], + see :meth:`set_pattern_definition` + + """ + self.gradient = None + self.dxf.solid_fill = 0 + self.dxf.pattern_name = name + self.dxf.color = color + self.dxf.pattern_scale = float(scale) + self.dxf.pattern_angle = float(angle) + self.dxf.pattern_double = int(double) + self.dxf.hatch_style = style + self.dxf.pattern_type = pattern_type + + if definition is None: + measurement = 1 + if self.doc: + measurement = self.doc.header.get("$MEASUREMENT", measurement) + predefined_pattern = ( + pattern.ISO_PATTERN if measurement else pattern.IMPERIAL_PATTERN + ) + definition = predefined_pattern.get(name, predefined_pattern["ANSI31"]) + self.set_pattern_definition( + definition, + factor=self.dxf.pattern_scale, + angle=self.dxf.pattern_angle, + ) + + def set_pattern_definition( + self, lines: Sequence, factor: float = 1, angle: float = 0 + ) -> None: + """Setup pattern definition by a list of definition lines and the + definition line is a 4-tuple (angle, base_point, offset, dash_length_items). + The pattern definition should be designed for a pattern scale factor of 1 and + a pattern rotation angle of 0. + + - angle: line angle in degrees + - base-point: (x, y) tuple + - offset: (dx, dy) tuple + - dash_length_items: list of dash items (item > 0 is a line, + item < 0 is a gap and item == 0.0 is a point) + + Args: + lines: list of definition lines + factor: pattern scale factor + angle: rotation angle in degrees + + """ + if factor != 1 or angle: + lines = pattern.scale_pattern(lines, factor=factor, angle=angle) + self.pattern = Pattern( + [PatternLine(line[0], line[1], line[2], line[3]) for line in lines] + ) + + def set_pattern_scale(self, scale: float) -> None: + """Sets the pattern scale factor and scales the pattern definition. + + The method always starts from the original base scale, the + :code:`set_pattern_scale(1)` call resets the pattern scale to the original + appearance as defined by the pattern designer, but only if the pattern attribute + :attr:`dxf.pattern_scale` represents the actual scale, it cannot + restore the original pattern scale from the pattern definition itself. + + Args: + scale: pattern scale factor + + """ + if not self.has_pattern_fill: + return + dxf = self.dxf + self.pattern.scale(factor=1.0 / dxf.pattern_scale * scale) # type: ignore + dxf.pattern_scale = scale + + def set_pattern_angle(self, angle: float) -> None: + """Sets the pattern rotation angle and rotates the pattern definition. + + The method always starts from the original base rotation of 0, the + :code:`set_pattern_angle(0)` call resets the pattern rotation angle to the + original appearance as defined by the pattern designer, but only if the + pattern attribute :attr:`dxf.pattern_angle` represents the actual pattern + rotation, it cannot restore the original rotation angle from the + pattern definition itself. + + Args: + angle: pattern rotation angle in degrees + + """ + if not self.has_pattern_fill: + return + dxf = self.dxf + self.pattern.scale(angle=angle - dxf.pattern_angle) # type: ignore + dxf.pattern_angle = angle % 360.0 + + def transform(self, m: Matrix44) -> DXFPolygon: + """Transform entity by transformation matrix `m` inplace.""" + dxf = self.dxf + ocs = OCSTransform(dxf.extrusion, m) + + elevation = Vec3(dxf.elevation).z + self.paths.transform(ocs, elevation=elevation) + dxf.elevation = ocs.transform_vertex(Vec3(0, 0, elevation)).replace( + x=0.0, y=0.0 + ) + dxf.extrusion = ocs.new_extrusion + if self.pattern: + # todo: non-uniform scaling + # take the scaling factor of the x-axis + factor = ocs.transform_length((self.dxf.pattern_scale, 0, 0)) + angle = ocs.transform_deg_angle(self.dxf.pattern_angle) + # todo: non-uniform pattern scaling is not supported + self.pattern.scale(factor, angle) + self.dxf.pattern_scale = factor + self.dxf.pattern_angle = angle + self.post_transform(m) + return self + + def triangulate(self, max_sagitta, min_segments=16) -> Iterator[Sequence[Vec3]]: + """Triangulate the HATCH/MPOLYGON in OCS coordinates, Elevation and offset is + applied to all vertices. + + Args: + max_sagitta: maximum distance from the center of the curve to the + center of the line segment between two approximation points to determine + if a segment should be subdivided. + min_segments: minimum segment count per Bézier curve + + .. versionadded:: 1.1 + + """ + from ezdxf import path + + elevation = Vec3(self.dxf.elevation) + if self.dxf.hasattr("offset"): # MPOLYGON + elevation += Vec3(self.dxf.offset) # offset in OCS? + boundary_paths = [path.from_hatch_boundary_path(p) for p in self.paths] + for vertices in path.triangulate(boundary_paths, max_sagitta, min_segments): + yield tuple(elevation + v for v in vertices) + + def render_pattern_lines(self) -> Iterator[tuple[Vec3, Vec3]]: + """Yields the pattern lines in WCS coordinates. + + .. versionadded:: 1.1 + + """ + from ezdxf.render import hatching + + if self.has_pattern_fill: + try: + yield from hatching.hatch_entity(self) + except hatching.HatchingError: + return + + @abc.abstractmethod + def set_solid_fill(self, color: int = 7, style: int = 1, rgb: Optional[RGB] = None): + ... + + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + if not self.is_alive: + return + if not self.paths.is_valid(): + auditor.fixed_error( + code=AuditError.INVALID_HATCH_BOUNDARY_PATH, + message=f"Deleted entity {str(self)} containing invalid boundary paths." + ) + auditor.trash(self) \ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/polyline.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/polyline.py new file mode 100644 index 0000000..8f6ceb1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/polyline.py @@ -0,0 +1,1139 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + Union, + cast, + Sequence, + Optional, +) +from itertools import chain +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER, VERTEXNAMES +from ezdxf.lldxf import const +from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS, UVec +from ezdxf.math.transformtools import OCSTransform, NonUniformScalingError +from ezdxf.render.polyline import virtual_polyline_entities +from ezdxf.explode import explode_entity +from ezdxf.query import EntityQuery +from ezdxf.entities import factory +from ezdxf.audit import AuditError +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity, acdb_entity_group_codes +from .lwpolyline import FORMAT_CODES +from .subentity import LinkedEntities + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.entities import DXFNamespace, Line, Arc, Face3d + from ezdxf.layouts import BaseLayout + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.eztypes import FaceType + +__all__ = ["Polyline", "Polyface", "Polymesh"] + +acdb_polyline = DefSubclass( + "AcDbPolylineDummy", + { + # AcDbPolylineDummy is a temporary solution while loading + # Group code 66 is obsolete - Vertices follow flag + # Elevation is a "dummy" point. The x and y values are always 0, + # and the Z value is the polyline elevation: + "elevation": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Polyline flags (bit-coded): + # 1 = closed POLYLINE or a POLYMESH closed in the M direction + # 2 = Curve-fit vertices have been added + # 4 = Spline-fit vertices have been added + # 8 = 3D POLYLINE + # 16 = POLYMESH + # 32 = POLYMESH is closed in the N direction + # 64 = POLYFACE + # 128 = linetype pattern is generated continuously around the vertices + "flags": DXFAttr(70, default=0), + "default_start_width": DXFAttr(40, default=0, optional=True), + "default_end_width": DXFAttr(41, default=0, optional=True), + "m_count": DXFAttr( + 71, + default=0, + optional=True, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + "n_count": DXFAttr( + 72, + default=0, + optional=True, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + "m_smooth_density": DXFAttr(73, default=0, optional=True), + "n_smooth_density": DXFAttr(74, default=0, optional=True), + # Curves and smooth surface type: + # 0 = No smooth surface fitted + # 5 = Quadratic B-spline surface + # 6 = Cubic B-spline surface + # 8 = Bezier surface + "smooth_type": DXFAttr( + 75, + default=0, + optional=True, + validator=validator.is_one_of({0, 5, 6, 8}), + fixer=RETURN_DEFAULT, + ), + "thickness": DXFAttr(39, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_polyline_group_codes = group_code_mapping(acdb_polyline, ignore=(66,)) +merged_polyline_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_polyline_group_codes # type: ignore +) + + +# Notes to SEQEND: +# todo: A loaded entity should have a valid SEQEND, a POLYLINE without vertices +# makes no sense - has to be tested +# +# A virtual POLYLINE does not need a SEQEND, because it can not be exported, +# therefore the SEQEND entity should not be created in the +# DXFEntity.post_new_hook() method. +# +# A bounded POLYLINE needs a SEQEND to valid at export, therefore the +# LinkedEntities.post_bind_hook() method creates a new SEQEND after binding +# the entity to a document if needed. + + +@factory.register_entity +class Polyline(LinkedEntities): + """DXF POLYLINE entity + + The POLYLINE entity is hard owner of its VERTEX entities and the SEQEND entity: + + VERTEX.dxf.owner == POLYLINE.dxf.handle + SEQEND.dxf.owner == POLYLINE.dxf.handle + + """ + + DXFTYPE = "POLYLINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_polyline) + # polyline flags (70) + CLOSED = 1 + MESH_CLOSED_M_DIRECTION = CLOSED + CURVE_FIT_VERTICES_ADDED = 2 + SPLINE_FIT_VERTICES_ADDED = 4 + POLYLINE_3D = 8 + POLYMESH = 16 + MESH_CLOSED_N_DIRECTION = 32 + POLYFACE = 64 + GENERATE_LINETYPE_PATTERN = 128 + # polymesh smooth type (75) + NO_SMOOTH = 0 + QUADRATIC_BSPLINE = 5 + CUBIC_BSPLINE = 6 + BEZIER_SURFACE = 8 + ANY3D = POLYLINE_3D | POLYMESH | POLYFACE + + @property + def vertices(self) -> list[DXFVertex]: + return self._sub_entities # type: ignore + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_polyline_group_codes) + return dxf + + def export_dxf(self, tagwriter: AbstractTagWriter): + """Export POLYLINE entity and all linked entities: VERTEX, SEQEND.""" + super().export_dxf(tagwriter) + # export sub-entities + self.process_sub_entities(lambda e: e.export_dxf(tagwriter)) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export POLYLINE specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, self.get_mode()) + + tagwriter.write_tag2(66, 1) # Vertices follow + self.dxf.export_dxf_attribs( + tagwriter, + [ + "elevation", + "flags", + "default_start_width", + "default_end_width", + "m_count", + "n_count", + "m_smooth_density", + "n_smooth_density", + "smooth_type", + "thickness", + "extrusion", + ], + ) + + def on_layer_change(self, layer: str): + """Event handler for layer change. Changes also the layer of all vertices. + + Args: + layer: new layer as string + + """ + for v in self.vertices: + v.dxf.layer = layer + + def on_linetype_change(self, linetype: str): + """Event handler for linetype change. Changes also the linetype of all + vertices. + + Args: + linetype: new linetype as string + + """ + for v in self.vertices: + v.dxf.linetype = linetype + + def get_vertex_flags(self) -> int: + return const.VERTEX_FLAGS[self.get_mode()] + + def get_mode(self) -> str: + """Returns POLYLINE type as string: + + - "AcDb2dPolyline" + - "AcDb3dPolyline" + - "AcDbPolygonMesh" + - "AcDbPolyFaceMesh" + + """ + if self.is_3d_polyline: + return "AcDb3dPolyline" + elif self.is_polygon_mesh: + return "AcDbPolygonMesh" + elif self.is_poly_face_mesh: + return "AcDbPolyFaceMesh" + else: + return "AcDb2dPolyline" + + @property + def is_2d_polyline(self) -> bool: + """``True`` if POLYLINE is a 2D polyline.""" + return self.dxf.flags & self.ANY3D == 0 + + @property + def is_3d_polyline(self) -> bool: + """``True`` if POLYLINE is a 3D polyline.""" + return bool(self.dxf.flags & self.POLYLINE_3D) + + @property + def is_polygon_mesh(self) -> bool: + """``True`` if POLYLINE is a polygon mesh, see :class:`Polymesh`""" + return bool(self.dxf.flags & self.POLYMESH) + + @property + def is_poly_face_mesh(self) -> bool: + """``True`` if POLYLINE is a poly face mesh, see :class:`Polyface`""" + return bool(self.dxf.flags & self.POLYFACE) + + @property + def is_closed(self) -> bool: + """``True`` if POLYLINE is closed.""" + return bool(self.dxf.flags & self.CLOSED) + + @property + def is_m_closed(self) -> bool: + """``True`` if POLYLINE (as :class:`Polymesh`) is closed in m + direction. + """ + return bool(self.dxf.flags & self.MESH_CLOSED_M_DIRECTION) + + @property + def is_n_closed(self) -> bool: + """``True`` if POLYLINE (as :class:`Polymesh`) is closed in n + direction. + """ + return bool(self.dxf.flags & self.MESH_CLOSED_N_DIRECTION) + + @property + def has_arc(self) -> bool: + """Returns ``True`` if 2D POLYLINE has an arc segment.""" + if self.is_2d_polyline: + return any( + v.dxf.hasattr("bulge") and bool(v.dxf.bulge) for v in self.vertices + ) + else: + return False + + @property + def has_width(self) -> bool: + """Returns ``True`` if 2D POLYLINE has default width values or any + segment with width attributes. + """ + if self.is_2d_polyline: + if self.dxf.hasattr("default_start_width") and bool( + self.dxf.default_start_width + ): + return True + if self.dxf.hasattr("default_end_width") and bool( + self.dxf.default_end_width + ): + return True + for v in self.vertices: + if v.dxf.hasattr("start_width") and bool(v.dxf.start_width): + return True + if v.dxf.hasattr("end_width") and bool(v.dxf.end_width): + return True + return False + + def m_close(self, status=True) -> None: + """Close POLYMESH in m direction if `status` is ``True`` (also closes + POLYLINE), clears closed state if `status` is ``False``. + """ + self.set_flag_state(self.MESH_CLOSED_M_DIRECTION, status, name="flags") + + def n_close(self, status=True) -> None: + """Close POLYMESH in n direction if `status` is ``True``, clears closed + state if `status` is ``False``. + """ + self.set_flag_state(self.MESH_CLOSED_N_DIRECTION, status, name="flags") + + def close(self, m_close=True, n_close=False) -> None: + """Set closed state of POLYMESH and POLYLINE in m direction and n + direction. ``True`` set closed flag, ``False`` clears closed flag. + """ + self.m_close(m_close) + self.n_close(n_close) + + def __len__(self) -> int: + """Returns count of :class:`Vertex` entities.""" + return len(self.vertices) + + def __getitem__(self, pos) -> DXFVertex: + """Get :class:`Vertex` entity at position `pos`, supports list-like slicing. + """ + return self.vertices[pos] + + def points(self) -> Iterator[Vec3]: + """Returns iterable of all polyline vertices as (x, y, z) tuples, + not as :class:`Vertex` objects. + """ + return (vertex.dxf.location for vertex in self.vertices) + + def _append_vertex(self, vertex: DXFVertex) -> None: + self.vertices.append(vertex) + + def append_vertices(self, points: Iterable[UVec], dxfattribs=None) -> None: + """Append multiple :class:`Vertex` entities at location `points`. + + Args: + points: iterable of (x, y[, z]) tuples + dxfattribs: dict of DXF attributes for the VERTEX objects + + """ + dxfattribs = dict(dxfattribs or {}) + for vertex in self._build_dxf_vertices(points, dxfattribs): + self._append_vertex(vertex) + + def append_formatted_vertices( + self, + points: Iterable[Sequence], + format: str = "xy", + dxfattribs=None, + ) -> None: + """Append multiple :class:`Vertex` entities at location `points`. + + Args: + points: iterable of (x, y, [start_width, [end_width, [bulge]]]) + tuple + format: format string, default is "xy", see: :ref:`format codes` + dxfattribs: dict of DXF attributes for the VERTEX objects + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["flags"] = dxfattribs.get("flags", 0) | self.get_vertex_flags() + + # same DXF attributes for VERTEX entities as for POLYLINE + dxfattribs["owner"] = self.dxf.owner + dxfattribs["layer"] = self.dxf.layer + if self.dxf.hasattr("linetype"): + dxfattribs["linetype"] = self.dxf.linetype + + for point in points: + attribs = vertex_attribs(point, format) + attribs.update(dxfattribs) + vertex = cast(DXFVertex, self._new_compound_entity("VERTEX", attribs)) + self._append_vertex(vertex) + + def append_vertex(self, point: UVec, dxfattribs=None) -> None: + """Append a single :class:`Vertex` entity at location `point`. + + Args: + point: as (x, y[, z]) tuple + dxfattribs: dict of DXF attributes for :class:`Vertex` class + + """ + dxfattribs = dict(dxfattribs or {}) + for vertex in self._build_dxf_vertices([point], dxfattribs): + self._append_vertex(vertex) + + def insert_vertices( + self, pos: int, points: Iterable[UVec], dxfattribs=None + ) -> None: + """Insert vertices `points` into :attr:`Polyline.vertices` list + at insertion location `pos` . + + Args: + pos: insertion position of list :attr:`Polyline.vertices` + points: list of (x, y[, z]) tuples + dxfattribs: dict of DXF attributes for :class:`Vertex` class + + """ + dxfattribs = dict(dxfattribs or {}) + self.vertices[pos:pos] = list(self._build_dxf_vertices(points, dxfattribs)) + + def _build_dxf_vertices( + self, points: Iterable[UVec], dxfattribs: dict + ) -> Iterator[DXFVertex]: + """Converts point (x, y, z) tuples into DXFVertex objects. + + Args: + points: list of (x, y, z)-tuples + dxfattribs: dict of DXF attributes + """ + dxfattribs["flags"] = dxfattribs.get("flags", 0) | self.get_vertex_flags() + + # same DXF attributes for VERTEX entities as for POLYLINE + dxfattribs["owner"] = self.dxf.handle + dxfattribs["layer"] = self.dxf.layer + if self.dxf.hasattr("linetype"): + dxfattribs["linetype"] = self.dxf.linetype + for point in points: + dxfattribs["location"] = Vec3(point) + yield cast(DXFVertex, self._new_compound_entity("VERTEX", dxfattribs)) + + def cast(self) -> Union[Polyline, Polymesh, Polyface]: + mode = self.get_mode() + if mode == "AcDbPolyFaceMesh": + return Polyface.from_polyline(self) + elif mode == "AcDbPolygonMesh": + return Polymesh.from_polyline(self) + else: + return self + + def transform(self, m: Matrix44) -> Polyline: + """Transform the POLYLINE entity by transformation matrix `m` inplace. + + A non-uniform scaling is not supported if a 2D POLYLINE contains + circular arc segments (bulges). + + Args: + m: transformation :class:`~ezdxf.math.Matrix44` + + Raises: + NonUniformScalingError: for non-uniform scaling of 2D POLYLINE + containing circular arc segments (bulges) + + """ + + def _ocs_locations(elevation): + for vertex in self.vertices: + location = vertex.dxf.location + if elevation is not None: + # Older DXF versions may not have written the z-axis, so + # replace existing z-axis by the elevation value. + location = location.replace(z=elevation) + yield location + + if self.is_2d_polyline: + dxf = self.dxf + ocs = OCSTransform(self.dxf.extrusion, m) + if not ocs.scale_uniform and self.has_arc: + raise NonUniformScalingError( + "2D POLYLINE containing arcs (bulges) does not support non uniform scaling" + ) + # The caller function has to catch this exception and explode the + # 2D POLYLINE into LINE and ELLIPSE entities. + if dxf.hasattr("elevation"): + z_axis = dxf.elevation.z + else: + z_axis = None + vertices = [ + ocs.transform_vertex(vertex) for vertex in _ocs_locations(z_axis) + ] + + # All vertices of a 2D polyline must have the same z-axis, which is + # the elevation of the polyline: + if vertices: + dxf.elevation = vertices[0].replace(x=0.0, y=0.0) + + for vertex, location in zip(self.vertices, vertices): + vdxf = vertex.dxf + vdxf.location = location + if vdxf.hasattr("start_width"): + vdxf.start_width = ocs.transform_width(vdxf.start_width) + if vdxf.hasattr("end_width"): + vdxf.end_width = ocs.transform_width(vdxf.end_width) + + if dxf.hasattr("default_start_width"): + dxf.default_start_width = ocs.transform_width(dxf.default_start_width) + if dxf.hasattr("default_end_width"): + dxf.default_end_width = ocs.transform_width(dxf.default_end_width) + if dxf.hasattr("thickness"): + dxf.thickness = ocs.transform_thickness(dxf.thickness) + + dxf.extrusion = ocs.new_extrusion + else: + for vertex in self.vertices: + vertex.transform(m) + self.post_transform(m) + return self + + def explode(self, target_layout: Optional[BaseLayout] = None) -> EntityQuery: + """Explode the POLYLINE entity as DXF primitives (LINE, ARC or 3DFACE) + into the target layout, if the target layout is ``None``, the target + layout is the layout of the POLYLINE entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container referencing all + DXF primitives. + + Args: + target_layout: target layout for DXF primitives, ``None`` for same + layout as source entity. + + """ + return explode_entity(self, target_layout) + + def virtual_entities(self) -> Iterator[Union[Line, Arc, Face3d]]: + """Yields the graphical representation of POLYLINE as virtual DXF + primitives (LINE, ARC or 3DFACE). + + These virtual entities are located at the original location, but are not + stored in the entity database, have no handle and are not assigned to + any layout. + + """ + for e in virtual_polyline_entities(self): + e.set_source_of_copy(self) + yield e + + def audit(self, auditor: Auditor) -> None: + """Audit and repair the POLYLINE entity.""" + + def audit_sub_entity(entity): + entity.doc = doc # grant same document + dxf = entity.dxf + if dxf.owner != owner: + dxf.owner = owner + if dxf.layer != layer: + dxf.layer = layer + + doc = self.doc + owner = self.dxf.handle + layer = self.dxf.layer + for vertex in self.vertices: + audit_sub_entity(vertex) + + seqend = self.seqend + if seqend: + audit_sub_entity(seqend) + elif doc: + self.new_seqend() + auditor.fixed_error( + code=AuditError.MISSING_REQUIRED_SEQEND, + message=f"Created required SEQEND entity for {str(self)}.", + dxf_entity=self, + ) + + +class Polyface(Polyline): + """ + PolyFace structure: + + POLYLINE + AcDbEntity + AcDbPolyFaceMesh + VERTEX - Vertex + AcDbEntity + AcDbVertex + AcDbPolyFaceMeshVertex + VERTEX - Face + AcDbEntity + AcDbFaceRecord + SEQEND + + Order of mesh_vertices and face_records is important (DXF R2010): + + 1. mesh_vertices: the polyface mesh vertex locations + 2. face_records: indices of the face forming vertices + + """ + + @classmethod + def from_polyline(cls, polyline: Polyline) -> Polyface: + polyface = cls.shallow_copy(polyline) + polyface._sub_entities = polyline._sub_entities + polyface.seqend = polyline.seqend + # do not destroy polyline - all data would be lost + return polyface + + def append_face(self, face: FaceType, dxfattribs=None) -> None: + """Append a single face. A `face` is a sequence of (x, y, z) tuples. + + Args: + face: sequence of (x, y, z) tuples + dxfattribs: dict of DXF attributes for the VERTEX objects + + """ + self.append_faces([face], dxfattribs) + + def _points_to_dxf_vertices( + self, points: Iterable[UVec], dxfattribs + ) -> list[DXFVertex]: + """Convert (x, y, z) tuples into DXFVertex objects. + + Args: + points: sequence of (x, y, z) tuples + dxfattribs: dict of DXF attributes for the VERTEX entity + + """ + dxfattribs["flags"] = dxfattribs.get("flags", 0) | self.get_vertex_flags() + + # All vertices have to be on the same layer as the POLYLINE entity: + dxfattribs["layer"] = self.get_dxf_attrib("layer", "0") + vertices: list[DXFVertex] = [] + for point in points: + dxfattribs["location"] = point + vertices.append( + cast("DXFVertex", self._new_compound_entity("VERTEX", dxfattribs)) + ) + return vertices + + def append_faces(self, faces: Iterable[FaceType], dxfattribs=None) -> None: + """Append multiple `faces`. `faces` is a list of single faces and a + single face is a sequence of (x, y, z) tuples. + + Args: + faces: iterable of sequences of (x, y, z) tuples + dxfattribs: dict of DXF attributes for the VERTEX entity + + """ + + def new_face_record(): + dxfattribs["flags"] = const.VTX_3D_POLYFACE_MESH_VERTEX + # location of face record vertex is always (0, 0, 0) + dxfattribs["location"] = Vec3() + return cast(DXFVertex, self._new_compound_entity("VERTEX", dxfattribs)) + + dxfattribs = dict(dxfattribs or {}) + + existing_vertices, existing_faces = self.indexed_faces() + new_faces: list[FaceProxy] = [] + for face in faces: + face_mesh_vertices = self._points_to_dxf_vertices(face, {}) + # Index of first new vertex + index = len(existing_vertices) + existing_vertices.extend(face_mesh_vertices) + face_record = FaceProxy(new_face_record(), existing_vertices) + + # Set VERTEX indices: + face_record.indices = tuple(range(index, index + len(face_mesh_vertices))) + new_faces.append(face_record) + self._rebuild(chain(existing_faces, new_faces)) + + def _rebuild(self, faces: Iterable[FaceProxy], precision: int = 6) -> None: + """Build a valid POLYFACE structure from `faces`. + + Args: + faces: iterable of FaceProxy objects. + + """ + polyface_builder = PolyfaceBuilder(faces, precision=precision) + # Why is list[DXFGraphic] incompatible to list[DXFVertex] when DXFVertex + # is a subclass of DXFGraphic? + self._sub_entities = polyface_builder.get_vertices() # type: ignore + self.update_count(polyface_builder.nvertices, polyface_builder.nfaces) + + def update_count(self, nvertices: int, nfaces: int) -> None: + self.dxf.m_count = nvertices + self.dxf.n_count = nfaces + + def optimize(self, precision: int = 6) -> None: + """Rebuilds the :class:`Polyface` by merging vertices with nearly same vertex + locations. + + Args: + precision: floating point precision for determining identical + vertex locations + + """ + vertices, faces = self.indexed_faces() + self._rebuild(faces, precision) + + def faces(self) -> Iterator[list[DXFVertex]]: + """Iterable of all faces, a face is a tuple of vertices. + + Returns: + list of [vertex, vertex, vertex, [vertex,] face_record] + + """ + _, faces = self.indexed_faces() + for face in faces: + face_vertices = list(face) + face_vertices.append(face.face_record) + yield face_vertices + + def indexed_faces(self) -> tuple[list[DXFVertex], Iterator[FaceProxy]]: + """Returns a list of all vertices and a generator of FaceProxy() + objects. + + (internal API) + """ + vertices: list[DXFVertex] = [] + face_records: list[DXFVertex] = [] + for vertex in self.vertices: + (vertices if vertex.is_poly_face_mesh_vertex else face_records).append( + vertex + ) + + faces = (FaceProxy(face_record, vertices) for face_record in face_records) + return vertices, faces + + +class FaceProxy: + """Represents a single face of a polyface structure. (internal class) + + vertices: + + List of all polyface vertices. + + face_record: + + The face forming vertex of type ``AcDbFaceRecord``, contains the indices + to the face building vertices. Indices of the DXF structure are 1-based + and a negative index indicates the beginning of an invisible edge. + Face.face_record.dxf.color determines the color of the face. + + indices: + + Indices to the face building vertices as tuple. This indices are 0-base + and are used to get vertices from the list `Face.vertices`. + + """ + + __slots__ = ("vertices", "face_record", "indices") + + def __init__(self, face_record: DXFVertex, vertices: Sequence[DXFVertex]): + """Returns iterable of all face vertices as :class:`Vertex` entities.""" + self.vertices: Sequence[DXFVertex] = vertices + self.face_record: DXFVertex = face_record + self.indices: Sequence[int] = self._indices() + + def __len__(self) -> int: + """Returns count of face vertices (without face_record).""" + return len(self.indices) + + def __getitem__(self, pos: int) -> DXFVertex: + """Returns :class:`Vertex` at position `pos`. + + Args: + pos: vertex position 0-based + + """ + return self.vertices[self.indices[pos]] + + def __iter__(self) -> Iterator["DXFVertex"]: + return (self.vertices[index] for index in self.indices) + + def points(self) -> Iterator[UVec]: + """Returns iterable of all face vertex locations as (x, y, z)-tuples.""" + return (vertex.dxf.location for vertex in self) + + def _raw_indices(self) -> Iterable[int]: + return (self.face_record.get_dxf_attrib(name, 0) for name in const.VERTEXNAMES) + + def _indices(self) -> Sequence[int]: + return tuple(abs(index) - 1 for index in self._raw_indices() if index != 0) + + def is_edge_visible(self, pos: int) -> bool: + """Returns ``True`` if edge starting at vertex `pos` is visible. + + Args: + pos: vertex position 0-based + + """ + name = const.VERTEXNAMES[pos] + return self.face_record.get_dxf_attrib(name) > 0 + + +class PolyfaceBuilder: + """Optimized POLYFACE builder. (internal class)""" + + def __init__(self, faces: Iterable[FaceProxy], precision: int = 6): + self.precision: int = precision + self.faces: list[DXFVertex] = [] + self.vertices: list[DXFVertex] = [] + self.index_mapping: dict[tuple[float, ...], int] = {} + self.build(faces) + + @property + def nvertices(self) -> int: + return len(self.vertices) + + @property + def nfaces(self) -> int: + return len(self.faces) + + def get_vertices(self) -> list[DXFVertex]: + vertices = self.vertices[:] + vertices.extend(self.faces) + return vertices + + def build(self, faces: Iterable[FaceProxy]) -> None: + for face in faces: + face_record = face.face_record + for vertex, name in zip(face, VERTEXNAMES): + index = self.add(vertex) + # preserve sign of old index value + sign = -1 if face_record.dxf.get(name, 0) < 0 else +1 + face_record.dxf.set(name, (index + 1) * sign) + self.faces.append(face_record) + + def add(self, vertex: DXFVertex) -> int: + def key(point): + return tuple((round(coord, self.precision) for coord in point)) + + location = key(vertex.dxf.location) + try: + return self.index_mapping[location] + except KeyError: + index = len(self.vertices) + self.index_mapping[location] = index + self.vertices.append(vertex) + return index + + +class Polymesh(Polyline): + """ + PolyMesh structure: + + POLYLINE + AcDbEntity + AcDbPolygonMesh + VERTEX + AcDbEntity + AcDbVertex + AcDbPolygonMeshVertex + """ + + @classmethod + def from_polyline(cls, polyline: Polyline) -> Polymesh: + polymesh = cls.shallow_copy(polyline) + polymesh._sub_entities = polyline._sub_entities + polymesh.seqend = polyline.seqend + return polymesh + + def set_mesh_vertex(self, pos: tuple[int, int], point: UVec, dxfattribs=None): + """Set location and DXF attributes of a single mesh vertex. + + Args: + pos: 0-based (row, col) tuple, position of mesh vertex + point: (x, y, z) tuple, new 3D coordinates of the mesh vertex + dxfattribs: dict of DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["location"] = point + vertex = self.get_mesh_vertex(pos) + vertex.update_dxf_attribs(dxfattribs) + + def get_mesh_vertex(self, pos: tuple[int, int]) -> DXFVertex: + """Get location of a single mesh vertex. + + Args: + pos: 0-based (row, col) tuple, position of mesh vertex + + """ + m_count = self.dxf.m_count + n_count = self.dxf.n_count + m, n = pos + if 0 <= m < m_count and 0 <= n < n_count: + return self.vertices[m * n_count + n] + else: + raise const.DXFIndexError(repr(pos)) + + def get_mesh_vertex_cache(self) -> MeshVertexCache: + """Get a :class:`MeshVertexCache` object for this POLYMESH. + The caching object provides fast access to the :attr:`location` + attribute of mesh vertices. + + """ + return MeshVertexCache(self) + + +class MeshVertexCache: + """Cache mesh vertices in a dict, keys are 0-based (row, col)-tuples. + + vertices: + Dict of mesh vertices, keys are 0-based (row, col)-tuples. Writing to + this dict doesn't change the DXF entity. + + """ + + __slots__ = ("vertices",) + + def __init__(self, mesh: Polyline): + self.vertices: dict[tuple[int, int], DXFVertex] = self._setup( + mesh, mesh.dxf.m_count, mesh.dxf.n_count + ) + + def _setup(self, mesh: Polyline, m_count: int, n_count: int) -> dict: + cache: dict[tuple[int, int], DXFVertex] = {} + vertices = iter(mesh.vertices) + for m in range(m_count): + for n in range(n_count): + cache[(m, n)] = next(vertices) + return cache + + def __getitem__(self, pos: tuple[int, int]) -> UVec: + """Get mesh vertex location as (x, y, z)-tuple. + + Args: + pos: 0-based (row, col)-tuple. + + """ + try: + return self.vertices[pos].dxf.location + except KeyError: + raise const.DXFIndexError(repr(pos)) + + def __setitem__(self, pos: tuple[int, int], location: UVec) -> None: + """Get mesh vertex location as (x, y, z)-tuple. + + Args: + pos: 0-based (row, col)-tuple. + location: (x, y, z)-tuple + + """ + try: + self.vertices[pos].dxf.location = location + except KeyError: + raise const.DXFIndexError(repr(pos)) + + +acdb_vertex = DefSubclass( + "AcDbVertex", + { # last subclass index -1 + # Location point in OCS if 2D, and WCS if 3D + "location": DXFAttr(10, xtype=XType.point3d), + "start_width": DXFAttr(40, default=0, optional=True), + "end_width": DXFAttr(41, default=0, optional=True), + # Bulge (optional; default is 0). The bulge is the tangent of one fourth + # the included angle for an arc segment, made negative if the arc goes + # clockwise from the start point to the endpoint. A bulge of 0 indicates + # a straight segment, and a bulge of 1 is a semicircle. + "bulge": DXFAttr(42, default=0, optional=True), + "flags": DXFAttr(70, default=0), + # Curve fit tangent direction (in degrees) + "tangent": DXFAttr(50, optional=True), + "vtx0": DXFAttr(71, optional=True), + "vtx1": DXFAttr(72, optional=True), + "vtx2": DXFAttr(73, optional=True), + "vtx3": DXFAttr(74, optional=True), + "vertex_identifier": DXFAttr(91, optional=True), + }, +) +acdb_vertex_group_codes = group_code_mapping(acdb_vertex) +merged_vertex_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_vertex_group_codes # type: ignore +) + + +@factory.register_entity +class DXFVertex(DXFGraphic): + """DXF VERTEX entity""" + + DXFTYPE = "VERTEX" + + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_vertex) + # Extra vertex created by curve-fitting: + EXTRA_VERTEX_CREATED = 1 + + # Curve-fit tangent defined for this vertex. A curve-fit tangent direction + # of 0 may be omitted from the DXF output, but is significant if this bit + # is set: + CURVE_FIT_TANGENT = 2 + + # 4 = unused, never set in dxf files + # Spline vertex created by spline-fitting + SPLINE_VERTEX_CREATED = 8 + SPLINE_FRAME_CONTROL_POINT = 16 + POLYLINE_3D_VERTEX = 32 + POLYGON_MESH_VERTEX = 64 + POLYFACE_MESH_VERTEX = 128 + FACE_FLAGS = POLYGON_MESH_VERTEX + POLYFACE_MESH_VERTEX + VTX3D = POLYLINE_3D_VERTEX + POLYGON_MESH_VERTEX + POLYFACE_MESH_VERTEX + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_vertex_group_codes) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + # VERTEX can have 3 subclasses if representing a `face record` or + # 4 subclasses if representing a vertex location, just the last + # subclass contains data + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + if self.is_face_record: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbFaceRecord") + else: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbVertex") + if self.is_3d_polyline_vertex: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDb3dPolylineVertex") + elif self.is_poly_face_mesh_vertex: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbPolyFaceMeshVertex") + elif self.is_polygon_mesh_vertex: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDbPolygonMeshVertex") + else: + tagwriter.write_tag2(SUBCLASS_MARKER, "AcDb2dVertex") + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "location", + "start_width", + "end_width", + "bulge", + "flags", + "tangent", + "vtx0", + "vtx1", + "vtx2", + "vtx3", + "vertex_identifier", + ], + ) + + @property + def is_2d_polyline_vertex(self) -> bool: + return self.dxf.flags & self.VTX3D == 0 + + @property + def is_3d_polyline_vertex(self) -> bool: + return self.dxf.flags & self.POLYLINE_3D_VERTEX + + @property + def is_polygon_mesh_vertex(self) -> bool: + return self.dxf.flags & self.POLYGON_MESH_VERTEX + + @property + def is_poly_face_mesh_vertex(self) -> bool: + return self.dxf.flags & self.FACE_FLAGS == self.FACE_FLAGS + + @property + def is_face_record(self) -> bool: + return (self.dxf.flags & self.FACE_FLAGS) == self.POLYFACE_MESH_VERTEX + + def transform(self, m: Matrix44) -> DXFVertex: + """Transform the VERTEX entity by transformation matrix `m` inplace.""" + if self.is_face_record: + return self + self.dxf.location = m.transform(self.dxf.location) + return self + + def format(self, format="xyz") -> Sequence: + """Return formatted vertex components as tuple. + + Format codes: + + - ``x`` = x-coordinate + - ``y`` = y-coordinate + - ``z`` = z-coordinate + - ``s`` = start width + - ``e`` = end width + - ``b`` = bulge value + - ``v`` = (x, y, z) as tuple + + Args: + format: format string, default is "xyz" + + """ + dxf = self.dxf + v = Vec3(dxf.location) + x, y, z = v.xyz + b = dxf.bulge + s = dxf.start_width + e = dxf.end_width + vars = locals() + return tuple(vars[code] for code in format.lower()) + + +def vertex_attribs(data: Sequence, format="xyseb") -> dict: + """Create VERTEX attributes from input data. + + Format codes: + + - ``x`` = x-coordinate + - ``y`` = y-coordinate + - ``s`` = start width + - ``e`` = end width + - ``b`` = bulge value + - ``v`` = (x, y [,z]) tuple (z-axis is ignored) + + Args: + data: list or tuple of point components + format: format string, default is 'xyseb' + + Returns: + dict with keys: 'location', 'bulge', 'start_width', 'end_width' + + """ + attribs = dict() + format = [code for code in format.lower() if code in FORMAT_CODES] + location = Vec3() + for code, value in zip(format, data): + if code not in FORMAT_CODES: + continue + if code == "v": + location = Vec3(value) + elif code == "b": + attribs["bulge"] = float(value) + elif code == "s": + attribs["start_width"] = float(value) + elif code == "e": + attribs["end_width"] = float(value) + elif code == "x": + location = location.replace(x=float(value)) + elif code == "y": + location = location.replace(y=float(value)) + attribs["location"] = location + return attribs diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/shape.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/shape.py new file mode 100644 index 0000000..8b2fd60 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/shape.py @@ -0,0 +1,138 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.math import NULLVEC, Z_AXIS +from ezdxf.math.transformtools import OCSTransform +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + elevation_to_z_axis, + acdb_entity_group_codes, +) +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + + +__all__ = ["Shape"] + +# Description of the "name" attribute from the DWG documentation: 20.4.37 SHAPE (33) +# In DXF the shape name is stored. When reading from DXF, the shape is found by +# iterating over all the text styles and when the text style contains a shape file, +# iterating over all the shapes until the one with the matching name is found. + +acdb_shape = DefSubclass( + "AcDbShape", + { + # Elevation is a legacy feature from R11 and prior, do not use this + # attribute, store the entity elevation in the z-axis of the vertices. + # ezdxf does not export the elevation attribute! + "elevation": DXFAttr(38, default=0, optional=True), + # Thickness could be negative: + "thickness": DXFAttr(39, default=0, optional=True), + # Insertion point (in WCS) + "insert": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Shape size: + "size": DXFAttr(40, default=1), + # Shape name: + "name": DXFAttr(2, default=""), + # Rotation angle in degrees: + "rotation": DXFAttr(50, default=0, optional=True), + # Relative X scale factor + "xscale": DXFAttr( + 41, + default=1, + optional=True, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Oblique angle in degrees: + "oblique": DXFAttr(51, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_shape_group_codes = group_code_mapping(acdb_shape) +merged_shape_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_shape_group_codes # type: ignore +) + + +@register_entity +class Shape(DXFGraphic): + """DXF SHAPE entity""" + + DXFTYPE = "SHAPE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_shape) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_shape_group_codes) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("center",)) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_shape.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "insert", + "size", + "name", + "thickness", + "rotation", + "xscale", + "oblique", + "extrusion", + ], + ) + + def transform(self, m: Matrix44) -> Shape: + """Transform the SHAPE entity by transformation matrix `m` inplace.""" + dxf = self.dxf + dxf.insert = m.transform(dxf.insert) # DXF Reference: WCS? + ocs = OCSTransform(self.dxf.extrusion, m) + + dxf.rotation = ocs.transform_deg_angle(dxf.rotation) + dxf.size = ocs.transform_length((0, dxf.size, 0)) + dxf.x_scale = ocs.transform_length( + (dxf.x_scale, 0, 0), reflection=dxf.x_scale + ) + if dxf.hasattr("thickness"): + dxf.thickness = ocs.transform_thickness(dxf.thickness) + + dxf.extrusion = ocs.new_extrusion + self.post_transform(m) + return self diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/solid.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/solid.py new file mode 100644 index 0000000..969e4ec --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/solid.py @@ -0,0 +1,279 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER, VERTEXNAMES +from ezdxf.math import Matrix44, Z_AXIS, NULLVEC, Vec3 +from ezdxf.math.transformtools import OCSTransform +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + elevation_to_z_axis, + acdb_entity_group_codes, +) +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import DXFNamespace + +__all__ = ["Solid", "Trace", "Face3d"] + +acdb_trace = DefSubclass( + "AcDbTrace", + { + # IMPORTANT: all 4 vertices have to be present in the DXF file, + # otherwise AutoCAD shows a DXF structure error and does not load the + # file! (SOLID, TRACE and 3DFACE) + # 1. corner Solid WCS; Trace OCS + "vtx0": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # 2. corner Solid WCS; Trace OCS + "vtx1": DXFAttr(11, xtype=XType.point3d, default=NULLVEC), + # 3. corner Solid WCS; Trace OCS + "vtx2": DXFAttr(12, xtype=XType.point3d, default=NULLVEC), + # 4. corner Solid WCS; Trace OCS: + # If only three corners are entered to define the SOLID, then the fourth + # corner coordinate is the same as the third. + "vtx3": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + # IMPORTANT: for TRACE and SOLID the last two vertices are in reversed + # order: a square has the vertex order 0-1-3-2 + # Elevation is a legacy feature from R11 and prior, do not use this + # attribute, store the entity elevation in the z-axis of the vertices. + # ezdxf does not export the elevation attribute! + "elevation": DXFAttr(38, default=0, optional=True), + # Thickness could be negative: + "thickness": DXFAttr(39, default=0, optional=True), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_trace_group_codes = group_code_mapping(acdb_trace) +merged_trace_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_trace_group_codes # type: ignore +) + + +class _Base(DXFGraphic): + def __getitem__(self, num): + return self.dxf.get(VERTEXNAMES[num]) + + def __setitem__(self, num, value): + return self.dxf.set(VERTEXNAMES[num], value) + + +@register_entity +class Solid(_Base): + """DXF SHAPE entity""" + + DXFTYPE = "SOLID" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_trace) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_trace_group_codes) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, VERTEXNAMES) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_trace.name) + if not self.dxf.hasattr("vtx3"): + self.dxf.vtx3 = self.dxf.vtx2 + self.dxf.export_dxf_attribs( + tagwriter, + [ + "vtx0", + "vtx1", + "vtx2", + "vtx3", + "thickness", + "extrusion", + ], + ) + + def transform(self, m: Matrix44) -> Solid: + """Transform the SOLID/TRACE entity by transformation matrix `m` inplace.""" + # SOLID and TRACE are OCS entities. + dxf = self.dxf + ocs = OCSTransform(self.dxf.extrusion, m) + for name in VERTEXNAMES: + if dxf.hasattr(name): + dxf.set(name, ocs.transform_vertex(dxf.get(name))) + if dxf.hasattr("thickness"): + dxf.thickness = ocs.transform_thickness(dxf.thickness) + dxf.extrusion = ocs.new_extrusion + self.post_transform(m) + return self + + def wcs_vertices(self, close: bool = False) -> list[Vec3]: + """Returns WCS vertices in correct order, + if argument `close` is ``True``, last vertex == first vertex. + Does **not** return the duplicated last vertex if the entity represents + a triangle. + + """ + ocs = self.ocs() + return list(ocs.points_to_wcs(self.vertices(close))) + + def vertices(self, close: bool = False) -> list[Vec3]: + """Returns OCS vertices in correct order, + if argument `close` is ``True``, last vertex == first vertex. + Does **not** return the duplicated last vertex if the entity represents + a triangle. + + """ + dxf = self.dxf + vertices: list[Vec3] = [dxf.vtx0, dxf.vtx1, dxf.vtx2] + if dxf.vtx3 != dxf.vtx2: # face is not a triangle + vertices.append(dxf.vtx3) + + # adjust weird vertex order of SOLID and TRACE: + # 0, 1, 2, 3 -> 0, 1, 3, 2 + if len(vertices) > 3: + vertices[2], vertices[3] = vertices[3], vertices[2] + + if close and not vertices[0].isclose(vertices[-1]): + vertices.append(vertices[0]) + return vertices + + +@register_entity +class Trace(Solid): + """DXF TRACE entity""" + + DXFTYPE = "TRACE" + + +acdb_face = DefSubclass( + "AcDbFace", + { + # 1. corner WCS: + "vtx0": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # 2. corner WCS: + "vtx1": DXFAttr(11, xtype=XType.point3d, default=NULLVEC), + # 3. corner WCS: + "vtx2": DXFAttr(12, xtype=XType.point3d, default=NULLVEC), + # 4. corner WCS: + # If only three corners are entered to define the SOLID, then the fourth + # corner coordinate is the same as the third. + "vtx3": DXFAttr(13, xtype=XType.point3d, default=NULLVEC), + # invisible: + # 1 = First edge is invisible + # 2 = Second edge is invisible + # 4 = Third edge is invisible + # 8 = Fourth edge is invisible + "invisible_edges": DXFAttr(70, default=0, optional=True), + }, +) +acdb_face_group_codes = group_code_mapping(acdb_face) +merged_face_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, acdb_face_group_codes # type: ignore +) + + +@register_entity +class Face3d(_Base): + """DXF 3DFACE entity""" + + # IMPORTANT: for 3DFACE the last two vertices are in regular order: + # a square has the vertex order 0-1-2-3 + + DXFTYPE = "3DFACE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_face) + + def is_invisible_edge(self, num: int) -> bool: + """Returns True if edge `num` is an invisible edge.""" + if num < 0 or num > 4: + raise ValueError(f"invalid edge: {num}") + return bool(self.dxf.invisible_edges & (1 << num)) + + def set_edge_visibility(self, num: int, visible: bool = False) -> None: + """Set visibility of edge `num`, status `True` for visible, status + `False` for invisible. + """ + if num < 0 or num >= 4: + raise ValueError(f"invalid edge: {num}") + if not visible: + self.dxf.invisible_edges = self.dxf.invisible_edges | (1 << num) + else: + self.dxf.invisible_edges = self.dxf.invisible_edges & ~(1 << num) + + def get_edges_visibility(self) -> list[bool]: + # if the face is a triangle, a fourth visibility flag + # may be present but is ignored + return [not self.is_invisible_edge(i) for i in range(4)] + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + # bypass DXFGraphic, loading proxy graphic is skipped! + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_face_group_codes) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_face.name) + if not self.dxf.hasattr("vtx3"): + self.dxf.vtx3 = self.dxf.vtx2 + self.dxf.export_dxf_attribs( + tagwriter, ["vtx0", "vtx1", "vtx2", "vtx3", "invisible_edges"] + ) + + def transform(self, m: Matrix44) -> Face3d: + """Transform the 3DFACE entity by transformation matrix `m` inplace.""" + dxf = self.dxf + # 3DFACE is a real 3d entity + dxf.vtx0, dxf.vtx1, dxf.vtx2, dxf.vtx3 = m.transform_vertices( + (dxf.vtx0, dxf.vtx1, dxf.vtx2, dxf.vtx3) + ) + self.post_transform(m) + return self + + def wcs_vertices(self, close: bool = False) -> list[Vec3]: + """Returns WCS vertices, if argument `close` is ``True``, + the first vertex is also returned as closing last vertex. + + Returns 4 vertices when `close` is ``False`` and 5 vertices when `close` is + ``True``. Some edges may have zero-length. This is a compatibility interface + to SOLID and TRACE. The 3DFACE entity is already defined by WCS vertices. + """ + dxf = self.dxf + vertices: list[Vec3] = [dxf.vtx0, dxf.vtx1, dxf.vtx2] + vtx3 = dxf.get("vtx3") + if ( + isinstance(vtx3, Vec3) and vtx3 != dxf.vtx2 + ): # face is not a triangle + vertices.append(vtx3) + if close: + vertices.append(vertices[0]) + return vertices diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/spatial_filter.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/spatial_filter.py new file mode 100644 index 0000000..0fd3f63 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/spatial_filter.py @@ -0,0 +1,201 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Iterable +from typing_extensions import Self +import logging + +from ezdxf.lldxf import const, validator +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.math import UVec, Vec2, Matrix44, Z_AXIS, NULLVEC +from ezdxf.entities import factory +from .dxfentity import SubclassProcessor, base_class +from .dxfobj import DXFObject +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.lldxf.tags import Tags + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["SpatialFilter"] + +# The HEADER variable $XCLIPFRAME determines if the clipping path polygon is displayed +# and plotted: +# 0 - not displayed, not plotted +# 1 - displayed, not plotted +# 2 - displayed and plotted + +logger = logging.getLogger("ezdxf") +AcDbFilter = "AcDbFilter" +AcDbSpatialFilter = "AcDbSpatialFilter" + +acdb_filter = DefSubclass(AcDbFilter, {}) +acdb_spatial_filter = DefSubclass( + AcDbSpatialFilter, + { + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + "origin": DXFAttr(11, xtype=XType.point3d, default=NULLVEC), + "is_clipping_enabled": DXFAttr( + 71, default=1, validator=validator.is_integer_bool, fixer=RETURN_DEFAULT + ), + "has_front_clipping_plane": DXFAttr( + 72, default=0, validator=validator.is_integer_bool, fixer=RETURN_DEFAULT + ), + "front_clipping_plane_distance": DXFAttr(40, default=0.0), + "has_back_clipping_plane": DXFAttr( + 73, default=0, validator=validator.is_integer_bool, fixer=RETURN_DEFAULT + ), + "back_clipping_plane_distance": DXFAttr(41, default=0.0), + }, +) +acdb_spatial_filter_group_codes = group_code_mapping(acdb_spatial_filter) + + +@factory.register_entity +class SpatialFilter(DXFObject): + DXFTYPE = "SPATIAL_FILTER" + DXFATTRIBS = DXFAttributes(base_class, acdb_filter, acdb_spatial_filter) + MIN_DXF_VERSION_FOR_EXPORT = const.DXF2000 + + def __init__(self) -> None: + super().__init__() + # clipping path vertices in OCS coordinates + self._boundary_vertices: tuple[Vec2, ...] = tuple() + + # This matrix is the inverse of the original block reference (insert entity) + # transformation. The original block reference transformation is the one that + # is applied to all entities in the block when the block reference is regenerated. + self._inverse_insert_matrix = Matrix44() + + # This matrix transforms points into the coordinate system of the clip boundary. + self._transform_matrix = Matrix44() + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, SpatialFilter) + # immutable data + entity._boundary_vertices = self._boundary_vertices + entity._inverse_insert_matrix = self._inverse_insert_matrix + entity._transform_matrix = self._transform_matrix + + @property + def boundary_vertices(self) -> tuple[Vec2, ...]: + """Returns the clipping path vertices in OCS coordinates.""" + return self._boundary_vertices + + def set_boundary_vertices(self, vertices: Iterable[UVec]) -> None: + """Set the clipping path vertices in OCS coordinates.""" + self._boundary_vertices = tuple(Vec2(v) for v in vertices) + if len(self._boundary_vertices) < 2: + raise const.DXFValueError("2 or more vertices required") + + @property + def inverse_insert_matrix(self) -> Matrix44: + """Returns the inverse insert matrix. + + This matrix is the inverse of the original block reference (insert entity) + transformation. The original block reference transformation is the one that + is applied to all entities in the block when the block reference is regenerated. + """ + return self._inverse_insert_matrix.copy() + + def set_inverse_insert_matrix(self, m: Matrix44) -> None: + self._inverse_insert_matrix = m.copy() + + @property + def transform_matrix(self) -> Matrix44: + """Returns the transform matrix. + + This matrix transforms points into the coordinate system of the clip boundary. + """ + return self._transform_matrix.copy() + + def set_transform_matrix(self, m: Matrix44) -> None: + self._transform_matrix = m.copy() + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.find_subclass(AcDbSpatialFilter) + if tags: + try: + self._load_boundary_data(tags) + except IndexError: + logger.warning( + f"Not enough matrix values in SPATIAL_FILTER(#{processor.handle})" + ) + processor.fast_load_dxfattribs( + dxf, acdb_spatial_filter_group_codes, subclass=tags + ) + else: + logger.warning( + f"Required subclass 'AcDbSpatialFilter' in object " + f"SPATIAL_FILTER(#{processor.handle}) not present" + ) + return dxf + + def _load_boundary_data(self, tags: Tags) -> None: + def to_matrix(v: list[float]) -> Matrix44: + # raises IndexError if not enough matrix values exist + return Matrix44( + # fmt: off + [ + v[0], v[4], v[8], 0.0, + v[1], v[5], v[9], 0.0, + v[2], v[6], v[10], 0.0, + v[3], v[7], v[11], 1.0, + ] + # fmt: on + ) + + self._boundary_vertices = tuple(Vec2(tag.value) for tag in tags.find_all(10)) + matrix_values = [float(tag.value) for tag in tags.find_all(40)] + # use only last 24 values + self._inverse_insert_matrix = to_matrix(matrix_values[-24:-12]) + self._transform_matrix = to_matrix(matrix_values[-12:]) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + + def write_matrix(m: Matrix44) -> None: + for index in range(3): + for value in m.get_col(index): + tagwriter.write_tag2(40, value) + + super().export_entity(tagwriter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, AcDbFilter) + tagwriter.write_tag2(const.SUBCLASS_MARKER, AcDbSpatialFilter) + tagwriter.write_tag2(70, len(self._boundary_vertices)) + for vertex in self._boundary_vertices: + tagwriter.write_vertex(10, vertex) + self.dxf.export_dxf_attribs( + tagwriter, ["extrusion", "origin", "is_clipping_enabled"] + ) + has_front_clipping = self.dxf.has_front_clipping_plane + tagwriter.write_tag2(72, has_front_clipping) + if has_front_clipping: + # AutoCAD does no accept tag 40, if front clipping is disabled + tagwriter.write_tag2(40, self.dxf.front_clipping_plane_distance) + has_back_clipping = self.dxf.has_back_clipping_plane + tagwriter.write_tag2(73, has_back_clipping) + if has_back_clipping: + # AutoCAD does no accept tag 41, if back clipping is disabled + tagwriter.write_tag2(41, self.dxf.back_clipping_plane_distance) + + write_matrix(self._inverse_insert_matrix) + write_matrix(self._transform_matrix) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/spline.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/spline.py new file mode 100644 index 0000000..0b21cbd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/spline.py @@ -0,0 +1,626 @@ +# Copyright (c) 2019-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + List, + Iterable, + Sequence, + cast, + Iterator, + Optional, +) +from typing_extensions import TypeAlias, Self +import array +import copy +from ezdxf.audit import AuditError +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import ( + SUBCLASS_MARKER, + DXF2000, + DXFValueError, + DXFStructureError, +) +from ezdxf.lldxf.packedtags import VertexArray, Tags +from ezdxf.math import ( + Vec3, + UVec, + Matrix44, + ConstructionEllipse, + Z_AXIS, + NULLVEC, + OCS, + uniform_knot_vector, + open_uniform_knot_vector, + BSpline, + required_knot_values, + required_fit_points, + required_control_points, + fit_points_to_cad_cv, +) +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, Ellipse + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.audit import Auditor + +__all__ = ["Spline"] + +# From the Autodesk ObjectARX reference: +# Objects of the AcDbSpline class use an embedded gelib object to maintain the +# actual spline information. +# +# Book recommendations: +# +# - "Curves and Surfaces for CAGD" by Gerald Farin +# - "Mathematical Elements for Computer Graphics" +# by David Rogers and Alan Adams +# - "An Introduction To Splines For Use In Computer Graphics & Geometric Modeling" +# by Richard H. Bartels, John C. Beatty, and Brian A Barsky +# +# http://help.autodesk.com/view/OARX/2018/ENU/?guid=OREF-AcDbSpline__setFitData_AcGePoint3dArray__AcGeVector3d__AcGeVector3d__AcGe__KnotParameterization_int_double +# Construction of a AcDbSpline entity from fit points: +# degree has no effect. A spline with degree=3 is always constructed when +# interpolating a series of fit points. + +acdb_spline = DefSubclass( + "AcDbSpline", + { + # Spline flags: + # 1 = Closed spline + # 2 = Periodic spline + # 4 = Rational spline + # 8 = Planar + # 16 = Linear (planar bit is also set) + "flags": DXFAttr(70, default=0), + # degree: The degree can't be higher than 11 according to the Autodesk + # ObjectARX reference. + "degree": DXFAttr(71, default=3, validator=validator.is_positive), + "n_knots": DXFAttr(72, xtype=XType.callback, getter="knot_count"), + "n_control_points": DXFAttr( + 73, xtype=XType.callback, getter="control_point_count" + ), + "n_fit_points": DXFAttr(74, xtype=XType.callback, getter="fit_point_count"), + "knot_tolerance": DXFAttr(42, default=1e-10, optional=True), + "control_point_tolerance": DXFAttr(43, default=1e-10, optional=True), + "fit_tolerance": DXFAttr(44, default=1e-10, optional=True), + # Start- and end tangents should be normalized, but CAD applications do not + # crash if they are not normalized. + "start_tangent": DXFAttr( + 12, + xtype=XType.point3d, + optional=True, + validator=validator.is_not_null_vector, + ), + "end_tangent": DXFAttr( + 13, + xtype=XType.point3d, + optional=True, + validator=validator.is_not_null_vector, + ), + # Extrusion is the normal vector (omitted if the spline is non-planar) + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # 10: Control points (in WCS); one entry per control point + # 11: Fit points (in WCS); one entry per fit point + # 40: Knot value (one entry per knot) + # 41: Weight (if not 1); with multiple group pairs, they are present if all + # are not 1 + }, +) +acdb_spline_group_codes = group_code_mapping(acdb_spline) + + +class SplineData: + def __init__(self, spline: Spline): + self.fit_points = spline.fit_points + self.control_points = spline.control_points + self.knots = spline.knots + self.weights = spline.weights + + +REMOVE_CODES = {10, 11, 40, 41, 72, 73, 74} + +Vertices: TypeAlias = List[Sequence[float]] + + +@register_entity +class Spline(DXFGraphic): + """DXF SPLINE entity""" + + DXFTYPE = "SPLINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_spline) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + CLOSED = 1 # closed b-spline + PERIODIC = 2 # uniform b-spline + RATIONAL = 4 # rational b-spline + PLANAR = 8 # all spline points in a plane, don't read or set this bit, just ignore like AutoCAD + LINEAR = 16 # always set with PLANAR, don't read or set this bit, just ignore like AutoCAD + + def __init__(self): + super().__init__() + self.fit_points = VertexArray() + self.control_points = VertexArray() + self.knots = [] + self.weights = [] + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy data: control_points, fit_points, weights, knot_values.""" + assert isinstance(entity, Spline) + entity._control_points = copy.deepcopy(self._control_points) + entity._fit_points = copy.deepcopy(self._fit_points) + entity._knots = copy.deepcopy(self._knots) + entity._weights = copy.deepcopy(self._weights) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + if tags: + tags = Tags(self.load_spline_data(tags)) + processor.fast_load_dxfattribs( + dxf, acdb_spline_group_codes, subclass=tags, recover=True + ) + else: + raise DXFStructureError( + f"missing 'AcDbSpline' subclass in SPLINE(#{dxf.handle})" + ) + return dxf + + def load_spline_data(self, tags) -> Iterator: + """Load and set spline data (fit points, control points, weights, + knots) and remove invalid start- and end tangents. + Yields the remaining unprocessed tags. + """ + control_points = [] + fit_points = [] + knots = [] + weights = [] + for tag in tags: + code, value = tag + if code == 10: + control_points.append(value) + elif code == 11: + fit_points.append(value) + elif code == 40: + knots.append(value) + elif code == 41: + weights.append(value) + elif code in (12, 13) and NULLVEC.isclose(value): + # Tangent values equal to (0, 0, 0) are invalid and ignored at + # the loading stage! + pass + else: + yield tag + self.control_points = control_points + self.fit_points = fit_points + self.knots = knots + self.weights = weights + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_spline.name) + self.dxf.export_dxf_attribs(tagwriter, ["extrusion", "flags", "degree"]) + tagwriter.write_tag2(72, self.knot_count()) + tagwriter.write_tag2(73, self.control_point_count()) + tagwriter.write_tag2(74, self.fit_point_count()) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "knot_tolerance", + "control_point_tolerance", + "fit_tolerance", + "start_tangent", + "end_tangent", + ], + ) + + self.export_spline_data(tagwriter) + + def export_spline_data(self, tagwriter: AbstractTagWriter): + for value in self._knots: + tagwriter.write_tag2(40, value) + + if len(self._weights): + for value in self._weights: + tagwriter.write_tag2(41, value) + + self._control_points.export_dxf(tagwriter, code=10) # type: ignore + self._fit_points.export_dxf(tagwriter, code=11) # type: ignore + + @property + def closed(self) -> bool: + """``True`` if spline is closed. A closed spline has a connection from + the last control point to the first control point. (read/write) + """ + return self.get_flag_state(self.CLOSED, name="flags") + + @closed.setter + def closed(self, status: bool) -> None: + self.set_flag_state(self.CLOSED, state=status, name="flags") + + @property + def knots(self) -> list[float]: + """Knot values as :code:`array.array('d')`.""" + return self._knots + + @knots.setter + def knots(self, values: Iterable[float]) -> None: + self._knots: list[float] = cast(List[float], array.array("d", values)) + + # DXF callback attribute Spline.dxf.n_knots + def knot_count(self) -> int: + """Count of knot values.""" + return len(self._knots) + + @property + def weights(self) -> list[float]: + """Control point weights as :code:`array.array('d')`.""" + return self._weights + + @weights.setter + def weights(self, values: Iterable[float]) -> None: + self._weights: list[float] = cast(List[float], array.array("d", values)) + + @property + def control_points(self) -> Vertices: + """:class:`~ezdxf.lldxf.packedtags.VertexArray` of control points in + :ref:`WCS`. + """ + return self._control_points + + @control_points.setter + def control_points(self, points: Iterable[UVec]) -> None: + self._control_points: Vertices = cast( + Vertices, VertexArray(Vec3.list(points)) + ) + + # DXF callback attribute Spline.dxf.n_control_points + def control_point_count(self) -> int: + """Count of control points.""" + return len(self.control_points) + + @property + def fit_points(self) -> Vertices: + """:class:`~ezdxf.lldxf.packedtags.VertexArray` of fit points in + :ref:`WCS`. + """ + return self._fit_points + + @fit_points.setter + def fit_points(self, points: Iterable[UVec]) -> None: + self._fit_points: Vertices = cast( + Vertices, + VertexArray(Vec3.list(points)), + ) + + # DXF callback attribute Spline.dxf.n_fit_points + def fit_point_count(self) -> int: + """Count of fit points.""" + return len(self.fit_points) + + def construction_tool(self) -> BSpline: + """Returns the construction tool :class:`ezdxf.math.BSpline`.""" + if self.control_point_count(): + weights = self.weights if len(self.weights) else None + knots = self.knots if len(self.knots) else None + return BSpline( + control_points=self.control_points, + order=self.dxf.degree + 1, + knots=knots, + weights=weights, + ) + elif self.fit_point_count(): + tangents = None + if self.dxf.hasattr("start_tangent") and self.dxf.hasattr("end_tangent"): + tangents = [self.dxf.start_tangent, self.dxf.end_tangent] + # SPLINE from fit points has always a degree of 3! + return fit_points_to_cad_cv( + self.fit_points, + tangents=tangents, + ) + else: + raise ValueError("Construction tool requires control- or fit points.") + + def apply_construction_tool(self, s) -> Spline: + """Apply SPLINE data from a :class:`~ezdxf.math.BSpline` construction + tool or from a :class:`geomdl.BSpline.Curve` object. + + """ + try: + self.control_points = s.control_points + except AttributeError: # maybe a geomdl.BSpline.Curve class + s = BSpline.from_nurbs_python_curve(s) + self.control_points = s.control_points + + self.dxf.degree = s.degree + self.fit_points = [] # remove fit points + self.knots = s.knots() + self.weights = s.weights() + self.set_flag_state(Spline.RATIONAL, state=bool(len(self.weights))) + return self # floating interface + + def flattening(self, distance: float, segments: int = 4) -> Iterator[Vec3]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments between two knots, if the + distance from the center of the approximation segment to the curve is + bigger than `distance` the segment will be subdivided. + + Args: + distance: maximum distance from the projected curve point onto the + segment chord. + segments: minimum segment count between two knots + + """ + return self.construction_tool().flattening(distance, segments) + + @classmethod + def from_arc(cls, entity: DXFGraphic) -> Spline: + """Create a new SPLINE entity from a CIRCLE, ARC or ELLIPSE entity. + + The new SPLINE entity has no owner, no handle, is not stored in + the entity database nor assigned to any layout! + + """ + dxftype = entity.dxftype() + if dxftype == "ELLIPSE": + ellipse = cast("Ellipse", entity).construction_tool() + elif dxftype == "CIRCLE": + ellipse = ConstructionEllipse.from_arc( + center=entity.dxf.get("center", NULLVEC), + radius=abs(entity.dxf.get("radius", 1.0)), + extrusion=entity.dxf.get("extrusion", Z_AXIS), + ) + elif dxftype == "ARC": + ellipse = ConstructionEllipse.from_arc( + center=entity.dxf.get("center", NULLVEC), + radius=abs(entity.dxf.get("radius", 1.0)), + extrusion=entity.dxf.get("extrusion", Z_AXIS), + start_angle=entity.dxf.get("start_angle", 0), + end_angle=entity.dxf.get("end_angle", 360), + ) + else: + raise TypeError("CIRCLE, ARC or ELLIPSE entity required.") + + spline = Spline.new(dxfattribs=entity.graphic_properties(), doc=entity.doc) + s = BSpline.from_ellipse(ellipse) + spline.dxf.degree = s.degree + spline.dxf.flags = Spline.RATIONAL + spline.control_points = s.control_points # type: ignore + spline.knots = s.knots() # type: ignore + spline.weights = s.weights() # type: ignore + return spline + + def set_open_uniform(self, control_points: Sequence[UVec], degree: int = 3) -> None: + """Open B-spline with a uniform knot vector, start and end at your first + and last control points. + + """ + self.dxf.flags = 0 + self.dxf.degree = degree + self.control_points = control_points # type: ignore + self.knots = open_uniform_knot_vector(len(control_points), degree + 1) + + def set_uniform(self, control_points: Sequence[UVec], degree: int = 3) -> None: + """B-spline with a uniform knot vector, does NOT start and end at your + first and last control points. + + """ + self.dxf.flags = 0 + self.dxf.degree = degree + self.control_points = control_points # type: ignore + self.knots = uniform_knot_vector(len(control_points), degree + 1) + + def set_closed(self, control_points: Sequence[UVec], degree=3) -> None: + """Closed B-spline with a uniform knot vector, start and end at your + first control point. + + """ + self.dxf.flags = self.PERIODIC | self.CLOSED + self.dxf.degree = degree + self.control_points = control_points # type: ignore + self.control_points.extend(control_points[:degree]) + # AutoDesk Developer Docs: + # If the spline is periodic, the length of knot vector will be greater + # than length of the control array by 1, but this does not work with + # BricsCAD. + self.knots = uniform_knot_vector(len(self.control_points), degree + 1) + + def set_open_rational( + self, + control_points: Sequence[UVec], + weights: Sequence[float], + degree: int = 3, + ) -> None: + """Open rational B-spline with a uniform knot vector, start and end at + your first and last control points, and has additional control + possibilities by weighting each control point. + + """ + self.set_open_uniform(control_points, degree=degree) + self.dxf.flags = self.dxf.flags | self.RATIONAL + if len(weights) != len(self.control_points): + raise DXFValueError("Control point count must be equal to weights count.") + self.weights = weights # type: ignore + + def set_uniform_rational( + self, + control_points: Sequence[UVec], + weights: Sequence[float], + degree: int = 3, + ) -> None: + """Rational B-spline with a uniform knot vector, does NOT start and end + at your first and last control points, and has additional control + possibilities by weighting each control point. + + """ + self.set_uniform(control_points, degree=degree) + self.dxf.flags = self.dxf.flags | self.RATIONAL + if len(weights) != len(self.control_points): + raise DXFValueError("Control point count must be equal to weights count.") + self.weights = weights # type: ignore + + def set_closed_rational( + self, + control_points: Sequence[UVec], + weights: Sequence[float], + degree: int = 3, + ) -> None: + """Closed rational B-spline with a uniform knot vector, start and end at + your first control point, and has additional control possibilities by + weighting each control point. + + """ + self.set_closed(control_points, degree=degree) + self.dxf.flags = self.dxf.flags | self.RATIONAL + weights = list(weights) + weights.extend(weights[:degree]) + if len(weights) != len(self.control_points): + raise DXFValueError("Control point count must be equal to weights count.") + self.weights = weights + + def transform(self, m: Matrix44) -> Spline: + """Transform the SPLINE entity by transformation matrix `m` inplace.""" + self._control_points.transform(m) # type: ignore + self._fit_points.transform(m) # type: ignore + # Transform optional attributes if they exist + dxf = self.dxf + for name in ("start_tangent", "end_tangent", "extrusion"): + if dxf.hasattr(name): + dxf.set(name, m.transform_direction(dxf.get(name))) + self.post_transform(m) + return self + + def audit(self, auditor: Auditor) -> None: + """Audit the SPLINE entity.""" + super().audit(auditor) + degree = self.dxf.degree + name = str(self) + + if degree < 1: + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_DEFINITION, + message=f"Removed {name} with invalid degree: {degree} < 1.", + ) + auditor.trash(self) + return + + n_control_points = len(self.control_points) + n_fit_points = len(self.fit_points) + + if n_control_points == 0 and n_fit_points == 0: + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_DEFINITION, + message=f"Removed {name} without any points (no geometry).", + ) + auditor.trash(self) + return + + if n_control_points > 0: + self._audit_control_points(auditor) + # Ignore fit points if defined by control points + elif n_fit_points > 0: + self._audit_fit_points(auditor) + + def _audit_control_points(self, auditor: Auditor): + name = str(self) + order = self.dxf.degree + 1 + n_control_points = len(self.control_points) + + # Splines with to few control points can't be processed: + n_control_points_required = required_control_points(order) + if n_control_points < n_control_points_required: + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_CONTROL_POINT_COUNT, + message=f"Removed {name} with invalid control point count: " + f"{n_control_points} < {n_control_points_required}", + ) + auditor.trash(self) + return + + n_weights = len(self.weights) + n_knots = len(self.knots) + n_knots_required = required_knot_values(n_control_points, order) + + if n_knots < n_knots_required: + # Can not fix entity: because the knot values are basic + # values which define the geometry of SPLINE. + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_KNOT_VALUE_COUNT, + message=f"Removed {name} with invalid knot value count: " + f"{n_knots} < {n_knots_required}", + ) + auditor.trash(self) + return + + if n_weights and n_weights != n_control_points: + # Can not fix entity: because the weights are basic + # values which define the geometry of SPLINE. + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_WEIGHT_COUNT, + message=f"Removed {name} with invalid weight count: " + f"{n_weights} != {n_control_points}", + ) + auditor.trash(self) + return + + def _audit_fit_points(self, auditor: Auditor): + name = str(self) + order = self.dxf.degree + 1 + # Assuming end tangents will be estimated if not present, + # like by ezdxf: + n_fit_points_required = required_fit_points(order, tangents=True) + + # Splines with to few fit points can't be processed: + n_fit_points = len(self.fit_points) + if n_fit_points < n_fit_points_required: + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_FIT_POINT_COUNT, + message=f"Removed {name} with invalid fit point count: " + f"{n_fit_points} < {n_fit_points_required}", + ) + auditor.trash(self) + return + + # Knot values have no meaning for splines defined by fit points: + if len(self.knots): + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_KNOT_VALUE_COUNT, + message=f"Removed unused knot values for {name} " + f"defined by fit points.", + ) + self.knots = [] + + # Weights have no meaning for splines defined by fit points: + if len(self.weights): + auditor.fixed_error( + code=AuditError.INVALID_SPLINE_WEIGHT_COUNT, + message=f"Removed unused weights for {name} " f"defined by fit points.", + ) + self.weights = [] + + def ocs(self) -> OCS: + # WCS entity which supports the "extrusion" attribute in a + # different way! + return OCS() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/subentity.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/subentity.py new file mode 100644 index 0000000..4e13edb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/subentity.py @@ -0,0 +1,217 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Callable, Optional +from typing_extensions import Self + +from ezdxf.entities import factory, DXFGraphic, SeqEnd, DXFEntity +from ezdxf.lldxf import const +from .copy import default_copy +import logging + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity + from ezdxf.entitydb import EntityDB + from ezdxf import xref + + +__all__ = ["entity_linker", "LinkedEntities"] +logger = logging.getLogger("ezdxf") + + +class LinkedEntities(DXFGraphic): + """Super class for common features of the INSERT and the POLYLINE entity. + Both have linked entities like the VERTEX or ATTRIB entity and a + SEQEND entity. + + """ + + def __init__(self) -> None: + super().__init__() + self._sub_entities: list[DXFGraphic] = [] + self.seqend: Optional[SeqEnd] = None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy all sub-entities ands SEQEND. (internal API)""" + assert isinstance(entity, LinkedEntities) + entity._sub_entities = [ + copy_strategy.copy(e) for e in self._sub_entities + ] + if self.seqend: + entity.seqend = copy_strategy.copy(self.seqend) + + def link_entity(self, entity: DXFEntity) -> None: + """Link VERTEX to ATTRIB entities.""" + assert isinstance(entity, DXFGraphic) + entity.set_owner(self.dxf.handle, self.dxf.paperspace) + self._sub_entities.append(entity) + + def link_seqend(self, seqend: DXFEntity) -> None: + """Link SEQEND entity. (internal API)""" + seqend.dxf.owner = self.dxf.owner + if self.seqend is not None: # destroy existing seqend + self.seqend.destroy() + self.seqend = seqend # type: ignore + + def post_bind_hook(self): + """Create always a SEQEND entity.""" + if self.seqend is None: + self.new_seqend() + + def all_sub_entities(self) -> Iterable[DXFEntity]: + """Yields all sub-entities and SEQEND. (internal API)""" + yield from self._sub_entities + if self.seqend: + yield self.seqend + + def process_sub_entities(self, func: Callable[[DXFEntity], None]): + """Call `func` for all sub-entities and SEQEND. (internal API)""" + for entity in self.all_sub_entities(): + if entity.is_alive: + func(entity) + + def add_sub_entities_to_entitydb(self, db: EntityDB) -> None: + """Add sub-entities (VERTEX, ATTRIB, SEQEND) to entity database `db`, + called from EntityDB. (internal API) + """ + + def add(entity: DXFEntity): + entity.doc = self.doc # grant same document + db.add(entity) + + if not self.seqend or not self.seqend.is_alive: + self.new_seqend() + self.process_sub_entities(add) + + def new_seqend(self): + """Create and bind new SEQEND. (internal API)""" + attribs = {"layer": self.dxf.layer} + if self.doc: + seqend = factory.create_db_entry("SEQEND", attribs, self.doc) + else: + seqend = factory.new("SEQEND", attribs) + self.link_seqend(seqend) + + def set_owner(self, owner: Optional[str], paperspace: int = 0): + """Set owner of all sub-entities and SEQEND. (internal API)""" + # Loading from file: POLYLINE/INSERT will be added to layout before + # vertices/attrib entities are linked, so set_owner() of POLYLINE does + # not set owner of vertices at loading time. + super().set_owner(owner, paperspace) + self.take_ownership() + + def take_ownership(self): + """Take ownership of all sub-entities and SEQEND. (internal API)""" + handle = self.dxf.handle + paperspace = self.dxf.paperspace + for entity in self.all_sub_entities(): + if entity.is_alive: + entity.dxf.owner = handle + entity.dxf.paperspace = paperspace + + def remove_dependencies(self, other: Optional[Drawing] = None): + """Remove all dependencies from current document to bind entity to + `other` document. (internal API) + """ + self.process_sub_entities(lambda e: e.remove_dependencies(other)) + super().remove_dependencies(other) + + def destroy(self) -> None: + """Destroy all data and references.""" + if not self.is_alive: + return + + self.process_sub_entities(func=lambda e: e.destroy()) + del self._sub_entities + del self.seqend + super().destroy() + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + self.process_sub_entities(lambda e: e.register_resources(registry)) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + assert isinstance(clone, LinkedEntities) + super().map_resources(clone, mapping) + for source, _clone in zip(self.all_sub_entities(), clone.all_sub_entities()): + source.map_resources(_clone, mapping) + + +LINKED_ENTITIES = {"INSERT": "ATTRIB", "POLYLINE": "VERTEX"} + + +def entity_linker() -> Callable[[DXFEntity], bool]: + """Create an DXF entities linker.""" + main_entity: Optional[DXFEntity] = None + expected_dxftype = "" + + def entity_linker_(entity: DXFEntity) -> bool: + """Collect and link entities which are linked to a parent entity: + + - VERTEX -> POLYLINE + - ATTRIB -> INSERT + + Args: + entity: examined DXF entity + + Returns: + True if `entity` is linked to a parent entity + + """ + nonlocal main_entity, expected_dxftype + dxftype: str = entity.dxftype() + # INSERT & POLYLINE are not linked entities, they are stored in the + # entity space. + are_linked_entities = False + if main_entity is not None: + # VERTEX, ATTRIB & SEQEND are linked tags, they are NOT stored in + # the entity space. + are_linked_entities = True + if dxftype == "SEQEND": + main_entity.link_seqend(entity) # type: ignore + # Marks also the end of the main entity + main_entity = None + # Check for valid DXF structure: + # VERTEX follows POLYLINE + # ATTRIB follows INSERT + elif dxftype == expected_dxftype: + main_entity.link_entity(entity) # type: ignore + else: + raise const.DXFStructureError( + f"Expected DXF entity {dxftype} or SEQEND" + ) + + elif dxftype in LINKED_ENTITIES: + # Only INSERT and POLYLINE have a linked entities structure: + if dxftype == "INSERT" and not entity.dxf.get("attribs_follow", 0): + # INSERT must not have following ATTRIBS: + # + # INSERT with no ATTRIBS, attribs_follow == 0 + # ATTRIB as a stand alone entity, which is a DXF structure + # error, but this error should be handled in the audit + # process. + # .... + # INSERT with ATTRIBS, attribs_follow == 1 + # ATTRIB as connected entity + # SEQEND + # + # Therefore a ATTRIB following an INSERT doesn't mean that + # these entities are linked. + pass + else: + main_entity = entity + expected_dxftype = LINKED_ENTITIES[dxftype] + + # Attached MTEXT entity - this feature most likely does not exist! + elif (dxftype == "MTEXT") and (entity.dxf.handle is None): + logger.error( + "Found attached MTEXT entity. Please open an issue at github: " + "https://github.com/mozman/ezdxf/issues and provide a DXF " + "example file." + ) + return are_linked_entities + + return entity_linker_ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/sun.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/sun.py new file mode 100644 index 0000000..434c510 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/sun.py @@ -0,0 +1,154 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2007 +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + RETURN_DEFAULT, + group_code_mapping, +) +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Sun"] + +acdb_sun = DefSubclass( + "AcDbSun", + { + "version": DXFAttr(90, default=1), + "status": DXFAttr( + 290, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "color": DXFAttr( + 63, + default=7, + validator=validator.is_valid_aci_color, + fixer=RETURN_DEFAULT, + ), + "true_color": DXFAttr(421, default=16777215), + "intensity": DXFAttr(40, default=1), + "shadows": DXFAttr( + 291, + default=1, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "julian_day": DXFAttr(91, default=2456922), + # Time in seconds past midnight: + "time": DXFAttr(92, default=43200), + "daylight_savings_time": DXFAttr( + 292, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + # Shadow type: + # 0 = Ray traced shadows + # 1 = Shadow maps + "shadow_type": DXFAttr( + 70, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "shadow_map_size": DXFAttr(71, default=256), + "shadow_softness": DXFAttr(280, default=1), + }, +) +acdb_sun_group_codes = group_code_mapping(acdb_sun) + + +@register_entity +class Sun(DXFObject): + """DXF SUN entity""" + + DXFTYPE = "SUN" + DXFATTRIBS = DXFAttributes(base_class, acdb_sun) + MIN_DXF_VERSION_FOR_EXPORT = DXF2007 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs(dxf, acdb_sun_group_codes, 1) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_sun.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "version", + "status", + "color", + "true_color", + "intensity", + "shadows", + "julian_day", + "time", + "daylight_savings_time", + "shadow_type", + "shadow_map_size", + "shadow_softness", + ], + ) + + +# todo: implement SUNSTUDY? +acdb_sunstudy = DefSubclass( + "AcDbSun", + { + "version": DXFAttr(90), + "name": DXFAttr(1), + "description": DXFAttr(2), + "output_type": DXFAttr(70), + "sheet_set_name": DXFAttr( + 3 + ), # Included only if Output type is Sheet Set. + "use_subset": DXFAttr( + 290 + ), # Included only if Output type is Sheet Set. + "sheet_subset_name": DXFAttr(4), + # Included only if Output type is Sheet Set. + "dates_from_calender": DXFAttr(291), + "date_input_array_size": DXFAttr(91), + # represents the number of dates picked + # 90 Julian day; represents the date. One entry for each date picked. + # 90 Seconds past midnight; represents the time of day. One entry for each date picked. + "range_of_dates": DXFAttr(292), + # 93 Start time. If range of dates flag is true. + # 94 End time. If range of dates flag is true. + # 95 Interval in seconds. If range of dates flag is true. + "hours_count": DXFAttr(73), + # 290 Hour. One entry for every hour as specified by the number of hours entry above. + "page_setup_wizard_handle": DXFAttr( + 340 + ), # Page setup wizard hard pointer ID + "view_handle": DXFAttr(341), # View hard pointer ID + "visual_style_handle": DXFAttr(342), # Visual Style ID + "shade_plot_type": DXFAttr(74), + "viewports_per_page": DXFAttr(75), + "row_count": DXFAttr(76), # Number of rows for viewport distribution + "column_count": DXFAttr(77), # Number of columns for viewport distribution + "spacing": DXFAttr(40), + "lock_viewports": DXFAttr(293), + "label_viewports": DXFAttr(294), + "text_style_handle": DXFAttr(343), + }, +) +acdb_sunstudy_group_codes = group_code_mapping(acdb_sunstudy) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/table.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/table.py new file mode 100644 index 0000000..f46784c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/table.py @@ -0,0 +1,71 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf.attributes import DXFAttr, DXFAttributes, DefSubclass +from ezdxf.lldxf import const +from .dxfentity import SubclassProcessor, DXFEntity +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["TableHead"] + +base_class = DefSubclass( + None, + { + "name": DXFAttr(2), + "handle": DXFAttr(5), + "owner": DXFAttr(330), + }, +) + +acdb_symbol_table = DefSubclass( + "AcDbSymbolTable", + { + "count": DXFAttr(70, default=0), + }, +) + + +@register_entity +class TableHead(DXFEntity): + """The table head structure is only maintained for export and not for + internal usage, ezdxf ignores an inconsistent table head at runtime. + + """ + + DXFTYPE = "TABLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + dxf.name = processor.base_class.get_first_value(2) + # Stored max table count is not required: + dxf.count = 0 + return dxf + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + assert self.dxf.handle, ( + "TABLE needs a handle, maybe loaded from DXF R12 without handle!" + ) + tagwriter.write_tag2(const.STRUCTURE_MARKER, self.DXFTYPE) + tagwriter.write_tag2(2, self.dxf.name) + if tagwriter.dxfversion >= const.DXF2000: + tagwriter.write_tag2(5, self.dxf.handle) + if self.has_extension_dict: + self.extension_dict.export_dxf(tagwriter) # type: ignore + tagwriter.write_tag2(const.OWNER_CODE, self.dxf.owner) + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_symbol_table.name) + tagwriter.write_tag2(70, self.dxf.count) + # There is always one exception: + if self.dxf.name == "DIMSTYLE": + tagwriter.write_tag2(const.SUBCLASS_MARKER, "AcDbDimStyleTable") + else: # DXF R12 + # TABLE does not need a handle at all + tagwriter.write_tag2(70, self.dxf.count) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/temporary_transform.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/temporary_transform.py new file mode 100644 index 0000000..6c43925 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/temporary_transform.py @@ -0,0 +1,49 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING +import abc + +if TYPE_CHECKING: + from ezdxf.math import Matrix44 + from ezdxf.entities.dxfgfx import DXFEntity + +__all__ = ["TemporaryTransformation", "TransformByBlockReference"] + + +class TemporaryTransformation: + __slots__ = ("_matrix",) + + def __init__(self) -> None: + self._matrix: Matrix44 | None = None + + def get_matrix(self) -> Matrix44 | None: + return self._matrix + + def set_matrix(self, m: Matrix44 | None) -> None: + self._matrix = m + + def add_matrix(self, m: Matrix44) -> None: + matrix = self.get_matrix() + if matrix is not None: + m = matrix @ m + self.set_matrix(m) + + @abc.abstractmethod + def apply_transformation(self, entity: DXFEntity) -> bool: ... + + +class TransformByBlockReference(TemporaryTransformation): + __slots__ = ("_matrix",) + + def apply_transformation(self, entity: DXFEntity) -> bool: + from ezdxf.transform import transform_entity_by_blockref + + m = self.get_matrix() + if m is None: + return False + + if transform_entity_by_blockref(entity, m): + self.set_matrix(None) + return True + return False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/text.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/text.py new file mode 100644 index 0000000..0431e60 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/text.py @@ -0,0 +1,483 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +import math + +from ezdxf.lldxf import validator +from ezdxf.lldxf import const +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, + merge_group_code_mappings, +) +from ezdxf.enums import ( + TextEntityAlignment, + MAP_TEXT_ENUM_TO_ALIGN_FLAGS, + MAP_TEXT_ALIGN_FLAGS_TO_ENUM, +) +from ezdxf.math import Vec3, UVec, Matrix44, NULLVEC, Z_AXIS +from ezdxf.math.transformtools import OCSTransform +from ezdxf.audit import Auditor +from ezdxf.tools.text import plain_text + +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import ( + DXFGraphic, + acdb_entity, + elevation_to_z_axis, + acdb_entity_group_codes, +) +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["Text", "acdb_text", "acdb_text_group_codes"] + +acdb_text = DefSubclass( + "AcDbText", + { + # First alignment point (in OCS): + "insert": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Text height + "height": DXFAttr( + 40, + default=2.5, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # Text content as string: + "text": DXFAttr( + 1, + default="", + validator=validator.is_valid_one_line_text, + fixer=validator.fix_one_line_text, + ), + # Text rotation in degrees (optional) + "rotation": DXFAttr(50, default=0, optional=True), + # Oblique angle in degrees, vertical = 0 deg (optional) + "oblique": DXFAttr(51, default=0, optional=True), + # Text style name (optional), given text style must have an entry in the + # text-styles tables. + "style": DXFAttr(7, default="Standard", optional=True), + # Relative X scale factor—width (optional) + # This value is also adjusted when fit-type text is used + "width": DXFAttr( + 41, + default=1, + optional=True, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # Text generation flags (optional) + # 2 = backward (mirror-x), + # 4 = upside down (mirror-y) + "text_generation_flag": DXFAttr( + 71, + default=0, + optional=True, + validator=validator.is_one_of({0, 2, 4, 6}), + fixer=RETURN_DEFAULT, + ), + # Horizontal text justification type (optional) horizontal justification + # 0 = Left + # 1 = Center + # 2 = Right + # 3 = Aligned (if vertical alignment = 0) + # 4 = Middle (if vertical alignment = 0) + # 5 = Fit (if vertical alignment = 0) + # This value is meaningful only if the value of a 72 or 73 group is nonzero + # (if the justification is anything other than baseline/left) + "halign": DXFAttr( + 72, + default=0, + optional=True, + validator=validator.is_in_integer_range(0, 6), + fixer=RETURN_DEFAULT, + ), + # Second alignment point (in OCS) (optional) + "align_point": DXFAttr(11, xtype=XType.point3d, optional=True), + # Elevation is a legacy feature from R11 and prior, do not use this + # attribute, store the entity elevation in the z-axis of the vertices. + # ezdxf does not export the elevation attribute! + "elevation": DXFAttr(38, default=0, optional=True), + # Thickness in extrusion direction, only supported for SHX font in + # AutoCAD/BricsCAD (optional), can be negative + "thickness": DXFAttr(39, default=0, optional=True), + # Extrusion direction (optional) + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_text_group_codes = group_code_mapping(acdb_text) +acdb_text2 = DefSubclass( + "AcDbText", + { + # Vertical text justification type (optional) + # 0 = Baseline + # 1 = Bottom + # 2 = Middle + # 3 = Top + "valign": DXFAttr( + 73, + default=0, + optional=True, + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ) + }, +) +acdb_text2_group_codes = group_code_mapping(acdb_text2) +merged_text_group_codes = merge_group_code_mappings( + acdb_entity_group_codes, # type: ignore + acdb_text_group_codes, + acdb_text2_group_codes, +) + + +# Formatting codes: +# %%d: '°' +# %%u in TEXT start underline formatting until next %%u or until end of line + + +@register_entity +class Text(DXFGraphic): + """DXF TEXT entity""" + + DXFTYPE = "TEXT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_text, acdb_text2) + # horizontal align values + LEFT = 0 + CENTER = 1 + RIGHT = 2 + # vertical align values + BASELINE = 0 + BOTTOM = 1 + MIDDLE = 2 + TOP = 3 + # text generation flags + MIRROR_X = 2 + MIRROR_Y = 4 + BACKWARD = MIRROR_X + UPSIDE_DOWN = MIRROR_Y + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + """Loading interface. (internal API)""" + dxf = super(DXFGraphic, self).load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, merged_text_group_codes) + if processor.r12: + # Transform elevation attribute from R11 to z-axis values: + elevation_to_z_axis(dxf, ("insert", "align_point")) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags. (internal API)""" + super().export_entity(tagwriter) + self.export_acdb_text(tagwriter) + self.export_acdb_text2(tagwriter) + + def export_acdb_text(self, tagwriter: AbstractTagWriter) -> None: + """Export TEXT data as DXF tags. (internal API)""" + if tagwriter.dxfversion > const.DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_text.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "insert", + "height", + "text", + "thickness", + "rotation", + "oblique", + "style", + "width", + "text_generation_flag", + "halign", + "align_point", + "extrusion", + ], + ) + + def export_acdb_text2(self, tagwriter: AbstractTagWriter) -> None: + """Export TEXT data as DXF tags. (internal API)""" + if tagwriter.dxfversion > const.DXF12: + tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_text2.name) + self.dxf.export_dxf_attribs(tagwriter, "valign") + + def set_placement( + self, + p1: UVec, + p2: Optional[UVec] = None, + align: Optional[TextEntityAlignment] = None, + ) -> Text: + """Set text alignment and location. + + The alignments :attr:`ALIGNED` and :attr:`FIT` + are special, they require a second alignment point, the text is aligned + on the virtual line between these two points and sits vertically at the + baseline. + + - :attr:`ALIGNED`: Text is stretched or compressed + to fit exactly between `p1` and `p2` and the text height is also + adjusted to preserve height/width ratio. + - :attr:`FIT`: Text is stretched or compressed to fit + exactly between `p1` and `p2` but only the text width is adjusted, + the text height is fixed by the :attr:`dxf.height` attribute. + - :attr:`MIDDLE`: also a special adjustment, centered + text like :attr:`MIDDLE_CENTER`, but vertically + centred at the total height of the text. + + Args: + p1: first alignment point as (x, y[, z]) + p2: second alignment point as (x, y[, z]), required for :attr:`ALIGNED` + and :attr:`FIT` else ignored + align: new alignment as enum :class:`~ezdxf.enums.TextEntityAlignment`, + ``None`` to preserve the existing alignment. + + """ + if align is None: + align = self.get_align_enum() + else: + assert isinstance(align, TextEntityAlignment) + self.set_align_enum(align) + self.dxf.insert = p1 + if align in (TextEntityAlignment.ALIGNED, TextEntityAlignment.FIT): + if p2 is None: + raise const.DXFValueError( + f"Alignment '{str(align)}' requires a second alignment point." + ) + else: + p2 = p1 + self.dxf.align_point = p2 + return self + + def get_placement(self) -> tuple[TextEntityAlignment, Vec3, Optional[Vec3]]: + """Returns a tuple (`align`, `p1`, `p2`), `align` is the alignment + enum :class:`~ezdxf.enum.TextEntityAlignment`, `p1` is the + alignment point, `p2` is only relevant if `align` is :attr:`ALIGNED` or + :attr:`FIT`, otherwise it is ``None``. + + """ + p1 = Vec3(self.dxf.insert) + # Except for "LEFT" is the "align point" the real insert point: + # If the required "align point" is not present use "insert"! + p2 = Vec3(self.dxf.get("align_point", p1)) + align = self.get_align_enum() + if align is TextEntityAlignment.LEFT: + return align, p1, None + if align in (TextEntityAlignment.FIT, TextEntityAlignment.ALIGNED): + return align, p1, p2 + return align, p2, None + + def set_align_enum(self, align=TextEntityAlignment.LEFT) -> Text: + """Just for experts: Sets the text alignment without setting the + alignment points, set adjustment points attr:`dxf.insert` and + :attr:`dxf.align_point` manually. + + Args: + align: :class:`~ezdxf.enums.TextEntityAlignment` + + """ + halign, valign = MAP_TEXT_ENUM_TO_ALIGN_FLAGS[align] + self.dxf.halign = halign + self.dxf.valign = valign + return self + + def get_align_enum(self) -> TextEntityAlignment: + """Returns the current text alignment as :class:`~ezdxf.enums.TextEntityAlignment`, + see also :meth:`set_placement`. + """ + halign = self.dxf.get("halign", 0) + valign = self.dxf.get("valign", 0) + if halign > 2: + valign = 0 + return MAP_TEXT_ALIGN_FLAGS_TO_ENUM.get( + (halign, valign), TextEntityAlignment.LEFT + ) + + def transform(self, m: Matrix44) -> Text: + """Transform the TEXT entity by transformation matrix `m` inplace.""" + dxf = self.dxf + if not dxf.hasattr("align_point"): + dxf.align_point = dxf.insert + ocs = OCSTransform(self.dxf.extrusion, m) + dxf.insert = ocs.transform_vertex(dxf.insert) + dxf.align_point = ocs.transform_vertex(dxf.align_point) + old_rotation = dxf.rotation + new_rotation = ocs.transform_deg_angle(old_rotation) + x_scale = ocs.transform_length(Vec3.from_deg_angle(old_rotation)) + y_scale = ocs.transform_length(Vec3.from_deg_angle(old_rotation + 90.0)) + + if not ocs.scale_uniform: + oblique_vec = Vec3.from_deg_angle(old_rotation + 90.0 - dxf.oblique) + new_oblique_deg = ( + new_rotation + + 90.0 + - ocs.transform_direction(oblique_vec).angle_deg + ) + dxf.oblique = new_oblique_deg + y_scale *= math.cos(math.radians(new_oblique_deg)) + + dxf.width *= x_scale / y_scale + dxf.height *= y_scale + dxf.rotation = new_rotation + + if dxf.hasattr("thickness"): # can be negative + dxf.thickness = ocs.transform_thickness(dxf.thickness) + dxf.extrusion = ocs.new_extrusion + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> Text: + """Optimized TEXT/ATTRIB/ATTDEF translation about `dx` in x-axis, `dy` + in y-axis and `dz` in z-axis, returns `self`. + + """ + ocs = self.ocs() + dxf = self.dxf + vec = Vec3(dx, dy, dz) + + dxf.insert = ocs.from_wcs(vec + ocs.to_wcs(dxf.insert)) + if dxf.hasattr("align_point"): + dxf.align_point = ocs.from_wcs(vec + ocs.to_wcs(dxf.align_point)) + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self + + def remove_dependencies(self, other: Optional[Drawing] = None) -> None: + """Remove all dependencies from actual document. + + (internal API) + """ + if not self.is_alive: + return + + super().remove_dependencies() + has_style = other is not None and (self.dxf.style in other.styles) + if not has_style: + self.dxf.style = "Standard" + + def register_resources(self, registry: xref.Registry) -> None: + """Register required resources to the resource registry.""" + super().register_resources(registry) + if self.dxf.hasattr("style"): + registry.add_text_style(self.dxf.style) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + """Translate resources from self to the copied entity.""" + super().map_resources(clone, mapping) + if clone.dxf.hasattr("style"): + clone.dxf.style = mapping.get_text_style(clone.dxf.style) + + def plain_text(self) -> str: + """Returns text content without formatting codes.""" + return plain_text(self.dxf.text) + + def audit(self, auditor: Auditor): + """Validity check.""" + super().audit(auditor) + auditor.check_text_style(self) + + @property + def is_backward(self) -> bool: + """Get/set text generation flag BACKWARDS, for mirrored text along the + x-axis. + """ + return bool(self.dxf.text_generation_flag & const.BACKWARD) + + @is_backward.setter + def is_backward(self, state) -> None: + self.set_flag_state(const.BACKWARD, state, "text_generation_flag") + + @property + def is_upside_down(self) -> bool: + """Get/set text generation flag UPSIDE_DOWN, for mirrored text along + the y-axis. + + """ + return bool(self.dxf.text_generation_flag & const.UPSIDE_DOWN) + + @is_upside_down.setter + def is_upside_down(self, state) -> None: + self.set_flag_state(const.UPSIDE_DOWN, state, "text_generation_flag") + + def wcs_transformation_matrix(self) -> Matrix44: + return text_transformation_matrix(self) + + def font_name(self) -> str: + """Returns the font name of the associated :class:`Textstyle`.""" + font_name = "arial.ttf" + style_name = self.dxf.style + if self.doc: + try: + style = self.doc.styles.get(style_name) + font_name = style.dxf.font + except ValueError: + pass + return font_name + + def fit_length(self) -> float: + """Returns the text length for alignments :attr:`TextEntityAlignment.FIT` + and :attr:`TextEntityAlignment.ALIGNED`, defined by the distance from + the insertion point to the align point or 0 for all other alignments. + + """ + length = 0.0 + align, p1, p2 = self.get_placement() + if align in (TextEntityAlignment.FIT, TextEntityAlignment.ALIGNED): + # text is stretch between p1 and p2 + length = p1.distance(p2) + return length + + +def text_transformation_matrix(entity: Text) -> Matrix44: + """Apply rotation, width factor, translation to the insertion point + and if necessary transformation from OCS to WCS. + """ + angle = math.radians(entity.dxf.rotation) + width_factor = entity.dxf.width + align, p1, p2 = entity.get_placement() + mirror_x = -1 if entity.is_backward else 1 + mirror_y = -1 if entity.is_upside_down else 1 + oblique = math.radians(entity.dxf.oblique) + location = p1 + if align in (TextEntityAlignment.ALIGNED, TextEntityAlignment.FIT): + width_factor = 1.0 # text goes from p1 to p2, no stretching applied + location = p1.lerp(p2, factor=0.5) + angle = (p2 - p1).angle # override stored angle + + m = Matrix44() + if oblique: + m *= Matrix44.shear_xy(angle_x=oblique) + sx = width_factor * mirror_x + sy = mirror_y + if sx != 1 or sy != 1: + m *= Matrix44.scale(sx, sy, 1) + if angle: + m *= Matrix44.z_rotate(angle) + if location: + m *= Matrix44.translate(location.x, location.y, location.z) + + ocs = entity.ocs() + if ocs.transform: # to WCS + m *= ocs.matrix + return m diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/textstyle.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/textstyle.py new file mode 100644 index 0000000..050c7c9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/textstyle.py @@ -0,0 +1,248 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging +from ezdxf.lldxf import validator, const +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.fonts import fonts + +__all__ = ["Textstyle"] +logger = logging.getLogger("ezdxf") + +acdb_style = DefSubclass( + "AcDbTextStyleTableRecord", + { + "name": DXFAttr( + 2, + default="Standard", + validator=validator.is_valid_table_name, + ), + # Flags: Standard flag values (bit-coded values): + # 1 = If set, this entry describes a shape + # 4 = Vertical text + # 16 = If set, table entry is externally dependent on a xref + # 32 = If both this bit and bit 16 are set, the externally dependent xref ... + # 64 = If set, the table entry was referenced by at least one entity in ... + # Vertical text works only for SHX fonts in AutoCAD and BricsCAD + "flags": DXFAttr(70, default=0), + # Fixed height, 0 if not fixed + "height": DXFAttr( + 40, + default=0, + validator=validator.is_greater_or_equal_zero, + fixer=RETURN_DEFAULT, + ), + # Width factor: a.k.a. "Stretch" + "width": DXFAttr( + 41, + default=1, + validator=validator.is_greater_zero, + fixer=RETURN_DEFAULT, + ), + # Oblique angle in degree, 0 = vertical + "oblique": DXFAttr(50, default=0), + # Generation flags: + # 2 = backward + # 4 = mirrored in Y + "generation_flags": DXFAttr(71, default=0), + # Last height used: + "last_height": DXFAttr(42, default=2.5), + # Primary font file name: + # ATTENTION: The font file name can be an empty string and the font family + # may be stored in XDATA! See also posts at the (unrelated) issue #380. + "font": DXFAttr(3, default=const.DEFAULT_TEXT_FONT), + # Big font name, blank if none + "bigfont": DXFAttr(4, default=""), + }, +) +acdb_style_group_codes = group_code_mapping(acdb_style) + + +# XDATA: This is not a reliable source for font data! +# 1001 ACAD +# 1000 Arial ; font-family sometimes an empty string! +# 1071 34 ; flags +# ---- +# "Arial" "normal" flags = 34 = 0b00:00000000:00000000:00100010 +# "Arial" "italic" flags = 16777250 = 0b01:00000000:00000000:00100010 +# "Arial" "bold" flags = 33554466 = 0b10:00000000:00000000:00100010 +# "Arial" "bold+italic" flags = 50331682 = 0b11:00000000:00000000:00100010 + + +@register_entity +class Textstyle(DXFEntity): + """DXF STYLE entity""" + + DXFTYPE = "STYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_style) + ITALIC = 0b01000000000000000000000000 + BOLD = 0b10000000000000000000000000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_style_group_codes) # type: ignore + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_style.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "flags", + "height", + "width", + "oblique", + "generation_flags", + "last_height", + "font", + "bigfont", + ], + ) + + @property + def has_extended_font_data(self) -> bool: + """Returns ``True`` if extended font data is present.""" + return self.has_xdata("ACAD") + + def get_extended_font_data(self) -> tuple[str, bool, bool]: + """Returns extended font data as tuple (font-family, italic-flag, + bold-flag). + + The extended font data is optional and not reliable! Returns + ("", ``False``, ``False``) if extended font data is not present. + + """ + family = "" + italic = False + bold = False + try: + xdata = self.get_xdata("ACAD") + except const.DXFValueError: + pass + else: + if len(xdata) > 1: + group_code, value = xdata[0] + if group_code == 1000: + family = value + group_code, value = xdata[1] + if group_code == 1071: + italic = bool(self.ITALIC & value) + bold = bool(self.BOLD & value) + return family, italic, bold + + def set_extended_font_data( + self, family: str = "", *, italic=False, bold=False + ) -> None: + """Set extended font data, the font-family name `family` is not + validated by `ezdxf`. Overwrites existing data. + """ + if self.has_xdata("ACAD"): + self.discard_xdata("ACAD") + + flags = 34 # unknown default flags + if italic: + flags += self.ITALIC + if bold: + flags += self.BOLD + self.set_xdata("ACAD", [(1000, family), (1071, flags)]) + + def discard_extended_font_data(self): + """Discard extended font data.""" + self.discard_xdata("ACAD") + + @property + def is_backward(self) -> bool: + """Get/set text generation flag BACKWARDS, for mirrored text along the + x-axis. + """ + return self.get_flag_state(const.BACKWARD, "generation_flags") + + @is_backward.setter + def is_backward(self, state) -> None: + self.set_flag_state(const.BACKWARD, state, "generation_flags") + + @property + def is_upside_down(self) -> bool: + """Get/set text generation flag UPSIDE_DOWN, for mirrored text along + the y-axis. + + """ + return self.get_flag_state(const.UPSIDE_DOWN, "generation_flags") + + @is_upside_down.setter + def is_upside_down(self, state) -> None: + self.set_flag_state(const.UPSIDE_DOWN, state, "generation_flags") + + @property + def is_vertical_stacked(self) -> bool: + """Get/set style flag VERTICAL_STACKED, for vertical stacked text.""" + return self.get_flag_state(const.VERTICAL_STACKED, "flags") + + @is_vertical_stacked.setter + def is_vertical_stacked(self, state) -> None: + self.set_flag_state(const.VERTICAL_STACKED, state, "flags") + + @property + def is_shape_file(self) -> bool: + """``True`` if entry describes a shape.""" + return self.dxf.name == "" and bool(self.dxf.flags & 1) + + def make_font( + self, + cap_height: Optional[float] = None, + width_factor: Optional[float] = None, + ) -> fonts.AbstractFont: + """Returns a font abstraction :class:`~ezdxf.tools.fonts.AbstractFont` + for this text style. Returns a font for a cap height of 1, if the + text style has auto height (:attr:`Textstyle.dxf.height` is 0) and + the given `cap_height` is ``None`` or 0. + Uses the :attr:`Textstyle.dxf.width` attribute if the given `width_factor` + is ``None`` or 0, the default value is 1. + The attribute :attr:`Textstyle.dxf.big_font` is ignored. + """ + from ezdxf.fonts import fonts + + ttf = "" + if self.has_extended_font_data: + family, italic, bold = self.get_extended_font_data() + if family: + text_style = "Italic" if italic else "Regular" + text_weight = 700 if bold else 400 + font_face = fonts.FontFace( + family=family, style=text_style, weight=text_weight + ) + ttf = fonts.find_font_file_name(font_face) + else: + ttf = self.dxf.get("font", const.DEFAULT_TTF) + if ttf == "": + ttf = const.DEFAULT_TTF + if cap_height is None or cap_height == 0.0: + cap_height = self.dxf.height + if cap_height == 0.0: + cap_height = 1.0 + if width_factor is None or width_factor == 0.0: + width_factor = self.dxf.width + return fonts.make_font(ttf, cap_height, width_factor) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/tolerance.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/tolerance.py new file mode 100644 index 0000000..979e69e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/tolerance.py @@ -0,0 +1,105 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000 +from ezdxf.math import NULLVEC, Z_AXIS, X_AXIS +from ezdxf.math.transformtools import transform_extrusion +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.math import Matrix44 + from ezdxf import xref + + +__all__ = ["Tolerance"] + +acdb_tolerance = DefSubclass( + "AcDbFcf", + { + "dimstyle": DXFAttr( + 3, + default="Standard", + validator=validator.is_valid_table_name, + ), + # Insertion point (in WCS): + "insert": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # String representing the visual representation of the tolerance: + "content": DXFAttr(1, default=""), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # X-axis direction vector (in WCS): + "x_axis_vector": DXFAttr( + 11, + xtype=XType.point3d, + default=X_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_tolerance_group_codes = group_code_mapping(acdb_tolerance) + + +@register_entity +class Tolerance(DXFGraphic): + """DXF TOLERANCE entity""" + + DXFTYPE = "TOLERANCE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_tolerance) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_tolerance_group_codes, subclass=2, recover=True + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_tolerance.name) + self.dxf.export_dxf_attribs( + tagwriter, + ["dimstyle", "insert", "content", "extrusion", "x_axis_vector"], + ) + + def register_resources(self, registry: xref.Registry) -> None: + super().register_resources(registry) + registry.add_dim_style(self.dxf.dimstyle) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + super().map_resources(clone, mapping) + clone.dxf.dimstyle = mapping.get_dim_style(self.dxf.dimstyle) + + def transform(self, m: Matrix44) -> Tolerance: + """Transform the TOLERANCE entity by transformation matrix `m` inplace.""" + self.dxf.insert = m.transform(self.dxf.insert) + self.dxf.x_axis_vector = m.transform_direction(self.dxf.x_axis_vector) + self.dxf.extrusion, _ = transform_extrusion(self.dxf.extrusion, m) + self.post_transform(m) + return self diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/ucs.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/ucs.py new file mode 100644 index 0000000..d83b93c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/ucs.py @@ -0,0 +1,85 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER +from ezdxf.lldxf import validator +from ezdxf.math import UCS, NULLVEC, X_AXIS, Y_AXIS +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + + +__all__ = ["UCSTableEntry"] +logger = logging.getLogger("ezdxf") + +acdb_ucs = DefSubclass( + "AcDbUCSTableRecord", + { + "name": DXFAttr(2, validator=validator.is_valid_table_name), + "flags": DXFAttr(70, default=0), + "origin": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "xaxis": DXFAttr( + 11, + xtype=XType.point3d, + default=X_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + "yaxis": DXFAttr( + 12, + xtype=XType.point3d, + default=Y_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_ucs_group_codes = group_code_mapping(acdb_ucs) + + +@register_entity +class UCSTableEntry(DXFEntity): + """DXF UCS table entity""" + + DXFTYPE = "UCS" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_ucs) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_ucs_group_codes) # type: ignore + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_ucs.name) + + self.dxf.export_dxf_attribs( + tagwriter, ["name", "flags", "origin", "xaxis", "yaxis"] + ) + + def ucs(self) -> UCS: + """Returns an :class:`ezdxf.math.UCS` object for this UCS table entry.""" + return UCS( + origin=self.dxf.origin, + ux=self.dxf.xaxis, + uy=self.dxf.yaxis, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/underlay.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/underlay.py new file mode 100644 index 0000000..e7457de --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/underlay.py @@ -0,0 +1,446 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Union, Iterable, Optional +from typing_extensions import Self +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000, DXFTypeError +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags +from ezdxf.math import NULLVEC, Z_AXIS, UVec, Matrix44, Vec3 +from .dxfentity import base_class, SubclassProcessor, DXFEntity +from .dxfgfx import DXFGraphic, acdb_entity +from .dxfobj import DXFObject +from .factory import register_entity +from .copy import default_copy +from ezdxf.math.transformtools import ( + InsertTransformationError, + InsertCoordinateSystem, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + + +__all__ = [ + "PdfUnderlay", + "DwfUnderlay", + "DgnUnderlay", + "PdfDefinition", + "DgnDefinition", + "DwfDefinition", + "Underlay", + "UnderlayDefinition", +] + +acdb_underlay = DefSubclass( + "AcDbUnderlayReference", + { + # Hard reference to underlay definition object + "underlay_def_handle": DXFAttr(340), + "insert": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Scale x factor: + "scale_x": DXFAttr( + 41, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Scale y factor: + "scale_y": DXFAttr( + 42, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Scale z factor: + "scale_z": DXFAttr( + 43, + default=1, + validator=validator.is_not_zero, + fixer=RETURN_DEFAULT, + ), + # Rotation angle in degrees: + "rotation": DXFAttr(50, default=0), + "extrusion": DXFAttr( + 210, + xtype=XType.point3d, + default=Z_AXIS, + optional=True, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Underlay display properties: + # 1 = Clipping is on + # 2 = Underlay is on + # 4 = Monochrome + # 8 = Adjust for background + "flags": DXFAttr(280, default=10), + # Contrast value (20-100; default = 100) + "contrast": DXFAttr( + 281, + default=100, + validator=validator.is_in_integer_range(20, 101), + fixer=validator.fit_into_integer_range(20, 101), + ), + # Fade value (0-80; default = 0) + "fade": DXFAttr( + 282, + default=0, + validator=validator.is_in_integer_range(0, 81), + fixer=validator.fit_into_integer_range(0, 81), + ), + }, +) +acdb_underlay_group_codes = group_code_mapping(acdb_underlay) + + +class Underlay(DXFGraphic): + """Virtual UNDERLAY entity.""" + + # DXFTYPE = 'UNDERLAY' + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_underlay) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def __init__(self) -> None: + super().__init__() + self._boundary_path: list[UVec] = [] + self._underlay_def: Optional[UnderlayDefinition] = None + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, Underlay) + entity._boundary_path = list(self._boundary_path) + entity._underlay_def = self._underlay_def + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(2) + + if tags: + tags = Tags(self.load_boundary_path(tags)) + processor.fast_load_dxfattribs( + dxf, acdb_underlay_group_codes, subclass=tags + ) + if len(self.boundary_path) < 2: + self.dxf = dxf + self.reset_boundary_path() + else: + raise const.DXFStructureError( + f"missing 'AcDbUnderlayReference' subclass in " + f"{self.DXFTYPE}(#{dxf.handle})" + ) + return dxf + + def load_boundary_path(self, tags: Tags) -> Iterable: + path = [] + for tag in tags: + if tag.code == 11: + path.append(tag.value) + else: + yield tag + self._boundary_path = path + + def post_load_hook(self, doc: Drawing) -> None: + super().post_load_hook(doc) + db = doc.entitydb + self._underlay_def = db.get(self.dxf.get("underlay_def_handle", None)) # type: ignore + + def post_bind_hook(self): + assert isinstance(self.dxf.handle, str) + underlay_def = self._underlay_def + if ( + isinstance(underlay_def, UnderlayDefinition) + and self.doc is underlay_def.doc # it's not a xref copy! + ): + underlay_def.append_reactor_handle(self.dxf.handle) + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_underlay.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "underlay_def_handle", + "insert", + "scale_x", + "scale_y", + "scale_z", + "rotation", + "extrusion", + "flags", + "contrast", + "fade", + ], + ) + self.export_boundary_path(tagwriter) + + def export_boundary_path(self, tagwriter: AbstractTagWriter): + for vertex in self.boundary_path: + tagwriter.write_vertex(11, vertex[:2]) + + def register_resources(self, registry: xref.Registry) -> None: + super().register_resources(registry) + if isinstance(self._underlay_def, UnderlayDefinition): + registry.add_handle(self._underlay_def.dxf.handle) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + assert isinstance(clone, Underlay) + super().map_resources(clone, mapping) + underlay_def_copy = self.map_underlay_def(clone, mapping) + clone._underlay_def = underlay_def_copy + clone.dxf.underlay_def_handle = underlay_def_copy.dxf.handle + underlay_def_copy.append_reactor_handle(clone.dxf.handle) + + def map_underlay_def( + self, clone: Underlay, mapping: xref.ResourceMapper + ) -> UnderlayDefinition: + underlay_def = self._underlay_def + assert isinstance(underlay_def, UnderlayDefinition) + + underlay_def_copy = mapping.get_reference_of_copy(underlay_def.dxf.handle) + assert isinstance(underlay_def_copy, UnderlayDefinition) + + doc = clone.doc + assert doc is not None + + underlay_dict = doc.rootdict.get_required_dict(underlay_def.acad_dict_name) + if underlay_dict.find_key(underlay_def_copy): # entry already exist + return underlay_def_copy + + # create required dictionary entry + key = doc.objects.next_underlay_key(lambda k: k not in underlay_dict) + underlay_dict.take_ownership(key, underlay_def_copy) + return underlay_def_copy + + def set_underlay_def(self, underlay_def: UnderlayDefinition) -> None: + self._underlay_def = underlay_def + self.dxf.underlay_def_handle = underlay_def.dxf.handle + underlay_def.append_reactor_handle(self.dxf.handle) + + def get_underlay_def(self) -> Optional[UnderlayDefinition]: + return self._underlay_def + + @property + def boundary_path(self): + return self._boundary_path + + @boundary_path.setter + def boundary_path(self, vertices: Iterable[UVec]) -> None: + self.set_boundary_path(vertices) + + @property + def clipping(self) -> bool: + return bool(self.dxf.flags & const.UNDERLAY_CLIPPING) + + @clipping.setter + def clipping(self, state: bool) -> None: + self.set_flag_state(const.UNDERLAY_CLIPPING, state) + + @property + def on(self) -> bool: + return bool(self.dxf.flags & const.UNDERLAY_ON) + + @on.setter + def on(self, state: bool) -> None: + self.set_flag_state(const.UNDERLAY_ON, state) + + @property + def monochrome(self) -> bool: + return bool(self.dxf.flags & const.UNDERLAY_MONOCHROME) + + @monochrome.setter + def monochrome(self, state: bool) -> None: + self.set_flag_state(const.UNDERLAY_MONOCHROME, state) + + @property + def adjust_for_background(self) -> bool: + return bool(self.dxf.flags & const.UNDERLAY_ADJUST_FOR_BG) + + @adjust_for_background.setter + def adjust_for_background(self, state: bool): + self.set_flag_state(const.UNDERLAY_ADJUST_FOR_BG, state) + + @property + def scaling(self) -> tuple[float, float, float]: + return self.dxf.scale_x, self.dxf.scale_y, self.dxf.scale_z + + @scaling.setter + def scaling(self, scale: Union[float, tuple]): + if isinstance(scale, (float, int)): + x, y, z = scale, scale, scale + else: + x, y, z = scale + self.dxf.scale_x = x + self.dxf.scale_y = y + self.dxf.scale_z = z + + def set_boundary_path(self, vertices: Iterable[UVec]) -> None: + # path coordinates as drawing coordinates but unscaled + vertices = list(vertices) + if len(vertices): + self._boundary_path = vertices + self.clipping = True + else: + self.reset_boundary_path() + + def reset_boundary_path(self) -> None: + """Removes the clipping path.""" + self._boundary_path = [] + self.clipping = False + + def destroy(self) -> None: + if not self.is_alive: + return + + if self._underlay_def: + self._underlay_def.discard_reactor_handle(self.dxf.handle) + del self._boundary_path + super().destroy() + + def transform(self, m: Matrix44) -> Underlay: + """Transform UNDERLAY entity by transformation matrix `m` inplace. + + Unlike the transformation matrix `m`, the UNDERLAY entity can not + represent a non-orthogonal target coordinate system and an + :class:`InsertTransformationError` will be raised in that case. + + """ + dxf = self.dxf + source_system = InsertCoordinateSystem( + insert=Vec3(dxf.insert), + scale=(dxf.scale_x, dxf.scale_y, dxf.scale_z), + rotation=dxf.rotation, + extrusion=dxf.extrusion, + ) + try: + target_system = source_system.transform(m) + except InsertTransformationError: + raise InsertTransformationError( + "UNDERLAY entity can not represent a non-orthogonal target coordinate system." + ) + dxf.insert = target_system.insert + dxf.rotation = target_system.rotation + dxf.extrusion = target_system.extrusion + dxf.scale_x = target_system.scale_factor_x + dxf.scale_y = target_system.scale_factor_y + dxf.scale_z = target_system.scale_factor_z + self.post_transform(m) + return self + + +@register_entity +class PdfUnderlay(Underlay): + """DXF PDFUNDERLAY entity""" + + DXFTYPE = "PDFUNDERLAY" + + +@register_entity +class PdfReference(Underlay): + """PDFREFERENCE ia a synonym for PDFUNDERLAY, ezdxf creates always PDFUNDERLAY + entities. + """ + + DXFTYPE = "PDFREFERENCE" + + +@register_entity +class DwfUnderlay(Underlay): + """DXF DWFUNDERLAY entity""" + + DXFTYPE = "DWFUNDERLAY" + + +@register_entity +class DgnUnderlay(Underlay): + """DXF DGNUNDERLAY entity""" + + DXFTYPE = "DGNUNDERLAY" + + +acdb_underlay_def = DefSubclass( + "AcDbUnderlayDefinition", + { + "filename": DXFAttr(1), # File name of underlay + "name": DXFAttr(2), + # underlay name - pdf=page number to display; dgn=default; dwf=???? + }, +) +acdb_underlay_def_group_codes = group_code_mapping(acdb_underlay_def) + + +# (PDF|DWF|DGN)DEFINITION - requires entry in objects table ACAD_(PDF|DWF|DGN)DEFINITIONS, +# ACAD_(PDF|DWF|DGN)DEFINITIONS do not exist by default +class UnderlayDefinition(DXFObject): + """Virtual UNDERLAY DEFINITION entity.""" + + DXFTYPE = "UNDERLAYDEFINITION" + DXFATTRIBS = DXFAttributes(base_class, acdb_underlay_def) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_underlay_def_group_codes, subclass=1 + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_underlay_def.name) + self.dxf.export_dxf_attribs(tagwriter, ["filename", "name"]) + + @property + def file_format(self) -> str: + return self.DXFTYPE[:3] + + @property + def entity_name(self) -> str: + return self.file_format + "UNDERLAY" + + @property + def acad_dict_name(self) -> str: + return f"ACAD_{self.file_format}DEFINITIONS" + + def post_new_hook(self): + self.set_reactors([self.dxf.owner]) + + +@register_entity +class PdfDefinition(UnderlayDefinition): + """DXF PDFDEFINITION entity""" + + DXFTYPE = "PDFDEFINITION" + + +@register_entity +class DwfDefinition(UnderlayDefinition): + """DXF DWFDEFINITION entity""" + + DXFTYPE = "DWFDEFINITION" + + +@register_entity +class DgnDefinition(UnderlayDefinition): + """DXF DGNDEFINITION entity""" + + DXFTYPE = "DGNDEFINITION" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/view.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/view.py new file mode 100644 index 0000000..e834f2a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/view.py @@ -0,0 +1,176 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging + +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER, DXF2000, DXF2007, DXF2010 +from ezdxf.math import Vec3, NULLVEC +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["View"] +logger = logging.getLogger("ezdxf") + +acdb_view = DefSubclass( + "AcDbViewTableRecord", + { + "name": DXFAttr(2, validator=validator.is_valid_table_name), + "flags": DXFAttr(70, default=0), + "height": DXFAttr(40, default=1), + "width": DXFAttr(41, default=1), + "center": DXFAttr(10, xtype=XType.point2d, default=NULLVEC), + "direction": DXFAttr( + 11, + xtype=XType.point3d, + default=Vec3(1, 1, 1), + validator=validator.is_not_null_vector, + ), + "target": DXFAttr(12, xtype=XType.point3d, default=NULLVEC), + "focal_length": DXFAttr(42, default=50), + "front_clipping": DXFAttr(43, default=0), + "back_clipping": DXFAttr(44, default=0), + "view_twist": DXFAttr(50, default=0), + "view_mode": DXFAttr(71, default=0), + # Render mode: + # 0 = 2D Optimized (classic 2D) + # 1 = Wireframe + # 2 = Hidden line + # 3 = Flat shaded + # 4 = Gouraud shaded + # 5 = Flat shaded with wireframe + # 6 = Gouraud shaded with wireframe + "render_mode": DXFAttr( + 281, + default=0, + dxfversion=DXF2000, + validator=validator.is_in_integer_range(0, 7), + fixer=RETURN_DEFAULT, + ), + # 1 if there is an UCS associated to this view, 0 otherwise. + "ucs": DXFAttr( + 72, + default=0, + dxfversion=DXF2000, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "ucs_origin": DXFAttr(110, xtype=XType.point3d, dxfversion=DXF2000), + "ucs_xaxis": DXFAttr( + 111, + xtype=XType.point3d, + dxfversion=DXF2000, + validator=validator.is_not_null_vector, + ), + "ucs_yaxis": DXFAttr( + 112, + xtype=XType.point3d, + dxfversion=DXF2000, + validator=validator.is_not_null_vector, + ), + # 0 = UCS is not orthographic + # 1 = Top + # 2 = Bottom + # 3 = Front + # 4 = Back + # 5 = Left + # 6 = Right + "ucs_ortho_type": DXFAttr( + 79, + dxfversion=DXF2000, + validator=validator.is_in_integer_range(0, 7), + fixer=lambda x: 0, + ), + "elevation": DXFAttr(146, dxfversion=DXF2000, default=0), + # handle of AcDbUCSTableRecord if UCS is a named UCS. If not present, + # then UCS is unnamed: + "ucs_handle": DXFAttr(345, dxfversion=DXF2000), + # handle of AcDbUCSTableRecord of base UCS if UCS is orthographic (79 code + # is non-zero). If not present and 79 code is non-zero, then base UCS is + # taken to be WORLD + "base_ucs_handle": DXFAttr(346, dxfversion=DXF2000), + # 1 if the camera is plottable + "camera_plottable": DXFAttr( + 73, + default=0, + dxfversion=DXF2007, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "background_handle": DXFAttr(332, optional=True, dxfversion=DXF2007), + "live_selection_handle": DXFAttr( + 334, optional=True, dxfversion=DXF2007 + ), + "visual_style_handle": DXFAttr(348, optional=True, dxfversion=DXF2007), + "sun_handle": DXFAttr(361, optional=True, dxfversion=DXF2010), + }, +) +acdb_view_group_codes = group_code_mapping(acdb_view) + + +@register_entity +class View(DXFEntity): + """DXF VIEW entity""" + + DXFTYPE = "VIEW" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_view) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.simple_dxfattribs_loader(dxf, acdb_view_group_codes) # type: ignore + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + if tagwriter.dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_view.name) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "flags", + "height", + "width", + "center", + "direction", + "target", + "focal_length", + "front_clipping", + "back_clipping", + "view_twist", + "view_mode", + "render_mode", + "ucs", + "ucs_origin", + "ucs_xaxis", + "ucs_yaxis", + "ucs_ortho_type", + "elevation", + "ucs_handle", + "base_ucs_handle", + "camera_plottable", + "background_handle", + "live_selection_handle", + "visual_style_handle", + "sun_handle", + ], + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/viewport.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/viewport.py new file mode 100644 index 0000000..6c81890 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/viewport.py @@ -0,0 +1,681 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional +from typing_extensions import Self +import math +from ezdxf.lldxf import validator +from ezdxf.lldxf import const +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.types import DXFTag, DXFVertex +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.const import ( + DXF12, + SUBCLASS_MARKER, + DXFStructureError, + DXFValueError, + DXFTableEntryError, +) +from ezdxf.math import ( + Vec3, + Vec2, + NULLVEC, + X_AXIS, + Y_AXIS, + Z_AXIS, + Matrix44, + BoundingBox2d, +) +from ezdxf.tools import set_flag_state +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf import xref + +__all__ = ["Viewport"] + +acdb_viewport = DefSubclass( + "AcDbViewport", + { + # DXF reference: Center point (in WCS) + # Correction to the DXF reference: + # This point represents the center of the viewport in paper space units + # (DCS), but is stored as 3D point inclusive z-axis! + "center": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + # Width in paper space units: + "width": DXFAttr(40, default=1), + # Height in paper space units: + "height": DXFAttr(41, default=1), + # Viewport status field: (according to the DXF Reference) + # -1 = On, but is fully off-screen, or is one of the viewports that is not + # active because the $MAXACTVP count is currently being exceeded. + # 0 = Off + # = On and active. The value indicates the order of + # stacking for the viewports, where 1 is the "active" viewport, 2 is the + # next, and so on. The "active" viewport determines how the paperspace layout + # is presented as a whole (location & zoom state) + "status": DXFAttr(68, default=0), + # Viewport id: (according to the DXF Reference) + # Special VIEWPORT id == 1, this viewport defines the area of the layout + # which is currently shown in the layout tab by the CAD application. + # I guess this is meant by "active viewport" and therefore it is most likely + # that this id is always 1. + # This "active viewport" is mandatory for a valid DXF file. + # BricsCAD set this id to -1 if the viewport is off and 'status' (group code 68) + # is not present. + "id": DXFAttr(69, default=2), + # DXF reference: View center point (in WCS): + # Correction to the DXF reference: + # This point represents the center point in model space (WCS) stored as + # 2D point! + "view_center_point": DXFAttr(12, xtype=XType.point2d, default=NULLVEC), + "snap_base_point": DXFAttr(13, xtype=XType.point2d, default=NULLVEC), + "snap_spacing": DXFAttr(14, xtype=XType.point2d, default=Vec2(10, 10)), + "grid_spacing": DXFAttr(15, xtype=XType.point2d, default=Vec2(10, 10)), + # View direction vector (WCS): + "view_direction_vector": DXFAttr(16, xtype=XType.point3d, default=Z_AXIS), + # View target point (in WCS): + "view_target_point": DXFAttr(17, xtype=XType.point3d, default=NULLVEC), + "perspective_lens_length": DXFAttr(42, default=50), + "front_clip_plane_z_value": DXFAttr(43, default=0), + "back_clip_plane_z_value": DXFAttr(44, default=0), + # View height (in model space units): + "view_height": DXFAttr(45, default=1), + "snap_angle": DXFAttr(50, default=0), + "view_twist_angle": DXFAttr(51, default=0), + "circle_zoom": DXFAttr(72, default=100), + # 331: Frozen layer object ID/handle (multiple entries may exist) (optional) + # Viewport status bit-coded flags: + # 1 (0x1) = Enables perspective mode + # 2 (0x2) = Enables front clipping + # 4 (0x4) = Enables back clipping + # 8 (0x8) = Enables UCS follow + # 16 (0x10) = Enables front clip not at eye + # 32 (0x20) = Enables UCS icon visibility + # 64 (0x40) = Enables UCS icon at origin + # 128 (0x80) = Enables fast zoom + # 256 (0x100) = Enables snap mode + # 512 (0x200) = Enables grid mode + # 1024 (0x400) = Enables isometric snap style + # 2048 (0x800) = Enables hide plot mode + # 4096 (0x1000) = kIsoPairTop. If set and kIsoPairRight is not set, then + # isopair top is enabled. If both kIsoPairTop and kIsoPairRight are set, + # then isopair left is enabled + # 8192 (0x2000) = kIsoPairRight. If set and kIsoPairTop is not set, then + # isopair right is enabled + # 16384 (0x4000) = Enables viewport zoom locking + # 32768 (0x8000) = Currently always enabled + # 65536 (0x10000) = Enables non-rectangular clipping + # 131072 (0x20000) = Turns the viewport off + # 262144 (0x40000) = Enables the display of the grid beyond the drawing + # limits + # 524288 (0x80000) = Enable adaptive grid display + # 1048576 (0x100000) = Enables subdivision of the grid below the set grid + # spacing when the grid display is adaptive + # 2097152 (0x200000) = Enables grid follows workplane switching + "flags": DXFAttr(90, default=0), + # Clipping viewports: the following handle point to a graphical entity + # located in the paperspace. Known supported entities: + # LWPOLYLINE (2D POLYLINE), CIRCLE, ELLIPSE, closed SPLINE + # Extract bounding- or clipping path: ezdxf.render.make_path() + "clipping_boundary_handle": DXFAttr(340, default="0", optional=True), + # Plot style sheet name assigned to this viewport + "plot_style_name": DXFAttr(1, default=""), + # Render mode: + # 0 = 2D Optimized (classic 2D) + # 1 = Wireframe + # 2 = Hidden line + # 3 = Flat shaded + # 4 = Gouraud shaded + # 5 = Flat shaded with wireframe + # 6 = Gouraud shaded with wireframe + "render_mode": DXFAttr( + 281, + default=0, + validator=validator.is_in_integer_range(0, 7), + fixer=RETURN_DEFAULT, + ), + "ucs_per_viewport": DXFAttr( + 71, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "ucs_icon": DXFAttr(74, default=0), + "ucs_origin": DXFAttr(110, xtype=XType.point3d, default=NULLVEC), + "ucs_x_axis": DXFAttr( + 111, + xtype=XType.point3d, + default=X_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + "ucs_y_axis": DXFAttr( + 112, + xtype=XType.point3d, + default=Y_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + # Handle of AcDbUCSTableRecord if UCS is a named UCS. + # If not present, then UCS is unnamed: + "ucs_handle": DXFAttr(345), + # Handle of AcDbUCSTableRecord of base UCS if UCS is orthographic (79 code + # is non-zero). If not present and 79 code is non-zero, then base UCS is + # taken to be WORLD: + "base_ucs_handle": DXFAttr(346, optional=True), + # UCS ortho type: + # 0 = not orthographic + # 1 = Top + # 2 = Bottom + # 3 = Front + # 4 = Back + # 5 = Left + # 6 = Right + "ucs_ortho_type": DXFAttr( + 79, + default=0, + validator=validator.is_in_integer_range(0, 7), + fixer=RETURN_DEFAULT, + ), + "elevation": DXFAttr(146, default=0), + # Shade plot mode: + # 0 = As Displayed + # 1 = Wireframe + # 2 = Hidden + # 3 = Rendered + "shade_plot_mode": DXFAttr( + 170, + dxfversion="AC1018", + validator=validator.is_in_integer_range(0, 4), + fixer=RETURN_DEFAULT, + ), + # Frequency of major grid lines compared to minor grid lines + "grid_frequency": DXFAttr(61, dxfversion="AC1021"), + "background_handle": DXFAttr(332, dxfversion="AC1021", optional=True), + "shade_plot_handle": DXFAttr(333, dxfversion="AC1021", optional=True), + "visual_style_handle": DXFAttr(348, dxfversion="AC1021", optional=True), + "default_lighting_flag": DXFAttr( + 292, dxfversion="AC1021", default=1, optional=True + ), + # Default lighting type: + # 0 = One distant light + # 1 = Two distant lights + "default_lighting_type": DXFAttr( + 282, + default=0, + dxfversion="AC1021", + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "view_brightness": DXFAttr(141, dxfversion="AC1021"), + "view_contrast": DXFAttr(142, dxfversion="AC1021"), + # as AutoCAD Color Index + "ambient_light_color_1": DXFAttr( + 63, + dxfversion="AC1021", + validator=validator.is_valid_aci_color, + ), + # as True Color: + "ambient_light_color_2": DXFAttr(421, dxfversion="AC1021"), + # as True Color: + "ambient_light_color_3": DXFAttr(431, dxfversion="AC1021"), + "sun_handle": DXFAttr(361, dxfversion="AC1021", optional=True), + # The following attributes are mentioned in the DXF reference but may not really exist: + # "Soft pointer reference to viewport object (for layer VP property override)" + "ref_vp_object_1": DXFAttr(335, dxfversion="AC1021"), # soft-pointer + "ref_vp_object_2": DXFAttr(343, dxfversion="AC1021"), # hard-pointer + "ref_vp_object_3": DXFAttr(344, dxfversion="AC1021"), # hard-pointer + "ref_vp_object_4": DXFAttr(91, dxfversion="AC1021"), # this is not a pointer! + }, +) +acdb_viewport_group_codes = group_code_mapping(acdb_viewport) +# Note: +# The ZOOM XP factor is calculated with the following formula: +# group_41 / group_45 (or pspace_height / mspace_height). + +FROZEN_LAYER_GROUP_CODE = 331 + + +@register_entity +class Viewport(DXFGraphic): + """DXF VIEWPORT entity""" + + DXFTYPE = "VIEWPORT" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_viewport) + + # Notes to viewport_id: + # The id of the first viewport has to be 1, which is the definition of + # paper space. For the following viewports it seems only important, that + # the id is greater than 1. + + def __init__(self) -> None: + super().__init__() + self._frozen_layers: list[str] = [] + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + assert isinstance(entity, Viewport) + entity._frozen_layers = list(self._frozen_layers) + + @property + def frozen_layers(self) -> list[str]: + """Set/get frozen layers as list of layer names.""" + return self._frozen_layers + + @frozen_layers.setter + def frozen_layers(self, names: Iterable[str]): + self._frozen_layers = list(names) + + def _layer_index(self, layer_name: str) -> int: + name_key = validator.make_table_key(layer_name) + for index, name in enumerate(self._frozen_layers): + if name_key == validator.make_table_key(name): + return index + return -1 + + def freeze(self, layer_name: str) -> None: + """Freeze `layer_name` in this viewport.""" + index = self._layer_index(layer_name) + if index == -1: + self._frozen_layers.append(layer_name) + + def is_frozen(self, layer_name: str) -> bool: + """Returns ``True`` if `layer_name` id frozen in this viewport.""" + return self._layer_index(layer_name) != -1 + + def thaw(self, layer_name: str) -> None: + """Thaw `layer_name` in this viewport.""" + index = self._layer_index(layer_name) + if index != -1: + del self._frozen_layers[index] + + @property + def is_visible(self) -> bool: + # VIEWPORT id == 1 or status == 1, this viewport defines the "active viewport" + # which is the area currently shown in the layout tab by the CAD + # application. + # BricsCAD set id to -1 if the viewport is off and 'status' (group + # code 68) is not present. + # status: -1= off-screen, 0= off, 1= "active viewport" + if self.dxf.hasattr("status"): + return self.dxf.status > 0 + return self.dxf.id > 1 + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.fast_load_dxfattribs( + dxf, acdb_viewport_group_codes, subclass=2, log=False + ) + if processor.r12: + self.load_xdata_into_dxf_namespace() + else: + if len(tags): + tags = self.load_frozen_layer_handles(tags) + if len(tags): + processor.log_unprocessed_tags(tags, subclass=acdb_viewport.name) + return dxf + + def post_load_hook(self, doc: Drawing): + super().post_load_hook(doc) + bag: list[str] = [] + db = doc.entitydb + for handle in self._frozen_layers: + try: + bag.append(db[handle].dxf.name) + except KeyError: # ignore non-existing layers + pass + self._frozen_layers = bag + + def load_frozen_layer_handles(self, tags: Tags) -> Tags: + unprocessed_tags = Tags() + for tag in tags: + if tag.code == FROZEN_LAYER_GROUP_CODE: + self._frozen_layers.append(tag.value) + else: + unprocessed_tags.append(tag) + return unprocessed_tags + + def load_xdata_into_dxf_namespace(self) -> None: + try: + tags = [v for c, v in self.xdata.get_xlist("ACAD", "MVIEW")] # type: ignore + except DXFValueError: + return + tags = tags[3:-2] + dxf = self.dxf + flags = 0 + flags = set_flag_state(flags, const.VSF_FAST_ZOOM, bool(tags[11])) + flags = set_flag_state(flags, const.VSF_SNAP_MODE, bool(tags[13])) + flags = set_flag_state(flags, const.VSF_GRID_MODE, bool(tags[14])) + flags = set_flag_state(flags, const.VSF_ISOMETRIC_SNAP_STYLE, bool(tags[15])) + flags = set_flag_state(flags, const.VSF_HIDE_PLOT_MODE, bool(tags[24])) + try: + dxf.view_target_point = tags[0] + dxf.view_direction_vector = tags[1] + dxf.view_twist_angle = tags[2] + dxf.view_height = tags[3] + dxf.view_center_point = tags[4], tags[5] + dxf.perspective_lens_length = tags[6] + dxf.front_clip_plane_z_value = tags[7] + dxf.back_clip_plane_z_value = tags[8] + dxf.render_mode = tags[9] # view_mode == render_mode ? + dxf.circle_zoom = tags[10] + # fast zoom flag : tag[11] + dxf.ucs_icon = tags[12] + # snap mode flag = tags[13] + # grid mode flag = tags[14] + # isometric snap style = tags[15] + # dxf.snap_isopair = tags[16] ??? + dxf.snap_angle = tags[17] + dxf.snap_base_point = tags[18], tags[19] + dxf.snap_spacing = tags[20], tags[21] + dxf.grid_spacing = tags[22], tags[23] + # hide plot flag = tags[24] + except IndexError: # internal exception + raise DXFStructureError("Invalid viewport entity - missing data") + dxf.flags = flags + self._frozen_layers = tags[26:] + self.xdata.discard("ACAD") # type: ignore + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + if tagwriter.dxfversion == DXF12: + self.export_acdb_viewport_r12(tagwriter) + else: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_viewport.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "center", + "width", + "height", + "status", + "id", + "view_center_point", + "snap_base_point", + "snap_spacing", + "grid_spacing", + "view_direction_vector", + "view_target_point", + "perspective_lens_length", + "front_clip_plane_z_value", + "back_clip_plane_z_value", + "view_height", + "snap_angle", + "view_twist_angle", + "circle_zoom", + ], + ) + if len(self.frozen_layers): + assert self.doc is not None, "valid DXF document required" + layers = self.doc.layers + for layer_name in self.frozen_layers: + try: + layer = layers.get(layer_name) + except DXFTableEntryError: + pass + else: + tagwriter.write_tag2(FROZEN_LAYER_GROUP_CODE, layer.dxf.handle) + + self.dxf.export_dxf_attribs( + tagwriter, + [ + "flags", + "clipping_boundary_handle", + "plot_style_name", + "render_mode", + "ucs_per_viewport", + "ucs_icon", + "ucs_origin", + "ucs_x_axis", + "ucs_y_axis", + "ucs_handle", + "base_ucs_handle", + "ucs_ortho_type", + "elevation", + "shade_plot_mode", + "grid_frequency", + "background_handle", + "shade_plot_handle", + "visual_style_handle", + "default_lighting_flag", + "default_lighting_type", + "view_brightness", + "view_contrast", + "ambient_light_color_1", + "ambient_light_color_2", + "ambient_light_color_3", + "sun_handle", + "ref_vp_object_1", + "ref_vp_object_2", + "ref_vp_object_3", + "ref_vp_object_4", + ], + ) + + def export_acdb_viewport_r12(self, tagwriter: AbstractTagWriter): + self.dxf.export_dxf_attribs( + tagwriter, + [ + "center", + "width", + "height", + "status", + "id", + ], + ) + tagwriter.write_tags(self.dxftags()) + + def dxftags(self) -> Tags: + def flag(flag): + return 1 if self.dxf.flags & flag else 0 + + dxf = self.dxf + tags = [ + DXFTag(1001, "ACAD"), + DXFTag(1000, "MVIEW"), + DXFTag(1002, "{"), + DXFTag(1070, 16), # extended data version, always 16 for R11/12 + DXFVertex(1010, dxf.view_target_point), + DXFVertex(1010, dxf.view_direction_vector), + DXFTag(1040, dxf.view_twist_angle), + DXFTag(1040, dxf.view_height), + DXFTag(1040, dxf.view_center_point[0]), + DXFTag( + 1040, + dxf.view_center_point[1], + ), + DXFTag(1040, dxf.perspective_lens_length), + DXFTag(1040, dxf.front_clip_plane_z_value), + DXFTag(1040, dxf.back_clip_plane_z_value), + DXFTag(1070, dxf.render_mode), + DXFTag(1070, dxf.circle_zoom), + DXFTag(1070, flag(const.VSF_FAST_ZOOM)), + DXFTag(1070, dxf.ucs_icon), + DXFTag(1070, flag(const.VSF_SNAP_MODE)), + DXFTag(1070, flag(const.VSF_GRID_MODE)), + DXFTag(1070, flag(const.VSF_ISOMETRIC_SNAP_STYLE)), + DXFTag(1070, 0), # snap isopair ??? + DXFTag(1040, dxf.snap_angle), + DXFTag(1040, dxf.snap_base_point[0]), + DXFTag(1040, dxf.snap_base_point[1]), + DXFTag(1040, dxf.snap_spacing[0]), + DXFTag(1040, dxf.snap_spacing[1]), + DXFTag(1040, dxf.grid_spacing[0]), + DXFTag(1040, dxf.grid_spacing[1]), + DXFTag(1070, flag(const.VSF_HIDE_PLOT_MODE)), + DXFTag(1002, "{"), # start frozen layer list + ] + tags.extend(DXFTag(1003, layer_name) for layer_name in self.frozen_layers) + tags.extend( + [ + DXFTag(1002, "}"), # end of frozen layer list + DXFTag(1002, "}"), # MVIEW + ] + ) + return Tags(tags) + + def register_resources(self, registry: xref.Registry) -> None: + assert self.doc is not None + super().register_resources(registry) + # The clipping path entity should not be added here! + registry.add_handle(self.dxf.get("ucs_handle")) + registry.add_handle(self.dxf.get("base_ucs_handle")) + registry.add_handle(self.dxf.get("visual_style_handle")) + registry.add_handle(self.dxf.get("background_handle")) + registry.add_handle(self.dxf.get("shade_plot_handle")) + registry.add_handle(self.dxf.get("sun_handle")) + + def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None: + assert isinstance(clone, Viewport) + super().map_resources(clone, mapping) + + mapping.map_existing_handle( + self, clone, "clipping_boundary_handle", optional=True + ) + mapping.map_existing_handle(self, clone, "ucs_handle", optional=True) + mapping.map_existing_handle(self, clone, "base_ucs_handle", optional=True) + mapping.map_existing_handle(self, clone, "visual_style_handle", optional=True) + mapping.map_existing_handle(self, clone, "sun_handle", optional=True) + # VIEWPORT entity is hard owner of the SUN object + clone.take_sun_ownership() + clone.frozen_layers = [mapping.get_layer(name) for name in self.frozen_layers] + + # I have no information to what entities the background- and the shade_plot + # handles are pointing to and I don't have any examples for that! + mapping.map_existing_handle(self, clone, "background_handle", optional=True) + mapping.map_existing_handle(self, clone, "shade_plot_handle", optional=True) + + # No information if these attributes really exist or any examples where these + # attributes are used. BricsCAD does not create these attributes when using + # viewport layer overrides: + for num in range(1, 5): + clone.dxf.discard(f"ref_vp_object_{num}") + + def take_sun_ownership(self) -> None: + assert self.doc is not None + sun = self.doc.entitydb.get(self.dxf.get("sun_handle")) + if sun: + sun.dxf.owner = self.dxf.handle + + def rename_frozen_layer(self, old_name: str, new_name: str) -> None: + assert self.doc is not None, "valid DXF document required" + key = self.doc.layers.key + old_key = key(old_name) + self.frozen_layers = [ + (name if key(name) != old_key else new_name) for name in self.frozen_layers + ] + + def clipping_rect_corners(self) -> list[Vec2]: + """Returns the default rectangular clipping path as list of + vertices. Use function :func:`ezdxf.path.make_path` to get also + non-rectangular shaped clipping paths if defined. + """ + center = self.dxf.center + cx = center.x + cy = center.y + width2 = self.dxf.width / 2 + height2 = self.dxf.height / 2 + return [ + Vec2(cx - width2, cy - height2), + Vec2(cx + width2, cy - height2), + Vec2(cx + width2, cy + height2), + Vec2(cx - width2, cy + height2), + ] + + def clipping_rect(self) -> tuple[Vec2, Vec2]: + """Returns the lower left and the upper right corner of the clipping + rectangle in paperspace coordinates. + """ + corners = self.clipping_rect_corners() + return corners[0], corners[2] + + @property + def has_extended_clipping_path(self) -> bool: + """Returns ``True`` if a non-rectangular clipping path is defined.""" + _flag = self.dxf.flags & const.VSF_NON_RECTANGULAR_CLIPPING + if _flag: + handle = self.dxf.clipping_boundary_handle + return handle != "0" + return False + + def get_scale(self) -> float: + """Returns the scaling factor from modelspace to viewport.""" + msp_height = self.dxf.view_height + if abs(msp_height) < 1e-12: + return 0.0 + vp_height = self.dxf.height + return vp_height / msp_height + + @property + def is_top_view(self) -> bool: + """Returns ``True`` if the viewport is a top view.""" + view_direction: Vec3 = self.dxf.view_direction_vector + return view_direction.is_null or view_direction.isclose(Z_AXIS) + + def get_view_center_point(self) -> Vec3: + # TODO: Is there a flag or attribute that determines which of these points is + # the center point? + center_point = Vec3(self.dxf.view_center_point) + if center_point.is_null: + center_point = Vec3(self.dxf.view_target_point) + return center_point + + def get_transformation_matrix(self) -> Matrix44: + """Returns the transformation matrix from modelspace to paperspace coordinates.""" + # supports only top-view viewports! + scale = self.get_scale() + rotation_angle: float = self.dxf.view_twist_angle + msp_center_point: Vec3 = self.get_view_center_point() + offset: Vec3 = self.dxf.center - (msp_center_point * scale) + m = Matrix44.scale(scale) + if rotation_angle: + m @= Matrix44.z_rotate(math.radians(rotation_angle)) + return m @ Matrix44.translate(offset.x, offset.y, 0) + + def get_aspect_ratio(self) -> float: + """Returns the aspect ratio of the viewport, return 0.0 if width or + height is zero. + """ + try: + return self.dxf.width / self.dxf.height + except ZeroDivisionError: + return 0.0 + + def get_modelspace_limits(self) -> tuple[float, float, float, float]: + """Returns the limits of the modelspace to view in drawing units + as tuple (min_x, min_y, max_x, max_y). + """ + msp_center_point: Vec3 = self.get_view_center_point() + msp_height: float = self.dxf.view_height + rotation_angle: float = self.dxf.view_twist_angle + ratio = self.get_aspect_ratio() + if ratio == 0.0: + raise ValueError("invalid viewport parameters width or height") + + w2 = msp_height * ratio * 0.5 + h2 = msp_height * 0.5 + if rotation_angle: + frame = Vec2.list(((-w2, -h2), (w2, -h2), (w2, h2), (-w2, h2))) + angle = math.radians(rotation_angle) + bbox = BoundingBox2d(v.rotate(angle) + msp_center_point for v in frame) + return bbox.extmin.x, bbox.extmin.y, bbox.extmax.x, bbox.extmax.y + else: + mx, my, _ = msp_center_point + return mx - w2, my - h2, mx + w2, my + h2 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/visualstyle.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/visualstyle.py new file mode 100644 index 0000000..07bf9df --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/visualstyle.py @@ -0,0 +1,235 @@ +# Copyright (c) 2019-2023, Manfred Moitzi +# License: MIT-License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from typing_extensions import Self +import copy +from ezdxf.lldxf import validator +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000, DXFStructureError +from ezdxf.lldxf.attributes import ( + DXFAttributes, + DefSubclass, + DXFAttr, + group_code_mapping, +) +from ezdxf.lldxf.tags import Tags +from .dxfentity import base_class, SubclassProcessor +from .dxfobj import DXFObject +from .factory import register_entity +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace, DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["VisualStyle"] + +acdb_visualstyle = DefSubclass( + "AcDbVisualStyle", + { + "description": DXFAttr(2), + # Style type: + # 0 = Flat + # 1 = FlatWithEdges + # 2 = Gouraud + # 3 = GouraudWithEdges + # 4 = 2dWireframe + # 5 = Wireframe + # 6 = Hidden + # 7 = Basic + # 8 = Realistic + # 9 = Conceptual + # 10 = Modeling + # 11 = Dim + # 12 = Brighten + # 13 = Thicken + # 14 = Linepattern + # 15 = Facepattern + # 16 = ColorChange + # 20 = JitterOff + # 21 = OverhangOff + # 22 = EdgeColorOff + # 23 = Shades of Gray + # 24 = Sketchy + # 25 = X-Ray + # 26 = Shaded with edges + # 27 = Shaded + "style_type": DXFAttr( + 70, validator=validator.is_in_integer_range(0, 28) + ), + # Face lighting type: + # 0 = Invisible + # 1 = Visible + # 2 = Phong + # 3 = Gooch + "face_lighting_model": DXFAttr( + 71, validator=validator.is_in_integer_range(0, 4) + ), + # Face lighting quality: + # 0 = No lighting + # 1 = Per face lighting + # 2 = Per vertex lighting + # 3 = Unknown + "face_lighting_quality": DXFAttr( + 72, validator=validator.is_in_integer_range(0, 4) + ), + # Face color mode: + # 0 = No color + # 1 = Object color + # 2 = Background color + # 3 = Custom color + # 4 = Mono color + # 5 = Tinted + # 6 = Desaturated + "face_color_mode": DXFAttr( + 73, validator=validator.is_in_integer_range(0, 6) + ), + # Face modifiers: + # 0 = No modifiers + # 1 = Opacity + # 2 = Specular + # 3 = Unknown + "face_modifiers": DXFAttr( + 90, validator=validator.is_in_integer_range(0, 4) + ), + "face_opacity_level": DXFAttr(40), + "face_specular_level": DXFAttr(41), + "color1": DXFAttr(62), + "color2": DXFAttr(63), + "face_style_mono_color": DXFAttr(421), + # Edge style model: + # 0 = No edges + # 1 = Isolines + # 2 = Facet edges + "edge_style_model": DXFAttr( + 74, validator=validator.is_in_integer_range(0, 3) + ), + "edge_style": DXFAttr(91), + "edge_intersection_color": DXFAttr(64), + "edge_obscured_color": DXFAttr(65), + "edge_obscured_linetype": DXFAttr(75), + "edge_intersection_linetype": DXFAttr(175), + "edge_crease_angle": DXFAttr(42), + "edge_modifiers": DXFAttr(92), + "edge_color": DXFAttr(66), + "edge_opacity_level": DXFAttr(43), + "edge_width": DXFAttr(76), + "edge_overhang": DXFAttr(77), + "edge_jitter": DXFAttr(78), + "edge_silhouette_color": DXFAttr(67), + "edge_silhouette_width": DXFAttr(79), + "edge_halo_gap": DXFAttr(170), + "edge_isoline_count": DXFAttr(171), + "edge_hide_precision": DXFAttr(290), # flag + "edge_style_apply": DXFAttr(174), # flag + "style_display_settings": DXFAttr(93), + "brightness": DXFAttr(44), + "shadow_type": DXFAttr(173), + "unknown1": DXFAttr(177), # required if xdata is present? + "internal_use_only_flag": DXFAttr( + 291 + ), # visual style only use internal + # Xdata must follow tag 291 (AutoCAD -> 'Xdata wasn't read' error) + # 70: Xdata count (count of tag groups) + # any code, value: multiple tags build a tag group + # 176, 1: end of group marker + # e.g. (291, 0) (70, 2) (62, 7) (420, 16777215) (176, 1) (90, 1) (176, 1) + }, +) +acdb_visualstyle_group_codes = group_code_mapping(acdb_visualstyle) + + +# undocumented Xdata in DXF R2018 +@register_entity +class VisualStyle(DXFObject): + """DXF VISUALSTYLE entity""" + + DXFTYPE = "VISUALSTYLE" + DXFATTRIBS = DXFAttributes(base_class, acdb_visualstyle) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 # official supported in R2007 + + def __init__(self): + super().__init__() + self.acad_xdata = None # to preserve AutoCAD xdata + + def copy_data(self, entity: Self, copy_strategy=default_copy) -> None: + """Copy acad internal data.""" + assert isinstance(entity, VisualStyle) + entity.acad_xdata = copy.deepcopy(self.acad_xdata) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + tags = processor.subclass_by_index(1) + if tags: + self.acad_xdata = self.store_acad_xdata(tags) + processor.fast_load_dxfattribs( + dxf, acdb_visualstyle_group_codes, subclass=tags + ) + else: + raise DXFStructureError( + f"missing 'AcDbVisualStyle' subclass in VISUALSTYLE(#{dxf.handle})" + ) + + return dxf + + @staticmethod + def store_acad_xdata(tags: Tags): + try: + index = tags.tag_index(291) + except IndexError: + return None + else: # store tags after 291 + index += 1 + xdata = tags[index:] + del tags[index:] # remove xdata from subclass + return xdata + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_visualstyle.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "description", + "style_type", + "face_lighting_model", + "face_lighting_quality", + "face_color_mode", + "face_modifiers", + "face_opacity_level", + "face_specular_level", + "color1", + "color2", + "face_style_mono_color", + "edge_style_model", + "edge_style", + "edge_intersection_color", + "edge_obscured_color", + "edge_obscured_linetype", + "edge_intersection_linetype", + "edge_crease_angle", + "edge_modifiers", + "edge_color", + "edge_opacity_level", + "edge_width", + "edge_overhang", + "edge_jitter", + "edge_silhouette_color", + "edge_silhouette_width", + "edge_halo_gap", + "edge_isoline_count", + "edge_hide_precision", + "edge_style_apply", + "style_display_settings", + "brightness", + "shadow_type", + "unknown1", + "internal_use_only_flag", + ], + ) + if self.acad_xdata: + tagwriter.write_tags(self.acad_xdata) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/vport.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/vport.py new file mode 100644 index 0000000..a7998e5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/vport.py @@ -0,0 +1,259 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import DXF12, SUBCLASS_MARKER, DXF2000, DXF2007 +from ezdxf.lldxf.validator import is_valid_vport_name +from ezdxf.math import Vec2, NULLVEC, Z_AXIS +from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity +from ezdxf.entities.layer import acdb_symbol_table_record +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["VPort"] +logger = logging.getLogger("ezdxf") + +acdb_vport = DefSubclass( + "AcDbViewportTableRecord", + { + "name": DXFAttr(2, validator=is_valid_vport_name), + "flags": DXFAttr(70, default=0), + "lower_left": DXFAttr(10, xtype=XType.point2d, default=Vec2(0, 0)), + "upper_right": DXFAttr(11, xtype=XType.point2d, default=Vec2(1, 1)), + "center": DXFAttr(12, xtype=XType.point2d, default=Vec2(0, 0)), + "snap_base": DXFAttr(13, xtype=XType.point2d, default=Vec2(0, 0)), + "snap_spacing": DXFAttr( + 14, xtype=XType.point2d, default=Vec2(0.5, 0.5) + ), + "grid_spacing": DXFAttr( + 15, xtype=XType.point2d, default=Vec2(0.5, 0.5) + ), + "direction": DXFAttr( + 16, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + "target": DXFAttr(17, xtype=XType.point3d, default=NULLVEC), + # height: DXF reference error: listed as group code 45 + "height": DXFAttr(40, default=1000), + "aspect_ratio": DXFAttr(41, default=1.34), + "focal_length": DXFAttr(42, default=50), + "front_clipping": DXFAttr(43, default=0), + "back_clipping": DXFAttr(44, default=0), + "snap_rotation": DXFAttr(50, default=0), + "view_twist": DXFAttr(51, default=0), + "view_mode": DXFAttr(71, default=0), + "circle_sides": DXFAttr(72, default=1000), + "fast_zoom": DXFAttr(73, default=1), # removed in R2007 + # ucs_icon: + # bit 0: 0=hide, 1=show + # bit 1: 0=display in lower left corner, 1=display at origin + "ucs_icon": DXFAttr(74, default=3), # show at origin + "snap_on": DXFAttr(75, default=0), # removed in R2007 + "grid_on": DXFAttr(76, default=0), # removed in R2007 + "snap_style": DXFAttr(77, default=0), # removed in R2007 + "snap_isopair": DXFAttr(78, default=0), # removed in R2007 + # R2000: 331 or 441 (optional) - ignored by ezdxf + # Soft or hard-pointer ID/handle to frozen layer objects; + # repeats for each frozen layers + # 70: Bit flags and perspective mode + # CTB-File? + "plot_style_sheet": DXFAttr(1, dxfversion=DXF2007), + # Render mode: + # 0 = 2D Optimized (classic 2D) + # 1 = Wireframe + # 2 = Hidden line + # 3 = Flat shaded + # 4 = Gouraud shaded + # 5 = Flat shaded with wireframe + # 6 = Gouraud shaded with wireframe + # All rendering modes other than 2D Optimized engage the new 3D graphics + # pipeline. These values directly correspond to the SHADEMODE command and + # the AcDbAbstractViewTableRecord::RenderMode enum + "render_mode": DXFAttr( + 281, + default=0, + dxfversion=DXF2000, + validator=validator.is_in_integer_range(0, 7), + fixer=RETURN_DEFAULT, + ), + # Value of UCSVP for this viewport. If set to 1, then viewport stores its + # own UCS which will become the current UCS whenever the viewport is + # activated. If set to 0, UCS will not change when this viewport is + # activated + "ucs_vp": DXFAttr( + 65, + dxfversion=DXF2000, + default=0, + validator=validator.is_integer_bool, + fixer=RETURN_DEFAULT, + ), + "ucs_origin": DXFAttr(110, xtype=XType.point3d, dxfversion=DXF2000), + "ucs_xaxis": DXFAttr( + 111, + xtype=XType.point3d, + dxfversion=DXF2000, + validator=validator.is_not_null_vector, + ), + "ucs_yaxis": DXFAttr( + 112, + xtype=XType.point3d, + dxfversion=DXF2000, + validator=validator.is_not_null_vector, + ), + # Handle of AcDbUCSTableRecord if UCS is a named UCS. If not present, + # then UCS is unnamed: + "ucs_handle": DXFAttr(345, dxfversion=DXF2000), + # Handle of AcDbUCSTableRecord of base UCS if UCS is orthographic (79 code + # is non-zero). If not present and 79 code is non-zero, then base UCS is + # taken to be WORLD: + "base_ucs_handle": DXFAttr(346, dxfversion=DXF2000), + # UCS ortho type: + # 0 = UCS is not orthographic + # 1 = Top + # 2 = Bottom + # 3 = Front + # 4 = Back + # 5 = Left + # 6 = Right + "ucs_ortho_type": DXFAttr( + 79, + dxfversion=DXF2000, + validator=validator.is_in_integer_range(0, 7), + ), + "elevation": DXFAttr(146, dxfversion=DXF2000, default=0), + "unknown1": DXFAttr(60, dxfversion=DXF2000), + "shade_plot_setting": DXFAttr(170, dxfversion=DXF2007), + "major_grid_lines": DXFAttr(61, dxfversion=DXF2007), + # Handle to background object + "background_handle": DXFAttr(332, dxfversion=DXF2007, optional=True), + # Handle to shade plot object + "shade_plot_handle": DXFAttr(333, dxfversion=DXF2007, optional=True), + # Handle to visual style object + "visual_style_handle": DXFAttr(348, dxfversion=DXF2007, optional=True), + "default_lighting_on": DXFAttr( + 292, + dxfversion=DXF2007, + validator=validator.is_integer_bool, + ), + # Default lighting type: + # 0 = One distant light + # 1 = Two distant lights + "default_lighting_type": DXFAttr( + 282, + dxfversion=DXF2007, + validator=validator.is_integer_bool, + ), + "brightness": DXFAttr(141, dxfversion=DXF2000), + "contrast": DXFAttr(142, dxfversion=DXF2000), + "ambient_color_aci": DXFAttr(63, dxfversion=DXF2000, optional=True), + "ambient_true_color": DXFAttr(421, dxfversion=DXF2000, optional=True), + "ambient_color_name": DXFAttr(431, dxfversion=DXF2000, optional=True), + # Hard-pointer handle to sun object: + "sun_handle": DXFAttr(361, dxfversion=DXF2007, optional=True), + }, +) +acdb_vport_group_codes = group_code_mapping(acdb_vport) + + +@register_entity +class VPort(DXFEntity): + """DXF VIEW entity""" + + DXFTYPE = "VPORT" + DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_vport) + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_vport_group_codes, subclass=2 + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + super().export_entity(tagwriter) + dxfversion = tagwriter.dxfversion + if dxfversion > DXF12: + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name) + tagwriter.write_tag2(SUBCLASS_MARKER, acdb_vport.name) + self.dxf.export_dxf_attribs( + tagwriter, + [ + "name", + "flags", + "lower_left", + "upper_right", + "center", + "snap_base", + "snap_spacing", + "grid_spacing", + "direction", + "target", + "height", + "aspect_ratio", + "focal_length", + "front_clipping", + "back_clipping", + "snap_rotation", + "view_twist", + "view_mode", + "circle_sides", + "fast_zoom", + "ucs_icon", + "snap_on", + "grid_on", + "snap_style", + "snap_isopair", + "plot_style_sheet", + "render_mode", + "ucs_vp", + "ucs_origin", + "ucs_xaxis", + "ucs_yaxis", + "ucs_handle", + "base_ucs_handle", + "ucs_ortho_type", + "elevation", + "unknown1", + "shade_plot_setting", + "major_grid_lines", + "background_handle", + "shade_plot_handle", + "visual_style_handle", + "default_lighting_on", + "default_lighting_type", + "brightness", + "contrast", + "ambient_color_aci", + "ambient_true_color", + "ambient_color_name", + ], + ) + + def reset_wcs(self) -> None: + """Reset coordinate system to the :ref:`WCS`.""" + self.dxf.ucs_vp = 1 + self.dxf.ucs_origin = (0, 0, 0) + self.dxf.ucs_xaxis = (1, 0, 0) + self.dxf.ucs_yaxis = (0, 1, 0) + self.dxf.ucs_ortho_type = 0 + self.dxf.discard("ucs_handle") + self.dxf.discard("base_ucs_handle") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/xdata.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/xdata.py new file mode 100644 index 0000000..d2fe7d4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/xdata.py @@ -0,0 +1,531 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Any, + MutableSequence, + MutableMapping, + Iterator, + Union, + Optional, +) +from contextlib import contextmanager +import logging + +from ezdxf.math import Vec3, Matrix44 +from ezdxf.lldxf.types import dxftag, VALID_XDATA_GROUP_CODES, DXFTag +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.const import XDATA_MARKER, DXFValueError, DXFTypeError +from ezdxf.lldxf.tags import ( + xdata_list, + remove_named_list_from_xdata, + get_named_list_from_xdata, + NotFoundException, +) +from ezdxf.tools import take2 +from ezdxf import options +from ezdxf.lldxf.repair import filter_invalid_xdata_group_codes + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["XData", "XDataUserList", "XDataUserDict"] +logger = logging.getLogger("ezdxf") + + +def has_valid_xdata_group_codes(tags: Tags) -> bool: + return all(tag.code in VALID_XDATA_GROUP_CODES for tag in tags) + + +class XData: + def __init__(self, xdata: Optional[Iterable[Tags]] = None): + self.data: dict[str, Tags] = dict() + if xdata is not None: + for data in xdata: + self._add(data) + + @classmethod + def safe_init(cls, xdata: Iterable[Tags]): + return cls( + [Tags(filter_invalid_xdata_group_codes(tags)) for tags in xdata] + ) + + def __len__(self): + return len(self.data) + + def __contains__(self, appid: str) -> bool: + """Returns ``True`` if DXF tags for `appid` exist.""" + return appid in self.data + + def update_keys(self): + """Update APPID keys. (internal API)""" + self.data = {tags[0].value: tags for tags in self.data.values()} + + def _add(self, tags: Tags) -> None: + tags = Tags(tags) + if len(tags): + appid = tags[0].value + if appid in self.data: + logger.info(f"Duplicate XDATA appid {appid} in one entity") + if has_valid_xdata_group_codes(tags): + self.data[appid] = tags + else: + raise DXFValueError(f"found invalid XDATA group code in {tags}") + + def add( + self, appid: str, tags: Iterable[Union[tuple[int, Any], DXFTag]] + ) -> None: + """Add a list of DXF tags for `appid`. The `tags` argument is an + iterable of (group code, value) tuples, where the group code has to be + an integer value. The mandatory XDATA marker (1001, appid) is added + automatically if front of the tags if missing. + + Each entity can contain only one list of tags for each `appid`. + Adding a second list of tags for the same `appid` replaces the + existing list of tags. + + The valid XDATA group codes are restricted to some specific values in + the range from 1000 to 1071, for more information see also the + internals about :ref:`xdata_internals`. + + """ + data = Tags(dxftag(code, value) for code, value in tags) + if len(data) == 0 or data[0] != (XDATA_MARKER, appid): + data.insert(0, dxftag(XDATA_MARKER, appid)) + self._add(data) + + def get(self, appid: str) -> Tags: + """Returns the DXF tags as :class:`~ezdxf.lldxf.tags.Tags` list + stored by `appid`. + + Raises: + DXFValueError: no data for `appid` exist + + """ + if appid in self.data: + return self.data[appid] + else: + raise DXFValueError(appid) + + def discard(self, appid): + """Delete DXF tags for `appid`. None existing appids are silently + ignored. + """ + if appid in self.data: + del self.data[appid] + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + for appid, tags in self.data.items(): + if options.filter_invalid_xdata_group_codes: + tags = Tags(filter_invalid_xdata_group_codes(tags)) + tagwriter.write_tags(tags) + + def has_xlist(self, appid: str, name: str) -> bool: + """Returns ``True`` if list `name` from XDATA `appid` exists. + + Args: + appid: APPID + name: list name + + """ + try: + self.get_xlist(appid, name) + except DXFValueError: + return False + else: + return True + + def get_xlist(self, appid: str, name: str) -> list[tuple]: + """Get list `name` from XDATA `appid`. + + Args: + appid: APPID + name: list name + + Returns: list of DXFTags including list name and curly braces '{' '}' tags + + Raises: + DXFKeyError: XDATA `appid` does not exist + DXFValueError: list `name` does not exist + + """ + xdata = self.get(appid) + try: + return get_named_list_from_xdata(name, xdata) + except NotFoundException: + raise DXFValueError( + f'No data list "{name}" not found for APPID "{appid}"' + ) + + def set_xlist(self, appid: str, name: str, tags: Iterable) -> None: + """Create new list `name` of XDATA `appid` with `xdata_tags` and + replaces list `name` if already exists. + + Args: + appid: APPID + name: list name + tags: list content as DXFTags or (code, value) tuples, list name and + curly braces '{' '}' tags will be added + """ + if appid not in self.data: + data = [(XDATA_MARKER, appid)] + data.extend(xdata_list(name, tags)) + self.add(appid, data) + else: + self.replace_xlist(appid, name, tags) + + def discard_xlist(self, appid: str, name: str) -> None: + """Deletes list `name` from XDATA `appid`. Ignores silently if XDATA + `appid` or list `name` not exist. + + Args: + appid: APPID + name: list name + + """ + try: + xdata = self.get(appid) + except DXFValueError: + pass + else: + try: + tags = remove_named_list_from_xdata(name, xdata) + except NotFoundException: + pass + else: + self.add(appid, tags) + + def replace_xlist(self, appid: str, name: str, tags: Iterable) -> None: + """Replaces list `name` of existing XDATA `appid` by `tags`. Appends + new list if list `name` do not exist, but raises `DXFValueError` if + XDATA `appid` do not exist. + + Low level interface, if not sure use `set_xdata_list()` instead. + + Args: + appid: APPID + name: list name + tags: list content as DXFTags or (code, value) tuples, list name and + curly braces '{' '}' tags will be added + Raises: + DXFValueError: XDATA `appid` do not exist + + """ + xdata = self.get(appid) + try: + data = remove_named_list_from_xdata(name, xdata) + except NotFoundException: + data = xdata + xlist = xdata_list(name, tags) + data.extend(xlist) + self.add(appid, data) + + def transform(self, m: Matrix44) -> None: + """Transform XDATA tags with group codes 1011, 1012, 1013, 1041 and + 1042 inplace. For more information see :ref:`xdata_internals` Internals. + + """ + transformed_data = dict() + for key, tags in self.data.items(): + transformed_data[key] = Tags(transform_xdata_tags(tags, m)) + self.data = transformed_data + + +def transform_xdata_tags(tags: Tags, m: Matrix44) -> Iterator[DXFTag]: + for tag in tags: + code, value = tag + if code == 1011: + # move, scale, rotate and mirror + yield dxftag(code, m.transform(Vec3(value))) + elif code == 1012: + # scale, rotate and mirror + yield dxftag(code, m.transform_direction(Vec3(value))) + elif code == 1013: + # rotate and mirror + vec = Vec3(value) + length = vec.magnitude + if length > 1e-12: + vec = m.transform_direction(vec).normalize(length) + yield dxftag(code, vec) + else: + yield tag + elif code == 1041 or code == 1042: + # scale distance and factor, works only for uniform scaling + vec = m.transform_direction(Vec3(value, 0, 0)) + yield dxftag(code, vec.magnitude) + else: + yield tag + + +class XDataUserList(MutableSequence): + """Manage named XDATA lists as a list-like object. + + Stores just a few data types with fixed group codes: + + 1000 str + 1010 Vec3 + 1040 float + 1071 32bit int + + """ + + converter = { + 1000: str, + 1010: Vec3, + 1040: float, + 1071: int, + } + group_codes = { + str: 1000, + Vec3: 1010, + float: 1040, + int: 1071, + } + + def __init__( + self, xdata: Optional[XData] = None, name="DefaultList", appid="EZDXF" + ): + """Setup a XDATA user list `name` for the given `appid`. + + The data is stored in the given `xdata` object, or in a new created + :class:`XData` instance if ``None``. + Changes of the content has to be committed at the end to be stored in + the underlying `xdata` object. + + Args: + xdata (XData): underlying :class:`XData` instance, if ``None`` a + new one will be created + name (str): name of the user list + appid (str): application specific AppID + + """ + if xdata is None: + xdata = XData() + self.xdata = xdata + self._appid = str(appid) + self._name = str(name) + try: + data = xdata.get_xlist(self._appid, self._name) + except DXFValueError: + data = [] + self._data: list = self._parse_list(data) + + @classmethod + @contextmanager + def entity( + cls, entity: DXFEntity, name="DefaultList", appid="EZDXF" + ) -> Iterator[XDataUserList]: + """Context manager to manage a XDATA list `name` for a given DXF + `entity`. Appends the user list to the existing :class:`XData` instance + or creates new :class:`XData` instance. + + Args: + entity (DXFEntity): target DXF entity for the XDATA + name (str): name of the user list + appid (str): application specific AppID + + """ + xdata = entity.xdata + if xdata is None: + xdata = XData() + entity.xdata = xdata + xlist = cls(xdata, name, appid) + yield xlist + xlist.commit() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.commit() + + def __str__(self): + """Return str(self).""" + return str(self._data) + + def insert(self, index: int, value) -> None: + self._data.insert(index, value) + + def __getitem__(self, item): + """Get self[item].""" + return self._data[item] + + def __setitem__(self, item, value): + """Set self[item] to value.""" + self._data.__setitem__(item, value) + + def __delitem__(self, item): + """Delete self[item].""" + self._data.__delitem__(item) + + def _parse_list(self, tags: Iterable[tuple]) -> list: + data = list(tags) + content = [] + for code, value in data[2:-1]: + factory = self.converter.get(code) + if factory: + content.append(factory(value)) + else: + raise DXFValueError(f"unsupported group code: {code}") + return content + + def __len__(self) -> int: + """Returns len(self).""" + return len(self._data) + + def commit(self) -> None: + """Store all changes to the underlying :class:`XData` instance. + This call is not required if using the :meth:`entity` context manager. + + Raises: + DXFValueError: invalid chars ``"\\n"`` or ``"\\r"`` in a string + DXFTypeError: invalid data type + + """ + data = [] + for value in self._data: + if isinstance(value, str): + if len(value) > 255: # XDATA limit for group code 1000 + raise DXFValueError("string too long, max. 255 characters") + if "\n" in value or "\r" in value: + raise DXFValueError( + "found invalid line break '\\n' or '\\r'" + ) + code = self.group_codes.get(type(value)) + if code: + data.append(dxftag(code, value)) + else: + raise DXFTypeError(f"invalid type: {type(value)}") + self.xdata.set_xlist(self._appid, self._name, data) + + +class XDataUserDict(MutableMapping): + """Manage named XDATA lists as a dict-like object. + + Uses XDataUserList to store key, value pairs in XDATA. + + This class does not create the required AppID table entry, only the + default AppID "EZDXF" exist by default. + + Implements the :class:`MutableMapping` interface. + + """ + + def __init__( + self, xdata: Optional[XData] = None, name="DefaultDict", appid="EZDXF" + ): + """Setup a XDATA user dict `name` for the given `appid`. + + The data is stored in the given `xdata` object, or in a new created + :class:`XData` instance if ``None``. + Changes of the content has to be committed at the end to be stored in + the underlying `xdata` object. + + Args: + xdata (XData): underlying :class:`XData` instance, if ``None`` a + new one will be created + name (str): name of the user list + appid (str): application specific AppID + + """ + self._xlist = XDataUserList(xdata, name, appid) + self._user_dict: dict[str, Any] = self._parse_xlist() + + def _parse_xlist(self) -> dict: + if self._xlist: + return dict(take2(self._xlist)) + else: + return dict() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.commit() + + def __str__(self): + """Return str(self).""" + return str(self._user_dict) + + @classmethod + @contextmanager + def entity( + cls, entity: DXFEntity, name="DefaultDict", appid="EZDXF" + ) -> Iterator[XDataUserDict]: + """Context manager to manage a XDATA dict `name` for a given DXF + `entity`. Appends the user dict to the existing :class:`XData` instance + or creates new :class:`XData` instance. + + Args: + entity (DXFEntity): target DXF entity for the XDATA + name (str): name of the user list + appid (str): application specific AppID + + """ + xdata = entity.xdata + if xdata is None: + xdata = XData() + entity.xdata = xdata + xdict = cls(xdata, name, appid) + yield xdict + xdict.commit() + + @property + def xdata(self): + return self._xlist.xdata + + def __len__(self): + """Returns len(self).""" + return len(self._user_dict) + + def __getitem__(self, key): + """Get self[key].""" + return self._user_dict[key] + + def __setitem__(self, key, item): + """Set self[key] to value, key has to be a string. + + Raises: + DXFTypeError: key is not a string + + """ + if not isinstance(key, str): + raise DXFTypeError("key is not a string") + self._user_dict[key] = item + + def __delitem__(self, key): + """Delete self[key].""" + del self._user_dict[key] + + def __iter__(self): + """Implement iter(self).""" + return iter(self._user_dict) + + def discard(self, key): + """Delete self[key], without raising a :class:`KeyError` if `key` does + not exist. + + """ + try: + del self._user_dict[key] + except KeyError: + pass + + def commit(self) -> None: + """Store all changes to the underlying :class:`XData` instance. + This call is not required if using the :meth:`entity` context manager. + + Raises: + DXFValueError: invalid chars ``"\\n"`` or ``"\\r"`` in a string + DXFTypeError: invalid data type + + """ + xlist = self._xlist + xlist.clear() + for key, value in self._user_dict.items(): + xlist.append(key) + xlist.append(value) + xlist.commit() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/xdict.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/xdict.py new file mode 100644 index 0000000..a7b8dae --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/xdict.py @@ -0,0 +1,241 @@ +# Copyright (c) 2019-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Union, Optional +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.const import DXFStructureError +from ezdxf.lldxf.const import ( + ACAD_XDICTIONARY, + XDICT_HANDLE_CODE, + APP_DATA_MARKER, +) +from .copy import default_copy + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import ( + Dictionary, + DXFEntity, + DXFObject, + Placeholder, + DictionaryVar, + XRecord, + ) + +__all__ = ["ExtensionDict"] + + +# Example for table head and -entries with extension dicts: +# AutodeskSamples\lineweights.dxf + + +class ExtensionDict: + """Stores extended data of entities in app data 'ACAD_XDICTIONARY', app + data contains just one entry to a hard-owned DICTIONARY objects, which is + not shared with other entities, each entity copy has its own extension + dictionary and the extension dictionary is destroyed when the owner entity + is deleted from database. + + """ + + __slots__ = ("_xdict",) + + def __init__(self, xdict: Union[str, Dictionary]): + # 1st loading stage: xdict as string -> handle to dict + # 2nd loading stage: xdict as DXF Dictionary + self._xdict = xdict + + @property + def dictionary(self) -> Dictionary: + """Returns the underlying :class:`~ezdxf.entities.Dictionary` object.""" + xdict = self._xdict + assert xdict is not None, "destroyed extension dictionary" + assert not isinstance(xdict, str), f"dictionary handle #{xdict} not resolved" + return xdict + + @property + def handle(self) -> str: + """Returns the handle of the underlying :class:`~ezdxf.entities.Dictionary` + object. + """ + return self.dictionary.dxf.handle + + def __getitem__(self, key: str): + """Get self[key].""" + return self.dictionary[key] + + def __setitem__(self, key: str, value): + """Set self[key] to value. + + Only DXF objects stored in the OBJECTS section are allowed as content + of the extension dictionary. DXF entities stored in layouts are not + allowed. + + Raises: + DXFTypeError: invalid DXF type + + """ + self.dictionary[key] = value + + def __delitem__(self, key: str): + """Delete self[key], destroys referenced entity.""" + del self.dictionary[key] + + def __contains__(self, key: str): + """Return `key` in self.""" + return key in self.dictionary + + def __len__(self): + """Returns count of extension dictionary entries.""" + return len(self.dictionary) + + def keys(self): + """Returns a :class:`KeysView` of all extension dictionary keys.""" + return self.dictionary.keys() + + def items(self): + """Returns an :class:`ItemsView` for all extension dictionary entries as + (key, entity) pairs. An entity can be a handle string if the entity + does not exist. + """ + return self.dictionary.items() + + def get(self, key: str, default=None) -> Optional[DXFEntity]: + """Return extension dictionary entry `key`.""" + return self.dictionary.get(key, default) + + def discard(self, key: str) -> None: + """Discard extension dictionary entry `key`.""" + return self.dictionary.discard(key) + + @classmethod + def new(cls, owner_handle: str, doc: Drawing): + xdict = doc.objects.add_dictionary( + owner=owner_handle, + # All data in the extension dictionary belongs only to the owner + hard_owned=True, + ) + return cls(xdict) + + def copy(self, copy_strategy=default_copy) -> ExtensionDict: + """Deep copy of the extension dictionary all entries are virtual + entities. + """ + new_xdict = copy_strategy.copy(self.dictionary) + return ExtensionDict(new_xdict) + + @property + def is_alive(self): + """Returns ``True`` if the underlying :class:`~ezdxf.entities.Dictionary` + object is not deleted. + """ + # Can not check if _xdict (as handle or Dictionary) really exist: + return self._xdict is not None + + @property + def has_valid_dictionary(self): + """Returns ``True`` if the underlying :class:`~ezdxf.entities.Dictionary` + really exist and is valid. + """ + xdict = self._xdict + if xdict is None or isinstance(xdict, str): + return False + return xdict.is_alive + + def update_owner(self, handle: str) -> None: + """Update owner tag of underlying :class:`~ezdxf.entities.Dictionary` + object. + + Internal API. + """ + assert self.is_alive, "destroyed extension dictionary" + self.dictionary.dxf.owner = handle + + @classmethod + def from_tags(cls, tags: Tags): + assert tags is not None + # Expected DXF structure: + # [(102, '{ACAD_XDICTIONARY', (360, handle), (102, '}')] + if len(tags) != 3 or tags[1].code != XDICT_HANDLE_CODE: + raise DXFStructureError("ACAD_XDICTIONARY error.") + return cls(tags[1].value) + + def load_resources(self, doc: Drawing) -> None: + handle = self._xdict + assert isinstance(handle, str) + self._xdict = doc.entitydb.get(handle) # type: ignore + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + assert self._xdict is not None + xdict = self._xdict + handle = xdict if isinstance(xdict, str) else xdict.dxf.handle + tagwriter.write_tag2(APP_DATA_MARKER, ACAD_XDICTIONARY) + tagwriter.write_tag2(XDICT_HANDLE_CODE, handle) + tagwriter.write_tag2(APP_DATA_MARKER, "}") + + def destroy(self): + """Destroy the underlying :class:`~ezdxf.entities.Dictionary` object.""" + if self.has_valid_dictionary: + self._xdict.destroy() + self._xdict = None + + def add_dictionary(self, name: str, hard_owned: bool = True) -> Dictionary: + """Create a new :class:`~ezdxf.entities.Dictionary` object as + extension dictionary entry `name`. + """ + dictionary = self.dictionary + doc = dictionary.doc + assert doc is not None, "valid DXF document required" + new_dict = doc.objects.add_dictionary( + owner=dictionary.dxf.handle, + hard_owned=hard_owned, + ) + dictionary[name] = new_dict + return new_dict + + def add_xrecord(self, name: str) -> XRecord: + """Create a new :class:`~ezdxf.entities.XRecord` object as + extension dictionary entry `name`. + """ + dictionary = self.dictionary + doc = dictionary.doc + assert doc is not None, "valid DXF document required" + xrecord = doc.objects.add_xrecord(dictionary.dxf.handle) + dictionary[name] = xrecord + return xrecord + + def add_dictionary_var(self, name: str, value: str) -> DictionaryVar: + """Create a new :class:`~ezdxf.entities.DictionaryVar` object as + extension dictionary entry `name`. + """ + dictionary = self.dictionary + doc = dictionary.doc + assert doc is not None, "valid DXF document required" + dict_var = doc.objects.add_dictionary_var(dictionary.dxf.handle, value) + dictionary[name] = dict_var + return dict_var + + def add_placeholder(self, name: str) -> Placeholder: + """Create a new :class:`~ezdxf.entities.Placeholder` object as + extension dictionary entry `name`. + """ + dictionary = self.dictionary + doc = dictionary.doc + assert doc is not None, "valid DXF document required" + placeholder = doc.objects.add_placeholder(dictionary.dxf.handle) + dictionary[name] = placeholder + return placeholder + + def link_dxf_object(self, name: str, obj: DXFObject) -> None: + """Link `obj` to the extension dictionary as entry `name`. + + Linked objects are owned by the extensions dictionary and therefore + cannot be a graphical entity, which have to be owned by a + :class:`~ezdxf.layouts.BaseLayout`. + + Raises: + DXFTypeError: `obj` has invalid DXF type + + """ + self.dictionary.link_dxf_object(name, obj) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entities/xline.py b/.venv/lib/python3.12/site-packages/ezdxf/entities/xline.py new file mode 100644 index 0000000..ef80803 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entities/xline.py @@ -0,0 +1,95 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf import validator +from ezdxf.lldxf.attributes import ( + DXFAttr, + DXFAttributes, + DefSubclass, + XType, + RETURN_DEFAULT, + group_code_mapping, +) +from ezdxf.lldxf.const import SUBCLASS_MARKER, DXF2000 +from ezdxf.math import Vec3, Matrix44, NULLVEC, Z_AXIS +from .dxfentity import base_class, SubclassProcessor +from .dxfgfx import DXFGraphic, acdb_entity +from .factory import register_entity + +if TYPE_CHECKING: + from ezdxf.entities import DXFNamespace + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +__all__ = ["Ray", "XLine"] + +acdb_xline = DefSubclass( + "AcDbXline", + { + "start": DXFAttr(10, xtype=XType.point3d, default=NULLVEC), + "unit_vector": DXFAttr( + 11, + xtype=XType.point3d, + default=Z_AXIS, + validator=validator.is_not_null_vector, + fixer=RETURN_DEFAULT, + ), + }, +) +acdb_xline_group_codes = group_code_mapping(acdb_xline) + + +@register_entity +class XLine(DXFGraphic): + """DXF XLINE entity""" + + DXFTYPE = "XLINE" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_xline) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + XLINE_SUBCLASS = "AcDbXline" + + def load_dxf_attribs( + self, processor: Optional[SubclassProcessor] = None + ) -> DXFNamespace: + dxf = super().load_dxf_attribs(processor) + if processor: + processor.fast_load_dxfattribs( + dxf, acdb_xline_group_codes, subclass=2, recover=True + ) + return dxf + + def export_entity(self, tagwriter: AbstractTagWriter) -> None: + """Export entity specific data as DXF tags.""" + super().export_entity(tagwriter) + tagwriter.write_tag2(SUBCLASS_MARKER, self.XLINE_SUBCLASS) + self.dxf.export_dxf_attribs(tagwriter, ["start", "unit_vector"]) + + def transform(self, m: Matrix44) -> XLine: + """Transform the XLINE/RAY entity by transformation matrix `m` inplace.""" + self.dxf.start = m.transform(self.dxf.start) + self.dxf.unit_vector = m.transform_direction( + self.dxf.unit_vector + ).normalize() + self.post_transform(m) + return self + + def translate(self, dx: float, dy: float, dz: float) -> XLine: + """Optimized XLINE/RAY translation about `dx` in x-axis, `dy` in + y-axis and `dz` in z-axis. + + """ + self.dxf.start = Vec3(dx, dy, dz) + self.dxf.start + # Avoid Matrix44 instantiation if not required: + if self.is_post_transform_required: + self.post_transform(Matrix44.translate(dx, dy, dz)) + return self + + +@register_entity +class Ray(XLine): + """DXF Ray entity""" + + DXFTYPE = "RAY" + DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_xline) + MIN_DXF_VERSION_FOR_EXPORT = DXF2000 + XLINE_SUBCLASS = "AcDbRay" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/entitydb.py b/.venv/lib/python3.12/site-packages/ezdxf/entitydb.py new file mode 100644 index 0000000..168d29a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/entitydb.py @@ -0,0 +1,432 @@ +# Copyright (c) 2019-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Optional, + Iterable, + TYPE_CHECKING, + Iterator, +) +from contextlib import contextmanager +from ezdxf.tools.handle import HandleGenerator +from ezdxf.lldxf.types import is_valid_handle +from ezdxf.entities.dxfentity import DXFEntity +from ezdxf.entities.dxfobj import DXFObject +from ezdxf.audit import AuditError, Auditor +from ezdxf.lldxf.const import DXFInternalEzdxfError +from ezdxf.entities import factory +from ezdxf.query import EntityQuery +from ezdxf.entities.copy import default_copy + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +DATABASE_EXCLUDE = { + "SECTION", + "ENDSEC", + "EOF", + "TABLE", + "ENDTAB", + "CLASS", + "ACDSRECORD", + "ACDSSCHEMA", +} + + +class EntityDB: + """A simple key/entity database. + + Every entity/object, except tables and sections, are represented as + DXFEntity or inherited types, these entities are stored in the + DXF document database, database-key is the `handle` as string. + + """ + + class Trashcan: + """Store handles to entities which should be deleted later.""" + + def __init__(self, db: EntityDB): + self._database = db._database + self._handles: set[str] = set() + + def add(self, handle: str): + """Put handle into trashcan to delete the entity later, this is + required for deleting entities while iterating the database. + """ + self._handles.add(handle) + + def clear(self): + """Remove handles in trashcan from database and destroy entities if + still alive. + """ + db = self._database + for handle in self._handles: + entity = db.get(handle) + if entity and entity.is_alive: + entity.destroy() + + if handle in db: + del db[handle] + + self._handles.clear() + + def __init__(self) -> None: + self._database: dict[str, DXFEntity] = {} + # DXF handles of entities to delete later: + self.handles = HandleGenerator() + self.locked: bool = False # used only for debugging + + def __getitem__(self, handle: str) -> DXFEntity: + """Get entity by `handle`, does not filter destroyed entities nor + entities in the trashcan. + """ + return self._database[handle] + + def __setitem__(self, handle: str, entity: DXFEntity) -> None: + """Set `entity` for `handle`.""" + assert isinstance(handle, str), type(handle) + assert isinstance(entity, DXFEntity), type(entity) + assert entity.is_alive, "Can not store destroyed entity." + if self.locked: + raise DXFInternalEzdxfError("Locked entity database.") + + if handle == "0" or not is_valid_handle(handle): + raise ValueError(f"Invalid handle {handle}.") + self._database[handle] = entity + + def __delitem__(self, handle: str) -> None: + """Delete entity by `handle`. Removes entity only from database, does + not destroy the entity. + """ + if self.locked: + raise DXFInternalEzdxfError("Locked entity database.") + del self._database[handle] + + def __contains__(self, handle: str) -> bool: + """``True`` if database contains `handle`.""" + if handle is None: + return False + assert isinstance(handle, str), type(handle) + return handle in self._database + + def __len__(self) -> int: + """Count of database items.""" + return len(self._database) + + def __iter__(self) -> Iterator[str]: + """Iterable of all handles, does filter destroyed entities but not + entities in the trashcan. + """ + return self.keys() # type: ignore + + def get(self, handle: str) -> Optional[DXFEntity]: + """Returns entity for `handle` or ``None`` if no entry exist, does + not filter destroyed entities. + """ + return self._database.get(handle) + + def next_handle(self) -> str: + """Returns next unique handle.""" + while True: + handle = self.handles.next() + if handle not in self._database: + return handle + + def keys(self) -> Iterable[str]: + """Iterable of all handles, does filter destroyed entities.""" + return (handle for handle, entity in self.items()) + + def values(self) -> Iterable[DXFEntity]: + """Iterable of all entities, does filter destroyed entities.""" + return (entity for handle, entity in self.items()) + + def items(self) -> Iterable[tuple[str, DXFEntity]]: + """Iterable of all (handle, entities) pairs, does filter destroyed + entities. + """ + return ( + (handle, entity) + for handle, entity in self._database.items() + if entity.is_alive + ) + + def add(self, entity: DXFEntity) -> None: + """Add `entity` to database, assigns a new handle to the `entity` + if :attr:`entity.dxf.handle` is ``None``. Adding the same entity + multiple times is possible and creates only a single database entry. + + """ + if entity.dxftype() in DATABASE_EXCLUDE: + if entity.dxf.handle is not None: + # Mark existing entity handle as used to avoid + # reassigning the same handle again. + self[entity.dxf.handle] = entity + return + handle: str = entity.dxf.handle + if handle is None: + handle = self.next_handle() + entity.update_handle(handle) + self[handle] = entity + + # Add sub entities ATTRIB, VERTEX and SEQEND to database: + # Add linked MTEXT columns to database: + if hasattr(entity, "add_sub_entities_to_entitydb"): + entity.add_sub_entities_to_entitydb(self) + + def delete_entity(self, entity: DXFEntity) -> None: + """Remove `entity` from database and destroy the `entity`.""" + if entity.is_alive: + del self[entity.dxf.handle] + entity.destroy() + + def discard(self, entity: DXFEntity) -> None: + """Discard `entity` from database without destroying the `entity`.""" + if entity.is_alive: + if hasattr(entity, "process_sub_entities"): + entity.process_sub_entities(lambda e: self.discard(e)) + + handle = entity.dxf.handle + try: + del self._database[handle] + entity.dxf.handle = None + except KeyError: + pass + + def duplicate_entity(self, entity: DXFEntity) -> DXFEntity: + """Duplicates `entity` and its sub entities (VERTEX, ATTRIB, SEQEND) + and store them with new handles in the entity database. + Graphical entities have to be added to a layout by + :meth:`~ezdxf.layouts.BaseLayout.add_entity`. DXF objects will + automatically added to the OBJECTS section. + + A new owner handle will be set by adding the duplicated entity to a + layout. + + Raises: + CopyNotSupported: copying of `entity` is not supported + + """ + doc = entity.doc + assert doc is not None, "valid DXF document required" + new_handle = self.next_handle() + new_entity: DXFEntity = entity.copy(copy_strategy=default_copy) + new_entity.dxf.handle = new_handle + factory.bind(new_entity, doc) + if isinstance(new_entity, DXFObject): + # add DXF objects automatically to the OBJECTS section + doc.objects.add_object(new_entity) + return new_entity + + def audit(self, auditor: Auditor): + """Restore database integrity: + + - restore database entries with modified handles (key != entity.dxf.handle) + - remove entities with invalid handles + - empty trashcan - destroy all entities in the trashcan + - removes destroyed database entries (purge) + + """ + assert self.locked is False, "Database is locked!" + add_entities = [] + + with self.trashcan() as trash: # type: ignore + for handle, entity in self.items(): + # Destroyed entities are already filtered! + if not is_valid_handle(handle): + auditor.fixed_error( + code=AuditError.INVALID_ENTITY_HANDLE, + message=f"Removed entity {entity.dxftype()} with invalid " + f'handle "{handle}" from entity database.', + ) + trash.add(handle) + if handle != entity.dxf.get("handle"): + # database handle != stored entity handle + # prevent entity from being destroyed: + self._database[handle] = None # type: ignore + trash.add(handle) + add_entities.append(entity) + + # Remove all destroyed entities from database: + self.purge() + + for entity in add_entities: + handle = entity.dxf.get("handle") + if handle is None: + auditor.fixed_error( + code=AuditError.INVALID_ENTITY_HANDLE, + message=f"Removed entity {entity.dxftype()} without handle " + f"from entity database.", + ) + continue + if not is_valid_handle(handle) or handle == "0": + auditor.fixed_error( + code=AuditError.INVALID_ENTITY_HANDLE, + message=f"Removed entity {entity.dxftype()} with invalid " + f'handle "{handle}" from entity database.', + ) + continue + self[handle] = entity + + def new_trashcan(self) -> EntityDB.Trashcan: + """Returns a new trashcan, empty trashcan manually by: : + func:`Trashcan.clear()`. + """ + return EntityDB.Trashcan(self) + + @contextmanager # type: ignore + def trashcan(self) -> EntityDB.Trashcan: # type: ignore + """Returns a new trashcan in context manager mode, trashcan will be + emptied when leaving context. + """ + trashcan_ = self.new_trashcan() + yield trashcan_ + # try ... finally is not required, in case of an exception the database + # is maybe already in an unreliable state. + trashcan_.clear() + + def purge(self) -> None: + """Remove all destroyed entities from database, but does not empty the + trashcan. + """ + # Important: operate on underlying data structure: + db = self._database + dead_handles = [handle for handle, entity in db.items() if not entity.is_alive] + for handle in dead_handles: + del db[handle] + + def dxf_types_in_use(self) -> set[str]: + return set(entity.dxftype() for entity in self.values()) + + def reset_handle(self, entity: DXFEntity, handle: str) -> bool: + """Try to reset the entity handle to a certain value. + Returns ``True`` if successful and ``False`` otherwise. + + """ + if handle in self._database: + return False + self.discard(entity) + entity.dxf.handle = handle + self.add(entity) + return True + + def query(self, query: str = "*") -> EntityQuery: + """Entity query over all entities in the DXF document. + + Args: + query: query string + + .. seealso:: + + :ref:`entity query string` and :ref:`entity queries` + + """ + return EntityQuery((e for e in self._database.values() if e.is_alive), query) + + +class EntitySpace: + """ + An :class:`EntitySpace` is a collection of :class:`~ezdxf.entities.DXFEntity` + objects, that stores only references to :class:`DXFEntity` objects. + + The :class:`~ezdxf.layouts.Modelspace`, any :class:`~ezdxf.layouts.Paperspace` + layout and :class:`~ezdxf.layouts.BlockLayout` objects have an + :class:`EntitySpace` container to store their entities. + + """ + + def __init__(self, entities: Optional[Iterable[DXFEntity]] = None): + self.entities: list[DXFEntity] = ( + list(e for e in entities if e.is_alive) if entities else [] + ) + + def __iter__(self) -> Iterator[DXFEntity]: + """Iterable of all entities, filters destroyed entities.""" + return (e for e in self.entities if e.is_alive) + + def __getitem__(self, index) -> DXFEntity: + """Get entity at index `item` + + :class:`EntitySpace` has a standard Python list like interface, + therefore `index` can be any valid list indexing or slicing term, like + a single index ``layout[-1]`` to get the last entity, or an index slice + ``layout[:10]`` to get the first 10 or fewer entities as + ``list[DXFEntity]``. Does not filter destroyed entities. + + """ + return self.entities[index] + + def __len__(self) -> int: + """Count of entities including destroyed entities.""" + return len(self.entities) + + def has_handle(self, handle: str) -> bool: + """``True`` if `handle` is present, does filter destroyed entities.""" + assert isinstance(handle, str), type(handle) + return any(e.dxf.handle == handle for e in self) + + def purge(self): + """Remove all destroyed entities from entity space.""" + self.entities = list(self) + + def add(self, entity: DXFEntity) -> None: + """Add `entity`.""" + assert isinstance(entity, DXFEntity), type(entity) + assert entity.is_alive, "Can not store destroyed entities" + self.entities.append(entity) + + def extend(self, entities: Iterable[DXFEntity]) -> None: + """Add multiple `entities`.""" + for entity in entities: + self.add(entity) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Export all entities into DXF file by `tagwriter`. + + (internal API) + """ + for entity in iter(self): + entity.export_dxf(tagwriter) + + def remove(self, entity: DXFEntity) -> None: + """Remove `entity`.""" + self.entities.remove(entity) + + def clear(self) -> None: + """Remove all entities.""" + # Do not destroy entities! + self.entities = list() + + def pop(self, index: int = -1) -> DXFEntity: + return self.entities.pop(index) + + def insert(self, index: int, entity: DXFEntity) -> None: + self.entities.insert(index, entity) + + def audit(self, auditor: Auditor) -> None: + db_get = auditor.entitydb.get + purge: list[DXFEntity] = [] + # Check if every entity is the entity that is stored for this handle in the + # entity database. + for entity in self: + handle = entity.dxf.handle + if entity is not db_get(handle): + # A different entity is stored in the database for this handle, + # see issues #604 and #833: + # - document has entities without handles (invalid for DXF R13+) + # - $HANDSEED is not the next usable handle + # - entity gets an already used handle + # - entity overwrites existing entity or will be overwritten by an entity + # loaded afterwards + auditor.fixed_error( + AuditError.REMOVED_INVALID_DXF_OBJECT, + f"Removed entity {entity} with a conflicting handle and without a " + f"database entry.", + ) + purge.append(entity) + if not purge: + return + for entity in purge: + self.entities.remove(entity) + # These are invalid entities do not call destroy() on them, because + # this method relies on well-defined entities! + entity._silent_kill() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/enums.py b/.venv/lib/python3.12/site-packages/ezdxf/enums.py new file mode 100644 index 0000000..ca282dc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/enums.py @@ -0,0 +1,253 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +from enum import IntEnum, IntFlag, Enum, auto +from ezdxf.lldxf import const + + +class TextHAlign(IntEnum): + """Enumeration for DXF attribute: :attr:`ezdxf.entities.Text.dxf.halign`""" + + LEFT = const.LEFT + CENTER = const.CENTER + RIGHT = const.RIGHT + ALIGNED = const.ALIGNED + MIDDLE = 4 + FIT = const.FIT + + +class TextVAlign(IntEnum): + """Enumeration for DXF attribute: :attr:`ezdxf.entities.Text.dxf.valign`""" + + BASELINE = const.BASELINE + BOTTOM = const.BOTTOM + MIDDLE = const.MIDDLE + TOP = const.TOP + + +# noinspection PyArgumentList +class TextEntityAlignment(Enum): + """Text alignment enum for the :class:`~ezdxf.entities.Text`, + :class:`~ezdxf.entities.Attrib` and :class:`~ezdxf.entities.AttDef` + entities. + """ + + LEFT = auto() + CENTER = auto() + RIGHT = auto() + ALIGNED = auto() + MIDDLE = auto() + FIT = auto() + BOTTOM_LEFT = auto() + BOTTOM_CENTER = auto() + BOTTOM_RIGHT = auto() + MIDDLE_LEFT = auto() + MIDDLE_CENTER = auto() + MIDDLE_RIGHT = auto() + TOP_LEFT = auto() + TOP_CENTER = auto() + TOP_RIGHT = auto() + + +MAP_TEXT_ENUM_TO_ALIGN_FLAGS = { + TextEntityAlignment.LEFT: (TextHAlign.LEFT, TextVAlign.BASELINE), + TextEntityAlignment.CENTER: (TextHAlign.CENTER, TextVAlign.BASELINE), + TextEntityAlignment.RIGHT: (TextHAlign.RIGHT, TextVAlign.BASELINE), + TextEntityAlignment.ALIGNED: (TextHAlign.ALIGNED, TextVAlign.BASELINE), + TextEntityAlignment.MIDDLE: (TextHAlign.MIDDLE, TextVAlign.BASELINE), + TextEntityAlignment.FIT: (TextHAlign.FIT, TextVAlign.BASELINE), + TextEntityAlignment.BOTTOM_LEFT: (TextHAlign.LEFT, TextVAlign.BOTTOM), + TextEntityAlignment.BOTTOM_CENTER: (TextHAlign.CENTER, TextVAlign.BOTTOM), + TextEntityAlignment.BOTTOM_RIGHT: (TextHAlign.RIGHT, TextVAlign.BOTTOM), + TextEntityAlignment.MIDDLE_LEFT: (TextHAlign.LEFT, TextVAlign.MIDDLE), + TextEntityAlignment.MIDDLE_CENTER: (TextHAlign.CENTER, TextVAlign.MIDDLE), + TextEntityAlignment.MIDDLE_RIGHT: (TextHAlign.RIGHT, TextVAlign.MIDDLE), + TextEntityAlignment.TOP_LEFT: (TextHAlign.LEFT, TextVAlign.TOP), + TextEntityAlignment.TOP_CENTER: (TextHAlign.CENTER, TextVAlign.TOP), + TextEntityAlignment.TOP_RIGHT: (TextHAlign.RIGHT, TextVAlign.TOP), +} +MAP_TEXT_ALIGN_FLAGS_TO_ENUM = dict( + (flags, enum) for enum, flags in MAP_TEXT_ENUM_TO_ALIGN_FLAGS.items() +) + +# Used by legacy add-ons MText and Table! +MAP_STRING_ALIGN_TO_FLAGS = { + "LEFT": (TextHAlign.LEFT, TextVAlign.BASELINE), + "CENTER": (TextHAlign.CENTER, TextVAlign.BASELINE), + "RIGHT": (TextHAlign.RIGHT, TextVAlign.BASELINE), + "ALIGNED": (TextHAlign.ALIGNED, TextVAlign.BASELINE), + "MIDDLE": (TextHAlign.MIDDLE, TextVAlign.BASELINE), + "FIT": (TextHAlign.FIT, TextVAlign.BASELINE), + "BOTTOM_LEFT": (TextHAlign.LEFT, TextVAlign.BOTTOM), + "BOTTOM_CENTER": (TextHAlign.CENTER, TextVAlign.BOTTOM), + "BOTTOM_RIGHT": (TextHAlign.RIGHT, TextVAlign.BOTTOM), + "MIDDLE_LEFT": (TextHAlign.LEFT, TextVAlign.MIDDLE), + "MIDDLE_CENTER": (TextHAlign.CENTER, TextVAlign.MIDDLE), + "MIDDLE_RIGHT": (TextHAlign.RIGHT, TextVAlign.MIDDLE), + "TOP_LEFT": (TextHAlign.LEFT, TextVAlign.TOP), + "TOP_CENTER": (TextHAlign.CENTER, TextVAlign.TOP), + "TOP_RIGHT": (TextHAlign.RIGHT, TextVAlign.TOP), +} +MAP_FLAGS_TO_STRING_ALIGN = dict( + (flags, name) for name, flags in MAP_STRING_ALIGN_TO_FLAGS.items() +) + + +class MTextEntityAlignment(IntEnum): + """Text alignment enum for the :class:`~ezdxf.entities.MText` entity.""" + + TOP_LEFT = const.MTEXT_TOP_LEFT + TOP_CENTER = const.MTEXT_TOP_CENTER + TOP_RIGHT = const.MTEXT_TOP_RIGHT + MIDDLE_LEFT = const.MTEXT_MIDDLE_LEFT + MIDDLE_CENTER = const.MTEXT_MIDDLE_CENTER + MIDDLE_RIGHT = const.MTEXT_MIDDLE_RIGHT + BOTTOM_LEFT = const.MTEXT_BOTTOM_LEFT + BOTTOM_CENTER = const.MTEXT_BOTTOM_CENTER + BOTTOM_RIGHT = const.MTEXT_BOTTOM_RIGHT + + +MAP_MTEXT_ALIGN_TO_FLAGS = { + MTextEntityAlignment.TOP_LEFT: (TextHAlign.LEFT, TextVAlign.TOP), + MTextEntityAlignment.TOP_CENTER: (TextHAlign.CENTER, TextVAlign.TOP), + MTextEntityAlignment.TOP_RIGHT: (TextHAlign.RIGHT, TextVAlign.TOP), + MTextEntityAlignment.MIDDLE_LEFT: (TextHAlign.LEFT, TextVAlign.MIDDLE), + MTextEntityAlignment.MIDDLE_CENTER: (TextHAlign.CENTER, TextVAlign.MIDDLE), + MTextEntityAlignment.MIDDLE_RIGHT: (TextHAlign.RIGHT, TextVAlign.MIDDLE), + MTextEntityAlignment.BOTTOM_LEFT: (TextHAlign.LEFT, TextVAlign.BOTTOM), + MTextEntityAlignment.BOTTOM_CENTER: (TextHAlign.CENTER, TextVAlign.BOTTOM), + MTextEntityAlignment.BOTTOM_RIGHT: (TextHAlign.RIGHT, TextVAlign.BOTTOM), +} + + +class MTextParagraphAlignment(IntEnum): + DEFAULT = 0 + LEFT = 1 + RIGHT = 2 + CENTER = 3 + JUSTIFIED = 4 + DISTRIBUTED = 5 + + +class MTextFlowDirection(IntEnum): + LEFT_TO_RIGHT = const.MTEXT_LEFT_TO_RIGHT + TOP_TO_BOTTOM = const.MTEXT_TOP_TO_BOTTOM + BY_STYLE = const.MTEXT_BY_STYLE + + +class MTextLineAlignment(IntEnum): # exclusive state + BOTTOM = 0 + MIDDLE = 1 + TOP = 2 + + +class MTextStroke(IntFlag): + """Combination of flags is supported: UNDERLINE + STRIKE_THROUGH""" + + UNDERLINE = 1 + STRIKE_THROUGH = 2 + OVERLINE = 4 + + +class MTextLineSpacing(IntEnum): + AT_LEAST = const.MTEXT_AT_LEAST + EXACT = const.MTEXT_EXACT + + +class MTextBackgroundColor(IntEnum): + OFF = const.MTEXT_BG_OFF + COLOR = const.MTEXT_BG_COLOR + WINDOW = const.MTEXT_BG_WINDOW_COLOR + CANVAS = const.MTEXT_BG_CANVAS_COLOR + + +class InsertUnits(IntEnum): + Unitless = 0 + Inches = 1 + Feet = 2 + Miles = 3 + Millimeters = 4 + Centimeters = 5 + Meters = 6 + Kilometers = 7 + Microinches = 8 + Mils = 9 + Yards = 10 + Angstroms = 11 + Nanometers = 12 + Microns = 13 + Decimeters = 14 + Decameters = 15 + Hectometers = 16 + Gigameters = 17 + AstronomicalUnits = 18 + Lightyears = 19 + Parsecs = 20 + USSurveyFeet = 21 + USSurveyInch = 22 + USSurveyYard = 23 + USSurveyMile = 24 + + +class Measurement(IntEnum): + Imperial = 0 + Metric = 1 + + +class LengthUnits(IntEnum): + Scientific = 1 + Decimal = 2 + Engineering = 3 + Architectural = 4 + Fractional = 5 + + +class AngularUnits(IntEnum): + DecimalDegrees = 0 + DegreesMinutesSeconds = 1 + Grad = 2 + Radians = 3 + + +class SortEntities(IntFlag): + DISABLE = 0 + SELECTION = 1 # 1 = Sorts for object selection + SNAP = 2 # 2 = Sorts for object snap + REDRAW = 4 # 4 = Sorts for redraws; obsolete + MSLIDE = 8 # 8 = Sorts for MSLIDE command slide creation; obsolete + REGEN = 16 # 16 = Sorts for REGEN commands + PLOT = 32 # 32 = Sorts for plotting + POSTSCRIPT = 64 # 64 = Sorts for PostScript output; obsolete + + +class ACI(IntEnum): + """AutoCAD Color Index""" + + BYBLOCK = 0 + BYLAYER = 256 + BYOBJECT = 257 + RED = 1 + YELLOW = 2 + GREEN = 3 + CYAN = 4 + BLUE = 5 + MAGENTA = 6 + BLACK = 7 + WHITE = 7 + GRAY = 8 + LIGHT_GRAY = 9 + + +class EndCaps(IntEnum): + """ Lineweight end caps setting for new objects. """ + NONE = 0 + ROUND = 1 + ANGLE = 2 + SQUARE = 3 + + +class JoinStyle(IntEnum): + """ Lineweight joint setting for new objects. """ + NONE = 0 + ROUND = 1 + ANGLE = 2 + FLAT = 3 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/explode.py b/.venv/lib/python3.12/site-packages/ezdxf/explode.py new file mode 100644 index 0000000..b53ae4a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/explode.py @@ -0,0 +1,402 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import logging +from typing import ( + TYPE_CHECKING, + Iterable, + Callable, + Optional, + cast, +) +from ezdxf.lldxf import const +from ezdxf.entities import factory +from ezdxf.entities.boundary_paths import ( + PolylinePath, + EdgePath, + LineEdge, + ArcEdge, + EllipseEdge, + SplineEdge, +) +from ezdxf.math import OCS, Vec3, ABS_TOL +from ezdxf.math.transformtools import ( + NonUniformScalingError, + InsertTransformationError, +) +from ezdxf.query import EntityQuery +from ezdxf.entities.copy import default_copy, CopyNotSupported + +if TYPE_CHECKING: + from ezdxf.entities import ( + DXFGraphic, + Insert, + Attrib, + Text, + Dimension, + ) + from ezdxf.entities.polygon import DXFPolygon + from ezdxf.layouts import BaseLayout + +logger = logging.getLogger("ezdxf") + +__all__ = [ + "virtual_block_reference_entities", + "virtual_boundary_path_entities", + "explode_block_reference", + "explode_entity", + "attrib_to_text", +] + + +def default_logging_callback(entity, reason): + logger.debug( + f'(Virtual Block Reference Entities) Ignoring {str(entity)}: "{reason}"' + ) + + +def explode_block_reference( + block_ref: Insert, + target_layout: BaseLayout, + *, + redraw_order=False, + copy_strategy=default_copy, +) -> EntityQuery: + """Explode a block reference into DXF primitives. + + Transforms the block entities into the required WCS location by applying the + block reference attributes `insert`, `extrusion`, `rotation` and the scaling + values `xscale`, `yscale` and `zscale`. + + Returns an EntityQuery() container with all exploded DXF entities. + + Attached ATTRIB entities are converted to TEXT entities, this is the + behavior of the BURST command of the AutoCAD Express Tools. + + This method does not apply the clipping path created by the XCLIP command. + The method returns all entities and ignores the clipping path polygon and no + entity is clipped. + + Args: + block_ref: Block reference entity (INSERT) + target_layout: explicit target layout for exploded DXF entities + redraw_order: create entities in ascending redraw order if ``True`` + copy_strategy: customizable copy strategy + + .. warning:: + + **Non uniform scaling** may lead to incorrect results for text entities + (TEXT, MTEXT, ATTRIB) and maybe some other entities. + + (internal API) + + """ + if target_layout is None: + raise const.DXFStructureError("Target layout is None.") + + if block_ref.doc is None: + raise const.DXFStructureError( + "Block reference has to be assigned to a DXF document." + ) + + def _explode_single_block_ref(block_ref): + for entity in virtual_block_reference_entities( + block_ref, redraw_order=redraw_order, copy_strategy=copy_strategy + ): + dxftype = entity.dxftype() + target_layout.add_entity(entity) + if dxftype == "DIMENSION": + # Render a graphical representation for each exploded DIMENSION + # entity as anonymous block. + cast("Dimension", entity).render() + entities.append(entity) + + # Convert attached ATTRIB entities to TEXT entities: + # This is the behavior of the BURST command of the AutoCAD Express Tools + for attrib in block_ref.attribs: + # Attached ATTRIB entities are already located in the WCS + text = attrib_to_text(attrib) + target_layout.add_entity(text) + entities.append(text) + + entitydb = block_ref.doc.entitydb + assert ( + entitydb is not None + ), "Exploding a block reference requires an entity database." + + entities: list[DXFGraphic] = [] + if block_ref.mcount > 1: + for virtual_insert in block_ref.multi_insert(): + _explode_single_block_ref(virtual_insert) + else: + _explode_single_block_ref(block_ref) + + source_layout = block_ref.get_layout() + if source_layout is not None: + # Remove and destroy exploded INSERT if assigned to a layout + source_layout.delete_entity(block_ref) + else: + entitydb.delete_entity(block_ref) + return EntityQuery(entities) + + +IGNORE_FROM_ATTRIB = { + "version", + "prompt", + "tag", + "flags", + "field_length", + "lock_position", + "attribute_type", +} + + +def attrib_to_text(attrib: Attrib) -> Text: + dxfattribs = attrib.dxfattribs(drop=IGNORE_FROM_ATTRIB) + # ATTRIB has same owner as INSERT but does not reside in any EntitySpace() + # and must not deleted from any layout. + # New TEXT entity has same handle as the replaced ATTRIB entity and replaces + # the ATTRIB entity in the database. + text = factory.new("TEXT", dxfattribs=dxfattribs) + if attrib.doc: + factory.bind(text, attrib.doc) + return cast("Text", text) + + +def virtual_block_reference_entities( + block_ref: Insert, + *, + skipped_entity_callback: Optional[Callable[[DXFGraphic, str], None]] = None, + redraw_order=False, + copy_strategy=default_copy, +) -> Iterable[DXFGraphic]: + """Yields 'virtual' parts of block reference `block_ref`. + + This method is meant to examine the block reference entities without the need to + explode the block reference. The `skipped_entity_callback()` will be called for all + entities which are not processed, signature: + :code:`skipped_entity_callback(entity: DXFGraphic, reason: str)`, + `entity` is the original (untransformed) DXF entity of the block definition, + the `reason` string is an explanation why the entity was skipped. + + These entities are located at the 'exploded' positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + This method does not apply the clipping path created by the XCLIP command. + The method returns all entities and ignores the clipping path polygon and no + entity is clipped. + + Args: + block_ref: Block reference entity (INSERT) + skipped_entity_callback: called whenever the transformation of an entity + is not supported and so was skipped. + redraw_order: yield entities in ascending redraw order if ``True`` + copy_strategy: customizable copy strategy + + .. warning:: + + **Non uniform scaling** may lead to incorrect results for text entities + (TEXT, MTEXT, ATTRIB) and maybe some other entities. + + (internal API) + + """ + assert block_ref.dxftype() == "INSERT" + from ezdxf.entities import Ellipse + + skipped_entity_callback = skipped_entity_callback or default_logging_callback + + def disassemble(layout: BaseLayout) -> Iterable[DXFGraphic]: + for entity in layout.entities_in_redraw_order() if redraw_order else layout: + # Do not explode ATTDEF entities. Already available in Insert.attribs + if entity.dxftype() == "ATTDEF": + continue + try: + copy = entity.copy(copy_strategy=copy_strategy) + except CopyNotSupported: + if hasattr(entity, "virtual_entities"): + yield from entity.virtual_entities() + else: + skipped_entity_callback(entity, "non copyable") + else: + if hasattr(copy, "remove_association"): + copy.remove_association() + yield copy + + def transform(entities): + for entity in entities: + try: + entity.transform(m) + except NotImplementedError: + skipped_entity_callback(entity, "non transformable") + except NonUniformScalingError: + dxftype = entity.dxftype() + if dxftype in {"ARC", "CIRCLE"}: + if abs(entity.dxf.radius) > ABS_TOL: + yield Ellipse.from_arc(entity).transform(m) + else: + skipped_entity_callback( + entity, f"Invalid radius in entity {str(entity)}." + ) + elif dxftype in {"LWPOLYLINE", "POLYLINE"}: # has arcs + yield from transform(entity.virtual_entities()) + else: + skipped_entity_callback(entity, "unsupported non-uniform scaling") + except InsertTransformationError: + # INSERT entity can not be represented in the target coordinate + # system defined by transformation matrix `m`. + # Yield transformed sub-entities of the INSERT entity: + yield from transform( + virtual_block_reference_entities( + entity, skipped_entity_callback=skipped_entity_callback + ) + ) + else: + yield entity + + m = block_ref.matrix44() + block_layout = block_ref.block() + if block_layout is None: + raise const.DXFStructureError( + f'Required block definition for "{block_ref.dxf.name}" does not exist.' + ) + + yield from transform(disassemble(block_layout)) + + +EXCLUDE_FROM_EXPLODE = {"POINT"} + + +def explode_entity( + entity: DXFGraphic, target_layout: Optional[BaseLayout] = None +) -> EntityQuery: + """Explode parts of an entity as primitives into target layout, if target + layout is ``None``, the target layout is the layout of the source entity. + + Returns an :class:`~ezdxf.query.EntityQuery` container with all DXF parts. + + Args: + entity: DXF entity to explode, has to have a :meth:`virtual_entities()` + method + target_layout: target layout for DXF parts, ``None`` for same layout as + source entity + + (internal API) + + """ + dxftype = entity.dxftype() + virtual_entities = getattr(entity, "virtual_entities") + if virtual_entities is None or dxftype in EXCLUDE_FROM_EXPLODE: + raise const.DXFTypeError(f"Can not explode entity {dxftype}.") + + if entity.doc is None: + raise const.DXFStructureError( + f"{dxftype} has to be assigned to a DXF document." + ) + + entitydb = entity.doc.entitydb + if entitydb is None: + raise const.DXFStructureError( + f"Exploding {dxftype} requires an entity database." + ) + + if target_layout is None: + target_layout = entity.get_layout() + if target_layout is None: + raise const.DXFStructureError( + f"{dxftype} without layout assignment, specify target layout." + ) + + entities = [] + for e in virtual_entities(): + target_layout.add_entity(e) + entities.append(e) + + source_layout = entity.get_layout() + if source_layout is not None: + source_layout.delete_entity(entity) + else: + entitydb.delete_entity(entity) + return EntityQuery(entities) + + +def virtual_boundary_path_entities( + polygon: DXFPolygon, +) -> list[list[DXFGraphic]]: + from ezdxf.entities import LWPolyline + + def polyline(): + p = LWPolyline.new(dxfattribs=dict(graphic_attribs)) + p.append_formatted_vertices(path.vertices, format="xyb") + p.dxf.extrusion = ocs.uz + p.dxf.elevation = elevation + p.closed = path.is_closed + return p + + graphic_attribs = polygon.graphic_properties() + elevation = float(polygon.dxf.elevation.z) + ocs = polygon.ocs() + entities = [] + for path in polygon.paths: + if isinstance(path, PolylinePath): + entities.append([polyline()]) + elif isinstance(path, EdgePath): + entities.append( + _virtual_edge_path(path, dict(graphic_attribs), ocs, elevation) + ) + return entities + + +def _virtual_edge_path( + path: EdgePath, dxfattribs, ocs: OCS, elevation: float +) -> list[DXFGraphic]: + from ezdxf.entities import Line, Arc, Ellipse, Spline + + def pnt_to_wcs(v): + return ocs.to_wcs(Vec3(v).replace(z=elevation)) + + def dir_to_wcs(v): + return ocs.to_wcs(v) + + edges: list[DXFGraphic] = [] + for edge in path.edges: + attribs = dict(dxfattribs) + if isinstance(edge, LineEdge): + attribs["start"] = pnt_to_wcs(edge.start) + attribs["end"] = pnt_to_wcs(edge.end) + edges.append(Line.new(dxfattribs=attribs)) + elif isinstance(edge, ArcEdge): + attribs["center"] = edge.center + attribs["radius"] = edge.radius + attribs["elevation"] = elevation + # Arcs angles are always stored in counter-clockwise orientation + # around the extrusion vector! + attribs["start_angle"] = edge.start_angle + attribs["end_angle"] = edge.end_angle + attribs["extrusion"] = ocs.uz + edges.append(Arc.new(dxfattribs=attribs)) + elif isinstance(edge, EllipseEdge): + attribs["center"] = pnt_to_wcs(edge.center) + attribs["major_axis"] = dir_to_wcs(edge.major_axis) + attribs["ratio"] = edge.ratio + # Ellipse angles are always stored in counter-clockwise orientation + # around the extrusion vector! + attribs["start_param"] = edge.start_param + attribs["end_param"] = edge.end_param + attribs["extrusion"] = ocs.uz + edges.append(Ellipse.new(dxfattribs=attribs)) + elif isinstance(edge, SplineEdge): + spline = Spline.new(dxfattribs=attribs) + spline.dxf.degree = edge.degree + spline.knots = edge.knot_values + spline.control_points = [pnt_to_wcs(v) for v in edge.control_points] + if edge.weights: + spline.weights = edge.weights + if edge.fit_points: + spline.fit_points = [pnt_to_wcs(v) for v in edge.fit_points] + if edge.start_tangent is not None: + spline.dxf.start_tangent = dir_to_wcs(edge.start_tangent) + if edge.end_tangent is not None: + spline.dxf.end_tangent = dir_to_wcs(edge.end_tangent) + edges.append(spline) + return edges diff --git a/.venv/lib/python3.12/site-packages/ezdxf/eztypes.py b/.venv/lib/python3.12/site-packages/ezdxf/eztypes.py new file mode 100644 index 0000000..6ce8fc5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/eztypes.py @@ -0,0 +1,63 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +""" ezdxf typing hints + +Only usable in type checking mode: + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.eztypes import GenericLayoutType + +Tips for Type Imports +--------------------- + +Import Drawing class: + + from ezdxf.document import Drawing + +Import DXF entities from ezdxf.entities: + + from ezdxf.entities import Line, Point, ... + +Import layouts from ezdxf.layouts: + + from ezdxf.layouts import BaseLayout, Layout, Modelspace, Paperspace, BlockLayout + +Import math tools from ezdxf.math: + + from ezdxf.math import Vec2, Vec3, Matrix44, ... + +Import path tools from ezdxf.path: + + from ezdxf.path import Path, make_path, ... + +""" +from __future__ import annotations +from typing import ( + Any, + Callable, + Dict, + Hashable, + Iterable, + List, + Sequence, + TYPE_CHECKING, + Tuple, + Union, +) +from typing_extensions import TypeAlias + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + from ezdxf.layouts.base import VirtualLayout + from ezdxf.layouts.blocklayout import BlockLayout + from ezdxf.layouts.layout import Layout + from ezdxf.lldxf.extendedtags import ExtendedTags + from ezdxf.lldxf.tags import Tags + from ezdxf.math import UVec + + IterableTags: TypeAlias = Iterable[Tuple[int, Any]] + SectionDict: TypeAlias = Dict[str, List[Union[Tags, ExtendedTags]]] + KeyFunc: TypeAlias = Callable[[DXFEntity], Hashable] + FaceType: TypeAlias = Sequence[UVec] + GenericLayoutType: TypeAlias = Union[Layout, BlockLayout, VirtualLayout] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/filemanagement.py b/.venv/lib/python3.12/site-packages/ezdxf/filemanagement.py new file mode 100644 index 0000000..d789130 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/filemanagement.py @@ -0,0 +1,278 @@ +# Copyright (C) 2018-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TextIO, TYPE_CHECKING, Union, Sequence, Optional +import base64 +import io +import pathlib +import os + +from ezdxf.tools.standards import setup_drawing +from ezdxf.lldxf.const import DXF2013 +from ezdxf.document import Drawing + +if TYPE_CHECKING: + from ezdxf.lldxf.validator import DXFInfo + + +def new( + dxfversion: str = DXF2013, + setup: Union[str, bool, Sequence[str]] = False, + units: int = 6, +) -> Drawing: + """Create a new :class:`~ezdxf.drawing.Drawing` from scratch, `dxfversion` + can be either "AC1009" the official DXF version name or "R12" the + AutoCAD release name. + + :func:`new` can create drawings for following DXF versions: + + ======= ======================== + Version AutoCAD Release + ======= ======================== + AC1009 AutoCAD R12 + AC1015 AutoCAD R2000 + AC1018 AutoCAD R2004 + AC1021 AutoCAD R2007 + AC1024 AutoCAD R2010 + AC1027 AutoCAD R2013 + AC1032 AutoCAD R2018 + ======= ======================== + + The `units` argument defines th document and modelspace units. The header + variable $MEASUREMENT will be set according to the given `units`, 0 for + inch, feet, miles, ... and 1 for metric units. For more information go to + module :mod:`ezdxf.units` + + Args: + dxfversion: DXF version specifier as string, default is "AC1027" + respectively "R2013" + setup: setup default styles, ``False`` for no setup, + ``True`` to setup everything or a list of topics as strings, + e.g. ["linetypes", "styles"] to setup only some topics: + + ================== ======================================== + Topic Description + ================== ======================================== + linetypes setup line types + styles setup text styles + dimstyles setup default `ezdxf` dimension styles + visualstyles setup 25 standard visual styles + ================== ======================================== + units: document and modelspace units, default is 6 for meters + + """ + doc = Drawing.new(dxfversion) + doc.units = units + doc.header["$MEASUREMENT"] = 0 if units in (1, 2, 3, 8, 9, 10) else 1 + if setup: + setup_drawing(doc, topics=setup) + return doc + + +def read(stream: TextIO) -> Drawing: + """Read a DXF document from a text-stream. Open stream in text mode + (``mode='rt'``) and set correct text encoding, the stream requires at least + a :meth:`readline` method. + + Since DXF version R2007 (AC1021) file encoding is always "utf-8", + use the helper function :func:`dxf_stream_info` to detect the required + text encoding for prior DXF versions. To preserve possible binary data in + use :code:`errors='surrogateescape'` as error handler for the import stream. + + If this function struggles to load the DXF document and raises a + :class:`DXFStructureError` exception, try the :func:`ezdxf.recover.read` + function to load this corrupt DXF document. + + Args: + stream: input text stream opened with correct encoding + + Raises: + DXFStructureError: for invalid or corrupted DXF structures + + """ + from ezdxf.document import Drawing + + return Drawing.read(stream) + + +def readfile( + filename: str | os.PathLike, + encoding: Optional[str] = None, + errors: str = "surrogateescape", +) -> Drawing: + """Read the DXF document `filename` from the file-system. + + This is the preferred method to load existing ASCII or Binary DXF files, + the required text encoding will be detected automatically and decoding + errors will be ignored. + + Override encoding detection by setting argument `encoding` to the + estimated encoding. (use Python encoding names like in the :func:`open` + function). + + If this function struggles to load the DXF document and raises a + :class:`DXFStructureError` exception, try the :func:`ezdxf.recover.readfile` + function to load this corrupt DXF document. + + Args: + filename: filename of the ASCII- or Binary DXF document + encoding: use ``None`` for auto detect (default), or set a specific + encoding like "utf-8", argument is ignored for Binary DXF files + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + IOError: not a DXF file or file does not exist + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + from ezdxf.lldxf.validator import is_dxf_file, is_binary_dxf_file + from ezdxf.tools.codepage import is_supported_encoding + from ezdxf.lldxf.tagger import binary_tags_loader + + filename = str(filename) + if is_binary_dxf_file(filename): + with open(filename, "rb") as fp: + data = fp.read() + loader = binary_tags_loader(data, errors=errors) + doc = Drawing.load(loader) + doc.filename = filename + return doc + + if not is_dxf_file(filename): + raise IOError(f"File '{filename}' is not a DXF file.") + + info = dxf_file_info(filename) + if encoding is not None: + # override default encodings if absolute necessary + info.encoding = encoding + with open(filename, mode="rt", encoding=info.encoding, errors=errors) as fp: + doc = read(fp) + + doc.filename = filename + if encoding is not None and is_supported_encoding(encoding): + # store overridden encoding if supported by AutoCAD, else default + # encoding stored in $DWGENCODING is used as document encoding or + # 'cp1252' if $DWGENCODING is unset. + doc.encoding = encoding + return doc + + +def dxf_file_info(filename: str | os.PathLike) -> DXFInfo: + """Reads basic file information from a DXF document: DXF version, encoding + and handle seed. + + """ + filename = str(filename) + with open(filename, mode="rt", encoding="utf-8", errors="ignore") as fp: + return dxf_stream_info(fp) + + +def dxf_stream_info(stream: TextIO) -> DXFInfo: + """Reads basic DXF information from a text stream: DXF version, encoding + and handle seed. + + """ + from ezdxf.lldxf.validator import dxf_info + + info = dxf_info(stream) + # R2007 files and later are always encoded as UTF-8 + if info.version >= "AC1021": + info.encoding = "utf-8" + return info + + +def readzip( + zipfile: str | os.PathLike, + filename: Optional[str] = None, + errors: str = "surrogateescape", +) -> Drawing: + """Load a DXF document specified by `filename` from a zip archive, or if + `filename` is ``None`` the first DXF document in the zip archive. + + Args: + zipfile: name of the zip archive + filename: filename of DXF file, or ``None`` to load the first DXF + document from the zip archive. + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + IOError: not a DXF file or file does not exist or + if `filename` is ``None`` - no DXF file found + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + from ezdxf.tools.zipmanager import ctxZipReader + + with ctxZipReader(str(zipfile), filename, errors=errors) as zipstream: + doc = read(zipstream) # type: ignore + doc.filename = zipstream.dxf_file_name + return doc + + +def decode_base64(data: bytes, errors: str = "surrogateescape") -> Drawing: + """Load a DXF document from base64 encoded binary data, like uploaded data + to web applications. + + Args: + data: DXF document base64 encoded binary data + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + # Copyright (c) 2020, Joseph Flack + # License: MIT License + # Decode base64 encoded data into binary data + binary_data = base64.b64decode(data) + + # Replace windows line ending '\r\n' by universal line ending '\n' + binary_data = binary_data.replace(b"\r\n", b"\n") + + # Read DXF file info from data, basic DXF information in the HEADER + # section is ASCII encoded so encoding setting here is not important + # for this task: + text = binary_data.decode("utf-8", errors="ignore") + stream = io.StringIO(text) + info = dxf_stream_info(stream) + stream.close() + + # Use encoding info to create correct decoded text input stream for ezdxf + text = binary_data.decode(info.encoding, errors=errors) + stream = io.StringIO(text) + + # Load DXF document from data stream + doc = read(stream) + stream.close() + return doc + + +def find_support_file( + filename: str, support_dirs: Optional[Sequence[str]] = None +) -> str: + """Find file `filename` in the support directories`.""" + if pathlib.Path(filename).exists(): + return filename + if support_dirs is None: + support_dirs = [] + for directory in support_dirs: + directory = directory.strip("\"'") + filepath = pathlib.Path(directory).expanduser() / filename + if filepath.exists(): + return str(filepath) + return filename diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__init__.py new file mode 100644 index 0000000..b51c98f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..78479ab Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_face.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_face.cpython-312.pyc new file mode 100644 index 0000000..57bc0a1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_face.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_manager.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_manager.cpython-312.pyc new file mode 100644 index 0000000..d5889f2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_manager.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_measurements.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_measurements.cpython-312.pyc new file mode 100644 index 0000000..a636c76 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_measurements.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_synonyms.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_synonyms.cpython-312.pyc new file mode 100644 index 0000000..1466d60 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/font_synonyms.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/fonts.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/fonts.cpython-312.pyc new file mode 100644 index 0000000..02a66db Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/fonts.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/glyphs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/glyphs.cpython-312.pyc new file mode 100644 index 0000000..bf5d824 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/glyphs.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/lff.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/lff.cpython-312.pyc new file mode 100644 index 0000000..b7ca90e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/lff.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/shapefile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/shapefile.cpython-312.pyc new file mode 100644 index 0000000..838172c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/shapefile.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/ttfonts.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/ttfonts.cpython-312.pyc new file mode 100644 index 0000000..3e959c8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/fonts/__pycache__/ttfonts.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_face.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_face.py new file mode 100644 index 0000000..f05a2a2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_face.py @@ -0,0 +1,78 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import NamedTuple + + +class FontFace(NamedTuple): + # filename without parent directories e.g. "OpenSans-Regular.ttf" + filename: str = "" + family: str = "sans-serif" + style: str = "Regular" + weight: int = 400 # Normal - usWeightClass + width: int = 5 # Medium(Normal) - usWidthClass + + @property + def is_italic(self) -> bool: + """Returns ``True`` if font face is italic.""" + return self.style.lower().find("italic") > -1 + + @property + def is_oblique(self) -> bool: + """Returns ``True`` if font face is oblique.""" + return self.style.lower().find("oblique") > -1 + + @property + def is_bold(self) -> bool: + """Returns ``True`` if font face weight > 400.""" + return self.weight > 400 + + @property + def weight_str(self) -> str: + """Returns the :attr:`weight` as string e.g. "Thin", "Normal", "Bold", ...""" + return get_weight_str(self.weight) + + @property + def width_str(self) -> str: + """Returns the :attr:`width` as string e.g. "Condensed", "Expanded", ...""" + return get_width_str(self.width) + + def distance(self, font_face: FontFace) -> tuple[int, int]: + return self.weight - font_face.weight, self.width - font_face.width + + +WEIGHT_STR = { + 100: "Thin", + 200: "ExtraLight", + 300: "Light", + 400: "Normal", + 500: "Medium", + 600: "SemiBold", + 700: "Bold", + 800: "ExtraBold", + 900: "Black", +} + +WIDTH_STR = { + 1: "UltraCondensed", + 2: "ExtraCondensed", + 3: "Condensed", + 4: "SemiCondensed", + 5: "Medium", # Normal + 6: "SemiExpanded", + 7: "Expanded", + 8: "ExtraExpanded", + 9: "UltraExpanded", +} + + +def get_weight_str(weight: int) -> str: + """Returns the :attr:`weight` as string e.g. "Thin", "Normal", "Bold", ...""" + key = max(min(round((weight + 1) / 100) * 100, 900), 100) + return WEIGHT_STR[key] + + +def get_width_str(width: int) -> str: + """Returns the :attr:`width` as string e.g. "Condensed", "Expanded", ...""" + key = max(min(width, 9), 1) + return WIDTH_STR[key] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_manager.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_manager.py new file mode 100644 index 0000000..bf21cfa --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_manager.py @@ -0,0 +1,526 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import pathlib +from typing import Iterable, NamedTuple, Optional, Sequence +import os +import platform +import json +import logging + +from pathlib import Path +from fontTools.ttLib import TTFont, TTLibError +from .font_face import FontFace +from . import shapefile, lff + +logger = logging.getLogger("ezdxf") +WINDOWS = "Windows" +LINUX = "Linux" +MACOS = "Darwin" + + +WIN_SYSTEM_ROOT = os.environ.get("SystemRoot", "C:/Windows") +WIN_FONT_DIRS = [ + # AutoCAD and BricsCAD do not support fonts installed in the user directory: + "~/AppData/Local/Microsoft/Windows/Fonts", + f"{WIN_SYSTEM_ROOT}/Fonts", +] +LINUX_FONT_DIRS = [ + "/usr/share/fonts", + "/usr/local/share/fonts", + "~/.fonts", + "~/.local/share/fonts", + "~/.local/share/texmf/fonts", +] +MACOS_FONT_DIRS = [ + "/Library/Fonts/", + "/System/Library/Fonts/" +] +FONT_DIRECTORIES = { + WINDOWS: WIN_FONT_DIRS, + LINUX: LINUX_FONT_DIRS, + MACOS: MACOS_FONT_DIRS, +} + +DEFAULT_FONTS = [ + "ArialUni.ttf", # for Windows + "Arial Unicode.ttf", # for macOS + "Arial.ttf", # for the case "Arial Unicode" does not exist + "DejaVuSansCondensed.ttf", # widths of glyphs is similar to Arial + "DejaVuSans.ttf", + "LiberationSans-Regular.ttf", + "OpenSans-Regular.ttf", +] +CURRENT_CACHE_VERSION = 2 + + +class CacheEntry(NamedTuple): + file_path: Path # full file path e.g. "C:\Windows\Fonts\DejaVuSans.ttf" + font_face: FontFace + + +GENERIC_FONT_FAMILY = { + "serif": "DejaVu Serif", + "sans-serif": "DejaVu Sans", + "monospace": "DejaVu Sans Mono", +} + + +class FontCache: + def __init__(self) -> None: + # cache key is the lowercase ttf font name without parent directories + # e.g. "arial.ttf" for "C:\Windows\Fonts\Arial.ttf" + self._cache: dict[str, CacheEntry] = dict() + + def __contains__(self, font_name: str) -> bool: + return self.key(font_name) in self._cache + + def __getitem__(self, item: str) -> CacheEntry: + return self._cache[self.key(item)] + + def __setitem__(self, item: str, entry: CacheEntry) -> None: + self._cache[self.key(item)] = entry + + def __len__(self): + return len(self._cache) + + def clear(self) -> None: + self._cache.clear() + + @staticmethod + def key(font_name: str) -> str: + return str(font_name).lower() + + def add_entry(self, font_path: Path, font_face: FontFace) -> None: + self._cache[self.key(font_path.name)] = CacheEntry(font_path, font_face) + + def get(self, font_name: str, fallback: str) -> CacheEntry: + try: + return self._cache[self.key(font_name)] + except KeyError: + entry = self._cache.get(self.key(fallback)) + if entry is not None: + return entry + else: # no fallback font available + raise FontNotFoundError("no fonts available, not even fallback fonts") + + def find_best_match(self, font_face: FontFace) -> Optional[FontFace]: + entry = self._cache.get(self.key(font_face.filename), None) + if entry: + return entry.font_face + return self.find_best_match_ex( + family=font_face.family, + style=font_face.style, + weight=font_face.weight, + width=font_face.width, + italic=font_face.is_italic, + ) + + def find_best_match_ex( + self, + family: str = "sans-serif", + style: str = "Regular", + weight: int = 400, + width: int = 5, + italic: Optional[bool] = False, + ) -> Optional[FontFace]: + # italic == None ... ignore italic flag + family = GENERIC_FONT_FAMILY.get(family, family) + entries = filter_family(family, self._cache.values()) + if len(entries) == 0: + return None + elif len(entries) == 1: + return entries[0].font_face + entries_ = filter_style(style, entries) + if len(entries_) == 1: + return entries_[0].font_face + elif len(entries_): + entries = entries_ + # best match by weight, italic, width + # Note: the width property is used to prioritize shapefile types: + # 1st .shx; 2nd: .shp; 3rd: .lff + result = sorted( + entries, + key=lambda e: ( + abs(e.font_face.weight - weight), + e.font_face.is_italic is not italic, + abs(e.font_face.width - width), + ), + ) + return result[0].font_face + + def loads(self, s: str) -> None: + cache: dict[str, CacheEntry] = dict() + try: + content = json.loads(s) + except json.JSONDecodeError: + raise IOError("invalid JSON file format") + try: + version = content["version"] + content = content["font-faces"] + except KeyError: + raise IOError("invalid cache file format") + if version == CURRENT_CACHE_VERSION: + for entry in content: + try: + file_path, family, style, weight, width = entry + except ValueError: + raise IOError("invalid cache file format") + path = Path(file_path) # full path, e.g. "C:\Windows\Fonts\Arial.ttf" + font_face = FontFace( + filename=path.name, # file name without parent dirs, e.g. "Arial.ttf" + family=family, # Arial + style=style, # Regular + weight=weight, # 400 (Normal) + width=width, # 5 (Normal) + ) + cache[self.key(path.name)] = CacheEntry(path, font_face) + else: + raise IOError("invalid cache file version") + self._cache = cache + + def dumps(self) -> str: + faces = [ + ( + str(entry.file_path), + entry.font_face.family, + entry.font_face.style, + entry.font_face.weight, + entry.font_face.width, + ) + for entry in self._cache.values() + ] + data = {"version": CURRENT_CACHE_VERSION, "font-faces": faces} + return json.dumps(data, indent=2) + + def print_available_fonts(self, verbose=False) -> None: + for entry in self._cache.values(): + print(f"{entry.file_path}") + if not verbose: + continue + font_type = entry.file_path.suffix.lower() + ff = entry.font_face + if font_type in (".shx", ".shp"): + print(f" Shape font file: '{ff.filename}'") + elif font_type == ".lff": + print(f" LibreCAD font file: '{ff.filename}'") + else: + print(f" TrueType/OpenType font file: '{ff.filename}'") + print(f" family: {ff.family}") + print(f" style: {ff.style}") + print(f" weight: {ff.weight}, {ff.weight_str}") + print(f" width: {ff.width}, {ff.width_str}") + print(f"\nfound {len(self._cache)} fonts") + + +def filter_family(family: str, entries: Iterable[CacheEntry]) -> list[CacheEntry]: + key = str(family).lower() + return [e for e in entries if e.font_face.family.lower().startswith(key)] + + +def filter_style(style: str, entries: Iterable[CacheEntry]) -> list[CacheEntry]: + key = str(style).lower() + return [e for e in entries if key in e.font_face.style.lower()] + + +# TrueType and OpenType fonts: +# Note: CAD applications like AutoCAD/BricsCAD do not support OpenType fonts! +SUPPORTED_TTF_TYPES = {".ttf", ".ttc", ".otf"} +# Basic stroke-fonts included in CAD applications: +SUPPORTED_SHAPE_FILES = {".shx", ".shp", ".lff"} +NO_FONT_FACE = FontFace() +FALLBACK_SHAPE_FILES = ["txt.shx", "txt.shp", "iso.shx", "iso.shp"] +FALLBACK_LFF = ["standard.lff", "iso.lff", "simplex.lff"] + + +class FontNotFoundError(Exception): + pass + + +class UnsupportedFont(Exception): + pass + + +class FontManager: + def __init__(self) -> None: + self.platform = platform.system() + self._font_cache: FontCache = FontCache() + self._match_cache: dict[int, Optional[FontFace]] = dict() + self._loaded_ttf_fonts: dict[str, TTFont] = dict() + self._loaded_shape_file_glyph_caches: dict[str, shapefile.GlyphCache] = dict() + self._loaded_lff_glyph_caches: dict[str, lff.GlyphCache] = dict() + self._fallback_font_name = "" + self._fallback_shape_file = "" + self._fallback_lff = "" + + def print_available_fonts(self, verbose=False) -> None: + self._font_cache.print_available_fonts(verbose=verbose) + + def has_font(self, font_name: str) -> bool: + return font_name in self._font_cache + + def clear(self) -> None: + self._font_cache = FontCache() + self._loaded_ttf_fonts.clear() + self._fallback_font_name = "" + + def fallback_font_name(self) -> str: + fallback_name = self._fallback_font_name + if fallback_name: + return fallback_name + fallback_name = DEFAULT_FONTS[0] + for name in DEFAULT_FONTS: + try: + cache_entry = self._font_cache.get(name, fallback_name) + fallback_name = cache_entry.file_path.name + break + except FontNotFoundError: + pass + self._fallback_font_name = fallback_name + return fallback_name + + def fallback_shapefile(self) -> str: + fallback_shape_file = self._fallback_shape_file + if fallback_shape_file: + return fallback_shape_file + + for name in FALLBACK_SHAPE_FILES: + if name in self._font_cache: + self._fallback_shape_file = name + return name + return "" + + def fallback_lff(self) -> str: + fallback_lff = self._fallback_lff + if fallback_lff: + return fallback_lff + + for name in FALLBACK_SHAPE_FILES: + if name in self._font_cache: + self._fallback_shape_file = name + return name + return "" + + def get_ttf_font(self, font_name: str, font_number: int = 0) -> TTFont: + try: + return self._loaded_ttf_fonts[font_name] + except KeyError: + pass + fallback_name = self.fallback_font_name() + try: + font = TTFont( + self._font_cache.get(font_name, fallback_name).file_path, + fontNumber=font_number, + ) + except IOError as e: + raise FontNotFoundError(str(e)) + except TTLibError as e: + raise FontNotFoundError(str(e)) + self._loaded_ttf_fonts[font_name] = font + return font + + def ttf_font_from_font_face(self, font_face: FontFace) -> TTFont: + return self.get_ttf_font(Path(font_face.filename).name) + + def get_shapefile_glyph_cache(self, font_name: str) -> shapefile.GlyphCache: + try: + return self._loaded_shape_file_glyph_caches[font_name] + except KeyError: + pass + fallback_name = self.fallback_shapefile() + try: + file_path = self._font_cache.get(font_name, fallback_name).file_path + except KeyError: + raise FontNotFoundError(f"shape font '{font_name}' not found") + try: + file = shapefile.readfile(str(file_path)) + except IOError: + raise FontNotFoundError(f"shape file '{file_path}' not found") + except shapefile.UnsupportedShapeFile as e: + raise UnsupportedFont(f"unsupported font'{file_path}': {str(e)}") + glyph_cache = shapefile.GlyphCache(file) + self._loaded_shape_file_glyph_caches[font_name] = glyph_cache + return glyph_cache + + def get_lff_glyph_cache(self, font_name: str) -> lff.GlyphCache: + try: + return self._loaded_lff_glyph_caches[font_name] + except KeyError: + pass + fallback_name = self.fallback_lff() + try: + file_path = self._font_cache.get(font_name, fallback_name).file_path + except KeyError: + raise FontNotFoundError(f"LibreCAD font '{font_name}' not found") + try: + s = pathlib.Path(file_path).read_text(encoding="utf8") + font = lff.loads(s) + except IOError: + raise FontNotFoundError(f"LibreCAD font file '{file_path}' not found") + glyph_cache = lff.GlyphCache(font) + self._loaded_lff_glyph_caches[font_name] = glyph_cache + return glyph_cache + + def get_font_face(self, font_name: str) -> FontFace: + cache_entry = self._font_cache.get(font_name, self.fallback_font_name()) + return cache_entry.font_face + + def find_best_match( + self, + family: str = "sans-serif", + style: str = "Regular", + weight=400, + width=5, + italic: Optional[bool] = False, + ) -> Optional[FontFace]: + key = hash((family, style, weight, width, italic)) + try: + return self._match_cache[key] + except KeyError: + pass + font_face = self._font_cache.find_best_match_ex( + family, style, weight, width, italic + ) + self._match_cache[key] = font_face + return font_face + + def find_font_name(self, font_face: FontFace) -> str: + """Returns the font file name of the font without parent directories + e.g. "LiberationSans-Regular.ttf". + """ + font_face = self._font_cache.find_best_match(font_face) # type: ignore + if font_face is None: + font_face = self.get_font_face(self.fallback_font_name()) + return font_face.filename + else: + return font_face.filename + + def build(self, folders: Optional[Sequence[str]] = None, support_dirs=True) -> None: + """Adds all supported font types located in the given `folders` to the font + manager. If no directories are specified, the known font folders for Windows, + Linux and macOS are searched by default, except `support_dirs` is ``False``. + Searches recursively all subdirectories. + + The folders stored in the config SUPPORT_DIRS option are scanned recursively for + .shx, .shp and .lff fonts, the basic stroke fonts included in CAD applications. + + """ + from ezdxf._options import options + + if folders: + dirs = list(folders) + else: + dirs = FONT_DIRECTORIES.get(self.platform, LINUX_FONT_DIRS) + if support_dirs: + dirs = dirs + list(options.support_dirs) + self.scan_all(dirs) + + def add_synonyms(self, synonyms: dict[str, str], reverse=True) -> None: + font_cache = self._font_cache + for font_name, synonym in synonyms.items(): + if not font_name in font_cache: + continue + if synonym in font_cache: + continue + cache_entry = font_cache[font_name] + font_cache[synonym] = cache_entry + if reverse: + self.add_synonyms({v: k for k, v in synonyms.items()}, reverse=False) + + def scan_all(self, folders: Iterable[str]) -> None: + for folder in folders: + folder = folder.strip("'\"") # strip quotes + if not folder: + continue + try: + self.scan_folder(Path(folder).expanduser()) + except PermissionError as e: + print(str(e)) + continue + + def scan_folder(self, folder: Path): + if not folder.exists(): + return + for file in folder.iterdir(): + if file.is_dir(): + self.scan_folder(file) + continue + ext = file.suffix.lower() + if ext in SUPPORTED_TTF_TYPES: + try: + font_face = get_ttf_font_face(file) + except Exception as e: + logger.warning(f"cannot open font '{file}': {str(e)}") + else: + self._font_cache.add_entry(file, font_face) + elif ext in SUPPORTED_SHAPE_FILES: + font_face = get_shape_file_font_face(file) + self._font_cache.add_entry(file, font_face) + + def dumps(self) -> str: + return self._font_cache.dumps() + + def loads(self, s: str) -> None: + self._font_cache.loads(s) + + +def normalize_style(style: str) -> str: + if style in {"Book"}: + style = "Regular" + return style + + +def get_ttf_font_face(font_path: Path) -> FontFace: + """The caller should catch ALL exception (see scan_folder function above) - strange + things can happen when reading TTF files. + """ + ttf = TTFont(font_path, fontNumber=0) + names = ttf["name"].names + family = "" + style = "" + for record in names: + if record.nameID == 1: + family = record.string.decode(record.getEncoding()) + elif record.nameID == 2: + style = record.string.decode(record.getEncoding()) + if family and style: + break + + try: + os2_table = ttf["OS/2"] + except Exception: # e.g. ComickBook_Simple.ttf has an invalid "OS/2" table + logger.info(f"cannot load OS/2 table of font '{font_path.name}'") + weight = 400 + width = 5 + else: + weight = os2_table.usWeightClass + width = os2_table.usWidthClass + return FontFace( + filename=font_path.name, + family=family, + style=normalize_style(style), + width=width, + weight=weight, + ) + + +def get_shape_file_font_face(font_path: Path) -> FontFace: + ext = font_path.suffix.lower() + # Note: the width property is not defined in shapefiles and is used to + # prioritize the shapefile types for find_best_match(): + # 1st .shx; 2nd: .shp; 3rd: .lff + + width = 5 + if ext == ".shp": + width = 6 + if ext == ".lff": + width = 7 + + return FontFace( + filename=font_path.name, # "txt.shx", "simplex.shx", ... + family=font_path.stem.lower(), # "txt", "simplex", ... + style=font_path.suffix.lower(), # ".shx", ".shp" or ".lff" + width=width, + weight=400, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_measurements.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_measurements.py new file mode 100644 index 0000000..0396c00 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_measurements.py @@ -0,0 +1,54 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import NamedTuple +# A Visual Guide to the Anatomy of Typography: https://visme.co/blog/type-anatomy/ +# Anatomy of a Character: https://www.fonts.com/content/learning/fontology/level-1/type-anatomy/anatomy + + +class FontMeasurements(NamedTuple): + baseline: float + cap_height: float + x_height: float + descender_height: float + + def scale(self, factor: float = 1.0) -> FontMeasurements: + return FontMeasurements( + self.baseline * factor, + self.cap_height * factor, + self.x_height * factor, + self.descender_height * factor, + ) + + def shift(self, distance: float = 0.0) -> FontMeasurements: + return FontMeasurements( + self.baseline + distance, + self.cap_height, + self.x_height, + self.descender_height, + ) + + def scale_from_baseline(self, desired_cap_height: float) -> FontMeasurements: + factor = desired_cap_height / self.cap_height + return FontMeasurements( + self.baseline, + desired_cap_height, + self.x_height * factor, + self.descender_height * factor, + ) + + @property + def cap_top(self) -> float: + return self.baseline + self.cap_height + + @property + def x_top(self) -> float: + return self.baseline + self.x_height + + @property + def bottom(self) -> float: + return self.baseline - self.descender_height + + @property + def total_height(self) -> float: + return self.cap_height + self.descender_height diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_synonyms.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_synonyms.py new file mode 100644 index 0000000..941d33e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/font_synonyms.py @@ -0,0 +1,10 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License + +FONT_SYNONYMS = { + "ariblk.ttf": "Arial Black.ttf", + "comic.ttf": "Comic Sans MS.ttf", + "arialuni.ttf": "Arial Unicode.ttf", + "times.ttf": "Times New Roman.ttf", + "trebuc.ttf": "Trebuchet MS.ttf", +} diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/fonts.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/fonts.py new file mode 100644 index 0000000..bcc5262 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/fonts.py @@ -0,0 +1,745 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Optional, TYPE_CHECKING, cast +import abc +import enum +import logging +import os +import pathlib + +from ezdxf import options +from .font_face import FontFace +from .font_manager import ( + FontManager, + SUPPORTED_TTF_TYPES, + FontNotFoundError, + UnsupportedFont, +) +from .font_synonyms import FONT_SYNONYMS +from .font_measurements import FontMeasurements +from .glyphs import GlyphPath, Glyphs + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity, Textstyle + +logger = logging.getLogger("ezdxf") +FONT_MANAGER_CACHE_FILE = "font_manager_cache.json" +# SUT = System Under Test, see build_sut_font_manager_cache() function +SUT_FONT_MANAGER_CACHE = False +CACHE_DIRECTORY = ".cache" +font_manager = FontManager() + +SHX_FONTS = { + # See examples in: CADKitSamples/Shapefont.dxf + # Shape file structure is not documented, therefore, replace these fonts by + # true type fonts. + # `None` is for: use the default font. + # + # All these replacement TTF fonts have a copyright remark: + # "(c) Copyright 1996 by Autodesk Inc., All rights reserved" + # and therefore can not be included in ezdxf or the associated repository! + # You got them if you install any Autodesk product, like the free available + # DWG/DXF viewer "TrueView" : https://www.autodesk.com/viewers + "AMGDT": "amgdt___.ttf", # Tolerance symbols + "AMGDT.SHX": "amgdt___.ttf", + "COMPLEX": "complex_.ttf", + "COMPLEX.SHX": "complex_.ttf", + "ISOCP": "isocp.ttf", + "ISOCP.SHX": "isocp.ttf", + "ITALIC": "italicc_.ttf", + "ITALIC.SHX": "italicc_.ttf", + "GOTHICG": "gothicg_.ttf", + "GOTHICG.SHX": "gothicg_.ttf", + "GREEKC": "greekc.ttf", + "GREEKC.SHX": "greekc.ttf", + "ROMANS": "romans__.ttf", + "ROMANS.SHX": "romans__.ttf", + "SCRIPTS": "scripts_.ttf", + "SCRIPTS.SHX": "scripts_.ttf", + "SCRIPTC": "scriptc_.ttf", + "SCRIPTC.SHX": "scriptc_.ttf", + "SIMPLEX": "simplex_.ttf", + "SIMPLEX.SHX": "simplex_.ttf", + "SYMATH": "symath__.ttf", + "SYMATH.SHX": "symath__.ttf", + "SYMAP": "symap___.ttf", + "SYMAP.SHX": "symap___.ttf", + "SYMETEO": "symeteo_.ttf", + "SYMETEO.SHX": "symeteo_.ttf", + "TXT": "txt_____.ttf", # Default AutoCAD font + "TXT.SHX": "txt_____.ttf", +} +LFF_FONTS = { + "TXT": "standard.lff", + "TXT.SHX": "standard.lff", +} +TTF_TO_SHX = {v: k for k, v in SHX_FONTS.items() if k.endswith("SHX")} +DESCENDER_FACTOR = 0.333 # from TXT SHX font - just guessing +X_HEIGHT_FACTOR = 0.666 # from TXT SHX font - just guessing +MONOSPACE = "*monospace" # last resort fallback font only for measurement + + +def map_shx_to_ttf(font_name: str) -> str: + """Map .shx font names to .ttf file names. e.g. "TXT" -> "txt_____.ttf" """ + # Map SHX fonts to True Type Fonts: + font_upper = font_name.upper() + if font_upper in SHX_FONTS: + font_name = SHX_FONTS[font_upper] + return font_name + + +def map_shx_to_lff(font_name: str) -> str: + """Map .shx font names to .lff file names. e.g. "TXT" -> "standard.lff" """ + font_upper = font_name.upper() + name = LFF_FONTS.get(font_upper, "") + if font_manager.has_font(name): + return name + if not font_upper.endswith(".SHX"): + lff_name = font_name + ".lff" + else: + lff_name = font_name[:-4] + ".lff" + if font_manager.has_font(lff_name): + return lff_name + return font_name + + +def is_shx_font_name(font_name: str) -> bool: + name = font_name.lower() + if name.endswith(".shx"): + return True + if "." not in name: + return True + return False + + +def map_ttf_to_shx(ttf: str) -> Optional[str]: + """Maps .ttf filenames to .shx font names. e.g. "txt_____.ttf" -> "TXT" """ + return TTF_TO_SHX.get(ttf.lower()) + + +def build_system_font_cache() -> None: + """Builds or rebuilds the font manager cache. The font manager cache has a fixed + location in the cache directory of the users home directory "~/.cache/ezdxf" or the + directory specified by the environment variable "XDG_CACHE_HOME". + """ + build_font_manager_cache(_get_font_manager_path()) + + +def find_font_face(font_name: str) -> FontFace: + """Returns the :class:`FontFace` definition for the given font filename + e.g. "LiberationSans-Regular.ttf". + + """ + return font_manager.get_font_face(font_name) + + +def get_font_face(font_name: str, map_shx=True) -> FontFace: + """Returns the :class:`FontFace` definition for the given font filename + e.g. "LiberationSans-Regular.ttf". + + This function translates a DXF font definition by the TTF font file name into a + :class:`FontFace` object. Returns the :class:`FontFace` of the default font when a + font is not available on the current system. + + Args: + font_name: raw font file name as stored in the + :class:`~ezdxf.entities.Textstyle` entity + map_shx: maps SHX font names to TTF replacement fonts, + e.g. "TXT" -> "txt_____.ttf" + + """ + if not isinstance(font_name, str): + raise TypeError("font_name has invalid type") + if map_shx: + font_name = map_shx_to_ttf(font_name) + return find_font_face(font_name) + + +def resolve_shx_font_name(font_name: str, order: str) -> str: + """Resolves a .shx font name, the argument `order` defines the resolve order: + + - "t" = map .shx fonts to TrueType fonts (.ttf, .ttc, .otf) + - "s" = use shapefile fonts (.shx, .shp) + - "l" = map .shx fonts to LibreCAD fonts (.lff) + + """ + if len(order) == 0: + return font_name + order = order.lower() + for type_str in order: + if type_str == "t": + name = map_shx_to_ttf(font_name) + if font_manager.has_font(name): + return name + elif type_str == "s": + if not font_name.lower().endswith(".shx"): + font_name += ".shx" + if font_manager.has_font(font_name): + return font_name + elif type_str == "l": + name = map_shx_to_lff(font_name) + if font_manager.has_font(name): + return name + return font_name + + +def resolve_font_face(font_name: str, order="tsl") -> FontFace: + """Returns the :class:`FontFace` definition for the given font filename + e.g. "LiberationSans-Regular.ttf". + + This function translates a DXF font definition by the TTF font file name into a + :class:`FontFace` object. Returns the :class:`FontFace` of the default font when a + font is not available on the current system. + + The order argument defines the resolve order for .shx fonts: + + - "t" = map .shx fonts to TrueType fonts (.ttf, .ttc, .otf) + - "s" = use shapefile fonts (.shx, .shp) + - "l" = map .shx fonts to LibreCAD fonts (.lff) + + Args: + font_name: raw font file name as stored in the + :class:`~ezdxf.entities.Textstyle` entity + order: resolving order + + """ + if not isinstance(font_name, str): + raise TypeError("font_name has invalid type") + if is_shx_font_name(font_name): + font_name = resolve_shx_font_name(font_name, order) + return find_font_face(font_name) + + +def get_font_measurements(font_name: str, map_shx=True) -> FontMeasurements: + """Get :class:`FontMeasurements` for the given font filename + e.g. "LiberationSans-Regular.ttf". + + Args: + font_name: raw font file name as stored in the + :class:`~ezdxf.entities.Textstyle` entity + map_shx: maps SHX font names to TTF replacement fonts, + e.g. "TXT" -> "txt_____.ttf" + + """ + if map_shx: + font_name = map_shx_to_ttf(font_name) + elif is_shx_font_name(font_name): + return FontMeasurements( + baseline=0, + cap_height=1, + x_height=X_HEIGHT_FACTOR, + descender_height=DESCENDER_FACTOR, + ) + font = TrueTypeFont(font_name, cap_height=1) + return font.measurements + + +def find_best_match( + *, + family: str = "sans-serif", + style: str = "Regular", + weight: int = 400, + width: int = 5, + italic: Optional[bool] = False, +) -> Optional[FontFace]: + """Returns a :class:`FontFace` that matches the given properties best. The search + is based the descriptive properties and not on comparing glyph shapes. Returns + ``None`` if no font was found. + + Args: + family: font family name e.g. "sans-serif", "Liberation Sans" + style: font style e.g. "Regular", "Italic", "Bold" + weight: weight in the range from 1-1000 (usWeightClass) + width: width in the range from 1-9 (usWidthClass) + italic: ``True``, ``False`` or ``None`` to ignore this flag + + """ + return font_manager.find_best_match(family, style, weight, width, italic) + + +def find_font_file_name(font_face: FontFace) -> str: + """Returns the true type font file name without parent directories e.g. "Arial.ttf".""" + return font_manager.find_font_name(font_face) + + +def load(): + """Reload all cache files. The cache files are loaded automatically at the import + of `ezdxf`. + """ + _load_font_manager() + # Add font name synonyms, see discussion #1002 + # Find macOS fonts on Windows/Linux and vice versa. + font_manager.add_synonyms(FONT_SYNONYMS, reverse=True) + + +def _get_font_manager_path(): + cache_path = options.xdg_path("XDG_CACHE_HOME", CACHE_DIRECTORY) + return cache_path / FONT_MANAGER_CACHE_FILE + + +def _load_font_manager() -> None: + fm_path = _get_font_manager_path() + if fm_path.exists(): + try: + font_manager.loads(fm_path.read_text()) + return + except IOError as e: + logger.info(f"Error loading cache file: {str(e)}") + build_font_manager_cache(fm_path) + + +def build_sut_font_manager_cache(repo_font_path: pathlib.Path) -> None: + """Load font manger cache for system under test (sut). + + Load the fonts included in the repository folder "./fonts" to guarantee the tests + have the same fonts available on all systems. + + This function should be called from "conftest.py". + + """ + global SUT_FONT_MANAGER_CACHE + SUT_FONT_MANAGER_CACHE = True + font_manager.clear() + cache_file = repo_font_path / "font_manager_cache.json" + if cache_file.exists(): + try: + font_manager.loads(cache_file.read_text()) + return + except IOError as e: + print(f"Error loading cache file: {str(e)}") + font_manager.build([str(repo_font_path)], support_dirs=False) + s = font_manager.dumps() + try: + cache_file.write_text(s) + except IOError as e: + print(f"Error writing cache file: {str(e)}") + + +def make_cache_directory(path: pathlib.Path) -> None: + if not path.exists(): + try: + path.mkdir(parents=True) + except IOError: + pass + + +def build_font_manager_cache(path: pathlib.Path) -> None: + font_manager.clear() + font_manager.build() + s = font_manager.dumps() + cache_dir = path.parent + make_cache_directory(cache_dir) + if not cache_dir.exists(): + logger.warning( + f"Cannot create cache home directory: '{str(cache_dir)}', cache files will " + f"not be saved.\nSee also issue https://github.com/mozman/ezdxf/issues/923." + ) + return + try: + path.write_text(s) + except IOError as e: + logger.warning(f"Error writing cache file: '{str(e)}'") + + +class FontRenderType(enum.Enum): + # render glyphs as filled paths: TTF, OTF + OUTLINE = enum.auto() + + # render glyphs as line strokes: SHX, SHP + STROKE = enum.auto + + +class AbstractFont: + """The `ezdxf` font abstraction for text measurement and text path rendering.""" + + font_render_type = FontRenderType.STROKE + name: str = "undefined" + + def __init__(self, measurements: FontMeasurements): + self.measurements = measurements + + @abc.abstractmethod + def text_width(self, text: str) -> float: + """Returns the text width in drawing units for the given `text` string.""" + pass + + @abc.abstractmethod + def text_width_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + """Returns the text width in drawing units, bypasses the stored `cap_height` and + `width_factor`. + """ + pass + + @abc.abstractmethod + def space_width(self) -> float: + """Returns the width of a "space" character a.k.a. word spacing.""" + pass + + @abc.abstractmethod + def text_path(self, text: str) -> GlyphPath: + """Returns the 2D text path for the given text.""" + ... + + @abc.abstractmethod + def text_path_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> GlyphPath: + """Returns the 2D text path for the given text, bypasses the stored `cap_height` + and `width_factor`.""" + ... + + @abc.abstractmethod + def text_glyph_paths( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> list[GlyphPath]: + """Returns a list of 2D glyph paths for the given text, bypasses the stored + `cap_height` and `width_factor`.""" + ... + + +class MonospaceFont(AbstractFont): + """Represents a monospaced font where each letter has the same cap- and descender + height and the same width. The given cap height and width factor are the default + values for measurements and rendering. The extended methods can override these + default values. + + This font exists only for generic text measurement in tests and does not render any + glyphs! + + """ + + font_render_type = FontRenderType.STROKE + name = MONOSPACE + + def __init__( + self, + cap_height: float, + width_factor: float = 1.0, + baseline: float = 0, + descender_factor: float = DESCENDER_FACTOR, + x_height_factor: float = X_HEIGHT_FACTOR, + ): + super().__init__( + FontMeasurements( + baseline=baseline, + cap_height=cap_height, + x_height=cap_height * x_height_factor, + descender_height=cap_height * descender_factor, + ) + ) + self._width_factor: float = abs(width_factor) + self._space_width = self.measurements.cap_height * self._width_factor + + def text_width(self, text: str) -> float: + """Returns the text width in drawing units for the given `text`.""" + return self.text_width_ex( + text, self.measurements.cap_height, self._width_factor + ) + + def text_width_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + """Returns the text width in drawing units, bypasses the stored `cap_height` and + `width_factor`. + """ + return len(text) * cap_height * width_factor + + def text_path(self, text: str) -> GlyphPath: + """Returns the rectangle text width x cap height as :class:`NumpyPath2d` instance.""" + return self.text_path_ex(text, self.measurements.cap_height, self._width_factor) + + def text_path_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> GlyphPath: + """Returns the rectangle text width x cap height as :class:`NumpyPath2d` + instance, bypasses the stored `cap_height` and `width_factor`. + """ + from ezdxf.path import Path + + text_width = self.text_width_ex(text, cap_height, width_factor) + p = Path((0, 0)) + p.line_to((text_width, 0)) + p.line_to((text_width, cap_height)) + p.line_to((0, cap_height)) + p.close() + return GlyphPath(p) + + def text_glyph_paths( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> list[GlyphPath]: + """Returns the same rectangle as the method :meth:`text_path_ex` in a list.""" + return [self.text_path_ex(text, cap_height, width_factor)] + + def space_width(self) -> float: + """Returns the width of a "space" char.""" + return self._space_width + + +class _CachedFont(AbstractFont, abc.ABC): + """Abstract font with caching support.""" + + _glyph_caches: dict[str, Glyphs] = dict() + + def __init__(self, font_name: str, cap_height: float, width_factor: float = 1.0): + self.name = font_name + cache = self.create_cache(font_name) + self.glyph_cache = cache + self.cap_height = float(cap_height) + self.width_factor = float(width_factor) + scale_factor: float = cache.get_scaling_factor(self.cap_height) + super().__init__(cache.font_measurements.scale(scale_factor)) + self._space_width: float = ( + self.glyph_cache.space_width * scale_factor * width_factor + ) + + @abc.abstractmethod + def create_cache(self, font_name: str) -> Glyphs: + ... + + def text_width(self, text: str) -> float: + """Returns the text width in drawing units for the given `text` string.""" + return self.text_width_ex(text, self.cap_height, self.width_factor) + + def text_width_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + """Returns the text width in drawing units, bypasses the stored `cap_height` and + `width_factor`. + """ + if not text.strip(): + return 0 + return self.glyph_cache.get_text_length(text, cap_height, width_factor) + + def text_path(self, text: str) -> GlyphPath: + """Returns the 2D text path for the given text.""" + + return self.text_path_ex(text, self.cap_height, self.width_factor) + + def text_path_ex( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> GlyphPath: + """Returns the 2D text path for the given text, bypasses the stored `cap_height` + and `width_factor`.""" + return self.glyph_cache.get_text_path(text, cap_height, width_factor) + + def text_glyph_paths( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> list[GlyphPath]: + """Returns a list of 2D glyph paths for the given text, bypasses the stored + `cap_height` and `width_factor`.""" + return self.glyph_cache.get_text_glyph_paths(text, cap_height, width_factor) + + def space_width(self) -> float: + """Returns the width of a "space" char.""" + return self._space_width + + +class TrueTypeFont(_CachedFont): + """Represents a TrueType font. Font measurement and glyph rendering is done by the + `fontTools` package. The given cap height and width factor are the default values + for measurements and glyph rendering. The extended methods can override these + default values. + """ + + font_render_type = FontRenderType.OUTLINE + + def create_cache(self, ttf: str) -> Glyphs: + from .ttfonts import TTFontRenderer + + key = pathlib.Path(ttf).name.lower() + try: + return self._glyph_caches[key] + except KeyError: + pass + try: + tt_font = font_manager.get_ttf_font(ttf) + try: # see issue #990 + cache = TTFontRenderer(tt_font) + except Exception: + raise UnsupportedFont + except UnsupportedFont: + fallback_font_name = font_manager.fallback_font_name() + logger.info(f"replacing unsupported font '{ttf}' by '{fallback_font_name}'") + cache = TTFontRenderer(font_manager.get_ttf_font(fallback_font_name)) + self._glyph_caches[key] = cache + return cache + + +class _UnmanagedTrueTypeFont(_CachedFont): + font_render_type = FontRenderType.OUTLINE + + def create_cache(self, ttf: str) -> Glyphs: + from .ttfonts import TTFontRenderer + from fontTools.ttLib import TTFont + + key = ttf.lower() + try: + return self._glyph_caches[key] + except KeyError: + pass + cache = TTFontRenderer(TTFont(ttf, fontNumber=0)) + self._glyph_caches[key] = cache + return cache + + +def sideload_ttf(font_path: str | os.PathLike, cap_height) -> AbstractFont: + """This function bypasses the FontManager and loads the TrueType font straight from + the file system, requires the absolute font file path e.g. "C:/Windows/Fonts/Arial.ttf". + + .. warning:: + + Expert feature, use with care: no fallback font and no error handling. + + """ + + return _UnmanagedTrueTypeFont(str(font_path), cap_height) + + +class ShapeFileFont(_CachedFont): + """Represents a shapefile font (.shx, .shp). Font measurement and glyph rendering is + done by the ezdxf.fonts.shapefile module. The given cap height and width factor are + the default values for measurements and glyph rendering. The extended methods can + override these default values. + + """ + + font_render_type = FontRenderType.STROKE + + def create_cache(self, font_name: str) -> Glyphs: + key = font_name.lower() + try: + return self._glyph_caches[key] + except KeyError: + pass + glyph_cache = font_manager.get_shapefile_glyph_cache(font_name) + self._glyph_caches[key] = glyph_cache + return glyph_cache + + +class LibreCadFont(_CachedFont): + """Represents a LibreCAD font (.shx, .shp). Font measurement and glyph rendering is + done by the ezdxf.fonts.lff module. The given cap height and width factor are the + default values for measurements and glyph rendering. The extended methods can + override these default values. + + """ + + font_render_type = FontRenderType.STROKE + + def create_cache(self, font_name: str) -> Glyphs: + key = font_name.lower() + try: + return self._glyph_caches[key] + except KeyError: + pass + glyph_cache = font_manager.get_lff_glyph_cache(font_name) + self._glyph_caches[key] = glyph_cache + return glyph_cache + + +def make_font( + font_name: str, cap_height: float, width_factor: float = 1.0 +) -> AbstractFont: + r"""Returns a font abstraction based on class :class:`AbstractFont`. + + Supported font types: + + - .ttf, .ttc and .otf - TrueType fonts + - .shx, .shp - Autodesk® shapefile fonts + - .lff - LibreCAD font format + + The special name "\*monospace" returns the fallback font :class:`MonospaceFont` for + testing and basic measurements. + + .. note:: The font definition files are not included in `ezdxf`. + + Args: + font_name: font file name as stored in the :class:`~ezdxf.entities.Textstyle` + entity e.g. "OpenSans-Regular.ttf" + cap_height: desired cap height in drawing units. + width_factor: horizontal text stretch factor + + """ + if font_name == MONOSPACE: + return MonospaceFont(cap_height, width_factor) + ext = pathlib.Path(font_name).suffix.lower() + last_resort = MonospaceFont(cap_height, width_factor) + if ext in SUPPORTED_TTF_TYPES: + try: + return TrueTypeFont(font_name, cap_height, width_factor) + except FontNotFoundError as e: + logger.warning(f"no default font found: {str(e)}") + return last_resort + elif ext == ".shx" or ext == ".shp": + try: + return ShapeFileFont(font_name, cap_height, width_factor) + except FontNotFoundError: + pass + except UnsupportedFont: + # change name - the font exists but is not supported + font_name = font_manager.fallback_font_name() + elif ext == ".lff": + try: + return LibreCadFont(font_name, cap_height, width_factor) + except FontNotFoundError: + pass + elif ext == "": # e.g. "TXT" + font_face = font_manager.find_best_match( + family=font_name, style=".shx", italic=None + ) + if font_face is not None: + return make_font(font_face.filename, cap_height, width_factor) + else: + logger.warning(f"unsupported font-name suffix: {font_name}") + font_name = font_manager.fallback_font_name() + + # return default TrueType font + try: + return TrueTypeFont(font_name, cap_height, width_factor) + except FontNotFoundError as e: + logger.warning(f"no default font found: {str(e)}") + return last_resort + + +def get_entity_font_face(entity: DXFEntity, doc: Optional[Drawing] = None) -> FontFace: + """Returns the :class:`FontFace` defined by the associated text style. + Returns the default font face if the `entity` does not have or support + the DXF attribute "style". Supports the extended font information stored in + :class:`~ezdxf.entities.Textstyle` table entries. + + Pass a DXF document as argument `doc` to resolve text styles for virtual + entities which are not assigned to a DXF document. The argument `doc` + always overrides the DXF document to which the `entity` is assigned to. + + """ + if entity.doc and doc is None: + doc = entity.doc + if doc is None: + return FontFace() + + style_name = "" + # This works also for entities which do not support "style", + # where style_name = entity.dxf.get("style") would fail. + if entity.dxf.is_supported("style"): + style_name = entity.dxf.style + + font_face = FontFace() + if style_name: + style = cast("Textstyle", doc.styles.get(style_name)) + family, italic, bold = style.get_extended_font_data() + if family: + text_style = "Italic" if italic else "Regular" + text_weight = 700 if bold else 400 + font_face = FontFace(family=family, style=text_style, weight=text_weight) + else: + ttf = style.dxf.font + if ttf: + font_face = get_font_face(ttf) + return font_face + + +load() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/glyphs.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/glyphs.py new file mode 100644 index 0000000..7e7cc2f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/glyphs.py @@ -0,0 +1,39 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing_extensions import TypeAlias +import abc + +from ezdxf.npshapes import NumpyPath2d +from .font_measurements import FontMeasurements + +GlyphPath: TypeAlias = NumpyPath2d + + +class Glyphs(abc.ABC): + font_measurements: FontMeasurements # of the raw font + space_width: float # word spacing of the raw font + + @abc.abstractmethod + def get_scaling_factor(self, cap_height: float) -> float: + ... + + @abc.abstractmethod + def get_text_length( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + ... + + def get_text_path( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> GlyphPath: + glyph_paths = self.get_text_glyph_paths(text, cap_height, width_factor) + if len(glyph_paths) == 0: + return GlyphPath(None) + return NumpyPath2d.concatenate(glyph_paths) + + @abc.abstractmethod + def get_text_glyph_paths( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> list[GlyphPath]: + ... diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/lff.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/lff.py new file mode 100644 index 0000000..e8dd9d8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/lff.py @@ -0,0 +1,324 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +# +# Basic tools for the LibreCAD Font Format: +# https://github.com/Rallaz/LibreCAD/wiki/lff-definition +from __future__ import annotations +from typing import Sequence, Iterator, Iterable, Optional, no_type_check +from typing_extensions import TypeAlias +from ezdxf.math import Vec2, BoundingBox2d, Matrix44 +from ezdxf import path +from .font_measurements import FontMeasurements +from .glyphs import GlyphPath, Glyphs + +__all__ = ["loads", "LCFont", "Glyph", "GlyphCache"] + + +def loads(s: str) -> LCFont: + lines = s.split("\n") + name, letter_spacing, word_spacing = parse_properties(lines) + lcf = LCFont(name, letter_spacing, word_spacing) + for glyph, parent_code in parse_glyphs(lines): + lcf.add(glyph, parent_code) + return lcf + + +class LCFont: + """Low level representation of LibreCAD fonts.""" + def __init__( + self, name: str = "", letter_spacing: float = 0.0, word_spacing: float = 0.0 + ) -> None: + self.name: str = name + self.letter_spacing: float = letter_spacing + self.word_spacing: float = word_spacing + self._glyphs: dict[int, Glyph] = dict() + + def __len__(self) -> int: + return len(self._glyphs) + + def __getitem__(self, item: int) -> Glyph: + return self._glyphs[item] + + def add(self, glyph: Glyph, parent_code: int = 0) -> None: + if parent_code: + try: + parent_glyph = self._glyphs[parent_code] + except KeyError: + return + glyph = parent_glyph.extend(glyph) + self._glyphs[glyph.code] = glyph + + def get(self, code: int) -> Optional[Glyph]: + return self._glyphs.get(code, None) + + +Polyline: TypeAlias = Sequence[Sequence[float]] + + +class Glyph: + """Low level representation of a LibreCAD glyph.""" + __slots__ = ("code", "polylines") + + def __init__(self, code: int, polylines: Sequence[Polyline]): + self.code: int = code + self.polylines: Sequence[Polyline] = tuple(polylines) + + def extend(self, glyph: Glyph) -> Glyph: + polylines = list(self.polylines) + polylines.extend(glyph.polylines) + return Glyph(glyph.code, polylines) + + def to_path(self) -> GlyphPath: + from ezdxf.math import OCS + + final_path = path.Path() + ocs = OCS() + for polyline in self.polylines: + p = path.Path() # empty path is required + path.add_2d_polyline( + p, convert_bulge_values(polyline), close=False, elevation=0, ocs=ocs + ) + final_path.extend_multi_path(p) + return GlyphPath(final_path) + + +def convert_bulge_values(polyline: Polyline) -> Iterator[Sequence[float]]: + # In DXF the bulge value is always stored at the start vertex of the arc. + last_index = len(polyline) - 1 + for index, vertex in enumerate(polyline): + bulge = 0.0 + if index < last_index: + next_vertex = polyline[index + 1] + try: + bulge = next_vertex[2] + except IndexError: + pass + yield vertex[0], vertex[1], bulge + + +def parse_properties(lines: list[str]) -> tuple[str, float, float]: + font_name = "" + letter_spacing = 0.0 + word_spacing = 0.0 + for line in lines: + line = line.strip() + if not line.startswith("#"): + continue + try: + name, value = line.split(":") + except ValueError: + continue + + name = name[1:].strip() + if name == "Name": + font_name = value.strip() + elif name == "LetterSpacing": + try: + letter_spacing = float(value) + except ValueError: + continue + elif name == "WordSpacing": + try: + word_spacing = float(value) + except ValueError: + continue + return font_name, letter_spacing, word_spacing + + +def scan_glyphs(lines: Iterable[str]) -> Iterator[list[str]]: + glyph: list[str] = [] + for line in lines: + if line.startswith("["): + if glyph: + yield glyph + glyph.clear() + if line: + glyph.append(line) + if glyph: + yield glyph + + +def strip_clutter(lines: list[str]) -> Iterator[str]: + for line in lines: + line = line.strip() + if not line.startswith("#"): + yield line + + +def scan_int_ex(s: str) -> int: + from string import hexdigits + + if len(s) == 0: + return 0 + try: + end = s.index("]") + except ValueError: + end = len(s) + s = s[1:end].lower() + s = "".join(c for c in s if c in hexdigits) + try: + return int(s, 16) + except ValueError: + return 0 + + +def parse_glyphs(lines: list[str]) -> Iterator[tuple[Glyph, int]]: + code: int + polylines: list[Polyline] = [] + for glyph in scan_glyphs(strip_clutter(lines)): + parent_code: int = 0 + polylines.clear() + line = glyph.pop(0) + if line[0] != "[": + continue + try: + code = int(line[1 : line.index("]")], 16) + except ValueError: + code = scan_int_ex(line) + if code == 0: + continue + line = glyph[0] + if line.startswith("C"): + glyph.pop(0) + try: + parent_code = int(line[1:], 16) + except ValueError: + continue + polylines = list(parse_polylines(glyph)) + yield Glyph(code, polylines), parent_code + + +def parse_polylines(lines: Iterable[str]) -> Iterator[Polyline]: + polyline: list[Sequence[float]] = [] + for line in lines: + polyline.clear() + for vertex in line.split(";"): + values = to_floats(vertex.split(",")) + if len(values) > 1: + polyline.append(values[:3]) + yield tuple(polyline) + + +def to_floats(values: Iterable[str]) -> Sequence[float]: + def strip(value: str) -> float: + if value.startswith("A"): + value = value[1:] + try: + return float(value) + except ValueError: + return 0.0 + + return tuple(strip(value) for value in values) + + +class GlyphCache(Glyphs): + """Text render engine for LibreCAD fonts with integrated glyph caching.""" + + def __init__(self, font: LCFont) -> None: + self.font: LCFont = font + self._glyph_cache: dict[int, GlyphPath] = dict() + self._advance_width_cache: dict[int, float] = dict() + self.space_width: float = self.font.word_spacing + self.empty_box: GlyphPath = self.get_empty_box() + self.font_measurements: FontMeasurements = self._get_font_measurements() + + def get_scaling_factor(self, cap_height: float) -> float: + try: + return cap_height / self.font_measurements.cap_height + except ZeroDivisionError: + return 1.0 + + def get_empty_box(self) -> GlyphPath: + glyph_A = self.get_shape(65) + box = BoundingBox2d(glyph_A.control_vertices()) + height = box.size.y + width = box.size.x + start = glyph_A.start + p = path.Path(start) + p.line_to(start + Vec2(width, 0)) + p.line_to(start + Vec2(width, height)) + p.line_to(start + Vec2(0, height)) + p.close() + p.move_to(glyph_A.end) + return GlyphPath(p) + + def _render_shape(self, shape_number) -> GlyphPath: + try: + glyph = self.font[shape_number] + except KeyError: + if shape_number > 32: + return self.empty_box + raise ValueError("space and non-printable characters are not glyphs") + return glyph.to_path() + + def get_shape(self, shape_number: int) -> GlyphPath: + if shape_number <= 32: + raise ValueError("space and non-printable characters are not glyphs") + try: + return self._glyph_cache[shape_number].clone() + except KeyError: + pass + glyph = self._render_shape(shape_number) + self._glyph_cache[shape_number] = glyph + advance_width = 0.0 + if len(glyph): + box = glyph.bbox() + assert box.extmax is not None + advance_width = box.extmax.x + self.font.letter_spacing + self._advance_width_cache[shape_number] = advance_width + return glyph.clone() + + def get_advance_width(self, shape_number: int) -> float: + if shape_number < 32: + return 0.0 + if shape_number == 32: + return self.space_width + try: + return self._advance_width_cache[shape_number] + except KeyError: + pass + _ = self.get_shape(shape_number) + return self._advance_width_cache[shape_number] + + @no_type_check + def _get_font_measurements(self) -> FontMeasurements: + # ignore last move_to command, which places the pen at the start of the + # following glyph + bbox = BoundingBox2d(self.get_shape(ord("x")).control_vertices()) + baseline = bbox.extmin.y + x_height = bbox.extmax.y - baseline + + bbox = BoundingBox2d(self.get_shape(ord("A")).control_vertices()) + cap_height = bbox.extmax.y - baseline + bbox = BoundingBox2d(self.get_shape(ord("p")).control_vertices()) + descender_height = baseline - bbox.extmin.y + return FontMeasurements( + baseline=baseline, + cap_height=cap_height, + x_height=x_height, + descender_height=descender_height, + ) + + def get_text_length( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + scaling_factor = self.get_scaling_factor(cap_height) * width_factor + return sum(self.get_advance_width(ord(c)) for c in text) * scaling_factor + + def get_text_glyph_paths( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> list[GlyphPath]: + glyph_paths: list[GlyphPath] = [] + sy = self.get_scaling_factor(cap_height) + sx = sy * width_factor + m = Matrix44.scale(sx, sy, 1) + current_location = 0.0 + for c in text: + shape_number = ord(c) + if shape_number > 32: + glyph = self.get_shape(shape_number) + m[3, 0] = current_location + glyph.transform_inplace(m) + glyph_paths.append(glyph) + current_location += self.get_advance_width(shape_number) * sx + return glyph_paths diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/shapefile.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/shapefile.py new file mode 100644 index 0000000..eb68c35 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/shapefile.py @@ -0,0 +1,1045 @@ +# Copyright (c) 2022-2023, Manfred Moitzi +# License: MIT License + +""" +This module provides support for fonts stored as SHX and SHP files. +(SHP is not the GIS file format!) + +The documentation about the SHP file format can be found at Autodesk: +https://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-DE941DB5-7044-433C-AA68-2A9AE98A5713 + +Using bytes for strings because no encoding is defined in shape-files. + +""" +from __future__ import annotations +from typing import ( + Sequence, + Iterable, + Iterator, + Callable, + Optional, + Any, + Set, + no_type_check, +) +import dataclasses +import enum +import math +import pathlib + +from ezdxf.math import ( + UVec, + Vec2, + ConstructionEllipse, + bulge_to_arc, + BoundingBox2d, + Matrix44, +) +from ezdxf import path +from .font_measurements import FontMeasurements +from .glyphs import GlyphPath, Glyphs + + +class ShapeFileException(Exception): + pass + + +class UnsupportedShapeFile(ShapeFileException): + pass + + +class UnsupportedShapeNumber(ShapeFileException): + pass + + +class InvalidFontDefinition(ShapeFileException): + pass + + +class InvalidFontParameters(ShapeFileException): + pass + + +class InvalidShapeRecord(ShapeFileException): + pass + + +class FileStructureError(ShapeFileException): + pass + + +class StackUnderflow(ShapeFileException): + pass + + +class FontEmbedding(enum.IntEnum): + ALLOWED = 0 + DISALLOWED = 1 + READONLY = 2 + + +class FontEncoding(enum.IntEnum): + UNICODE = 0 + PACKED_MULTIBYTE_1 = 1 + SHAPE_FILE = 2 + + +class FontMode(enum.IntEnum): + HORIZONTAL = 0 + BIDIRECT = 2 + + +NO_DATA: Sequence[int] = tuple() +DEBUG = False +DEBUG_CODES: Set[int] = set() +DEBUG_SHAPE_NUMBERS = set() +ORD_NULL = ord("0") +ORD_MINUS = ord("-") + + +# slots=True - Python 3.10+ +@dataclasses.dataclass +class Symbol: + number: int + byte_count: int + name: bytes + data: Sequence[int] = NO_DATA + + def export_str(self, as_num: int = 0) -> list[bytes]: + num = as_num if as_num else self.number + export = [f"*{num:05X},{self.byte_count},".encode() + self.name] + export.extend(format_shape_data_string(self.data)) + return export + + +def format_shape_data_string(data: Sequence[int]) -> list[bytes]: + export = [] + s = b"" + for num in data: + s2 = s + f"{num},".encode() + if len(s2) < 80: + s = s2 + else: + export.append(s[:-1]) + s = f",{num},".encode() + if s: + export.append(s[:-1]) + return export + + +class ShapeFile: + """Low level representation of a SHX/SHP file.""" + def __init__( + self, + name: bytes, + above: int, + below: int, + mode=FontMode.HORIZONTAL, + encoding=FontEncoding.UNICODE, + embed=FontEmbedding.ALLOWED, + ): + self.shapes: dict[int, Symbol] = dict() + self.name = name + self.above = above + self.below = below + self.mode = mode + self.encoding = encoding + self.embed = embed + + @property + def cap_height(self) -> float: + return float(self.above) + + @property + def descender(self) -> float: + return float(self.below) + + @property + def is_font(self) -> bool: + return self.encoding != FontEncoding.SHAPE_FILE + + @property + def is_shape_file(self) -> bool: + return self.encoding == FontEncoding.SHAPE_FILE + + def find(self, name: bytes) -> Optional[Symbol]: + for symbol in self.shapes.values(): + if name == symbol.name: + return symbol + return None + + def __len__(self): + return len(self.shapes) + + def __getitem__(self, item): + return self.shapes[item] + + @staticmethod + def from_ascii_records(records: Sequence[bytes]): + if len(records) == 2: + encoding = FontEncoding.UNICODE + above = 0 + below = 0 + embed = FontEmbedding.ALLOWED + mode = FontMode.HORIZONTAL + end = 0 + header, params = records + try: + # ignore second value: defbytes + spec, _, name = header.split(b",", maxsplit=2) + except ValueError: + raise InvalidFontDefinition() + if spec == b"*UNIFONT": + try: + above, below, mode, encoding, embed, end = params.split(b",") # type: ignore + except ValueError: + raise InvalidFontParameters(params) + elif spec == b"*0": + try: + above, below, mode, *rest = params.split(b",") # type: ignore + end = rest[-1] # type: ignore + except ValueError: + raise InvalidFontParameters(params) + else: # it's a simple shape file + encoding = FontEncoding.SHAPE_FILE + assert int(end) == 0 + + return ShapeFile( + name.strip(), + int(above), + int(below), + FontMode(int(mode)), + FontEncoding(int(encoding)), + FontEmbedding(int(embed)), + ) + + def parse_ascii_records(self, records: Iterable[Sequence[bytes]]) -> None: + for record in records: + if len(record) < 2: + raise InvalidShapeRecord(record) + try: + number, byte_count, name = split_def_record(record[0]) + except ValueError: + raise FileStructureError(record[0]) + + assert len(number) > 1 + if number[1] == ORD_NULL: # hex if first char is "0" like "*0000A" + int_num = int(number[1:], 16) + else: # like "*130" + int_num = int(number[1:], 10) + + symbol = Symbol(int_num, int(byte_count), name) + data = b"".join(record[1:]) + symbol.data = tuple(parse_codes(split_record(data))) + if symbol.data[-1] == 0: + self.shapes[int_num] = symbol + else: + s = record[0].decode(errors="ignore") + raise FileStructureError(f"file structure error at symbol <{s}>") + + def get_codes(self, number: int) -> Sequence[int]: + symbol = self.shapes.get(number) + if symbol is None: + raise UnsupportedShapeNumber(number) + return symbol.data + + def render_shape(self, number: int, stacked=False) -> GlyphPath: + return render_shapes([number], self.get_codes, stacked=stacked) + + def render_shapes(self, numbers: Sequence[int], stacked=False) -> GlyphPath: + return render_shapes(numbers, self.get_codes, stacked=stacked) + + def render_text(self, text: str, stacked=False) -> GlyphPath: + numbers = [ord(char) for char in text] + return render_shapes( + numbers, self.get_codes, stacked=stacked, reset_to_baseline=True + ) + + def shape_string(self, shape_number: int, as_num: int = 0) -> list[bytes]: + return self.shapes[shape_number].export_str(as_num) + + +def readfile(filename: str) -> ShapeFile: + """Load shape-file `filename`, the file type is detected by the file + name extension and should be ".shp" or ".shx" otherwise rises an + exception :class:`UnsupportedShapeFile`. + """ + data = pathlib.Path(filename).read_bytes() + filename = filename.lower() + if filename.endswith(".shp"): + return shp_load(data) + elif filename.endswith(".shx"): + return shx_load(data) + else: + raise UnsupportedShapeFile("unknown filetype") + + +def split_def_record(record: bytes) -> Sequence[bytes]: + return tuple(s.strip() for s in record.split(b",", maxsplit=2)) + + +def split_record(record: bytes) -> Sequence[bytes]: + return tuple(s.strip() for s in record.split(b",")) + + +def parse_codes(codes: Iterable[bytes]) -> Iterator[int]: + for code in codes: + code = code.strip(b"()") + if code == b"": + continue + if code[0] == ORD_NULL: + yield int(code, 16) + elif code[0] == ORD_MINUS and code[1] == ORD_NULL: + yield int(code, 16) + else: + yield int(code, 10) + + +def shp_load(data: bytes) -> ShapeFile: + records = parse_string_records(merge_lines(filter_noise(data.split(b"\n")))) + if b"*UNIFONT" in records: + font_definition = records.pop(b"*UNIFONT") + elif b"*0" in records: + font_definition = records.pop(b"*0") + else: + # a common shape file without a name + # symbol numbers are decimal!!! + font_definition = (b"_,_,_", b"") + shp = ShapeFile.from_ascii_records(font_definition) + shp.parse_ascii_records(records.values()) + return shp + + +def shx_load(data: bytes) -> ShapeFile: + if data.startswith(b"AutoCAD-86 shapes 1.0"): + return load_shx_shape_file_1_0(data) + elif data.startswith(b"AutoCAD-86 shapes 1.1"): + return load_shx_shape_file_1_1(data) + elif data.startswith(b"AutoCAD-86 unifont 1.0"): + return load_shx_unifont_file_1_0(data) + elif data.startswith(b"AutoCAD-86 bigfont 1.0"): + raise UnsupportedShapeFile("BIGFONT shapes are not supported yet") + raise UnsupportedShapeFile("unknown shape file format") + + +def load_shx_shape_file_1_0(data: bytes) -> ShapeFile: + above = 0 + below = 0 + mode = FontMode.HORIZONTAL + name = b"" + shapes = parse_shx_shapes(data) + font_definition = shapes.get(0) + if font_definition: + shapes.pop(0) + shape_data = font_definition.data + above = shape_data[0] + below = shape_data[1] + mode = FontMode(shape_data[2]) + + shape_file = ShapeFile(name, above=above, below=below, mode=mode) + shape_file.shapes = shapes + return shape_file + + +def load_shx_shape_file_1_1(data: bytes) -> ShapeFile: + # seems to be the same as v1.0: + return load_shx_shape_file_1_0(data) + + +class DataReader: + def __init__(self, data: bytes, index=0): + self.data = data + self.index = index + + @property + def has_data(self) -> bool: + return self.index < len(self.data) + + def skip(self, n: int) -> None: + self.index += n + + def u8(self) -> int: + index = self.index + self.index += 1 + return self.data[index] + + def i8(self) -> int: + value = self.data[self.index] + self.index += 1 + if value > 127: + return (value & 127) - 128 # ??? + return value + + def octant(self) -> int: + value = self.data[self.index] + self.index += 1 + if value & 128: + return -(value & 127) + else: + return value + + def read_str(self) -> bytes: + data = bytearray() + while True: + char = self.u8() + if char: + data.append(char) + else: + return data + + def read_bytes(self, n: int) -> bytes: + index = self.index + self.index += n + return self.data[index : index + n] + + def u16(self) -> int: + # little ending + index = self.index + self.index += 2 + return self.data[index] + (self.data[index + 1] << 8) + + +# the old 'AutoCAD-86 shapes 1.0' format +SHX_SHAPES_START_INDEX = 0x17 + + +def parse_shx_shapes(data: bytes) -> dict[int, Symbol]: + """SHX/SHP shape parser.""" + shapes: dict[int, Symbol] = dict() + reader = DataReader(data, SHX_SHAPES_START_INDEX) + if reader.u8() != 0x1A: + raise FileStructureError("signature byte 0x1A not found") + first_number = reader.u16() + last_number = reader.u16() + shape_count = reader.u16() + index_table: list[tuple[int, int]] = [] + for _ in range(shape_count): + shape_number = reader.u16() + data_size = reader.u16() + index_table.append((shape_number, data_size)) + if index_table[0][0] != first_number: + raise FileStructureError("invalid first entry in index table") + if index_table[-1][0] != last_number: + raise FileStructureError("invalid last entry in index table") + for shape_number, length in index_table: + record = reader.read_bytes(length) + try: + name, shape_data = parse_shx_data_record(record) + except IndexError: + raise FileStructureError( + f"SHX parsing error shape *{shape_number:05X}: {str(record)}" + ) + byte_count = length - len(name) - 1 + shapes[shape_number] = Symbol(shape_number, byte_count, name, shape_data) + if reader.read_bytes(3) != b"EOF": + raise FileStructureError("EOF marker not found") + return shapes + + +def parse_shx_data_record(data: bytes) -> tuple[bytes, Sequence[int]]: + """Low level SHX/SHP shape record parser.""" + reader = DataReader(data) + name = reader.read_str() + codes = parse_shape_codes(reader) + return name, codes + + +# the new 'AutoCAD-86 unifont 1.0' format +SHX_UNIFONT_START_INDEX = 0x18 + + +def load_shx_unifont_file_1_0(data: bytes) -> ShapeFile: + reader = DataReader(data, SHX_UNIFONT_START_INDEX) + name, above, below, mode, encoding, embed = parse_shx_unifont_definition(reader) + shape_file = ShapeFile( + name, + above=above, + below=below, + mode=mode, + encoding=encoding, + embed=embed, + ) + try: + shape_file.shapes = parse_shx_unifont_shapes(reader) + except IndexError: + raise FileStructureError("pre-mature end of file") + return shape_file + + +def parse_shx_unifont_definition(reader: DataReader) -> Sequence[Any]: + if reader.u8() != 0x1A: + raise FileStructureError("signature byte 0x1A not found") + reader.skip(6) + # u16 record count: in isocp.shx = 238 (0xEE 0x00) + # = 1 definition record + 237 character records + # u16 isocp.shx: 0 (0x00 0x00), always 0??? + # u16 font definition record size; isocp.shx: 52 (0x34 0x00) + + name = reader.read_str() + above = reader.u8() + below = reader.u8() + mode = FontMode(reader.u8()) + encoding = FontEncoding(reader.u8()) + embed = FontEmbedding(reader.u8()) + reader.skip(1) # <00> byte - end of font definition + return name, above, below, mode, encoding, embed + + +def parse_shx_unifont_shapes(reader: DataReader) -> dict[int, Symbol]: + shapes: dict[int, Symbol] = dict() + while reader.has_data: + shape_number = reader.u16() + byte_count = reader.u16() + name = reader.read_str() + byte_count = byte_count - len(name) - 1 + data_record = reader.read_bytes(byte_count) + codes = parse_shape_codes(DataReader(data_record), unifont=True) + shapes[shape_number] = Symbol(shape_number, byte_count, name, codes) + return shapes + + +SINGLE_CODES = {1, 2, 5, 6, 14} + + +def parse_shape_codes(reader: DataReader, unifont=False) -> Sequence[int]: + codes: list[int] = [] + while True: + code = reader.u8() + codes.append(code) + if code == 0: + return tuple(codes) + elif code in SINGLE_CODES or code > 14: + continue + elif code == 3 or code == 4: # size control + codes.append(reader.u8()) + elif code == 7: # sub shape + if unifont: + codes.append(reader.u16()) + else: + codes.append(reader.u8()) + elif code == 8: # displacement + codes.append(reader.i8()) + codes.append(reader.i8()) + elif code == 9: # multiple displacement + x, y = 1, 1 + while x or y: + x = reader.i8() + y = reader.i8() + codes.append(x) + codes.append(y) + elif code == 10: # octant arc + codes.append(reader.u8()) # radius + codes.append(reader.octant()) # octant specs + elif code == 11: # fractional arc + codes.append(reader.u8()) # start offset + codes.append(reader.u8()) # end offset + codes.append(reader.u8()) # radius hi + codes.append(reader.u8()) # radius lo + codes.append(reader.octant()) # octant specs + elif code == 12: # bulge arcs + codes.append(reader.i8()) # x + codes.append(reader.i8()) # y + codes.append(reader.i8()) # bulge + elif code == 13: # multiple bulge arcs + x, y = 1, 1 + while x or y: + x = reader.i8() + y = reader.i8() + codes.append(x) + codes.append(y) + if x or y: + codes.append(reader.i8()) + + +def filter_noise(lines: Iterable[bytes]) -> Iterator[bytes]: + for line in lines: + line.rstrip(b"\r\n") + line = line.strip() + if line: + line = line.split(b";")[0] + line = line.strip() + if line: + yield line + + +def merge_lines(lines: Iterable[bytes]) -> Iterator[bytes]: + current = b"" + for next_line in lines: + if not current: + current = next_line + elif current.startswith(b"*"): + if next_line.startswith(b","): # wrapped specification line? + current += next_line + else: + yield current + current = next_line + elif current.endswith(b","): + current += next_line + elif next_line.startswith(b","): + current += next_line + else: + yield current + current = next_line + if current: + yield current + + +def parse_string_records( + lines: Iterable[bytes], +) -> dict[bytes, Sequence[bytes]]: + records: dict[bytes, Sequence[bytes]] = dict() + name = None + record = [] + for line in lines: + if line.startswith(b"*BIGFONT"): + raise UnsupportedShapeFile("BIGFONT shape files are not supported yet") + if line.startswith(b"*"): + if name is not None: + records[name] = tuple(record) + name = line.split(b",")[0].strip() + record = [line] + else: + record.append(line) + + if name is not None: + records[name] = tuple(record) + return records + + +def render_shapes( + shape_numbers: Sequence[int], + get_codes: Callable[[int], Sequence[int]], + stacked: bool, + start: UVec = (0, 0), + reset_to_baseline=False, +) -> GlyphPath: + """Renders multiple shapes into a single glyph path.""" + ctx = ShapeRenderer( + path.Path(start), + pen_down=True, + stacked=stacked, + get_codes=get_codes, + ) + for shape_number in shape_numbers: + try: + ctx.render(shape_number, reset_to_baseline=reset_to_baseline) + except UnsupportedShapeNumber: + pass + except StackUnderflow: + raise StackUnderflow( + f"stack underflow while rendering shape number {shape_number}" + ) + # move cursor to the start of the next char??? + return GlyphPath(ctx.p) + + +# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F +VEC_X = [1, 1, 1, 0.5, 0, -0.5, -1, -1, -1, -1, -1, -0.5, 0, 0.5, 1, 1] +# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F +VEC_Y = [0, 0.5, 1, 1, 1, 1, 1, 0.5, 0, -0.5, -1, -1, -1, -1, -1, -0.5] + + +class ShapeRenderer: + """Low level glyph renderer for SHX/SHP fonts.""" + def __init__( + self, + p: path.Path, + get_codes: Callable[[int], Sequence[int]], + *, + vector_length: float = 1.0, + pen_down: bool = True, + stacked: bool = False, + ): + self.p = p + self.vector_length = float(vector_length) # initial vector length + self.pen_down = pen_down + self.stacked = stacked # vertical stacked text + self._location_stack: list[Vec2] = [] + self._get_codes = get_codes + self._baseline_y = self.p.start.y + + @property + def current_location(self) -> Vec2: + return Vec2(self.p.end) + + def push(self) -> None: + self._location_stack.append(self.current_location) + + def pop(self) -> None: + self.p.move_to(self._location_stack.pop()) + + def render( + self, + shape_number: int, + reset_to_baseline=False, + ) -> None: + self.pen_down = True + codes = self._get_codes(shape_number) + index = 0 + skip_next = False + while index < len(codes): + code = codes[index] + if DEBUG and (code in DEBUG_CODES) and shape_number: + DEBUG_SHAPE_NUMBERS.add(shape_number) + index += 1 + if code > 15 and not skip_next: + self.draw_vector(code) + elif code == 0: + break + elif code == 1 and not skip_next: # pen down + self.pen_down = True + elif code == 2 and not skip_next: # pen up + self.pen_down = False + elif code == 3 or code == 4: # scale size + factor = codes[index] + index += 1 + if not skip_next: + if code == 3: + self.vector_length /= factor + elif code == 4: + self.vector_length *= factor + continue + elif code == 5 and not skip_next: # push location state + self.push() + elif code == 6 and not skip_next: # pop location state + try: + self.pop() + except IndexError: + raise StackUnderflow() + elif code == 7: # sub-shape: + sub_shape_number = codes[index] + index += 1 + if not skip_next: + # Use current state of pen and location! + self.render(sub_shape_number) + # resume with current state of pen and location! + elif code == 8: # displacement vector + x = codes[index] + y = codes[index + 1] + index += 2 + if not skip_next: + self.draw_displacement(x, y) + elif code == 9: # multiple displacements vectors + while True: + x = codes[index] + y = codes[index + 1] + index += 2 + if x == 0 and y == 0: + break + if not skip_next: + self.draw_displacement(x, y) + elif code == 10: # 10 octant arc + radius = codes[index] + start_octant, octant_span, ccw = decode_octant_specs(codes[index + 1]) + if octant_span == 0: # full circle + octant_span = 8 + index += 2 + if not skip_next: + self.draw_arc_span( + radius * self.vector_length, + math.radians(start_octant * 45), + math.radians(octant_span * 45), + ccw, + ) + elif code == 11: # fractional arc + # TODO: this still seems not 100% correct, see vertical placing + # of characters "9" and "&" for font isocp.shx. + # This is solved by placing the end point on the baseline after + # each character rendering, but only for text rendering. + # The remaining problems can possibly be due to a loss of + # precision when converting floats to ints. + start_offset = codes[index] + end_offset = codes[index + 1] + radius = (codes[index + 2] << 8) + codes[index + 3] + start_octant, octant_span, ccw = decode_octant_specs(codes[index + 4]) + index += 5 + if end_offset == 0: + end_offset = 256 + binary_deg = 45.0 / 256.0 + start_offset_angle = start_offset * binary_deg + end_offset_angle = end_offset * binary_deg + if ccw: + end_octant = start_octant + octant_span - 1 + start_angle = start_octant * 45.0 + start_offset_angle + end_angle = end_octant * 45.0 + end_offset_angle + else: + end_octant = start_octant - octant_span + 1 + start_angle = start_octant * 45.0 - start_offset_angle + end_angle = end_octant * 45.0 - end_offset_angle + + if not skip_next: + self.draw_arc_start_to_end( + radius * self.vector_length, + math.radians(start_angle), + math.radians(end_angle), + ccw, + ) + elif code == 12: # bulge arc + x = codes[index] + y = codes[index + 1] + bulge = codes[index + 2] + index += 3 + if not skip_next: + self.draw_bulge(x, y, bulge) + elif code == 13: # multiple bulge arcs + while True: + x = codes[index] + y = codes[index + 1] + if x == 0 and y == 0: + index += 2 + break + bulge = codes[index + 2] + index += 3 + if not skip_next: + self.draw_bulge(x, y, bulge) + elif code == 14: # flag vertical text + if not self.stacked: + skip_next = True + continue + skip_next = False + + if reset_to_baseline: + # HACK: because of invalid fractional arc rendering! + if not math.isclose(self.p.end.y, self._baseline_y): + self.p.move_to((self.p.end.x, self._baseline_y)) + + def draw_vector(self, code: int) -> None: + angle: int = code & 0xF + length: int = (code >> 4) & 0xF + self.draw_displacement(VEC_X[angle] * length, VEC_Y[angle] * length) + + def draw_displacement(self, x: float, y: float): + scale = self.vector_length + target = self.current_location + Vec2(x * scale, y * scale) + if self.pen_down: + self.p.line_to(target) + else: + self.p.move_to(target) + + def draw_arc_span( + self, radius: float, start_angle: float, span_angle: float, ccw: bool + ): + # IMPORTANT: radius has to be scaled by self.vector_length! + end_angle = start_angle + (span_angle if ccw else -span_angle) + self.draw_arc_start_to_end(radius, start_angle, end_angle, ccw) + + def draw_arc_start_to_end( + self, radius: float, start_angle: float, end_angle: float, ccw: bool + ): + # IMPORTANT: radius has to be scaled by self.vector_length! + assert radius > 0.0 + arc = ConstructionEllipse( + major_axis=(radius, 0), + start_param=start_angle, + end_param=end_angle, + ccw=ccw, + ) + # arc goes start -> end if ccw otherwise end -> start + # move arc start-point to the end-point of current path + arc.center += self.current_location - Vec2( + arc.start_point if ccw else arc.end_point + ) + if self.pen_down: + path.add_ellipse(self.p, arc, reset=False) + else: + self.p.move_to(arc.end_point if ccw else arc.start_point) + + def draw_arc( + self, + center: Vec2, + radius: float, + start_param: float, + end_param: float, + ccw: bool, + ): + # IMPORTANT: radius has to be scaled by self.vector_length! + arc = ConstructionEllipse( + center=center, + major_axis=(radius, 0), + start_param=start_param, + end_param=end_param, + ccw=ccw, + ) + if self.pen_down: + path.add_ellipse(self.p, arc, reset=False) + else: + self.p.move_to(arc.end_point if ccw else arc.start_point) + + def draw_bulge(self, x: float, y: float, bulge: float): + if self.pen_down and bulge: + start_point = self.current_location + scale = self.vector_length + ccw = bulge > 0 + end_point = start_point + Vec2(x * scale, y * scale) + bulge = abs(bulge) / 127.0 + if ccw: # counter-clockwise + center, start_angle, end_angle, radius = bulge_to_arc( + start_point, end_point, bulge + ) + else: # clockwise + center, start_angle, end_angle, radius = bulge_to_arc( + end_point, start_point, bulge + ) + self.draw_arc(center, radius, start_angle, end_angle, ccw=True) + else: + self.draw_displacement(x, y) + + +def decode_octant_specs(specs: int) -> tuple[int, int, bool]: + ccw = True + if specs < 0: + ccw = False + specs = -specs + start_octant = (specs >> 4) & 0xF + octant_span = specs & 0xF + return start_octant, octant_span, ccw + + +def find_shape_number(filename: str, name: bytes) -> int: + """Returns the shape number for shape `name` from the shape-file, returns -1 if not + found. + + The filename can be an absolute path or the shape-file will be searched in the + current directory and all directories stored in :attr:`ezdxf.options.support_dirs`. + Supports shape files of type ".shx" and ".shp". + """ + from ezdxf.filemanagement import find_support_file + from ezdxf import options + + shape_file_name = find_support_file(filename, options.support_dirs) + index = -1 + try: + shapes = readfile(shape_file_name) + except (IOError, ShapeFileException): + return index + shx_symbol = shapes.find(name) + if shx_symbol is not None: + return shx_symbol.number + return index + + +class GlyphCache(Glyphs): + def __init__(self, font: ShapeFile) -> None: + """Text render engine for SHX/SHP fonts with integrated glyph caching.""" + self.font: ShapeFile = font + self._glyph_cache: dict[int, GlyphPath] = dict() + self._advance_width_cache: dict[int, float] = dict() + self.space_width: float = self.detect_space_width() + self.empty_box: GlyphPath = self.get_empty_box() + self.font_measurements: FontMeasurements = self._get_font_measurements() + + def get_scaling_factor(self, cap_height: float) -> float: + try: + return cap_height / self.font_measurements.cap_height + except ZeroDivisionError: + return 1.0 + + def detect_space_width(self) -> float: + if 32 not in self.font.shapes: + return self.get_shape(65).end.x # width of "A" + space = self.get_shape(32) + return space.end.x + + def get_empty_box(self) -> GlyphPath: + glyph_A = self.get_shape(65) + box = BoundingBox2d(glyph_A.control_vertices()) + height = box.size.y + width = box.size.x + start = glyph_A.start + p = path.Path(start) + p.line_to(start + Vec2(width, 0)) + p.line_to(start + Vec2(width, height)) + p.line_to(start + Vec2(0, height)) + p.close() + p.move_to(glyph_A.end) + return GlyphPath(p) + + def _render_shape(self, shape_number) -> GlyphPath: + ctx = ShapeRenderer( + path.Path(), + pen_down=True, + stacked=False, + get_codes=self.font.get_codes, + ) + try: + ctx.render(shape_number, reset_to_baseline=False) + except StackUnderflow: + pass + return GlyphPath(ctx.p) + + def get_shape(self, shape_number: int) -> GlyphPath: + try: + return self._glyph_cache[shape_number].clone() + except KeyError: + pass + try: + glyph = self._render_shape(shape_number) + except UnsupportedShapeNumber: + if shape_number < 32: + glyph = GlyphPath(None) + else: + glyph = self.empty_box + self._glyph_cache[shape_number] = glyph + try: + width = glyph.end.x + except IndexError: + width = self.space_width + self._advance_width_cache[shape_number] = width + return glyph.clone() + + def get_advance_width(self, shape_number: int) -> float: + if shape_number == 32: + return self.space_width + try: + return self._advance_width_cache[shape_number] + except KeyError: + pass + return self.get_shape(shape_number).end.x + + @no_type_check + def _get_font_measurements(self) -> FontMeasurements: + # ignore last move_to command, which places the pen at the start of the + # following glyph + bbox = BoundingBox2d(self.get_shape(ord("x")).control_vertices()[:-1]) + baseline = bbox.extmin.y + x_height = bbox.extmax.y - baseline + + cap_height = self.font.above + if cap_height == 0: + bbox = BoundingBox2d(self.get_shape(ord("A")).control_vertices()[:-1]) + cap_height = bbox.extmax.y - baseline + descender_height = self.font.below + if descender_height == 0: + bbox = BoundingBox2d(self.get_shape(ord("p")).control_vertices()[:-1]) + descender_height = baseline - bbox.extmin.y + return FontMeasurements( + baseline=baseline, + cap_height=cap_height, + x_height=x_height, + descender_height=descender_height, + ) + + def get_text_length( + self, text: str, cap_height: float, width_factor: float = 1.0 + ) -> float: + scaling_factor = self.get_scaling_factor(cap_height) * width_factor + return sum(self.get_advance_width(ord(c)) for c in text) * scaling_factor + + def get_text_glyph_paths( + self, text: str, cap_height: float = 1.0, width_factor: float = 1.0 + ) -> list[GlyphPath]: + """Returns the glyph paths of string `s` as a list, scaled to cap height.""" + glyph_paths: list[GlyphPath] = [] + sy = self.get_scaling_factor(cap_height) + sx = sy * width_factor + m = Matrix44.scale(sx, sy, 1) + current_location = 0.0 + for c in text: + shape_number = ord(c) + if shape_number > 32: + glyph = self.get_shape(shape_number) + m[3, 0] = current_location + glyph.transform_inplace(m) + glyph_paths.append(glyph) + current_location += self.get_advance_width(shape_number) * sx + return glyph_paths diff --git a/.venv/lib/python3.12/site-packages/ezdxf/fonts/ttfonts.py b/.venv/lib/python3.12/site-packages/ezdxf/fonts/ttfonts.py new file mode 100644 index 0000000..e05bb08 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/fonts/ttfonts.py @@ -0,0 +1,206 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, no_type_check +from fontTools.pens.basePen import BasePen +from fontTools.ttLib import TTFont + +from ezdxf.math import Matrix44, UVec, BoundingBox2d +from ezdxf.path import Path +from .font_manager import FontManager, UnsupportedFont +from .font_measurements import FontMeasurements +from .glyphs import GlyphPath, Glyphs + +UNICODE_WHITE_SQUARE = 9633 # U+25A1 +UNICODE_REPLACEMENT_CHAR = 65533 # U+FFFD + +font_manager = FontManager() + + +class PathPen(BasePen): + def __init__(self, glyph_set) -> None: + super().__init__(glyph_set) + self._path = Path() + + @property + def path(self) -> GlyphPath: + return GlyphPath(self._path) + + def _moveTo(self, pt: UVec) -> None: + self._path.move_to(pt) + + def _lineTo(self, pt: UVec) -> None: + self._path.line_to(pt) + + def _curveToOne(self, pt1: UVec, pt2: UVec, pt3: UVec) -> None: + self._path.curve4_to(pt3, pt1, pt2) + + def _qCurveToOne(self, pt1: UVec, pt2: UVec) -> None: + self._path.curve3_to(pt2, pt1) + + def _closePath(self) -> None: + self._path.close_sub_path() + + +class NoKerning: + def get(self, c0: str, c1: str) -> float: + return 0.0 + + +class KerningTable(NoKerning): + __slots__ = ("_cmap", "_kern_table") + + def __init__(self, font: TTFont, cmap, fmt: int = 0): + self._cmap = cmap + self._kern_table = font["kern"].getkern(fmt) + + def get(self, c0: str, c1: str) -> float: + try: + return self._kern_table[(self._cmap[ord(c0)], self._cmap[ord(c1)])] + except (KeyError, TypeError): + return 0.0 + + +def get_fontname(font: TTFont) -> str: + names = font["name"].names + for record in names: + if record.nameID == 1: + return record.string.decode(record.getEncoding()) + return "unknown" + + +class TTFontRenderer(Glyphs): + def __init__(self, font: TTFont, kerning=False): + self._glyph_path_cache: dict[str, GlyphPath] = dict() + self._generic_glyph_cache: dict[str, Any] = dict() + self._glyph_width_cache: dict[str, float] = dict() + self.font = font + self.cmap = self.font.getBestCmap() + if self.cmap is None: + raise UnsupportedFont(f"font '{self.font_name}' has no character map.") + self.glyph_set = self.font.getGlyphSet() + self.kerning = NoKerning() + if kerning: + try: + self.kerning = KerningTable(self.font, self.cmap) + except KeyError: # kerning table does not exist + pass + self.undefined_generic_glyph = self.glyph_set[".notdef"] + self.font_measurements = self._get_font_measurements() + self.space_width = self.detect_space_width() + + @property + def font_name(self) -> str: + return get_fontname(self.font) + + @no_type_check + def _get_font_measurements(self) -> FontMeasurements: + bbox = BoundingBox2d(self.get_glyph_path("x").control_vertices()) + baseline = bbox.extmin.y + x_height = bbox.extmax.y - baseline + bbox = BoundingBox2d(self.get_glyph_path("A").control_vertices()) + cap_height = bbox.extmax.y - baseline + bbox = BoundingBox2d(self.get_glyph_path("p").control_vertices()) + descender_height = baseline - bbox.extmin.y + return FontMeasurements( + baseline=baseline, + cap_height=cap_height, + x_height=x_height, + descender_height=descender_height, + ) + + def get_scaling_factor(self, cap_height: float) -> float: + return 1.0 / self.font_measurements.cap_height * cap_height + + def get_generic_glyph(self, char: str): + try: + return self._generic_glyph_cache[char] + except KeyError: + pass + try: + generic_glyph = self.glyph_set[self.cmap[ord(char)]] + except KeyError: + generic_glyph = self.undefined_generic_glyph + self._generic_glyph_cache[char] = generic_glyph + return generic_glyph + + def get_glyph_path(self, char: str) -> GlyphPath: + """Returns the raw glyph path, without any scaling applied.""" + try: + return self._glyph_path_cache[char].clone() + except KeyError: + pass + pen = PathPen(self.glyph_set) + self.get_generic_glyph(char).draw(pen) + glyph_path = pen.path + self._glyph_path_cache[char] = glyph_path + return glyph_path.clone() + + def get_glyph_width(self, char: str) -> float: + """Returns the raw glyph width, without any scaling applied.""" + try: + return self._glyph_width_cache[char] + except KeyError: + pass + width = 0.0 + try: + width = self.get_generic_glyph(char).width + except KeyError: + pass + self._glyph_width_cache[char] = width + return width + + def get_text_glyph_paths( + self, s: str, cap_height: float = 1.0, width_factor: float = 1.0 + ) -> list[GlyphPath]: + """Returns the glyph paths of string `s` as a list, scaled to cap height.""" + glyph_paths: list[GlyphPath] = [] + x_offset: float = 0 + requires_kerning = isinstance(self.kerning, KerningTable) + resize_factor = self.get_scaling_factor(cap_height) + y_factor = resize_factor + x_factor = resize_factor * width_factor + # set scaling factor: + m = Matrix44.scale(x_factor, y_factor, 1.0) + # set vertical offset: + m[3, 1] = -self.font_measurements.baseline * y_factor + prev_char = "" + + for char in s: + if requires_kerning: + x_offset += self.kerning.get(prev_char, char) * x_factor + # set horizontal offset: + m[3, 0] = x_offset + glyph_path = self.get_glyph_path(char) + glyph_path.transform_inplace(m) + if len(glyph_path): + glyph_paths.append(glyph_path) + x_offset += self.get_glyph_width(char) * x_factor + prev_char = char + return glyph_paths + + def detect_space_width(self) -> float: + """Returns the space width for the raw (unscaled) font.""" + return self.get_glyph_width(" ") + + def _get_text_length_with_kerning(self, s: str, cap_height: float = 1.0) -> float: + length = 0.0 + c0 = "" + kern = self.kerning.get + width = self.get_glyph_width + for c1 in s: + length += kern(c0, c1) + width(c1) + c0 = c1 + return length * self.get_scaling_factor(cap_height) + + def get_text_length( + self, s: str, cap_height: float = 1.0, width_factor: float = 1.0 + ) -> float: + if isinstance(self.kerning, KerningTable): + return self._get_text_length_with_kerning(s, cap_height) * width_factor + width = self.get_glyph_width + return ( + sum(width(c) for c in s) + * self.get_scaling_factor(cap_height) + * width_factor + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/gfxattribs.py b/.venv/lib/python3.12/site-packages/ezdxf/gfxattribs.py new file mode 100644 index 0000000..cc9ac78 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/gfxattribs.py @@ -0,0 +1,327 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, Optional, Iterator, TYPE_CHECKING + +from ezdxf import colors +from ezdxf.lldxf import validator, const + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity + +__all__ = ["GfxAttribs", "TRANSPARENCY_BYBLOCK"] + + +DEFAULT_LAYER = "0" +DEFAULT_ACI_COLOR = colors.BYLAYER +DEFAULT_LINETYPE = "ByLayer" +DEFAULT_LINEWEIGHT = const.LINEWEIGHT_BYLAYER +DEFAULT_LTSCALE = 1.0 +TRANSPARENCY_BYBLOCK = -1.0 # special value + + +class GfxAttribs: + """ + Represents often used DXF attributes of graphical entities. + + Args: + layer (str): layer name as string + color (int): :ref:`ACI` color value as integer + rgb: RGB true color (red, green, blue) tuple, each channel value in the + range from 0 to 255, ``None`` for not set + linetype (str): linetype name, does not check if the linetype exist! + lineweight (int): see :ref:`lineweights` documentation for valid values + transparency (float): transparency value in the range from 0.0 to 1.0, + where 0.0 is opaque and 1.0 if fully transparent, -1.0 for + transparency by block, ``None`` for transparency by layer + ltscale (float): linetype scaling factor > 0.0, default factor is 1.0 + + Raises: + DXFValueError: invalid attribute value + + """ + + _layer: str = DEFAULT_LAYER + _aci_color: int = DEFAULT_ACI_COLOR + _true_color: Optional[colors.RGB] = None + _linetype: str = DEFAULT_LINETYPE + _lineweight: int = DEFAULT_LINEWEIGHT + _transparency: Optional[float] = None + _ltscale: float = DEFAULT_LTSCALE + + def __init__( + self, + *, + layer: str = DEFAULT_LAYER, + color: int = DEFAULT_ACI_COLOR, + rgb: Optional[colors.RGB] = None, + linetype: str = DEFAULT_LINETYPE, + lineweight: int = DEFAULT_LINEWEIGHT, + transparency: Optional[float] = None, + ltscale: float = DEFAULT_LTSCALE, + ): + self.layer = layer + self.color = color + self.rgb = rgb + self.linetype = linetype + self.lineweight = lineweight + self.transparency = transparency + self.ltscale = ltscale + + def __str__(self) -> str: + s = [] + if self._layer != DEFAULT_LAYER: + s.append(f"layer='{self._layer}'") + if self._aci_color != DEFAULT_ACI_COLOR: + s.append(f"color={self._aci_color}") + if self._true_color is not None: + s.append(f"rgb={self._true_color}") + if self._linetype != DEFAULT_LINETYPE: + s.append(f"linetype='{self._linetype}'") + if self._lineweight != DEFAULT_LINEWEIGHT: + s.append(f"lineweight={self._lineweight}") + if self._transparency is not None: + s.append(f"transparency={round(self._transparency, 3)}") + if self._ltscale != DEFAULT_LTSCALE: + s.append(f"ltscale={round(self._ltscale, 3)}") + + return ", ".join(s) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.__str__()})" + + def __iter__(self) -> Iterator[tuple[str, Any]]: + """Returns iter(self).""" + return iter(self.items()) + + def items(self, default_values=False) -> list[tuple[str, Any]]: + """Returns the DXF attributes as list of name, value pairs, returns + also the default values if argument `default_values` is ``True``. + The true_color and transparency attributes do not have default values, + the absence of these attributes is the default value. + """ + data: list[tuple[str, Any]] = [] + if default_values or self._layer != DEFAULT_LAYER: + data.append(("layer", self._layer)) + if default_values or self._aci_color != DEFAULT_ACI_COLOR: + data.append(("color", self._aci_color)) + if self._true_color is not None: + # absence is the default value + data.append(("true_color", colors.rgb2int(self._true_color))) + if default_values or self._linetype != DEFAULT_LINETYPE: + data.append(("linetype", self._linetype)) + if default_values or self._lineweight != DEFAULT_LINEWEIGHT: + data.append(("lineweight", self.lineweight)) + if self._transparency is not None: + # absence is the default value + if self._transparency == TRANSPARENCY_BYBLOCK: + data.append(("transparency", colors.TRANSPARENCY_BYBLOCK)) + else: + data.append( + ( + "transparency", + colors.float2transparency(self._transparency), + ) + ) + if default_values or self._ltscale != DEFAULT_LTSCALE: + data.append(("ltscale", self._ltscale)) + return data + + def asdict(self, default_values=False) -> dict[str, Any]: + """Returns the DXF attributes as :class:`dict`, returns also the + default values if argument `default_values` is ``True``. + The true_color and transparency attributes do not have default values, + the absence of these attributes is the default value. + """ + return dict(self.items(default_values)) + + @property + def layer(self) -> str: + """layer name""" + return self._layer + + @layer.setter + def layer(self, name: str): + if validator.is_valid_layer_name(name): + self._layer = name + else: + raise const.DXFValueError(f"invalid layer name '{name}'") + + @property + def color(self) -> int: + """:ref:`ACI` color value""" + return self._aci_color + + @color.setter + def color(self, value: int): + if validator.is_valid_aci_color(value): + self._aci_color = value + else: + raise const.DXFValueError(f"invalid ACI color value '{value}'") + + @property + def rgb(self) -> Optional[colors.RGB]: + """true color value as (red, green, blue) tuple, ``None`` for not set""" + return self._true_color + + @rgb.setter + def rgb(self, value: Optional[colors.RGB]): + if value is None: + self._true_color = None + elif validator.is_valid_rgb(value): + self._true_color = value + else: + raise const.DXFValueError(f"invalid true color value '{value}'") + + @property + def linetype(self) -> str: + """linetype name""" + return self._linetype + + @linetype.setter + def linetype(self, name: str): + if validator.is_valid_table_name(name): + self._linetype = name + else: + raise const.DXFValueError(f"invalid linetype name '{name}'") + + @property + def lineweight(self) -> int: + """lineweight""" + return self._lineweight + + @lineweight.setter + def lineweight(self, value: int): + if validator.is_valid_lineweight(value): + self._lineweight = value + else: + raise const.DXFValueError(f"invalid lineweight value '{value}'") + + @property + def transparency(self) -> Optional[float]: + """transparency value from 0.0 for opaque to 1.0 is fully transparent, + -1.0 is for transparency by block and ``None`` if for transparency + by layer + """ + return self._transparency + + @transparency.setter + def transparency(self, value: Optional[float]): + if value is None: + self._transparency = None + elif value == TRANSPARENCY_BYBLOCK: + self._transparency = TRANSPARENCY_BYBLOCK + elif isinstance(value, float) and (0.0 <= value <= 1.0): + self._transparency = value + else: + raise const.DXFValueError(f"invalid transparency value '{value}'") + + @property + def ltscale(self) -> float: + """linetype scaling factor""" + return self._ltscale + + @ltscale.setter + def ltscale(self, value: float): + if isinstance(value, (float, int)) and (value > 1e-6): + self._ltscale = float(value) + else: + raise const.DXFValueError(f"invalid linetype scale value '{value}'") + + @classmethod + def load_from_header(cls, doc: Drawing) -> GfxAttribs: + """Load default DXF attributes from the HEADER section. + + There is no default true color value and the default transparency is not + stored in the HEADER section. + + Loads following header variables: + + - ``$CLAYER`` - current layer name + - ``$CECOLOR`` - current ACI color + - ``$CELTYPE`` - current linetype name + - ``$CELWEIGHT`` - current lineweight + - ``$CELTSCALE`` - current linetype scaling factor + + """ + header = doc.header + return cls( + layer=header.get("$CLAYER", DEFAULT_LAYER), + color=header.get("$CECOLOR", DEFAULT_ACI_COLOR), + linetype=header.get("$CELTYPE", DEFAULT_LINETYPE), + lineweight=header.get("$CELWEIGHT", DEFAULT_LINEWEIGHT), + ltscale=header.get("$CELTSCALE", DEFAULT_LTSCALE), + ) + + def write_to_header(self, doc: "Drawing") -> None: + """Write DXF attributes as default values to the HEADER section. + + Writes following header variables: + + - ``$CLAYER`` - current layer name, if a layer table entry exist in `doc` + - ``$CECOLOR`` - current ACI color + - ``$CELTYPE`` - current linetype name, if a linetype table entry exist in `doc` + - ``$CELWEIGHT`` - current lineweight + - ``$CELTSCALE`` - current linetype scaling factor + + """ + header = doc.header + if doc.layers.has_entry(self.layer): + header["$CLAYER"] = self.layer + header["$CECOLOR"] = self.color + if doc.linetypes.has_entry(self.linetype): + header["$CELTYPE"] = self.linetype + header["$CELWEIGHT"] = self.lineweight + header["$CELTSCALE"] = self.ltscale + + @classmethod + def from_entity(cls, entity: DXFEntity) -> GfxAttribs: + """Get the graphical attributes of an `entity` as :class:`GfxAttribs` + object. + """ + try: + d = entity.graphic_properties() # type: ignore + except AttributeError: + return cls() + return cls.from_dict(d) + + @classmethod + def from_dict(cls, d: dict[str, Any]) -> GfxAttribs: + """Construct :class:`GfxAttribs` from a dictionary of raw DXF values. + + Supported attributes are: + + - layer: layer name as string + - color: :ref:`ACI` value as int + - true_color: raw DXF integer value for RGB colors + - rgb: RGB tuple of int or ``None`` + - linetype: linetype name as string + - lineweight: lineweight as int, see basic concept of :ref:`lineweights` + - transparency: raw DXF integer value of transparency or a float in the + range from 0.0 to 1.0 + - ltscale: linetype scaling factor as float + + """ + attribs = cls() + for attrib_name in [ + "layer", + "color", + "linetype", + "lineweight", + "ltscale", + "rgb", + ]: + if attrib_name in d: + setattr(attribs, attrib_name, d[attrib_name]) + if "true_color" in d: + attribs.rgb = colors.int2rgb(d["true_color"]) + if "transparency" in d: + transparency = d["transparency"] + if isinstance(transparency, float): + attribs.transparency = transparency + elif transparency == colors.TRANSPARENCY_BYBLOCK: + attribs.transparency = TRANSPARENCY_BYBLOCK + else: + attribs.transparency = colors.transparency2float(transparency) + return attribs diff --git a/.venv/lib/python3.12/site-packages/ezdxf/graphicsfactory.py b/.venv/lib/python3.12/site-packages/ezdxf/graphicsfactory.py new file mode 100644 index 0000000..7efa89b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/graphicsfactory.py @@ -0,0 +1,2685 @@ +# Copyright (c) 2013-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Sequence, + cast, + Optional, +) +import math +import logging +import warnings +from ezdxf.lldxf import const +from ezdxf.lldxf.const import DXFValueError, DXFVersionError, DXF2000, DXF2013 +from ezdxf.math import ( + Vec3, + UVec, + UCS, + global_bspline_interpolation, + fit_points_to_cad_cv, + arc_angle_span_deg, + ConstructionArc, + NULLVEC, +) +from ezdxf.render.arrows import ARROWS +from ezdxf.entities import factory, Point, Spline, Body, Surface, Line, Circle +from ezdxf.entities.mtext_columns import * +from ezdxf.entities.dimstyleoverride import DimStyleOverride +from ezdxf.render.dim_linear import multi_point_linear_dimension +from ezdxf.tools import guid + +logger = logging.getLogger("ezdxf") + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.eztypes import GenericLayoutType + from ezdxf.entities import ( + Arc, + AttDef, + Dimension, + ArcDimension, + DXFGraphic, + Ellipse, + ExtrudedSurface, + Face3d, + Hatch, + Image, + ImageDef, + Insert, + LWPolyline, + Leader, + LoftedSurface, + MLine, + MText, + MPolygon, + Mesh, + Polyface, + Polyline, + Polymesh, + Ray, + Region, + RevolvedSurface, + Shape, + Solid, + Solid3d, + SweptSurface, + Text, + Trace, + Underlay, + UnderlayDefinition, + Wipeout, + XLine, + MultiLeader, + Helix, + ) + from ezdxf.render.mleader import ( + MultiLeaderMTextBuilder, + MultiLeaderBlockBuilder, + ) + + +class CreatorInterface: + def __init__(self, doc: Drawing): + self.doc = doc + + @property + def dxfversion(self) -> str: + return self.doc.dxfversion + + @property + def is_active_paperspace(self): + return False + + def new_entity(self, type_: str, dxfattribs: dict) -> DXFGraphic: + """ + Create entity in drawing database and add entity to the entity space. + + Args: + type_ : DXF type string, like "LINE", "CIRCLE" or "LWPOLYLINE" + dxfattribs: DXF attributes for the new entity + + """ + entity = factory.create_db_entry(type_, dxfattribs, self.doc) + self.add_entity(entity) # type: ignore + return entity # type: ignore + + def add_entity(self, entity: DXFGraphic) -> None: + pass + + def add_point(self, location: UVec, dxfattribs=None) -> Point: + """ + Add a :class:`~ezdxf.entities.Point` entity at `location`. + + Args: + location: 2D/3D point in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["location"] = Vec3(location) + return self.new_entity("POINT", dxfattribs) # type: ignore + + def add_line(self, start: UVec, end: UVec, dxfattribs=None) -> Line: + """ + Add a :class:`~ezdxf.entities.Line` entity from `start` to `end`. + + Args: + start: 2D/3D point in :ref:`WCS` + end: 2D/3D point in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["start"] = Vec3(start) + dxfattribs["end"] = Vec3(end) + return self.new_entity("LINE", dxfattribs) # type: ignore + + def add_circle( + self, center: UVec, radius: float, dxfattribs=None + ) -> Circle: + """ + Add a :class:`~ezdxf.entities.Circle` entity. This is an 2D element, + which can be placed in space by using :ref:`OCS`. + + Args: + center: 2D/3D point in :ref:`WCS` + radius: circle radius + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["center"] = Vec3(center) + dxfattribs["radius"] = float(radius) + return self.new_entity("CIRCLE", dxfattribs) # type: ignore + + def add_ellipse( + self, + center: UVec, + major_axis: UVec = (1, 0, 0), + ratio: float = 1, + start_param: float = 0, + end_param: float = math.tau, + dxfattribs=None, + ) -> Ellipse: + """ + Add an :class:`~ezdxf.entities.Ellipse` entity, `ratio` is the ratio of + minor axis to major axis, `start_param` and `end_param` defines start + and end point of the ellipse, a full ellipse goes from 0 to 2π. + The ellipse goes from start to end param in `counter-clockwise` + direction. + + Args: + center: center of ellipse as 2D/3D point in :ref:`WCS` + major_axis: major axis as vector (x, y, z) + ratio: ratio of minor axis to major axis in range +/-[1e-6, 1.0] + start_param: start of ellipse curve + end_param: end param of ellipse curve + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("ELLIPSE requires DXF R2000") + ratio = float(ratio) + if abs(ratio) > 1.0: # not valid for AutoCAD + raise DXFValueError("invalid axis ratio > 1.0") + _major_axis = Vec3(major_axis) + if _major_axis.is_null: # not valid for AutoCAD + raise DXFValueError("invalid major axis: (0, 0, 0)") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["center"] = Vec3(center) + dxfattribs["major_axis"] = _major_axis + dxfattribs["ratio"] = ratio + dxfattribs["start_param"] = float(start_param) + dxfattribs["end_param"] = float(end_param) + return self.new_entity("ELLIPSE", dxfattribs) # type: ignore + + def add_arc( + self, + center: UVec, + radius: float, + start_angle: float, + end_angle: float, + is_counter_clockwise: bool = True, + dxfattribs=None, + ) -> Arc: + """ + Add an :class:`~ezdxf.entities.Arc` entity. The arc goes from + `start_angle` to `end_angle` in counter-clockwise direction by default, + set parameter `is_counter_clockwise` to ``False`` for clockwise + orientation. + + Args: + center: center of arc as 2D/3D point in :ref:`WCS` + radius: arc radius + start_angle: start angle in degrees + end_angle: end angle in degrees + is_counter_clockwise: ``False`` for clockwise orientation + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["center"] = Vec3(center) + dxfattribs["radius"] = float(radius) + if is_counter_clockwise: + dxfattribs["start_angle"] = float(start_angle) + dxfattribs["end_angle"] = float(end_angle) + else: + dxfattribs["start_angle"] = float(end_angle) + dxfattribs["end_angle"] = float(start_angle) + return self.new_entity("ARC", dxfattribs) # type: ignore + + def add_solid(self, points: Iterable[UVec], dxfattribs=None) -> Solid: + """Add a :class:`~ezdxf.entities.Solid` entity, `points` is an iterable + of 3 or 4 points. + + .. hint:: + + The last two vertices are in reversed order: a square has the + vertex order 0-1-3-2 + + Args: + points: iterable of 3 or 4 2D/3D points in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + return self._add_quadrilateral("SOLID", points, dxfattribs) # type: ignore + + def add_trace(self, points: Iterable[UVec], dxfattribs=None) -> Trace: + """Add a :class:`~ezdxf.entities.Trace` entity, `points` is an iterable + of 3 or 4 points. + + .. hint:: + + The last two vertices are in reversed order: a square has the + vertex order 0-1-3-2 + + Args: + points: iterable of 3 or 4 2D/3D points in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + return self._add_quadrilateral("TRACE", points, dxfattribs) # type: ignore + + def add_3dface(self, points: Iterable[UVec], dxfattribs=None) -> Face3d: + """ + Add a :class:`~ezdxf.entities.3DFace` entity, `points` is an iterable + 3 or 4 2D/3D points. + + .. hint:: + + In contrast to SOLID and TRACE, the last two vertices are in + regular order: a square has the vertex order 0-1-2-3 + + Args: + points: iterable of 3 or 4 2D/3D points in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + return self._add_quadrilateral("3DFACE", points, dxfattribs) # type: ignore + + def add_text( + self, + text: str, + *, + height: Optional[float] = None, + rotation: Optional[float] = None, + dxfattribs=None, + ) -> Text: + """ + Add a :class:`~ezdxf.entities.Text` entity, see also + :class:`~ezdxf.entities.Textstyle`. + + Args: + text: content string + height: text height in drawing units + rotation: text rotation in degrees + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["text"] = str(text) + if height is not None: + dxfattribs["height"] = float(height) + if rotation is not None: + dxfattribs["rotation"] = float(rotation) + dxfattribs.setdefault("insert", Vec3()) + return self.new_entity("TEXT", dxfattribs) # type: ignore + + def add_blockref(self, name: str, insert: UVec, dxfattribs=None) -> Insert: + """ + Add an :class:`~ezdxf.entities.Insert` entity. + + When inserting a block reference into the modelspace or another block + layout with different units, the scaling factor between these units + should be applied as scaling attributes (:attr:`xscale`, ...) e.g. + modelspace in meters and block in centimeters, :attr:`xscale` has to + be 0.01. + + Args: + name: block name as str + insert: insert location as 2D/3D point in :ref:`WCS` + dxfattribs: additional DXF attributes + + """ + if not isinstance(name, str): + raise DXFValueError("Block name as string required.") + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + dxfattribs["insert"] = Vec3(insert) + return self.new_entity("INSERT", dxfattribs) # type: ignore + + def add_auto_blockref( + self, + name: str, + insert: UVec, + values: dict[str, str], + dxfattribs=None, + ) -> Insert: + """ + Add an :class:`~ezdxf.entities.Insert` entity. This method adds for each + :class:`~ezdxf.entities.Attdef` entity, defined in the block definition, + automatically an :class:`Attrib` entity to the block reference and set + (tag, value) DXF attributes of the ATTRIB entities by the (key, value) + pairs (both as strings) of the `values` dict. + + The Attrib entities are placed relative to the insert point, which is + equal to the block base point. + + This method wraps the INSERT and all the ATTRIB entities into an + anonymous block, which produces the best visual results, especially for + non-uniform scaled block references, because the transformation and + scaling is done by the CAD application. But this makes evaluation of + block references with attributes more complicated, if you prefer INSERT + and ATTRIB entities without a wrapper block use the + :meth:`add_blockref_with_attribs` method. + + Args: + name: block name + insert: insert location as 2D/3D point in :ref:`WCS` + values: :class:`~ezdxf.entities.Attrib` tag values as (tag, value) pairs + dxfattribs: additional DXF attributes + + """ + if not isinstance(name, str): + raise DXFValueError("Block name as string required.") + + def unpack(dxfattribs) -> tuple[str, str, UVec]: + tag = dxfattribs.pop("tag") + text = values.get(tag, "") + location = dxfattribs.pop("insert") + return tag, text, location + + def autofill() -> None: + # ATTRIBs are placed relative to the base point + for attdef in blockdef.attdefs(): + dxfattribs = attdef.dxfattribs(drop={"prompt", "handle"}) + tag, text, location = unpack(dxfattribs) + blockref.add_attrib(tag, text, location, dxfattribs) + + dxfattribs = dict(dxfattribs or {}) + autoblock = self.doc.blocks.new_anonymous_block() + blockref = autoblock.add_blockref(name, (0, 0)) + blockdef = self.doc.blocks[name] + autofill() + return self.add_blockref(autoblock.name, insert, dxfattribs) + + def add_attdef( + self, + tag: str, + insert: UVec = (0, 0), + text: str = "", + *, + height: Optional[float] = None, + rotation: Optional[float] = None, + dxfattribs=None, + ) -> AttDef: + """ + Add an :class:`~ezdxf.entities.AttDef` as stand alone DXF entity. + + Set position and alignment by the idiom:: + + layout.add_attdef("NAME").set_placement( + (2, 3), align=TextEntityAlignment.MIDDLE_CENTER + ) + + Args: + tag: tag name as string + insert: insert location as 2D/3D point in :ref:`WCS` + text: tag value as string + height: text height in drawing units + rotation: text rotation in degrees + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["tag"] = str(tag) + dxfattribs["insert"] = Vec3(insert) + dxfattribs["text"] = str(text) + if height is not None: + dxfattribs["height"] = float(height) + if rotation is not None: + dxfattribs["rotation"] = float(rotation) + return self.new_entity("ATTDEF", dxfattribs) # type: ignore + + def add_polyline2d( + self, + points: Iterable[UVec], + format: Optional[str] = None, + *, + close: bool = False, + dxfattribs=None, + ) -> Polyline: + """ + Add a 2D :class:`~ezdxf.entities.Polyline` entity. + + Args: + points: iterable of 2D points in :ref:`WCS` + close: ``True`` for a closed polyline + format: user defined point format like :meth:`add_lwpolyline`, + default is ``None`` + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + if "closed" in dxfattribs: + warnings.warn( + 'dxfattribs key "closed" is deprecated, ' + 'use keyword argument "close"', + DeprecationWarning, + ) + + close = dxfattribs.pop("closed", close) + polyline: Polyline = self.new_entity("POLYLINE", dxfattribs) # type: ignore + polyline.close(close) + if format is not None: + polyline.append_formatted_vertices(points, format=format) + else: + polyline.append_vertices(points) + if self.doc: + polyline.add_sub_entities_to_entitydb(self.doc.entitydb) + return polyline + + def add_polyline3d( + self, + points: Iterable[UVec], + *, + close: bool = False, + dxfattribs=None, + ) -> Polyline: + """Add a 3D :class:`~ezdxf.entities.Polyline` entity. + + Args: + points: iterable of 3D points in :ref:`WCS` + close: ``True`` for a closed polyline + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["flags"] = ( + dxfattribs.get("flags", 0) | const.POLYLINE_3D_POLYLINE + ) + return self.add_polyline2d(points, close=close, dxfattribs=dxfattribs) + + def add_polymesh( + self, size: tuple[int, int] = (3, 3), dxfattribs=None + ) -> Polymesh: + """ + Add a :class:`~ezdxf.entities.Polymesh` entity, which is a wrapper class + for the POLYLINE entity. A polymesh is a grid of `mcount` x `ncount` + vertices and every vertex has its own (x, y, z)-coordinates. + + Args: + size: 2-tuple (`mcount`, `ncount`) + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["flags"] = ( + dxfattribs.get("flags", 0) | const.POLYLINE_3D_POLYMESH + ) + m_size = max(size[0], 2) + n_size = max(size[1], 2) + dxfattribs["m_count"] = m_size + dxfattribs["n_count"] = n_size + m_close = dxfattribs.pop("m_close", False) + n_close = dxfattribs.pop("n_close", False) + polymesh: Polymesh = self.new_entity("POLYLINE", dxfattribs) # type: ignore + + points = [(0, 0, 0)] * (m_size * n_size) + polymesh.append_vertices(points) # init mesh vertices + polymesh.close(m_close, n_close) + if self.doc: + polymesh.add_sub_entities_to_entitydb(self.doc.entitydb) + + return polymesh + + def add_polyface(self, dxfattribs=None) -> Polyface: + """Add a :class:`~ezdxf.entities.Polyface` entity, which is a wrapper + class for the POLYLINE entity. + + Args: + dxfattribs: additional DXF attributes for + :class:`~ezdxf.entities.Polyline` entity + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["flags"] = ( + dxfattribs.get("flags", 0) | const.POLYLINE_POLYFACE + ) + m_close = dxfattribs.pop("m_close", False) + n_close = dxfattribs.pop("n_close", False) + polyface: Polyface = self.new_entity("POLYLINE", dxfattribs) # type: ignore + polyface.close(m_close, n_close) + if self.doc: + polyface.add_sub_entities_to_entitydb(self.doc.entitydb) + + return polyface + + def _add_quadrilateral( + self, type_: str, points: Iterable[UVec], dxfattribs=None + ) -> DXFGraphic: + dxfattribs = dict(dxfattribs or {}) + entity = self.new_entity(type_, dxfattribs) + for x, point in enumerate(self._four_points(points)): + entity[x] = Vec3(point) # type: ignore + return entity + + @staticmethod + def _four_points(points: Iterable[UVec]) -> Iterable[UVec]: + vertices = list(points) + if len(vertices) not in (3, 4): + raise DXFValueError("3 or 4 points required.") + for vertex in vertices: + yield vertex + if len(vertices) == 3: + yield vertices[-1] # last again + + def add_shape( + self, + name: str, + insert: UVec = (0, 0), + size: float = 1.0, + dxfattribs=None, + ) -> Shape: + """ + Add a :class:`~ezdxf.entities.Shape` reference to an external stored shape. + + Args: + name: shape name as string + insert: insert location as 2D/3D point in :ref:`WCS` + size: size factor + dxfattribs: additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = str(name) + dxfattribs["insert"] = Vec3(insert) + dxfattribs["size"] = float(size) + return self.new_entity("SHAPE", dxfattribs) # type: ignore + + # new entities in DXF AC1015 (R2000) + + def add_lwpolyline( + self, + points: Iterable[UVec], + format: str = "xyseb", + *, + close: bool = False, + dxfattribs=None, + ) -> LWPolyline: + """ + Add a 2D polyline as :class:`~ezdxf.entities.LWPolyline` entity. + A points are defined as (x, y, [start_width, [end_width, [bulge]]]) + tuples, but order can be redefined by the `format` argument. Set + `start_width`, `end_width` to 0 to be ignored like + (x, y, 0, 0, bulge). + + The :class:`~ezdxf.entities.LWPolyline` is defined as a single DXF + entity and needs less disk space than a + :class:`~ezdxf.entities.Polyline` entity. (requires DXF R2000) + + Format codes: + + - ``x`` = x-coordinate + - ``y`` = y-coordinate + - ``s`` = start width + - ``e`` = end width + - ``b`` = bulge value + - ``v`` = (x, y [,z]) tuple (z-axis is ignored) + + Args: + points: iterable of (x, y, [start_width, [end_width, [bulge]]]) tuples + format: user defined point format, default is "xyseb" + close: ``True`` for a closed polyline + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("LWPOLYLINE requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + if "closed" in dxfattribs: + warnings.warn( + 'dxfattribs key "closed" is deprecated, ' + 'use keyword argument "close"', + DeprecationWarning, + ) + close = dxfattribs.pop("closed", close) + lwpolyline: LWPolyline = self.new_entity("LWPOLYLINE", dxfattribs) # type: ignore + lwpolyline.set_points(points, format=format) + lwpolyline.closed = close + return lwpolyline + + def add_mtext(self, text: str, dxfattribs=None) -> MText: + """ + Add a multiline text entity with automatic text wrapping at boundaries + as :class:`~ezdxf.entities.MText` entity. + (requires DXF R2000) + + Args: + text: content string + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("MTEXT requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + mtext: MText = self.new_entity("MTEXT", dxfattribs) # type: ignore + mtext.text = str(text) + return mtext + + def add_mtext_static_columns( + self, + content: Iterable[str], + width: float, + gutter_width: float, + height: float, + dxfattribs=None, + ) -> MText: + """Add a multiline text entity with static columns as + :class:`~ezdxf.entities.MText` entity. The content is spread + across the columns, the count of content strings determine the count + of columns. + + This factory method adds automatically a column break ``"\\N"`` at the + end of each column text to force a new column. + The `height` attribute should be big enough to reserve enough space for + the tallest column. Too small values produce valid DXF files, but the + visual result will not be as expected. The `height` attribute also + defines the total height of the MTEXT entity. + + (requires DXF R2000) + + Args: + content: iterable of column content + width: column width + gutter_width: distance between columns + height: max. column height + dxfattribs: additional DXF attributes + + """ + dxfversion = self.dxfversion + if dxfversion < DXF2000: + raise DXFVersionError("MTEXT requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + content = list(content) + if dxfversion < const.DXF2018: + mtext = make_static_columns_r2000( + content, width, gutter_width, height, dxfattribs + ) + else: + mtext = make_static_columns_r2018( + content, width, gutter_width, height, dxfattribs + ) + if self.doc: + self.doc.entitydb.add(mtext) + self.add_entity(mtext) + return mtext + + def add_mtext_dynamic_auto_height_columns( + self, + content: str, + width: float, + gutter_width: float, + height: float, + count: int, + dxfattribs=None, + ) -> MText: + """Add a multiline text entity with as many columns as needed for the + given common fixed `height`. The content is spread across the columns + automatically by the CAD application. The `height` argument also defines + the total height of the MTEXT entity. To get the correct column `count` + requires an **exact** MTEXT rendering like AutoCAD, which is + not done by `ezdxf`, therefore passing the expected column `count` + is required to calculate the correct total width. + + This current implementation works best for DXF R2018, because the + content is stored as a continuous text in a single MTEXT entity. For + DXF versions prior to R2018 the content should be distributed across + multiple MTEXT entities (one entity per column), which is not done by + `ezdxf`, but the result is correct for advanced DXF viewers and CAD + application, which do the MTEXT content distribution completely by + itself. + + Because of the current limitations the use of this method is not + recommend. This situation may improve in future releases, but the exact + rendering of the content will also slow down the processing speed + dramatically. + + (requires DXF R2000) + + Args: + content: column content as a single string + width: column width + gutter_width: distance between columns + height: max. column height + count: expected column count + dxfattribs: additional DXF attributes + + """ + dxfversion = self.dxfversion + if dxfversion < DXF2000: + raise DXFVersionError("MTEXT requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + if dxfversion < const.DXF2018: + mtext = make_dynamic_auto_height_columns_r2000( + content, width, gutter_width, height, count, dxfattribs + ) + else: + mtext = make_dynamic_auto_height_columns_r2018( + content, width, gutter_width, height, count, dxfattribs + ) + if self.doc: + self.doc.entitydb.add(mtext) + self.add_entity(mtext) + return mtext + + def add_mtext_dynamic_manual_height_columns( + self, + content: str, + width: float, + gutter_width: float, + heights: Sequence[float], + dxfattribs=None, + ) -> MText: + """Add a multiline text entity with dynamic columns as + :class:`~ezdxf.entities.MText` entity. The content is spread + across the columns automatically by the CAD application. + The `heights` sequence determine the height of the columns, except for + the last column, which always takes the remaining content. The height + value for the last column is required but can be 0, because the value + is ignored. The count of `heights` also determines the count of columns, + and :code:`max(heights)` defines the total height of the MTEXT entity, + which may be wrong if the last column requires more space. + + This current implementation works best for DXF R2018, because the + content is stored as a continuous text in a single MTEXT entity. For + DXF versions prior to R2018 the content should be distributed across + multiple MTEXT entities (one entity per column), which is not done by + `ezdxf`, but the result is correct for advanced DXF viewers and CAD + application, which do the MTEXT content distribution completely by + itself. + + (requires DXF R2000) + + Args: + content: column content as a single string + width: column width + gutter_width: distance between columns + heights: column height for each column + dxfattribs: additional DXF attributes + + """ + # The current implementation work well for R2018. + # + # For the prior DXF versions the current implementation puts the whole + # content into the first (main) column. + # This works for AutoCAD and BricsCAD, both collect the content from + # the linked MTEXT columns and the main column and do their own MTEXT + # rendering - DO trust the DXF content! + # The drawing add-on will fail at this until a usable MTEXT renderer + # is implemented. For now the drawing add-on renders the main MTEXT and + # the linked MTEXT columns as standalone MTEXT entities, and all content + # is stored in the main MTEXT entity. + # For the same reason the R2018 MTEXT rendering is not correct. + # In DXF R2018 the MTEXT entity is a single entity without linked + # MTEXT columns and the content is a single string, which has to be + # parsed, rendered and distributed across the columns by the + # CAD application itself. + + dxfversion = self.dxfversion + if dxfversion < DXF2000: + raise DXFVersionError("MTEXT requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + if dxfversion < const.DXF2018: + mtext = make_dynamic_manual_height_columns_r2000( + content, width, gutter_width, heights, dxfattribs + ) + else: + mtext = make_dynamic_manual_height_columns_r2018( + content, width, gutter_width, heights, dxfattribs + ) + if self.doc: + self.doc.entitydb.add(mtext) + self.add_entity(mtext) + return mtext + + def add_ray(self, start: UVec, unit_vector: UVec, dxfattribs=None) -> Ray: + """ + Add a :class:`~ezdxf.entities.Ray` that begins at `start` point and + continues to infinity (construction line). (requires DXF R2000) + + Args: + start: location 3D point in :ref:`WCS` + unit_vector: 3D vector (x, y, z) + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("RAY requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["start"] = Vec3(start) + dxfattribs["unit_vector"] = Vec3(unit_vector).normalize() + return self.new_entity("RAY", dxfattribs) # type: ignore + + def add_xline( + self, start: UVec, unit_vector: UVec, dxfattribs=None + ) -> XLine: + """Add an infinity :class:`~ezdxf.entities.XLine` (construction line). + (requires DXF R2000) + + Args: + start: location 3D point in :ref:`WCS` + unit_vector: 3D vector (x, y, z) + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("XLINE requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["start"] = Vec3(start) + dxfattribs["unit_vector"] = Vec3(unit_vector).normalize() + return self.new_entity("XLINE", dxfattribs) # type: ignore + + def add_spline( + self, + fit_points: Optional[Iterable[UVec]] = None, + degree: int = 3, + dxfattribs=None, + ) -> Spline: + """Add a B-spline (:class:`~ezdxf.entities.Spline` entity) defined by + the given `fit_points` - the control points and knot values are created + by the CAD application, therefore it is not predictable how the rendered + spline will look like, because for every set of fit points exists an + infinite set of B-splines. + + If `fit_points` is ``None``, an "empty" spline will be created, all data + has to be set by the user. + + The SPLINE entity requires DXF R2000. + + AutoCAD creates a spline through fit points by a global curve + interpolation and an unknown method to estimate the direction of the + start- and end tangent. + + .. seealso:: + + - :ref:`tut_spline` + - :func:`ezdxf.math.fit_points_to_cad_cv` + + Args: + fit_points: iterable of fit points as ``(x, y[, z])`` in :ref:`WCS`, + creates an empty :class:`~ezdxf.entities.Spline` if ``None`` + degree: degree of B-spline, max. degree supported by AutoCAD is 11 + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("SPLINE requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["degree"] = int(degree) + spline: Spline = self.new_entity("SPLINE", dxfattribs) # type: ignore + if fit_points is not None: + spline.fit_points = Vec3.generate(fit_points) + return spline + + def add_spline_control_frame( + self, + fit_points: Iterable[UVec], + degree: int = 3, + method: str = "chord", + dxfattribs=None, + ) -> Spline: + """Add a :class:`~ezdxf.entities.Spline` entity passing through the + given `fit_points`, the control points are calculated by a global curve + interpolation without start- and end tangent constrains. + The new SPLINE entity is defined by control points and not by the fit + points, therefore the SPLINE looks always the same, no matter which CAD + application renders the SPLINE. + + - "uniform": creates a uniform t vector, from 0 to 1 evenly spaced, see + `uniform`_ method + - "distance", "chord": creates a t vector with values proportional to + the fit point distances, see `chord length`_ method + - "centripetal", "sqrt_chord": creates a t vector with values + proportional to the fit point sqrt(distances), see `centripetal`_ + method + - "arc": creates a t vector with values proportional to the arc length + between fit points. + + Use function :meth:`add_cad_spline_control_frame` to create + SPLINE entities from fit points similar to CAD application including + start- and end tangent constraints. + + Args: + fit_points: iterable of fit points as (x, y[, z]) in :ref:`WCS` + degree: degree of B-spline, max. degree supported by AutoCAD is 11 + method: calculation method for parameter vector t + dxfattribs: additional DXF attributes + + """ + bspline = global_bspline_interpolation( + fit_points, degree=degree, method=method + ) + return self.add_open_spline( + control_points=bspline.control_points, + degree=bspline.degree, + knots=bspline.knots(), + dxfattribs=dxfattribs, + ) + + def add_cad_spline_control_frame( + self, + fit_points: Iterable[UVec], + tangents: Optional[Iterable[UVec]] = None, + dxfattribs=None, + ) -> Spline: + """Add a :class:`~ezdxf.entities.Spline` entity passing through the + given fit points. This method creates the same control points as CAD + applications. + + Args: + fit_points: iterable of fit points as (x, y[, z]) in :ref:`WCS` + tangents: start- and end tangent, default is autodetect + dxfattribs: additional DXF attributes + + """ + s = fit_points_to_cad_cv(fit_points, tangents=tangents) + spline = self.add_spline(dxfattribs=dxfattribs) + spline.apply_construction_tool(s) + return spline + + def add_open_spline( + self, + control_points: Iterable[UVec], + degree: int = 3, + knots: Optional[Iterable[float]] = None, + dxfattribs=None, + ) -> Spline: + """ + Add an open uniform :class:`~ezdxf.entities.Spline` defined by + `control_points`. (requires DXF R2000) + + Open uniform B-splines start and end at your first and last control point. + + Args: + control_points: iterable of 3D points in :ref:`WCS` + degree: degree of B-spline, max. degree supported by AutoCAD is 11 + knots: knot values as iterable of floats + dxfattribs: additional DXF attributes + + """ + spline = self.add_spline(dxfattribs=dxfattribs) + spline.set_open_uniform(list(control_points), degree) + if knots is not None: + spline.knots = knots # type: ignore + return spline + + def add_rational_spline( + self, + control_points: Iterable[UVec], + weights: Sequence[float], + degree: int = 3, + knots: Optional[Iterable[float]] = None, + dxfattribs=None, + ) -> Spline: + """ + Add an open rational uniform :class:`~ezdxf.entities.Spline` defined by + `control_points`. (requires DXF R2000) + + `weights` has to be an iterable of floats, which defines the influence + of the associated control point to the shape of the B-spline, therefore + for each control point is one weight value required. + + Open rational uniform B-splines start and end at the first and last + control point. + + Args: + control_points: iterable of 3D points in :ref:`WCS` + weights: weight values as iterable of floats + degree: degree of B-spline, max. degree supported by AutoCAD is 11 + knots: knot values as iterable of floats + dxfattribs: additional DXF attributes + + """ + spline = self.add_spline(dxfattribs=dxfattribs) + spline.set_open_rational(list(control_points), weights, degree) + if knots is not None: + spline.knots = knots # type: ignore + return spline + + def add_body(self, dxfattribs=None) -> Body: + """Add a :class:`~ezdxf.entities.Body` entity. + (requires DXF R2000 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + return self._add_acis_entity("BODY", dxfattribs) + + def add_region(self, dxfattribs=None) -> Region: + """Add a :class:`~ezdxf.entities.Region` entity. + (requires DXF R2000 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + return self._add_acis_entity("REGION", dxfattribs) # type: ignore + + def add_3dsolid(self, dxfattribs=None) -> Solid3d: + """Add a 3DSOLID entity (:class:`~ezdxf.entities.Solid3d`). + (requires DXF R2000 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + return self._add_acis_entity("3DSOLID", dxfattribs) # type: ignore + + def add_surface(self, dxfattribs=None) -> Surface: + """Add a :class:`~ezdxf.entities.Surface` entity. + (requires DXF R2007 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + if self.dxfversion < const.DXF2007: + raise DXFVersionError("SURFACE requires DXF R2007 or later") + return self._add_acis_entity("SURFACE", dxfattribs) # type: ignore + + def add_extruded_surface(self, dxfattribs=None) -> ExtrudedSurface: + """Add a :class:`~ezdxf.entities.ExtrudedSurface` entity. + (requires DXF R2007 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + if self.dxfversion < const.DXF2007: + raise DXFVersionError("EXTRUDEDSURFACE requires DXF R2007 or later") + return self._add_acis_entity("EXTRUDEDSURFACE", dxfattribs) # type: ignore + + def add_lofted_surface(self, dxfattribs=None) -> LoftedSurface: + """Add a :class:`~ezdxf.entities.LoftedSurface` entity. + (requires DXF R2007 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + if self.dxfversion < const.DXF2007: + raise DXFVersionError("LOFTEDSURFACE requires DXF R2007 or later") + return self._add_acis_entity("LOFTEDSURFACE", dxfattribs) # type: ignore + + def add_revolved_surface(self, dxfattribs=None) -> RevolvedSurface: + """ + Add a :class:`~ezdxf.entities.RevolvedSurface` entity. + (requires DXF R2007 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + if self.dxfversion < const.DXF2007: + raise DXFVersionError("REVOLVEDSURFACE requires DXF R2007 or later") + return self._add_acis_entity("REVOLVEDSURFACE", dxfattribs) # type: ignore + + def add_swept_surface(self, dxfattribs=None) -> SweptSurface: + """ + Add a :class:`~ezdxf.entities.SweptSurface` entity. + (requires DXF R2007 or later) + + The ACIS data has to be set as :term:`SAT` or :term:`SAB`. + + """ + if self.dxfversion < const.DXF2007: + raise DXFVersionError("SWEPTSURFACE requires DXF R2007 or later") + return self._add_acis_entity("SWEPTSURFACE", dxfattribs) # type: ignore + + def _add_acis_entity(self, name, dxfattribs) -> Body: + if self.dxfversion < const.DXF2000: + raise DXFVersionError(f"{name} requires DXF R2000 or later") + dxfattribs = dict(dxfattribs or {}) + if self.dxfversion >= DXF2013: + dxfattribs.setdefault("flags", 1) + dxfattribs.setdefault("uid", guid()) + return self.new_entity(name, dxfattribs) # type: ignore + + def add_hatch(self, color: int = 7, dxfattribs=None) -> Hatch: + """Add a :class:`~ezdxf.entities.Hatch` entity. (requires DXF R2000) + + Args: + color: fill color as :ref`ACI`, default is 7 (black/white). + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("HATCH requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["solid_fill"] = 1 + dxfattribs["color"] = int(color) + dxfattribs["pattern_name"] = "SOLID" + return self.new_entity("HATCH", dxfattribs) # type: ignore + + def add_mpolygon( + self, + color: int = const.BYLAYER, + fill_color: Optional[int] = None, + dxfattribs=None, + ) -> MPolygon: + """Add a :class:`~ezdxf.entities.MPolygon` entity. (requires DXF R2000) + + The MPOLYGON entity is not a core DXF entity and is not supported by + every CAD application or DXF library. + + DXF version R2004+ is required to use a fill color different from + BYLAYER. For R2000 the fill color is always BYLAYER, set any ACI value + to create a filled MPOLYGON entity. + + Args: + color: boundary color as :ref:`ACI`, default is BYLAYER. + fill_color: fill color as :ref:`ACI`, default is ``None`` + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("MPOLYGON requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + if fill_color is None: + dxfattribs["solid_fill"] = 0 + else: + dxfattribs["solid_fill"] = 1 + dxfattribs["fill_color"] = fill_color + + dxfattribs["pattern_name"] = "SOLID" + dxfattribs["pattern_type"] = const.HATCH_TYPE_PREDEFINED + dxfattribs["color"] = int(color) + return self.new_entity("MPOLYGON", dxfattribs) # type: ignore + + def add_mesh(self, dxfattribs=None) -> Mesh: + """ + Add a :class:`~ezdxf.entities.Mesh` entity. (requires DXF R2007) + + Args: + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("MESH requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + return self.new_entity("MESH", dxfattribs) # type: ignore + + def add_image( + self, + image_def: ImageDef, + insert: UVec, + size_in_units: tuple[float, float], + rotation: float = 0.0, + dxfattribs=None, + ) -> Image: + """ + Add an :class:`~ezdxf.entities.Image` entity, requires a + :class:`~ezdxf.entities.ImageDef` entity, see :ref:`tut_image`. + (requires DXF R2000) + + Args: + image_def: required image definition as :class:`~ezdxf.entities.ImageDef` + insert: insertion point as 3D point in :ref:`WCS` + size_in_units: size as (x, y) tuple in drawing units + rotation: rotation angle around the extrusion axis, default is the + z-axis, in degrees + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("IMAGE requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + x_pixels, y_pixels = image_def.dxf.image_size.vec2 + x_units, y_units = size_in_units + x_units_per_pixel = x_units / x_pixels + y_units_per_pixel = y_units / y_pixels + x_angle_rad = math.radians(rotation) + y_angle_rad = x_angle_rad + (math.pi / 2.0) + + dxfattribs["insert"] = Vec3(insert) + dxfattribs["u_pixel"] = Vec3.from_angle(x_angle_rad, x_units_per_pixel) + dxfattribs["v_pixel"] = Vec3.from_angle(y_angle_rad, y_units_per_pixel) + dxfattribs["image_def"] = image_def # is not a real DXF attrib + return self.new_entity("IMAGE", dxfattribs) # type: ignore + + def add_wipeout(self, vertices: Iterable[UVec], dxfattribs=None) -> Wipeout: + """Add a :class:`ezdxf.entities.Wipeout` entity, the masking area is + defined by WCS `vertices`. + + This method creates only a 2D entity in the xy-plane of the layout, + the z-axis of the input vertices are ignored. + + """ + dxfattribs = dict(dxfattribs or {}) + wipeout: Wipeout = self.new_entity("WIPEOUT", dxfattribs=dxfattribs) # type: ignore + wipeout.set_masking_area(vertices) + doc = self.doc + if doc and ("ACAD_WIPEOUT_VARS" not in doc.rootdict): + doc.set_wipeout_variables(frame=0) + return wipeout + + def add_underlay( + self, + underlay_def: UnderlayDefinition, + insert: UVec = (0, 0, 0), + scale=(1, 1, 1), + rotation: float = 0.0, + dxfattribs=None, + ) -> Underlay: + """ + Add an :class:`~ezdxf.entities.Underlay` entity, requires a + :class:`~ezdxf.entities.UnderlayDefinition` entity, + see :ref:`tut_underlay`. (requires DXF R2000) + + Args: + underlay_def: required underlay definition as :class:`~ezdxf.entities.UnderlayDefinition` + insert: insertion point as 3D point in :ref:`WCS` + scale: underlay scaling factor as (x, y, z) tuple or as single + value for uniform scaling for x, y and z + rotation: rotation angle around the extrusion axis, default is the + z-axis, in degrees + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("UNDERLAY requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + dxfattribs["insert"] = Vec3(insert) + dxfattribs["underlay_def_handle"] = underlay_def.dxf.handle + dxfattribs["rotation"] = float(rotation) + + underlay: Underlay = self.new_entity( # type: ignore + underlay_def.entity_name, dxfattribs + ) + underlay.scaling = scale + underlay.set_underlay_def(underlay_def) + return underlay + + def _safe_dimstyle(self, name: str) -> str: + if self.doc and self.doc.dimstyles.has_entry(name): + return name + logger.debug( + f'Replacing undefined DIMSTYLE "{name}" by "Standard" DIMSTYLE.' + ) + return "Standard" + + def add_linear_dim( + self, + base: UVec, + p1: UVec, + p2: UVec, + location: Optional[UVec] = None, + text: str = "<>", + angle: float = 0, + # 0=horizontal, 90=vertical, else=rotated + text_rotation: Optional[float] = None, + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add horizontal, vertical and rotated :class:`~ezdxf.entities.Dimension` + line. If an :class:`~ezdxf.math.UCS` is used for dimension line rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + See also: :ref:`tut_linear_dimension` + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.Dimension` entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + base: location of dimension line, any point on the dimension line or + its extension will do (in UCS) + p1: measurement point 1 and start point of extension line 1 (in UCS) + p2: measurement point 2 and start point of extension line 2 (in UCS) + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, everything + else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZDXF" + angle: angle from ucs/wcs x-axis to dimension line in degrees + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + type_ = {"dimtype": const.DIM_LINEAR | const.DIM_BLOCK_EXCLUSIVE} + dimline: Dimension = self.new_entity("DIMENSION", dxfattribs=type_) # type: ignore + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["defpoint"] = Vec3(base) # group code 10 + dxfattribs["text"] = str(text) + dxfattribs["defpoint2"] = Vec3(p1) # group code 13 + dxfattribs["defpoint3"] = Vec3(p2) # group code 14 + dxfattribs["angle"] = float(angle) + + # text_rotation ALWAYS overrides implicit angles as absolute angle + # (x-axis=0, y-axis=90)! + if text_rotation is not None: + dxfattribs["text_rotation"] = float(text_rotation) + dimline.update_dxf_attribs(dxfattribs) + + style = DimStyleOverride(dimline, override=override) + if location is not None: + # special version, just for linear dimension + style.set_location(location, leader=False, relative=False) + return style + + def add_multi_point_linear_dim( + self, + base: UVec, + points: Iterable[UVec], + angle: float = 0, + ucs: Optional[UCS] = None, + avoid_double_rendering: bool = True, + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + discard=False, + ) -> None: + """ + Add multiple linear dimensions for iterable `points`. If an + :class:`~ezdxf.math.UCS` is used for dimension line rendering, all point + definitions in UCS coordinates, translation into :ref:`WCS` and + :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. See also: + :ref:`tut_linear_dimension` + + This method sets many design decisions by itself, the necessary geometry + will be generated automatically, no required nor possible + :meth:`~ezdxf.entities.DimStyleOverride.render` call. + This method is easy to use, but you get what you get. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + base: location of dimension line, any point on the dimension line + or its extension will do (in UCS) + points: iterable of measurement points (in UCS) + angle: angle from ucs/wcs x-axis to dimension line in degrees + (0 = horizontal, 90 = vertical) + ucs: user defined coordinate system + avoid_double_rendering: suppresses the first extension line and the + first arrow if possible for continued dimension entities + dimstyle: dimension style name (DimStyle table entry), + default is "EZDXF" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + discard: discard rendering result for friendly CAD applications like + BricsCAD to get a native and likely better rendering result. + (does not work with AutoCAD) + + """ + dxfattribs = dict(dxfattribs or {}) + multi_point_linear_dimension( + cast("GenericLayoutType", self), + base=base, + points=points, + angle=angle, + ucs=ucs, + avoid_double_rendering=avoid_double_rendering, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + discard=discard, + ) + + def add_aligned_dim( + self, + p1: UVec, + p2: UVec, + distance: float, + text: str = "<>", + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add linear dimension aligned with measurement points `p1` and `p2`. If + an :class:`~ezdxf.math.UCS` is used for dimension line rendering, all + point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector + is defined by UCS or (0, 0, 1) by default. + See also: :ref:`tut_linear_dimension` + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object, + to create the necessary dimension geometry, you have to call + :meth:`DimStyleOverride.render` manually, this two-step process allows + additional processing steps on the :class:`~ezdxf.entities.Dimension` + entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + p1: measurement point 1 and start point of extension line 1 (in UCS) + p2: measurement point 2 and start point of extension line 2 (in UCS) + distance: distance of dimension line from measurement points + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZDXF" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + _p1 = Vec3(p1) + _p2 = Vec3(p2) + direction = _p2 - _p1 + angle = direction.angle_deg + base = direction.orthogonal().normalize(distance) + _p1 + return self.add_linear_dim( + base=base, + p1=_p1, + p2=_p2, + dimstyle=dimstyle, + text=text, + angle=angle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_angular_dim_2l( + self, + base: UVec, + line1: tuple[UVec, UVec], + line2: tuple[UVec, UVec], + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add angular :class:`~ezdxf.entities.Dimension` from two lines. The + measurement is always done from `line1` to `line2` in counter-clockwise + orientation. This does not always match the result in CAD applications! + + If an :class:`~ezdxf.math.UCS` is used for angular dimension rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.Dimension` entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + base: location of dimension line, any point on the dimension line or + its extension is valid (in UCS) + line1: specifies start leg of the angle (start point, end point) and + determines extension line 1 (in UCS) + line2: specifies end leg of the angle (start point, end point) and + determines extension line 2 (in UCS) + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + type_ = {"dimtype": const.DIM_ANGULAR | const.DIM_BLOCK_EXCLUSIVE} + dimline: Dimension = self.new_entity("DIMENSION", dxfattribs=type_) # type: ignore + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["text"] = str(text) + + dxfattribs["defpoint2"] = Vec3(line1[0]) # group code 13 + dxfattribs["defpoint3"] = Vec3(line1[1]) # group code 14 + dxfattribs["defpoint4"] = Vec3(line2[0]) # group code 15 + dxfattribs["defpoint"] = Vec3(line2[1]) # group code 10 + dxfattribs["defpoint5"] = Vec3(base) # group code 16 + + # text_rotation ALWAYS overrides implicit angles as absolute angle (x-axis=0, y-axis=90)! + if text_rotation is not None: + dxfattribs["text_rotation"] = float(text_rotation) + + dimline.update_dxf_attribs(dxfattribs) + style = DimStyleOverride(dimline, override=override) + if location is not None: + style.user_location_override(location) + return style + + def add_angular_dim_3p( + self, + base: UVec, + center: UVec, + p1: UVec, + p2: UVec, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add angular :class:`~ezdxf.entities.Dimension` from three points + (center, p1, p2). The measurement is always done from `p1` to `p2` in + counter-clockwise orientation. This does not always match the result in + CAD applications! + + If an :class:`~ezdxf.math.UCS` is used for angular dimension rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.Dimension` entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + base: location of dimension line, any point on the dimension line + or its extension is valid (in UCS) + center: specifies the vertex of the angle + p1: specifies start leg of the angle (center -> p1) and end-point + of extension line 1 (in UCS) + p2: specifies end leg of the angle (center -> p2) and end-point + of extension line 2 (in UCS) + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + type_ = {"dimtype": const.DIM_ANGULAR_3P | const.DIM_BLOCK_EXCLUSIVE} + dimline = cast( + "Dimension", self.new_entity("DIMENSION", dxfattribs=type_) + ) + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["text"] = str(text) + dxfattribs["defpoint"] = Vec3(base) + dxfattribs["defpoint2"] = Vec3(p1) + dxfattribs["defpoint3"] = Vec3(p2) + dxfattribs["defpoint4"] = Vec3(center) + + # text_rotation ALWAYS overrides implicit angles as absolute angle + # (x-axis=0, y-axis=90)! + if text_rotation is not None: + dxfattribs["text_rotation"] = float(text_rotation) + + dimline.update_dxf_attribs(dxfattribs) + style = DimStyleOverride(dimline, override=override) + if location is not None: + style.user_location_override(location) + return style + + def add_angular_dim_cra( + self, + center: UVec, + radius: float, + start_angle: float, + end_angle: float, + distance: float, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create an angular dimension by (c)enter point, + (r)adius and start- and end (a)ngles, the measurement text is placed at + the default location defined by the associated `dimstyle`. + The measurement is always done from `start_angle` to `end_angle` in + counter-clockwise orientation. This does not always match the result in + CAD applications! + For further information see the more generic factory method + :func:`add_angular_dim_3p`. + + Args: + center: center point of the angle (in UCS) + radius: the distance from `center` to the start of the extension + lines in drawing units + start_angle: start angle in degrees (in UCS) + end_angle: end angle in degrees (in UCS) + distance: distance from start of the extension lines to the + dimension line in drawing units + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + sa = float(start_angle) + ea = float(end_angle) + ext_line_start = float(radius) + dim_line_offset = float(distance) + center_ = Vec3(center) + + center_angle = sa + arc_angle_span_deg(sa, ea) / 2.0 + # ca = (sa + ea) / 2 is not correct: e.g. 30, -30 is 0 but should be 180 + + base = center_ + Vec3.from_deg_angle(center_angle) * ( + ext_line_start + dim_line_offset + ) + p1 = center_ + Vec3.from_deg_angle(sa) * ext_line_start + p2 = center_ + Vec3.from_deg_angle(ea) * ext_line_start + return self.add_angular_dim_3p( + base=base, + center=center_, + p1=p1, + p2=p2, + location=location, + text=text, + text_rotation=text_rotation, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_angular_dim_arc( + self, + arc: ConstructionArc, + distance: float, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create an angular dimension from a + :class:`~ezdxf.math.ConstructionArc`. This construction tool can + be created from ARC entities and the tool itself provides various + construction class methods. + The measurement text is placed at the default location defined by the + associated `dimstyle`. + The measurement is always done from `start_angle` to `end_angle` of the + arc in counter-clockwise orientation. + This does not always match the result in CAD applications! + For further information see the more generic factory method + :func:`add_angular_dim_3p`. + + Args: + arc: :class:`~ezdxf.math.ConstructionArc` + distance: distance from start of the extension lines to the + dimension line in drawing units + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + return self.add_angular_dim_cra( + center=arc.center, + radius=arc.radius, + start_angle=arc.start_angle, + end_angle=arc.end_angle, + distance=distance, + location=location, + text=text, + text_rotation=text_rotation, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_arc_dim_3p( + self, + base: UVec, + center: UVec, + p1: UVec, + p2: UVec, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add :class:`~ezdxf.entities.ArcDimension` from three points + (center, p1, p2). Point `p1` defines the radius and the start-angle of + the arc, point `p2` only defines the end-angle of the arc. + + If an :class:`~ezdxf.math.UCS` is used for arc dimension rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.ArcDimension` entity between creation and + rendering. + + .. note:: + + `Ezdxf` does not render the arc dimension like CAD applications and + does not consider all DIMSTYLE variables, so the rendering results + are **very** different from CAD applications. + + Args: + base: location of dimension line, any point on the dimension line + or its extension is valid (in UCS) + center: specifies the vertex of the angle + p1: specifies the radius (center -> p1) and the star angle of the + arc, this is also the start point for the 1st extension line (in UCS) + p2: specifies the end angle of the arc. The start 2nd extension line + is defined by this angle and the radius defined by p1 (in UCS) + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + # always set dimtype to 8 for DXF R2013+, the DXF export handles the + # version dependent dimtype + type_ = {"dimtype": const.DIM_ARC | const.DIM_BLOCK_EXCLUSIVE} + dimline: ArcDimension = self.new_entity( # type: ignore + "ARC_DIMENSION", dxfattribs=type_ + ) + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["text"] = str(text) + dxfattribs["defpoint"] = Vec3(base) + dxfattribs["defpoint2"] = Vec3(p1) + dxfattribs["defpoint3"] = Vec3(p2) + dxfattribs["defpoint4"] = Vec3(center) + dxfattribs["start_angle"] = 0.0 # unknown meaning + dxfattribs["end_angle"] = 0.0 # unknown meaning + dxfattribs["is_partial"] = 0 # unknown meaning + dxfattribs["has_leader"] = 0 # ignored by ezdxf + dxfattribs["leader_point1"] = NULLVEC # ignored by ezdxf + dxfattribs["leader_point2"] = NULLVEC # ignored by ezdxf + + # text_rotation ALWAYS overrides implicit angles as absolute angle + # (x-axis=0, y-axis=90)! + if text_rotation is not None: + dxfattribs["text_rotation"] = float(text_rotation) + + dimline.update_dxf_attribs(dxfattribs) + style = DimStyleOverride(dimline, override=override) + if location is not None: + style.user_location_override(location) + return style + + def add_arc_dim_cra( + self, + center: UVec, + radius: float, + start_angle: float, + end_angle: float, + distance: float, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create an arc dimension by (c)enter point, + (r)adius and start- and end (a)ngles, the measurement text is placed at + the default location defined by the associated `dimstyle`. + + .. note:: + + `Ezdxf` does not render the arc dimension like CAD applications and + does not consider all DIMSTYLE variables, so the rendering results + are **very** different from CAD applications. + + Args: + center: center point of the angle (in UCS) + radius: the distance from `center` to the start of the extension + lines in drawing units + start_angle: start-angle in degrees (in UCS) + end_angle: end-angle in degrees (in UCS) + distance: distance from start of the extension lines to the + dimension line in drawing units + location: user defined location for text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + sa = float(start_angle) + ea = float(end_angle) + ext_line_start = float(radius) + dim_line_offset = float(distance) + center_ = Vec3(center) + + center_angle = sa + arc_angle_span_deg(sa, ea) / 2.0 + # ca = (sa + ea) / 2 is not correct: e.g. 30, -30 is 0 but should be 180 + + base = center_ + Vec3.from_deg_angle(center_angle) * ( + ext_line_start + dim_line_offset + ) + p1 = center_ + Vec3.from_deg_angle(sa) * ext_line_start + p2 = center_ + Vec3.from_deg_angle(ea) * ext_line_start + return self.add_arc_dim_3p( + base=base, + center=center_, + p1=p1, + p2=p2, + location=location, + text=text, + text_rotation=text_rotation, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_arc_dim_arc( + self, + arc: ConstructionArc, + distance: float, + *, + location: Optional[UVec] = None, + text: str = "<>", + text_rotation: Optional[float] = None, + dimstyle: str = "EZ_CURVED", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create an arc dimension from a + :class:`~ezdxf.math.ConstructionArc`. This construction tool can + be created from ARC entities and the tool itself provides various + construction class methods. + The measurement text is placed at the default location defined by the + associated `dimstyle`. + + .. note:: + + `Ezdxf` does not render the arc dimension like CAD applications and + does not consider all DIMSTYLE variables, so the rendering results + are **very** different from CAD applications. + + Args: + arc: :class:`~ezdxf.math.ConstructionArc` + distance: distance from start of the extension lines to the + dimension line in drawing units + location: user defined location for the text midpoint (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + text_rotation: rotation angle of the dimension text as absolute + angle (x-axis=0, y-axis=90) in degrees + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_CURVED" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + return self.add_arc_dim_cra( + center=arc.center, + radius=arc.radius, + start_angle=arc.start_angle, + end_angle=arc.end_angle, + distance=distance, + location=location, + text=text, + text_rotation=text_rotation, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_diameter_dim( + self, + center: UVec, + mpoint: Optional[UVec] = None, + radius: Optional[float] = None, + angle: Optional[float] = None, + *, + location: Optional[UVec] = None, + text: str = "<>", + dimstyle: str = "EZ_RADIUS", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add a diameter :class:`~ezdxf.entities.Dimension` line. The diameter + dimension line requires a `center` point and a point `mpoint` on the + circle or as an alternative a `radius` and a dimension line `angle` in + degrees. + + If an :class:`~ezdxf.math.UCS` is used for dimension line rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the :class:`~ezdxf.entities.Dimension` + entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + center: specifies the center of the circle (in UCS) + mpoint: specifies the measurement point on the circle (in UCS) + radius: specify radius, requires argument `angle`, overrides `p1` argument + angle: specify angle of dimension line in degrees, requires argument + `radius`, overrides `p1` argument + location: user defined location for the text midpoint (in UCS) + text: ``None`` or ``"<>"`` the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_RADIUS" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + type_ = {"dimtype": const.DIM_DIAMETER | const.DIM_BLOCK_EXCLUSIVE} + dimline = cast( + "Dimension", self.new_entity("DIMENSION", dxfattribs=type_) + ) + center = Vec3(center) + if location is not None: + if radius is None: + raise ValueError("Argument radius is required.") + location = Vec3(location) + + # (center - location) just works as expected, but in my + # understanding it should be: (location - center) + radius_vec = (center - location).normalize(length=radius) + else: # defined by mpoint = measurement point on circle + if mpoint is None: # defined by radius and angle + if angle is None: + raise ValueError("Argument angle or mpoint required.") + if radius is None: + raise ValueError("Argument radius or mpoint required.") + radius_vec = Vec3.from_deg_angle(angle, radius) + else: + radius_vec = Vec3(mpoint) - center + + p1 = center + radius_vec + p2 = center - radius_vec + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["defpoint"] = Vec3(p1) # group code 10 + dxfattribs["defpoint4"] = Vec3(p2) # group code 15 + dxfattribs["text"] = str(text) + + dimline.update_dxf_attribs(dxfattribs) + + style = DimStyleOverride(dimline, override=override) + if location is not None: + style.user_location_override(location) + return style + + def add_diameter_dim_2p( + self, + p1: UVec, + p2: UVec, + text: str = "<>", + dimstyle: str = "EZ_RADIUS", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create a diameter dimension by two points on the + circle and the measurement text at the default location defined by the + associated `dimstyle`, for further information see general method + :func:`add_diameter_dim`. Center point of the virtual circle is the + midpoint between `p1` and `p2`. + + - dimstyle "EZ_RADIUS": places the dimension text outside + - dimstyle "EZ_RADIUS_INSIDE": places the dimension text inside + + Args: + p1: first point of the circle (in UCS) + p2: second point on the opposite side of the center point of the + circle (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_RADIUS" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + mpoint = Vec3(p1) + center = mpoint.lerp(p2) + return self.add_diameter_dim( + center, + mpoint, + text=text, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_radius_dim( + self, + center: UVec, + mpoint: Optional[UVec] = None, + radius: Optional[float] = None, + angle: Optional[float] = None, + *, + location: Optional[UVec] = None, + text: str = "<>", + dimstyle: str = "EZ_RADIUS", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add a radius :class:`~ezdxf.entities.Dimension` line. The radius + dimension line requires a `center` point and a point `mpoint` on the + circle or as an alternative a `radius` and a dimension line `angle` in + degrees. See also: :ref:`tut_radius_dimension` + + If a :class:`~ezdxf.math.UCS` is used for dimension line rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.Dimension` entity between creation and rendering. + + Following render types are supported: + + - Default text location outside: text aligned with dimension line; + dimension style: "EZ_RADIUS" + - Default text location outside horizontal: "EZ_RADIUS" + dimtoh=1 + - Default text location inside: text aligned with dimension line; + dimension style: "EZ_RADIUS_INSIDE" + - Default text location inside horizontal: "EZ_RADIUS_INSIDE" + dimtih=1 + - User defined text location: argument `location` != ``None``, text + aligned with dimension line; dimension style: "EZ_RADIUS" + - User defined text location horizontal: argument `location` != ``None``, + "EZ_RADIUS" + dimtoh=1 for text outside horizontal, "EZ_RADIUS" + + dimtih=1 for text inside horizontal + + Placing the dimension text at a user defined `location`, overrides the + `mpoint` and the `angle` argument, but requires a given `radius` + argument. The `location` argument does not define the exact text + location, instead it defines the dimension line starting at `center` + and the measurement text midpoint projected on this dimension line + going through `location`, if text is aligned to the dimension line. + If text is horizontal, `location` is the kink point of the dimension + line from radial to horizontal direction. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + center: center point of the circle (in UCS) + mpoint: measurement point on the circle, overrides `angle` and + `radius` (in UCS) + radius: radius in drawing units, requires argument `angle` + angle: specify angle of dimension line in degrees, requires + argument `radius` + location: user defined dimension text location, overrides `mpoint` + and `angle`, but requires `radius` (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_RADIUS" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + type_ = {"dimtype": const.DIM_RADIUS | const.DIM_BLOCK_EXCLUSIVE} + dimline = cast( + "Dimension", self.new_entity("DIMENSION", dxfattribs=type_) + ) + center = Vec3(center) + if location is not None: + if radius is None: + raise ValueError("Argument radius is required.") + location = Vec3(location) + radius_vec = (location - center).normalize(length=radius) + mpoint = center + radius_vec + else: # defined by mpoint = measurement point on circle + if mpoint is None: # defined by radius and angle + if angle is None: + raise ValueError("Argument angle or mpoint required.") + if radius is None: + raise ValueError("Argument radius or mpoint required.") + mpoint = center + Vec3.from_deg_angle(angle, radius) + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["defpoint4"] = Vec3(mpoint) # group code 15 + dxfattribs["defpoint"] = Vec3(center) # group code 10 + dxfattribs["text"] = str(text) + + dimline.update_dxf_attribs(dxfattribs) + + style = DimStyleOverride(dimline, override=override) + if location is not None: + style.user_location_override(location) + + return style + + def add_radius_dim_2p( + self, + center: UVec, + mpoint: UVec, + *, + text: str = "<>", + dimstyle: str = "EZ_RADIUS", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create a radius dimension by center point, + measurement point on the circle and the measurement text at the default + location defined by the associated `dimstyle`, for further information + see general method :func:`add_radius_dim`. + + - dimstyle "EZ_RADIUS": places the dimension text outside + - dimstyle "EZ_RADIUS_INSIDE": places the dimension text inside + + Args: + center: center point of the circle (in UCS) + mpoint: measurement point on the circle (in UCS) + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_RADIUS" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + return self.add_radius_dim( + center, + mpoint, + text=text, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_radius_dim_cra( + self, + center: UVec, + radius: float, + angle: float, + *, + text: str = "<>", + dimstyle: str = "EZ_RADIUS", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Shortcut method to create a radius dimension by (c)enter point, + (r)adius and (a)ngle, the measurement text is placed at the default + location defined by the associated `dimstyle`, for further information + see general method :func:`add_radius_dim`. + + - dimstyle "EZ_RADIUS": places the dimension text outside + - dimstyle "EZ_RADIUS_INSIDE": places the dimension text inside + + Args: + center: center point of the circle (in UCS) + radius: radius in drawing units + angle: angle of dimension line in degrees + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZ_RADIUS" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + return self.add_radius_dim( + center, + radius=radius, + angle=angle, + text=text, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_ordinate_dim( + self, + feature_location: UVec, + offset: UVec, + dtype: int, + *, + origin: UVec = NULLVEC, + rotation: float = 0.0, + text: str = "<>", + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """ + Add an ordinate type :class:`~ezdxf.entities.Dimension` line. The + feature location is defined in the global coordinate system, which is + set as render UCS, which is the :ref:`WCS` by default. + + If an :class:`~ezdxf.math.UCS` is used for dimension line rendering, + all point definitions in UCS coordinates, translation into :ref:`WCS` + and :ref:`OCS` is done by the rendering function. Extrusion vector is + defined by UCS or (0, 0, 1) by default. + + This method returns a :class:`~ezdxf.entities.DimStyleOverride` object - + to create the necessary dimension geometry, you have to call + :meth:`~ezdxf.entities.DimStyleOverride.render` manually, this two-step + process allows additional processing steps on the + :class:`~ezdxf.entities.Dimension` entity between creation and rendering. + + .. note:: + + `Ezdxf` does not consider all DIMSTYLE variables, so the + rendering results are different from CAD applications. + + Args: + feature_location: feature location in the global coordinate system (UCS) + offset: offset vector of leader end point from the feature location + in the local coordinate system + dtype: 1 = x-type, 0 = y-type + origin: specifies the origin (0, 0) of the local coordinate + system in UCS + rotation: rotation angle of the local coordinate system in degrees + text: ``None`` or "<>" the measurement is drawn as text, + " " (a single space) suppresses the dimension text, + everything else `text` is drawn as dimension text + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZDXF" + override: :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes for the DIMENSION entity + + Returns: :class:`~ezdxf.entities.DimStyleOverride` + + """ + dtype = int(dtype) + if dtype not in (0, 1): + raise DXFValueError("invalid dtype (0, 1)") + + type_ = { + "dimtype": const.DIM_ORDINATE + | const.DIM_BLOCK_EXCLUSIVE + | (const.DIM_ORDINATE_TYPE * dtype) + } + + dimline = cast( + "Dimension", self.new_entity("DIMENSION", dxfattribs=type_) + ) + origin_ = Vec3(origin) + feature_location_ = Vec3(feature_location) + end_point_ = feature_location_ + Vec3(offset) + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs["defpoint"] = origin_ # group code 10 + rotation = float(rotation) + if rotation: + # Horizontal direction in clockwise orientation, see DXF reference + # for group code 51: + dxfattribs["horizontal_direction"] = -rotation + + relative_feature_location = feature_location_ - origin_ + dxfattribs[ + "defpoint2" + ] = origin_ + relative_feature_location.rotate_deg(rotation) + dxfattribs["defpoint3"] = end_point_.rotate_deg(rotation) + dxfattribs["text"] = str(text) + dimline.update_dxf_attribs(dxfattribs) + + style = DimStyleOverride(dimline, override=override) + return style + + def add_ordinate_x_dim( + self, + feature_location: UVec, + offset: UVec, + *, + origin: UVec = NULLVEC, + rotation: float = 0.0, + text: str = "<>", + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """Shortcut to add an x-type feature ordinate DIMENSION, for more + information see :meth:`add_ordinate_dim`. + + """ + return self.add_ordinate_dim( + feature_location=feature_location, + offset=offset, + dtype=1, + origin=origin, + rotation=rotation, + text=text, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_ordinate_y_dim( + self, + feature_location: UVec, + offset: UVec, + *, + origin: UVec = NULLVEC, + rotation: float = 0.0, + text: str = "<>", + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> DimStyleOverride: + """Shortcut to add a y-type feature ordinate DIMENSION, for more + information see :meth:`add_ordinate_dim`. + + """ + return self.add_ordinate_dim( + feature_location=feature_location, + offset=offset, + dtype=0, + origin=origin, + rotation=rotation, + text=text, + dimstyle=dimstyle, + override=override, + dxfattribs=dxfattribs, + ) + + def add_arrow( + self, + name: str, + insert: UVec, + size: float = 1.0, + rotation: float = 0, + dxfattribs=None, + ) -> Vec3: + return ARROWS.render_arrow( + self, # type: ignore + name=name, + insert=insert, + size=size, + rotation=rotation, + dxfattribs=dxfattribs, + ).vec3 + + def add_arrow_blockref( + self, + name: str, + insert: UVec, + size: float = 1.0, + rotation: float = 0, + dxfattribs=None, + ) -> Vec3: + return ARROWS.insert_arrow( + self, # type: ignore + name=name, + insert=insert, + size=size, + rotation=rotation, + dxfattribs=dxfattribs, + ).vec3 + + def add_leader( + self, + vertices: Iterable[UVec], + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + ) -> Leader: + """ + The :class:`~ezdxf.entities.Leader` entity represents an arrow, made up + of one or more vertices (or spline fit points) and an arrowhead. + The label or other content to which the :class:`~ezdxf.entities.Leader` + is attached is stored as a separate entity, and is not part of the + :class:`~ezdxf.entities.Leader` itself. (requires DXF R2000) + + :class:`~ezdxf.entities.Leader` shares its styling infrastructure with + :class:`~ezdxf.entities.Dimension`. + + By default a :class:`~ezdxf.entities.Leader` without any annotation is + created. For creating more fancy leaders and annotations see + documentation provided by Autodesk or `Demystifying DXF: LEADER and MULTILEADER + implementation notes `_ . + + + Args: + vertices: leader vertices (in :ref:`WCS`) + dimstyle: dimension style name (:class:`~ezdxf.entities.DimStyle` + table entry), default is "EZDXF" + override: override :class:`~ezdxf.entities.DimStyleOverride` attributes + dxfattribs: additional DXF attributes + + """ + + def filter_unsupported_dimstyle_attributes(attribs: dict) -> dict: + return { + k: v + for k, v in attribs.items() + if k not in LEADER_UNSUPPORTED_DIMSTYLE_ATTRIBS + } + + if self.dxfversion < DXF2000: + raise DXFVersionError("LEADER requires DXF R2000") + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["dimstyle"] = self._safe_dimstyle(dimstyle) + dxfattribs.setdefault("annotation_type", 3) + leader = cast("Leader", self.new_entity("LEADER", dxfattribs)) + leader.set_vertices(vertices) + if override: + override = filter_unsupported_dimstyle_attributes(override) + if "dimldrblk" in override: + self.doc.acquire_arrow(override["dimldrblk"]) + # Class Leader() supports the required OverrideMixin() interface + DimStyleOverride( + cast("Dimension", leader), override=override + ).commit() + return leader + + def add_multileader_mtext( + self, + style: str = "Standard", + dxfattribs=None, + ) -> MultiLeaderMTextBuilder: + """Add a :class:`~ezdxf.entities.MultiLeader` entity but returns + a :class:`~ezdxf.render.MultiLeaderMTextBuilder`. + + """ + from ezdxf.render.mleader import MultiLeaderMTextBuilder + + multileader = self._make_multileader(style, dxfattribs) + return MultiLeaderMTextBuilder(multileader) + + def add_multileader_block( + self, + style: str = "Standard", + dxfattribs=None, + ) -> MultiLeaderBlockBuilder: + """Add a :class:`~ezdxf.entities.MultiLeader` entity but returns + a :class:`~ezdxf.render.MultiLeaderBlockBuilder`. + + """ + from ezdxf.render.mleader import MultiLeaderBlockBuilder + + multileader = self._make_multileader(style, dxfattribs) + return MultiLeaderBlockBuilder(multileader) + + def _make_multileader( + self, + style: str, + dxfattribs=None, + ) -> MultiLeader: + if self.dxfversion < DXF2000: + raise DXFVersionError("MULTILEADER requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + mleader_style = self.doc.mleader_styles.get(style) + if mleader_style is None: + raise DXFValueError(f"MLEADERSTYLE '{style}' does not exist") + dxfattribs["style_handle"] = mleader_style.dxf.handle + return self.new_entity("MULTILEADER", dxfattribs=dxfattribs) # type: ignore + + def add_mline( + self, + vertices: Optional[Iterable[UVec]] = None, + *, + close: bool = False, + dxfattribs=None, + ) -> MLine: + """Add a :class:`~ezdxf.entities.MLine` entity + + Args: + vertices: MLINE vertices (in :ref:`WCS`) + close: ``True`` to add a closed MLINE + dxfattribs: additional DXF attributes + + """ + if self.dxfversion < DXF2000: + raise DXFVersionError("MLine requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + style_name = dxfattribs.pop("style_name", "Standard") + mline: MLine = self.new_entity("MLINE", dxfattribs) # type: ignore + # close() method regenerates geometry! + mline.set_flag_state(mline.CLOSED, close) + mline.set_style(style_name) + if vertices: + mline.extend(vertices) + return mline + + def add_helix( + self, + radius: float, + pitch: float, + turns: float, + ccw=True, + dxfattribs=None, + ) -> Helix: + """ + Add a :class:`~ezdxf.entities.Helix` entity. + + The center of the helix is always (0, 0, 0) and the helix axis direction + is the +z-axis. + + Transform the new HELIX by the :meth:`~ezdxf.entities.DXFGraphic.transform` + method to your needs. + + Args: + radius: helix radius + pitch: the height of one complete helix turn + turns: count of turns + ccw: creates a counter-clockwise turning (right-handed) helix if ``True`` + dxfattribs: additional DXF attributes + + """ + from ezdxf import path + + if self.dxfversion < DXF2000: + raise DXFVersionError("Helix requires DXF R2000") + dxfattribs = dict(dxfattribs or {}) + helix: Helix = self.new_entity("HELIX", dxfattribs) # type: ignore + base = Vec3(0, 0, 0) + helix.dxf.axis_base_point = base + helix.dxf.radius = float(radius) + helix.dxf.start_point = base + (radius, 0, 0) + helix.dxf.axis_vector = Vec3(0, 0, 1 if pitch > 0 else -1) + helix.dxf.turns = turns + helix.dxf.turn_height = pitch + helix.dxf.handedness = int(ccw) + helix.dxf.constrain = 1 # turns + p = path.helix(radius, pitch, turns, ccw) + splines = list(path.to_bsplines_and_vertices(p)) + if splines: + helix.apply_construction_tool(splines[0]) + return helix + + +LEADER_UNSUPPORTED_DIMSTYLE_ATTRIBS = {"dimblk", "dimblk1", "dimblk2"} diff --git a/.venv/lib/python3.12/site-packages/ezdxf/groupby.py b/.venv/lib/python3.12/site-packages/ezdxf/groupby.py new file mode 100644 index 0000000..80068c9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/groupby.py @@ -0,0 +1,94 @@ +# Purpose: Grouping entities by DXF attributes or a key function. +# Copyright (c) 2017-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Hashable, TYPE_CHECKING, Optional + +from ezdxf.lldxf.const import DXFValueError, DXFAttributeError + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + from ezdxf.eztypes import KeyFunc + + +def groupby( + entities: Iterable[DXFEntity], + dxfattrib: str = "", + key: Optional[KeyFunc] = None, +) -> dict[Hashable, list[DXFEntity]]: + """ + Groups a sequence of DXF entities by a DXF attribute like ``'layer'``, + returns a dict with `dxfattrib` values as key and a list of entities + matching this `dxfattrib`. + A `key` function can be used to combine some DXF attributes (e.g. layer and + color) and should return a hashable data type like a tuple of strings, + integers or floats, `key` function example:: + + def group_key(entity: DXFEntity): + return entity.dxf.layer, entity.dxf.color + + For not suitable DXF entities return ``None`` to exclude this entity, in + this case it's not required, because :func:`groupby` catches + :class:`DXFAttributeError` exceptions to exclude entities, which do not + provide layer and/or color attributes, automatically. + + Result dict for `dxfattrib` = ``'layer'`` may look like this:: + + { + '0': [ ... list of entities ], + 'ExampleLayer1': [ ... ], + 'ExampleLayer2': [ ... ], + ... + } + + Result dict for `key` = `group_key`, which returns a ``(layer, color)`` + tuple, may look like this:: + + { + ('0', 1): [ ... list of entities ], + ('0', 3): [ ... ], + ('0', 7): [ ... ], + ('ExampleLayer1', 1): [ ... ], + ('ExampleLayer1', 2): [ ... ], + ('ExampleLayer1', 5): [ ... ], + ('ExampleLayer2', 7): [ ... ], + ... + } + + All entity containers (modelspace, paperspace layouts and blocks) and the + :class:`~ezdxf.query.EntityQuery` object have a dedicated :meth:`groupby` + method. + + Args: + entities: sequence of DXF entities to group by a DXF attribute or a + `key` function + dxfattrib: grouping DXF attribute like ``'layer'`` + key: key function, which accepts a :class:`DXFEntity` as argument and + returns a hashable grouping key or ``None`` to ignore this entity + + """ + if all((dxfattrib, key)): + raise DXFValueError( + "Specify a dxfattrib or a key function, but not both." + ) + if dxfattrib != "": + key = lambda entity: entity.dxf.get_default(dxfattrib) + if key is None: + raise DXFValueError( + "no valid argument found, specify a dxfattrib or a key function, " + "but not both." + ) + + result: dict[Hashable, list[DXFEntity]] = dict() + for dxf_entity in entities: + if not dxf_entity.is_alive: + continue + try: + group_key = key(dxf_entity) + except DXFAttributeError: + # ignore DXF entities, which do not support all query attributes + continue + if group_key is not None: + group = result.setdefault(group_key, []) + group.append(dxf_entity) + return result diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__init__.py new file mode 100644 index 0000000..821145b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from .base import BaseLayout, VirtualLayout +from .layout import Layout, Modelspace, Paperspace +from .blocklayout import BlockLayout +from .layouts import Layouts diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..e6db64f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000..c9c2acf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/base.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/blocklayout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/blocklayout.cpython-312.pyc new file mode 100644 index 0000000..7be96da Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/blocklayout.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layout.cpython-312.pyc new file mode 100644 index 0000000..80cba28 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layout.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layouts.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layouts.cpython-312.pyc new file mode 100644 index 0000000..2316a84 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/layouts/__pycache__/layouts.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/base.py b/.venv/lib/python3.12/site-packages/ezdxf/layouts/base.py new file mode 100644 index 0000000..f7b9c7e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/layouts/base.py @@ -0,0 +1,468 @@ +# Copyright (c) 2019-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Union, Iterable, Optional + +from ezdxf.entities import factory, is_graphic_entity, SortEntsTable +from ezdxf.enums import InsertUnits +from ezdxf.lldxf.const import ( + DXFKeyError, + DXFValueError, + DXFStructureError, + LATEST_DXF_VERSION, + DXFTypeError, +) +from ezdxf.query import EntityQuery +from ezdxf.groupby import groupby +from ezdxf.entitydb import EntityDB, EntitySpace +from ezdxf.graphicsfactory import CreatorInterface + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic, BlockRecord, ExtensionDict + from ezdxf.eztypes import KeyFunc + +SUPPORTED_FOREIGN_ENTITY_TYPES = { + "ARC", + "LINE", + "CIRCLE", + "ELLIPSE", + "POINT", + "LWPOLYLINE", + "SPLINE", + "3DFACE", + "SOLID", + "TRACE", + "SHAPE", + "POLYLINE", + "MESH", + "TEXT", + "MTEXT", + "HATCH", + "ATTRIB", + "ATTDEF", +} + + +class _AbstractLayout(CreatorInterface): + entity_space = EntitySpace() + + @property + def entitydb(self) -> EntityDB: + """Returns drawing entity database. (internal API)""" + return self.doc.entitydb + + def rename(self, name) -> None: + pass + + def __len__(self) -> int: + """Returns count of entities owned by the layout.""" + return len(self.entity_space) + + def __iter__(self) -> Iterator[DXFGraphic]: + """Returns iterable of all drawing entities in this layout.""" + return iter(self.entity_space) # type: ignore + + def __getitem__(self, index): + """Get entity at `index`. + + The underlying data structure for storing entities is organized like a + standard Python list, therefore `index` can be any valid list indexing + or slicing term, like a single index ``layout[-1]`` to get the last + entity, or an index slice ``layout[:10]`` to get the first 10 or less + entities as ``list[DXFGraphic]``. + + """ + return self.entity_space[index] + + def query(self, query: str = "*") -> EntityQuery: + """Get all DXF entities matching the :ref:`entity query string`.""" + return EntityQuery(iter(self), query) + + def groupby(self, dxfattrib: str = "", key: Optional[KeyFunc] = None) -> dict: + """ + Returns a ``dict`` of entity lists, where entities are grouped by a + `dxfattrib` or a `key` function. + + Args: + dxfattrib: grouping by DXF attribute like ``'layer'`` + key: key function, which accepts a :class:`DXFGraphic` entity as + argument and returns the grouping key of an entity or ``None`` + to ignore the entity. Reason for ignoring: a queried DXF + attribute is not supported by entity. + + """ + return groupby(iter(self), dxfattrib, key) + + def destroy(self): + pass + + def purge(self): + """Remove all destroyed entities from the layout entity space.""" + self.entity_space.purge() + + +class BaseLayout(_AbstractLayout): + def __init__(self, block_record: BlockRecord): + doc = block_record.doc + assert doc is not None + super().__init__(doc) + self.entity_space = block_record.entity_space + # This is the real central layout management structure: + self.block_record: BlockRecord = block_record + + @property + def block_record_handle(self): + """Returns block record handle. (internal API)""" + return self.block_record.dxf.handle + + @property + def layout_key(self) -> str: + """Returns the layout key as hex string. + + The layout key is the handle of the associated BLOCK_RECORD entry in the + BLOCK_RECORDS table. + + (internal API) + """ + return self.block_record.dxf.handle + + @property + def is_alive(self): + """``False`` if layout is deleted.""" + return self.block_record.is_alive + + @property + def is_active_paperspace(self) -> bool: + """``True`` if is active layout.""" + return self.block_record.is_active_paperspace + + @property + def is_any_paperspace(self) -> bool: + """``True`` if is any kind of paperspace layout.""" + return self.block_record.is_any_paperspace + + @property + def is_modelspace(self) -> bool: + """``True`` if is modelspace layout.""" + return self.block_record.is_modelspace + + @property + def is_any_layout(self) -> bool: + """``True`` if is any kind of modelspace or paperspace layout.""" + return self.block_record.is_any_layout + + @property + def is_block_layout(self) -> bool: + """``True`` if not any kind of modelspace or paperspace layout, just a + regular block definition. + """ + return self.block_record.is_block_layout + + @property + def units(self) -> InsertUnits: + """Get/Set layout/block drawing units as enum, see also :ref:`set + drawing units`. + """ + # todo: doesn't care about units stored in XDATA, see ezdxf/units.py + # Don't know what this units are used for, but header var $INSUNITS + # are the real units of the model space. + return self.block_record.dxf.units + + @units.setter + def units(self, value: InsertUnits) -> None: + """Set layout/block drawing units as enum.""" + self.block_record.dxf.units = value # has a DXF validator + + def get_extension_dict(self) -> ExtensionDict: + """Returns the associated extension dictionary, creates a new one if + necessary. + """ + block_record = self.block_record + if block_record.has_extension_dict: + return block_record.get_extension_dict() + else: + return block_record.new_extension_dict() + + def add_entity(self, entity: DXFGraphic) -> None: + """Add an existing :class:`DXFGraphic` entity to a layout, but be sure + to unlink (:meth:`~BaseLayout.unlink_entity`) `entity` from the previous + owner layout. Adding entities from a different DXF drawing is not + supported. + + .. warning:: + + This is a low-level tool - use it with caution and make sure you understand + what you are doing! If used improperly, the DXF document may be damaged. + + """ + # bind virtual entities to the DXF document: + doc = self.doc + if entity.dxf.handle is None and doc: + factory.bind(entity, doc) + handle = entity.dxf.handle + if handle is None or handle not in self.doc.entitydb: + raise DXFStructureError( + "Adding entities from a different DXF drawing is not supported." + ) + + if not is_graphic_entity(entity): + raise DXFTypeError(f"invalid entity {str(entity)}") + self.block_record.add_entity(entity) + + def add_foreign_entity(self, entity: DXFGraphic, copy=True) -> None: + """Add a foreign DXF entity to a layout, this foreign entity could be + from another DXF document or an entity without an assigned DXF document. + The intention of this method is to add **simple** entities from another + DXF document or from a DXF iterator, for more complex operations use the + :mod:`~ezdxf.addons.importer` add-on. Especially objects with BLOCK + section (INSERT, DIMENSION, MLEADER) or OBJECTS section dependencies + (IMAGE, UNDERLAY) can not be supported by this simple method. + + Not all DXF types are supported and every dependency or resource + reference from another DXF document will be removed except attribute + layer will be preserved but only with default attributes like + color ``7`` and linetype ``CONTINUOUS`` because the layer attribute + doesn't need a layer table entry. + + If the entity is part of another DXF document, it will be unlinked from + this document and its entity database if argument `copy` is ``False``, + else the entity will be copied. Unassigned entities like from DXF + iterators will just be added. + + Supported DXF types: + + - POINT + - LINE + - CIRCLE + - ARC + - ELLIPSE + - LWPOLYLINE + - SPLINE + - POLYLINE + - 3DFACE + - SOLID + - TRACE + - SHAPE + - MESH + - ATTRIB + - ATTDEF + - TEXT + - MTEXT + - HATCH + + Args: + entity: DXF entity to copy or move + copy: if ``True`` copy entity from other document else unlink from + other document + + Raises: + CopyNotSupported: copying of `entity` i not supported + """ + foreign_doc = entity.doc + dxftype = entity.dxftype() + if dxftype not in SUPPORTED_FOREIGN_ENTITY_TYPES: + raise DXFTypeError(f"unsupported DXF type: {dxftype}") + if foreign_doc is self.doc: + raise DXFValueError("entity from same DXF document") + + if foreign_doc is not None: + if copy: + entity = entity.copy() + else: + # Unbind entity from other document without destruction. + factory.unbind(entity) + + entity.remove_dependencies(self.doc) + # add to this layout & bind to document + self.add_entity(entity) + + def unlink_entity(self, entity: DXFGraphic) -> None: + """Unlink `entity` from layout but does not delete entity from the + entity database, this removes `entity` just from the layout entity space. + """ + self.block_record.unlink_entity(entity) + + def delete_entity(self, entity: DXFGraphic) -> None: + """Delete `entity` from layout entity space and the entity database, + this destroys the `entity`. + """ + self.block_record.delete_entity(entity) + + def delete_all_entities(self) -> None: + """Delete all entities from this layout and from entity database, + this destroys all entities in this layout. + """ + # Create list, because delete modifies the base data structure of + # the iterator: + for entity in list(self): + self.delete_entity(entity) + + def move_to_layout(self, entity: DXFGraphic, layout: BaseLayout) -> None: + """Move entity to another layout. + + Args: + entity: DXF entity to move + layout: any layout (modelspace, paperspace, block) from + **same** drawing + + """ + if entity.doc != layout.doc: + raise DXFStructureError( + "Moving between different DXF drawings is not supported." + ) + try: + self.unlink_entity(entity) + except ValueError: + raise DXFValueError("Layout does not contain entity.") + else: + layout.add_entity(entity) + + def destroy(self) -> None: + """Delete all linked resources. (internal API)""" + # block_records table is owner of block_record has to delete it + # the block_record is the owner of the entities and deletes them all + self.doc.block_records.remove(self.block_record.dxf.name) + + def get_sortents_table(self, create: bool = True) -> SortEntsTable: + """Get/Create the SORTENTSTABLE object associated to the layout. + + Args: + create: new table if table do not exist and `create` is ``True`` + + Raises: + DXFValueError: if table not exist and `create` is ``False`` + + (internal API) + """ + xdict = self.get_extension_dict() + try: + sortents_table = xdict["ACAD_SORTENTS"] + except DXFKeyError: + if create: + sortents_table = self.doc.objects.new_entity( + "SORTENTSTABLE", + dxfattribs={ + "owner": xdict.handle, + "block_record_handle": self.layout_key, + }, + ) + xdict["ACAD_SORTENTS"] = sortents_table + else: + raise DXFValueError( + "Extension dictionary entry ACAD_SORTENTS does not exist." + ) + return sortents_table + + def set_redraw_order(self, handles: Union[dict, Iterable[tuple[str, str]]]) -> None: + """If the header variable $SORTENTS `Regen` flag (bit-code value 16) + is set, AutoCAD regenerates entities in ascending handles order. + + To change redraw order associate a different sort-handle to entities, + this redefines the order in which the entities are regenerated. + The `handles` argument can be a dict of entity_handle and sort_handle + as (k, v) pairs, or an iterable of (entity_handle, sort_handle) tuples. + + The sort-handle doesn't have to be unique, some or all entities can + share the same sort-handle and a sort-handle can be an existing handle. + + The "0" handle can be used, but this sort-handle will be drawn as + latest (on top of all other entities) and not as first as expected. + + Args: + handles: iterable or dict of handle associations; an iterable + of 2-tuples (entity_handle, sort_handle) or a dict (k, v) + association as (entity_handle, sort_handle) + + """ + sortents = self.get_sortents_table() + if isinstance(handles, dict): + handles = handles.items() + sortents.set_handles(handles) + + def get_redraw_order(self) -> Iterable[tuple[str, str]]: + """Returns iterable for all existing table entries as (entity_handle, + sort_handle) pairs, see also :meth:`~BaseLayout.set_redraw_order`. + + """ + if self.block_record.has_extension_dict: + xdict = self.get_extension_dict() + else: + return tuple() + + try: + sortents_table = xdict["ACAD_SORTENTS"] + except DXFKeyError: + return tuple() + return iter(sortents_table) + + def entities_in_redraw_order(self, reverse=False) -> Iterable[DXFGraphic]: + """Yields all entities from layout in ascending redraw order or + descending redraw order if `reverse` is ``True``. + """ + from ezdxf import reorder + + redraw_order = self.get_redraw_order() + if reverse: + return reorder.descending(self.entity_space, redraw_order) # type: ignore + return reorder.ascending(self.entity_space, redraw_order) # type: ignore + + +class VirtualLayout(_AbstractLayout): + """Helper class to disassemble complex entities into basic DXF + entities by rendering into a virtual layout. + + All entities do not have an assigned DXF document and therefore + are not stored in any entity database and can not be added to another + layout by :meth:`add_entity`. + + Deleting entities from this layout does not destroy the entity! + + """ + + def __init__(self): + super().__init__(None) + self.entity_space = EntitySpace() + + @property + def dxfversion(self) -> str: + return LATEST_DXF_VERSION + + def add_entity(self, entity: DXFGraphic) -> None: + self.entity_space.add(entity) + + def new_entity(self, type_: str, dxfattribs: dict) -> DXFGraphic: + entity = factory.new(type_, dxfattribs=dxfattribs) + self.entity_space.add(entity) + return entity # type: ignore + + def unlink_entity(self, entity: DXFGraphic) -> None: + self.entity_space.remove(entity) + + def delete_entity(self, entity: DXFGraphic) -> None: + self.entity_space.remove(entity) + + def delete_all_entities(self) -> None: + self.entity_space.clear() + + def copy_all_to_layout(self, layout: BaseLayout) -> None: + """Copy all entities to a real document layout.""" + doc = layout.doc + entitydb = doc.entitydb + for entity in self.entity_space: + try: + clone = entity.copy() + except DXFTypeError: + continue + clone.doc = doc + entitydb.add(clone) + layout.add_entity(clone) # type: ignore + + def move_all_to_layout(self, layout: BaseLayout) -> None: + """Move all entities to a real document layout.""" + doc = layout.doc + entitydb = doc.entitydb + for entity in self.entity_space: + entity.doc = doc + entitydb.add(entity) + layout.add_entity(entity) # type: ignore + self.delete_all_entities() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/blocklayout.py b/.venv/lib/python3.12/site-packages/ezdxf/layouts/blocklayout.py new file mode 100644 index 0000000..acb1dc4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/layouts/blocklayout.py @@ -0,0 +1,132 @@ +# Copyright (c) 2019-2021, Manfred Moitzi +# License: MIT License +from typing import Iterable, Optional +from ezdxf.math import Vec3, UVec +from ezdxf.lldxf import const +from .base import BaseLayout +from ezdxf.entities import DXFGraphic, AttDef, Block, EndBlk + + +class BlockLayout(BaseLayout): + """BlockLayout has the same factory-functions as Layout, but is managed + in the :class:`BlocksSection` class. It represents a DXF Block. + + """ + + def __contains__(self, entity) -> bool: + """Returns ``True`` if block contains `entity`. + + Args: + entity: :class:`DXFGraphic` object or handle as hex string + + """ + if isinstance(entity, str): + entity = self.entitydb[entity] + return entity in self.entity_space + + @property + def block(self) -> Optional[Block]: + """the associated :class:`~ezdxf.entities.Block` entity.""" + return self.block_record.block + + @property + def endblk(self) -> Optional[EndBlk]: + """the associated :class:`~ezdxf.entities.EndBlk` entity.""" + return self.block_record.endblk + + @property + def name(self) -> str: + """Get/set the BLOCK name""" + return self.block_record.dxf.name + + @name.setter + def name(self, new_name) -> None: + self.block_record.rename(new_name) + + @property + def dxf(self): + """DXF name space of associated :class:`~ezdxf.entities.BlockRecord` + table entry. + """ + return self.block_record.dxf + + @property + def can_explode(self) -> bool: + """Set property to ``True`` to allow exploding block references of + this block. + """ + return bool(self.block_record.dxf.explode) + + @can_explode.setter + def can_explode(self, value: bool): + self.block_record.dxf.explode = int(value) + + @property + def scale_uniformly(self) -> bool: + """Set property to ``True`` to allow block references of this block + only scale uniformly. + """ + return bool(self.block_record.dxf.scale) + + @scale_uniformly.setter + def scale_uniformly(self, value: bool): + self.block_record.dxf.scale = int(value) + + @property + def base_point(self) -> Vec3: + """Get/Set the base point of the block.""" + return Vec3(self.block.dxf.base_point) # type: ignore + + @base_point.setter + def base_point(self, value: UVec) -> None: + self.block.dxf.base_point = Vec3(value) # type: ignore + + def attdefs(self) -> Iterable[AttDef]: + """Returns iterable of all :class:`~ezdxf.entities.attrib.Attdef` + entities. + """ + return (e for e in self if isinstance(e, AttDef)) + + def has_attdef(self, tag: str) -> bool: + """Returns ``True`` if an :class:`~ezdxf.entities.attrib.Attdef` for + `tag` exist. + """ + return self.get_attdef(tag) is not None + + def get_attdef(self, tag: str) -> Optional[DXFGraphic]: + """Returns attached :class:`~ezdxf.entities.attrib.Attdef` entity by + `tag` name. + """ + for attdef in self.attdefs(): + if tag == attdef.dxf.tag: + return attdef + return None + + def get_attdef_text(self, tag: str, default: str = "") -> str: + """Returns text content for :class:`~ezdxf.entities.attrib.Attdef` + `tag` as string or returns `default` if no :class:`Attdef` for `tag` + exist. + + Args: + tag: name of tag + default: default value if `tag` not exist + + """ + attdef = self.get_attdef(tag) + if attdef is None: + return default + return attdef.dxf.text + + def get_const_attdefs(self) -> Iterable[AttDef]: + """Returns iterable for all constant ATTDEF entities. (internal API)""" + return (attdef for attdef in self.attdefs() if attdef.is_const) + + def has_non_const_attdef(self) -> bool: + """Returns ``True`` if the block has a non constant attribute + definition. + """ + return any(not attdef.is_const for attdef in self.attdefs()) + + def update_block_flags(self): + state = self.has_non_const_attdef() + self.block.set_flag_state(const.BLK_NON_CONSTANT_ATTRIBUTES, state) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/layout.py b/.venv/lib/python3.12/site-packages/ezdxf/layouts/layout.py new file mode 100644 index 0000000..f7a1787 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/layouts/layout.py @@ -0,0 +1,862 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Any, + Union, + cast, + Optional, +) +import logging + +from ezdxf.math import Vec2, UVec +from ezdxf.entitydb import EntitySpace +from ezdxf.lldxf import const +from ezdxf.lldxf.validator import make_table_key +from .base import BaseLayout + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.layouts import BlockLayout + from ezdxf.entities import GeoData, Viewport, DXFLayout, DXFGraphic, BlockRecord + +logger = logging.getLogger("ezdxf") + + +def get_block_entity_space(doc: Drawing, block_record_handle: str) -> EntitySpace: + block_record = doc.entitydb[block_record_handle] + return block_record.entity_space # type: ignore + + +class Layout(BaseLayout): + """ + Layout representation - base class for :class:`Modelspace` and + :class:`Paperspace` + + Every layout consist of a LAYOUT entity in the OBJECTS section, an + associated BLOCK in the BLOCKS section and a BLOCK_RECORD_TABLE entry. + + layout_key: handle of the BLOCK_RECORD, every layout entity has this + handle as owner attribute (entity.dxf.owner) + + There are 3 different layout types: + + 1. :class:`Modelspace` + 2. active :class:`Paperspace` layout + 3. inactive :class:`Paperspace` layout + + Internal Structure + + For every layout exist a :class:`BlockLayout` object in + :class:`BlocksSection` and a :class:`Layout` object + (as :class:`Modelspace` or :class:`Paperspace`) in :class:`Layouts`. + + The entity space of the :class:`BlockLayout` object and the entity space + of the :class:`Layout` object are the same object. + + """ + + # plot_layout_flags of LAYOUT entity + PLOT_VIEWPORT_BORDERS = 1 + SHOW_PLOT_STYLES = 2 + PLOT_CENTERED = 4 + PLOT_HIDDEN = 8 + USE_STANDARD_SCALE = 16 + PLOT_PLOTSTYLES = 32 + SCALE_LINEWEIGHTS = 64 + PRINT_LINEWEIGHTS = 128 + DRAW_VIEWPORTS_FIRST = 512 + MODEL_TYPE = 1024 + UPDATE_PAPER = 2048 + ZOOM_TO_PAPER_ON_UPDATE = 4096 + INITIALIZING = 8192 + PREV_PLOT_INIT = 16384 + + def __init__(self, layout: DXFLayout, doc: Drawing): + self.dxf_layout = layout + handle = layout.dxf.get("block_record_handle", "0") + try: + block_record = doc.entitydb[handle] + except KeyError: + block_record = _find_layout_block_record(layout) # type: ignore + if block_record is None: + raise const.DXFStructureError( + f"required BLOCK_RECORD #{handle} for layout '{layout.dxf.name}' " + f"does not exist" + ) + if block_record.dxftype() != "BLOCK_RECORD": + raise const.DXFStructureError( + f"expected BLOCK_RECORD(#{handle}) for layout '{layout.dxf.name}' " + f"has invalid entity type: {block_record.dxftype()}" + ) + # link is maybe broken + block_record.dxf.layout = layout.dxf.handle + super().__init__(block_record) # type: ignore + + @classmethod + def new(cls, name: str, block_name: str, doc: Drawing, dxfattribs=None) -> Layout: + """Returns the required structures for a new layout: + + - a :class:`BlockLayout` with BLOCK_RECORD, BLOCK and ENDBLK entities + - LAYOUT entity in the objects section + + Args: + name: layout name as shown in tabs of CAD applications e.g. 'Layout2' + block_name: layout block name e.g. '*Paper_Space2' + doc: drawing document + dxfattribs: additional DXF attributes for LAYOUT entity + + (internal API) + + """ + block_layout: BlockLayout = doc.blocks.new(block_name) + dxfattribs = dxfattribs or {} + dxfattribs.update( + { + "name": name, + "block_record_handle": block_layout.block_record_handle, + } + ) + dxf_layout = doc.objects.new_entity("LAYOUT", dxfattribs=dxfattribs) + return cls(dxf_layout, doc) # type: ignore + + @classmethod + def load(cls, layout: DXFLayout, doc: Drawing): + """Loading interface. (internal API)""" + _layout = cls(layout, doc) + _layout._repair_owner_tags() + return _layout + + @property + def name(self) -> str: + """Layout name as shown in tabs of :term:`CAD` applications.""" + return self.dxf_layout.dxf.name + + @property # dynamic DXF attribute dispatching, e.g. DXFLayout.dxf.layout_flags + def dxf(self) -> Any: + """Returns the DXF name space attribute of the associated + :class:`~ezdxf.entities.DXFLayout` object. + + This enables direct access to the underlying LAYOUT entity, + e.g. ``Layout.dxf.layout_flags`` + + """ + return self.dxf_layout.dxf + + @property + def block_record_name(self) -> str: + """Returns the name of the associated BLOCK_RECORD as string.""" + return self.block_record.dxf.name + + def _repair_owner_tags(self) -> None: + """Set `owner` and `paperspace` attributes of entities hosted by this + layout to correct values. + """ + layout_key = self.layout_key + paperspace = 0 if self.is_modelspace else 1 + for entity in self: + if entity.dxf.owner != layout_key: + entity.dxf.owner = layout_key + if entity.dxf.paperspace != paperspace: + entity.dxf.paperspace = paperspace + + def __contains__(self, entity: Union[DXFGraphic, str]) -> bool: + """Returns ``True`` if `entity` is stored in this layout. + + Args: + entity: :class:`DXFGraphic` object or handle as hex string + + """ + if isinstance(entity, str): # entity is a handle string + entity = self.entitydb[entity] # type: ignore + return entity.dxf.owner == self.layout_key # type: ignore + + def destroy(self) -> None: + """Delete all entities and the layout itself from entity database and + all linked structures. + + (internal API) + """ + + self.doc.objects.delete_entity(self.dxf_layout) + # super() deletes block_record and associated entity space + super().destroy() + + @property + def plot_layout_flags(self) -> int: + return self.dxf_layout.dxf.plot_layout_flags + + def reset_extents( + self, extmin=(+1e20, +1e20, +1e20), extmax=(-1e20, -1e20, -1e20) + ) -> None: + """Reset `extents`_ to given values or the AutoCAD default values. + + "Drawing extents are the bounds of the area occupied by objects." + (Quote Autodesk Knowledge Network) + + Args: + extmin: minimum extents or (+1e20, +1e20, +1e20) as default value + extmax: maximum extents or (-1e20, -1e20, -1e20) as default value + + """ + dxf = self.dxf_layout.dxf + dxf.extmin = extmin + dxf.extmax = extmax + + def reset_limits(self, limmin=None, limmax=None) -> None: + """Reset `limits`_ to given values or the AutoCAD default values. + + "Sets an invisible rectangular boundary in the drawing area that can + limit the grid display and limit clicking or entering point locations." + (Quote Autodesk Knowledge Network) + + The :class:`Paperspace` class has an additional method + :meth:`~Paperspace.reset_paper_limits` to deduce the default limits from + the paper size settings. + + Args: + limmin: minimum limits or (0, 0) as default + limmax: maximum limits or (paper width, paper height) as default value + + """ + dxf = self.dxf_layout.dxf + if limmin is None: + limmin = (0, 0) + if limmax is None: + limmax = (dxf.paper_width, dxf.paper_height) + + dxf.limmin = limmin + dxf.limmax = limmax + + def set_plot_type(self, value: int = 5) -> None: + """ + === ============================================================ + 0 last screen display + 1 drawing extents + 2 drawing limits + 3 view specific (defined by :attr:`Layout.dxf.plot_view_name`) + 4 window specific (defined by :meth:`Layout.set_plot_window_limits`) + 5 layout information (default) + === ============================================================ + + Args: + value: plot type + + Raises: + DXFValueError: for `value` out of range + + """ + if 0 <= int(value) <= 5: + self.dxf.plot_type = value + else: + raise const.DXFValueError("Plot type value out of range (0-5).") + + def set_plot_style(self, name: str = "ezdxf.ctb", show: bool = False) -> None: + """Set plot style file of type `.ctb`. + + Args: + name: plot style filename + show: show plot style effect in preview? (AutoCAD specific attribute) + + """ + self.dxf_layout.dxf.current_style_sheet = name + self.use_plot_styles(True) + self.show_plot_styles(show) + + def get_plot_style_filename(self) -> str: + return self.dxf_layout.dxf.current_style_sheet + + def set_plot_window( + self, + lower_left: tuple[float, float] = (0, 0), + upper_right: tuple[float, float] = (0, 0), + ) -> None: + """Set plot window size in (scaled) paper space units. + + Args: + lower_left: lower left corner as 2D point + upper_right: upper right corner as 2D point + + """ + x1, y1 = lower_left + x2, y2 = upper_right + dxf = self.dxf_layout.dxf + dxf.plot_window_x1 = x1 + dxf.plot_window_y1 = y1 + dxf.plot_window_x2 = x2 + dxf.plot_window_y2 = y2 + self.set_plot_type(4) + + def get_plot_unit_scale_factor(self) -> float: + denom = self.dxf.scale_denominator + numerator = self.dxf.scale_numerator + scale = 1.0 + if denom: + scale = numerator / denom + if self.dxf.plot_paper_units == 1: + return scale # mm + else: + return scale * 25.4 # inch + + # plot layout flags setter + def plot_viewport_borders(self, state: bool = True) -> None: + self.set_plot_flags(self.PLOT_VIEWPORT_BORDERS, state) + + def show_plot_styles(self, state: bool = True) -> None: + self.set_plot_flags(self.SHOW_PLOT_STYLES, state) + + def plot_centered(self, state: bool = True) -> None: + self.set_plot_flags(self.PLOT_CENTERED, state) + + def plot_hidden(self, state: bool = True) -> None: + self.set_plot_flags(self.PLOT_HIDDEN, state) + + def use_standard_scale(self, state: bool = True) -> None: + self.set_plot_flags(self.USE_STANDARD_SCALE, state) + + def use_plot_styles(self, state: bool = True) -> None: + self.set_plot_flags(self.PLOT_PLOTSTYLES, state) + + def scale_lineweights(self, state: bool = True) -> None: + self.set_plot_flags(self.SCALE_LINEWEIGHTS, state) + + def print_lineweights(self, state: bool = True) -> None: + self.set_plot_flags(self.PRINT_LINEWEIGHTS, state) + + def draw_viewports_first(self, state: bool = True) -> None: + self.set_plot_flags(self.DRAW_VIEWPORTS_FIRST, state) + + def model_type(self, state: bool = True) -> None: + self.set_plot_flags(self.MODEL_TYPE, state) + + def update_paper(self, state: bool = True) -> None: + self.set_plot_flags(self.UPDATE_PAPER, state) + + def zoom_to_paper_on_update(self, state: bool = True) -> None: + self.set_plot_flags(self.ZOOM_TO_PAPER_ON_UPDATE, state) + + def plot_flags_initializing(self, state: bool = True) -> None: + self.set_plot_flags(self.INITIALIZING, state) + + def prev_plot_init(self, state: bool = True) -> None: + self.set_plot_flags(self.PREV_PLOT_INIT, state) + + def set_plot_flags(self, flag, state: bool = True) -> None: + self.dxf_layout.set_flag_state(flag, state=state, name="plot_layout_flags") + + +class Modelspace(Layout): + """:class:`Modelspace` - not deletable, all entities of this layout are + stored in the ENTITIES section of the DXF file, the associated + "*Model_Space" block is empty, block name is fixed as "*Model_Space", + the name is fixed as "Model". + + """ + + @property + def name(self) -> str: + """Name of modelspace is fixed as "Model".""" + return "Model" + + def new_geodata(self, dxfattribs=None) -> GeoData: + """Creates a new :class:`GeoData` entity and replaces existing ones. + The GEODATA entity resides in the OBJECTS section and not in the + modelspace, it is linked to the modelspace by an + :class:`~ezdxf.entities.ExtensionDict` located in BLOCK_RECORD of the + modelspace. + + The GEODATA entity requires DXF R2010. The DXF reference does not + document if other layouts than the modelspace supports geo referencing, + so I assume getting/setting geo data may only make sense for the + modelspace. + + Args: + dxfattribs: DXF attributes for :class:`~ezdxf.entities.GeoData` entity + + """ + if self.doc.dxfversion < const.DXF2010: + raise const.DXFValueError("GEODATA entity requires DXF R2010 or later.") + + if dxfattribs is None: + dxfattribs = {} + xdict = self.get_extension_dict() + geodata = self.doc.objects.add_geodata( + owner=xdict.dictionary.dxf.handle, + dxfattribs=dxfattribs, + ) + xdict["ACAD_GEOGRAPHICDATA"] = geodata + return geodata + + def get_geodata(self) -> Optional[GeoData]: + """Returns the :class:`~ezdxf.entities.GeoData` entity associated to + the modelspace or ``None``. + """ + try: + xdict = self.block_record.get_extension_dict() + except AttributeError: + return None + try: + return xdict["ACAD_GEOGRAPHICDATA"] + except const.DXFKeyError: + return None + + +class Paperspace(Layout): + """There are two kind of paperspace layouts: + + 1. Active Layout - all entities of this layout are stored in the ENTITIES + section, the associated "*Paper_Space" block is empty, block name + "*Paper_Space" is mandatory and also marks the active layout, the layout + name can be an arbitrary string. + + 2. Inactive Layout - all entities of this layouts are stored in the + associated BLOCK called "*Paper_SpaceN", where "N" is an arbitrary + number, I don't know if the block name schema "*Paper_SpaceN" is + mandatory, the layout name can be an arbitrary string. + + There is no different handling for active layouts and inactive layouts in + `ezdxf`, this differentiation is just for AutoCAD important and it is not + documented in the DXF reference. + + """ + + def rename(self, name: str) -> None: + """Rename layout to `name`, changes the name displayed in tabs by + CAD applications, not the internal BLOCK name. (internal API) + + Use method :meth:`~ezdxf.layouts.Layouts.rename` of the + :meth:`~ezdxf.layouts.Layouts` class to rename paper space + layouts. + + """ + self.dxf_layout.dxf.name = name + + def viewports(self) -> list[Viewport]: + """Get all VIEWPORT entities defined in this paperspace layout.""" + return [e for e in self if e.is_alive and e.dxftype() == "VIEWPORT"] # type: ignore + + def main_viewport(self) -> Optional[Viewport]: + """Returns the main viewport of this paper space layout, or ``None`` + if no main viewport exist. + + """ + # Theory: the first VP found is the main VP of the layout, the attributes status + # and id are ignored by BricsCAD and AutoCAD!? + for viewport in self.viewports(): + dxf = viewport.dxf + if dxf.hasattr("status") and dxf.status == 1: + return viewport + if dxf.id == 1: + return viewport + return None + + def add_viewport( + self, + center: UVec, + size: tuple[float, float], + view_center_point: UVec, + view_height: float, + status: int = 2, + dxfattribs=None, + ) -> Viewport: + """Add a new :class:`~ezdxf.entities.Viewport` entity. + + Viewport :attr:`status`: + + - -1 is on, but is fully off-screen, or is one of the viewports that is not + active because the $MAXACTVP count is currently being exceeded. + - 0 is off + - any value>0 is on and active. The value indicates the order of + stacking for the viewports, where 1 is the "active viewport", 2 is the + next, ... + + """ + dxfattribs = dxfattribs or {} + width, height = size + attribs = { + "center": center, # center in paperspace + "width": width, # width in paperspace + "height": height, # height in paperspace + "status": status, + "layer": "VIEWPORTS", + # use separated layer to turn off for plotting + "view_center_point": view_center_point, # in modelspace + "view_height": view_height, # in modelspace + } + attribs.update(dxfattribs) + viewport = cast("Viewport", self.new_entity("VIEWPORT", attribs)) + viewport.dxf.id = self.get_next_viewport_id() + return viewport + + def get_next_viewport_id(self): + viewports = self.viewports() + if viewports: + return max(vp.dxf.id for vp in viewports) + 1 + return 2 + + def reset_viewports(self) -> None: + """Delete all existing viewports, and create a new main viewport.""" + # remove existing viewports + for viewport in self.viewports(): + self.delete_entity(viewport) + self.add_new_main_viewport() + + def reset_main_viewport(self, center: UVec = None, size: UVec = None) -> Viewport: + """Reset the main viewport of this paper space layout to the given + values, or reset them to the default values, deduced from the paper + settings. Creates a new main viewport if none exist. + + Ezdxf does not create a main viewport by default, because CAD + applications don't require one. + + Args: + center: center of the viewport in paper space units + size: viewport size as (width, height) tuple in paper space units + + """ + viewport = self.main_viewport() + if viewport is None: + viewport = self.add_new_main_viewport() + default_center, default_size = self.default_viewport_config() + if center is None: + center = default_center + if size is None: + size = default_size + + viewport.dxf.center = center + width, height = size + viewport.dxf.width = width + viewport.dxf.height = height + return viewport + + def default_viewport_config( + self, + ) -> tuple[tuple[float, float], tuple[float, float]]: + dxf = self.dxf_layout.dxf + if dxf.plot_paper_units == 0: # inches + unit_factor = 25.4 + else: # mm + unit_factor = 1.0 + + # all paper parameters in mm! + # all viewport parameters in paper space units inch/mm + scale factor! + scale_factor = dxf.scale_denominator / dxf.scale_numerator + + def paper_units(value): + return value / unit_factor * scale_factor + + paper_width = paper_units(dxf.paper_width) + paper_height = paper_units(dxf.paper_height) + # plot origin offset + x_offset = paper_units(dxf.plot_origin_x_offset) + y_offset = paper_units(dxf.plot_origin_y_offset) + + # printing area + printable_width = ( + paper_width - paper_units(dxf.left_margin) - paper_units(dxf.right_margin) + ) + printable_height = ( + paper_height - paper_units(dxf.bottom_margin) - paper_units(dxf.top_margin) + ) + + # AutoCAD viewport (window) size + vp_width = paper_width * 1.1 + vp_height = paper_height * 1.1 + + # center of printing area + center = ( + printable_width / 2 - x_offset, + printable_height / 2 - y_offset, + ) + return center, (vp_width, vp_height) + + def add_new_main_viewport(self) -> Viewport: + """Add a new main viewport.""" + center, size = self.default_viewport_config() + vp_height = size[1] + # create 'main' viewport + main_viewport = self.add_viewport( + center=center, # no influence to 'main' viewport? + size=size, # I don't get it, just use paper size! + view_center_point=center, # same as center + view_height=vp_height, # view height in paper space units + status=1, # main viewport + ) + if len(self.entity_space) > 1: + # move main viewport to index 0 of entity space + _vp = self.entity_space.pop() + assert _vp is main_viewport + self.entity_space.insert(0, main_viewport) + + main_viewport.dxf.id = 1 # set as main viewport + main_viewport.dxf.flags = 557088 # AutoCAD default value + self.set_current_viewport_handle(main_viewport.dxf.handle) + return main_viewport + + def set_current_viewport_handle(self, handle: str) -> None: + self.dxf_layout.dxf.viewport_handle = handle + + def page_setup( + self, + size: tuple[float, float] = (297, 210), + margins: tuple[float, float, float, float] = (0, 0, 0, 0), + units: str = "mm", + offset: tuple[float, float] = (0, 0), + rotation: int = 0, + scale: Union[int, tuple[float, float]] = 16, + name: str = "ezdxf", + device: str = "DWG to PDF.pc3", + ) -> None: + """Setup plot settings and paper size and reset viewports. + All parameters in given `units` (mm or inch). + + Reset paper limits, extents and viewports. + + Args: + size: paper size as (width, height) tuple + margins: (top, right, bottom, left) hint: clockwise + units: "mm" or "inch" + offset: plot origin offset is 2D point + rotation: see table Rotation + scale: integer in range [0, 32] defines a standard scale type or + as tuple(numerator, denominator) e.g. (1, 50) for scale 1:50 + name: paper name prefix "{name}_({width}_x_{height}_{unit})" + device: device .pc3 configuration file or system printer name + + === ============ + int Rotation + === ============ + 0 no rotation + 1 90 degrees counter-clockwise + 2 upside-down + 3 90 degrees clockwise + === ============ + + """ + if int(rotation) not in (0, 1, 2, 3): + raise const.DXFValueError("valid rotation values: 0-3") + + if isinstance(scale, tuple): + standard_scale = 16 + scale_num, scale_denom = scale + elif isinstance(scale, int): + standard_scale = scale + scale_num, scale_denom = const.STD_SCALES.get(standard_scale, (1.0, 1.0)) + else: + raise const.DXFTypeError( + "Scale has to be an int or a tuple(numerator, denominator)" + ) + if scale_num == 0: + raise const.DXFValueError("Scale numerator can't be 0.") + if scale_denom == 0: + raise const.DXFValueError("Scale denominator can't be 0.") + paper_width, paper_height = size + margin_top, margin_right, margin_bottom, margin_left = margins + units = units.lower() + if units.startswith("inch"): + units = "Inches" + plot_paper_units = 0 + unit_factor = 25.4 # inch to mm + elif units == "mm": + units = "MM" + plot_paper_units = 1 + unit_factor = 1.0 + else: + raise const.DXFValueError('Supported units: "mm" and "inch"') + + # Setup PLOTSETTINGS + # all paper sizes in mm + dxf = self.dxf_layout.dxf + if not dxf.hasattr("plot_layout_flags"): + dxf.plot_layout_flags = dxf.get_default("plot_layout_flags") + self.use_standard_scale(False) # works best, don't know why + dxf.page_setup_name = "" + dxf.plot_configuration_file = device + dxf.paper_size = f"{name}_({paper_width:.2f}_x_{paper_height:.2f}_{units})" + dxf.left_margin = margin_left * unit_factor + dxf.bottom_margin = margin_bottom * unit_factor + dxf.right_margin = margin_right * unit_factor + dxf.top_margin = margin_top * unit_factor + dxf.paper_width = paper_width * unit_factor + dxf.paper_height = paper_height * unit_factor + dxf.scale_numerator = scale_num + dxf.scale_denominator = scale_denom + dxf.plot_paper_units = plot_paper_units + dxf.plot_rotation = rotation + + x_offset, y_offset = offset + dxf.plot_origin_x_offset = x_offset * unit_factor # conversion to mm + dxf.plot_origin_y_offset = y_offset * unit_factor # conversion to mm + dxf.standard_scale_type = standard_scale + dxf.unit_factor = 1.0 / unit_factor # 1/1 for mm; 1/25.4 ... for inch + + # Setup Layout + self.reset_paper_limits() + self.reset_extents() + self.reset_viewports() + + def reset_paper_limits(self) -> None: + """Set paper limits to default values, all values in paperspace units + but without plot scale (?). + + """ + dxf = self.dxf_layout.dxf + if dxf.plot_paper_units == 0: # inch + unit_factor = 25.4 + else: # mm + unit_factor = 1.0 + + # all paper sizes are stored in mm + paper_width = dxf.paper_width / unit_factor # in plot paper units + paper_height = dxf.paper_height / unit_factor # in plot paper units + left_margin = dxf.left_margin / unit_factor + bottom_margin = dxf.bottom_margin / unit_factor + x_offset = dxf.plot_origin_x_offset / unit_factor + y_offset = dxf.plot_origin_y_offset / unit_factor + # plot origin is the lower left corner of the printable paper area + # limits are the paper borders relative to the plot origin + shift_x = left_margin + x_offset + shift_y = bottom_margin + y_offset + dxf.limmin = (-shift_x, -shift_y) # paper space units + dxf.limmax = (paper_width - shift_x, paper_height - shift_y) + + def get_paper_limits(self) -> tuple[Vec2, Vec2]: + """Returns paper limits in plot paper units, relative to the plot origin. + + plot origin = lower left corner of printable area + plot origin offset + + Returns: + tuple (Vec2(x1, y1), Vec2(x2, y2)), lower left corner is (x1, y1), + upper right corner is (x2, y2). + + """ + return Vec2(self.dxf.limmin), Vec2(self.dxf.limmax) + + def page_setup_r12( + self, + size: tuple[float, float] = (297, 210), + margins: tuple[float, float, float, float] = (0, 0, 0, 0), + units: str = "mm", + offset: tuple[float, float] = (0, 0), + rotation: float = 0, + scale: Union[int, tuple[float, float]] = 16, + ) -> None: + # remove existing viewports + for viewport in self.viewports(): + self.delete_entity(viewport) + + if int(rotation) not in (0, 1, 2, 3): + raise const.DXFValueError("Valid rotation values: 0-3") + + if isinstance(scale, int): + scale_num, scale_denom = const.STD_SCALES.get(scale, (1, 1)) + else: + scale_num, scale_denom = scale + + if scale_num == 0: + raise const.DXFValueError("Scale numerator can't be 0.") + if scale_denom == 0: + raise const.DXFValueError("Scale denominator can't be 0.") + + scale_factor = scale_denom / scale_num + + # TODO: don't know how to set inch or mm mode in R12 + units = units.lower() + if units.startswith("inch"): + units = "Inches" + plot_paper_units = 0 + unit_factor = 25.4 # inch to mm + elif units == "mm": + units = "MM" + plot_paper_units = 1 + unit_factor = 1.0 + else: + raise const.DXFValueError('Supported units: "mm" and "inch"') + + # all viewport parameters are scaled paper space units + def paper_units(value): + return value * scale_factor + + margin_top = paper_units(margins[0]) + margin_right = paper_units(margins[1]) + margin_bottom = paper_units(margins[2]) + margin_left = paper_units(margins[3]) + paper_width = paper_units(size[0]) + paper_height = paper_units(size[1]) + self.doc.header["$PLIMMIN"] = (0, 0) + self.doc.header["$PLIMMAX"] = (paper_width, paper_height) + self.doc.header["$PEXTMIN"] = (0, 0, 0) + self.doc.header["$PEXTMAX"] = (paper_width, paper_height, 0) + + # printing area + printable_width = paper_width - margin_left - margin_right + printable_height = paper_height - margin_bottom - margin_top + + # AutoCAD viewport (window) size + vp_width = paper_width * 1.1 + vp_height = paper_height * 1.1 + + # center of printing area + center = (printable_width / 2, printable_height / 2) + + # create 'main' viewport + main_viewport = self.add_viewport( + center=center, # no influence to 'main' viewport? + size=(vp_width, vp_height), # I don't get it, just use paper size! + view_center_point=center, # same as center + view_height=vp_height, # view height in paper space units + status=1, # main viewport + ) + main_viewport.dxf.id = 1 # set as main viewport + main_viewport.dxf.render_mode = 1000 # AutoDesk default (view mode?) + + def get_paper_limits_r12(self) -> tuple[Vec2, Vec2]: + """Returns paper limits in plot paper units.""" + limmin = self.doc.header.get("$PLIMMIN", (0, 0)) + limmax = self.doc.header.get("$PLIMMAX", (0, 0)) + return Vec2(limmin), Vec2(limmax) + + +def _find_layout_block_record(layout: DXFLayout) -> BlockRecord | None: + """Find and link the lost BLOCK_RECORD for the given LAYOUT entity.""" + + def link_layout(block_record: BlockRecord) -> None: + logger.info( + f"fixing broken links for '{layout.dxf.name}' between {str(layout)} and {str(block_record)}" + ) + layout.dxf.block_record_handle = block_record.dxf.handle + block_record.dxf.layout = layout.dxf.handle + + doc = layout.doc + assert doc is not None + if layout.dxf.name == "Model": # modelspace layout + key = make_table_key("*Model_Space") + for block_record in doc.tables.block_records: + if make_table_key(block_record.dxf.name) == key: + link_layout(block_record) + return block_record + return None + + # paperspace layout + search_key = make_table_key("*Paper_Space") + paper_space_records = [ + block_record + for block_record in doc.tables.block_records + if make_table_key(block_record.dxf.name).startswith(search_key) + ] + + def search(key): + for block_record in paper_space_records: + layout_handle = block_record.dxf.get("layout", "0") + if doc.entitydb.get(layout_handle) is key: + link_layout(block_record) + return block_record + return None + + # first search all records for the lost record + block_record = search(layout) + if block_record is None: + # link layout to the next orphaned record + block_record = search(None) + return block_record diff --git a/.venv/lib/python3.12/site-packages/ezdxf/layouts/layouts.py b/.venv/lib/python3.12/site-packages/ezdxf/layouts/layouts.py new file mode 100644 index 0000000..190fce6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/layouts/layouts.py @@ -0,0 +1,384 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, cast, Optional +import logging +from ezdxf.lldxf.const import DXFKeyError, DXFValueError, DXFInternalEzdxfError +from ezdxf.lldxf.const import ( + MODEL_SPACE_R2000, + PAPER_SPACE_R2000, + TMP_PAPER_SPACE_NAME, +) +from ezdxf.lldxf.validator import is_valid_table_name +from .layout import Layout, Modelspace, Paperspace +from ezdxf.entities import DXFEntity, BlockRecord + +if TYPE_CHECKING: + from ezdxf.audit import Auditor + from ezdxf.document import Drawing + from ezdxf.entities import Dictionary, DXFLayout + +logger = logging.getLogger("ezdxf") + + +def key(name: str) -> str: + """AutoCAD uses case insensitive layout names, but stores the name case + sensitive.""" + return name.upper() + + +MODEL = key("Model") + + +class Layouts: + def __init__(self, doc: Drawing): + """Default constructor. (internal API)""" + self.doc = doc + # Store layout names in normalized form: key(name) + self._layouts: dict[str, Layout] = {} + # key: layout name as original case-sensitive string; value: DXFLayout() + self._dxf_layouts: Dictionary = cast( + "Dictionary", self.doc.rootdict["ACAD_LAYOUT"] + ) + + @classmethod + def setup(cls, doc: Drawing): + """Constructor from scratch. (internal API)""" + layouts = Layouts(doc) + layouts.setup_modelspace() + layouts.setup_paperspace() + return layouts + + def __len__(self) -> int: + """Returns count of existing layouts, including the modelspace + layout.""" + return len(self._layouts) + + def __contains__(self, name: str) -> bool: + """Returns ``True`` if layout `name` exist.""" + assert isinstance(name, str), type(str) + return key(name) in self._layouts + + def __iter__(self) -> Iterator[Layout]: + """Returns iterable of all layouts as :class:`~ezdxf.layouts.Layout` + objects, including the modelspace layout. + """ + return iter(self._layouts.values()) + + def _add_layout(self, name: str, layout: Layout): + dxf_layout = layout.dxf_layout + dxf_layout.dxf.name = name + dxf_layout.dxf.owner = self._dxf_layouts.dxf.handle + self._layouts[key(name)] = layout + self._dxf_layouts[name] = dxf_layout + + def _discard(self, layout: Layout): + name = layout.name + self._dxf_layouts.discard(name) + del self._layouts[key(name)] + + def append_layout(self, layout: Layout) -> None: + """Append an existing (copied) paperspace layout as last layout tab.""" + index = 1 + base_layout_name = layout.dxf.name + layout_name = base_layout_name + while layout_name in self: + index += 1 + layout_name = base_layout_name + f" ({index})" + layout.dxf.taborder = len(self._layouts) + 1 + self._add_layout(layout_name, layout) + + def setup_modelspace(self): + """Modelspace setup. (internal API)""" + self._new_special( + Modelspace, "Model", MODEL_SPACE_R2000, dxfattribs={"taborder": 0} + ) + + def setup_paperspace(self): + """First layout setup. (internal API)""" + self._new_special( + Paperspace, "Layout1", PAPER_SPACE_R2000, dxfattribs={"taborder": 1} + ) + + def _new_special(self, cls, name: str, block_name: str, dxfattribs: dict) -> Layout: + if name in self._layouts: + raise DXFValueError(f'Layout "{name}" already exists') + dxfattribs["owner"] = self._dxf_layouts.dxf.handle + layout = cls.new(name, block_name, self.doc, dxfattribs=dxfattribs) + self._add_layout(name, layout) + return layout + + def unique_paperspace_name(self) -> str: + """Returns a unique paperspace name. (internal API)""" + blocks = self.doc.blocks + count = 0 + while "*Paper_Space%d" % count in blocks: + count += 1 + return "*Paper_Space%d" % count + + def new(self, name: str, dxfattribs=None) -> Paperspace: + """Returns a new :class:`~ezdxf.layouts.Paperspace` layout. + + Args: + name: layout name as shown in tabs in :term:`CAD` applications + dxfattribs: additional DXF attributes for the + :class:`~ezdxf.entities.layout.DXFLayout` entity + + Raises: + DXFValueError: Invalid characters in layout name. + DXFValueError: Layout `name` already exist. + + """ + assert isinstance(name, str), type(str) + if not is_valid_table_name(name): + raise DXFValueError("Layout name contains invalid characters.") + + if name in self: + raise DXFValueError(f'Layout "{name}" already exist.') + + dxfattribs = dict(dxfattribs or {}) # copy attribs + dxfattribs["owner"] = self._dxf_layouts.dxf.handle + dxfattribs.setdefault("taborder", len(self._layouts) + 1) + block_name = self.unique_paperspace_name() + layout = Paperspace.new(name, block_name, self.doc, dxfattribs=dxfattribs) + # Default extents are ok! + # Reset limits to (0, 0) and (paper width, paper height) + layout.reset_limits() + self._add_layout(name, layout) + return layout # type: ignore + + @classmethod + def load(cls, doc: "Drawing") -> "Layouts": + """Constructor if loading from file. (internal API)""" + layouts = cls(doc) + layouts.setup_from_rootdict() + + # DXF R12: block/block_record for *Model_Space and *Paper_Space + # already exist: + if len(layouts) < 2: # restore missing DXF Layouts + layouts.restore("Model", MODEL_SPACE_R2000, taborder=0) + layouts.restore("Layout1", PAPER_SPACE_R2000, taborder=1) + return layouts + + def restore(self, name: str, block_record_name: str, taborder: int) -> None: + """Restore layout from block if DXFLayout does not exist. + (internal API)""" + if name in self: + return + block_layout = self.doc.blocks.get(block_record_name) + self._new_from_block_layout(name, block_layout, taborder) + + def _new_from_block_layout(self, name, block_layout, taborder: int) -> "Layout": + dxfattribs = { + "owner": self._dxf_layouts.dxf.handle, + "name": name, + "block_record_handle": block_layout.block_record_handle, + "taborder": taborder, + } + dxf_layout = cast( + "DXFLayout", + self.doc.objects.new_entity("LAYOUT", dxfattribs=dxfattribs), + ) + if key(name) == MODEL: + layout = Modelspace.load(dxf_layout, self.doc) + else: + layout = Paperspace.load(dxf_layout, self.doc) + self._add_layout(name, layout) + return layout + + def setup_from_rootdict(self) -> None: + """Setup layout manager from root dictionary. (internal API)""" + layout: Layout + for name, dxf_layout in self._dxf_layouts.items(): + if isinstance(dxf_layout, str): + logger.debug(f"ignore missing LAYOUT(#{dxf_layout}) entity '{name}'") + continue + if key(name) == MODEL: + layout = Modelspace(dxf_layout, self.doc) + else: + layout = Paperspace(dxf_layout, self.doc) + # assert name == layout.dxf.name + self._layouts[key(name)] = layout + + def modelspace(self) -> Modelspace: + """Returns the :class:`~ezdxf.layouts.Modelspace` layout.""" + return cast(Modelspace, self.get("Model")) + + def names(self) -> list[str]: + """Returns a list of all layout names, all names in original case + sensitive form.""" + return [layout.name for layout in self._layouts.values()] + + def get(self, name: Optional[str]) -> Layout: + """Returns :class:`~ezdxf.layouts.Layout` by `name`, case insensitive + "Model" == "MODEL". + + Args: + name: layout name as shown in tab, e.g. ``'Model'`` for modelspace + + """ + name = name or self.names_in_taborder()[1] # first paperspace layout + return self._layouts[key(name)] + + def rename(self, old_name: str, new_name: str) -> None: + """Rename a layout from `old_name` to `new_name`. + Can not rename layout ``'Model'`` and the new name of a layout must + not exist. + + Args: + old_name: actual layout name, case insensitive + new_name: new layout name, case insensitive + + Raises: + DXFValueError: try to rename ``'Model'`` + DXFValueError: Layout `new_name` already exist. + + """ + assert isinstance(old_name, str), type(old_name) + assert isinstance(new_name, str), type(new_name) + if key(old_name) == MODEL: + raise DXFValueError("Can not rename model space.") + if new_name in self: + raise DXFValueError(f'Layout "{new_name}" already exist.') + if old_name not in self: + raise DXFValueError(f'Layout "{old_name}" does not exist.') + + layout = self.get(old_name) + self._discard(layout) + layout.rename(new_name) + self._add_layout(new_name, layout) + + def names_in_taborder(self) -> list[str]: + """Returns all layout names in tab order as shown in :term:`CAD` + applications.""" + names = [ + (layout.dxf.taborder, layout.name) for layout in self._layouts.values() + ] + return [name for order, name in sorted(names)] + + def get_layout_for_entity(self, entity: DXFEntity) -> Layout: + """Returns the owner layout for a DXF `entity`.""" + owner = entity.dxf.owner + if owner is None: + raise DXFKeyError("No associated layout, owner is None.") + return self.get_layout_by_key(entity.dxf.owner) + + def get_layout_by_key(self, layout_key: str) -> Layout: + """Returns a layout by its `layout_key`. (internal API)""" + assert isinstance(layout_key, str), type(layout_key) + error_msg = f'Layout with key "{layout_key}" does not exist.' + try: + block_record = self.doc.entitydb[layout_key] + except KeyError: + raise DXFKeyError(error_msg) + if not isinstance(block_record, BlockRecord): + # VERTEX, ATTRIB, SEQEND are owned by the parent entity + raise DXFKeyError(error_msg) + try: + dxf_layout = self.doc.entitydb[block_record.dxf.layout] + except KeyError: + raise DXFKeyError(error_msg) + return self.get(dxf_layout.dxf.name) + + def get_active_layout_key(self): + """Returns layout kay for the active paperspace layout. + (internal API)""" + active_layout_block_record = self.doc.block_records.get(PAPER_SPACE_R2000) + return active_layout_block_record.dxf.handle + + def set_active_layout(self, name: str) -> None: + """Set layout `name` as active paperspace layout.""" + assert isinstance(name, str), type(name) + if key(name) == MODEL: # reserved layout name + raise DXFValueError("Can not set model space as active layout") + # raises KeyError if layout 'name' does not exist + new_active_layout = self.get(name) + old_active_layout_key = self.get_active_layout_key() + if old_active_layout_key == new_active_layout.layout_key: + return # layout 'name' is already the active layout + + blocks = self.doc.blocks + new_active_paper_space_name = new_active_layout.block_record_name + + blocks.rename_block(PAPER_SPACE_R2000, TMP_PAPER_SPACE_NAME) + blocks.rename_block(new_active_paper_space_name, PAPER_SPACE_R2000) + blocks.rename_block(TMP_PAPER_SPACE_NAME, new_active_paper_space_name) + + def delete(self, name: str) -> None: + """Delete layout `name` and destroy all entities in that layout. + + Args: + name (str): layout name as shown in tabs + + Raises: + DXFKeyError: if layout `name` do not exists + DXFValueError: deleting modelspace layout is not possible + DXFValueError: deleting last paperspace layout is not possible + + """ + assert isinstance(name, str), type(name) + if key(name) == MODEL: + raise DXFValueError("Can not delete modelspace layout.") + + layout = self.get(name) + if len(self) < 3: + raise DXFValueError("Can not delete last paperspace layout.") + if layout.layout_key == self.get_active_layout_key(): + # Layout `name` is the active layout: + for layout_name in self._layouts: + # Set any other paperspace layout as active layout + if layout_name not in (key(name), MODEL): + self.set_active_layout(layout_name) + break + self._discard(layout) + layout.destroy() + + def active_layout(self) -> Paperspace: + """Returns the active paperspace layout.""" + for layout in self: + if layout.is_active_paperspace: + return cast(Paperspace, layout) + raise DXFInternalEzdxfError("No active paperspace layout found.") + + def audit(self, auditor: Auditor): + from ezdxf.audit import AuditError + + doc = auditor.doc + + # Find/remove orphaned LAYOUT objects: + layouts = (o for o in doc.objects if o.dxftype() == "LAYOUT") + for layout in layouts: + name = layout.dxf.get("name") + if name not in self: + auditor.fixed_error( + code=AuditError.ORPHANED_LAYOUT_ENTITY, + message=f'Removed orphaned {str(layout)} "{name}"', + ) + doc.objects.delete_entity(layout) + + # Find/remove orphaned paperspace BLOCK_RECORDS named: *Paper_Space... + psp_br_handles = { + br.dxf.handle + for br in doc.block_records + if br.dxf.name.lower().startswith("*paper_space") + } + psp_layout_br_handles = { + layout.dxf.block_record_handle + for layout in self._layouts.values() + if key(layout.name) != MODEL + } + mismatch = psp_br_handles.difference(psp_layout_br_handles) + if len(mismatch): + for handle in mismatch: + br = doc.entitydb.get(handle) + name = br.dxf.get("name") # type: ignore + auditor.fixed_error( + code=AuditError.ORPHANED_PAPER_SPACE_BLOCK_RECORD_ENTITY, + message=f'Removed orphaned layout {str(br)} "{name}"', + ) + if name in doc.blocks: + doc.blocks.delete_block(name) + else: + doc.block_records.remove(name) + # Does not check the LAYOUT content this is done in the BlockSection, + # because the content of layouts is stored as blocks. diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__init__.py new file mode 100644 index 0000000..52171b2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__init__.py @@ -0,0 +1,3 @@ +# Low Level DXF modules +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..9a40956 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/attributes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/attributes.cpython-312.pyc new file mode 100644 index 0000000..904e676 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/attributes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/const.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/const.cpython-312.pyc new file mode 100644 index 0000000..7f1b735 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/const.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/encoding.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/encoding.cpython-312.pyc new file mode 100644 index 0000000..5c6c3a8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/encoding.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/extendedtags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/extendedtags.cpython-312.pyc new file mode 100644 index 0000000..d99362f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/extendedtags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/fileindex.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/fileindex.cpython-312.pyc new file mode 100644 index 0000000..293f6bf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/fileindex.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/hdrvars.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/hdrvars.cpython-312.pyc new file mode 100644 index 0000000..759a13f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/hdrvars.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/loader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/loader.cpython-312.pyc new file mode 100644 index 0000000..5751ee6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/loader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/packedtags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/packedtags.cpython-312.pyc new file mode 100644 index 0000000..3fee8e4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/packedtags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/repair.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/repair.cpython-312.pyc new file mode 100644 index 0000000..a2075dc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/repair.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagger.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagger.cpython-312.pyc new file mode 100644 index 0000000..2d128f4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagger.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tags.cpython-312.pyc new file mode 100644 index 0000000..a120d2d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagwriter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagwriter.cpython-312.pyc new file mode 100644 index 0000000..763122e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/tagwriter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/types.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000..ca2b5c7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/types.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/validator.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/validator.cpython-312.pyc new file mode 100644 index 0000000..aff88ce Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/__pycache__/validator.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/attributes.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/attributes.py new file mode 100644 index 0000000..d0edabb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/attributes.py @@ -0,0 +1,255 @@ +# Copyright (c) 2011-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Optional, + TYPE_CHECKING, + Iterable, + Iterator, + Callable, + Any, + Union, + NewType, + cast, + NamedTuple, + Mapping, +) +from enum import Enum +from .const import DXFAttributeError, DXF12 +import copy + +if TYPE_CHECKING: + from ezdxf.entities import DXFEntity + + +class DefSubclass(NamedTuple): + name: Optional[str] + attribs: dict[str, DXFAttr] + + +VIRTUAL_TAG = -666 + + +class XType(Enum): + """Extended Attribute Types""" + + point2d = 1 # 2D points only + point3d = 2 # 3D points only + any_point = 3 # 2D or 3D points + callback = 4 # callback attribute + + +def group_code_mapping( + subclass: DefSubclass, *, ignore: Optional[Iterable[int]] = None +) -> dict[int, Union[str, list[str]]]: + # Unique group codes are stored as group_code : name + # Duplicate group codes are stored as group_code : [name1, name2, ...] + # The order of appearance is important, therefore also callback attributes + # have to be included, but they should not be loaded into the DXF namespace. + mapping: dict[int, Union[str, list[str]]] = dict() + for name, dxfattrib in subclass.attribs.items(): + if dxfattrib.xtype == XType.callback: + # Mark callback attributes for special treatment as invalid + # Python name: + name = "*" + name + code = dxfattrib.code + existing_data: Union[None, str, list[str]] = mapping.get(code) + if existing_data is None: + mapping[code] = name + else: + if isinstance(existing_data, str): + existing_data = [existing_data] + mapping[code] = existing_data + assert isinstance(existing_data, list) + existing_data.append(name) + + if ignore: + # Mark these tags as "*IGNORE" to be ignored, + # but they are not real callbacks! See POLYLINE for example! + for code in ignore: + mapping[code] = "*IGNORE" + return mapping + + +def merge_group_code_mappings(*mappings: Mapping) -> dict[int, str]: + merge_group_code_mapping: dict[int, str] = {} + for index, mapping in enumerate(mappings): + msg = f"{index}. mapping contains none unique group codes" + if not all(isinstance(e, str) for e in mapping.values()): + raise TypeError(msg) + if any(k in merge_group_code_mapping for k in mapping.keys()): + raise TypeError(msg) + merge_group_code_mapping.update(mapping) + return merge_group_code_mapping + + +# Unique object as marker +ReturnDefault = NewType("ReturnDefault", object) +RETURN_DEFAULT = cast(ReturnDefault, object()) + + +class DXFAttr: + """Represents a DXF attribute for an DXF entity, accessible by the + DXF namespace :attr:`DXFEntity.dxf` like ``entity.dxf.color = 7``. + This definitions are immutable by design not by implementation. + + Extended Attribute Types + ------------------------ + + - XType.point2d: 2D points only + - XType.point3d: 3D point only + - XType.any_point: mixed 2D/3D point + - XType.callback: Calls get_value(entity) to get the value of DXF + attribute 'name', and calls set_value(entity, value) to set value + of DXF attribute 'name'. + + See example definition: ezdxf.entities.dxfgfx.acdb_entity. + + """ + + def __init__( + self, + code: int, + xtype: Optional[XType] = None, + default=None, + optional: bool = False, + dxfversion: str = DXF12, + getter: str = "", + setter: str = "", + alias: str = "", + validator: Optional[Callable[[Any], bool]] = None, + fixer: Optional[Union[Callable[[Any], Any], None, ReturnDefault]] = None, + ): + + # Attribute name set by DXFAttributes.__init__() + self.name: str = "" + + # DXF group code + self.code: int = code + + # Extended attribute type: + self.xtype: Optional[XType] = xtype + + # DXF default value + self.default: Any = default + + # If optional is True, this attribute will be exported to DXF files + # only if the given value differs from default value. + self.optional: bool = optional + + # This attribute is valid for all DXF versions starting from the + # specified DXF version, default is DXF12 = 'AC1009' + self.dxfversion: str = dxfversion + + # DXF entity getter method name for callback attributes + self.getter: str = getter + + # DXF entity setter method name for callback attributes + self.setter: str = setter + + # Alternative name for this attribute + self.alias: str = alias + + # Returns True if given value is valid - the validator should be as + # fast as possible! + self.validator: Optional[Callable[[Any], bool]] = validator + + # Returns a fixed value for invalid attributes, the fixer is called + # only if the validator returns False. + if fixer is RETURN_DEFAULT: + fixer = self._return_default + # excluding ReturnDefault type + self.fixer = cast(Optional[Callable[[Any], Any]], fixer) + + def _return_default(self, x: Any) -> Any: + return self.default + + def __str__(self) -> str: + return f"({self.name}, {self.code})" + + def __repr__(self) -> str: + return "DXFAttr" + self.__str__() + + def get_callback_value(self, entity: DXFEntity) -> Any: + """ + Executes a callback function in 'entity' to get a DXF value. + + Callback function is defined by self.getter as string. + + Args: + entity: DXF entity + + Raises: + AttributeError: getter method does not exist + TypeError: getter is None + + Returns: + DXF attribute value + + """ + try: + return getattr(entity, self.getter)() + except AttributeError: + raise DXFAttributeError( + f"DXF attribute {self.name}: invalid getter {self.getter}." + ) + except TypeError: + raise DXFAttributeError(f"DXF attribute {self.name} has no getter.") + + def set_callback_value(self, entity: DXFEntity, value: Any) -> None: + """Executes a callback function in 'entity' to set a DXF value. + + Callback function is defined by self.setter as string. + + Args: + entity: DXF entity + value: DXF attribute value + + Raises: + AttributeError: setter method does not exist + TypeError: setter is None + + """ + try: + getattr(entity, self.setter)(value) + except AttributeError: + raise DXFAttributeError( + f"DXF attribute {self.name}: invalid setter {self.setter}." + ) + except TypeError: + raise DXFAttributeError(f"DXF attribute {self.name} has no setter.") + + def is_valid_value(self, value: Any) -> bool: + if self.validator: + return self.validator(value) + else: + return True + + +class DXFAttributes: + __slots__ = ("_attribs",) + + def __init__(self, *subclassdefs: DefSubclass): + self._attribs: dict[str, DXFAttr] = dict() + for subclass in subclassdefs: + for name, dxfattrib in subclass.attribs.items(): + dxfattrib.name = name + self._attribs[name] = dxfattrib + if dxfattrib.alias: + alias = copy.copy(dxfattrib) + alias.name = dxfattrib.alias + alias.alias = dxfattrib.name + self._attribs[dxfattrib.alias] = alias + + def __contains__(self, name: str) -> bool: + return name in self._attribs + + def get(self, key: str) -> Optional[DXFAttr]: + return self._attribs.get(key) + + def build_group_code_items(self, func=lambda x: True) -> Iterator[tuple[int, str]]: + return ( + (attrib.code, name) + for name, attrib in self._attribs.items() + if attrib.code > 0 and func(name) + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/const.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/const.py new file mode 100644 index 0000000..016c49d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/const.py @@ -0,0 +1,702 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from dataclasses import dataclass + +DXF9 = "AC1004" +DXF10 = "AC1006" +DXF12 = "AC1009" +DXF13 = "AC1012" +DXF14 = "AC1014" +DXF2000 = "AC1015" +DXF2004 = "AC1018" +DXF2007 = "AC1021" +DXF2010 = "AC1024" +DXF2013 = "AC1027" +DXF2018 = "AC1032" + +acad_release = { + DXF9: "R9", + DXF10: "R10", + DXF12: "R12", + DXF13: "R13", + DXF14: "R14", + DXF2000: "R2000", + DXF2004: "R2004", + DXF2007: "R2007", + DXF2010: "R2010", + DXF2013: "R2013", + DXF2018: "R2018", +} + +acad_maint_ver = { + DXF12: 0, + DXF2000: 6, + DXF2004: 0, + DXF2007: 25, + DXF2010: 6, + DXF2013: 105, + DXF2018: 4, +} + +versions_supported_by_new = [ + DXF12, + DXF2000, + DXF2004, + DXF2007, + DXF2010, + DXF2013, + DXF2018, +] +versions_supported_by_save = versions_supported_by_new +LATEST_DXF_VERSION = versions_supported_by_new[-1] + +acad_release_to_dxf_version = {acad: dxf for dxf, acad in acad_release.items()} + + +class DXFError(Exception): + """Base exception for all `ezdxf` exceptions. """ + pass + + +class InvalidGeoDataException(DXFError): + pass + + +class DXFStructureError(DXFError): + pass + + +class DXFLoadError(DXFError): + pass + + +class DXFAppDataError(DXFStructureError): + pass + + +class DXFXDataError(DXFStructureError): + pass + + +class DXFVersionError(DXFError): + """Errors related to features not supported by the chosen DXF Version""" + pass + + +class DXFInternalEzdxfError(DXFError): + """Indicates internal errors - should be fixed by mozman""" + pass + + +class DXFUnsupportedFeature(DXFError): + """Indicates unsupported features for DXFEntities e.g. translation for + ACIS data + """ + pass + + +class DXFValueError(DXFError, ValueError): + pass + + +class DXFKeyError(DXFError, KeyError): + pass + + +class DXFAttributeError(DXFError, AttributeError): + pass + + +class DXFIndexError(DXFError, IndexError): + pass + + +class DXFTypeError(DXFError, TypeError): + pass + + +class DXFTableEntryError(DXFValueError): + pass + + +class DXFEncodingError(DXFError): + pass + + +class DXFDecodingError(DXFError): + pass + + +class DXFInvalidLineType(DXFValueError): + pass + + +class DXFBlockInUseError(DXFValueError): + pass + + +class DXFUndefinedBlockError(DXFKeyError): + pass + + +class DXFRenderError(DXFError): + """Errors related to DXF "rendering" tasks. + + In this context "rendering" means creating the graphical representation of + complex DXF entities by DXF primitives (LINE, TEXT, ...) + e.g. for DIMENSION or LEADER entities. + """ + pass + + +class DXFMissingDefinitionPoint(DXFRenderError): + """Missing required definition points in the DIMENSION entity.""" + + +def normalize_dxfversion(dxfversion: str, check_save=True) -> str: + """Normalizes the DXF version string to "AC10xx".""" + dxfversion = dxfversion.upper() + dxfversion = acad_release_to_dxf_version.get(dxfversion, dxfversion) + if check_save and dxfversion not in versions_supported_by_save: + raise DXFVersionError(f"Invalid DXF version: {dxfversion}") + return dxfversion + + +MANAGED_SECTIONS = { + "HEADER", + "CLASSES", + "TABLES", + "BLOCKS", + "ENTITIES", + "OBJECTS", + "ACDSDATA", +} + +TABLE_NAMES_ACAD_ORDER = [ + "VPORT", + "LTYPE", + "LAYER", + "STYLE", + "VIEW", + "UCS", + "APPID", + "DIMSTYLE", + "BLOCK_RECORD", +] + +DEFAULT_TEXT_STYLE = "Standard" +DEFAULT_TEXT_FONT = "txt" +APP_DATA_MARKER = 102 +SUBCLASS_MARKER = 100 +XDATA_MARKER = 1001 +COMMENT_MARKER = 999 +STRUCTURE_MARKER = 0 +HEADER_VAR_MARKER = 9 +ACAD_REACTORS = "{ACAD_REACTORS" +ACAD_XDICTIONARY = "{ACAD_XDICTIONARY" +XDICT_HANDLE_CODE = 360 +REACTOR_HANDLE_CODE = 330 +OWNER_CODE = 330 + +# https://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-2553CF98-44F6-4828-82DD-FE3BC7448113 +MAX_STR_LEN = 255 # DXF R12 without line endings +EXT_MAX_STR_LEN = 2049 # DXF R2000+ without line endings + +# Special tag codes for internal purpose: +# -1 to -5 id reserved by AutoCAD for internal use, but this tags will never be +# saved to file. +# Same approach here, the following tags have to be converted/transformed into +# normal tags before saved to file. +COMPRESSED_TAGS = -10 + +# All color related constants are located in colors.py +BYBLOCK = 0 +BYLAYER = 256 +BYOBJECT = 257 +RED = 1 +YELLOW = 2 +GREEN = 3 +CYAN = 4 +BLUE = 5 +MAGENTA = 6 +BLACK = 7 +WHITE = 7 + +# All transparency related constants are located in colors.py +TRANSPARENCY_BYBLOCK = 0x01000000 + + +LINEWEIGHT_BYLAYER = -1 +LINEWEIGHT_BYBLOCK = -2 +LINEWEIGHT_DEFAULT = -3 + +VALID_DXF_LINEWEIGHTS = ( + 0, + 5, + 9, + 13, + 15, + 18, + 20, + 25, + 30, + 35, + 40, + 50, + 53, + 60, + 70, + 80, + 90, + 100, + 106, + 120, + 140, + 158, + 200, + 211, +) +MAX_VALID_LINEWEIGHT = VALID_DXF_LINEWEIGHTS[-1] +VALID_DXF_LINEWEIGHT_VALUES = set(VALID_DXF_LINEWEIGHTS) | { + LINEWEIGHT_DEFAULT, + LINEWEIGHT_BYLAYER, + LINEWEIGHT_BYBLOCK, +} + +# Entity: Polyline, Polymesh +# 70 flags +POLYLINE_CLOSED = 1 +POLYLINE_MESH_CLOSED_M_DIRECTION = POLYLINE_CLOSED +POLYLINE_CURVE_FIT_VERTICES_ADDED = 2 +POLYLINE_SPLINE_FIT_VERTICES_ADDED = 4 +POLYLINE_3D_POLYLINE = 8 +POLYLINE_3D_POLYMESH = 16 +POLYLINE_MESH_CLOSED_N_DIRECTION = 32 +POLYLINE_POLYFACE = 64 +POLYLINE_GENERATE_LINETYPE_PATTERN = 128 + +# Entity: Polymesh +# 75 surface smooth type +POLYMESH_NO_SMOOTH = 0 +POLYMESH_QUADRATIC_BSPLINE = 5 +POLYMESH_CUBIC_BSPLINE = 6 +POLYMESH_BEZIER_SURFACE = 8 + +# Entity: Vertex +# 70 flags +VERTEXNAMES = ("vtx0", "vtx1", "vtx2", "vtx3") +VTX_EXTRA_VERTEX_CREATED = 1 # Extra vertex created by curve-fitting +VTX_CURVE_FIT_TANGENT = 2 # Curve-fit tangent defined for this vertex. +# A curve-fit tangent direction of 0 may be omitted from the DXF output, but is +# significant if this bit is set. +# 4 = unused, never set in dxf files +VTX_SPLINE_VERTEX_CREATED = 8 # Spline vertex created by spline-fitting +VTX_SPLINE_FRAME_CONTROL_POINT = 16 +VTX_3D_POLYLINE_VERTEX = 32 +VTX_3D_POLYGON_MESH_VERTEX = 64 +VTX_3D_POLYFACE_MESH_VERTEX = 128 + +VERTEX_FLAGS = { + "AcDb2dPolyline": 0, + "AcDb3dPolyline": VTX_3D_POLYLINE_VERTEX, + "AcDbPolygonMesh": VTX_3D_POLYGON_MESH_VERTEX, + "AcDbPolyFaceMesh": VTX_3D_POLYGON_MESH_VERTEX + | VTX_3D_POLYFACE_MESH_VERTEX, +} +POLYLINE_FLAGS = { + "AcDb2dPolyline": 0, + "AcDb3dPolyline": POLYLINE_3D_POLYLINE, + "AcDbPolygonMesh": POLYLINE_3D_POLYMESH, + "AcDbPolyFaceMesh": POLYLINE_POLYFACE, +} + +# block-type flags (bit coded values, may be combined): +# Entity: BLOCK +# 70 flags + +# This is an anonymous block generated by hatching, associative dimensioning, +# other internal operations, or an application: +BLK_ANONYMOUS = 1 + +# This block has non-constant attribute definitions (this bit is not set if the +# block has any attribute definitions that are constant, or has no attribute +# definitions at all) +BLK_NON_CONSTANT_ATTRIBUTES = 2 + +# This block is an external reference (xref): +BLK_XREF = 4 + +# This block is an xref overlay: +BLK_XREF_OVERLAY = 8 + +# This block is externally dependent: +BLK_EXTERNAL = 16 + +# This is a resolved external reference, or dependent of an external reference +# (ignored on input): +BLK_RESOLVED = 32 + +# This definition is a referenced external reference (ignored on input): +BLK_REFERENCED = 64 + +LWPOLYLINE_CLOSED = 1 +LWPOLYLINE_PLINEGEN = 128 + +DEFAULT_TTF = "DejaVuSans.ttf" + +# TextHAlign enum +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 +FIT = 5 + +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 +MIRROR_X = 2 +BACKWARD = MIRROR_X +MIRROR_Y = 4 +UPSIDE_DOWN = MIRROR_Y + +VERTICAL_STACKED = 4 # only stored in TextStyle.dxf.flags! + +# Special char and encodings used in TEXT, ATTRIB and ATTDEF: +# "%%d" -> "°" +SPECIAL_CHAR_ENCODING = { + "c": "Ø", # alt-0216 + "d": "°", # alt-0176 + "p": "±", # alt-0177 +} +# Inline codes for strokes in TEXT, ATTRIB and ATTDEF +# %%u underline +# %%o overline +# %%k strike through +# Formatting will be applied until the same code appears again or the end +# of line. +# Special codes and formatting is case insensitive: d=D, u=U + +# MTextEntityAlignment enum +MTEXT_TOP_LEFT = 1 +MTEXT_TOP_CENTER = 2 +MTEXT_TOP_RIGHT = 3 +MTEXT_MIDDLE_LEFT = 4 +MTEXT_MIDDLE_CENTER = 5 +MTEXT_MIDDLE_RIGHT = 6 +MTEXT_BOTTOM_LEFT = 7 +MTEXT_BOTTOM_CENTER = 8 +MTEXT_BOTTOM_RIGHT = 9 + +# MTextFlowDirection enum +MTEXT_LEFT_TO_RIGHT = 1 +MTEXT_TOP_TO_BOTTOM = 3 +MTEXT_BY_STYLE = 5 + +# MTextLineSpacing enum +MTEXT_AT_LEAST = 1 +MTEXT_EXACT = 2 + +MTEXT_COLOR_INDEX = { + "red": RED, + "yellow": YELLOW, + "green": GREEN, + "cyan": CYAN, + "blue": BLUE, + "magenta": MAGENTA, + "white": WHITE, +} + +# MTextBackgroundColor enum +MTEXT_BG_OFF = 0 +MTEXT_BG_COLOR = 1 +MTEXT_BG_WINDOW_COLOR = 2 +MTEXT_BG_CANVAS_COLOR = 3 +MTEXT_TEXT_FRAME = 16 + + +CLOSED_SPLINE = 1 +PERIODIC_SPLINE = 2 +RATIONAL_SPLINE = 4 +PLANAR_SPLINE = 8 +LINEAR_SPLINE = 16 + +# Hatch constants +HATCH_TYPE_USER_DEFINED = 0 +HATCH_TYPE_PREDEFINED = 1 +HATCH_TYPE_CUSTOM = 2 +HATCH_PATTERN_TYPE = ["user-defined", "predefined", "custom"] + +ISLAND_DETECTION = ["nested", "outermost", "ignore"] +HATCH_STYLE_NORMAL = 0 +HATCH_STYLE_NESTED = 0 +HATCH_STYLE_OUTERMOST = 1 +HATCH_STYLE_IGNORE = 2 + +BOUNDARY_PATH_DEFAULT = 0 +BOUNDARY_PATH_EXTERNAL = 1 +BOUNDARY_PATH_POLYLINE = 2 +BOUNDARY_PATH_DERIVED = 4 +BOUNDARY_PATH_TEXTBOX = 8 +BOUNDARY_PATH_OUTERMOST = 16 + + +def boundary_path_flag_names(flags: int) -> list[str]: + if flags == 0: + return ["default"] + types: list[str] = [] + if flags & BOUNDARY_PATH_EXTERNAL: + types.append("external") + if flags & BOUNDARY_PATH_POLYLINE: + types.append("polyline") + if flags & BOUNDARY_PATH_DERIVED: + types.append("derived") + if flags & BOUNDARY_PATH_TEXTBOX: + types.append("textbox") + if flags & BOUNDARY_PATH_OUTERMOST: + types.append("outermost") + return types + + +@dataclass(frozen=True) +class BoundaryPathState: + external: bool = False + derived: bool = False + textbox: bool = False + outermost: bool = False + + @staticmethod + def from_flags(flag: int) -> "BoundaryPathState": + return BoundaryPathState( + external=bool(flag & BOUNDARY_PATH_EXTERNAL), + derived=bool(flag & BOUNDARY_PATH_DERIVED), + textbox=bool(flag & BOUNDARY_PATH_TEXTBOX), + outermost=bool(flag & BOUNDARY_PATH_OUTERMOST), + ) + + @property + def default(self) -> bool: + return not ( + self.external or self.derived or self.outermost or self.textbox + ) + + +GRADIENT_TYPES = frozenset( + [ + "LINEAR", + "CYLINDER", + "INVCYLINDER", + "SPHERICAL", + "INVSPHERICAL", + "HEMISPHERICAL", + "INVHEMISPHERICAL", + "CURVED", + "INVCURVED", + ] +) + +# Viewport Status Flags (VSF) group code=90 +VSF_PERSPECTIVE_MODE = 0x1 # enabled if set +VSF_FRONT_CLIPPING = 0x2 # enabled if set +VSF_BACK_CLIPPING = 0x4 # enabled if set +VSF_USC_FOLLOW = 0x8 # enabled if set +VSF_FRONT_CLIPPING_NOT_AT_EYE = 0x10 # enabled if set +VSF_UCS_ICON_VISIBILITY = 0x20 # enabled if set +VSF_UCS_ICON_AT_ORIGIN = 0x40 # enabled if set +VSF_FAST_ZOOM = 0x80 # enabled if set +VSF_SNAP_MODE = 0x100 # enabled if set +VSF_GRID_MODE = 0x200 # enabled if set +VSF_ISOMETRIC_SNAP_STYLE = 0x400 # enabled if set +VSF_HIDE_PLOT_MODE = 0x800 # enabled if set + +# If set and kIsoPairRight is not set, then isopair top is enabled. +# If both kIsoPairTop and kIsoPairRight are set, then isopair left is enabled: +VSF_KISOPAIR_TOP = 0x1000 + +# If set and kIsoPairTop is not set, then isopair right is enabled: +VSF_KISOPAIR_RIGHT = 0x2000 +VSF_VIEWPORT_ZOOM_LOCKING = 0x4000 # enabled if set +VSF_LOCK_ZOOM = 0x4000 # enabled if set +VSF_CURRENTLY_ALWAYS_ENABLED = 0x8000 # always set without a meaning :) +VSF_NON_RECTANGULAR_CLIPPING = 0x10000 # enabled if set +VSF_TURN_VIEWPORT_OFF = 0x20000 +VSF_NO_GRID_LIMITS = 0x40000 +VSF_ADAPTIVE_GRID_DISPLAY = 0x80000 +VSF_SUBDIVIDE_GRID = 0x100000 +VSF_GRID_FOLLOW_WORKPLANE = 0x200000 + +# Viewport Render Mode (VRM) group code=281 +VRM_2D_OPTIMIZED = 0 +VRM_WIREFRAME = 1 +VRM_HIDDEN_LINE = 2 +VRM_FLAT_SHADED = 3 +VRM_GOURAUD_SHADED = 4 +VRM_FLAT_SHADED_WITH_WIREFRAME = 5 +VRM_GOURAUD_SHADED_WITH_WIREFRAME = 6 + +IMAGE_SHOW = 1 +IMAGE_SHOW_WHEN_NOT_ALIGNED = 2 +IMAGE_USE_CLIPPING_BOUNDARY = 4 +IMAGE_TRANSPARENCY_IS_ON = 8 + +UNDERLAY_CLIPPING = 1 +UNDERLAY_ON = 2 +UNDERLAY_MONOCHROME = 4 +UNDERLAY_ADJUST_FOR_BG = 8 + +DIM_LINEAR = 0 +DIM_ALIGNED = 1 +DIM_ANGULAR = 2 +DIM_DIAMETER = 3 +DIM_RADIUS = 4 +DIM_ANGULAR_3P = 5 +DIM_ORDINATE = 6 +DIM_ARC = 8 +DIM_BLOCK_EXCLUSIVE = 32 +DIM_ORDINATE_TYPE = 64 # unset for x-type, set for y-type +DIM_USER_LOCATION_OVERRIDE = 128 + +DIMZIN_SUPPRESS_ZERO_FEET_AND_PRECISELY_ZERO_INCHES = 0 +DIMZIN_INCLUDES_ZERO_FEET_AND_PRECISELY_ZERO_INCHES = 1 +DIMZIN_INCLUDES_ZERO_FEET_AND_SUPPRESSES_ZERO_INCHES = 2 +DIMZIN_INCLUDES_ZERO_INCHES_AND_SUPPRESSES_ZERO_FEET = 3 +DIMZIN_SUPPRESSES_LEADING_ZEROS = 4 # only decimal dimensions +DIMZIN_SUPPRESSES_TRAILING_ZEROS = 8 # only decimal dimensions + +# ATTRIB & ATTDEF flags +ATTRIB_INVISIBLE = 1 # Attribute is invisible (does not appear) +ATTRIB_CONST = 2 # This is a constant attribute +ATTRIB_VERIFY = 4 # Verification is required on input of this attribute +ATTRIB_IS_PRESET = 8 # no prompt during insertion + +# '|' is allowed in layer name, as ltype name ... +INVALID_NAME_CHARACTERS = '<>/\\":;?*=`' +INVALID_LAYER_NAME_CHARACTERS = set(INVALID_NAME_CHARACTERS) + +STD_SCALES = { + 1: (1.0 / 128.0, 12.0), + 2: (1.0 / 64.0, 12.0), + 3: (1.0 / 32.0, 12.0), + 4: (1.0 / 16.0, 12.0), + 5: (3.0 / 32.0, 12.0), + 6: (1.0 / 8.0, 12.0), + 7: (3.0 / 16.0, 12.0), + 8: (1.0 / 4.0, 12.0), + 9: (3.0 / 8.0, 12.0), + 10: (1.0 / 2.0, 12.0), + 11: (3.0 / 4.0, 12.0), + 12: (1.0, 12.0), + 13: (3.0, 12.0), + 14: (6.0, 12.0), + 15: (12.0, 12.0), + 16: (1.0, 1.0), + 17: (1.0, 2.0), + 18: (1.0, 4.0), + 19: (1.0, 8.0), + 20: (1.0, 10.0), + 21: (1.0, 16.0), + 22: (1.0, 20.0), + 23: (1.0, 30.0), + 24: (1.0, 40.0), + 25: (1.0, 50.0), + 26: (1.0, 100.0), + 27: (2.0, 1.0), + 28: (4.0, 1.0), + 29: (8.0, 1.0), + 30: (10.0, 1.0), + 31: (100.0, 1.0), + 32: (1000.0, 1.0), +} + +RASTER_UNITS = { + "none": 0, + "mm": 1, + "cm": 2, + "m": 3, + "km": 4, + "in": 5, + "ft": 6, + "yd": 7, + "mi": 8, +} +REVERSE_RASTER_UNITS = {value: name for name, value in RASTER_UNITS.items()} + +MODEL_SPACE_R2000 = "*Model_Space" +MODEL_SPACE_R12 = "$Model_Space" +PAPER_SPACE_R2000 = "*Paper_Space" +PAPER_SPACE_R12 = "$Paper_Space" +TMP_PAPER_SPACE_NAME = "*Paper_Space999999" + +MODEL_SPACE = { + MODEL_SPACE_R2000.lower(), + MODEL_SPACE_R12.lower(), +} + +PAPER_SPACE = { + PAPER_SPACE_R2000.lower(), + PAPER_SPACE_R12.lower(), +} + +LAYOUT_NAMES = { + PAPER_SPACE_R2000.lower(), + PAPER_SPACE_R12.lower(), + MODEL_SPACE_R2000.lower(), + MODEL_SPACE_R12.lower(), +} + + +# TODO: make enum +DIMJUST = { + "center": 0, + "left": 1, + "right": 2, + "above1": 3, + "above2": 4, +} + + +# TODO: make enum +DIMTAD = { + "above": 1, + "center": 0, + "below": 4, +} + + +DEFAULT_ENCODING = "cp1252" + +MLINE_TOP = 0 +MLINE_ZERO = 1 +MLINE_BOTTOM = 2 +MLINE_HAS_VERTICES = 1 +MLINE_CLOSED = 2 +MLINE_SUPPRESS_START_CAPS = 4 +MLINE_SUPPRESS_END_CAPS = 8 + +MLINESTYLE_FILL = 1 +MLINESTYLE_MITER = 2 +MLINESTYLE_START_SQUARE = 16 +MLINESTYLE_START_INNER_ARC = 32 +MLINESTYLE_START_ROUND = 64 +MLINESTYLE_END_SQUARE = 256 +MLINESTYLE_END_INNER_ARC = 512 +MLINESTYLE_END_ROUND = 1024 + +# VP Layer Overrides + +OVR_ALPHA_KEY = "ADSK_XREC_LAYER_ALPHA_OVR" +OVR_COLOR_KEY = "ADSK_XREC_LAYER_COLOR_OVR" +OVR_LTYPE_KEY = "ADSK_XREC_LAYER_LINETYPE_OVR" +OVR_LW_KEY = "ADSK_XREC_LAYER_LINEWT_OVR" + +OVR_ALPHA_CODE = 440 +OVR_COLOR_CODE = 420 +OVR_LTYPE_CODE = 343 +OVR_LW_CODE = 91 +OVR_VP_HANDLE_CODE = 335 + +OVR_APP_ALPHA = "{ADSK_LYR_ALPHA_OVERRIDE" +OVR_APP_COLOR = "{ADSK_LYR_COLOR_OVERRIDE" +OVR_APP_LTYPE = "{ADSK_LYR_LINETYPE_OVERRIDE" +OVR_APP_LW = "{ADSK_LYR_LINEWT_OVERRIDE" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/encoding.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/encoding.py new file mode 100644 index 0000000..5e72d43 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/encoding.py @@ -0,0 +1,85 @@ +# Copyright (c) 2016-2023, Manfred Moitzi +# License: MIT License +import re +import codecs +import binascii + +surrogate_escape = codecs.lookup_error("surrogateescape") +BACKSLASH_UNICODE = re.compile(r"(\\U\+[A-F0-9]{4})") +MIF_ENCODED = re.compile(r"(\\M\+[1-5][A-F0-9]{4})") + + +def dxf_backslash_replace(exc: Exception): + if isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)): + s = "" + # mypy does not recognize properties: exc.start, exc.end, exc.object + for c in exc.object[exc.start : exc.end]: + x = ord(c) + if x <= 0xFF: + s += "\\x%02x" % x + elif 0xDC80 <= x <= 0xDCFF: + # Delegate surrogate handling: + return surrogate_escape(exc) + elif x <= 0xFFFF: + s += "\\U+%04x" % x + else: + s += "\\U+%08x" % x + return s, exc.end + else: + raise TypeError(f"Can't handle {exc.__class__.__name__}") + + +def encode(s: str, encoding="utf8") -> bytes: + """Shortcut to use the correct error handler""" + return s.encode(encoding, errors="dxfreplace") + + +def _decode(s: str) -> str: + if s.startswith(r"\U+"): + return chr(int(s[3:], 16)) + else: + return s + + +def has_dxf_unicode(s: str) -> bool: + """Returns ``True`` if string `s` contains ``\\U+xxxx`` encoded characters.""" + return bool(re.search(BACKSLASH_UNICODE, s)) + + +def decode_dxf_unicode(s: str) -> str: + """Decode ``\\U+xxxx`` encoded characters.""" + + return "".join(_decode(part) for part in re.split(BACKSLASH_UNICODE, s)) + + +def has_mif_encoding(s: str) -> bool: + """Returns ``True`` if string `s` contains MIF encoded (``\\M+cxxxx``) characters. + """ + return bool(re.search(MIF_ENCODED, s)) + + +def decode_mif_to_unicode(s: str) -> str: + """Decode MIF encoded characters ``\\M+cxxxx``.""" + return "".join(_decode_mif(part) for part in re.split(MIF_ENCODED, s)) + + +MIF_CODE_PAGE = { + # See https://docs.intellicad.org/files/oda/2021_11/oda_drawings_docs/frames.html?frmname=topic&frmfile=FontHandling.html + "1": "cp932", # Japanese (Shift-JIS) + "2": "cp950", # Traditional Chinese (Big 5) + "3": "cp949", # Wansung (KS C-5601-1987) + "4": "cp1391", # Johab (KS C-5601-1992) + "5": "cp936", # Simplified Chinese (GB 2312-80) +} + + +def _decode_mif(s: str) -> str: + if s.startswith(r"\M+"): + try: + code_page = MIF_CODE_PAGE[s[3]] + codec = codecs.lookup(code_page) + byte_data = binascii.unhexlify(s[4:]) + return codec.decode(byte_data)[0] + except Exception: + pass + return s diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/extendedtags.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/extendedtags.py new file mode 100644 index 0000000..462544f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/extendedtags.py @@ -0,0 +1,463 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, Iterator +from itertools import chain +import logging +from .types import tuples_to_tags, NONE_TAG +from .tags import Tags, DXFTag +from .const import DXFStructureError, DXFValueError, DXFKeyError +from .types import ( + APP_DATA_MARKER, + SUBCLASS_MARKER, + XDATA_MARKER, + EMBEDDED_OBJ_MARKER, + EMBEDDED_OBJ_STR, +) +from .types import is_app_data_marker, is_embedded_object_marker +from .tagger import internal_tag_compiler + +if TYPE_CHECKING: + from ezdxf.eztypes import IterableTags + +logger = logging.getLogger("ezdxf") + + +class ExtendedTags: + """Manages DXF tags located in sub structures: + + - Subclasses + - AppData + - Extended Data (XDATA) + - Embedded objects + + Args: + tags: iterable of type DXFTag() + legacy: flag for DXF R12 tags + + """ + + __slots__ = ("subclasses", "appdata", "xdata", "embedded_objects") + + def __init__(self, tags: Optional[Iterable[DXFTag]] = None, legacy=False): + if isinstance(tags, str): + raise DXFValueError( + "use ExtendedTags.from_text() to create tags from a string." + ) + + # code == 102, keys are "{", values are Tags() + self.appdata: list[Tags] = list() + + # code == 100, keys are "subclass-name", values are Tags() + self.subclasses: list[Tags] = list() + + # code >= 1000, keys are "APPID", values are Tags() + self.xdata: list[Tags] = list() + + # Store embedded objects as list, but embedded objects are rare, so + # storing an empty list for every DXF entity is waste of memory. + # Support for multiple embedded objects is maybe future proof, but + # for now only one embedded object per entity is used. + self.embedded_objects: Optional[list[Tags]] = None + + if tags is not None: + self._setup(iter(tags)) + if legacy: + self.legacy_repair() + + def legacy_repair(self): + """Legacy (DXF R12) tags handling and repair.""" + self.flatten_subclasses() + # ... and we can do some checks: + # DXF R12 does not support (102, '{APPID') ... structures + if len(self.appdata): + # Just a debug message, do not delete appdata, this would corrupt + # the data structure. + self.debug("Found application defined entity data in DXF R12.") + + # That is really unlikely, but... + if self.embedded_objects is not None: + # Removing embedded objects from DXF R12 does not corrupt the + # data structure: + self.embedded_objects = None + self.debug("Found embedded object in DXF R12.") + + def flatten_subclasses(self): + """Flatten subclasses in legacy mode (DXF R12). + + There exists DXF R12 with subclass markers, technical incorrect but + works if the reader ignore subclass marker tags, unfortunately ezdxf + tries to use this subclass markers and therefore R12 parsing by ezdxf + does not work without removing these subclass markers. + + This method removes all subclass markers and flattens all subclasses + into ExtendedTags.noclass. + + """ + if len(self.subclasses) < 2: + return + noclass = self.noclass + for subclass in self.subclasses[1:]: + # Exclude first tag (100, subclass marker): + noclass.extend(subclass[1:]) + self.subclasses = [noclass] + self.debug("Removed subclass marker from entity for DXF R12.") + + def debug(self, msg: str) -> None: + msg += f" <{self.entity_name()}>" + logger.debug(msg) + + def entity_name(self) -> str: + try: + handle = f"(#{self.get_handle()})" + except DXFValueError: + handle = "" + return self.dxftype() + handle + + def __copy__(self) -> ExtendedTags: + """Shallow copy.""" + + def copy(tag_lists): + return [tags.clone() for tags in tag_lists] + + clone = self.__class__() + clone.appdata = copy(self.appdata) + clone.subclasses = copy(self.subclasses) + clone.xdata = copy(self.xdata) + if self.embedded_objects is not None: + clone.embedded_objects = copy(self.embedded_objects) + return clone + + clone = __copy__ + + def __getitem__(self, index) -> Tags: + return self.noclass[index] + + @property + def noclass(self) -> Tags: + """Short cut to access first subclass.""" + return self.subclasses[0] + + def get_handle(self) -> str: + """Returns handle as hex string.""" + return self.noclass.get_handle() + + def dxftype(self) -> str: + """Returns DXF type as string like "LINE".""" + return self.noclass[0].value + + def replace_handle(self, handle: str) -> None: + """Replace the existing entity handle by a new value.""" + self.noclass.replace_handle(handle) + + def _setup(self, tags: Iterator[DXFTag]) -> None: + def is_end_of_class(tag): + # fast path + if tag.code not in { + SUBCLASS_MARKER, + EMBEDDED_OBJ_MARKER, + XDATA_MARKER, + }: + return False + else: + # really an embedded object + if ( + tag.code == EMBEDDED_OBJ_MARKER + and tag.value != EMBEDDED_OBJ_STR + ): + return False + else: + return True + + def collect_base_class() -> DXFTag: + """The base class contains AppData, but not XDATA and ends with + SUBCLASS_MARKER, XDATA_MARKER or EMBEDDED_OBJ_MARKER. + """ + # All subclasses begin with (100, subclass name) EXCEPT DIMASSOC + # has a subclass starting with: (1, AcDbOsnapPointRef) + # This special subclass is ignored by ezdxf, content is included in + # the preceding subclass: (100, AcDbDimAssoc) + # TEXT contains 2x the (100, AcDbText). + # + # Therefore it is not possible to use an (ordered) dict with + # the subclass name as key, but usual use case is access by + # numerical index. + + data = Tags() + try: + while True: + tag = next(tags) + if is_app_data_marker(tag): + app_data_pos = len(self.appdata) + data.append(DXFTag(tag.code, app_data_pos)) + collect_app_data(tag) + elif is_end_of_class(tag): + self.subclasses.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.subclasses.append(data) + return NONE_TAG + + def collect_subclass(starttag: DXFTag) -> DXFTag: + """A subclass does NOT contain AppData or XDATA, and ends with + SUBCLASS_MARKER, XDATA_MARKER or EMBEDDED_OBJ_MARKER. + """ + # All subclasses begin with (100, subclass name) + # for exceptions and rant see: collect_base_class() + + data = Tags([starttag]) + try: + while True: + tag = next(tags) + # removed app data collection in subclasses + if is_end_of_class(tag): + self.subclasses.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.subclasses.append(data) + return NONE_TAG + + def collect_app_data(starttag: DXFTag) -> None: + """AppData can't contain XDATA or subclasses. + + AppData can only appear in the first unnamed subclass + """ + data = Tags([starttag]) + # Alternative closing tag 'APPID}': + closing_strings = ("}", starttag.value[1:] + "}") + while True: + try: + tag = next(tags) + except StopIteration: + raise DXFStructureError( + "Missing closing (102, '}') tag in appdata structure." + ) + data.append(tag) + if (tag.code == APP_DATA_MARKER) and ( + tag.value in closing_strings + ): + break + # Other (102, ) tags are treated as usual DXF tags. + self.appdata.append(data) + + def collect_xdata(starttag: DXFTag) -> DXFTag: + """XDATA is always at the end of the entity even if an embedded + object is present and can not contain AppData or subclasses. + + """ + data = Tags([starttag]) + try: + while True: + tag = next(tags) + if tag.code == XDATA_MARKER: + self.xdata.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.xdata.append(data) + return NONE_TAG + + def collect_embedded_object(starttag: DXFTag) -> DXFTag: + """Since AutoCAD 2018, DXF entities can contain embedded objects + starting with a (101, 'Embedded Object') tag. + + All embedded object data is collected in a simple Tags() object, + no subclass app data or XDATA processing is done. + ezdxf does not use or modify the embedded object data, the data is + just stored and written out as it is. + + self.embedded_objects = [ + 1. embedded object as Tags(), + 2. embedded object as Tags(), + ... + ] + + Support for multiple embedded objects is maybe future proof, but + for now only one embedded object per entity is used. + + """ + if self.embedded_objects is None: + self.embedded_objects = list() + data = Tags([starttag]) + try: + while True: + tag = next(tags) + if ( + is_embedded_object_marker(tag) + or tag.code == XDATA_MARKER + ): + # Another embedded object found: maybe in the future + # DXF entities can contain more than one embedded + # object. + self.embedded_objects.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.embedded_objects.append(data) + return NONE_TAG + + # Preceding tags without a subclass + tag = collect_base_class() + while tag.code == SUBCLASS_MARKER: + tag = collect_subclass(tag) + + while is_embedded_object_marker(tag): + tag = collect_embedded_object(tag) + + # XDATA appear after an embedded object + while tag.code == XDATA_MARKER: + tag = collect_xdata(tag) + + if tag is not NONE_TAG: + raise DXFStructureError( + "Unexpected tag '%r' at end of entity." % tag + ) + + def __iter__(self) -> Iterator[DXFTag]: + for subclass in self.subclasses: + for tag in subclass: + if tag.code == APP_DATA_MARKER and isinstance(tag.value, int): + yield from self.appdata[tag.value] + else: + yield tag + yield from chain.from_iterable(self.xdata) + if self.embedded_objects is not None: + yield from chain.from_iterable(self.embedded_objects) + + def get_subclass(self, name: str, pos: int = 0) -> Tags: + """Get subclass `name`. + + Args: + name: subclass name as string like "AcDbEntity" + pos: start searching at subclass `pos`. + + """ + for index, subclass in enumerate(self.subclasses): + try: + if (index >= pos) and (subclass[0].value == name): + return subclass + except IndexError: + pass # subclass[0]: ignore empty subclasses + + raise DXFKeyError(f'Subclass "{name}" does not exist.') + + def has_subclass(self, name: str) -> bool: + for subclass in self.subclasses: + try: + if subclass[0].value == name: + return True + except IndexError: + pass # ignore empty subclasses + return False + + def has_xdata(self, appid: str) -> bool: + """``True`` if has XDATA for `appid`.""" + return any(xdata[0].value == appid for xdata in self.xdata) + + def get_xdata(self, appid: str) -> Tags: + """Returns XDATA for `appid` as :class:`Tags`.""" + for xdata in self.xdata: + if xdata[0].value == appid: + return xdata + raise DXFValueError(f'No extended data for APPID "{appid}".') + + def set_xdata(self, appid: str, tags: IterableTags) -> None: + """Set `tags` as XDATA for `appid`.""" + xdata = self.get_xdata(appid) + xdata[1:] = tuples_to_tags(tags) + + def new_xdata( + self, appid: str, tags: Optional[IterableTags] = None + ) -> Tags: + """Append a new XDATA block. + + Assumes that no XDATA block with the same `appid` already exist:: + + try: + xdata = tags.get_xdata('EZDXF') + except ValueError: + xdata = tags.new_xdata('EZDXF') + """ + xtags = Tags([DXFTag(XDATA_MARKER, appid)]) + if tags is not None: + xtags.extend(tuples_to_tags(tags)) + self.xdata.append(xtags) + return xtags + + def has_app_data(self, appid: str) -> bool: + """``True`` if has application defined data for `appid`.""" + return any(appdata[0].value == appid for appdata in self.appdata) + + def get_app_data(self, appid: str) -> Tags: + """Returns application defined data for `appid` as :class:`Tags` + including marker tags.""" + for appdata in self.appdata: + if appdata[0].value == appid: + return appdata + raise DXFValueError( + f'Application defined group "{appid}" does not exist.' + ) + + def get_app_data_content(self, appid: str) -> Tags: + """Returns application defined data for `appid` as :class:`Tags` + without first and last marker tag. + """ + return Tags(self.get_app_data(appid)[1:-1]) + + def set_app_data_content(self, appid: str, tags: IterableTags) -> None: + """Set application defined data for `appid` for already exiting data.""" + app_data = self.get_app_data(appid) + app_data[1:-1] = tuples_to_tags(tags) + + def new_app_data( + self, + appid: str, + tags: Optional[IterableTags] = None, + subclass_name: Optional[str] = None, + ) -> Tags: + """Append a new application defined data to subclass `subclass_name`. + + Assumes that no app data block with the same `appid` already exist:: + + try: + app_data = tags.get_app_data('{ACAD_REACTORS', tags) + except ValueError: + app_data = tags.new_app_data('{ACAD_REACTORS', tags) + + """ + if not appid.startswith("{"): + raise DXFValueError("Appid has to start with '{'.") + + app_tags = Tags( + [ + DXFTag(APP_DATA_MARKER, appid), + DXFTag(APP_DATA_MARKER, "}"), + ] + ) + if tags is not None: + app_tags[1:1] = tuples_to_tags(tags) + + if subclass_name is None: + subclass = self.noclass + else: + # raises KeyError, if not exist + subclass = self.get_subclass(subclass_name, 1) + app_data_pos = len(self.appdata) + subclass.append(DXFTag(APP_DATA_MARKER, app_data_pos)) + self.appdata.append(app_tags) + return app_tags + + @classmethod + def from_text(cls, text: str, legacy=False) -> ExtendedTags: + """Create :class:`ExtendedTags` from DXF text.""" + return cls(internal_tag_compiler(text), legacy=legacy) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/fileindex.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/fileindex.py new file mode 100644 index 0000000..d60abd4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/fileindex.py @@ -0,0 +1,158 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, NamedTuple, BinaryIO + +from .const import DXFStructureError +from ezdxf.tools.codepage import toencoding + + +class IndexEntry(NamedTuple): + code: int + value: str + location: int + line: int + + +class FileStructure: + """DXF file structure representation stored as file locations. + + Store all DXF structure tags and some other tags as :class:`IndexEntry` + tuples: + + - code: group code + - value: tag value as string + - location: file location as int + - line: line number as int + + Indexed tags: + + - structure tags, every tag with group code 0 + - section names, (2, name) tag following a (0, SECTION) tag + - entity handle tags with group code 5, the DIMSTYLE handle group code + 105 is also stored as group code 5 + + """ + + def __init__(self, filename: str): + # stores the file system name of the DXF document. + self.filename: str = filename + # DXF version if header variable $ACADVER is present, default is DXFR12 + self.version: str = "AC1009" + # Python encoding required to read the DXF document as text file. + self.encoding: str = "cp1252" + self.index: list[IndexEntry] = [] + + def print(self) -> None: + print(f"Filename: {self.filename}") + print(f"DXF Version: {self.version}") + print(f"encoding: {self.encoding}") + for entry in self.index: + print(f"Line: {entry.line} - ({entry.code}, {entry.value})") + + def get(self, code: int, value: str, start: int = 0) -> int: + """Returns index of first entry matching `code` and `value`.""" + self_index = self.index + index: int = start + count: int = len(self_index) + while index < count: + entry = self_index[index] + if entry.code == code and entry.value == value: + return index + index += 1 + raise ValueError(f"No entry for tag ({code}, {value}) found.") + + def fetchall( + self, code: int, value: str, start: int = 0 + ) -> Iterable[IndexEntry]: + """Iterate over all specified entities. + + e.g. fetchall(0, 'LINE') returns an iterator for all LINE entities. + + """ + for entry in self.index[start:]: + if entry.code == code and entry.value == value: + yield entry + + +def load(filename: str) -> FileStructure: + """Load DXF file structure for file `filename`, the file has to be seekable. + + Args: + filename: file system file name + + Raises: + DXFStructureError: Invalid or incomplete DXF file. + + """ + file_structure = FileStructure(filename) + file: BinaryIO = open(filename, mode="rb") + line: int = 1 + eof: bool = False + header: bool = False + index: list[IndexEntry] = [] + prev_code: int = -1 + prev_value: bytes = b"" + structure = None # the current structure tag: 'SECTION', 'LINE', ... + + def load_tag() -> tuple[int, bytes]: + nonlocal line + try: + code = int(file.readline()) + except ValueError: + raise DXFStructureError(f"Invalid group code in line {line}") + + if code < 0 or code > 1071: + raise DXFStructureError(f"Invalid group code {code} in line {line}") + value = file.readline().rstrip(b"\r\n") + line += 2 + return code, value + + def load_header_var() -> str: + _, value = load_tag() + return value.decode() + + while not eof: + location = file.tell() + tag_line = line + try: + code, value = load_tag() + if header and code == 9: + if value == b"$ACADVER": + file_structure.version = load_header_var() + elif value == b"$DWGCODEPAGE": + file_structure.encoding = toencoding(load_header_var()) + continue + except IOError: + break + + if code == 0: + # All structure tags have group code == 0, store file location + structure = value + index.append(IndexEntry(0, value.decode(), location, tag_line)) + eof = value == b"EOF" + + elif code == 2 and prev_code == 0 and prev_value == b"SECTION": + # Section name is the tag (2, name) following the (0, SECTION) tag. + header = value == b"HEADER" + index.append(IndexEntry(2, value.decode(), location, tag_line)) + + elif code == 5 and structure != b"DIMSTYLE": + # Entity handles have always group code 5. + index.append(IndexEntry(5, value.decode(), location, tag_line)) + + elif code == 105 and structure == b"DIMSTYLE": + # Except the DIMSTYLE table entry has group code 105. + index.append(IndexEntry(5, value.decode(), location, tag_line)) + + prev_code = code + prev_value = value + + file.close() + if not eof: + raise DXFStructureError(f"Unexpected end of file.") + + if file_structure.version >= "AC1021": # R2007 and later + file_structure.encoding = "utf-8" + file_structure.index = index + return file_structure diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/hdrvars.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/hdrvars.py new file mode 100644 index 0000000..b0a9d49 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/hdrvars.py @@ -0,0 +1,26 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +from typing import Sequence, Union, Callable, Any, NamedTuple, Optional +from .types import DXFVertex, DXFTag, cast_tag_value + + +def SingleValue(value: Union[str, float], code: int = 1) -> DXFTag: + return DXFTag(code, cast_tag_value(code, value)) + + +def Point2D(value: Sequence[float]) -> DXFVertex: + return DXFVertex(10, (value[0], value[1])) + + +def Point3D(value: Sequence[float]) -> DXFVertex: + return DXFVertex(10, (value[0], value[1], value[2])) + + +class HeaderVarDef(NamedTuple): + name: str + code: int + factory: Callable[[Any], Any] + mindxf: str + maxdxf: str + priority: int + default: Optional[Any] = None diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/loader.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/loader.py new file mode 100644 index 0000000..3b87822 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/loader.py @@ -0,0 +1,156 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import logging +from typing import Iterable, TYPE_CHECKING, Optional +from collections import OrderedDict + +from .const import DXFStructureError +from .tags import group_tags, DXFTag, Tags +from .extendedtags import ExtendedTags +from ezdxf.entities import factory + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity + from ezdxf.eztypes import SectionDict + +logger = logging.getLogger("ezdxf") + + +def load_dxf_structure( + tagger: Iterable[DXFTag], ignore_missing_eof: bool = False +) -> SectionDict: + """Divide input tag stream from tagger into DXF structure entities. + Each DXF structure entity starts with a DXF structure (0, ...) tag, + and ends before the next DXF structure tag. + + Generated structure: + + each entity is a Tags() object + + { + # 1. section, HEADER section consist only of one entity + 'HEADER': [entity], + 'CLASSES': [entity, entity, ...], # 2. section + 'TABLES': [entity, entity, ...], # 3. section + ... + 'OBJECTS': [entity, entity, ...], + } + + { + # HEADER section consist only of one entity + 'HEADER': [(0, 'SECTION'), (2, 'HEADER'), .... ], + 'CLASSES': [ + [(0, 'SECTION'), (2, 'CLASSES')], + [(0, 'CLASS'), ...], + [(0, 'CLASS'), ...] + ], + 'TABLES': [ + [(0, 'SECTION'), (2, 'TABLES')], + [(0, 'TABLE'), (2, 'VPORT')], + [(0, 'VPORT'), ...], + ... , + [(0, 'ENDTAB')] + ], + ... + 'OBJECTS': [ + [(0, 'SECTION'), (2, 'OBJECTS')], + ... , + ] + } + + Args: + tagger: generates DXFTag() entities from input data + ignore_missing_eof: raises DXFStructureError() if False and EOF tag is + not present, set to True only in tests + + Returns: + dict of sections, each section is a list of DXF structure entities + as Tags() objects + + """ + + def inside_section() -> bool: + if len(section): + return section[0][0] == (0, "SECTION") # first entity, first tag + return False + + def outside_section() -> bool: + if len(section): + return section[0][0] != (0, "SECTION") # first entity, first tag + return True + + sections: SectionDict = OrderedDict() + section: list[Tags] = [] + eof = False + # The structure checking here should not be changed, ezdxf expect a valid + # DXF file, to load messy DXF files exist an (future) add-on + # called 'recover'. + + for entity in group_tags(tagger): + tag = entity[0] + if tag == (0, "SECTION"): + if inside_section(): + raise DXFStructureError("DXFStructureError: missing ENDSEC tag.") + if len(section): + logger.warning( + "DXF Structure Warning: found tags outside a SECTION, " + "ignored by ezdxf." + ) + section = [entity] + elif tag == (0, "ENDSEC"): + # ENDSEC tag is not collected. + if outside_section(): + raise DXFStructureError( + "DXFStructureError: found ENDSEC tag without previous " + "SECTION tag." + ) + section_header = section[0] + + if len(section_header) < 2 or section_header[1].code != 2: + raise DXFStructureError( + "DXFStructureError: missing required section NAME tag " + "(2, name) at start of section." + ) + name_tag = section_header[1] + sections[name_tag.value] = section # type: ignore + # Collect tags outside of sections, but ignore it. + section = [] + elif tag == (0, "EOF"): + # EOF tag is not collected. + if eof: + logger.warning("DXF Structure Warning: found more than one EOF tags.") + eof = True + else: + section.append(entity) + if inside_section(): + raise DXFStructureError("DXFStructureError: missing ENDSEC tag.") + if not eof and not ignore_missing_eof: + raise DXFStructureError("DXFStructureError: missing EOF tag.") + return sections + + +def load_dxf_entities( + entities: Iterable[Tags], doc: Optional[Drawing] = None +) -> Iterable[DXFEntity]: + for entity in entities: + yield factory.load(ExtendedTags(entity), doc) + + +def load_and_bind_dxf_content(sections: dict, doc: Drawing) -> None: + # HEADER has no database entries. + db = doc.entitydb + for name in ["TABLES", "CLASSES", "ENTITIES", "BLOCKS", "OBJECTS"]: + if name in sections: + section = sections[name] + for index, entity in enumerate(load_dxf_entities(section, doc)): + handle = entity.dxf.get("handle") + if handle and handle in db: + logger.warning( + f"Found non-unique entity handle #{handle}, data validation is required." + ) + # Replace Tags() by DXFEntity() objects + section[index] = entity + # Bind entities to the DXF document: + factory.bind(entity, doc) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/packedtags.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/packedtags.py new file mode 100644 index 0000000..8e7c1d7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/packedtags.py @@ -0,0 +1,208 @@ +# Copyright (c) 2018-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, MutableSequence, Sequence, Iterator, Optional +from typing_extensions import overload +from array import array +import numpy as np + +from ezdxf.lldxf.tagwriter import AbstractTagWriter +from ezdxf.math import Matrix44 +from ezdxf.tools.indexing import Index + +from .tags import Tags +from .types import DXFTag + + +class TagList: + """Store data in a standard Python ``list``.""" + + __slots__ = ("values",) + + def __init__(self, data: Optional[Iterable] = None): + self.values: MutableSequence = list(data or []) + + def clone(self) -> TagList: + """Returns a deep copy.""" + return self.__class__(data=self.values) + + @classmethod + def from_tags(cls, tags: Tags, code: int) -> TagList: + """ + Setup list from iterable tags. + + Args: + tags: tag collection as :class:`~ezdxf.lldxf.tags.Tags` + code: group code to collect + + """ + return cls(data=(tag.value for tag in tags if tag.code == code)) + + def clear(self) -> None: + """Delete all data values.""" + del self.values[:] + + +class TagArray(TagList): + """Store data in an :class:`array.array`. Array type is defined by class + variable ``DTYPE``. + """ + + __slots__ = ("values",) + # Defines the data type of array.array() + DTYPE = "i" + + def __init__(self, data: Optional[Iterable] = None): + self.values: array = array(self.DTYPE, data or []) + + def set_values(self, values: Iterable) -> None: + """Replace data by `values`.""" + self.values[:] = array(self.DTYPE, values) + + +class VertexArray: + """Store vertices in a ``numpy.ndarray``. Vertex size is defined by class variable + ``VERTEX_SIZE``. + """ + + VERTEX_SIZE = 3 + __slots__ = ("values",) + + def __init__(self, data: Iterable[Sequence[float]] | None = None): + size = self.VERTEX_SIZE + if data: + values = np.array(data, dtype=np.float64) + if values.shape[1] != size: + raise TypeError( + f"invalid data shape, expected (n, {size}), got {values.shape}" + ) + else: + values = np.ndarray((0, size), dtype=np.float64) + self.values = values + + def __len__(self) -> int: + """Count of vertices.""" + return len(self.values) + + @overload + def __getitem__(self, index: int) -> Sequence[float]: ... + + @overload + def __getitem__(self, index: slice) -> Sequence[Sequence[float]]: ... + + def __getitem__(self, index: int | slice): + """Get vertex at `index`, extended slicing supported.""" + return self.values[index] + + def __setitem__(self, index: int, point: Sequence[float]) -> None: + """Set vertex `point` at `index`, extended slicing not supported.""" + if isinstance(index, slice): + raise TypeError("slicing not supported") + self._set_point(self._index(index), point) + + def __delitem__(self, index: int | slice) -> None: + """Delete vertex at `index`, extended slicing supported.""" + if isinstance(index, slice): + self._del_points(self._slicing(index)) + else: + self._del_points((index,)) + + def __str__(self) -> str: + """String representation.""" + return str(self.values) + + def __iter__(self) -> Iterator[Sequence[float]]: + """Returns iterable of vertices.""" + return iter(self.values) + + def insert(self, pos: int, point: Sequence[float]): + """Insert `point` in front of vertex at index `pos`. + + Args: + pos: insert position + point: point as tuple + + """ + size = self.VERTEX_SIZE + if len(point) != size: + raise ValueError(f"point requires exact {size} components.") + + values = self.values + if len(values) == 0: + self.extend((point,)) + ins_point = np.array((point,), dtype=np.float64) + self.values = np.concatenate((values[0:pos], ins_point, values[pos:])) + + def clone(self) -> VertexArray: + """Returns a deep copy.""" + return self.__class__(data=self.values) + + @classmethod + def from_tags(cls, tags: Iterable[DXFTag], code: int = 10) -> VertexArray: + """Setup point array from iterable tags. + + Args: + tags: iterable of :class:`~ezdxf.lldxf.types.DXFVertex` + code: group code to collect + + """ + vertices = [tag.value for tag in tags if tag.code == code] + return cls(data=vertices) + + def _index(self, item) -> int: + return Index(self).index(item, error=IndexError) + + def _slicing(self, index) -> Iterable[int]: + return Index(self).slicing(index) + + def _set_point(self, index: int, point: Sequence[float]): + size = self.VERTEX_SIZE + if len(point) != size: + raise ValueError(f"point requires exact {size} components.") + self.values[index] = point # type: ignore + + def _del_points(self, indices: Iterable[int]) -> None: + del_flags = set(indices) + survivors = np.array( + [v for i, v in enumerate(self.values) if i not in del_flags], np.float64 + ) + self.values = survivors + + def export_dxf(self, tagwriter: AbstractTagWriter, code=10): + for vertex in self.values: + tagwriter.write_tag2(code, vertex[0]) + tagwriter.write_tag2(code + 10, vertex[1]) + if len(vertex) > 2: + tagwriter.write_tag2(code + 20, vertex[2]) + + def append(self, point: Sequence[float]) -> None: + """Append `point`.""" + if len(point) != self.VERTEX_SIZE: + raise ValueError(f"point requires exact {self.VERTEX_SIZE} components.") + self.extend((point,)) + + def extend(self, points: Iterable[Sequence[float]]) -> None: + """Extend array by `points`.""" + vertices = np.array(points, np.float64) + if vertices.shape[1] != self.VERTEX_SIZE: + raise ValueError(f"points require exact {self.VERTEX_SIZE} components.") + if len(self.values) == 0: + self.values = vertices + else: + self.values = np.concatenate((self.values, vertices)) + + def clear(self) -> None: + """Delete all vertices.""" + self.values = np.ndarray((0, self.VERTEX_SIZE), dtype=np.float64) + + def set(self, points: Iterable[Sequence[float]]) -> None: + """Replace all vertices by `points`.""" + vertices = np.array(points, np.float64) + if vertices.shape[1] != self.VERTEX_SIZE: + raise ValueError(f"points require exact {self.VERTEX_SIZE} components.") + self.values = vertices + + def transform(self, m: Matrix44) -> None: + """Transform vertices inplace by transformation matrix `m`.""" + if self.VERTEX_SIZE in (2, 3): + m.transform_array_inplace(self.values, self.VERTEX_SIZE) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/repair.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/repair.py new file mode 100644 index 0000000..4f00cc0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/repair.py @@ -0,0 +1,212 @@ +# Copyright (c) 2016-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Optional, + TYPE_CHECKING, + Sequence, + Any, + Iterator, +) +from functools import partial +import logging +from .tags import DXFTag +from .types import POINT_CODES, NONE_TAG, VALID_XDATA_GROUP_CODES + +if TYPE_CHECKING: + from ezdxf.eztypes import Tags + +logger = logging.getLogger("ezdxf") + + +def tag_reorder_layer(tagger: Iterable[DXFTag]) -> Iterator[DXFTag]: + """Reorder coordinates of legacy DXF Entities, for now only LINE. + + Input Raw tag filter. + + Args: + tagger: low level tagger + + """ + + collector: Optional[list] = None + for tag in tagger: + if tag.code == 0: + if collector is not None: + # stop collecting if inside a supported entity + entity = _s(collector[0].value) + yield from COORDINATE_FIXING_TOOLBOX[entity](collector) # type: ignore + collector = None + + if _s(tag.value) in COORDINATE_FIXING_TOOLBOX: + collector = [tag] + # do not yield collected tag yet + tag = NONE_TAG + else: # tag.code != 0 + if collector is not None: + collector.append(tag) + # do not yield collected tag yet + tag = NONE_TAG + if tag is not NONE_TAG: + yield tag + + +# invalid point codes if not part of a point started with 1010, 1011, 1012, 1013 +INVALID_Y_CODES = {code + 10 for code in POINT_CODES} +INVALID_Z_CODES = {code + 20 for code in POINT_CODES} +# A single group code 38 is an elevation tag (e.g. LWPOLYLINE) +# Is (18, 28, 38?) is a valid point code? +INVALID_Z_CODES.remove(38) +INVALID_CODES = INVALID_Y_CODES | INVALID_Z_CODES +X_CODES = POINT_CODES + + +def filter_invalid_point_codes(tagger: Iterable[DXFTag]) -> Iterable[DXFTag]: + """Filter invalid and misplaced point group codes. + + - removes x-axis without following y-axis + - removes y- and z-axis without leading x-axis + + Args: + tagger: low level tagger + + """ + + def entity() -> str: + if handle_tag: + return f"in entity #{_s(handle_tag[1])}" + else: + return "" + + expected_code = -1 + z_code = 0 + point: list[Any] = [] + handle_tag = None + for tag in tagger: + code = tag[0] + if code == 5: # ignore DIMSTYLE entity + handle_tag = tag + if point and code != expected_code: + # at least x, y axis is required else ignore point + if len(point) > 1: + yield from point + else: + logger.info( + f"remove misplaced x-axis tag: {str(point[0])}" + entity() + ) + point.clear() + + if code in X_CODES: + expected_code = code + 10 + z_code = code + 20 + point.append(tag) + elif code == expected_code: + point.append(tag) + expected_code += 10 + if expected_code > z_code: + expected_code = -1 + else: + # ignore point group codes without leading x-axis + if code not in INVALID_CODES: + yield tag + else: + axis = "y-axis" if code in INVALID_Y_CODES else "z-axis" + logger.info( + f"remove misplaced {axis} tag: {str(tag)}" + entity() + ) + + if len(point) == 1: + logger.info(f"remove misplaced x-axis tag: {str(point[0])}" + entity()) + elif len(point) > 1: + yield from point + + +def fix_coordinate_order(tags: Tags, codes: Sequence[int] = (10, 11)): + def extend_codes(): + for code in codes: + yield code # x tag + yield code + 10 # y tag + yield code + 20 # z tag + + def get_coords(code: int): + # if x or y coordinate is missing, it is a DXFStructureError + # but here is not the location to validate the DXF structure + try: + yield coordinates[code] + except KeyError: + pass + try: + yield coordinates[code + 10] + except KeyError: + pass + try: + yield coordinates[code + 20] + except KeyError: + pass + + coordinate_codes = frozenset(extend_codes()) + coordinates = {} + remaining_tags = [] + insert_pos = None + for tag in tags: + # separate tags + if tag.code in coordinate_codes: + coordinates[tag.code] = tag + if insert_pos is None: + insert_pos = tags.index(tag) + else: + remaining_tags.append(tag) + + if len(coordinates) == 0: + # no coordinates found, this is probably a DXFStructureError, + # but here is not the location to validate the DXF structure, + # just do nothing. + return tags + + ordered_coords = [] + for code in codes: + ordered_coords.extend(get_coords(code)) + remaining_tags[insert_pos:insert_pos] = ordered_coords + return remaining_tags + + +COORDINATE_FIXING_TOOLBOX = { + "LINE": partial(fix_coordinate_order, codes=(10, 11)), +} + + +def filter_invalid_xdata_group_codes( + tags: Iterable[DXFTag], +) -> Iterator[DXFTag]: + return (tag for tag in tags if tag.code in VALID_XDATA_GROUP_CODES) + + +def filter_invalid_handles(tags: Iterable[DXFTag]) -> Iterator[DXFTag]: + line = -1 + handle_code = 5 + structure_tag = "" + for tag in tags: + line += 2 + if tag.code == 0: + structure_tag = tag.value + if _s(tag.value) == "DIMSTYLE": + handle_code = 105 + else: + handle_code = 5 + elif tag.code == handle_code: + try: + int(tag.value, 16) + except ValueError: + logger.warning( + f'skipped invalid handle "{_s(tag.value)}" in ' + f'DXF entity "{_s(structure_tag)}" near line {line}' + ) + continue + yield tag + + +def _s(b) -> str: + if isinstance(b, bytes): + return b.decode(encoding="ascii", errors="ignore") + return b diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagger.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagger.py new file mode 100644 index 0000000..3138a8d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagger.py @@ -0,0 +1,384 @@ +# Copyright (c) 2016-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, TextIO, Iterator, Any, Optional, Sequence +import struct +from .types import ( + DXFTag, + DXFVertex, + DXFBinaryTag, + BYTES, + INT16, + INT32, + INT64, + DOUBLE, + POINT_CODES, + TYPE_TABLE, + BINARY_DATA, + is_point_code, +) +from .const import DXFStructureError +from ezdxf.tools.codepage import toencoding + + +def internal_tag_compiler(s: str) -> Iterable[DXFTag]: + """Yields DXFTag() from trusted (internal) source - relies on + well-formed and error free DXF format. Does not skip comment + tags (group code == 999). + + Args: + s: DXF unicode string, lines separated by universal line endings '\n' + + """ + assert isinstance(s, str) + lines: list[str] = s.split("\n") + # split() creates an extra item, if s ends with '\n', + # but lines[-1] can be an empty string!!! + if s.endswith("\n"): + lines.pop() + pos: int = 0 + count: int = len(lines) + point: tuple[float, ...] + while pos < count: + code = int(lines[pos]) + value = lines[pos + 1] + pos += 2 + if code in POINT_CODES: + # next tag; y-axis is mandatory - internal_tag_compiler relies on + # well formed DXF strings: + y = lines[pos + 1] + pos += 2 + if pos < count: + # next tag; z coordinate just for 3d points + z_code = int(lines[pos]) + z = lines[pos + 1] + else: # if string s ends with a 2d point + z_code, z = -1, "" + if z_code == code + 20: # 3d point + pos += 2 + point = (float(value), float(y), float(z)) + else: # 2d point + point = (float(value), float(y)) + yield DXFVertex(code, point) # 2d/3d point + elif code in BINARY_DATA: + yield DXFBinaryTag.from_string(code, value) + else: # single value tag: int, float or string + yield DXFTag(code, TYPE_TABLE.get(code, str)(value)) + + +# No performance advantage by processing binary data! +# +# Profiling result for just reading DXF data (profiling/raw_data_reading.py): +# Loading the example file "torso_uniform.dxf" (50MB) by readline() from a +# text stream with decoding takes ~0.65 seconds longer than loading the same +# file as binary data. +# +# Text :1.30s vs Binary data: 0.65s) +# This is twice the time, but without any processing, ascii_tags_loader() takes +# ~5.3 seconds to process this file. +# +# And this performance advantage is more than lost by the necessary decoding +# of the binary data afterwards, even much fewer strings have to be decoded, +# because numeric data like group codes and vertices doesn't need to be +# decoded. +# +# I assume the runtime overhead for calling Python functions is the reason. + + +def ascii_tags_loader(stream: TextIO, skip_comments: bool = True) -> Iterator[DXFTag]: + """Yields :class:``DXFTag`` objects from a text `stream` (untrusted + external source) and does not optimize coordinates. Comment tags (group + code == 999) will be skipped if argument `skip_comments` is `True`. + ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always an + unicode string without a trailing '\n'. + Works with file system streams and :class:`StringIO` streams, only required + feature is the :meth:`readline` method. + + Args: + stream: text stream + skip_comments: skip comment tags (group code == 999) if `True` + + Raises: + DXFStructureError: Found invalid group code. + + """ + line: int = 1 + eof = False + yield_comments = not skip_comments + # localize attributes + readline = stream.readline + _DXFTag = DXFTag + # readline() returns an empty string at EOF, not exception will be raised! + while not eof: + code: str = readline() + if code: # empty string indicates EOF + try: + group_code = int(code) + except ValueError: + raise DXFStructureError(f'Invalid group code "{code}" at line {line}.') + else: + return + + value: str = readline() + if value: # empty string indicates EOF + value = value.rstrip("\n") + if group_code == 0 and value == "EOF": + eof = True # yield EOF tag but ignore any data beyond EOF + if group_code != 999 or yield_comments: + yield _DXFTag(group_code, value) + line += 2 + else: + return + + +def binary_tags_loader( + data: bytes, errors: str = "surrogateescape" +) -> Iterator[DXFTag]: + """Yields :class:`DXFTag` or :class:`DXFBinaryTag` objects from binary DXF + `data` (untrusted external source) and does not optimize coordinates. + ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is either an + unicode string,``float``, ``int`` or ``bytes`` for binary chunks. + + Args: + data: binary DXF data + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD: "\ufffd" + - "strict" to raise an :class:`UnicodeDecodeError` + + Raises: + DXFStructureError: Not a binary DXF file + DXFVersionError: Unsupported DXF version + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + if data[:22] != b"AutoCAD Binary DXF\r\n\x1a\x00": + raise DXFStructureError("Not a binary DXF data structure.") + + def scan_params(): + dxfversion = "AC1009" + encoding = "cp1252" + try: + # Limit search to first 1024 bytes - an arbitrary number + # start index for 1-byte group code + start = data.index(b"$ACADVER", 22, 1024) + 10 + except ValueError: + pass # HEADER var $ACADVER not present + else: + if data[start] != 65: # not 'A' = 2-byte group code + start += 1 + dxfversion = data[start : start + 6].decode() + + if dxfversion >= "AC1021": + encoding = "utf8" + else: + try: + # Limit search to first 1024 bytes - an arbitrary number + # start index for 1-byte group code + start = data.index(b"$DWGCODEPAGE", 22, 1024) + 14 + except ValueError: + pass # HEADER var $DWGCODEPAGE not present + else: # name schema is 'ANSI_xxxx' + if data[start] != 65: # not 'A' = 2-byte group code + start += 1 + end = start + 5 + while data[end] != 0: + end += 1 + codepage = data[start:end].decode() + encoding = toencoding(codepage) + + return encoding, dxfversion + + encoding, dxfversion = scan_params() + r12 = dxfversion <= "AC1009" + index: int = 22 + data_length: int = len(data) + unpack = struct.unpack_from + value: Any + + while index < data_length: + # decode next group code + code = data[index] + if r12: + if code == 255: # extended data + code = (data[index + 2] << 8) | data[index + 1] + index += 3 + else: + index += 1 + else: # 2-byte group code + code = (data[index + 1] << 8) | code + index += 2 + + # decode next value + if code in BINARY_DATA: + length = data[index] + index += 1 + value = data[index : index + length] + index += length + yield DXFBinaryTag(code, value) + else: + if code in INT16: + value = unpack(" Iterator[DXFTag]: + """Compiles DXF tag values imported by ascii_tags_loader() into Python + types. + + Raises DXFStructureError() for invalid float values and invalid coordinate + values. + + Expects DXF coordinates written in x, y[, z] order, this is not required by + the DXF standard, but nearly all CAD applications write DXF coordinates that + (sane) way, there are older CAD applications (namely an older QCAD version) + that write LINE coordinates in x1, x2, y1, y2 order, which does not work + with tag_compiler(). For this cases use tag_reorder_layer() from the repair + module to reorder the LINE coordinates:: + + tag_compiler(tag_reorder_layer(ascii_tags_loader(stream))) + + Args: + tags: DXF tag generator e.g. ascii_tags_loader() + + Raises: + DXFStructureError: Found invalid DXF tag or unexpected coordinate order. + + """ + + def error_msg(tag): + return ( + f'Invalid tag (code={tag.code}, value="{tag.value}") ' f"near line: {line}." + ) + + undo_tag: Optional[DXFTag] = None + line: int = 0 + point: tuple[float, ...] + # Silencing mypy by "type: ignore", because this is a work horse function + # and should not be slowed down by isinstance(...) checks or unnecessary + # cast() calls + while True: + try: + if undo_tag is not None: + x = undo_tag + undo_tag = None + else: + x = next(tags) + line += 2 + code: int = x.code + if code in POINT_CODES: + # y-axis is mandatory + y = next(tags) + line += 2 + if y.code != code + 10: # like 20 for base x-code 10 + raise DXFStructureError( + f"Missing required y coordinate near line: {line}." + ) + # z-axis just for 3d points + z = next(tags) + line += 2 + try: + # z-axis like (30, 0.0) for base x-code 10 + if z.code == code + 20: + point = (float(x.value), float(y.value), float(z.value)) + else: + point = (float(x.value), float(y.value)) + undo_tag = z + except ValueError: + raise DXFStructureError( + f"Invalid floating point values near line: {line}." + ) + yield DXFVertex(code, point) + elif code in BINARY_DATA: + # Maybe pre compiled in low level tagger (binary DXF): + if isinstance(x, DXFBinaryTag): + tag = x + else: + try: + tag = DXFBinaryTag.from_string(code, x.value) + except ValueError: + raise DXFStructureError( + f"Invalid binary data near line: {line}." + ) + yield tag + else: # Just a single tag + try: + # Fast path! + if code == 0: + value = x.value.strip() + else: + value = x.value + yield DXFTag(code, TYPE_TABLE.get(code, str)(value)) + except ValueError: + # ProE stores int values as floats :(( + if TYPE_TABLE.get(code, str) is int: + try: + yield DXFTag(code, int(float(x.value))) + except ValueError: + raise DXFStructureError(error_msg(x)) + else: + raise DXFStructureError(error_msg(x)) + except StopIteration: + return + + +def json_tag_loader( + data: Sequence[Any], skip_comments: bool = True +) -> Iterator[DXFTag]: + """Yields :class:``DXFTag`` objects from a JSON data structure (untrusted + external source) and does not optimize coordinates. Comment tags (group + code == 999) will be skipped if argument `skip_comments` is `True`. + ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always an + unicode string without a trailing ``\n``. + + The expected JSON format is a list of [group-code, value] pairs where each pair is + a DXF tag. The `compact` and the `verbose` format is supported. + + Args: + data: JSON data structure as a sequence of [group-code, value] pairs + skip_comments: skip comment tags (group code == 999) if `True` + + Raises: + DXFStructureError: Found invalid group code or value type. + + """ + yield_comments = not skip_comments + _DXFTag = DXFTag + for tag_number, (code, value) in enumerate(data): + if not isinstance(code, int): + raise DXFStructureError( + f'Invalid group code "{code}" in tag number {tag_number}.' + ) + if is_point_code(code) and isinstance(value, (list, tuple)): + # yield coordinates as single tags + for index, coordinate in enumerate(value): + yield _DXFTag(code + index * 10, coordinate) + continue + if code != 999 or yield_comments: + yield _DXFTag(code, value) + if code == 0 and value == "EOF": + return diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tags.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tags.py new file mode 100644 index 0000000..65b95f0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tags.py @@ -0,0 +1,458 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +""" +Tags +---- + +A list of :class:`~ezdxf.lldxf.types.DXFTag`, inherits from Python standard list. +Unlike the statement in the DXF Reference "Do not write programs that rely on +the order given here", tag order is sometimes essential and some group codes +may appear multiples times in one entity. At the worst case +(:class:`~ezdxf.entities.material.Material`: normal map shares group codes with +diffuse map) using same group codes with different meanings. + +""" +from __future__ import annotations +from typing import Iterable, Iterator, Any, Optional + +from .const import DXFStructureError, DXFValueError, STRUCTURE_MARKER +from .types import DXFTag, EMBEDDED_OBJ_MARKER, EMBEDDED_OBJ_STR, dxftag +from .tagger import internal_tag_compiler +from . import types + +COMMENT_CODE = 999 + + +class Tags(list): + """Collection of :class:`~ezdxf.lldxf.types.DXFTag` as flat list. + Low level tag container, only required for advanced stuff. + + """ + + @classmethod + def from_text(cls, text: str) -> Tags: + """Constructor from DXF string.""" + return cls(internal_tag_compiler(text)) + + @classmethod + def from_tuples(cls, tags: Iterable[tuple[int, Any]]) -> Tags: + return cls(DXFTag(code, value) for code, value in tags) + + def __copy__(self) -> Tags: + return self.__class__(tag.clone() for tag in self) + + clone = __copy__ + + def get_handle(self) -> str: + """Get DXF handle. Raises :class:`DXFValueError` if handle not exist. + + Returns: + handle as plain hex string like ``'FF00'`` + + Raises: + DXFValueError: no handle found + + """ + try: + code, handle = self[1] # fast path for most common cases + except IndexError: + raise DXFValueError("No handle found.") + + if code == 5 or code == 105: + return handle + + for code, handle in self: + if code == 5 or code == 105: + return handle + raise DXFValueError("No handle found.") + + def replace_handle(self, new_handle: str) -> None: + """Replace existing handle. + + Args: + new_handle: new handle as plain hex string e.g. ``'FF00'`` + + """ + for index, tag in enumerate(self): + if tag.code in (5, 105): + self[index] = DXFTag(tag.code, new_handle) + return + + def dxftype(self) -> str: + """Returns DXF type of entity, e.g. ``'LINE'``.""" + return self[0].value + + def has_tag(self, code: int) -> bool: + """Returns ``True`` if a :class:`~ezdxf.lldxf.types.DXFTag` with given + group `code` is present. + + Args: + code: group code as int + + """ + return any(tag.code == code for tag in self) + + def get_first_value(self, code: int, default: Any=DXFValueError) -> Any: + """Returns value of first :class:`~ezdxf.lldxf.types.DXFTag` with given + group code or default if `default` != :class:`DXFValueError`, else + raises :class:`DXFValueError`. + + Args: + code: group code as int + default: return value for default case or raises :class:`DXFValueError` + + """ + for tag in self: + if tag.code == code: + return tag.value + if default is DXFValueError: + raise DXFValueError(code) + else: + return default + + def get_first_tag(self, code: int, default=DXFValueError) -> DXFTag: + """Returns first :class:`~ezdxf.lldxf.types.DXFTag` with given group + code or `default`, if `default` != :class:`DXFValueError`, else raises + :class:`DXFValueError`. + + Args: + code: group code as int + default: return value for default case or raises :class:`DXFValueError` + + """ + for tag in self: + if tag.code == code: + return tag + if default is DXFValueError: + raise DXFValueError(code) + else: + return default + + def find_all(self, code: int) -> Tags: + """Returns a list of :class:`~ezdxf.lldxf.types.DXFTag` with given + group code. + + Args: + code: group code as int + + """ + return self.__class__(tag for tag in self if tag.code == code) + + def tag_index(self, code: int, start: int = 0, end: Optional[int] = None) -> int: + """Return index of first :class:`~ezdxf.lldxf.types.DXFTag` with given + group code. + + Args: + code: group code as int + start: start index as int + end: end index as int, ``None`` for end index = ``len(self)`` + + """ + if end is None: + end = len(self) + index = start + while index < end: + if self[index].code == code: + return index + index += 1 + raise DXFValueError(code) + + def update(self, tag: DXFTag) -> None: + """Update first existing tag with same group code as `tag`, raises + :class:`DXFValueError` if tag not exist. + + """ + index = self.tag_index(tag.code) + self[index] = tag + + def set_first(self, tag: DXFTag) -> None: + """Update first existing tag with group code ``tag.code`` or append tag.""" + try: + self.update(tag) + except DXFValueError: + self.append(tag) + + def remove_tags(self, codes: Iterable[int]) -> None: + """Remove all tags inplace with group codes specified in `codes`. + + Args: + codes: iterable of group codes as int + + """ + self[:] = [tag for tag in self if tag.code not in set(codes)] + + def pop_tags(self, codes: Iterable[int]) -> Iterator[DXFTag]: + """Pop tags with group codes specified in `codes`. + + Args: + codes: iterable of group codes + + """ + remaining = [] + codes = set(codes) + for tag in self: + if tag.code in codes: + yield tag + else: + remaining.append(tag) + self[:] = remaining + + def remove_tags_except(self, codes: Iterable[int]) -> None: + """Remove all tags inplace except those with group codes specified in + `codes`. + + Args: + codes: iterable of group codes + + """ + self[:] = [tag for tag in self if tag.code in set(codes)] + + def filter(self, codes: Iterable[int]) -> Iterator[DXFTag]: + """Iterate and filter tags by group `codes`. + + Args: + codes: group codes to filter + + """ + return (tag for tag in self if tag.code not in set(codes)) + + def collect_consecutive_tags( + self, codes: Iterable[int], start: int = 0, end: Optional[int] = None + ) -> Tags: + """Collect all consecutive tags with group code in `codes`, `start` and + `end` delimits the search range. A tag code not in codes ends the + process. + + Args: + codes: iterable of group codes + start: start index as int + end: end index as int, ``None`` for end index = ``len(self)`` + + Returns: + collected tags as :class:`Tags` + + """ + codes = frozenset(codes) + index = int(start) + if end is None: + end = len(self) + bag = self.__class__() + + while index < end: + tag = self[index] + if tag.code in codes: + bag.append(tag) + index += 1 + else: + break + return bag + + def has_embedded_objects(self) -> bool: + for tag in self: + if tag.code == EMBEDDED_OBJ_MARKER and tag.value == EMBEDDED_OBJ_STR: + return True + return False + + @classmethod + def strip(cls, tags: Tags, codes: Iterable[int]) -> Tags: + """Constructor from `tags`, strips all tags with group codes in `codes` + from tags. + + Args: + tags: iterable of :class:`~ezdxf.lldxf.types.DXFTag` + codes: iterable of group codes as int + + """ + return cls((tag for tag in tags if tag.code not in frozenset(codes))) + + def get_soft_pointers(self) -> Tags: + """Returns all soft-pointer handles in group code range 330-339.""" + return Tags(tag for tag in self if types.is_soft_pointer(tag)) + + def get_hard_pointers(self) -> Tags: + """Returns all hard-pointer handles in group code range 340-349, 390-399 and + 480-481. Hard pointers protect an object from being purged. + """ + return Tags(tag for tag in self if types.is_hard_pointer(tag)) + + def get_soft_owner_handles(self) -> Tags: + """Returns all soft-owner handles in group code range 350-359.""" + return Tags(tag for tag in self if types.is_soft_owner(tag)) + + def get_hard_owner_handles(self) -> Tags: + """Returns all hard-owner handles in group code range 360-369.""" + return Tags(tag for tag in self if types.is_hard_owner(tag)) + + def has_translatable_pointers(self) -> bool: + """Returns ``True`` if any pointer handle has to be translated during INSERT + and XREF operations. + """ + return any(types.is_translatable_pointer(tag) for tag in self) + + def get_translatable_pointers(self) -> Tags: + """Returns all pointer handles which should be translated during INSERT and XREF + operations. + """ + return Tags(tag for tag in self if types.is_translatable_pointer(tag)) + + +def text2tags(text: str) -> Tags: + return Tags.from_text(text) + + +def group_tags( + tags: Iterable[DXFTag], splitcode: int = STRUCTURE_MARKER +) -> Iterable[Tags]: + """Group of tags starts with a SplitTag and ends before the next SplitTag. + A SplitTag is a tag with code == splitcode, like (0, 'SECTION') for + splitcode == 0. + + Args: + tags: iterable of :class:`DXFTag` + splitcode: group code of split tag + + """ + + # first do nothing, skip tags in front of the first split tag + def append(tag): + pass + + group = None + for tag in tags: + if tag.code == splitcode: + if group is not None: + yield group + group = Tags([tag]) + append = group.append # redefine append: add tags to this group + else: + append(tag) + if group is not None: + yield group + + +def text_to_multi_tags( + text: str, code: int = 303, size: int = 255, line_ending: str = "^J" +) -> Tags: + text = "".join(text).replace("\n", line_ending) + + def chop(): + start = 0 + end = size + while start < len(text): + yield text[start:end] + start = end + end += size + + return Tags(DXFTag(code, part) for part in chop()) + + +def multi_tags_to_text(tags: Tags, line_ending: str = "^J") -> str: + return "".join(tag.value for tag in tags).replace(line_ending, "\n") + + +OPEN_LIST = (1002, "{") +CLOSE_LIST = (1002, "}") + + +def xdata_list(name: str, xdata_tags: Iterable) -> Tags: + tags = Tags() + if name: + tags.append((1000, name)) + tags.append(OPEN_LIST) + tags.extend(xdata_tags) + tags.append(CLOSE_LIST) + return tags + + +def remove_named_list_from_xdata(name: str, tags: Tags) -> Tags: + start, end = get_start_and_end_of_named_list_in_xdata(name, tags) + del tags[start:end] + return tags + + +def get_named_list_from_xdata(name: str, tags: Tags) -> Tags: + start, end = get_start_and_end_of_named_list_in_xdata(name, tags) + return Tags(tags[start:end]) + + +class NotFoundException(Exception): + pass + + +def get_start_and_end_of_named_list_in_xdata(name: str, tags: Tags) -> tuple[int, int]: + start = None + end = None + level = 0 + for index in range(len(tags)): + tag = tags[index] + + if start is None and tag == (1000, name): + next_tag = tags[index + 1] + if next_tag == OPEN_LIST: + start = index + continue + if start is not None: + if tag == OPEN_LIST: + level += 1 + elif tag == CLOSE_LIST: + level -= 1 + if level == 0: + end = index + break + + if start is None: + raise NotFoundException + if end is None: + raise DXFStructureError('Invalid XDATA structure: missing (1002, "}").') + return start, end + 1 + + +def find_begin_and_end_of_encoded_xdata_tags(name: str, tags: Tags) -> tuple[int, int]: + """Find encoded XDATA tags, surrounded by group code 1000 tags + name_BEGIN and name_END (e.g. MTEXT column specification). + + Raises: + NotFoundError: tag group not found + DXFStructureError: missing begin- or end tag + + """ + begin_name = name + "_BEGIN" + end_name = name + "_END" + start = None + end = None + for index, (code, value) in enumerate(tags): + if code == 1000: + if value == begin_name: + start = index + elif value == end_name: + end = index + 1 + break + if start is None: + if end is not None: # end tag without begin tag! + raise DXFStructureError( + f"Invalid XDATA structure: missing begin tag (1000, {begin_name})." + ) + raise NotFoundException + if end is None: + raise DXFStructureError( + f"Invalid XDATA structure: missing end tag (1000, {end_name})." + ) + return start, end + + +def binary_data_to_dxf_tags( + data: bytes, + length_group_code: int = 160, + value_group_code: int = 310, + value_size=127, +) -> Tags: + """Convert binary data to DXF tags.""" + tags = Tags() + length = len(data) + tags.append(dxftag(length_group_code, length)) + index = 0 + while index < length: + chunk = data[index : index + value_size] + tags.append(dxftag(value_group_code, chunk)) + index += value_size + return tags diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagwriter.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagwriter.py new file mode 100644 index 0000000..5dbd24c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/tagwriter.py @@ -0,0 +1,316 @@ +# Copyright (c) 2018-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Any, TextIO, TYPE_CHECKING, Union, Iterable, BinaryIO +import abc + +from .types import TAG_STRING_FORMAT, cast_tag_value, DXFVertex +from .types import BYTES, INT16, INT32, INT64, DOUBLE, BINARY_DATA +from .tags import DXFTag, Tags +from .const import LATEST_DXF_VERSION +from ezdxf.tools import take2 +import struct + +if TYPE_CHECKING: + from ezdxf.lldxf.extendedtags import ExtendedTags + from ezdxf.entities import DXFEntity + +__all__ = [ + "TagWriter", + "BinaryTagWriter", + "TagCollector", + "basic_tags_from_text", + "AbstractTagWriter", +] +CRLF = b"\r\n" + + +class AbstractTagWriter: + # Options for functions using an inherited class for DXF export: + dxfversion = LATEST_DXF_VERSION + write_handles = True + # Force writing optional values if equal to default value when True. + # True is only used for testing scenarios! + force_optional = False + + # Start of low level interface: + @abc.abstractmethod + def write_tag(self, tag: DXFTag) -> None: ... + + @abc.abstractmethod + def write_tag2(self, code: int, value: Any) -> None: ... + + @abc.abstractmethod + def write_str(self, s: str) -> None: ... + + # End of low level interface + + # Tag export based on low level tag export: + def write_tags(self, tags: Union[Tags, ExtendedTags]) -> None: + for tag in tags: + self.write_tag(tag) + + def write_vertex(self, code: int, vertex: Iterable[float]) -> None: + for index, value in enumerate(vertex): + self.write_tag2(code + index * 10, value) + + +class TagWriter(AbstractTagWriter): + """Writes DXF tags into a text stream.""" + + def __init__( + self, + stream: TextIO, + dxfversion: str = LATEST_DXF_VERSION, + write_handles: bool = True, + ): + self._stream: TextIO = stream + self.dxfversion: str = dxfversion + self.write_handles: bool = write_handles + self.force_optional: bool = False + + # Start of low level interface: + def write_tag(self, tag: DXFTag) -> None: + self._stream.write(tag.dxfstr()) + + def write_tag2(self, code: int, value: Any) -> None: + self._stream.write(TAG_STRING_FORMAT % (code, value)) + + def write_str(self, s: str) -> None: + self._stream.write(s) + + # End of low level interface + + def write_vertex(self, code: int, vertex: Iterable[float]) -> None: + """Optimized vertex export.""" + write = self._stream.write + for index, value in enumerate(vertex): + write(TAG_STRING_FORMAT % (code + index * 10, value)) + + +class BinaryTagWriter(AbstractTagWriter): + """Write binary encoded DXF tags into a binary stream. + + .. warning:: + + DXF files containing ``ACSH_SWEEP_CLASS`` entities and saved as Binary + DXF by `ezdxf` can not be opened with AutoCAD, this is maybe also true + for other 3rd party entities. BricsCAD opens this binary DXF files + without complaining, but saves the ``ACSH_SWEEP_CLASS`` entities as + ``ACAD_PROXY_OBJECT`` when writing back, so error analyzing is not + possible without the full version of AutoCAD. + + I have no clue why, because converting this DXF files from binary + format back to ASCII format by `ezdxf` produces a valid DXF for + AutoCAD - so all required information is preserved. + + Two examples available: + + - AutodeskSamples\visualization_-_condominium_with_skylight.dxf + - AutodeskSamples\visualization_-_conference_room.dxf + + """ + + def __init__( + self, + stream: BinaryIO, + dxfversion=LATEST_DXF_VERSION, + write_handles: bool = True, + encoding="utf8", + ): + self._stream = stream + self.dxfversion = dxfversion + self.write_handles = write_handles + self._encoding = encoding # output encoding + self._r12 = self.dxfversion <= "AC1009" + + def write_signature(self) -> None: + self._stream.write(b"AutoCAD Binary DXF\r\n\x1a\x00") + + # Start of low level interface: + def write_tag(self, tag: DXFTag) -> None: + if isinstance(tag, DXFVertex): + for code, value in tag.dxftags(): + self.write_tag2(code, value) + else: + self.write_tag2(tag.code, tag.value) + + def write_str(self, s: str) -> None: + data = s.split("\n") + for code, value in take2(data): + self.write_tag2(int(code), value) + + def write_tag2(self, code: int, value: Any) -> None: + # Binary DXF files do not support comments! + assert code != 999 + if code in BINARY_DATA: + self._write_binary_chunks(code, value) + return + stream = self._stream + + # write group code + if self._r12: + # Special group code handling if DXF R12 and older + if code >= 1000: # extended data + stream.write(b"\xff") + # always 2-byte group code for extended data + stream.write(code.to_bytes(2, "little")) + else: + stream.write(code.to_bytes(1, "little")) + else: # for R2000+ do not need a leading 0xff in front of extended data + stream.write(code.to_bytes(2, "little")) + # write tag content + if code in BYTES: + stream.write(int(value).to_bytes(1, "little")) + elif code in INT16: + stream.write(int(value).to_bytes(2, "little", signed=True)) + elif code in INT32: + stream.write(int(value).to_bytes(4, "little", signed=True)) + elif code in INT64: + stream.write(int(value).to_bytes(8, "little", signed=True)) + elif code in DOUBLE: + stream.write(struct.pack(" None: + # Split binary data into small chunks, 127 bytes is the + # regular size of binary data in ASCII DXF files. + CHUNK_SIZE = 127 + index = 0 + size = len(data) + stream = self._stream + + while index < size: + # write group code + if self._r12 and code >= 1000: # extended data, just 1004? + stream.write(b"\xff") # extended data marker + # binary data does not exist in regular R12 entities, + # only 2-byte group codes required + stream.write(code.to_bytes(2, "little")) + + # write max CHUNK_SIZE bytes of binary data in one tag + chunk = data[index : index + CHUNK_SIZE] + # write actual chunk size + stream.write(len(chunk).to_bytes(1, "little")) + stream.write(chunk) + index += CHUNK_SIZE + + +class TagCollector(AbstractTagWriter): + """Collect DXF tags as DXFTag() entities for testing.""" + + def __init__( + self, + dxfversion: str = LATEST_DXF_VERSION, + write_handles: bool = True, + optional: bool = True, + ): + self.tags: list[DXFTag] = [] + self.dxfversion: str = dxfversion + self.write_handles: bool = write_handles + self.force_optional: bool = optional + + # Start of low level interface: + def write_tag(self, tag: DXFTag) -> None: + if hasattr(tag, "dxftags"): + self.tags.extend(tag.dxftags()) + else: + self.tags.append(tag) + + def write_tag2(self, code: int, value: Any) -> None: + self.tags.append(DXFTag(code, cast_tag_value(int(code), value))) + + def write_str(self, s: str) -> None: + self.write_tags(Tags.from_text(s)) + + # End of low level interface + + def has_all_tags(self, other: TagCollector): + return all(tag in self.tags for tag in other.tags) + + def reset(self): + self.tags = [] + + @classmethod + def dxftags(cls, entity: DXFEntity, dxfversion=LATEST_DXF_VERSION): + collector = cls(dxfversion=dxfversion) + entity.export_dxf(collector) + return Tags(collector.tags) + + +def basic_tags_from_text(text: str) -> list[DXFTag]: + """Returns all tags from `text` as basic DXFTags(). All complex tags are + resolved into basic (code, value) tags (e.g. DXFVertex(10, (1, 2, 3)) -> + DXFTag(10, 1), DXFTag(20, 2), DXFTag(30, 3). + + Args: + text: DXF data as string + + Returns: List of basic DXF tags (code, value) + + """ + collector = TagCollector() + collector.write_tags(Tags.from_text(text)) + return collector.tags + + +class JSONTagWriter(AbstractTagWriter): + """Writes DXF tags in JSON format into a text stream. + + The `compact` format is a list of ``[group-code, value]`` pairs where each pair is + a DXF tag. The group-code has to be an integer and the value has to be a string, + integer, float or list of floats for vertices. + + The `verbose` format (`compact` is ``False``) is a list of ``[group-code, value]`` + pairs where each pair is a 1:1 representation of a DXF tag. The group-code has to be + an integer and the value has to be a string. + + """ + + JSON_HEADER = "[\n" + JSON_STRING = '[{0}, "{1}"],\n' + JSON_NUMBER = '[{0}, {1}],\n' + VERTEX_TAG_FORMAT = "[{0}, {1}],\n" + + def __init__( + self, + stream: TextIO, + dxfversion: str = LATEST_DXF_VERSION, + write_handles=True, + compact=True, + ): + self._stream = stream + self.dxfversion = str(dxfversion) + self.write_handles = bool(write_handles) + self.force_optional = False + self.compact = bool(compact) + self._stream.write(self.JSON_HEADER) + + def write_tag(self, tag: DXFTag) -> None: + if isinstance(tag, DXFVertex): + if self.compact: + vertex = ",".join(str(value) for _, value in tag.dxftags()) + self._stream.write( + self.VERTEX_TAG_FORMAT.format(tag.code, f"[{vertex}]") + ) + else: + for code, value in tag.dxftags(): + self.write_tag2(code, value) + else: + self.write_tag2(tag.code, tag.value) + + def write_tag2(self, code: int, value: Any) -> None: + if code == 0 and value == "EOF": + self._stream.write('[0, "EOF"]\n]\n') # no trailing comma! + return + if self.compact and isinstance(value, (float, int)): + self._stream.write(self.JSON_NUMBER.format(code, value)) + return + self._stream.write(self.JSON_STRING.format(code, value)) + + def write_str(self, s: str) -> None: + self.write_tags(Tags.from_text(s)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/types.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/types.py new file mode 100644 index 0000000..b19efe0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/types.py @@ -0,0 +1,472 @@ +# Copyright (c) 2014-2022, Manfred Moitzi +# License: MIT License +""" +DXF Types +========= + +Required DXF tag interface: + + - property :attr:`code`: group code as int + - property :attr:`value`: tag value of unspecific type + - :meth:`dxfstr`: returns the DXF string + - :meth:`clone`: returns a deep copy of tag + +""" +from __future__ import annotations +from typing import ( + Union, + Iterable, + Sequence, + Type, + Any, +) +from array import array +from itertools import chain +from binascii import unhexlify, hexlify +import reprlib +from ezdxf.math import Vec3 + + +TAG_STRING_FORMAT = "%3d\n%s\n" +POINT_CODES = { + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 110, + 111, + 112, + 210, + 211, + 212, + 213, + 1010, + 1011, + 1012, + 1013, +} + +MAX_GROUP_CODE = 1071 +GENERAL_MARKER = 0 +SUBCLASS_MARKER = 100 +XDATA_MARKER = 1001 +EMBEDDED_OBJ_MARKER = 101 +APP_DATA_MARKER = 102 +EXT_DATA_MARKER = 1001 +GROUP_MARKERS = { + GENERAL_MARKER, + SUBCLASS_MARKER, + EMBEDDED_OBJ_MARKER, + APP_DATA_MARKER, + EXT_DATA_MARKER, +} +BINARY_FLAGS = {70, 90} +HANDLE_CODES = {5, 105} +POINTER_CODES = set(chain(range(320, 370), range(390, 400), (480, 481, 1005))) + +# pointer group codes 320-329 are not translated during INSERT and XREF operations +TRANSLATABLE_POINTER_CODES = set( + chain(range(330, 370), range(390, 400), (480, 481, 1005)) +) +HEX_HANDLE_CODES = set(chain(HANDLE_CODES, POINTER_CODES)) +BINARY_DATA = {310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 1004} +EMBEDDED_OBJ_STR = "Embedded Object" + +BYTES = set(range(290, 300)) # bool + +INT16 = set( + chain( + range(60, 80), + range(170, 180), + range(270, 290), + range(370, 390), + range(400, 410), + range(1060, 1071), + ) +) + +INT32 = set( + chain( + range(90, 100), + range(420, 430), + range(440, 450), + range(450, 460), # Long in DXF reference, ->signed<- or unsigned? + [1071], + ) +) + +INT64 = set(range(160, 170)) + +DOUBLE = set( + chain( + range(10, 60), + range(110, 150), + range(210, 240), + range(460, 470), + range(1010, 1060), + ) +) + +VALID_XDATA_GROUP_CODES = { + 1000, + 1001, + 1002, + 1003, + 1004, + 1005, + 1010, + 1011, + 1012, + 1013, + 1040, + 1041, + 1042, + 1070, + 1071, +} + + +def _build_type_table(types): + table = {} + for caster, codes in types: + for code in codes: + table[code] = caster + return table + + +TYPE_TABLE = _build_type_table( + [ + # all group code < 0 are spacial tags for internal use + (float, DOUBLE), + (int, BYTES), + (int, INT16), + (int, INT32), + (int, INT64), + ] +) + + +class DXFTag: + """Immutable DXFTag class. + + Args: + code: group code as int + value: tag value, type depends on group code + + """ + + __slots__ = ("_code", "_value") + + def __init__(self, code: int, value: Any): + self._code: int = int(code) + # Do not use _value, always use property value - overwritten in subclasses + self._value = value + + def __str__(self) -> str: + """Returns content string ``'(code, value)'``.""" + return str((self._code, self.value)) + + def __repr__(self) -> str: + """Returns representation string ``'DXFTag(code, value)'``.""" + return f"DXFTag{str(self)}" + + @property + def code(self) -> int: + return self._code + + @property + def value(self) -> Any: + return self._value + + def __getitem__(self, index: int): + """Returns :attr:`code` for index 0 and :attr:`value` for index 1, + emulates a tuple. + """ + return (self._code, self.value)[index] + + def __iter__(self): + """Returns (code, value) tuples.""" + yield self._code + yield self.value + + def __eq__(self, other) -> bool: + """``True`` if `other` and `self` has same content for :attr:`code` + and :attr:`value`. + """ + return (self._code, self.value) == other + + def __hash__(self): + """Hash support, :class:`DXFTag` can be used in sets and as dict key.""" + return hash((self._code, self._value)) + + def dxfstr(self) -> str: + """Returns the DXF string e.g. ``' 0\\nLINE\\n'``""" + return TAG_STRING_FORMAT % (self.code, self._value) + + def clone(self) -> "DXFTag": + """Returns a clone of itself, this method is necessary for the more + complex (and not immutable) DXF tag types. + """ + return self # immutable tags + + +# Special marker tag +NONE_TAG = DXFTag(0, 0) + + +def uniform_appid(appid: str) -> str: + if appid[0] == "{": + return appid + else: + return "{" + appid + + +def is_app_data_marker(tag: DXFTag) -> bool: + return tag.code == APP_DATA_MARKER and tag.value.startswith("{") + + +def is_embedded_object_marker(tag: DXFTag) -> bool: + return tag.code == EMBEDDED_OBJ_MARKER and tag.value == EMBEDDED_OBJ_STR + + +def is_arbitrary_pointer(tag: DXFTag) -> bool: + """Arbitrary object handles; handle values that are taken "as is". + They are not translated during INSERT and XREF operations. + """ + return 319 < tag.code < 330 + + +def is_soft_pointer(tag: DXFTag) -> bool: + """Soft-pointer handle; arbitrary soft pointers to other objects within same DXF + file or drawing. Translated during INSERT and XREF operations. + """ + return 329 < tag.code < 340 or tag.code == 1005 + + +def is_hard_pointer(tag: DXFTag) -> bool: + """Hard-pointer handle; arbitrary hard pointers to other objects within same DXF + file or drawing. Translated during INSERT and XREF operations. Hard pointers + protect an object from being purged. + """ + code = tag.code + return 339 < code < 350 or 389 < code < 400 or 479 < code < 482 + + +def is_soft_owner(tag: DXFTag) -> bool: + """Soft-owner handle; arbitrary soft ownership links to other objects within same + DXF file or drawing. Translated during INSERT and XREF operations. + """ + return 349 < tag.code < 360 + + +def is_hard_owner(tag: DXFTag) -> bool: + """Hard-owner handle; arbitrary hard ownership links to other objects within same + DXF file or drawing. Translated during INSERT and XREF operations. Hard owner handle + protect an object from being purged. + """ + return 359 < tag.code < 370 + + +def is_translatable_pointer(tag: DXFTag) -> bool: + # pointer group codes 320-329 are not translated during INSERT and XREF operations + return tag.code in TRANSLATABLE_POINTER_CODES + + +class DXFVertex(DXFTag): + """Represents a 2D or 3D vertex, stores only the group code of the + x-component of the vertex, because the y-group-code is x-group-code + 10 + and z-group-code id x-group-code+20, this is a rule that ALWAYS applies. + This tag is `immutable` by design, not by implementation. + + Args: + code: group code of x-component + value: sequence of x, y and optional z values + + """ + + __slots__ = () + + def __init__(self, code: int, value: Iterable[float]): + super(DXFVertex, self).__init__(code, array("d", value)) + + def __str__(self) -> str: + return str(self.value) + + def __repr__(self) -> str: + return f"DXFVertex({self.code}, {str(self)})" + + def __hash__(self): + x, y, *z = self._value + z = 0.0 if len(z) == 0 else z[0] + return hash((self.code, x, y, z)) + + @property + def value(self) -> tuple[float, ...]: + return tuple(self._value) + + def dxftags(self) -> Iterable[DXFTag]: + """Returns all vertex components as single :class:`DXFTag` objects.""" + c = self.code + return ( + DXFTag(code, value) for code, value in zip((c, c + 10, c + 20), self.value) + ) + + def dxfstr(self) -> str: + """Returns the DXF string for all vertex components.""" + return "".join(tag.dxfstr() for tag in self.dxftags()) + + +class DXFBinaryTag(DXFTag): + """Immutable BinaryTags class - immutable by design, not by implementation.""" + + __slots__ = () + + def __str__(self) -> str: + return f"({self.code}, {self.tostring()})" + + def __repr__(self) -> str: + return f"DXFBinaryTag({self.code}, {reprlib.repr(self.tostring())})" + + def tostring(self) -> str: + """Returns binary value as single hex-string.""" + assert isinstance(self.value, bytes) + return hexlify(self.value).upper().decode() + + def dxfstr(self) -> str: + """Returns the DXF string for all vertex components.""" + return TAG_STRING_FORMAT % (self.code, self.tostring()) + + @classmethod + def from_string(cls, code: int, value: Union[str, bytes]): + return cls(code, unhexlify(value)) + + +def dxftag(code: int, value: Any) -> DXFTag: + """DXF tag factory function. + + Args: + code: group code + value: tag value + + Returns: :class:`DXFTag` or inherited + + """ + if code in BINARY_DATA: + return DXFBinaryTag(code, value) + elif code in POINT_CODES: + return DXFVertex(code, value) + else: + return DXFTag(code, cast_tag_value(code, value)) + + +def tuples_to_tags(iterable: Iterable[tuple[int, Any]]) -> Iterable[DXFTag]: + """Returns an iterable if :class:`DXFTag` or inherited, accepts an + iterable of (code, value) tuples as input. + """ + for code, value in iterable: + if code in POINT_CODES: + yield DXFVertex(code, value) + elif code in BINARY_DATA: + assert isinstance(value, (str, bytes)) + yield DXFBinaryTag.from_string(code, value) + else: + yield DXFTag(code, value) + + +def is_valid_handle(handle) -> bool: + if isinstance(handle, str): + try: + int(handle, 16) + return True + except (ValueError, TypeError): + pass + return False + + +def is_binary_data(code: int) -> bool: + return code in BINARY_DATA + + +def is_pointer_code(code: int) -> bool: + return code in POINTER_CODES + + +def is_point_code(code: int) -> bool: + return code in POINT_CODES + + +def is_point_tag(tag: Sequence) -> bool: + return tag[0] in POINT_CODES + + +def cast_tag_value(code: int, value: Any) -> Any: + return TYPE_TABLE.get(code, str)(value) + + +def tag_type(code: int) -> Type: + return TYPE_TABLE.get(code, str) + + +def strtag(tag: Union[DXFTag, tuple[int, Any]]) -> str: + return TAG_STRING_FORMAT % tuple(tag) + + +def get_xcode_for(code) -> int: + if code in HEX_HANDLE_CODES: + return 1005 + if code in BINARY_DATA: + return 1004 + type_ = TYPE_TABLE.get(code, str) + if type_ is int: + return 1070 + if type_ is float: + return 1040 + return 1000 + + +def cast_value(code: int, value): + if value is not None: + if code in POINT_CODES: + return Vec3(value) + return TYPE_TABLE.get(code, str)(value) + else: + return None + + +TAG_TYPES = { + int: "", + float: "", + str: "", +} + + +def tag_type_str(code: int) -> str: + if code in GROUP_MARKERS: + return "" + elif code in HANDLE_CODES: + return "" + elif code in POINTER_CODES: + return "" + elif is_point_code(code): + return "" + elif is_binary_data(code): + return "" + else: + return TAG_TYPES[tag_type(code)] + + +def render_tag(tag: DXFTag, col: int) -> Any: + code, value = tag + if col == 0: + return str(code) + elif col == 1: + return tag_type_str(code) + elif col == 2: + return str(value) + else: + raise IndexError(col) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/lldxf/validator.py b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/validator.py new file mode 100644 index 0000000..a133a58 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/lldxf/validator.py @@ -0,0 +1,560 @@ +# Copyright (C) 2018-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TextIO, Iterable, Optional, cast, Sequence, Iterator +import logging +import io +import bisect +import math + +from .const import ( + DXFStructureError, + DXFError, + DXFValueError, + DXFTypeError, + DXFAppDataError, + DXFXDataError, + APP_DATA_MARKER, + HEADER_VAR_MARKER, + XDATA_MARKER, + INVALID_LAYER_NAME_CHARACTERS, + acad_release, + VALID_DXF_LINEWEIGHT_VALUES, + VALID_DXF_LINEWEIGHTS, + LINEWEIGHT_BYLAYER, + TRANSPARENCY_BYBLOCK, +) + +from .tagger import ascii_tags_loader, binary_tags_loader +from .types import is_embedded_object_marker, DXFTag, NONE_TAG +from ezdxf.tools.codepage import toencoding +from ezdxf.math import NULLVEC, Vec3 + +logger = logging.getLogger("ezdxf") + + +class DXFInfo: + """DXF Info Record + + .. attribute:: release + + .. attribute:: version + + .. attribute:: encoding + + .. attribute:: handseed + + .. attribute:: insert_units + + .. attribute:: insert_base + + """ + + EXPECTED_COUNT = 5 + + def __init__(self) -> None: + self.release: str = "R12" + self.version: str = "AC1009" + self.encoding: str = "cp1252" + self.handseed: str = "0" + self.insert_units: int = 0 # unitless + self.insert_base: Vec3 = NULLVEC + + def __str__(self) -> str: + return "\n".join(self.data_strings()) + + def data_strings(self) -> list[str]: + from ezdxf import units + + return [ + f"release: {self.release}", + f"version: {self.version}", + f"encoding: {self.encoding}", + f"next handle: 0x{self.handseed}", + f"insert units: {self.insert_units} <{units.decode(self.insert_units)}>", + f"insert base point: {self.insert_base}", + ] + + def set_header_var(self, name: str, value) -> int: + if name == "$ACADVER": + self.version = str(value) + self.release = acad_release.get(value, "R12") + elif name == "$DWGCODEPAGE": + self.encoding = toencoding(value) + elif name == "$HANDSEED": + self.handseed = str(value) + elif name == "$INSUNITS": + try: + self.insert_units = int(value) + except ValueError: + pass + elif name == "$INSBASE": + try: + self.insert_base = Vec3(value) + except (ValueError, TypeError): + pass + else: + return 0 + return 1 + + +def dxf_info(stream: TextIO) -> DXFInfo: + """Scans the HEADER section of an ASCII DXF document and returns a :class:`DXFInfo` + object, which contains information about the DXF version, text encoding, drawing + units and insertion base point. + """ + return _detect_dxf_info(ascii_tags_loader(stream)) + + +def binary_dxf_info(data: bytes) -> DXFInfo: + """Scans the HEADER section of a binary DXF document and returns a :class:`DXFInfo` + object, which contains information about the DXF version, text encoding, drawing + units and insertion base point. + """ + return _detect_dxf_info(binary_tags_loader(data)) + + +def _detect_dxf_info(tagger: Iterator[DXFTag]) -> DXFInfo: + info = DXFInfo() + # comments will be skipped + if next(tagger) != (0, "SECTION"): + # unexpected or invalid DXF structure + return info + if next(tagger) != (2, "HEADER"): + # Without a leading HEADER section the document is processed as DXF R12 file + # with only an ENTITIES section. + return info + tag = NONE_TAG + undo_tag = NONE_TAG + found: int = 0 + while tag != (0, "ENDSEC"): + if undo_tag is NONE_TAG: + tag = next(tagger) + else: + tag = undo_tag + undo_tag = NONE_TAG + if tag.code != HEADER_VAR_MARKER: + continue + var_name = str(tag.value) + code, value = next(tagger) + if code == 10: + x = float(value) + y = float(next(tagger).value) + z = 0.0 + tag = next(tagger) + if tag.code == 30: + z = float(tag.value) + else: + undo_tag = tag + value = Vec3(x, y, z) + found += info.set_header_var(var_name, value) + if found >= DXFInfo.EXPECTED_COUNT: + break + return info + + +def header_validator(tagger: Iterable[DXFTag]) -> Iterable[DXFTag]: + """Checks the tag structure of the content of the header section. + + Do not feed (0, 'SECTION') (2, 'HEADER') and (0, 'ENDSEC') tags! + + Args: + tagger: generator/iterator of low level tags or compiled tags + + Raises: + DXFStructureError() -> invalid group codes + DXFValueError() -> invalid header variable name + + """ + variable_name_tag = True + for tag in tagger: + code, value = tag + if variable_name_tag: + if code != HEADER_VAR_MARKER: + raise DXFStructureError( + f"Invalid header variable tag {code}, {value})." + ) + if not value.startswith("$"): + raise DXFValueError( + f'Invalid header variable name "{value}", missing leading "$".' + ) + variable_name_tag = False + else: + variable_name_tag = True + yield tag + + +def entity_structure_validator(tags: list[DXFTag]) -> Iterable[DXFTag]: + """Checks for valid DXF entity tag structure. + + - APP DATA can not be nested and every opening tag (102, '{...') needs a + closing tag (102, '}') + - extended group codes (>=1000) allowed before XDATA section + - XDATA section starts with (1001, APPID) and is always at the end of an + entity + - XDATA section: only group code >= 1000 is allowed + - XDATA control strings (1002, '{') and (1002, '}') have to be balanced + - embedded objects may follow XDATA + + XRECORD entities will not be checked. + + Args: + tags: list of DXFTag() + + Raises: + DXFAppDataError: for invalid APP DATA + DXFXDataError: for invalid XDATA + + """ + assert isinstance(tags, list) + dxftype = cast(str, tags[0].value) + is_xrecord = dxftype == "XRECORD" + handle: str = "???" + app_data: bool = False + xdata: bool = False + xdata_list_level: int = 0 + app_data_closing_tag: str = "}" + embedded_object: bool = False + for tag in tags: + if tag.code == 5 and handle == "???": + handle = cast(str, tag.value) + + if is_embedded_object_marker(tag): + embedded_object = True + + if embedded_object: # no further validation + yield tag + continue # with next tag + + if xdata and not embedded_object: + if tag.code < 1000: + dxftype = cast(str, tags[0].value) + raise DXFXDataError( + f"Invalid XDATA structure in entity {dxftype}(#{handle}), " + f"only group code >=1000 allowed in XDATA section" + ) + if tag.code == 1002: + value = cast(str, tag.value) + if value == "{": + xdata_list_level += 1 + elif value == "}": + xdata_list_level -= 1 + else: + raise DXFXDataError( + f'Invalid XDATA control string (1002, "{value}") entity' + f" {dxftype}(#{handle})." + ) + if xdata_list_level < 0: # more closing than opening tags + raise DXFXDataError( + f"Invalid XDATA structure in entity {dxftype}(#{handle}), " + f'unbalanced list markers, missing (1002, "{{").' + ) + + if tag.code == APP_DATA_MARKER and not is_xrecord: + # Ignore control tags (102, ...) tags in XRECORD + value = cast(str, tag.value) + if value.startswith("{"): + if app_data: # already in app data mode + raise DXFAppDataError( + f"Invalid APP DATA structure in entity {dxftype}" + f"(#{handle}), APP DATA can not be nested." + ) + app_data = True + # 'APPID}' is also a valid closing tag + app_data_closing_tag = value[1:] + "}" + elif value == "}" or value == app_data_closing_tag: + if not app_data: + raise DXFAppDataError( + f"Invalid APP DATA structure in entity {dxftype}" + f'(#{handle}), found (102, "}}") tag without opening tag.' + ) + app_data = False + app_data_closing_tag = "}" + else: + raise DXFAppDataError( + f'Invalid APP DATA structure tag (102, "{value}") in ' + f"entity {dxftype}(#{handle})." + ) + + # XDATA section starts with (1001, APPID) and is always at the end of + # an entity. + if tag.code == XDATA_MARKER and xdata is False: + xdata = True + if app_data: + raise DXFAppDataError( + f"Invalid APP DATA structure in entity {dxftype}" + f'(#{handle}), missing closing tag (102, "}}").' + ) + yield tag + + if app_data: + raise DXFAppDataError( + f"Invalid APP DATA structure in entity {dxftype}(#{handle}), " + f'missing closing tag (102, "}}").' + ) + if xdata: + if xdata_list_level < 0: + raise DXFXDataError( + f"Invalid XDATA structure in entity {dxftype}(#{handle}), " + f'unbalanced list markers, missing (1002, "{{").' + ) + elif xdata_list_level > 0: + raise DXFXDataError( + f"Invalid XDATA structure in entity {dxftype}(#{handle}), " + f'unbalanced list markers, missing (1002, "}}").' + ) + + +def is_dxf_file(filename: str) -> bool: + """Returns ``True`` if `filename` is an ASCII DXF file.""" + with io.open(filename, errors="ignore") as fp: + return is_dxf_stream(fp) + + +def is_binary_dxf_file(filename: str) -> bool: + """Returns ``True`` if `filename` is a binary DXF file.""" + with open(filename, "rb") as fp: + sentinel = fp.read(22) + return sentinel == b"AutoCAD Binary DXF\r\n\x1a\x00" + + +def is_dwg_file(filename: str) -> bool: + """Returns ``True`` if `filename` is a DWG file.""" + return dwg_version(filename) is not None + + +def dwg_version(filename: str) -> Optional[str]: + """Returns DWG version of `filename` as string or ``None``.""" + with open(str(filename), "rb") as fp: + try: + version = fp.read(6).decode(errors="ignore") + except IOError: + return None + if version not in acad_release: + return None + return version + + +def is_dxf_stream(stream: TextIO) -> bool: + try: + reader = ascii_tags_loader(stream) + except DXFError: + return False + try: + for tag in reader: + # The common case for well formed DXF files + if tag == (0, "SECTION"): + return True + # Accept/Ignore tags in front of first SECTION - like AutoCAD and + # BricsCAD, but group code should be < 1000, until reality proofs + # otherwise. + if tag.code > 999: + return False + except DXFStructureError: + pass + return False + + +# Names used in symbol table records and in dictionaries must follow these rules: +# +# - Names can be any length in ObjectARX, but symbol names entered by users in +# AutoCAD are limited to 255 characters. +# - AutoCAD preserves the case of names but does not use the case in +# comparisons. For example, AutoCAD considers "Floor" to be the same symbol +# as "FLOOR." +# - Names can be composed of all characters allowed by Windows or Mac OS for +# filenames, except comma (,), backquote (‘), semi-colon (;), and equal +# sign (=). +# http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-83ABF20A-57D4-4AB3-8A49-D91E0F70DBFF + + +def is_valid_table_name(name: str) -> bool: + # remove backslash of special DXF string encodings + if "\\" in name: + # remove prefix of special DXF unicode encoding + name = name.replace(r"\U+", "") + # remove prefix of special DXF encoding M+xxxxx + # I don't know the real name of this encoding, so I call it "mplus" encoding + name = name.replace(r"\M+", "") + chars = set(name) + return not bool(INVALID_LAYER_NAME_CHARACTERS.intersection(chars)) + + +def make_table_key(name: str) -> str: + """Make unified table entry key.""" + if not isinstance(name, str): + raise DXFTypeError(f"name has to be a string, got {type(name)}") + return name.lower() + + +def is_valid_layer_name(name: str) -> bool: + if is_adsk_special_layer(name): + return True + return is_valid_table_name(name) + + +def is_adsk_special_layer(name: str) -> bool: + if name.startswith("*") and len(name) > 1: + # Special Autodesk layers starts with the otherwise invalid character * + # These layers do not show up in the layer panel. + # Only the first letter can be an asterisk. + return is_valid_table_name(name[1:]) + return False + + +def is_valid_block_name(name: str) -> bool: + if name.startswith("*"): + return is_valid_table_name(name[1:]) + else: + return is_valid_table_name(name) + + +def is_valid_vport_name(name: str) -> bool: + if name.startswith("*"): + return name.upper() == "*ACTIVE" + else: + return is_valid_table_name(name) + + +def is_valid_lineweight(lineweight: int) -> bool: + return lineweight in VALID_DXF_LINEWEIGHT_VALUES + + +def fix_lineweight(lineweight: int) -> int: + if lineweight in VALID_DXF_LINEWEIGHT_VALUES: + return lineweight + if lineweight < -3: + return LINEWEIGHT_BYLAYER + if lineweight > 211: + return 211 + index = bisect.bisect(VALID_DXF_LINEWEIGHTS, lineweight) + return VALID_DXF_LINEWEIGHTS[index] + + +def is_valid_aci_color(aci: int) -> bool: + return 0 <= aci <= 257 + + +def is_valid_rgb(rgb) -> bool: + if not isinstance(rgb, Sequence): + return False + if len(rgb) != 3: + return False + for value in rgb: + if not isinstance(value, int) or value < 0 or value > 255: + return False + return True + + +def is_in_integer_range(start: int, end: int): + """Range of integer values, excluding the `end` value.""" + + def _validator(value: int) -> bool: + return start <= value < end + + return _validator + + +def fit_into_integer_range(start: int, end: int): + def _fixer(value: int) -> int: + return min(max(value, start), end - 1) + + return _fixer + + +def fit_into_float_range(start: float, end: float): + def _fixer(value: float) -> float: + return min(max(value, start), end) + + return _fixer + + +def is_in_float_range(start: float, end: float): + """Range of float values, including the `end` value.""" + + def _validator(value: float) -> bool: + return start <= value <= end + + return _validator + + +def is_not_null_vector(v) -> bool: + return not NULLVEC.isclose(v) + + +def is_not_zero(v: float) -> bool: + return not math.isclose(v, 0.0, abs_tol=1e-12) + + +def is_not_negative(v) -> bool: + return v >= 0 + + +is_greater_or_equal_zero = is_not_negative + + +def is_positive(v) -> bool: + return v > 0 + + +is_greater_zero = is_positive + + +def is_valid_bitmask(mask: int): + def _validator(value: int) -> bool: + return not bool(~mask & value) + + return _validator + + +def fix_bitmask(mask: int): + def _fixer(value: int) -> int: + return mask & value + + return _fixer + + +def is_integer_bool(v) -> bool: + return v in (0, 1) + + +def fix_integer_bool(v) -> int: + return 1 if v else 0 + + +def is_one_of(values: set): + def _validator(v) -> bool: + return v in values + + return _validator + + +def is_valid_one_line_text(text: str) -> bool: + has_line_breaks = bool(set(text).intersection({"\n", "\r"})) + return not has_line_breaks and not text.endswith("^") + + +def fix_one_line_text(text: str) -> str: + return text.replace("\n", "").replace("\r", "").rstrip("^") + + +def is_valid_attrib_tag(tag: str) -> bool: + return is_valid_one_line_text(tag) + + +def fix_attrib_tag(tag: str) -> str: + return fix_one_line_text(tag) + + +def is_handle(handle) -> bool: + try: + int(handle, 16) + except (ValueError, TypeError): + return False + return True + + +def is_transparency(value) -> bool: + if isinstance(value, int): + return value == TRANSPARENCY_BYBLOCK or bool(value & 0x02000000) + return False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/math/__init__.py new file mode 100644 index 0000000..062fed9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/__init__.py @@ -0,0 +1,65 @@ +# Copyright (c) 2011-2024, Manfred Moitzi +# License: MIT License +from typing import Iterable +# Using * imports to simplify namespace imports, therefore every module +# has to have an export declaration: __all__ = [...] + +# Import base types as C-extensions if available: +from ._ctypes import * +# Everything else are pure Python imports: +from .construct2d import * +from .construct3d import * +from .parametrize import * +from .bspline import * +from .bezier import * +from .bezier_interpolation import * +from .eulerspiral import * +from .ucs import * +from .bulge import * +from .arc import * +from .line import * +from .circle import * +from .ellipse import * +from .box import * +from .shape import * +from .bbox import * +from .offset2d import * +from .transformtools import * +from .curvetools import * +from .polyline import * + +ABS_TOL = 1e-12 +REL_TOL = 1e-9 + + +def close_vectors(a: Iterable[AnyVec], b: Iterable[UVec], *, + rel_tol=REL_TOL, abs_tol=ABS_TOL) -> bool: + return all(v1.isclose(v2, rel_tol=rel_tol, abs_tol=abs_tol) + for v1, v2 in zip(a, b)) + + +def xround(value: float, rounding: float = 0.) -> float: + """Extended rounding function. + + The argument `rounding` defines the rounding limit: + + ======= ====================================== + 0 remove fraction + 0.1 round next to x.1, x.2, ... x.0 + 0.25 round next to x.25, x.50, x.75 or x.00 + 0.5 round next to x.5 or x.0 + 1.0 round to a multiple of 1: remove fraction + 2.0 round to a multiple of 2: xxx2, xxx4, xxx6 ... + 5.0 round to a multiple of 5: xxx5 or xxx0 + 10.0 round to a multiple of 10: xx10, xx20, ... + ======= ====================================== + + Args: + value: float value to round + rounding: rounding limit + + """ + if rounding == 0: + return round(value) + factor = 1. / rounding + return round(value * factor) / factor diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..e66697e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier3p.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier3p.cpython-312.pyc new file mode 100644 index 0000000..c7d22a2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier3p.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier4p.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier4p.cpython-312.pyc new file mode 100644 index 0000000..2beae6f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bezier4p.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bspline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bspline.cpython-312.pyc new file mode 100644 index 0000000..13fa263 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_bspline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_construct.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_construct.cpython-312.pyc new file mode 100644 index 0000000..55bd80a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_construct.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_ctypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_ctypes.cpython-312.pyc new file mode 100644 index 0000000..e2221ea Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_ctypes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_mapbox_earcut.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_mapbox_earcut.cpython-312.pyc new file mode 100644 index 0000000..ecec38d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_mapbox_earcut.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_matrix44.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_matrix44.cpython-312.pyc new file mode 100644 index 0000000..87d7e1f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_matrix44.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_vector.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_vector.cpython-312.pyc new file mode 100644 index 0000000..5b0bb21 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/_vector.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/arc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/arc.cpython-312.pyc new file mode 100644 index 0000000..b7011de Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/arc.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bbox.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bbox.cpython-312.pyc new file mode 100644 index 0000000..5ad95d8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bbox.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier.cpython-312.pyc new file mode 100644 index 0000000..044e665 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier_interpolation.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier_interpolation.cpython-312.pyc new file mode 100644 index 0000000..c11f5bf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bezier_interpolation.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/box.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/box.cpython-312.pyc new file mode 100644 index 0000000..1774194 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/box.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bspline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bspline.cpython-312.pyc new file mode 100644 index 0000000..a633fe4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bspline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bulge.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bulge.cpython-312.pyc new file mode 100644 index 0000000..70effd4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/bulge.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/circle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/circle.cpython-312.pyc new file mode 100644 index 0000000..28f3009 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/circle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clipping.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clipping.cpython-312.pyc new file mode 100644 index 0000000..d28b51b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clipping.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clustering.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clustering.cpython-312.pyc new file mode 100644 index 0000000..2d7ba04 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/clustering.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct2d.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct2d.cpython-312.pyc new file mode 100644 index 0000000..0bdca25 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct2d.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct3d.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct3d.cpython-312.pyc new file mode 100644 index 0000000..a4f87b6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/construct3d.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/cspline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/cspline.cpython-312.pyc new file mode 100644 index 0000000..137f3fc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/cspline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/curvetools.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/curvetools.cpython-312.pyc new file mode 100644 index 0000000..01ce316 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/curvetools.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ellipse.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ellipse.cpython-312.pyc new file mode 100644 index 0000000..a84dfbe Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ellipse.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/eulerspiral.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/eulerspiral.cpython-312.pyc new file mode 100644 index 0000000..60dadf7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/eulerspiral.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/legacy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/legacy.cpython-312.pyc new file mode 100644 index 0000000..dd1e791 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/legacy.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/linalg.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/linalg.cpython-312.pyc new file mode 100644 index 0000000..eab0b5c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/linalg.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/line.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/line.cpython-312.pyc new file mode 100644 index 0000000..8b07cd2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/line.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/offset2d.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/offset2d.cpython-312.pyc new file mode 100644 index 0000000..b9ec8e3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/offset2d.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/parametrize.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/parametrize.cpython-312.pyc new file mode 100644 index 0000000..01f43b9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/parametrize.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/perlin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/perlin.cpython-312.pyc new file mode 100644 index 0000000..d7f79fd Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/perlin.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/polyline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/polyline.cpython-312.pyc new file mode 100644 index 0000000..48f0e5f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/polyline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/rtree.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/rtree.cpython-312.pyc new file mode 100644 index 0000000..d7b12df Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/rtree.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/shape.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/shape.cpython-312.pyc new file mode 100644 index 0000000..f20930f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/shape.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/transformtools.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/transformtools.cpython-312.pyc new file mode 100644 index 0000000..b246d88 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/transformtools.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/triangulation.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/triangulation.cpython-312.pyc new file mode 100644 index 0000000..906d797 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/triangulation.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ucs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ucs.cpython-312.pyc new file mode 100644 index 0000000..8149b36 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/math/__pycache__/ucs.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier3p.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier3p.py new file mode 100644 index 0000000..26589ff --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier3p.py @@ -0,0 +1,200 @@ +# Copyright (c) 2021-2024 Manfred Moitzi +# License: MIT License +# pylint: disable=unused-variable +from __future__ import annotations +from typing import ( + Iterator, + Sequence, + Optional, + Generic, + TypeVar, +) +import math + +# The pure Python implementation can't import from ._ctypes or ezdxf.math! +from ._vector import Vec3, Vec2 +from ._matrix44 import Matrix44 + + +__all__ = ["Bezier3P"] + + +def check_if_in_valid_range(t: float) -> None: + if not 0.0 <= t <= 1.0: + raise ValueError("t not in range [0 to 1]") + + +T = TypeVar("T", Vec2, Vec3) + + +class Bezier3P(Generic[T]): + """Implements an optimized quadratic `Bézier curve`_ for exact 3 control + points. + + The class supports points of type :class:`Vec2` and :class:`Vec3` as input, the + class instances are immutable. + + Args: + defpoints: sequence of definition points as :class:`Vec2` or + :class:`Vec3` compatible objects. + + """ + + __slots__ = ("_control_points", "_offset") + + def __init__(self, defpoints: Sequence[T]): + if len(defpoints) != 3: + raise ValueError("Three control points required.") + point_type = defpoints[0].__class__ + if not point_type.__name__ in ("Vec2", "Vec3"): # Cython types!!! + raise TypeError(f"invalid point type: {point_type.__name__}") + + # The start point is the curve offset + offset: T = defpoints[0] + self._offset: T = offset + # moving the curve to the origin reduces floating point errors: + self._control_points: tuple[T, ...] = tuple(p - offset for p in defpoints) + + @property + def control_points(self) -> Sequence[T]: + """Control points as tuple of :class:`Vec3` or :class:`Vec2` objects.""" + # ezdxf optimization: p0 is always (0, 0, 0) + _, p1, p2 = self._control_points + offset = self._offset + return offset, p1 + offset, p2 + offset + + def tangent(self, t: float) -> T: + """Returns direction vector of tangent for location `t` at the + Bèzier-curve. + + Args: + t: curve position in the range ``[0, 1]`` + + """ + check_if_in_valid_range(t) + return self._get_curve_tangent(t) + + def point(self, t: float) -> T: + """Returns point for location `t` at the Bèzier-curve. + + Args: + t: curve position in the range ``[0, 1]`` + + """ + check_if_in_valid_range(t) + return self._get_curve_point(t) + + def approximate(self, segments: int) -> Iterator[T]: + """Approximate `Bézier curve`_ by vertices, yields `segments` + 1 + vertices as ``(x, y[, z])`` tuples. + + Args: + segments: count of segments for approximation + + """ + if segments < 1: + raise ValueError(segments) + delta_t: float = 1.0 / segments + cp = self.control_points + yield cp[0] + for segment in range(1, segments): + yield self._get_curve_point(delta_t * segment) + yield cp[2] + + def approximated_length(self, segments: int = 128) -> float: + """Returns estimated length of Bèzier-curve as approximation by line + `segments`. + """ + length: float = 0.0 + prev_point: Optional[T] = None + for point in self.approximate(segments): + if prev_point is not None: + length += prev_point.distance(point) + prev_point = point + return length + + def flattening(self, distance: float, segments: int = 4) -> Iterator[T]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments, if the distance from the center + of the approximation segment to the curve is bigger than `distance` the + segment will be subdivided. + + Args: + distance: maximum distance from the center of the quadratic (C2) + curve to the center of the linear (C1) curve between two + approximation points to determine if a segment should be + subdivided. + segments: minimum segment count + + """ + stack: list[tuple[float, T]] = [] + dt: float = 1.0 / segments + t0: float = 0.0 + t1: float + cp = self.control_points + start_point: T = cp[0] + end_point: T + + yield start_point + while t0 < 1.0: + t1 = t0 + dt + if math.isclose(t1, 1.0): + end_point = cp[2] + t1 = 1.0 + else: + end_point = self._get_curve_point(t1) + + while True: + mid_t: float = (t0 + t1) * 0.5 + mid_point: T = self._get_curve_point(mid_t) + chk_point: T = start_point.lerp(end_point) + + d = chk_point.distance(mid_point) + if d < distance: + yield end_point + t0 = t1 + start_point = end_point + if stack: + t1, end_point = stack.pop() + else: + break + else: + stack.append((t1, end_point)) + t1 = mid_t + end_point = mid_point + + def _get_curve_point(self, t: float) -> T: + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + _, p1, p2 = self._control_points + _1_minus_t = 1.0 - t + # a = (1 - t) ** 2 + b = 2.0 * t * _1_minus_t + c = t * t + # add offset at last - it is maybe very large + return p1 * b + p2 * c + self._offset + + def _get_curve_tangent(self, t: float) -> T: + # tangent vector is independent from offset location! + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + _, p1, p2 = self._control_points + # a = -2 * (1 - t) + b = 2.0 - 4.0 * t + c = 2.0 * t + return p1 * b + p2 * c + + def reverse(self) -> Bezier3P[T]: + """Returns a new Bèzier-curve with reversed control point order.""" + return Bezier3P(list(reversed(self.control_points))) + + def transform(self, m: Matrix44) -> Bezier3P[Vec3]: + """General transformation interface, returns a new :class:`Bezier3P` + curve and it is always a 3D curve. + + Args: + m: 4x4 transformation :class:`Matrix44` + + """ + defpoints = Vec3.generate(self.control_points) + return Bezier3P(tuple(m.transform_vertices(defpoints))) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier4p.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier4p.py new file mode 100644 index 0000000..dfe675e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_bezier4p.py @@ -0,0 +1,336 @@ +# Copyright (c) 2010-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + Sequence, + TypeVar, + Generic, +) +import math + +# The pure Python implementation can't import from ._ctypes or ezdxf.math! +from ._vector import Vec3, Vec2 +from ._matrix44 import Matrix44 +from ._construct import arc_angle_span_deg + +if TYPE_CHECKING: + from ezdxf.math import UVec + from ezdxf.math.ellipse import ConstructionEllipse + +__all__ = [ + "Bezier4P", + "cubic_bezier_arc_parameters", + "cubic_bezier_from_arc", + "cubic_bezier_from_ellipse", +] + +T = TypeVar("T", Vec2, Vec3) + + +class Bezier4P(Generic[T]): + """Implements an optimized cubic `Bézier curve`_ for exact 4 control points. + + A `Bézier curve`_ is a parametric curve, parameter `t` goes from 0 to 1, + where 0 is the first control point and 1 is the fourth control point. + + The class supports points of type :class:`Vec2` and :class:`Vec3` as input, the + class instances are immutable. + + Args: + defpoints: sequence of definition points as :class:`Vec2` or + :class:`Vec3` compatible objects. + + """ + + __slots__ = ("_control_points", "_offset") + + def __init__(self, defpoints: Sequence[T]): + if len(defpoints) != 4: + raise ValueError("Four control points required.") + point_type = defpoints[0].__class__ + if not point_type.__name__ in ("Vec2", "Vec3"): # Cython types!!! + raise TypeError(f"invalid point type: {point_type.__name__}") + + # The start point is the curve offset + offset: T = defpoints[0] + self._offset: T = offset + # moving the curve to the origin reduces floating point errors: + self._control_points: tuple[T, ...] = tuple(p - offset for p in defpoints) + + @property + def control_points(self) -> Sequence[T]: + """Control points as tuple of :class:`Vec3` or :class:`Vec2` objects.""" + # ezdxf optimization: p0 is always (0, 0, 0) + p0, p1, p2, p3 = self._control_points + offset = self._offset + return offset, p1 + offset, p2 + offset, p3 + offset + + def tangent(self, t: float) -> T: + """Returns direction vector of tangent for location `t` at the + Bèzier-curve. + + Args: + t: curve position in the range ``[0, 1]`` + + """ + if not (0 <= t <= 1.0): + raise ValueError("t not in range [0 to 1]") + return self._get_curve_tangent(t) + + def point(self, t: float) -> T: + """Returns point for location `t` at the Bèzier-curve. + + Args: + t: curve position in the range ``[0, 1]`` + + """ + if not (0 <= t <= 1.0): + raise ValueError("t not in range [0 to 1]") + return self._get_curve_point(t) + + def approximate(self, segments: int) -> Iterator[T]: + """Approximate `Bézier curve`_ by vertices, yields `segments` + 1 + vertices as ``(x, y[, z])`` tuples. + + Args: + segments: count of segments for approximation + + """ + if segments < 1: + raise ValueError(segments) + delta_t = 1.0 / segments + cp = self.control_points + yield cp[0] + for segment in range(1, segments): + yield self._get_curve_point(delta_t * segment) + yield cp[3] + + def flattening(self, distance: float, segments: int = 4) -> Iterator[T]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments, if the distance from the center + of the approximation segment to the curve is bigger than `distance` the + segment will be subdivided. + + Args: + distance: maximum distance from the center of the cubic (C3) + curve to the center of the linear (C1) curve between two + approximation points to determine if a segment should be + subdivided. + segments: minimum segment count + + """ + stack: list[tuple[float, T]] = [] + dt: float = 1.0 / segments + t0: float = 0.0 + t1: float + cp = self.control_points + start_point: T = cp[0] + end_point: T + + yield start_point + while t0 < 1.0: + t1 = t0 + dt + if math.isclose(t1, 1.0): + end_point = cp[3] + t1 = 1.0 + else: + end_point = self._get_curve_point(t1) + + while True: + mid_t: float = (t0 + t1) * 0.5 + mid_point: T = self._get_curve_point(mid_t) + chk_point: T = start_point.lerp(end_point) + + d = chk_point.distance(mid_point) + if d < distance: + yield end_point + t0 = t1 + start_point = end_point + if stack: + t1, end_point = stack.pop() + else: + break + else: + stack.append((t1, end_point)) + t1 = mid_t + end_point = mid_point + + def _get_curve_point(self, t: float) -> T: + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + # add offset at last - it is maybe very large + _, p1, p2, p3 = self._control_points + t2 = t * t + _1_minus_t = 1.0 - t + # a = _1_minus_t_square * _1_minus_t + b = 3.0 * _1_minus_t * _1_minus_t * t + c = 3.0 * _1_minus_t * t2 + d = t2 * t + return p1 * b + p2 * c + p3 * d + self._offset + + def _get_curve_tangent(self, t: float) -> T: + # tangent vector is independent from offset location! + # 1st control point (p0) is always (0, 0, 0) + # => p0 * a is always (0, 0, 0) + _, p1, p2, p3 = self._control_points + t2 = t * t + # a = -3.0 * (1.0 - t) ** 2 + b = 3.0 * (1.0 - 4.0 * t + 3.0 * t2) + c = 3.0 * t * (2.0 - 3.0 * t) + d = 3.0 * t2 + return p1 * b + p2 * c + p3 * d + + def approximated_length(self, segments: int = 128) -> float: + """Returns estimated length of Bèzier-curve as approximation by line + `segments`. + """ + length = 0.0 + prev_point = None + for point in self.approximate(segments): + if prev_point is not None: + length += prev_point.distance(point) + prev_point = point + return length + + def reverse(self) -> Bezier4P[T]: + """Returns a new Bèzier-curve with reversed control point order.""" + return Bezier4P(list(reversed(self.control_points))) + + def transform(self, m: Matrix44) -> Bezier4P[Vec3]: + """General transformation interface, returns a new :class:`Bezier4p` + curve as a 3D curve. + + Args: + m: 4x4 transformation :class:`Matrix44` + + """ + defpoints = Vec3.generate(self.control_points) + return Bezier4P(tuple(m.transform_vertices(defpoints))) + + +def cubic_bezier_from_arc( + center: UVec = (0, 0, 0), + radius: float = 1, + start_angle: float = 0, + end_angle: float = 360, + segments: int = 1, +) -> Iterator[Bezier4P[Vec3]]: + """Returns an approximation for a circular 2D arc by multiple cubic + Bézier-curves. + + Args: + center: circle center as :class:`Vec3` compatible object + radius: circle radius + start_angle: start angle in degrees + end_angle: end angle in degrees + segments: count of Bèzier-curve segments, at least one segment for each + quarter (90 deg), 1 for as few as possible. + + """ + center_: Vec3 = Vec3(center) + radius = float(radius) + angle_span: float = arc_angle_span_deg(start_angle, end_angle) + if abs(angle_span) < 1e-9: + return + + s: float = start_angle + start_angle = math.radians(s) % math.tau + end_angle = math.radians(s + angle_span) + while start_angle > end_angle: + end_angle += math.tau + + for control_points in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + defpoints = [center_ + (p * radius) for p in control_points] + yield Bezier4P(defpoints) + + +PI_2: float = math.pi / 2.0 + + +def cubic_bezier_from_ellipse( + ellipse: "ConstructionEllipse", segments: int = 1 +) -> Iterator[Bezier4P[Vec3]]: + """Returns an approximation for an elliptic arc by multiple cubic + Bézier-curves. + + Args: + ellipse: ellipse parameters as :class:`~ezdxf.math.ConstructionEllipse` + object + segments: count of Bèzier-curve segments, at least one segment for each + quarter (π/2), 1 for as few as possible. + + """ + param_span: float = ellipse.param_span + if abs(param_span) < 1e-9: + return + start_angle: float = ellipse.start_param % math.tau + end_angle: float = start_angle + param_span + while start_angle > end_angle: + end_angle += math.tau + + def transform(points: Iterable[Vec3]) -> Iterator[Vec3]: + center = Vec3(ellipse.center) + x_axis: Vec3 = ellipse.major_axis + y_axis: Vec3 = ellipse.minor_axis + for p in points: + yield center + x_axis * p.x + y_axis * p.y + + for defpoints in cubic_bezier_arc_parameters(start_angle, end_angle, segments): + yield Bezier4P(tuple(transform(defpoints))) + + +# Circular arc to Bezier curve: +# Source: https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves +# Optimization: https://spencermortensen.com/articles/bezier-circle/ +# actual c = 0.5522847498307935 = 4.0/3.0*(sqrt(2)-1.0) and max. deviation of ~0.03% +DEFAULT_TANGENT_FACTOR = 4.0 / 3.0 # 1.333333333333333333 +# optimal c = 0.551915024494 and max. deviation of ~0.02% +OPTIMIZED_TANGENT_FACTOR = 1.3324407374108935 +# Not sure if this is the correct way to apply this optimization, +# so i stick to the original version for now: +TANGENT_FACTOR = DEFAULT_TANGENT_FACTOR + + +def cubic_bezier_arc_parameters( + start_angle: float, end_angle: float, segments: int = 1 +) -> Iterator[tuple[Vec3, Vec3, Vec3, Vec3]]: + """Yields cubic Bézier-curve parameters for a circular 2D arc with center + at (0, 0) and a radius of 1 in the form of [start point, 1. control point, + 2. control point, end point]. + + Args: + start_angle: start angle in radians + end_angle: end angle in radians (end_angle > start_angle!) + segments: count of Bèzier-curve segments, at least one segment for each + quarter (π/2) + + """ + if segments < 1: + raise ValueError("Invalid argument segments (>= 1).") + delta_angle: float = end_angle - start_angle + if delta_angle > 0: + arc_count = max(math.ceil(delta_angle / math.pi * 2.0), segments) + else: + raise ValueError("Delta angle from start- to end angle has to be > 0.") + + segment_angle: float = delta_angle / arc_count + tangent_length: float = TANGENT_FACTOR * math.tan(segment_angle / 4.0) + + angle: float = start_angle + end_point: Vec3 = Vec3.from_angle(angle) + for _ in range(arc_count): + start_point = end_point + angle += segment_angle + end_point = Vec3.from_angle(angle) + control_point_1 = start_point + ( + -start_point.y * tangent_length, + start_point.x * tangent_length, + ) + control_point_2 = end_point + ( + end_point.y * tangent_length, + -end_point.x * tangent_length, + ) + yield start_point, control_point_1, control_point_2, end_point diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_bspline.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_bspline.py new file mode 100644 index 0000000..a6a09e6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_bspline.py @@ -0,0 +1,275 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +# Pure Python implementation of the B-spline basis function. +from __future__ import annotations +from typing import Iterable, Sequence, Optional +import math +import bisect + +# The pure Python implementation can't import from ._ctypes or ezdxf.math! +from ._vector import Vec3, NULLVEC +from .linalg import binomial_coefficient + +__all__ = ["Basis", "Evaluator"] + + +class Basis: + """Immutable Basis function class.""" + + __slots__ = ("_knots", "_weights", "_order", "_count") + + def __init__( + self, + knots: Iterable[float], + order: int, + count: int, + weights: Optional[Sequence[float]] = None, + ): + self._knots = tuple(knots) + self._weights = tuple(weights or []) + self._order: int = int(order) + self._count: int = int(count) + + # validation checks: + len_weights = len(self._weights) + if len_weights != 0 and len_weights != self._count: + raise ValueError("invalid weight count") + if len(self._knots) != self._order + self._count: + raise ValueError("invalid knot count") + + @property + def max_t(self) -> float: + return self._knots[-1] + + @property + def order(self) -> int: + return self._order + + @property + def degree(self) -> int: + return self._order - 1 + + @property + def knots(self) -> tuple[float, ...]: + return self._knots + + @property + def weights(self) -> tuple[float, ...]: + return self._weights + + @property + def is_rational(self) -> bool: + """Returns ``True`` if curve is a rational B-spline. (has weights)""" + return bool(self._weights) + + def basis_vector(self, t: float) -> list[float]: + """Returns the expanded basis vector.""" + span = self.find_span(t) + p = self._order - 1 + front = span - p + back = self._count - span - 1 + basis = self.basis_funcs(span, t) + return ([0.0] * front) + basis + ([0.0] * back) + + def find_span(self, u: float) -> int: + """Determine the knot span index.""" + # Linear search is more reliable than binary search of the Algorithm A2.1 + # from The NURBS Book by Piegl & Tiller. + knots = self._knots + count = self._count # text book: n+1 + if u >= knots[count]: # special case + return count - 1 # n + p = self._order - 1 + # common clamped spline: + if knots[p] == 0.0: # use binary search + # This is fast and works most of the time, + # but Test 621 : test_weired_closed_spline() + # goes into an infinity loop, because of + # a weird knot configuration. + return bisect.bisect_right(knots, u, p, count) - 1 + else: # use linear search + span = 0 + while knots[span] <= u and span < count: + span += 1 + return span - 1 + + def basis_funcs(self, span: int, u: float) -> list[float]: + # Source: The NURBS Book: Algorithm A2.2 + order = self._order + knots = self._knots + N = [0.0] * order + left = list(N) + right = list(N) + N[0] = 1.0 + for j in range(1, order): + left[j] = u - knots[max(0, span + 1 - j)] + right[j] = knots[span + j] - u + saved = 0.0 + for r in range(j): + temp = N[r] / (right[r + 1] + left[j - r]) + N[r] = saved + right[r + 1] * temp + saved = left[j - r] * temp + N[j] = saved + if self.is_rational: + return self.span_weighting(N, span) + else: + return N + + def span_weighting(self, nbasis: list[float], span: int) -> list[float]: + size = len(nbasis) + weights = self._weights[span - self._order + 1 : span + 1] + products = [nb * w for nb, w in zip(nbasis, weights)] + s = sum(products) + return [0.0] * size if s == 0.0 else [p / s for p in products] + + def basis_funcs_derivatives(self, span: int, u: float, n: int = 1): + # Source: The NURBS Book: Algorithm A2.3 + order = self._order + p = order - 1 + n = min(n, p) + + knots = self._knots + left = [1.0] * order + right = [1.0] * order + ndu = [[1.0] * order for _ in range(order)] + + for j in range(1, order): + left[j] = u - knots[max(0, span + 1 - j)] + right[j] = knots[span + j] - u + saved = 0.0 + for r in range(j): + # lower triangle + ndu[j][r] = right[r + 1] + left[j - r] + temp = ndu[r][j - 1] / ndu[j][r] + # upper triangle + ndu[r][j] = saved + (right[r + 1] * temp) + saved = left[j - r] * temp + ndu[j][j] = saved + + # load the basis_vector functions + derivatives = [[0.0] * order for _ in range(order)] + for j in range(order): + derivatives[0][j] = ndu[j][p] + + # loop over function index + a = [[1.0] * order, [1.0] * order] + for r in range(order): + s1 = 0 + s2 = 1 + # alternate rows in array a + a[0][0] = 1.0 + + # loop to compute kth derivative + for k in range(1, n + 1): + d = 0.0 + rk = r - k + pk = p - k + if r >= k: + a[s2][0] = a[s1][0] / ndu[pk + 1][rk] + d = a[s2][0] * ndu[rk][pk] + if rk >= -1: + j1 = 1 + else: + j1 = -rk + if (r - 1) <= pk: + j2 = k - 1 + else: + j2 = p - r + for j in range(j1, j2 + 1): + a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][rk + j] + d += a[s2][j] * ndu[rk + j][pk] + if r <= pk: + a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r] + d += a[s2][k] * ndu[r][pk] + derivatives[k][r] = d + + # Switch rows + s1, s2 = s2, s1 + + # Multiply through by the correct factors + r = float(p) # type: ignore + for k in range(1, n + 1): + for j in range(order): + derivatives[k][j] *= r + r *= p - k + return derivatives[: n + 1] + + +class Evaluator: + """B-spline curve point and curve derivative evaluator.""" + + __slots__ = ["_basis", "_control_points"] + + def __init__(self, basis: Basis, control_points: Sequence[Vec3]): + self._basis = basis + self._control_points = control_points + + def point(self, u: float) -> Vec3: + # Source: The NURBS Book: Algorithm A3.1 + basis = self._basis + control_points = self._control_points + if math.isclose(u, basis.max_t): + u = basis.max_t + + p = basis.degree + span = basis.find_span(u) + N = basis.basis_funcs(span, u) + return Vec3.sum( + N[i] * control_points[span - p + i] for i in range(p + 1) + ) + + def points(self, t: Iterable[float]) -> Iterable[Vec3]: + for u in t: + yield self.point(u) + + def derivative(self, u: float, n: int = 1) -> list[Vec3]: + """Return point and derivatives up to n <= degree for parameter u.""" + # Source: The NURBS Book: Algorithm A3.2 + basis = self._basis + control_points = self._control_points + if math.isclose(u, basis.max_t): + u = basis.max_t + + p = basis.degree + span = basis.find_span(u) + basis_funcs_ders = basis.basis_funcs_derivatives(span, u, n) + if basis.is_rational: + # Homogeneous point representation required: + # (x*w, y*w, z*w, w) + CKw: list[Vec3] = [] + wders: list[float] = [] + weights = basis.weights + for k in range(n + 1): + v = NULLVEC + wder = 0.0 + for j in range(p + 1): + index = span - p + j + bas_func_weight = basis_funcs_ders[k][j] * weights[index] + # control_point * weight * bas_func_der = (x*w, y*w, z*w) * bas_func_der + v += control_points[index] * bas_func_weight + wder += bas_func_weight + CKw.append(v) + wders.append(wder) + + # Source: The NURBS Book: Algorithm A4.2 + CK: list[Vec3] = [] + for k in range(n + 1): + v = CKw[k] + for i in range(1, k + 1): + v -= binomial_coefficient(k, i) * wders[i] * CK[k - i] + CK.append(v / wders[0]) + else: + CK = [ + Vec3.sum( + basis_funcs_ders[k][j] * control_points[span - p + j] + for j in range(p + 1) + ) + for k in range(n + 1) + ] + return CK + + def derivatives( + self, t: Iterable[float], n: int = 1 + ) -> Iterable[list[Vec3]]: + for u in t: + yield self.derivative(u, n) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_construct.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_construct.py new file mode 100644 index 0000000..10d4ff0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_construct.py @@ -0,0 +1,362 @@ +# Copyright (c) 2011-2024, Manfred Moitzi +# License: MIT License +# These are the pure Python implementations of the Cython accelerated +# construction tools: ezdxf/acc/construct.pyx +from __future__ import annotations +from typing import Iterable, Sequence, Optional, TYPE_CHECKING +import math + +# The pure Python implementation can't import from ._ctypes or ezdxf.math! +from ._vector import Vec2, Vec3 + +if TYPE_CHECKING: + from ezdxf.math import UVec + +TOLERANCE = 1e-10 +RAD_ABS_TOL = 1e-15 +DEG_ABS_TOL = 1e-13 + + +def has_clockwise_orientation(vertices: Iterable[UVec]) -> bool: + """Returns ``True`` if the given 2D `vertices` have clockwise orientation. + Ignores the z-axis of all vertices. + + Args: + vertices: iterable of :class:`Vec2` compatible objects + + Raises: + ValueError: less than 3 vertices + + """ + vertices = Vec2.list(vertices) + if len(vertices) < 3: + raise ValueError("At least 3 vertices required.") + + # close polygon: + if not vertices[0].isclose(vertices[-1]): + vertices.append(vertices[0]) + + return ( + sum( + (p2.x - p1.x) * (p2.y + p1.y) + for p1, p2 in zip(vertices, vertices[1:]) + ) + > 0.0 + ) + + +def intersection_line_line_2d( + line1: Sequence[Vec2], + line2: Sequence[Vec2], + virtual=True, + abs_tol=TOLERANCE, +) -> Optional[Vec2]: + """ + Compute the intersection of two lines in the xy-plane. + + Args: + line1: start- and end point of first line to test + e.g. ((x1, y1), (x2, y2)). + line2: start- and end point of second line to test + e.g. ((x3, y3), (x4, y4)). + virtual: ``True`` returns any intersection point, ``False`` returns + only real intersection points. + abs_tol: tolerance for intersection test. + + Returns: + ``None`` if there is no intersection point (parallel lines) or + intersection point as :class:`Vec2` + + """ + # Algorithm based on: http://paulbourke.net/geometry/pointlineplane/ + # chapter: Intersection point of two line segments in 2 dimensions + s1, s2 = line1 # the subject line + c1, c2 = line2 # the clipping line + s1x = s1.x + s1y = s1.y + s2x = s2.x + s2y = s2.y + c1x = c1.x + c1y = c1.y + c2x = c2.x + c2y = c2.y + + den = (c2y - c1y) * (s2x - s1x) - (c2x - c1x) * (s2y - s1y) + if math.fabs(den) <= abs_tol: + return None + + us = ((c2x - c1x) * (s1y - c1y) - (c2y - c1y) * (s1x - c1x)) / den + intersection_point = Vec2(s1x + us * (s2x - s1x), s1y + us * (s2y - s1y)) + if virtual: + return intersection_point + + # 0 = intersection point is the start point of the line + # 1 = intersection point is the end point of the line + # otherwise: linear interpolation + lwr = 0.0 # tolerances required? + upr = 1.0 # tolerances required? + if lwr <= us <= upr: # intersection point is on the subject line + uc = ((s2x - s1x) * (s1y - c1y) - (s2y - s1y) * (s1x - c1x)) / den + if lwr <= uc <= upr: # intersection point is on the clipping line + return intersection_point + return None + + +def _determinant(v1, v2, v3) -> float: + """Returns determinant.""" + e11, e12, e13 = v1 + e21, e22, e23 = v2 + e31, e32, e33 = v3 + + return ( + e11 * e22 * e33 + + e12 * e23 * e31 + + e13 * e21 * e32 + - e13 * e22 * e31 + - e11 * e23 * e32 + - e12 * e21 * e33 + ) + + +def intersection_ray_ray_3d( + ray1: Sequence[Vec3], ray2: Sequence[Vec3], abs_tol=TOLERANCE +) -> Sequence[Vec3]: + """ + Calculate intersection of two 3D rays, returns a 0-tuple for parallel rays, + a 1-tuple for intersecting rays and a 2-tuple for not intersecting and not + parallel rays with points of the closest approach on each ray. + + Args: + ray1: first ray as tuple of two points as :class:`Vec3` objects + ray2: second ray as tuple of two points as :class:`Vec3` objects + abs_tol: absolute tolerance for comparisons + + """ + # source: http://www.realtimerendering.com/intersections.html#I304 + o1, p1 = ray1 + d1 = (p1 - o1).normalize() + o2, p2 = ray2 + d2 = (p2 - o2).normalize() + d1xd2 = d1.cross(d2) + denominator = d1xd2.magnitude_square + if denominator <= abs_tol: + # ray1 is parallel to ray2 + return tuple() + else: + o2_o1 = o2 - o1 + det1 = _determinant(o2_o1, d2, d1xd2) + det2 = _determinant(o2_o1, d1, d1xd2) + p1 = o1 + d1 * (det1 / denominator) + p2 = o2 + d2 * (det2 / denominator) + if p1.isclose(p2, abs_tol=abs_tol): + # ray1 and ray2 have an intersection point + return (p1,) + else: + # ray1 and ray2 do not have an intersection point, + # p1 and p2 are the points of closest approach on each ray + return p1, p2 + + +def arc_angle_span_deg(start: float, end: float) -> float: + """Returns the counter-clockwise angle span from `start` to `end` in degrees. + + Returns the angle span in the range of [0, 360], 360 is a full circle. + Full circle handling is a special case, because normalization of angles + which describe a full circle would return 0 if treated as regular angles. + e.g. (0, 360) → 360, (0, -360) → 360, (180, -180) → 360. + Input angles with the same value always return 0 by definition: (0, 0) → 0, + (-180, -180) → 0, (360, 360) → 0. + + """ + # Input values are equal, returns 0 by definition: + if math.isclose(start, end, abs_tol=DEG_ABS_TOL): + return 0.0 + + # Normalized start- and end angles are equal, but input values are + # different, returns 360 by definition: + start %= 360.0 + if math.isclose(start, end % 360.0, abs_tol=DEG_ABS_TOL): + return 360.0 + + # Special treatment for end angle == 360 deg: + if not math.isclose(end, 360.0, abs_tol=DEG_ABS_TOL): + end %= 360.0 + + if end < start: + end += 360.0 + return end - start + + +def arc_angle_span_rad(start: float, end: float) -> float: + """Returns the counter-clockwise angle span from `start` to `end` in radians. + + Returns the angle span in the range of [0, 2π], 2π is a full circle. + Full circle handling is a special case, because normalization of angles + which describe a full circle would return 0 if treated as regular angles. + e.g. (0, 2π) → 2π, (0, -2π) → 2π, (π, -π) → 2π. + Input angles with the same value always return 0 by definition: (0, 0) → 0, + (-π, -π) → 0, (2π, 2π) → 0. + + """ + tau = math.tau + # Input values are equal, returns 0 by definition: + if math.isclose(start, end, abs_tol=RAD_ABS_TOL): + return 0.0 + + # Normalized start- and end angles are equal, but input values are + # different, returns 360 by definition: + start %= tau + if math.isclose(start, end % tau, abs_tol=RAD_ABS_TOL): + return tau + + # Special treatment for end angle == 2π: + if not math.isclose(end, tau, abs_tol=RAD_ABS_TOL): + end %= tau + + if end < start: + end += tau + return end - start + + +def is_point_in_polygon_2d( + point: Vec2, polygon: list[Vec2], abs_tol=TOLERANCE +) -> int: + """ + Test if `point` is inside `polygon`. Returns +1 for inside, 0 for on the + boundary and -1 for outside. + + Supports convex and concave polygons with clockwise or counter-clockwise oriented + polygon vertices. Does not raise an exception for degenerated polygons. + + + Args: + point: 2D point to test as :class:`Vec2` + polygon: list of 2D points as :class:`Vec2` + abs_tol: tolerance for distance check + + Returns: + +1 for inside, 0 for on the boundary, -1 for outside + + """ + # Source: http://www.faqs.org/faqs/graphics/algorithms-faq/ + # Subject 2.03: How do I find if a point lies within a polygon? + # polygon: the Cython implementation needs a list as input to be fast! + assert isinstance(polygon, list) + if len(polygon) < 3: # empty polygon + return -1 + + if polygon[0].isclose(polygon[-1]): # open polygon is required + polygon = polygon[:-1] + if len(polygon) < 3: + return -1 + x = point.x + y = point.y + inside = False + x1, y1 = polygon[-1] + for x2, y2 in polygon: + # is point on polygon boundary line: + # is point in x-range of line + a, b = (x2, x1) if x2 < x1 else (x1, x2) + if a <= x <= b: + # is point in y-range of line + c, d = (y2, y1) if y2 < y1 else (y1, y2) + if (c <= y <= d) and abs( + (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1) + ) <= abs_tol: + return 0 # on boundary line + if ((y1 <= y < y2) or (y2 <= y < y1)) and ( + x < (x2 - x1) * (y - y1) / (y2 - y1) + x1 + ): + inside = not inside + x1 = x2 + y1 = y2 + if inside: + return 1 # inside polygon + else: + return -1 # outside polygon + + +# Values stored in GeoData RSS tag are not precise enough to match +# control calculation at epsg.io: +# Semi Major Axis: 6.37814e+06 +# Semi Minor Axis: 6.35675e+06 +WGS84_SEMI_MAJOR_AXIS = 6378137 +WGS84_SEMI_MINOR_AXIS = 6356752.3142 +WGS84_ELLIPSOID_ECCENTRIC = 0.08181919092890624 +# WGS84_ELLIPSOID_ECCENTRIC = math.sqrt( +# 1.0 - WGS84_SEMI_MINOR_AXIS**2 / WGS84_SEMI_MAJOR_AXIS**2 +# ) +CONST_E2 = 1.3591409142295225 # math.e / 2.0 +CONST_PI_2 = 1.5707963267948966 # math.pi / 2.0 +CONST_PI_4 = 0.7853981633974483 # math.pi / 4.0 + + +def gps_to_world_mercator(longitude: float, latitude: float) -> tuple[float, float]: + """Transform GPS (long/lat) to World Mercator. + + Transform WGS84 `EPSG:4326 `_ location given as + latitude and longitude in decimal degrees as used by GPS into World Mercator + cartesian 2D coordinates in meters `EPSG:3395 `_. + + Args: + longitude: represents the longitude value (East-West) in decimal degrees + latitude: represents the latitude value (North-South) in decimal degrees. + + .. versionadded:: 1.3.0 + + """ + # From: https://epsg.io/4326 + # EPSG:4326 WGS84 - World Geodetic System 1984, used in GPS + # To: https://epsg.io/3395 + # EPSG:3395 - World Mercator + # Source: https://gis.stackexchange.com/questions/259121/transformation-functions-for-epsg3395-projection-vs-epsg3857 + longitude = math.radians(longitude) # east + latitude = math.radians(latitude) # north + a = WGS84_SEMI_MAJOR_AXIS + e = WGS84_ELLIPSOID_ECCENTRIC + e_sin_lat = math.sin(latitude) * e + c = math.pow((1.0 - e_sin_lat) / (1.0 + e_sin_lat), e / 2.0) # 7-7 p.44 + y = a * math.log(math.tan(CONST_PI_4 + latitude / 2.0) * c) # 7-7 p.44 + x = a * longitude + return x, y + + +def world_mercator_to_gps(x: float, y: float, tol: float = 1e-6) -> tuple[float, float]: + """Transform World Mercator to GPS. + + Transform WGS84 World Mercator `EPSG:3395 `_ + location given as cartesian 2D coordinates x, y in meters into WGS84 decimal + degrees as longitude and latitude `EPSG:4326 `_ as + used by GPS. + + Args: + x: coordinate WGS84 World Mercator + y: coordinate WGS84 World Mercator + tol: accuracy for latitude calculation + + .. versionadded:: 1.3.0 + + """ + # From: https://epsg.io/3395 + # EPSG:3395 - World Mercator + # To: https://epsg.io/4326 + # EPSG:4326 WGS84 - World Geodetic System 1984, used in GPS + # Source: Map Projections - A Working Manual + # https://pubs.usgs.gov/pp/1395/report.pdf + a = WGS84_SEMI_MAJOR_AXIS + e = WGS84_ELLIPSOID_ECCENTRIC + e2 = e / 2.0 + pi2 = CONST_PI_2 + t = math.e ** (-y / a) # 7-10 p.44 + latitude_ = pi2 - 2.0 * math.atan(t) # 7-11 p.45 + while True: + e_sin_lat = math.sin(latitude_) * e + latitude = pi2 - 2.0 * math.atan( + t * ((1.0 - e_sin_lat) / (1.0 + e_sin_lat)) ** e2 + ) # 7-9 p.44 + if abs(latitude - latitude_) < tol: + break + latitude_ = latitude + + longitude = x / a # 7-12 p.45 + return math.degrees(longitude), math.degrees(latitude) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_ctypes.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_ctypes.py new file mode 100644 index 0000000..7e404fd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_ctypes.py @@ -0,0 +1,101 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from typing import Union, Sequence +from typing_extensions import TypeAlias +# noinspection PyUnresolvedReferences +from ezdxf.acc import USE_C_EXT + +__all__ = [ + "Vec3", + "Vec2", + "AnyVec", + "UVec", + "X_AXIS", + "Y_AXIS", + "Z_AXIS", + "NULLVEC", + "distance", + "lerp", + "Matrix44", + "Bezier4P", + "Bezier3P", + "Basis", + "Evaluator", + "cubic_bezier_arc_parameters", + "cubic_bezier_from_arc", + "cubic_bezier_from_ellipse", + "has_clockwise_orientation", + "intersection_line_line_2d", + "intersection_ray_ray_3d", + "arc_angle_span_deg", + "arc_angle_span_rad", + "is_point_in_polygon_2d", + "world_mercator_to_gps", + "gps_to_world_mercator", +] +# Import of Python or Cython implementations: +if USE_C_EXT: + from ezdxf.acc.vector import ( + Vec3, + Vec2, + X_AXIS, + Y_AXIS, + Z_AXIS, + NULLVEC, + distance, + lerp, + ) + from ezdxf.acc.matrix44 import Matrix44 + from ezdxf.acc.bezier4p import ( + Bezier4P, + cubic_bezier_arc_parameters, + cubic_bezier_from_arc, + cubic_bezier_from_ellipse, + ) + from ezdxf.acc.bezier3p import Bezier3P + from ezdxf.acc.bspline import Basis, Evaluator + from ezdxf.acc.construct import ( + has_clockwise_orientation, + intersection_line_line_2d, + intersection_ray_ray_3d, + arc_angle_span_deg, + arc_angle_span_rad, + is_point_in_polygon_2d, + world_mercator_to_gps, + gps_to_world_mercator, + + ) +else: + from ._vector import ( + Vec3, + Vec2, + X_AXIS, + Y_AXIS, + Z_AXIS, + NULLVEC, + distance, + lerp, + ) + from ._matrix44 import Matrix44 + from ._bezier4p import ( + Bezier4P, + cubic_bezier_arc_parameters, + cubic_bezier_from_arc, + cubic_bezier_from_ellipse, + ) + from ._bezier3p import Bezier3P + from ._bspline import Basis, Evaluator + from ._construct import ( + has_clockwise_orientation, + intersection_line_line_2d, + intersection_ray_ray_3d, + arc_angle_span_deg, + arc_angle_span_rad, + is_point_in_polygon_2d, + world_mercator_to_gps, + gps_to_world_mercator, + ) + +# Early required type aliases +AnyVec: TypeAlias = Union[Vec2, Vec3] +UVec: TypeAlias = Union[Sequence[float], Vec2, Vec3] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_mapbox_earcut.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_mapbox_earcut.py new file mode 100644 index 0000000..adf9ee9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_mapbox_earcut.py @@ -0,0 +1,831 @@ +# Source: https://github.com/mapbox/earcut +# License: ISC License (MIT compatible) +# +# Copyright (c) 2016, Mapbox +# +# Permission to use, copy, modify, and/or distribute this software for any purpose +# with or without fee is hereby granted, provided that the above copyright notice +# and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +# THIS SOFTWARE. +# +# The Algorithm +# ------------- +# The library implements a modified ear slicing algorithm, optimized by z-order +# curve hashing and extended to handle holes, twisted polygons, degeneracies and +# self-intersections in a way that doesn't guarantee correctness of triangulation, +# but attempts to always produce acceptable results for practical data. +# +# Translation to Python: +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +# +# Notes +# ----- +# Exterior path (outer path) vertices are stored in counter-clockwise order +# Hole vertices are stored in clockwise order +# Vertex order will be maintained by the algorithm automatically. +# Boundary behavior for holes: +# - holes outside the exterior path are ignored +# - invalid result for holes partially extending beyond the exterior path +# - invalid result for overlapping holes +# - invalid result for holes in holes +# Very stable in all circumstances - DOES NOT CRASH! +# +# Steiner Point +# ------------- +# https://en.wikipedia.org/wiki/Steiner_point_(computational_geometry) +# A Steiner point is a point that is not part of the input to a geometric +# optimization problem but is added during the solution of the problem, to +# create a better solution than would be possible from the original points +# alone. +# A Steiner point is defined as a hole with a single point! +# +from __future__ import annotations +from typing import Sequence, Optional, Protocol, TypeVar + +import math + + +class Point(Protocol): + x: float + y: float + + +class Node: + def __init__(self, i: int, point: Point) -> None: + self.i: int = i + + # store source point for output + self.point = point + + # vertex coordinates + self.x: float = point.x + self.y: float = point.y + + # previous and next vertex nodes in a polygon ring + self.prev: Node = None # type: ignore + self.next: Node = None # type: ignore + + # z-order curve value + self.z: int = 0 + + # previous and next nodes in z-order + self.prev_z: Node = None # type: ignore + self.next_z: Node = None # type: ignore + + # indicates whether this is a steiner point + self.steiner: bool = False + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + +T = TypeVar("T", bound=Point) + + +def earcut(exterior: list[T], holes: list[list[T]]) -> list[Sequence[T]]: + """Implements a modified ear slicing algorithm, optimized by z-order + curve hashing and extended to handle holes, twisted polygons, degeneracies + and self-intersections in a way that doesn't guarantee correctness of + triangulation, but attempts to always produce acceptable results for + practical data. + + Source: https://github.com/mapbox/earcut + + Args: + exterior: outer path as list of points as objects which provide a + `x`- and a `y`-attribute + holes: list of holes, each hole is list of points, a hole with + a single points is a Steiner point + + Returns: + Returns a list of triangles, each triangle is a tuple of three points, + the output points are the same objects as the input points. + + """ + # exterior points in counter-clockwise order + outer_node: Node = linked_list(exterior, 0, ccw=True) + triangles: list[Sequence[T]] = [] + + if outer_node is None or outer_node.next is outer_node.prev: + return triangles + + if len(holes) > 0: + outer_node = eliminate_holes(holes, len(exterior), outer_node) + + min_x: float = 0.0 + min_y: float = 0.0 + inv_size: float = 0.0 + + # if the shape is not too simple, we'll use z-order curve hash later + # calculate polygon bbox + if len(exterior) > 80: + min_x = max_x = exterior[0].x + min_y = max_y = exterior[0].y + for point in exterior: + x = point.x + y = point.y + min_x = min(min_x, x) + min_y = min(min_y, y) + max_x = max(max_x, x) + max_y = max(max_y, y) + + # min_x, min_y and inv_size are later used to transform coords into + # integers for z-order calculation + inv_size = max(max_x - min_x, max_y - min_y) + inv_size = 32767 / inv_size if inv_size != 0 else 0 + + earcut_linked(outer_node, triangles, min_x, min_y, inv_size, 0) # type: ignore + return triangles + + +def linked_list(points: Sequence[Point], start: int, ccw: bool) -> Node: + """Create a circular doubly linked list from polygon points in the specified + winding order + """ + last: Node = None # type: ignore + if ccw is (signed_area(points) < 0): + for point in points: + last = insert_node(start, point, last) + start += 1 + else: + end = start + len(points) + for point in reversed(points): + last = insert_node(end, point, last) + end -= 1 + + # open polygon: where the 1st vertex is not coincident with the last vertex + if last and last == last.next: # true equals + remove_node(last) + last = last.next + return last + + +def signed_area(points: Sequence[Point]) -> float: + s: float = 0.0 + if not len(points): + return s + prev = points[-1] + for point in points: + s += (point.x - prev.x) * (point.y + prev.y) + prev = point + # s < 0 is counter-clockwise + # s > 0 is clockwise + return s + + +def area(p: Node, q: Node, r: Node) -> float: + """Returns signed area of a triangle""" + return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) + + +def is_valid_diagonal(a: Node, b: Node): + """Check if a diagonal between two polygon nodes is valid (lies in polygon + interior) + """ + return ( + a.next.i != b.i + and a.prev.i != b.i + and not intersects_polygon(a, b) # doesn't intersect other edges + and ( + locally_inside(a, b) + and locally_inside(b, a) + and middle_inside(a, b) + and ( + area(a.prev, a, b.prev) or area(a, b.prev, b) + ) # does not create opposite-facing sectors + or a == b # true equals + and area(a.prev, a, a.next) > 0 + and area(b.prev, b, b.next) > 0 + ) # special zero-length case + ) + + +def intersects_polygon(a: Node, b: Node) -> bool: + """Check if a polygon diagonal intersects any polygon segments""" + p = a + while True: + if ( + p.i != a.i + and p.next.i != a.i + and p.i != b.i + and p.next.i != b.i + and intersects(p, p.next, a, b) + ): + return True + p = p.next + if p is a: + break + return False + + +def sign(num: float) -> int: + if num < 0.0: + return -1 + if num > 0.0: + return 1 + return 0 + + +def on_segment(p: Node, q: Node, r: Node) -> bool: + return max(p.x, r.x) >= q.x >= min(p.x, r.x) and max(p.y, r.y) >= q.y >= min( + p.y, r.y + ) + + +def intersects(p1: Node, q1: Node, p2: Node, q2: Node) -> bool: + """check if two segments intersect""" + o1 = sign(area(p1, q1, p2)) + o2 = sign(area(p1, q1, q2)) + o3 = sign(area(p2, q2, p1)) + o4 = sign(area(p2, q2, q1)) + + if o1 != o2 and o3 != o4: + return True # general case + + if o1 == 0 and on_segment(p1, p2, q1): + return True # p1, q1 and p2 are collinear and p2 lies on p1q1 + if o2 == 0 and on_segment(p1, q2, q1): + return True # p1, q1 and q2 are collinear and q2 lies on p1q1 + if o3 == 0 and on_segment(p2, p1, q2): + return True # p2, q2 and p1 are collinear and p1 lies on p2q2 + if o4 == 0 and on_segment(p2, q1, q2): + return True # p2, q2 and q1 are collinear and q1 lies on p2q2 + return False + + +def insert_node(i: int, point: Point, last: Node) -> Node: + """create a node and optionally link it with previous one (in a circular + doubly linked list) + """ + p = Node(i, point) + + if last is None: + p.prev = p + p.next = p + else: + p.next = last.next + p.prev = last + last.next.prev = p + last.next = p + return p + + +def remove_node(p: Node) -> None: + p.next.prev = p.prev + p.prev.next = p.next + + if p.prev_z: + p.prev_z.next_z = p.next_z + if p.next_z: + p.next_z.prev_z = p.prev_z + + +def eliminate_holes( + holes: Sequence[Sequence[Point]], start: int, outer_node: Node +) -> Node: + """link every hole into the outer loop, producing a single-ring polygon + without holes + """ + queue: list[Node] = [] + for hole in holes: + if len(hole) < 1: # skip empty holes + continue + # hole vertices in clockwise order + _list = linked_list(hole, start, ccw=False) + if _list is _list.next: + _list.steiner = True + start += len(hole) + queue.append(get_leftmost(_list)) + queue.sort(key=lambda node: (node.x, node.y)) + + # process holes from left to right + for hole_ in queue: + outer_node = eliminate_hole(hole_, outer_node) + return outer_node + + +def eliminate_hole(hole: Node, outer_node: Node) -> Node: + """Find a bridge between vertices that connects hole with an outer ring and + link it + """ + bridge = find_hole_bridge(hole, outer_node) + if bridge is None: + return outer_node + + bridge_reverse = split_polygon(bridge, hole) + + # filter collinear points around the cuts + filter_points(bridge_reverse, bridge_reverse.next) + return filter_points(bridge, bridge.next) + + +def filter_points(start: Node, end: Optional[Node] = None) -> Node: + """eliminate colinear or duplicate points""" + if start is None: + return start + if end is None: + end = start + + p = start + + while True: + again = False + if not p.steiner and ( + p == p.next or area(p.prev, p, p.next) == 0 # true equals + ): + remove_node(p) + p = end = p.prev + if p is p.next: + break + again = True + else: + p = p.next + if not (again or p is not end): + break + return end + + +# main ear slicing loop which triangulates a polygon (given as a linked list) +def earcut_linked( + ear: Node, + triangles: list[Sequence[Point]], + min_x: float, + min_y: float, + inv_size: float, + pass_: int, +) -> None: + if ear is None: + return + + # interlink polygon nodes in z-order + if not pass_ and inv_size: + index_curve(ear, min_x, min_y, inv_size) + + stop = ear + + # iterate through ears, slicing them one by one + while ear.prev is not ear.next: + prev = ear.prev + next = ear.next + + _is_ear = ( + is_ear_hashed(ear, min_x, min_y, inv_size) if inv_size else is_ear(ear) + ) + if _is_ear: + # cut off the triangle + triangles.append((prev.point, ear.point, next.point)) + remove_node(ear) + + # skipping the next vertex leads to less sliver triangles + ear = next.next + stop = next.next + continue + + ear = next + + # if we looped through the whole remaining polygon and can't find any more ears + if ear is stop: + # try filtering points and slicing again + if not pass_: + earcut_linked( + filter_points(ear), + triangles, + min_x, + min_y, + inv_size, + 1, + ) + + # if this didn't work, try curing all small self-intersections locally + elif pass_ == 1: + ear = cure_local_intersections(filter_points(ear), triangles) + earcut_linked(ear, triangles, min_x, min_y, inv_size, 2) + + # as a last resort, try splitting the remaining polygon into two + elif pass_ == 2: + split_ear_cut(ear, triangles, min_x, min_y, inv_size) + break + + +def is_ear(ear: Node) -> bool: + """check whether a polygon node forms a valid ear with adjacent nodes""" + a: Node = ear.prev + b: Node = ear + c: Node = ear.next + + if area(a, b, c) >= 0: + return False # reflex, can't be an ear + + # now make sure we don't have other points inside the potential ear + ax = a.x + bx = b.x + cx = c.x + ay = a.y + by = b.y + cy = c.y + + # triangle bbox; min & max are calculated like this for speed + x0 = min(ax, bx, cx) + x1 = max(ax, bx, cx) + y0 = min(ay, by, cy) + y1 = max(ay, by, cy) + p: Node = c.next + + while p is not a: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and point_in_triangle(ax, ay, bx, by, cx, cy, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.next + + return True + + +def is_ear_hashed(ear: Node, min_x: float, min_y: float, inv_size: float): + a: Node = ear.prev + b: Node = ear + c: Node = ear.next + + if area(a, b, c) >= 0: + return False # reflex, can't be an ear + + ax = a.x + bx = b.x + cx = c.x + ay = a.y + by = b.y + cy = c.y + + # triangle bbox; min & max are calculated like this for speed + x0 = min(ax, bx, cx) + x1 = max(ax, bx, cx) + y0 = min(ay, by, cy) + y1 = max(ay, by, cy) + + # z-order range for the current triangle bbox; + min_z = z_order(x0, y0, min_x, min_y, inv_size) + max_z = z_order(x1, y1, min_x, min_y, inv_size) + + p: Node = ear.prev_z + n: Node = ear.next_z + + # look for points inside the triangle in both directions + while p and p.z >= min_z and n and n.z <= max_z: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and p is not a + and p is not c + and point_in_triangle(ax, ay, bx, by, cx, cy, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.prev_z + + if ( + x0 <= n.x <= x1 + and y0 <= n.y <= y1 + and n is not a + and n is not c + and point_in_triangle(ax, ay, bx, by, cx, cy, n.x, n.y) + and area(n.prev, n, n.next) >= 0 + ): + return False + n = n.next_z + + # look for remaining points in decreasing z-order + while p and p.z >= min_z: + if ( + x0 <= p.x <= x1 + and y0 <= p.y <= y1 + and p is not a + and p is not c + and point_in_triangle(ax, ay, bx, by, cx, cy, p.x, p.y) + and area(p.prev, p, p.next) >= 0 + ): + return False + p = p.prev_z + + # look for remaining points in increasing z-order + while n and n.z <= max_z: + if ( + x0 <= n.x <= x1 + and y0 <= n.y <= y1 + and n is not a + and n is not c + and point_in_triangle(ax, ay, bx, by, cx, cy, n.x, n.y) + and area(n.prev, n, n.next) >= 0 + ): + return False + n = n.next_z + return True + + +def get_leftmost(start: Node) -> Node: + """Find the leftmost node of a polygon ring""" + p = start + leftmost = start + while True: + if p.x < leftmost.x or (p.x == leftmost.x and p.y < leftmost.y): + leftmost = p + p = p.next + if p is start: + break + return leftmost + + +def point_in_triangle( + ax: float, + ay: float, + bx: float, + by: float, + cx: float, + cy: float, + px: float, + py: float, +) -> bool: + """Check if a point lies within a convex triangle""" + return ( + (cx - px) * (ay - py) >= (ax - px) * (cy - py) + and (ax - px) * (by - py) >= (bx - px) * (ay - py) + and (bx - px) * (cy - py) >= (cx - px) * (by - py) + ) + + +def sector_contains_sector(m: Node, p: Node): + """Whether sector in vertex m contains sector in vertex p in the same + coordinates. + """ + return area(m.prev, m, p.prev) < 0 and area(p.next, m, m.next) < 0 + + +def index_curve(start: Node, min_x: float, min_y: float, inv_size: float): + """Interlink polygon nodes in z-order""" + p = start + while True: + if p.z == 0: + p.z = z_order(p.x, p.y, min_x, min_y, inv_size) + p.prev_z = p.prev + p.next_z = p.next + p = p.next + if p is start: + break + + p.prev_z.next_z = None # type: ignore + p.prev_z = None # type: ignore + + sort_linked(p) + + +def z_order(x0: float, y0: float, min_x: float, min_y: float, inv_size: float) -> int: + """Z-order of a point given coords and inverse of the longer side of data + bbox. + """ + # coords are transformed into non-negative 15-bit integer range + x = int((x0 - min_x) * inv_size) + y = int((y0 - min_y) * inv_size) + + x = (x | (x << 8)) & 0x00FF00FF + x = (x | (x << 4)) & 0x0F0F0F0F + x = (x | (x << 2)) & 0x33333333 + x = (x | (x << 1)) & 0x55555555 + + y = (y | (y << 8)) & 0x00FF00FF + y = (y | (y << 4)) & 0x0F0F0F0F + y = (y | (y << 2)) & 0x33333333 + y = (y | (y << 1)) & 0x55555555 + + return x | (y << 1) + + +# Simon Tatham's linked list merge sort algorithm +# http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +def sort_linked(head: Node) -> Node: + in_size = 1 + tail: Node + while True: + p = head + head = None # type: ignore + tail = None # type: ignore + num_merges = 0 + while p: + num_merges += 1 + q = p + p_size = 0 + for i in range(in_size): + p_size += 1 + q = q.next_z + if not q: + break + q_size = in_size + while p_size > 0 or (q_size > 0 and q): + if p_size != 0 and (q_size == 0 or not q or p.z <= q.z): + e = p + p = p.next_z + p_size -= 1 + else: + e = q + q = q.next_z + q_size -= 1 + + if tail: + tail.next_z = e + else: + head = e + e.prev_z = tail + tail = e + p = q + tail.next_z = None # type: ignore + in_size *= 2 + if num_merges <= 1: + break + return head + + +def split_polygon(a: Node, b: Node) -> Node: + """Link two polygon vertices with a bridge. + + If the vertices belong to the same ring, it splits polygon into two. + If one belongs to the outer ring and another to a hole, it merges it into a + single ring. + """ + a2 = Node(a.i, a.point) + b2 = Node(b.i, b.point) + an = a.next + bp = b.prev + + a.next = b + b.prev = a + + a2.next = an + an.prev = a2 + + b2.next = a2 + a2.prev = b2 + + bp.next = b2 + b2.prev = bp + + return b2 + + +# go through all polygon nodes and cure small local self-intersections +def cure_local_intersections(start: Node, triangles: list[Sequence[Point]]) -> Node: + p = start + while True: + a = p.prev + b = p.next.next + + if ( + not a == b # true equals + and intersects(a, p, p.next, b) + and locally_inside(a, b) + and locally_inside(b, a) + ): + triangles.append((a.point, p.point, b.point)) + # remove two nodes involved + remove_node(p) + remove_node(p.next) + p = start = b + + p = p.next + if p is start: + break + return filter_points(p) + + +def split_ear_cut( + start: Node, + triangles: list[Sequence[Point]], + min_x: float, + min_y: float, + inv_size: float, +) -> None: + """Try splitting polygon into two and triangulate them independently""" + # look for a valid diagonal that divides the polygon into two + a = start + while True: + b = a.next.next + while b is not a.prev: + if a.i != b.i and is_valid_diagonal(a, b): + # split the polygon in two by the diagonal + c = split_polygon(a, b) + + # filter colinear points around the cuts + a = filter_points(a, a.next) + c = filter_points(c, c.next) + + # run earcut on each half + earcut_linked(a, triangles, min_x, min_y, inv_size, 0) + earcut_linked(c, triangles, min_x, min_y, inv_size, 0) + return + b = b.next + a = a.next + if a is start: + break + + +# David Eberly's algorithm for finding a bridge between hole and outer polygon +def find_hole_bridge(hole: Node, outer_node: Node) -> Node: + p = outer_node + hx = hole.x + hy = hole.y + qx = -math.inf + m: Node = None # type: ignore + # find a segment intersected by a ray from the hole's leftmost point to the left; + # segment's endpoint with lesser x will be potential connection point + while True: + if p.y >= hy >= p.next.y != p.y: + x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y) + if hx >= x > qx: + qx = x + m = p if p.x < p.next.x else p.next + if x == hx: # ??? use math.isclose + # hole touches outer segment; pick leftmost endpoint + return m + p = p.next + if p is outer_node: + break + + if m is None: + return None + + # look for points inside the triangle of hole point, segment intersection and endpoint; + # if there are no points found, we have a valid connection; + # otherwise choose the point of the minimum angle with the ray as connection point + stop = m + mx = m.x + my = m.y + tan_min = math.inf + p = m + + while True: + if ( + hx >= p.x >= mx + and hx != p.x + and point_in_triangle( + hx if hy < my else qx, + hy, + mx, + my, + qx if hy < my else hx, + hy, + p.x, + p.y, + ) + ): + tan = abs(hy - p.y) / (hx - p.x) # tangential + + if locally_inside(p, hole) and ( + tan < tan_min + or ( + tan == tan_min + and (p.x > m.x or (p.x == m.x and sector_contains_sector(m, p))) + ) + ): + m = p + tan_min = tan + + p = p.next + if p is stop: + break + return m + + +def locally_inside(a: Node, b: Node) -> bool: + """Check if a polygon diagonal is locally inside the polygon""" + return ( + area(a, b, a.next) >= 0 and area(a, a.prev, b) >= 0 + if area(a.prev, a, a.next) < 0 + else area(a, b, a.prev) < 0 or area(a, a.next, b) < 0 + ) + + +def middle_inside(a: Node, b: Node) -> bool: + """Check if the middle point of a polygon diagonal is inside the polygon""" + p = a + inside = False + px = (a.x + b.x) / 2 + py = (a.y + b.y) / 2 + while True: + if ( + ((p.y > py) != (p.next.y > py)) + and p.next.y != p.y + and (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) + ): + inside = not inside + p = p.next + if p is a: + break + return inside diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_matrix44.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_matrix44.py new file mode 100644 index 0000000..4ea124b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_matrix44.py @@ -0,0 +1,718 @@ +# original code from package: gameobjects +# Home-page: http://code.google.com/p/gameobjects/ +# Author: Will McGugan +# Download-URL: http://code.google.com/p/gameobjects/downloads/list +# Copyright (c) 2011-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterable, Iterator, TYPE_CHECKING, Optional +import math +import numpy as np +import numpy.typing as npt + +from math import sin, cos, tan +from itertools import chain + +# The pure Python implementation can't import from ._ctypes or ezdxf.math! +from ._vector import Vec3, X_AXIS, Y_AXIS, Z_AXIS, NULLVEC, Vec2 + +if TYPE_CHECKING: + from ezdxf.math import UVec + +__all__ = ["Matrix44"] + + +# removed array.array because array is optimized for space not speed, and space +# optimization is not needed + + +def floats(items: Iterable) -> list[float]: + return [float(v) for v in items] + + +class Matrix44: + """An optimized 4x4 `transformation matrix`_. + + The utility functions for constructing transformations and transforming + vectors and points assumes that vectors are stored as row vectors, meaning + when multiplied, transformations are applied left to right (e.g. vAB + transforms v by A then by B). + + Matrix44 initialization: + + - ``Matrix44()`` returns the identity matrix. + - ``Matrix44(values)`` values is an iterable with the 16 components of + the matrix. + - ``Matrix44(row1, row2, row3, row4)`` four rows, each row with four + values. + + .. _transformation matrix: https://en.wikipedia.org/wiki/Transformation_matrix + + """ + + __slots__ = ("_matrix",) + _matrix: npt.NDArray[np.float64] + + # fmt: off + _identity = np.array([ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ], dtype=np.float64 + ) + # fmt: on + + def __init__(self, *args): + """ + Matrix44() is the identity matrix. + + Matrix44(values) values is an iterable with the 16 components of the matrix. + + Matrix44(row1, row2, row3, row4) four rows, each row with four values. + + """ + nargs = len(args) + if nargs == 0: + self._matrix = Matrix44._identity.copy() + elif nargs == 1: + self._matrix = np.array(args[0], dtype=np.float64) + elif nargs == 4: + self._matrix = np.array(list(chain(*args)), dtype=np.float64) + else: + raise ValueError( + "Invalid count of arguments (4 row vectors or one " + "list with 16 values)." + ) + if self._matrix.shape != (16,): + raise ValueError("Invalid matrix count") + + def __repr__(self) -> str: + """Returns the representation string of the matrix in row-major order: + ``Matrix44((col0, col1, col2, col3), (...), (...), (...))`` + """ + + def format_row(row): + return "(%s)" % ", ".join(str(value) for value in row) + + return "Matrix44(%s)" % ", ".join(format_row(row) for row in self.rows()) + + def get_2d_transformation(self) -> tuple[float, ...]: + """Returns a 2D transformation as a row-major matrix in a linear + array (tuple). + + A more correct transformation could be implemented like so: + https://stackoverflow.com/questions/10629737/convert-3d-4x4-rotation-matrix-into-2d + """ + m = self._matrix + return m[0], m[1], 0.0, m[4], m[5], 0.0, m[12], m[13], 1.0 + + @staticmethod + def from_2d_transformation(components: Sequence[float]) -> Matrix44: + """Returns the :class:`Matrix44` class for an affine 2D (3x3) transformation + matrix defined by 6 float values: m11, m12, m21, m22, m31, m32. + """ + if len(components) != 6: + raise ValueError( + "First 2 columns of a 3x3 matrix required: m11, m12, m21, m22, m31, m32" + ) + + m44 = Matrix44() + m = m44._matrix + m[0] = components[0] + m[1] = components[1] + m[4] = components[2] + m[5] = components[3] + m[12] = components[4] + m[13] = components[5] + return m44 + + def get_row(self, row: int) -> tuple[float, ...]: + """Get row as list of four float values. + + Args: + row: row index [0 .. 3] + + """ + if 0 <= row < 4: + index = row * 4 + return tuple(self._matrix[index : index + 4]) + else: + raise IndexError(f"invalid row index: {row}") + + def set_row(self, row: int, values: Sequence[float]) -> None: + """Sets the values in a row. + + Args: + row: row index [0 .. 3] + values: iterable of four row values + + """ + if 0 <= row < 4: + index = row * 4 + self._matrix[index : index + len(values)] = floats(values) + else: + raise IndexError(f"invalid row index: {row}") + + def get_col(self, col: int) -> tuple[float, ...]: + """Returns a column as a tuple of four floats. + + Args: + col: column index [0 .. 3] + """ + if 0 <= col < 4: + m = self._matrix + return m[col], m[col + 4], m[col + 8], m[col + 12] + else: + raise IndexError(f"invalid row index: {col}") + + def set_col(self, col: int, values: Sequence[float]): + """Sets the values in a column. + + Args: + col: column index [0 .. 3] + values: iterable of four column values + + """ + if 0 <= col < 4: + m = self._matrix + a, b, c, d = values + m[col] = float(a) + m[col + 4] = float(b) + m[col + 8] = float(c) + m[col + 12] = float(d) + else: + raise IndexError(f"invalid row index: {col}") + + def copy(self) -> Matrix44: + """Returns a copy of same type.""" + return self.__class__(self._matrix) + + __copy__ = copy + + @property + def origin(self) -> Vec3: + m = self._matrix + return Vec3(m[12], m[13], m[14]) + + @origin.setter + def origin(self, v: UVec) -> None: + m = self._matrix + m[12], m[13], m[14] = Vec3(v) + + @property + def ux(self) -> Vec3: + return Vec3(self._matrix[0:3]) + + @property + def uy(self) -> Vec3: + return Vec3(self._matrix[4:7]) + + @property + def uz(self) -> Vec3: + return Vec3(self._matrix[8:11]) + + @property + def is_cartesian(self) -> bool: + """Returns ``True`` if target coordinate system is a right handed + orthogonal coordinate system. + """ + return self.uy.cross(self.uz).normalize().isclose(self.ux.normalize()) + + @property + def is_orthogonal(self) -> bool: + """Returns ``True`` if target coordinate system has orthogonal axis. + + Does not check for left- or right handed orientation, any orientation + of the axis valid. + + """ + ux = self.ux.normalize() + uy = self.uy.normalize() + uz = self.uz.normalize() + return ( + abs(ux.dot(uy)) <= 1e-9 + and abs(ux.dot(uz)) <= 1e-9 + and abs(uy.dot(uz)) <= 1e-9 + ) + + @classmethod + def scale( + cls, sx: float, sy: Optional[float] = None, sz: Optional[float] = None + ) -> Matrix44: + """Returns a scaling transformation matrix. If `sy` is ``None``, + `sy` = `sx`, and if `sz` is ``None`` `sz` = `sx`. + + """ + if sy is None: + sy = sx + if sz is None: + sz = sx + # fmt: off + m = cls([ + float(sx), 0., 0., 0., + 0., float(sy), 0., 0., + 0., 0., float(sz), 0., + 0., 0., 0., 1. + ]) + # fmt: on + return m + + @classmethod + def translate(cls, dx: float, dy: float, dz: float) -> Matrix44: + """Returns a translation matrix for translation vector (dx, dy, dz).""" + # fmt: off + return cls([ + 1., 0., 0., 0., + 0., 1., 0., 0., + 0., 0., 1., 0., + float(dx), float(dy), float(dz), 1. + ]) + # fmt: on + + @classmethod + def x_rotate(cls, angle: float) -> Matrix44: + """Returns a rotation matrix about the x-axis. + + Args: + angle: rotation angle in radians + + """ + cos_a = cos(angle) + sin_a = sin(angle) + # fmt: off + return cls([ + 1., 0., 0., 0., + 0., cos_a, sin_a, 0., + 0., -sin_a, cos_a, 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def y_rotate(cls, angle: float) -> Matrix44: + """Returns a rotation matrix about the y-axis. + + Args: + angle: rotation angle in radians + + """ + cos_a = cos(angle) + sin_a = sin(angle) + # fmt: off + return cls([ + cos_a, 0., -sin_a, 0., + 0., 1., 0., 0., + sin_a, 0., cos_a, 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def z_rotate(cls, angle: float) -> Matrix44: + """Returns a rotation matrix about the z-axis. + + Args: + angle: rotation angle in radians + + """ + cos_a = cos(angle) + sin_a = sin(angle) + # fmt: off + return cls([ + cos_a, sin_a, 0., 0., + -sin_a, cos_a, 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def axis_rotate(cls, axis: UVec, angle: float) -> Matrix44: + """Returns a rotation matrix about an arbitrary `axis`. + + Args: + axis: rotation axis as ``(x, y, z)`` tuple or :class:`Vec3` object + angle: rotation angle in radians + + """ + c = cos(angle) + s = sin(angle) + omc = 1.0 - c + x, y, z = Vec3(axis).normalize() + # fmt: off + return cls([ + x * x * omc + c, y * x * omc + z * s, x * z * omc - y * s, 0., + x * y * omc - z * s, y * y * omc + c, y * z * omc + x * s, 0., + x * z * omc + y * s, y * z * omc - x * s, z * z * omc + c, 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def xyz_rotate(cls, angle_x: float, angle_y: float, angle_z: float) -> Matrix44: + """Returns a rotation matrix for rotation about each axis. + + Args: + angle_x: rotation angle about x-axis in radians + angle_y: rotation angle about y-axis in radians + angle_z: rotation angle about z-axis in radians + + """ + cx = cos(angle_x) + sx = sin(angle_x) + cy = cos(angle_y) + sy = sin(angle_y) + cz = cos(angle_z) + sz = sin(angle_z) + + sxsy = sx * sy + cxsy = cx * sy + # fmt: off + return cls([ + cy * cz, sxsy * cz + cx * sz, -cxsy * cz + sx * sz, 0., + -cy * sz, -sxsy * sz + cx * cz, cxsy * sz + sx * cz, 0., + sy, -sx * cy, cx * cy, 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def shear_xy(cls, angle_x: float = 0, angle_y: float = 0) -> Matrix44: + """Returns a translation matrix for shear mapping (visually similar + to slanting) in the xy-plane. + + Args: + angle_x: slanting angle in x direction in radians + angle_y: slanting angle in y direction in radians + + """ + tx = math.tan(angle_x) + ty = math.tan(angle_y) + # fmt: off + return cls([ + 1., ty, 0., 0., + tx, 1., 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ]) + # fmt: on + + @classmethod + def perspective_projection( + cls, + left: float, + right: float, + top: float, + bottom: float, + near: float, + far: float, + ) -> Matrix44: + """Returns a matrix for a 2D projection. + + Args: + left: Coordinate of left of screen + right: Coordinate of right of screen + top: Coordinate of the top of the screen + bottom: Coordinate of the bottom of the screen + near: Coordinate of the near clipping plane + far: Coordinate of the far clipping plane + + """ + # fmt: off + return cls([ + (2. * near) / (right - left), 0., 0., 0., + 0., (2. * near) / (top - bottom), 0., 0., + (right + left) / (right - left), (top + bottom) / (top - bottom), + -((far + near) / (far - near)), -1., + 0., 0., -((2. * far * near) / (far - near)), 0. + ]) + # fmt: on + + @classmethod + def perspective_projection_fov( + cls, fov: float, aspect: float, near: float, far: float + ) -> Matrix44: + """Returns a matrix for a 2D projection. + + Args: + fov: The field of view (in radians) + aspect: The aspect ratio of the screen (width / height) + near: Coordinate of the near clipping plane + far: Coordinate of the far clipping plane + + """ + vrange = near * tan(fov / 2.0) + left = -vrange * aspect + right = vrange * aspect + bottom = -vrange + top = vrange + return cls.perspective_projection(left, right, bottom, top, near, far) + + @staticmethod + def chain(*matrices: Matrix44) -> Matrix44: + """Compose a transformation matrix from one or more `matrices`.""" + transformation = Matrix44() + for matrix in matrices: + transformation *= matrix + return transformation + + @staticmethod + def ucs( + ux: Vec3 = X_AXIS, + uy: Vec3 = Y_AXIS, + uz: Vec3 = Z_AXIS, + origin: Vec3 = NULLVEC, + ) -> Matrix44: + """Returns a matrix for coordinate transformation from WCS to UCS. + For transformation from UCS to WCS, transpose the returned matrix. + + Args: + ux: x-axis for UCS as unit vector + uy: y-axis for UCS as unit vector + uz: z-axis for UCS as unit vector + origin: UCS origin as location vector + + """ + ux_x, ux_y, ux_z = ux + uy_x, uy_y, uy_z = uy + uz_x, uz_y, uz_z = uz + or_x, or_y, or_z = origin + # fmt: off + return Matrix44(( + ux_x, ux_y, ux_z, 0, + uy_x, uy_y, uy_z, 0, + uz_x, uz_y, uz_z, 0, + or_x, or_y, or_z, 1, + )) + # fmt: on + + def __setitem__(self, index: tuple[int, int], value: float): + """Set (row, column) element.""" + row, col = index + if 0 <= row < 4 and 0 <= col < 4: + self._matrix[row * 4 + col] = float(value) + else: + raise IndexError(f"index out of range: {index}") + + def __getitem__(self, index: tuple[int, int]): + """Get (row, column) element.""" + row, col = index + if 0 <= row < 4 and 0 <= col < 4: + return self._matrix[row * 4 + col] + else: + raise IndexError(f"index out of range: {index}") + + def __iter__(self) -> Iterator[float]: + """Iterates over all matrix values.""" + return iter(self._matrix) + + def __mul__(self, other: Matrix44) -> Matrix44: + """Returns a new matrix as result of the matrix multiplication with + another matrix. + """ + m1 = self._matrix.reshape(4, 4) + m2 = other._matrix.reshape(4, 4) + result = np.matmul(m1, m2) + return self.__class__(np.ravel(result)) + + # __matmul__ = __mul__ does not work! + + def __matmul__(self, other: Matrix44) -> Matrix44: + """Returns a new matrix as result of the matrix multiplication with + another matrix. + """ + m1 = self._matrix.reshape(4, 4) + m2 = other._matrix.reshape(4, 4) + result = np.matmul(m1, m2) + return self.__class__(np.ravel(result)) + + def __imul__(self, other: Matrix44) -> Matrix44: + """Inplace multiplication with another matrix.""" + m1 = self._matrix.reshape(4, 4) + m2 = other._matrix.reshape(4, 4) + result = np.matmul(m1, m2) + self._matrix = np.ravel(result) + return self + + def rows(self) -> Iterator[tuple[float, ...]]: + """Iterate over rows as 4-tuples.""" + return (self.get_row(index) for index in (0, 1, 2, 3)) + + def columns(self) -> Iterator[tuple[float, ...]]: + """Iterate over columns as 4-tuples.""" + return (self.get_col(index) for index in (0, 1, 2, 3)) + + def transform(self, vector: UVec) -> Vec3: + """Returns a transformed vertex.""" + m = self._matrix + x, y, z = Vec3(vector) + # fmt: off + return Vec3( + x * m[0] + y * m[4] + z * m[8] + m[12], + x * m[1] + y * m[5] + z * m[9] + m[13], + x * m[2] + y * m[6] + z * m[10] + m[14] + ) + # fmt: on + + def transform_direction(self, vector: UVec, normalize=False) -> Vec3: + """Returns a transformed direction vector without translation.""" + m = self._matrix + x, y, z = Vec3(vector) + # fmt: off + v = Vec3( + x * m[0] + y * m[4] + z * m[8], + x * m[1] + y * m[5] + z * m[9], + x * m[2] + y * m[6] + z * m[10] + ) + # fmt: on + return v.normalize() if normalize else v + + ocs_to_wcs = transform_direction + + def transform_vertices(self, vectors: Iterable[UVec]) -> Iterator[Vec3]: + """Returns an iterable of transformed vertices.""" + # fmt: off + ( + m0, m1, m2, m3, + m4, m5, m6, m7, + m8, m9, m10, m11, + m12, m13, m14, m15, + ) = self._matrix + # fmt: on + for vector in vectors: + x, y, z = Vec3(vector) + # fmt: off + yield Vec3( + x * m0 + y * m4 + z * m8 + m12, + x * m1 + y * m5 + z * m9 + m13, + x * m2 + y * m6 + z * m10 + m14 + ) + # fmt: on + + def fast_2d_transform(self, points: Iterable[UVec]) -> Iterator[Vec2]: + """Fast transformation of 2D points. For 3D input points the z-axis will be + ignored. This only works reliable if only 2D transformations have been applied + to the 4x4 matrix! + + Profiling results - speed gains over :meth:`transform_vertices`: + + - pure Python code: ~1.6x + - Python with C-extensions: less than 1.1x + - PyPy 3.8: ~4.3x + + But speed isn't everything, returning the processed input points as :class:`Vec2` + instances is another advantage. + + .. versionadded:: 1.1 + + """ + m = self._matrix + m0 = m[0] + m1 = m[1] + m4 = m[4] + m5 = m[5] + m12 = m[12] + m13 = m[13] + for pnt in points: + v = Vec2(pnt) + x = v.x + y = v.y + yield Vec2(x * m0 + y * m4 + m12, x * m1 + y * m5 + m13) + + def transform_array_inplace(self, array: np.ndarray, ndim: int) -> None: + """Transforms a numpy array inplace, the argument `ndim` defines the dimensions + to transform, this allows 2D/3D transformation on arrays with more columns + e.g. a polyline array which stores points as (x, y, start_width, end_width, + bulge) values. + + .. versionadded:: 1.1 + + """ + # This implementation exist only for compatibility to the Cython implementation! + # This version is 3.4x faster than the Cython version of Matrix44.fast_2d_transform() + # for larger point arrays but 10.5x slower than the Cython version of this method. + if ndim == 2: + m = np.array(self.get_2d_transformation(), dtype=np.float64) + m.shape = (3, 3) + elif ndim == 3: + m = np.array(self._matrix, dtype=np.float64) + m.shape = (4, 4) + else: + raise ValueError("ndim has to be 2 or 3") + + v = np.matmul( + np.concatenate((array[:, :ndim], np.ones((array.shape[0], 1))), axis=1), m + ) + array[:, :ndim] = v[:, :ndim].copy() + + def transform_directions( + self, vectors: Iterable[UVec], normalize=False + ) -> Iterator[Vec3]: + """Returns an iterable of transformed direction vectors without + translation. + + """ + m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, *_ = self._matrix + for vector in vectors: + x, y, z = Vec3(vector) + # fmt: off + v = Vec3( + x * m0 + y * m4 + z * m8, + x * m1 + y * m5 + z * m9, + x * m2 + y * m6 + z * m10 + ) + # fmt: on + yield v.normalize() if normalize else v + + def ucs_vertex_from_wcs(self, wcs: Vec3) -> Vec3: + """Returns an UCS vector from WCS vertex. + + Works only if matrix is used as cartesian UCS without scaling. + + (internal API) + + """ + return self.ucs_direction_from_wcs(wcs - self.origin) + + def ucs_direction_from_wcs(self, wcs: Vec3) -> Vec3: + """Returns UCS direction vector from WCS direction. + + Works only if matrix is used as cartesian UCS without scaling. + + (internal API) + + """ + m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, *_ = self._matrix + x, y, z = wcs + # fmt: off + return Vec3( + x * m0 + y * m1 + z * m2, + x * m4 + y * m5 + z * m6, + x * m8 + y * m9 + z * m10, + ) + # fmt: on + + ocs_from_wcs = ucs_direction_from_wcs + + def transpose(self) -> None: + """Swaps the rows for columns inplace.""" + m = self._matrix.reshape(4, 4) + self._matrix = np.ravel(m.T) + + def determinant(self) -> float: + """Returns determinant.""" + return np.linalg.det(self._matrix.reshape(4, 4)) + + def inverse(self) -> None: + """Calculates the inverse of the matrix. + + Raises: + ZeroDivisionError: if matrix has no inverse. + + """ + try: + inverse = np.linalg.inv(self._matrix.reshape(4, 4)) + except np.linalg.LinAlgError: + raise ZeroDivisionError + self._matrix = np.ravel(inverse) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/_vector.py b/.venv/lib/python3.12/site-packages/ezdxf/math/_vector.py new file mode 100644 index 0000000..0e6fb27 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/_vector.py @@ -0,0 +1,825 @@ +# Copyright (c) 2018-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Tuple, + Iterable, + Sequence, + TYPE_CHECKING, + Iterator, + Optional, +) +from functools import partial +import math +import random + +if TYPE_CHECKING: + from ezdxf.math import UVec, AnyVec + +ABS_TOL = 1e-12 +isclose = partial(math.isclose, abs_tol=ABS_TOL) + +__all__ = ["Vec3", "Vec2"] + + +class Vec3: + """Immutable 3D vector class. + + This class is optimized for universality not for speed. + Immutable means you can't change (x, y, z) components after initialization:: + + v1 = Vec3(1, 2, 3) + v2 = v1 + v2.z = 7 # this is not possible, raises AttributeError + v2 = Vec3(v2.x, v2.y, 7) # this creates a new Vec3() object + assert v1.z == 3 # and v1 remains unchanged + + + :class:`Vec3` initialization: + + - ``Vec3()``, returns ``Vec3(0, 0, 0)`` + - ``Vec3((x, y))``, returns ``Vec3(x, y, 0)`` + - ``Vec3((x, y, z))``, returns ``Vec3(x, y, z)`` + - ``Vec3(x, y)``, returns ``Vec3(x, y, 0)`` + - ``Vec3(x, y, z)``, returns ``Vec3(x, y, z)`` + + Addition, subtraction, scalar multiplication and scalar division left and + right-handed are supported:: + + v = Vec3(1, 2, 3) + v + (1, 2, 3) == Vec3(2, 4, 6) + (1, 2, 3) + v == Vec3(2, 4, 6) + v - (1, 2, 3) == Vec3(0, 0, 0) + (1, 2, 3) - v == Vec3(0, 0, 0) + v * 3 == Vec3(3, 6, 9) + 3 * v == Vec3(3, 6, 9) + Vec3(3, 6, 9) / 3 == Vec3(1, 2, 3) + -Vec3(1, 2, 3) == (-1, -2, -3) + + Comparison between vectors and vectors or tuples is supported:: + + Vec3(1, 2, 3) < Vec3 (2, 2, 2) + (1, 2, 3) < tuple(Vec3(2, 2, 2)) # conversion necessary + Vec3(1, 2, 3) == (1, 2, 3) + + bool(Vec3(1, 2, 3)) is True + bool(Vec3(0, 0, 0)) is False + + """ + + __slots__ = ["_x", "_y", "_z"] + + def __init__(self, *args): + self._x, self._y, self._z = self.decompose(*args) + + @property + def x(self) -> float: + """x-axis value""" + return self._x + + @property + def y(self) -> float: + """y-axis value""" + return self._y + + @property + def z(self) -> float: + """z-axis value""" + return self._z + + @property + def xy(self) -> Vec3: + """Vec3 as ``(x, y, 0)``, projected on the xy-plane.""" + return self.__class__(self._x, self._y) + + @property + def xyz(self) -> tuple[float, float, float]: + """Vec3 as ``(x, y, z)`` tuple.""" + return self._x, self._y, self._z + + @property + def vec2(self) -> Vec2: + """Real 2D vector as :class:`Vec2` object.""" + return Vec2((self._x, self._y)) + + def replace( + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ) -> Vec3: + """Returns a copy of vector with replaced x-, y- and/or z-axis.""" + if x is None: + x = self._x + if y is None: + y = self._y + if z is None: + z = self._z + return self.__class__(x, y, z) + + def round(self, ndigits=None) -> Vec3: + """Returns a new vector where all components are rounded to `ndigits`. + + Uses standard Python :func:`round` function for rounding. + """ + return self.__class__( + round(self._x, ndigits), + round(self._y, ndigits), + round(self._z, ndigits), + ) + + @classmethod + def list(cls, items: Iterable[UVec]) -> list[Vec3]: + """Returns a list of :class:`Vec3` objects.""" + return list(cls.generate(items)) + + @classmethod + def tuple(cls, items: Iterable[UVec]) -> Sequence[Vec3]: + """Returns a tuple of :class:`Vec3` objects.""" + return tuple(cls.generate(items)) + + @classmethod + def generate(cls, items: Iterable[UVec]) -> Iterator[Vec3]: + """Returns an iterable of :class:`Vec3` objects.""" + return (cls(item) for item in items) + + @classmethod + def from_angle(cls, angle: float, length: float = 1.0) -> Vec3: + """Returns a :class:`Vec3` object from `angle` in radians in the + xy-plane, z-axis = ``0``. + """ + return cls(math.cos(angle) * length, math.sin(angle) * length, 0.0) + + @classmethod + def from_deg_angle(cls, angle: float, length: float = 1.0) -> Vec3: + """Returns a :class:`Vec3` object from `angle` in degrees in the + xy-plane, z-axis = ``0``. + """ + return cls.from_angle(math.radians(angle), length) + + @staticmethod + def decompose(*args) -> Tuple[float, float, float]: # cannot use "tuple" here! + """Converts input into a (x, y, z) tuple. + + Valid arguments are: + + - no args: ``decompose()`` returns (0, 0, 0) + - 1 arg: ``decompose(arg)``, `arg` is tuple or list, tuple has to be + (x, y[, z]): ``decompose((x, y))`` returns (x, y, 0.) + - 2 args: ``decompose(x, y)`` returns (x, y, 0) + - 3 args: ``decompose(x, y, z)`` returns (x, y, z) + + Returns: + (x, y, z) tuple + + (internal API) + + """ + length = len(args) + if length == 0: + return 0.0, 0.0, 0.0 + elif length == 1: + data = args[0] + if isinstance(data, Vec3): + return data._x, data._y, data._z + else: + length = len(data) + if length == 2: + x, y = data + z = 0.0 + elif length == 3: + x, y, z = data + else: + raise TypeError + return float(x), float(y), float(z) + elif length == 2: + x, y = args + return float(x), float(y), 0.0 + elif length == 3: + x, y, z = args + return float(x), float(y), float(z) + raise TypeError + + @classmethod + def random(cls, length: float = 1) -> Vec3: + """Returns a random vector.""" + x = random.uniform(-1, 1) + y = random.uniform(-1, 1) + z = random.uniform(-1, 1) + return Vec3(x, y, z).normalize(length) + + def __str__(self) -> str: + """Return ``'(x, y, z)'`` as string.""" + return "({0.x}, {0.y}, {0.z})".format(self) + + def __repr__(self) -> str: + """Return ``'Vec3(x, y, z)'`` as string.""" + return "Vec3" + self.__str__() + + def __len__(self) -> int: + """Returns always ``3``.""" + return 3 + + def __hash__(self) -> int: + """Returns hash value of vector, enables the usage of vector as key in + ``set`` and ``dict``. + """ + return hash(self.xyz) + + def copy(self) -> Vec3: + """Returns a copy of vector as :class:`Vec3` object.""" + return self # immutable! + + __copy__ = copy + + def __deepcopy__(self, memodict: dict) -> Vec3: + """:func:`copy.deepcopy` support.""" + return self # immutable! + + def __getitem__(self, index: int) -> float: + """Support for indexing: + + - v[0] is v.x + - v[1] is v.y + - v[2] is v.z + + """ + if isinstance(index, slice): + raise TypeError("slicing not supported") + if index == 0: + return self._x + elif index == 1: + return self._y + elif index == 2: + return self._z + else: + raise IndexError(f"invalid index {index}") + + def __iter__(self) -> Iterator[float]: + """Returns iterable of x-, y- and z-axis.""" + yield self._x + yield self._y + yield self._z + + def __abs__(self) -> float: + """Returns length (magnitude) of vector.""" + return self.magnitude + + @property + def magnitude(self) -> float: + """Length of vector.""" + return self.magnitude_square**0.5 + + @property + def magnitude_xy(self) -> float: + """Length of vector in the xy-plane.""" + return math.hypot(self._x, self._y) + + @property + def magnitude_square(self) -> float: + """Square length of vector.""" + x, y, z = self._x, self._y, self._z + return x * x + y * y + z * z + + @property + def is_null(self) -> bool: + """``True`` if all components are close to zero: ``Vec3(0, 0, 0)``. + Has a fixed absolute testing tolerance of 1e-12! + """ + return ( + abs(self._x) <= ABS_TOL + and abs(self._y) <= ABS_TOL + and abs(self._z) <= ABS_TOL + ) + + def is_parallel( + self, other: Vec3, *, rel_tol: float = 1e-9, abs_tol: float = 1e-12 + ) -> bool: + """Returns ``True`` if `self` and `other` are parallel to vectors.""" + v1 = self.normalize() + v2 = other.normalize() + return v1.isclose(v2, rel_tol=rel_tol, abs_tol=abs_tol) or v1.isclose( + -v2, rel_tol=rel_tol, abs_tol=abs_tol + ) + + @property + def spatial_angle(self) -> float: + """Spatial angle between vector and x-axis in radians.""" + return math.acos(X_AXIS.dot(self.normalize())) + + @property + def spatial_angle_deg(self) -> float: + """Spatial angle between vector and x-axis in degrees.""" + return math.degrees(self.spatial_angle) + + @property + def angle(self) -> float: + """Angle between vector and x-axis in the xy-plane in radians.""" + return math.atan2(self._y, self._x) + + @property + def angle_deg(self) -> float: + """Returns angle of vector and x-axis in the xy-plane in degrees.""" + return math.degrees(self.angle) + + def orthogonal(self, ccw: bool = True) -> Vec3: + """Returns orthogonal 2D vector, z-axis is unchanged. + + Args: + ccw: counter-clockwise if ``True`` else clockwise + + """ + return ( + self.__class__(-self._y, self._x, self._z) + if ccw + else self.__class__(self._y, -self._x, self._z) + ) + + def lerp(self, other: UVec, factor=0.5) -> Vec3: + """Returns linear interpolation between `self` and `other`. + + Args: + other: end point as :class:`Vec3` compatible object + factor: interpolation factor (0 = self, 1 = other, + 0.5 = mid point) + + """ + d = (self.__class__(other) - self) * float(factor) + return self.__add__(d) + + def project(self, other: UVec) -> Vec3: + """Returns projected vector of `other` onto `self`.""" + uv = self.normalize() + return uv * uv.dot(other) + + def normalize(self, length: float = 1.0) -> Vec3: + """Returns normalized vector, optional scaled by `length`.""" + return self.__mul__(length / self.magnitude) + + def reversed(self) -> Vec3: + """Returns negated vector (-`self`).""" + return self.__class__(-self._x, -self._y, -self._z) + + __neg__ = reversed + + def __bool__(self) -> bool: + """Returns ``True`` if vector is not (0, 0, 0).""" + return not self.is_null + + def isclose( + self, other: UVec, *, rel_tol: float = 1e-9, abs_tol: float = 1e-12 + ) -> bool: + """Returns ``True`` if `self` is close to `other`. + Uses :func:`math.isclose` to compare all axis. + + Learn more about the :func:`math.isclose` function in + `PEP 485 `_. + + """ + x, y, z = self.decompose(other) + return ( + math.isclose(self._x, x, rel_tol=rel_tol, abs_tol=abs_tol) + and math.isclose(self._y, y, rel_tol=rel_tol, abs_tol=abs_tol) + and math.isclose(self._z, z, rel_tol=rel_tol, abs_tol=abs_tol) + ) + + def __eq__(self, other: UVec) -> bool: + """Equal operator. + + Args: + other: :class:`Vec3` compatible object + """ + if not isinstance(other, Vec3): + other = Vec3(other) + return self.x == other.x and self.y == other.y and self.z == other.z + + def __lt__(self, other: UVec) -> bool: + """Lower than operator. + + Args: + other: :class:`Vec3` compatible object + + """ + x, y, z = self.decompose(other) + if self._x == x: + if self._y == y: + return self._z < z + else: + return self._y < y + else: + return self._x < x + + def __add__(self, other: UVec) -> Vec3: + """Add :class:`Vec3` operator: `self` + `other`.""" + x, y, z = self.decompose(other) + return self.__class__(self._x + x, self._y + y, self._z + z) + + def __radd__(self, other: UVec) -> Vec3: + """RAdd :class:`Vec3` operator: `other` + `self`.""" + return self.__add__(other) + + def __sub__(self, other: UVec) -> Vec3: + """Sub :class:`Vec3` operator: `self` - `other`.""" + + x, y, z = self.decompose(other) + return self.__class__(self._x - x, self._y - y, self._z - z) + + def __rsub__(self, other: UVec) -> Vec3: + """RSub :class:`Vec3` operator: `other` - `self`.""" + x, y, z = self.decompose(other) + return self.__class__(x - self._x, y - self._y, z - self._z) + + def __mul__(self, other: float) -> Vec3: + """Scalar Mul operator: `self` * `other`.""" + scalar = float(other) + return self.__class__(self._x * scalar, self._y * scalar, self._z * scalar) + + def __rmul__(self, other: float) -> Vec3: + """Scalar RMul operator: `other` * `self`.""" + return self.__mul__(other) + + def __truediv__(self, other: float) -> Vec3: + """Scalar Div operator: `self` / `other`.""" + scalar = float(other) + return self.__class__(self._x / scalar, self._y / scalar, self._z / scalar) + + @staticmethod + def sum(items: Iterable[UVec]) -> Vec3: + """Add all vectors in `items`.""" + s = NULLVEC + for v in items: + s += v + return s + + def dot(self, other: UVec) -> float: + """Dot operator: `self` . `other` + + Args: + other: :class:`Vec3` compatible object + """ + x, y, z = self.decompose(other) + return self._x * x + self._y * y + self._z * z + + def cross(self, other: UVec) -> Vec3: + """Cross operator: `self` x `other` + + Args: + other: :class:`Vec3` compatible object + """ + x, y, z = self.decompose(other) + return self.__class__( + self._y * z - self._z * y, + self._z * x - self._x * z, + self._x * y - self._y * x, + ) + + def distance(self, other: UVec) -> float: + """Returns distance between `self` and `other` vector.""" + v = self.__class__(other) + return v.__sub__(self).magnitude + + def angle_between(self, other: UVec) -> float: + """Returns angle between `self` and `other` in radians. +angle is + counter clockwise orientation. + + Args: + other: :class:`Vec3` compatible object + + """ + cos_theta = self.normalize().dot(self.__class__(other).normalize()) + # avoid domain errors caused by floating point imprecision: + if cos_theta < -1.0: + cos_theta = -1.0 + elif cos_theta > 1.0: + cos_theta = 1.0 + return math.acos(cos_theta) + + def angle_about(self, base: UVec, target: UVec) -> float: + # (c) 2020 by Matt Broadway, MIT License + """Returns counter-clockwise angle in radians about `self` from `base` to + `target` when projected onto the plane defined by `self` as the normal + vector. + + Args: + base: base vector, defines angle 0 + target: target vector + """ + x_axis = (base - self.project(base)).normalize() + y_axis = self.cross(x_axis).normalize() + target_projected_x = x_axis.dot(target) + target_projected_y = y_axis.dot(target) + return math.atan2(target_projected_y, target_projected_x) % math.tau + + def rotate(self, angle: float) -> Vec3: + """Returns vector rotated about `angle` around the z-axis. + + Args: + angle: angle in radians + + """ + v = self.__class__(self.x, self.y, 0.0) + v = Vec3.from_angle(v.angle + angle, v.magnitude) + return self.__class__(v.x, v.y, self.z) + + def rotate_deg(self, angle: float) -> Vec3: + """Returns vector rotated about `angle` around the z-axis. + + Args: + angle: angle in degrees + + """ + return self.rotate(math.radians(angle)) + + +X_AXIS = Vec3(1, 0, 0) +Y_AXIS = Vec3(0, 1, 0) +Z_AXIS = Vec3(0, 0, 1) +NULLVEC = Vec3(0, 0, 0) + + +def distance(p1: UVec, p2: UVec) -> float: + """Returns distance between points `p1` and `p2`. + + Args: + p1: first point as :class:`Vec3` compatible object + p2: second point as :class:`Vec3` compatible object + + """ + return Vec3(p1).distance(p2) + + +def lerp(p1: UVec, p2: UVec, factor: float = 0.5) -> Vec3: + """Returns linear interpolation between points `p1` and `p2` as :class:`Vec3`. + + Args: + p1: first point as :class:`Vec3` compatible object + p2: second point as :class:`Vec3` compatible object + factor: interpolation factor (``0`` = `p1`, ``1`` = `p2`, ``0.5`` = mid point) + + """ + return Vec3(p1).lerp(p2, factor) + + +class Vec2: + """Immutable 2D vector class. + + Args: + v: vector object with :attr:`x` and :attr:`y` attributes/properties or a + sequence of float ``[x, y, ...]`` or x-axis as float if argument `y` + is not ``None`` + y: second float for :code:`Vec2(x, y)` + + :class:`Vec2` implements a subset of :class:`Vec3`. + + """ + + __slots__ = ["x", "y"] + + def __init__(self, v=(0.0, 0.0), y=None) -> None: + try: # fast path for Vec2() and Vec3() or any object providing x and y attributes + self.x = v.x + self.y = v.y + except AttributeError: + if y is None: # given one tuple + self.x = float(v[0]) + self.y = float(v[1]) + else: # two floats given + self.x = float(v) + self.y = float(y) + + @property + def vec3(self) -> Vec3: + """Returns a 3D vector.""" + return Vec3(self.x, self.y, 0) + + def round(self, ndigits=None) -> Vec2: + """Returns a new vector where all components are rounded to `ndigits`. + + Uses standard Python :func:`round` function for rounding. + """ + return self.__class__(round(self.x, ndigits), round(self.y, ndigits)) + + @classmethod + def list(cls, items: Iterable[UVec]) -> list[Vec2]: + return list(cls.generate(items)) + + @classmethod + def tuple(cls, items: Iterable[UVec]) -> Sequence[Vec2]: + """Returns a tuple of :class:`Vec3` objects.""" + return tuple(cls.generate(items)) + + @classmethod + def generate(cls, items: Iterable[UVec]) -> Iterator[Vec2]: + return (cls(item) for item in items) + + @classmethod + def from_angle(cls, angle: float, length: float = 1.0) -> Vec2: + return cls(math.cos(angle) * length, math.sin(angle) * length) + + @classmethod + def from_deg_angle(cls, angle: float, length: float = 1.0) -> Vec2: + return cls.from_angle(math.radians(angle), length) + + def __str__(self) -> str: + return "({0.x}, {0.y})".format(self) + + def __repr__(self) -> str: + return "Vec2" + self.__str__() + + def __len__(self) -> int: + return 2 + + def __hash__(self) -> int: + return hash((self.x, self.y)) + + def copy(self) -> Vec2: + return self.__class__((self.x, self.y)) + + __copy__ = copy + + def __deepcopy__(self, memodict: dict) -> Vec2: + try: + return memodict[id(self)] + except KeyError: + v = self.copy() + memodict[id(self)] = v + return v + + def __getitem__(self, index: int) -> float: + if isinstance(index, slice): + raise TypeError("slicing not supported") + if index == 0: + return self.x + elif index == 1: + return self.y + else: + raise IndexError(f"invalid index {index}") + + def __iter__(self) -> Iterator[float]: + yield self.x + yield self.y + + def __abs__(self) -> float: + return self.magnitude + + @property + def magnitude(self) -> float: + """Returns length of vector.""" + return math.hypot(self.x, self.y) + + @property + def is_null(self) -> bool: + return abs(self.x) <= ABS_TOL and abs(self.y) <= ABS_TOL + + @property + def angle(self) -> float: + """Angle of vector in radians.""" + return math.atan2(self.y, self.x) + + @property + def angle_deg(self) -> float: + """Angle of vector in degrees.""" + return math.degrees(self.angle) + + def orthogonal(self, ccw: bool = True) -> Vec2: + """Orthogonal vector + + Args: + ccw: counter-clockwise if ``True`` else clockwise + + """ + if ccw: + return self.__class__(-self.y, self.x) + else: + return self.__class__(self.y, -self.x) + + def lerp(self, other: AnyVec, factor: float = 0.5) -> Vec2: + """Linear interpolation between `self` and `other`. + + Args: + other: target vector/point + factor: interpolation factor (0=self, 1=other, 0.5=mid point) + + Returns: interpolated vector + + """ + x = self.x + (other.x - self.x) * factor + y = self.y + (other.y - self.y) * factor + return self.__class__(x, y) + + def project(self, other: AnyVec) -> Vec2: + """Project vector `other` onto `self`.""" + uv = self.normalize() + return uv * uv.dot(other) + + def normalize(self, length: float = 1.0) -> Vec2: + return self.__mul__(length / self.magnitude) + + def reversed(self) -> Vec2: + return self.__class__(-self.x, -self.y) + + __neg__ = reversed + + def __bool__(self) -> bool: + return not self.is_null + + def isclose( + self, other: AnyVec, *, rel_tol: float = 1e-9, abs_tol: float = 1e-12 + ) -> bool: + if not isinstance(other, Vec2): + other = Vec2(other) + return math.isclose( + self.x, other.x, rel_tol=rel_tol, abs_tol=abs_tol + ) and math.isclose(self.y, other.y, rel_tol=rel_tol, abs_tol=abs_tol) + + def __eq__(self, other: UVec) -> bool: + if not isinstance(other, Vec2): + other = Vec2(other) + return self.x == other.x and self.y == other.y + + def __lt__(self, other: UVec) -> bool: + # accepts also tuples, for more convenience at testing + x, y, *_ = other + if self.x == x: + return self.y < y + else: + return self.x < x + + def __add__(self, other: AnyVec) -> Vec2: + try: + return self.__class__(self.x + other.x, self.y + other.y) + except AttributeError: + raise TypeError("invalid argument") + + def __sub__(self, other: AnyVec) -> Vec2: + try: + return self.__class__(self.x - other.x, self.y - other.y) + except AttributeError: + raise TypeError("invalid argument") + + def __rsub__(self, other: AnyVec) -> Vec2: + try: + return self.__class__(other.x - self.x, other.y - self.y) + except AttributeError: + raise TypeError("invalid argument") + + def __mul__(self, other: float) -> Vec2: + return self.__class__(self.x * other, self.y * other) + + def __rmul__(self, other: float) -> Vec2: + return self.__class__(self.x * other, self.y * other) + + def __truediv__(self, other: float) -> Vec2: + return self.__class__(self.x / other, self.y / other) + + def dot(self, other: AnyVec) -> float: + return self.x * other.x + self.y * other.y + + def det(self, other: AnyVec) -> float: + return self.x * other.y - self.y * other.x + + def distance(self, other: AnyVec) -> float: + return math.hypot(self.x - other.x, self.y - other.y) + + def angle_between(self, other: AnyVec) -> float: + """Calculate angle between `self` and `other` in radians. +angle is + counter-clockwise orientation. + + """ + cos_theta = self.normalize().dot(other.normalize()) + # avoid domain errors caused by floating point imprecision: + if cos_theta < -1.0: + cos_theta = -1.0 + elif cos_theta > 1.0: + cos_theta = 1.0 + return math.acos(cos_theta) + + def rotate(self, angle: float) -> Vec2: + """Rotate vector around origin. + + Args: + angle: angle in radians + + """ + return self.__class__.from_angle(self.angle + angle, self.magnitude) + + def rotate_deg(self, angle: float) -> Vec2: + """Rotate vector around origin. + + Args: + angle: angle in degrees + + Returns: rotated vector + + """ + return self.__class__.from_angle( + self.angle + math.radians(angle), self.magnitude + ) + + @staticmethod + def sum(items: Iterable[Vec2]) -> Vec2: + """Add all vectors in `items`.""" + s = Vec2(0, 0) + for v in items: + s += v + return s diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/arc.py b/.venv/lib/python3.12/site-packages/ezdxf/math/arc.py new file mode 100644 index 0000000..3d55a68 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/arc.py @@ -0,0 +1,537 @@ +# Copyright (c) 2018-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Sequence, Iterator, Optional +import math +import numpy as np + +from ezdxf.math import Vec2, UVec +from .bbox import BoundingBox2d +from .construct2d import enclosing_angles +from .circle import ConstructionCircle +from .line import ConstructionRay, ConstructionLine +from .ucs import UCS + +if TYPE_CHECKING: + from ezdxf.entities import Arc + from ezdxf.layouts import BaseLayout + +__all__ = ["ConstructionArc", "arc_chord_length", "arc_segment_count"] + +QUARTER_ANGLES = [0, math.pi * 0.5, math.pi, math.pi * 1.5] + + +class ConstructionArc: + """Construction tool for 2D arcs. + + :class:`ConstructionArc` represents a 2D arc in the xy-plane, use an + :class:`UCS` to place a DXF :class:`~ezdxf.entities.Arc` entity in 3D space, + see method :meth:`add_to_layout`. + + Implements the 2D transformation tools: :meth:`translate`, + :meth:`scale_uniform` and :meth:`rotate_z` + + Args: + center: center point as :class:`Vec2` compatible object + radius: radius + start_angle: start angle in degrees + end_angle: end angle in degrees + is_counter_clockwise: swaps start- and end angle if ``False`` + + """ + + def __init__( + self, + center: UVec = (0, 0), + radius: float = 1.0, + start_angle: float = 0.0, + end_angle: float = 360.0, + is_counter_clockwise: Optional[bool] = True, + ): + + self.center = Vec2(center) + self.radius = radius + if is_counter_clockwise: + self.start_angle = start_angle + self.end_angle = end_angle + else: + self.start_angle = end_angle + self.end_angle = start_angle + + @property + def start_point(self) -> Vec2: + """start point of arc as :class:`Vec2`.""" + return self.center + Vec2.from_deg_angle(self.start_angle, self.radius) + + @property + def end_point(self) -> Vec2: + """end point of arc as :class:`Vec2`.""" + return self.center + Vec2.from_deg_angle(self.end_angle, self.radius) + + @property + def is_passing_zero(self) -> bool: + """Returns ``True`` if the arc passes the x-axis (== 0 degree).""" + return self.start_angle > self.end_angle + + @property + def circle(self) -> ConstructionCircle: + return ConstructionCircle(self.center, self.radius) + + @property + def bounding_box(self) -> BoundingBox2d: + """bounding box of arc as :class:`BoundingBox2d`.""" + bbox = BoundingBox2d((self.start_point, self.end_point)) + bbox.extend(self.main_axis_points()) + return bbox + + def angles(self, num: int) -> Iterable[float]: + """Returns `num` angles from start- to end angle in degrees in + counter-clockwise order. + + All angles are normalized in the range from [0, 360). + + """ + if num < 2: + raise ValueError("num >= 2") + start: float = self.start_angle % 360 + stop: float = self.end_angle % 360 + if stop <= start: + stop += 360 + for angle in np.linspace(start, stop, num=num, endpoint=True): + yield angle % 360 + + @property + def angle_span(self) -> float: + """Returns angle span of arc from start- to end param.""" + end: float = self.end_angle + if end < self.start_angle: + end += 360.0 + return end - self.start_angle + + def vertices(self, a: Iterable[float]) -> Iterable[Vec2]: + """Yields vertices on arc for angles in iterable `a` in WCS as location + vectors. + + Args: + a: angles in the range from 0 to 360 in degrees, arc goes + counter clockwise around the z-axis, WCS x-axis = 0 deg. + + """ + center = self.center + radius = self.radius + + for angle in a: + yield center + Vec2.from_deg_angle(angle, radius) + + def flattening(self, sagitta: float) -> Iterable[Vec2]: + """Approximate the arc by vertices in WCS, argument `sagitta` is the + max. distance from the center of an arc segment to the center of its + chord. + + """ + radius: float = abs(self.radius) + if radius > 0: + start: float = self.start_angle + stop: float = self.end_angle + if math.isclose(start, stop): + return + start %= 360 + stop %= 360 + if stop <= start: + stop += 360 + angle_span: float = math.radians(stop - start) + count = arc_segment_count(radius, angle_span, sagitta) + yield from self.vertices(np.linspace(start, stop, count + 1)) + + def tangents(self, a: Iterable[float]) -> Iterable[Vec2]: + """Yields tangents on arc for angles in iterable `a` in WCS as + direction vectors. + + Args: + a: angles in the range from 0 to 360 in degrees, arc goes + counter-clockwise around the z-axis, WCS x-axis = 0 deg. + + """ + for angle in a: + r: float = math.radians(angle) + yield Vec2((-math.sin(r), math.cos(r))) + + def main_axis_points(self) -> Iterator[Vec2]: + center: Vec2 = self.center + radius: float = self.radius + start: float = math.radians(self.start_angle) + end: float = math.radians(self.end_angle) + for angle in QUARTER_ANGLES: + if enclosing_angles(angle, start, end): + yield center + Vec2.from_angle(angle, radius) + + def translate(self, dx: float, dy: float) -> ConstructionArc: + """Move arc about `dx` in x-axis and about `dy` in y-axis, returns + `self` (floating interface). + + Args: + dx: translation in x-axis + dy: translation in y-axis + + """ + self.center += Vec2(dx, dy) + return self + + def scale_uniform(self, s: float) -> ConstructionArc: + """Scale arc inplace uniform about `s` in x- and y-axis, returns + `self` (floating interface). + """ + self.radius *= float(s) + return self + + def rotate_z(self, angle: float) -> ConstructionArc: + """Rotate arc inplace about z-axis, returns `self` + (floating interface). + + Args: + angle: rotation angle in degrees + + """ + self.start_angle += angle + self.end_angle += angle + return self + + @property + def start_angle_rad(self) -> float: + """Returns the start angle in radians.""" + return math.radians(self.start_angle) + + @property + def end_angle_rad(self) -> float: + """Returns the end angle in radians.""" + return math.radians(self.end_angle) + + @staticmethod + def validate_start_and_end_point( + start_point: UVec, end_point: UVec + ) -> tuple[Vec2, Vec2]: + start_point = Vec2(start_point) + end_point = Vec2(end_point) + if start_point == end_point: + raise ValueError( + "Start- and end point have to be different points." + ) + return start_point, end_point + + @classmethod + def from_2p_angle( + cls, + start_point: UVec, + end_point: UVec, + angle: float, + ccw: bool = True, + ) -> ConstructionArc: + """Create arc from two points and enclosing angle. Additional + precondition: arc goes by default in counter-clockwise orientation from + `start_point` to `end_point`, can be changed by `ccw` = ``False``. + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + angle: enclosing angle in degrees + ccw: counter-clockwise direction if ``True`` + + """ + _start_point, _end_point = cls.validate_start_and_end_point( + start_point, end_point + ) + angle = math.radians(angle) + if angle == 0: + raise ValueError("Angle can not be 0.") + if ccw is False: + _start_point, _end_point = _end_point, _start_point + alpha2: float = angle / 2.0 + distance: float = _end_point.distance(_start_point) + distance2: float = distance / 2.0 + radius: float = distance2 / math.sin(alpha2) + height: float = distance2 / math.tan(alpha2) + mid_point: Vec2 = _end_point.lerp(_start_point, factor=0.5) + + distance_vector: Vec2 = _end_point - _start_point + height_vector: Vec2 = distance_vector.orthogonal().normalize(height) + center: Vec2 = mid_point + height_vector + + return ConstructionArc( + center=center, + radius=radius, + start_angle=(_start_point - center).angle_deg, + end_angle=(_end_point - center).angle_deg, + is_counter_clockwise=True, + ) + + @classmethod + def from_2p_radius( + cls, + start_point: UVec, + end_point: UVec, + radius: float, + ccw: bool = True, + center_is_left: bool = True, + ) -> ConstructionArc: + """Create arc from two points and arc radius. + Additional precondition: arc goes by default in counter-clockwise + orientation from `start_point` to `end_point` can be changed + by `ccw` = ``False``. + + The parameter `center_is_left` defines if the center of the arc is + left or right of the line from `start_point` to `end_point`. + Parameter `ccw` = ``False`` swaps start- and end point, which also + inverts the meaning of ``center_is_left``. + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + radius: arc radius + ccw: counter-clockwise direction if ``True`` + center_is_left: center point of arc is left of line from start- to + end point if ``True`` + + """ + _start_point, _end_point = cls.validate_start_and_end_point( + start_point, end_point + ) + radius = float(radius) + if radius <= 0: + raise ValueError("Radius has to be > 0.") + if ccw is False: + _start_point, _end_point = _end_point, _start_point + + mid_point: Vec2 = _end_point.lerp(_start_point, factor=0.5) + distance: float = _end_point.distance(_start_point) + distance2: float = distance / 2.0 + height: float = math.sqrt(radius ** 2 - distance2 ** 2) + center: Vec2 = mid_point + (_end_point - _start_point).orthogonal( + ccw=center_is_left + ).normalize(height) + + return ConstructionArc( + center=center, + radius=radius, + start_angle=(_start_point - center).angle_deg, + end_angle=(_end_point - center).angle_deg, + is_counter_clockwise=True, + ) + + @classmethod + def from_3p( + cls, + start_point: UVec, + end_point: UVec, + def_point: UVec, + ccw: bool = True, + ) -> ConstructionArc: + """Create arc from three points. + Additional precondition: arc goes in counter-clockwise + orientation from `start_point` to `end_point`. + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + def_point: additional definition point as :class:`Vec2` compatible + object + ccw: counter-clockwise direction if ``True`` + + """ + start_point, end_point = cls.validate_start_and_end_point( + start_point, end_point + ) + def_point = Vec2(def_point) + if def_point == start_point or def_point == end_point: + raise ValueError( + "def_point has to be different to start- and end point" + ) + + circle = ConstructionCircle.from_3p(start_point, end_point, def_point) + center = Vec2(circle.center) + return ConstructionArc( + center=center, + radius=circle.radius, + start_angle=(start_point - center).angle_deg, + end_angle=(end_point - center).angle_deg, + is_counter_clockwise=ccw, + ) + + def add_to_layout( + self, layout: BaseLayout, ucs: Optional[UCS] = None, dxfattribs=None + ) -> Arc: + """Add arc as DXF :class:`~ezdxf.entities.Arc` entity to a layout. + + Supports 3D arcs by using an :ref:`UCS`. An :class:`ConstructionArc` is + always defined in the xy-plane, but by using an arbitrary UCS, the arc + can be placed in 3D space, automatically OCS transformation included. + + Args: + layout: destination layout as :class:`~ezdxf.layouts.BaseLayout` + object + ucs: place arc in 3D space by :class:`~ezdxf.math.UCS` object + dxfattribs: additional DXF attributes for the ARC entity + + """ + arc = layout.add_arc( + center=self.center, + radius=self.radius, + start_angle=self.start_angle, + end_angle=self.end_angle, + dxfattribs=dxfattribs, + ) + return arc if ucs is None else arc.transform(ucs.matrix) + + def intersect_ray( + self, ray: ConstructionRay, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of arc and `ray` as sequence of + :class:`Vec2` objects. + + Args: + ray: intersection ray + abs_tol: absolute tolerance for tests (e.g. test for tangents) + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 line intersects or touches the arc at one point + 2 line intersects the arc at two points + =========== ================================== + + """ + assert isinstance(ray, ConstructionRay) + return [ + point + for point in self.circle.intersect_ray(ray, abs_tol) + if self._is_point_in_arc_range(point) + ] + + def intersect_line( + self, line: ConstructionLine, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of arc and `line` as sequence of + :class:`Vec2` objects. + + Args: + line: intersection line + abs_tol: absolute tolerance for tests (e.g. test for tangents) + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 line intersects or touches the arc at one point + 2 line intersects the arc at two points + =========== ================================== + + """ + assert isinstance(line, ConstructionLine) + return [ + point + for point in self.circle.intersect_line(line, abs_tol) + if self._is_point_in_arc_range(point) + ] + + def intersect_circle( + self, circle: ConstructionCircle, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of arc and `circle` as sequence of + :class:`Vec2` objects. + + Args: + circle: intersection circle + abs_tol: absolute tolerance for tests + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 circle intersects or touches the arc at one point + 2 circle intersects the arc at two points + =========== ================================== + + """ + assert isinstance(circle, ConstructionCircle) + return [ + point + for point in self.circle.intersect_circle(circle, abs_tol) + if self._is_point_in_arc_range(point) + ] + + def intersect_arc( + self, other: ConstructionArc, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of two arcs as sequence of + :class:`Vec2` objects. + + Args: + other: other intersection arc + abs_tol: absolute tolerance for tests + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 other arc intersects or touches the arc at one point + 2 other arc intersects the arc at two points + =========== ================================== + + """ + assert isinstance(other, ConstructionArc) + return [ + point + for point in self.circle.intersect_circle(other.circle, abs_tol) + if self._is_point_in_arc_range(point) + and other._is_point_in_arc_range(point) + ] + + def _is_point_in_arc_range(self, point: Vec2) -> bool: + # The point has to be on the circle defined by the arc, this is not + # tested here! Helper tools to check intersections. + start: float = self.start_angle % 360.0 + end: float = self.end_angle % 360.0 + angle: float = (point - self.center).angle_deg % 360.0 + if start > end: # arc passes 0 degree + return angle >= start or angle <= end + return start <= angle <= end + + +def arc_chord_length(radius: float, sagitta: float) -> float: + """Returns the chord length for an arc defined by `radius` and + the `sagitta`_. + + Args: + radius: arc radius + sagitta: distance from the center of the arc to the center of its base + + """ + return 2.0 * math.sqrt(2.0 * radius * sagitta - sagitta * sagitta) + + +def arc_segment_count(radius: float, angle: float, sagitta: float) -> int: + """Returns the count of required segments for the approximation + of an arc for a given maximum `sagitta`_. + + Args: + radius: arc radius + angle: angle span of the arc in radians + sagitta: max. distance from the center of an arc segment to the + center of its chord + + """ + chord_length: float = arc_chord_length(radius, sagitta) + alpha: float = math.asin(chord_length / 2.0 / radius) * 2.0 + return math.ceil(angle / alpha) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/bbox.py b/.venv/lib/python3.12/site-packages/ezdxf/math/bbox.py new file mode 100644 index 0000000..f600131 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/bbox.py @@ -0,0 +1,457 @@ +# Copyright (c) 2019-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional, Iterator, Sequence, TypeVar, Generic +import abc +import math +import numpy as np + +from ezdxf.math import Vec3, Vec2, UVec + +T = TypeVar("T", Vec2, Vec3) + +__all__ = ["BoundingBox2d", "BoundingBox", "AbstractBoundingBox"] + + +class AbstractBoundingBox(Generic[T], abc.ABC): + extmin: T + extmax: T + + @abc.abstractmethod + def __init__(self, vertices: Optional[Iterable[UVec]] = None): + ... + + def copy(self): + box = self.__class__() + box.extmin = self.extmin + box.extmax = self.extmax + return box + + def __str__(self) -> str: + return f"[{self.extmin}, {self.extmax}]" + + def __repr__(self) -> str: + name = self.__class__.__name__ + if self.has_data: + return f"{name}({self.__str__()})" + else: + return f"{name}()" + + def __iter__(self) -> Iterator[T]: + if self.has_data: + yield self.extmin + yield self.extmax + + @abc.abstractmethod + def extend(self, vertices: Iterable[UVec]) -> None: + ... + + @property + @abc.abstractmethod + def is_empty(self) -> bool: + ... + + @abc.abstractmethod + def inside(self, vertex: UVec) -> bool: + ... + + @abc.abstractmethod + def has_intersection(self, other: AbstractBoundingBox[T]) -> bool: + ... + + @abc.abstractmethod + def has_overlap(self, other: AbstractBoundingBox[T]) -> bool: + ... + + @abc.abstractmethod + def intersection(self, other: AbstractBoundingBox[T]) -> AbstractBoundingBox[T]: + ... + + def contains(self, other: AbstractBoundingBox[T]) -> bool: + """Returns ``True`` if the `other` bounding box is completely inside + this bounding box. + + """ + return self.inside(other.extmin) and self.inside(other.extmax) + + def any_inside(self, vertices: Iterable[UVec]) -> bool: + """Returns ``True`` if any vertex is inside this bounding box. + + Vertices at the box border are inside! + """ + if self.has_data: + return any(self.inside(v) for v in vertices) + return False + + def all_inside(self, vertices: Iterable[UVec]) -> bool: + """Returns ``True`` if all vertices are inside this bounding box. + + Vertices at the box border are inside! + """ + if self.has_data: + # all() returns True for an empty set of vertices + has_any = False + for v in vertices: + has_any = True + if not self.inside(v): + return False + return has_any + return False + + @property + def has_data(self) -> bool: + """Returns ``True`` if the bonding box has known limits.""" + return math.isfinite(self.extmin.x) + + @property + def size(self) -> T: + """Returns size of bounding box.""" + return self.extmax - self.extmin + + @property + def center(self) -> T: + """Returns center of bounding box.""" + return self.extmin.lerp(self.extmax) + + def union(self, other: AbstractBoundingBox[T]) -> AbstractBoundingBox[T]: + """Returns a new bounding box as union of this and `other` bounding + box. + """ + vertices: list[T] = [] + if self.has_data: + vertices.extend(self) + if other.has_data: + vertices.extend(other) + return self.__class__(vertices) + + def rect_vertices(self) -> Sequence[Vec2]: + """Returns the corners of the bounding box in the xy-plane as + :class:`Vec2` objects. + """ + if self.has_data: + x0, y0, *_ = self.extmin + x1, y1, *_ = self.extmax + return Vec2(x0, y0), Vec2(x1, y0), Vec2(x1, y1), Vec2(x0, y1) + else: + raise ValueError("empty bounding box") + + def grow(self, value: float) -> None: + """Grow or shrink the bounding box by an uniform value in x, y and + z-axis. A negative value shrinks the bounding box. + Raises :class:`ValueError` for shrinking the size of the bounding box to + zero or below in any dimension. + """ + if self.has_data: + if value < 0.0: + min_ext = min(self.size) + if -value >= min_ext / 2.0: + raise ValueError("shrinking one or more dimensions <= 0") + self.extmax += Vec3(value, value, value) + self.extmin += Vec3(-value, -value, -value) + + +class BoundingBox(AbstractBoundingBox[Vec3]): + """3D bounding box. + + Args: + vertices: iterable of ``(x, y, z)`` tuples or :class:`Vec3` objects + + """ + + __slots__ = ("extmin", "extmax") + + def __init__(self, vertices: Optional[Iterable[UVec]] = None): + self.extmin = Vec3(math.inf, math.inf, math.inf) + self.extmax = self.extmin + if vertices is not None: + try: + self.extmin, self.extmax = extents3d(vertices) + except ValueError: + # No or invalid data creates an empty BoundingBox + pass + + @property + def is_empty(self) -> bool: + """Returns ``True`` if the bounding box is empty or the bounding box + has a size of 0 in any or all dimensions or is undefined. + + """ + if self.has_data: + sx, sy, sz = self.size + return sx * sy * sz == 0.0 + return True + + def extend(self, vertices: Iterable[UVec]) -> None: + """Extend bounds by `vertices`. + + Args: + vertices: iterable of vertices + + """ + v = list(vertices) + if not v: + return + if self.has_data: + v.extend([self.extmin, self.extmax]) + self.extmin, self.extmax = extents3d(v) + + def inside(self, vertex: UVec) -> bool: + """Returns ``True`` if `vertex` is inside this bounding box. + + Vertices at the box border are inside! + """ + if not self.has_data: + return False + x, y, z = Vec3(vertex).xyz + xmin, ymin, zmin = self.extmin.xyz + xmax, ymax, zmax = self.extmax.xyz + return (xmin <= x <= xmax) and (ymin <= y <= ymax) and (zmin <= z <= zmax) + + def has_intersection(self, other: AbstractBoundingBox[T]) -> bool: + """Returns ``True`` if this bounding box intersects with `other` but does + not include touching bounding boxes, see also :meth:`has_overlap`:: + + bbox1 = BoundingBox([(0, 0, 0), (1, 1, 1)]) + bbox2 = BoundingBox([(1, 1, 1), (2, 2, 2)]) + assert bbox1.has_intersection(bbox2) is False + + """ + # Source: https://gamemath.com/book/geomtests.html#intersection_two_aabbs + # Check for a separating axis: + if not self.has_data or not other.has_data: + return False + o_min = Vec3(other.extmin) # could be a 2D bounding box + o_max = Vec3(other.extmax) # could be a 2D bounding box + + # Check for a separating axis: + if self.extmin.x >= o_max.x: + return False + if self.extmax.x <= o_min.x: + return False + if self.extmin.y >= o_max.y: + return False + if self.extmax.y <= o_min.y: + return False + if self.extmin.z >= o_max.z: + return False + if self.extmax.z <= o_min.z: + return False + return True + + def has_overlap(self, other: AbstractBoundingBox[T]) -> bool: + """Returns ``True`` if this bounding box intersects with `other` but + in contrast to :meth:`has_intersection` includes touching bounding boxes too:: + + bbox1 = BoundingBox([(0, 0, 0), (1, 1, 1)]) + bbox2 = BoundingBox([(1, 1, 1), (2, 2, 2)]) + assert bbox1.has_overlap(bbox2) is True + + """ + # Source: https://gamemath.com/book/geomtests.html#intersection_two_aabbs + # Check for a separating axis: + if not self.has_data or not other.has_data: + return False + o_min = Vec3(other.extmin) # could be a 2D bounding box + o_max = Vec3(other.extmax) # could be a 2D bounding box + # Check for a separating axis: + if self.extmin.x > o_max.x: + return False + if self.extmax.x < o_min.x: + return False + if self.extmin.y > o_max.y: + return False + if self.extmax.y < o_min.y: + return False + if self.extmin.z > o_max.z: + return False + if self.extmax.z < o_min.z: + return False + return True + + def cube_vertices(self) -> Sequence[Vec3]: + """Returns the 3D corners of the bounding box as :class:`Vec3` objects.""" + if self.has_data: + x0, y0, z0 = self.extmin + x1, y1, z1 = self.extmax + return ( + Vec3(x0, y0, z0), + Vec3(x1, y0, z0), + Vec3(x1, y1, z0), + Vec3(x0, y1, z0), + Vec3(x0, y0, z1), + Vec3(x1, y0, z1), + Vec3(x1, y1, z1), + Vec3(x0, y1, z1), + ) + else: + raise ValueError("empty bounding box") + + def intersection(self, other: AbstractBoundingBox[T]) -> BoundingBox: + """Returns the bounding box of the intersection cube of both + 3D bounding boxes. Returns an empty bounding box if the intersection + volume is 0. + + """ + new_bbox = self.__class__() + if not self.has_intersection(other): + return new_bbox + s_min_x, s_min_y, s_min_z = Vec3(self.extmin) + o_min_x, o_min_y, o_min_z = Vec3(other.extmin) + s_max_x, s_max_y, s_max_z = Vec3(self.extmax) + o_max_x, o_max_y, o_max_z = Vec3(other.extmax) + new_bbox.extend( + [ + ( + max(s_min_x, o_min_x), + max(s_min_y, o_min_y), + max(s_min_z, o_min_z), + ), + ( + min(s_max_x, o_max_x), + min(s_max_y, o_max_y), + min(s_max_z, o_max_z), + ), + ] + ) + return new_bbox + + +class BoundingBox2d(AbstractBoundingBox[Vec2]): + """2D bounding box. + + Args: + vertices: iterable of ``(x, y[, z])`` tuples or :class:`Vec3` objects + + """ + + __slots__ = ("extmin", "extmax") + + def __init__(self, vertices: Optional[Iterable[UVec]] = None): + self.extmin = Vec2(math.inf, math.inf) + self.extmax = self.extmin + if vertices is not None: + try: + self.extmin, self.extmax = extents2d(vertices) + except ValueError: + # No or invalid data creates an empty BoundingBox + pass + + @property + def is_empty(self) -> bool: + """Returns ``True`` if the bounding box is empty. The bounding box has a + size of 0 in any or all dimensions or is undefined. + """ + if self.has_data: + sx, sy = self.size + return sx * sy == 0.0 + return True + + def extend(self, vertices: Iterable[UVec]) -> None: + """Extend bounds by `vertices`. + + Args: + vertices: iterable of vertices + + """ + v = list(vertices) + if not v: + return + if self.has_data: + v.extend([self.extmin, self.extmax]) + self.extmin, self.extmax = extents2d(v) + + def inside(self, vertex: UVec) -> bool: + """Returns ``True`` if `vertex` is inside this bounding box. + + Vertices at the box border are inside! + """ + if not self.has_data: + return False + v = Vec2(vertex) + min_ = self.extmin + max_ = self.extmax + return (min_.x <= v.x <= max_.x) and (min_.y <= v.y <= max_.y) + + def has_intersection(self, other: AbstractBoundingBox[T]) -> bool: + """Returns ``True`` if this bounding box intersects with `other` but does + not include touching bounding boxes, see also :meth:`has_overlap`:: + + bbox1 = BoundingBox2d([(0, 0), (1, 1)]) + bbox2 = BoundingBox2d([(1, 1), (2, 2)]) + assert bbox1.has_intersection(bbox2) is False + + """ + # Source: https://gamemath.com/book/geomtests.html#intersection_two_aabbs + if not self.has_data or not other.has_data: + return False + # Check for a separating axis: + if self.extmin.x >= other.extmax.x: + return False + if self.extmax.x <= other.extmin.x: + return False + if self.extmin.y >= other.extmax.y: + return False + if self.extmax.y <= other.extmin.y: + return False + return True + + def intersection(self, other: AbstractBoundingBox[T]) -> BoundingBox2d: + """Returns the bounding box of the intersection rectangle of both + 2D bounding boxes. Returns an empty bounding box if the intersection + area is 0. + """ + new_bbox = self.__class__() + if not self.has_intersection(other): + return new_bbox + s_min_x, s_min_y = Vec2(self.extmin) + o_min_x, o_min_y = Vec2(other.extmin) + s_max_x, s_max_y = Vec2(self.extmax) + o_max_x, o_max_y = Vec2(other.extmax) + new_bbox.extend( + [ + (max(s_min_x, o_min_x), max(s_min_y, o_min_y)), + (min(s_max_x, o_max_x), min(s_max_y, o_max_y)), + ] + ) + return new_bbox + + def has_overlap(self, other: AbstractBoundingBox[T]) -> bool: + """Returns ``True`` if this bounding box intersects with `other` but + in contrast to :meth:`has_intersection` includes touching bounding boxes too:: + + bbox1 = BoundingBox2d([(0, 0), (1, 1)]) + bbox2 = BoundingBox2d([(1, 1), (2, 2)]) + assert bbox1.has_overlap(bbox2) is True + + """ + # Source: https://gamemath.com/book/geomtests.html#intersection_two_aabbs + if not self.has_data or not other.has_data: + return False + # Check for a separating axis: + if self.extmin.x > other.extmax.x: + return False + if self.extmax.x < other.extmin.x: + return False + if self.extmin.y > other.extmax.y: + return False + if self.extmax.y < other.extmin.y: + return False + return True + + +def extents3d(vertices: Iterable[UVec]) -> tuple[Vec3, Vec3]: + """Returns the extents of the bounding box as tuple (extmin, extmax).""" + vertices = np.array([Vec3(v).xyz for v in vertices], dtype=np.float64) + if len(vertices): + return Vec3(vertices.min(0)), Vec3(vertices.max(0)) + else: + raise ValueError("no vertices given") + + +def extents2d(vertices: Iterable[UVec]) -> tuple[Vec2, Vec2]: + """Returns the extents of the bounding box as tuple (extmin, extmax).""" + vertices = np.array([(x, y) for x, y, *_ in vertices], dtype=np.float64) + if len(vertices): + return Vec2(vertices.min(0)), Vec2(vertices.max(0)) + else: + raise ValueError("no vertices given") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/bezier.py b/.venv/lib/python3.12/site-packages/ezdxf/math/bezier.py new file mode 100644 index 0000000..cbafc6d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/bezier.py @@ -0,0 +1,260 @@ +# Copyright (c) 2010-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence +from functools import lru_cache +import math +import numpy as np + +from ezdxf.math import Vec3, NULLVEC, Matrix44, UVec + + +__all__ = ["Bezier"] + + +""" + +Bezier curves +============= + +https://www.cl.cam.ac.uk/teaching/2000/AGraphHCI/SMEG/node3.html + +A Bezier curve is a weighted sum of n+1 control points, P0, P1, ..., Pn, where +the weights are the Bernstein polynomials. + +The Bezier curve of order n+1 (degree n) has n+1 control points. These are the +first three orders of Bezier curve definitions. + +(75) linear P(t) = (1-t)*P0 + t*P1 +(76) quadratic P(t) = (1-t)^2*P0 + 2*(t-1)*t*P1 + t^2*P2 +(77) cubic P(t) = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3 + +Ways of thinking about Bezier curves +------------------------------------ + +There are several useful ways in which you can think about Bezier curves. +Here are the ones that I use. + +Linear interpolation +~~~~~~~~~~~~~~~~~~~~ + +Equation (75) is obviously a linear interpolation between two points. Equation +(76) can be rewritten as a linear interpolation between linear interpolations +between points. + +Weighted average +~~~~~~~~~~~~~~~~ + +A Bezier curve can be seen as a weighted average of all of its control points. +Because all of the weights are positive, and because the weights sum to one, the +Bezier curve is guaranteed to lie within the convex hull of its control points. + +Refinement of the control polygon +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A Bezier curve can be seen as some sort of refinement of the polygon made by +connecting its control points in order. The Bezier curve starts and ends at the +two end points and its shape is determined by the relative positions of the n-1 +other control points, although it will generally not pass through these other +control points. The tangent vectors at the start and end of the curve pass +through the end point and the immediately adjacent point. + +Continuity +---------- + +You should note that each Bezier curve is independent of any other Bezier curve. +If we wish two Bezier curves to join with any type of continuity, then we must +explicitly position the control points of the second curve so that they bear +the appropriate relationship with the control points in the first curve. + +Any Bezier curve is infinitely differentiable within itself, and is therefore +continuous to any degree. + +""" + + +class Bezier: + """Generic `Bézier curve`_ of any degree. + + A `Bézier curve`_ is a parametric curve used in computer graphics and + related fields. Bézier curves are used to model smooth curves that can be + scaled indefinitely. "Paths", as they are commonly referred to in image + manipulation programs, are combinations of linked Bézier curves. + Paths are not bound by the limits of rasterized images and are intuitive to + modify. (Source: Wikipedia) + + This is a generic implementation which works with any count of definition + points greater than 2, but it is a simple and slow implementation. For more + performance look at the specialized :class:`Bezier4P` and :class:`Bezier3P` + classes. + + Objects are immutable. + + Args: + defpoints: iterable of definition points as :class:`Vec3` compatible objects. + + """ + + def __init__(self, defpoints: Iterable[UVec]): + self._defpoints: Sequence[Vec3] = Vec3.tuple(defpoints) + + @property + def control_points(self) -> Sequence[Vec3]: + """Control points as tuple of :class:`Vec3` objects.""" + return self._defpoints + + def approximate(self, segments: int = 20) -> Iterable[Vec3]: + """Approximates curve by vertices as :class:`Vec3` objects, vertices + count = segments + 1. + """ + return self.points(self.params(segments)) + + def flattening(self, distance: float, segments: int = 4) -> Iterable[Vec3]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments, if the distance from the center + of the approximation segment to the curve is bigger than `distance` the + segment will be subdivided. + + Args: + distance: maximum distance from the center of the curve (Cn) + to the center of the linear (C1) curve between two + approximation points to determine if a segment should be + subdivided. + segments: minimum segment count + + """ + + def subdiv(start_point, end_point, start_t: float, end_t: float): + mid_t = (start_t + end_t) * 0.5 + mid_point = self.point(mid_t) + chk_point = start_point.lerp(end_point) + # center point point is faster than projecting mid point onto + # vector start -> end: + if chk_point.distance(mid_point) < distance: + yield end_point + else: + yield from subdiv(start_point, mid_point, start_t, mid_t) + yield from subdiv(mid_point, end_point, mid_t, end_t) + + dt = 1.0 / segments + t0 = 0.0 + start_point = self._defpoints[0] + yield start_point + while t0 < 1.0: + t1 = t0 + dt + if math.isclose(t1, 1.0): + end_point = self._defpoints[-1] + t1 = 1.0 + else: + end_point = self.point(t1) + yield from subdiv(start_point, end_point, t0, t1) + t0 = t1 + start_point = end_point + + def params(self, segments: int) -> Iterable[float]: + """Yield evenly spaced parameters from 0 to 1 for given segment count.""" + yield from np.linspace(0.0, 1.0, segments + 1) + + def point(self, t: float) -> Vec3: + """Returns a point for parameter `t` in range [0, 1] as :class:`Vec3` + object. + """ + if t < 0.0 or t > 1.0: + raise ValueError("Parameter t not in range [0, 1]") + if (1.0 - t) < 5e-6: + t = 1.0 + point = NULLVEC + pts = self._defpoints + n = len(pts) + + for i in range(n): + point += bernstein_basis(n - 1, i, t) * pts[i] + return point + + def points(self, t: Iterable[float]) -> Iterable[Vec3]: + """Yields multiple points for parameters in vector `t` as :class:`Vec3` + objects. Parameters have to be in range [0, 1]. + """ + for u in t: + yield self.point(u) + + def derivative(self, t: float) -> tuple[Vec3, Vec3, Vec3]: + """Returns (point, 1st derivative, 2nd derivative) tuple for parameter `t` + in range [0, 1] as :class:`Vec3` objects. + """ + if t < 0.0 or t > 1.0: + raise ValueError("Parameter t not in range [0, 1]") + + if (1.0 - t) < 5e-6: + t = 1.0 + pts = self._defpoints + n = len(pts) + n0 = n - 1 + point = NULLVEC + d1 = NULLVEC + d2 = NULLVEC + t2 = t * t + n0_1 = n0 - 1 + if t == 0.0: + d1 = n0 * (pts[1] - pts[0]) + d2 = n0 * n0_1 * (pts[0] - 2.0 * pts[1] + pts[2]) + for i in range(n): + tmp_bas = bernstein_basis(n0, i, t) + point += tmp_bas * pts[i] + if 0.0 < t < 1.0: + _1_t = 1.0 - t + i_n0_t = i - n0 * t + d1 += i_n0_t / (t * _1_t) * tmp_bas * pts[i] + d2 += ( + (i_n0_t * i_n0_t - n0 * t2 - i * (1.0 - 2.0 * t)) + / (t2 * _1_t * _1_t) + * tmp_bas + * pts[i] + ) + if t == 1.0: + d1 = n0 * (pts[n0] - pts[n0_1]) + d2 = n0 * n0_1 * (pts[n0] - 2 * pts[n0_1] + pts[n0 - 2]) + return point, d1, d2 + + def derivatives( + self, t: Iterable[float] + ) -> Iterable[tuple[Vec3, Vec3, Vec3]]: + """Returns multiple (point, 1st derivative, 2nd derivative) tuples for + parameter vector `t` as :class:`Vec3` objects. + Parameters in range [0, 1] + """ + for u in t: + yield self.derivative(u) + + def reverse(self) -> Bezier: + """Returns a new Bèzier-curve with reversed control point order.""" + return Bezier(list(reversed(self.control_points))) + + def transform(self, m: Matrix44) -> Bezier: + """General transformation interface, returns a new :class:`Bezier` curve. + + Args: + m: 4x4 transformation matrix (:class:`ezdxf.math.Matrix44`) + + """ + defpoints = tuple(m.transform_vertices(self.control_points)) + return Bezier(defpoints) + + +def bernstein_basis(n: int, i: int, t: float) -> float: + # handle the special cases to avoid domain problem with pow + if t == 0.0 and i == 0: + ti = 1.0 + else: + ti = pow(t, i) + if n == i and t == 1.0: + tni = 1.0 + else: + tni = pow((1.0 - t), (n - i)) + Ni = factorial(n) / (factorial(i) * factorial(n - i)) + return Ni * ti * tni + + +@lru_cache(maxsize=None) +def factorial(n: int): + return math.factorial(n) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/bezier_interpolation.py b/.venv/lib/python3.12/site-packages/ezdxf/math/bezier_interpolation.py new file mode 100644 index 0000000..f3c1eba --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/bezier_interpolation.py @@ -0,0 +1,76 @@ +# Copyright (c) 2010-2023 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence +from ezdxf.math import Vec3, Bezier4P, UVec + +# These are low-level interpolation tools for B-splines, which can not be +# integrated into other curve related modules! +__all__ = ["cubic_bezier_interpolation", "tangents_cubic_bezier_interpolation"] + + +def cubic_bezier_interpolation( + points: Iterable[UVec], +) -> Iterable[Bezier4P[Vec3]]: + """Returns an interpolation curve for given data `points` as multiple cubic + Bézier-curves. Returns n-1 cubic Bézier-curves for n given data points, + curve i goes from point[i] to point[i+1]. + + Args: + points: data points + + """ + from ezdxf.math.linalg import tridiagonal_matrix_solver + + # Source: https://towardsdatascience.com/b%C3%A9zier-interpolation-8033e9a262c2 + pnts = Vec3.tuple(points) + if len(pnts) < 3: + return + + num = len(pnts) - 1 + + # setup tri-diagonal matrix (a, b, c) + b = [4.0] * num + a = [1.0] * num + c = [1.0] * num + b[0] = 2.0 + b[num - 1] = 7.0 + a[num - 1] = 2.0 + + # setup right-hand side quantities + points_vector = [pnts[0] + 2.0 * pnts[1]] + points_vector.extend( + 2.0 * (2.0 * pnts[i] + pnts[i + 1]) for i in range(1, num - 1) + ) + points_vector.append(8.0 * pnts[num - 1] + pnts[num]) + + # solve tri-diagonal linear equation system + solution = tridiagonal_matrix_solver([a, b, c], points_vector) + control_points_1 = Vec3.list(solution.rows()) + control_points_2 = [ + p * 2.0 - cp for p, cp in zip(pnts[1:], control_points_1[1:]) + ] + control_points_2.append((control_points_1[num - 1] + pnts[num]) / 2.0) + + for defpoints in zip( + pnts, control_points_1, control_points_2, pnts[1:] + ): + yield Bezier4P(defpoints) + + +def tangents_cubic_bezier_interpolation( + fit_points: Sequence[Vec3], normalize=True +) -> list[Vec3]: + if len(fit_points) < 3: + raise ValueError("At least 3 points required") + + curves = list(cubic_bezier_interpolation(fit_points)) + tangents = [ + (curve.control_points[1] - curve.control_points[0]) for curve in curves + ] + + last_points = curves[-1].control_points + tangents.append(last_points[3] - last_points[2]) + if normalize: + tangents = [t.normalize() for t in tangents] + return tangents diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/box.py b/.venv/lib/python3.12/site-packages/ezdxf/math/box.py new file mode 100644 index 0000000..69e9f9e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/box.py @@ -0,0 +1,268 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterable +import math +from ezdxf.math import Vec2, UVec +from .bbox import BoundingBox2d +from .line import ConstructionLine +from .construct2d import point_to_line_relation + + +ABS_TOL = 1e-12 + +__all__ = ["ConstructionBox"] + + +class ConstructionBox: + """Construction tool for 2D rectangles. + + Args: + center: center of rectangle + width: width of rectangle + height: height of rectangle + angle: angle of rectangle in degrees + + """ + + def __init__( + self, + center: UVec = (0, 0), + width: float = 1, + height: float = 1, + angle: float = 0, + ): + self._center = Vec2(center) + self._width: float = abs(width) + self._height: float = abs(height) + self._angle: float = angle # in degrees + # corners: lower left, lower right, upper right, upper left: + self._corners: Sequence[Vec2] = tuple() + self._tainted: bool = True + + @classmethod + def from_points(cls, p1: UVec, p2: UVec) -> ConstructionBox: + """Creates a box from two opposite corners, box sides are parallel to x- + and y-axis. + + Args: + p1: first corner as :class:`Vec2` compatible object + p2: second corner as :class:`Vec2` compatible object + + """ + _p1 = Vec2(p1) + _p2 = Vec2(p2) + width: float = abs(_p2.x - _p1.x) + height: float = abs(_p2.y - _p1.y) + center: Vec2 = _p1.lerp(_p2) + return cls(center=center, width=width, height=height) + + def update(self) -> None: + if not self._tainted: + return + center = self.center + w2 = Vec2.from_deg_angle(self._angle, self._width / 2.0) + h2 = Vec2.from_deg_angle(self._angle + 90, self._height / 2.0) + self._corners = ( + center - w2 - h2, # lower left + center + w2 - h2, # lower right + center + w2 + h2, # upper right + center - w2 + h2, # upper left + ) + self._tainted = False + + @property + def bounding_box(self) -> BoundingBox2d: + """:class:`BoundingBox2d`""" + return BoundingBox2d(self.corners) + + @property + def center(self) -> Vec2: + """box center""" + return self._center + + @center.setter + def center(self, c: UVec) -> None: + self._center = Vec2(c) + self._tainted = True + + @property + def width(self) -> float: + """box width""" + return self._width + + @width.setter + def width(self, w: float) -> None: + self._width = abs(w) + self._tainted = True + + @property + def height(self) -> float: + """box height""" + return self._height + + @height.setter + def height(self, h: float) -> None: + self._height = abs(h) + self._tainted = True + + @property + def incircle_radius(self) -> float: + """incircle radius""" + return min(self._width, self._height) * 0.5 + + @property + def circumcircle_radius(self) -> float: + """circum circle radius""" + return math.hypot(self._width, self._height) * 0.5 + + @property + def angle(self) -> float: + """rotation angle in degrees""" + return self._angle + + @angle.setter + def angle(self, a: float) -> None: + self._angle = a + self._tainted = True + + @property + def corners(self) -> Sequence[Vec2]: + """box corners as sequence of :class:`Vec2` objects.""" + self.update() + return self._corners + + def __iter__(self) -> Iterable[Vec2]: + """Iterable of box corners as :class:`Vec2` objects.""" + return iter(self.corners) + + def __getitem__(self, corner) -> Vec2: + """Get corner by index `corner`, ``list`` like slicing is supported.""" + return self.corners[corner] + + def __repr__(self) -> str: + """Returns string representation of box as + ``ConstructionBox(center, width, height, angle)``""" + return f"ConstructionBox({self.center}, {self.width}, {self.height}, {self.angle})" + + def translate(self, dx: float, dy: float) -> None: + """Move box about `dx` in x-axis and about `dy` in y-axis. + + Args: + dx: translation in x-axis + dy: translation in y-axis + + """ + self.center += Vec2((dx, dy)) + + def expand(self, dw: float, dh: float) -> None: + """Expand box: `dw` expand width, `dh` expand height.""" + self.width += dw + self.height += dh + + def scale(self, sw: float, sh: float) -> None: + """Scale box: `sw` scales width, `sh` scales height.""" + self.width *= sw + self.height *= sh + + def rotate(self, angle: float) -> None: + """Rotate box by `angle` in degrees.""" + self.angle += angle + + def is_inside(self, point: UVec) -> bool: + """Returns ``True`` if `point` is inside of box.""" + point = Vec2(point) + delta = self.center - point + if abs(self.angle) < ABS_TOL: # fast path for horizontal rectangles + return abs(delta.x) <= (self._width / 2.0) and abs(delta.y) <= ( + self._height / 2.0 + ) + else: + distance = delta.magnitude + if distance > self.circumcircle_radius: + return False + elif distance <= self.incircle_radius: + return True + else: + # inside if point is "left of line" of all borderlines. + p1, p2, p3, p4 = self.corners + return all( + ( + point_to_line_relation(point, a, b) < 1 + for a, b in [(p1, p2), (p2, p3), (p3, p4), (p4, p1)] + ) + ) + + def is_any_corner_inside(self, other: ConstructionBox) -> bool: + """Returns ``True`` if any corner of `other` box is inside this box.""" + return any(self.is_inside(p) for p in other.corners) + + def is_overlapping(self, other: ConstructionBox) -> bool: + """Returns ``True`` if this box and `other` box do overlap.""" + distance = (self.center - other.center).magnitude + max_distance = self.circumcircle_radius + other.circumcircle_radius + if distance > max_distance: + return False + min_distance = self.incircle_radius + other.incircle_radius + if distance <= min_distance: + return True + + if self.is_any_corner_inside(other): + return True + if other.is_any_corner_inside(self): + return True + # no corner is inside of any box, maybe crossing boxes? + # check intersection of diagonals + c1, c2, c3, c4 = self.corners + diag1 = ConstructionLine(c1, c3) + diag2 = ConstructionLine(c2, c4) + + t1, t2, t3, t4 = other.corners + test_diag = ConstructionLine(t1, t3) + if test_diag.has_intersection(diag1) or test_diag.has_intersection( + diag2 + ): + return True + test_diag = ConstructionLine(t2, t4) + if test_diag.has_intersection(diag1) or test_diag.has_intersection( + diag2 + ): + return True + + return False + + def border_lines(self) -> Sequence[ConstructionLine]: + """Returns borderlines of box as sequence of :class:`ConstructionLine`.""" + p1, p2, p3, p4 = self.corners + return ( + ConstructionLine(p1, p2), + ConstructionLine(p2, p3), + ConstructionLine(p3, p4), + ConstructionLine(p4, p1), + ) + + def intersect(self, line: ConstructionLine) -> list[Vec2]: + """Returns 0, 1 or 2 intersection points between `line` and box + borderlines. + + Args: + line: line to intersect with borderlines + + Returns: + list of intersection points + + =========== ================================== + list size Description + =========== ================================== + 0 no intersection + 1 line touches box at one corner + 2 line intersects with box + =========== ================================== + + """ + result = set() + for border_line in self.border_lines(): + p = line.intersect(border_line) + if p is not None: + result.add(p) + return sorted(result) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/bspline.py b/.venv/lib/python3.12/site-packages/ezdxf/math/bspline.py new file mode 100644 index 0000000..e325dcb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/bspline.py @@ -0,0 +1,1567 @@ +# Copyright (c) 2012-2024, Manfred Moitzi +# License: MIT License +""" +B-Splines +========= + +https://www.cl.cam.ac.uk/teaching/2000/AGraphHCI/SMEG/node4.html + +Rational B-splines +================== + +https://www.cl.cam.ac.uk/teaching/2000/AGraphHCI/SMEG/node5.html: + +"The NURBS Book" by Les Piegl and Wayne Tiller + +https://books.google.at/books/about/The_NURBS_Book.html?id=7dqY5dyAwWkC&redir_esc=y + +""" +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + Sequence, + TYPE_CHECKING, + Optional, +) +import math +import numpy as np + +from ezdxf.math import ( + Vec3, + UVec, + NULLVEC, + Basis, + Evaluator, + create_t_vector, + estimate_end_tangent_magnitude, + distance_point_line_3d, + arc_angle_span_deg, +) +from ezdxf.math import linalg +from ezdxf.lldxf.const import DXFValueError + + +if TYPE_CHECKING: + from ezdxf.math import ( + ConstructionArc, + ConstructionEllipse, + Matrix44, + Bezier4P, + ) + + +__all__ = [ + # High level functions: + "fit_points_to_cad_cv", + "global_bspline_interpolation", + "local_cubic_bspline_interpolation", + "rational_bspline_from_arc", + "rational_bspline_from_ellipse", + "fit_points_to_cubic_bezier", + "open_uniform_bspline", + "closed_uniform_bspline", + # B-spline representation with derivatives support: + "BSpline", + # Low level interpolation function: + "unconstrained_global_bspline_interpolation", + "global_bspline_interpolation_end_tangents", + "cad_fit_point_interpolation", + "global_bspline_interpolation_first_derivatives", + "local_cubic_bspline_interpolation_from_tangents", + # Low level knot parametrization functions: + "knots_from_parametrization", + "averaged_knots_unconstrained", + "averaged_knots_constrained", + "natural_knots_unconstrained", + "natural_knots_constrained", + "double_knots", + # Low level knot function: + "required_knot_values", + "uniform_knot_vector", + "open_uniform_knot_vector", + "required_fit_points", + "required_control_points", +] + + +def fit_points_to_cad_cv( + fit_points: Iterable[UVec], + tangents: Optional[Iterable[UVec]] = None, +) -> BSpline: + """Returns a cubic :class:`BSpline` from fit points as close as possible + to common CAD applications like BricsCAD. + + There exist infinite numerical correct solution for this setup, but some + facts are known: + + - CAD applications use the global curve interpolation with start- and end + derivatives if the end tangents are defined otherwise the equation system will + be completed by setting the second derivatives of the start and end point to 0, + for more information read this answer on stackoverflow: https://stackoverflow.com/a/74863330/6162864 + - The degree of the B-spline is always 3 regardless which degree is stored in the + SPLINE entity, this is only valid for B-splines defined by fit points + - Knot parametrization method is "chord" + - Knot distribution is "natural" + + Args: + fit_points: points the spline is passing through + tangents: start- and end tangent, default is autodetect + + """ + # See also Spline class in ezdxf/entities/spline.py: + points = Vec3.list(fit_points) + if len(points) < 2: + raise ValueError("two or more points required ") + + if tangents is None: + control_points, knots = cad_fit_point_interpolation(points) + return BSpline(control_points, order=4, knots=knots) + t = Vec3.list(tangents) + m1, m2 = estimate_end_tangent_magnitude(points, method="chord") + start_tangent = t[0].normalize(m1) + end_tangent = t[-1].normalize(m2) + + return global_bspline_interpolation( + points, + degree=3, + tangents=(start_tangent, end_tangent), + method="chord", + ) + + +def fit_points_to_cubic_bezier(fit_points: Iterable[UVec]) -> BSpline: + """Returns a cubic :class:`BSpline` from fit points **without** end + tangents. + + This function uses the cubic Bèzier interpolation to create multiple Bèzier + curves and combine them into a single B-spline, this works for short simple + splines better than the :func:`fit_points_to_cad_cv`, but is worse + for longer and more complex splines. + + Args: + fit_points: points the spline is passing through + + """ + points = Vec3.list(fit_points) + if len(points) < 2: + raise ValueError("two or more points required ") + + from ezdxf.math import cubic_bezier_interpolation, bezier_to_bspline + + bezier_curves = cubic_bezier_interpolation(points) + return bezier_to_bspline(bezier_curves) + + +def global_bspline_interpolation( + fit_points: Iterable[UVec], + degree: int = 3, + tangents: Optional[Iterable[UVec]] = None, + method: str = "chord", +) -> BSpline: + """`B-spline`_ interpolation by the `Global Curve Interpolation`_. + Given are the fit points and the degree of the B-spline. + The function provides 3 methods for generating the parameter vector t: + + - "uniform": creates a uniform t vector, from 0 to 1 evenly spaced, see + `uniform`_ method + - "chord", "distance": creates a t vector with values proportional to the + fit point distances, see `chord length`_ method + - "centripetal", "sqrt_chord": creates a t vector with values proportional + to the fit point sqrt(distances), see `centripetal`_ method + - "arc": creates a t vector with values proportional to the arc length + between fit points. + + It is possible to constraint the curve by tangents, by start- and end + tangent if only two tangents are given or by one tangent for each fit point. + + If tangents are given, they represent 1st derivatives and should be + scaled if they are unit vectors, if only start- and end tangents given the + function :func:`~ezdxf.math.estimate_end_tangent_magnitude` helps with an + educated guess, if all tangents are given, scaling by chord length is a + reasonable choice (Piegl & Tiller). + + Args: + fit_points: fit points of B-spline, as list of :class:`Vec3` compatible + objects + tangents: if only two vectors are given, take the first and the last + vector as start- and end tangent constraints or if for all fit + points a tangent is given use all tangents as interpolation + constraints (optional) + degree: degree of B-spline + method: calculation method for parameter vector t + + Returns: + :class:`BSpline` + + """ + _fit_points = Vec3.list(fit_points) + count = len(_fit_points) + order: int = degree + 1 + + if tangents: + # two control points for tangents will be added + count += 2 + if order > count and tangents is None: + raise ValueError(f"More fit points required for degree {degree}") + + t_vector = list(create_t_vector(_fit_points, method)) + # natural knot generation for uneven degrees else averaged + knot_generation_method = "natural" if degree % 2 else "average" + if tangents is not None: + _tangents = Vec3.list(tangents) + if len(_tangents) == 2: + control_points, knots = global_bspline_interpolation_end_tangents( + _fit_points, + _tangents[0], + _tangents[1], + degree, + t_vector, + knot_generation_method, + ) + elif len(_tangents) == len(_fit_points): + ( + control_points, + knots, + ) = global_bspline_interpolation_first_derivatives( + _fit_points, _tangents, degree, t_vector + ) + else: + raise ValueError( + "Invalid count of tangents, two tangents as start- and end " + "tangent constrains or one tangent for each fit point." + ) + else: + control_points, knots = unconstrained_global_bspline_interpolation( + _fit_points, degree, t_vector, knot_generation_method + ) + bspline = BSpline(control_points, order=order, knots=knots) + return bspline + + +def local_cubic_bspline_interpolation( + fit_points: Iterable[UVec], + method: str = "5-points", + tangents: Optional[Iterable[UVec]] = None, +) -> BSpline: + """`B-spline`_ interpolation by 'Local Cubic Curve Interpolation', which + creates B-spline from fit points and estimated tangent direction at start-, + end- and passing points. + + Source: Piegl & Tiller: "The NURBS Book" - chapter 9.3.4 + + Available tangent estimation methods: + + - "3-points": 3 point interpolation + - "5-points": 5 point interpolation + - "bezier": cubic bezier curve interpolation + - "diff": finite difference + + or pass pre-calculated tangents, which overrides tangent estimation. + + Args: + fit_points: all B-spline fit points as :class:`Vec3` compatible objects + method: tangent estimation method + tangents: tangents as :class:`Vec3` compatible objects (optional) + + Returns: + :class:`BSpline` + + """ + from .parametrize import estimate_tangents + + _fit_points = Vec3.list(fit_points) + if tangents: + _tangents = Vec3.list(tangents) + else: + _tangents = estimate_tangents(_fit_points, method) + control_points, knots = local_cubic_bspline_interpolation_from_tangents( + _fit_points, _tangents + ) + return BSpline(control_points, order=4, knots=knots) + + +def required_knot_values(count: int, order: int) -> int: + """Returns the count of required knot-values for a B-spline of `order` and + `count` control points. + + Args: + count: count of control points, in text-books referred as "n + 1" + order: order of B-Spline, in text-books referred as "k" + + Relationship: + + "p" is the degree of the B-spline, text-book notation. + + - k = p + 1 + - 2 ≤ k ≤ n + 1 + + """ + k = int(order) + n = int(count) - 1 + p = k - 1 + if not (2 <= k <= (n + 1)): + raise DXFValueError("Invalid count/order combination") + # n + p + 2 = count + order + return n + p + 2 + + +def required_fit_points(order: int, tangents=True) -> int: + """Returns the count of required fit points to calculate the spline + control points. + + Args: + order: spline order (degree + 1) + tangents: start- and end tangent are given or estimated + + """ + if tangents: + # If tangents are given or estimated two points for start- and end + # tangent will be added automatically for the global bspline + # interpolation. see function fit_points_to_cad_cv() + order -= 2 + # required condition: order > count, see global_bspline_interpolation() + return max(order, 2) + + +def required_control_points(order: int) -> int: + """Returns the required count of control points for a valid B-spline. + + Args: + order: spline order (degree + 1) + + Required condition: 2 <= order <= count, therefore: count >= order + + """ + return max(order, 2) + + +def normalize_knots(knots: Sequence[float]) -> list[float]: + """Normalize knot vector into range [0, 1].""" + min_val = knots[0] + max_val = knots[-1] - min_val + return [(v - min_val) / max_val for v in knots] + + +def uniform_knot_vector(count: int, order: int, normalize=False) -> list[float]: + """Returns an uniform knot vector for a B-spline of `order` and `count` + control points. + + `order` = degree + 1 + + Args: + count: count of control points + order: spline order + normalize: normalize values in range [0, 1] if ``True`` + + """ + if normalize: + max_value = float(count + order - 1) + else: + max_value = 1.0 + return [knot_value / max_value for knot_value in range(count + order)] + + +def open_uniform_knot_vector(count: int, order: int, normalize=False) -> list[float]: + """Returns an open (clamped) uniform knot vector for a B-spline of `order` + and `count` control points. + + `order` = degree + 1 + + Args: + count: count of control points + order: spline order + normalize: normalize values in range [0, 1] if ``True`` + + """ + k = count - order + if normalize: + max_value = float(count - order + 1) + tail = [1.0] * order + else: + max_value = 1.0 + tail = [1.0 + k] * order + + knots = [0.0] * order + knots.extend((1.0 + v) / max_value for v in range(k)) + knots.extend(tail) + return knots + + +def knots_from_parametrization( + n: int, p: int, t: Iterable[float], method="average", constrained=False +) -> list[float]: + """Returns a 'clamped' knot vector for B-splines. All knot values are + normalized in the range [0, 1]. + + Args: + n: count fit points - 1 + p: degree of spline + t: parametrization vector, length(t_vector) == n, normalized [0, 1] + method: "average", "natural" + constrained: ``True`` for B-spline constrained by end derivatives + + Returns: + List of n+p+2 knot values as floats + + """ + order = int(p + 1) + if order > (n + 1): + raise DXFValueError("Invalid n/p combination, more fit points required.") + + t = [float(v) for v in t] + if t[0] != 0.0 or not math.isclose(t[-1], 1.0): + raise ValueError("Parametrization vector t has to be normalized.") + + if method == "average": + return ( + averaged_knots_constrained(n, p, t) + if constrained + else averaged_knots_unconstrained(n, p, t) + ) + elif method == "natural": + return ( + natural_knots_constrained(n, p, t) + if constrained + else natural_knots_unconstrained(n, p, t) + ) + else: + raise ValueError(f"Unknown knot generation method: {method}") + + +def averaged_knots_unconstrained(n: int, p: int, t: Sequence[float]) -> list[float]: + """Returns an averaged knot vector from parametrization vector `t` for an + unconstrained B-spline. + + Args: + n: count of control points - 1 + p: degree + t: parametrization vector, normalized [0, 1] + + """ + assert t[0] == 0.0 + assert math.isclose(t[-1], 1.0) + + knots = [0.0] * (p + 1) + knots.extend(sum(t[j : j + p]) / p for j in range(1, n - p + 1)) + if knots[-1] > 1.0: + raise ValueError("Normalized [0, 1] values required") + knots.extend([1.0] * (p + 1)) + return knots + + +def averaged_knots_constrained(n: int, p: int, t: Sequence[float]) -> list[float]: + """Returns an averaged knot vector from parametrization vector `t` for a + constrained B-spline. + + Args: + n: count of control points - 1 + p: degree + t: parametrization vector, normalized [0, 1] + + """ + assert t[0] == 0.0 + assert math.isclose(t[-1], 1.0) + + knots = [0.0] * (p + 1) + knots.extend(sum(t[j : j + p - 1]) / p for j in range(n - p)) + knots.extend([1.0] * (p + 1)) + return knots + + +def natural_knots_unconstrained(n: int, p: int, t: Sequence[float]) -> list[float]: + """Returns a 'natural' knot vector from parametrization vector `t` for an + unconstrained B-spline. + + Args: + n: count of control points - 1 + p: degree + t: parametrization vector, normalized [0, 1] + + """ + assert t[0] == 0.0 + assert math.isclose(t[-1], 1.0) + + knots = [0.0] * (p + 1) + knots.extend(t[2 : n - p + 2]) + knots.extend([1.0] * (p + 1)) + return knots + + +def natural_knots_constrained(n: int, p: int, t: Sequence[float]) -> list[float]: + """Returns a 'natural' knot vector from parametrization vector `t` for a + constrained B-spline. + + Args: + n: count of control points - 1 + p: degree + t: parametrization vector, normalized [0, 1] + + """ + assert t[0] == 0.0 + assert math.isclose(t[-1], 1.0) + + knots = [0.0] * (p + 1) + knots.extend(t[1 : n - p + 1]) + knots.extend([1.0] * (p + 1)) + return knots + + +def double_knots(n: int, p: int, t: Sequence[float]) -> list[float]: + """Returns a knot vector from parametrization vector `t` for B-spline + constrained by first derivatives at all fit points. + + Args: + n: count of fit points - 1 + p: degree of spline + t: parametrization vector, first value has to be 0.0 and last value has + to be 1.0 + + """ + assert t[0] == 0.0 + assert math.isclose(t[-1], 1.0) + + u = [0.0] * (p + 1) + prev_t = 0.0 + + u1 = [] + for t1 in t[1:-1]: + if p == 2: + # add one knot between prev_t and t + u1.append((prev_t + t1) / 2.0) + u1.append(t1) + else: + if prev_t == 0.0: # first knot + u1.append(t1 / 2) + else: + # add one knot at the 1st third and one knot + # at the 2nd third between prev_t and t. + u1.append((2 * prev_t + t1) / 3.0) + u1.append((prev_t + 2 * t1) / 3.0) + prev_t = t1 + u.extend(u1[: n * 2 - p]) + u.append((t[-2] + 1.0) / 2.0) # last knot + u.extend([1.0] * (p + 1)) + return u + + +def _get_best_solver(matrix: list| linalg.Matrix, degree: int) -> linalg.Solver: + """Returns best suited linear equation solver depending on matrix configuration and + python interpreter. + """ + # v1.2: added NumpySolver + # Acceleration of banded diagonal matrix solver is still a thing but only for + # really big matrices N > 30 in pure Python and N > 20 for C-extension np_support + # PyPy has no advantages when using the NumpySolver + if not isinstance(matrix, linalg.Matrix): + matrix =linalg.Matrix(matrix) + + if matrix.nrows < 20: # use default equation solver + return linalg.NumpySolver(matrix.matrix) + else: + # Theory: band parameters m1, m2 are at maximum degree-1, for + # B-spline interpolation and approximation: + # m1 = m2 = degree-1 + # But the speed gain is not that big and just to be sure: + m1, m2 = linalg.detect_banded_matrix(matrix, check_all=False) + A = linalg.compact_banded_matrix(matrix, m1, m2) + return linalg.BandedMatrixLU(A, m1, m2) + + +def unconstrained_global_bspline_interpolation( + fit_points: Sequence[UVec], + degree: int, + t_vector: Sequence[float], + knot_generation_method: str = "average", +) -> tuple[list[Vec3], list[float]]: + """Interpolates the control points for a B-spline by global interpolation + from fit points without any constraints. + + Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.1 + + Args: + fit_points: points the B-spline has to pass + degree: degree of spline >= 2 + t_vector: parametrization vector, first value has to be 0 and last + value has to be 1 + knot_generation_method: knot generation method from parametrization + vector, "average" or "natural" + + Returns: + 2-tuple of control points as list of Vec3 objects and the knot vector + as list of floats + + """ + # Source: http://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/INT-APP/CURVE-INT-global.html + knots = knots_from_parametrization( + len(fit_points) - 1, + degree, + t_vector, + knot_generation_method, + constrained=False, + ) + N = Basis(knots=knots, order=degree + 1, count=len(fit_points)) + solver = _get_best_solver([N.basis_vector(t) for t in t_vector], degree) + mat_B = np.array(fit_points, dtype=np.float64) + control_points = solver.solve_matrix(mat_B) + return Vec3.list(control_points.rows()), knots + + +def global_bspline_interpolation_end_tangents( + fit_points: list[Vec3], + start_tangent: Vec3, + end_tangent: Vec3, + degree: int, + t_vector: Sequence[float], + knot_generation_method: str = "average", +) -> tuple[list[Vec3], list[float]]: + """Calculates the control points for a B-spline by global interpolation + from fit points and the 1st derivative of the start- and end point as constraints. + These 'tangents' are 1st derivatives and not unit vectors, if an estimation + of the magnitudes is required use the :func:`estimate_end_tangent_magnitude` + function. + + Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.2 + + Args: + fit_points: points the B-spline has to pass + start_tangent: 1st derivative as start constraint + end_tangent: 1st derivative as end constrain + degree: degree of spline >= 2 + t_vector: parametrization vector, first value has to be 0 and last + value has to be 1 + knot_generation_method: knot generation method from parametrization + vector, "average" or "natural" + + Returns: + 2-tuple of control points as list of Vec3 objects and the knot vector + as list of floats + + """ + n = len(fit_points) - 1 + p = degree + if degree > 3: + # todo: 'average' produces weird results for degree > 3, 'natural' is + # better but also not good + knot_generation_method = "natural" + knots = knots_from_parametrization( + n + 2, p, t_vector, knot_generation_method, constrained=True + ) + + N = Basis(knots=knots, order=p + 1, count=n + 3) + rows = [N.basis_vector(u) for u in t_vector] + spacing = [0.0] * (n + 1) + rows.insert(1, [-1.0, +1.0] + spacing) + rows.insert(-1, spacing + [-1.0, +1.0]) + fit_points.insert(1, start_tangent * (knots[p + 1] / p)) + fit_points.insert(-1, end_tangent * ((1.0 - knots[-(p + 2)]) / p)) + + solver = _get_best_solver(rows, degree) + control_points = solver.solve_matrix(fit_points) + return Vec3.list(control_points.rows()), knots + + +def cad_fit_point_interpolation( + fit_points: list[Vec3], +) -> tuple[list[Vec3], list[float]]: + """Calculates the control points for a B-spline by global interpolation + from fit points without any constraints in the same way as AutoCAD and BricsCAD. + + Source: https://stackoverflow.com/a/74863330/6162864 + + Args: + fit_points: points the B-spline has to pass + + Returns: + 2-tuple of control points as list of Vec3 objects and the knot vector + as list of floats + + """ + + def coefficients1() -> list[float]: + """Returns the coefficients for equation [1].""" + # Piegl & Tiller: "The NURBS Book" formula (3.9) + up1 = knots[p + 1] + up2 = knots[p + 2] + f = p * (p - 1) / up1 + return [ + f / up1, # P0 + -f * (up1 + up2) / (up1 * up2), # P1 + f / up2, # P2 + ] + + def coefficients2() -> list[float]: + """Returns the coefficients for equation [n-1].""" + # Piegl & Tiller: "The NURBS Book" formula (3.10) + m = len(knots) - 1 + ump1 = knots[m - p - 1] + ump2 = knots[m - p - 2] + f = p * (p - 1) / (1.0 - ump1) + return [ + f / (1.0 - ump2), # Pn-2 + -f * (2.0 - ump1 - ump2) / (1.0 - ump1) / (1.0 - ump2), # Pn-1 + f / (1.0 - ump1), # Pn + ] + + t_vector = list(create_t_vector(fit_points, "chord")) + n = len(fit_points) - 1 + p = 3 + knots = knots_from_parametrization( + n + 2, p, t_vector, method="natural", constrained=True + ) + + N = Basis(knots=knots, order=p + 1, count=n + 3) + rows = [N.basis_vector(u) for u in t_vector] + spacing = [0.0] * n + rows.insert(1, coefficients1() + spacing) + rows.insert(-1, spacing + coefficients2()) + + # C"(0) == 0 + fit_points.insert(1, Vec3(0, 0, 0)) + # C"(1) == 0 + fit_points.insert(-1, Vec3(0, 0, 0)) + + solver = _get_best_solver(rows, p) + control_points = solver.solve_matrix(fit_points) + return Vec3.list(control_points.rows()), knots + + +def global_bspline_interpolation_first_derivatives( + fit_points: list[Vec3], + derivatives: list[Vec3], + degree: int, + t_vector: Sequence[float], +) -> tuple[list[Vec3], list[float]]: + """Interpolates the control points for a B-spline by a global + interpolation from fit points and 1st derivatives as constraints. + + Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.4 + + Args: + fit_points: points the B-spline has to pass + derivatives: 1st derivatives as constrains, not unit vectors! + Scaling by chord length is a reasonable choice (Piegl & Tiller). + degree: degree of spline >= 2 + t_vector: parametrization vector, first value has to be 0 and last + value has to be 1 + + Returns: + 2-tuple of control points as list of Vec3 objects and the knot vector + as list of floats + + """ + + def nbasis(t: float): + span = N.find_span(t) + front = span - p + back = count + p + 1 - span + for basis in N.basis_funcs_derivatives(span, t, n=1): + yield [0.0] * front + basis + [0.0] * back + + p = degree + n = len(fit_points) - 1 + knots = double_knots(n, p, t_vector) + count = len(fit_points) * 2 + N = Basis(knots=knots, order=p + 1, count=count) + A = [ + [1.0] + [0.0] * (count - 1), # Q0 + [-1.0, +1.0] + [0.0] * (count - 2), # D0 + ] + ncols = len(A[0]) + for f in (nbasis(t) for t in t_vector[1:-1]): + A.extend([row[:ncols] for row in f]) # Qi, Di + # swapped equations! + A.append([0.0] * (count - 2) + [-1.0, +1.0]) # Dn + A.append([0.0] * (count - 1) + [+1.0]) # Qn + assert len(set(len(row) for row in A)) == 1, "inhomogeneous matrix detected" + + # Build right handed matrix B + B: list[Vec3] = [] + for rows in zip(fit_points, derivatives): + B.extend(rows) # Qi, Di + + # also swap last rows! + B[-1], B[-2] = B[-2], B[-1] # Dn, Qn + + # modify equation for derivatives D0 and Dn + B[1] *= knots[p + 1] / p + B[-2] *= (1.0 - knots[-(p + 2)]) / p + solver = _get_best_solver(A, degree) + control_points = solver.solve_matrix(B) + return Vec3.list(control_points.rows()), knots + + +def local_cubic_bspline_interpolation_from_tangents( + fit_points: list[Vec3], tangents: list[Vec3] +) -> tuple[list[Vec3], list[float]]: + """Interpolates the control points for a cubic B-spline by local + interpolation from fit points and tangents as unit vectors for each fit + point. Use the :func:`estimate_tangents` function to estimate end tangents. + + Source: Piegl & Tiller: "The NURBS Book" - chapter 9.3.4 + + Args: + fit_points: curve definition points - curve has to pass all given fit + points + tangents: one tangent vector for each fit point as unit vectors + + Returns: + 2-tuple of control points as list of Vec3 objects and the knot vector + as list of floats + + """ + assert len(fit_points) == len(tangents) + assert len(fit_points) > 2 + + degree = 3 + order = degree + 1 + control_points = [fit_points[0]] + u = 0.0 + params = [] + for i in range(len(fit_points) - 1): + p0 = fit_points[i] + p3 = fit_points[i + 1] + t0 = tangents[i] + t3 = tangents[i + 1] + a = 16.0 - (t0 + t3).magnitude_square # always > 0! + b = 12.0 * (p3 - p0).dot(t0 + t3) + c = -36.0 * (p3 - p0).magnitude_square + try: + alpha_plus, alpha_minus = linalg.quadratic_equation(a, b, c) + except ValueError: # complex solution + continue + p1 = p0 + alpha_plus * t0 / 3.0 + p2 = p3 - alpha_plus * t3 / 3.0 + control_points.extend((p1, p2)) + u += 3.0 * (p1 - p0).magnitude + params.append(u) + control_points.append(fit_points[-1]) + + knots = [0.0] * order + max_u = params[-1] + for v in params[:-1]: + knot = v / max_u + knots.extend((knot, knot)) + knots.extend([1.0] * 4) + + assert len(knots) == required_knot_values(len(control_points), order) + return control_points, knots + + +class BSpline: + """B-spline construction tool. + + Internal representation of a `B-spline`_ curve. The default configuration + of the knot vector is a uniform open `knot`_ vector ("clamped"). + + Factory functions: + + - :func:`fit_points_to_cad_cv` + - :func:`fit_points_to_cubic_bezier` + - :func:`open_uniform_bspline` + - :func:`closed_uniform_bspline` + - :func:`rational_bspline_from_arc` + - :func:`rational_bspline_from_ellipse` + - :func:`global_bspline_interpolation` + - :func:`local_cubic_bspline_interpolation` + + Args: + control_points: iterable of control points as :class:`Vec3` compatible + objects + order: spline order (degree + 1) + knots: iterable of knot values + weights: iterable of weight values + + """ + + __slots__ = ("_control_points", "_basis", "_clamped") + + def __init__( + self, + control_points: Iterable[UVec], + order: int = 4, + knots: Optional[Iterable[float]] = None, + weights: Optional[Iterable[float]] = None, + ): + self._control_points = Vec3.tuple(control_points) + count = len(self._control_points) + order = int(order) + if order > count: + raise DXFValueError( + f"got {count} control points, need {order} or more for order of {order}" + ) + + if knots is None: + knots = open_uniform_knot_vector(count, order, normalize=True) + else: + knots = tuple(knots) + required_knot_count = count + order + if len(knots) != required_knot_count: + raise ValueError( + f"{required_knot_count} knot values required, got {len(knots)}." + ) + if knots[0] != 0.0: + knots = normalize_knots(knots) + self._basis = Basis(knots, order, count, weights=weights) + self._clamped = len(set(knots[:order])) == 1 and len(set(knots[-order:])) == 1 + + def __str__(self): + return ( + f"BSpline degree={self.degree}, {self.count} " + f"control points, {len(self.knots())} knot values, " + f"{len(self.weights())} weights" + ) + + @property + def control_points(self) -> Sequence[Vec3]: + """Control points as tuple of :class:`~ezdxf.math.Vec3`""" + return self._control_points + + @property + def count(self) -> int: + """Count of control points, (n + 1 in text book notation).""" + return len(self._control_points) + + @property + def max_t(self) -> float: + """Biggest `knot`_ value.""" + return self._basis.max_t + + @property + def order(self) -> int: + """Order (k) of B-spline = p + 1""" + return self._basis.order + + @property + def degree(self) -> int: + """Degree (p) of B-spline = order - 1""" + return self._basis.degree + + @property + def evaluator(self) -> Evaluator: + return Evaluator(self._basis, self._control_points) + + @property + def is_rational(self): + """Returns ``True`` if curve is a rational B-spline. (has weights)""" + return self._basis.is_rational + + @property + def is_clamped(self): + """Returns ``True`` if curve is a clamped (open) B-spline.""" + return self._clamped + + @staticmethod + def from_fit_points(points: Iterable[UVec], degree=3, method="chord") -> BSpline: + """Returns :class:`BSpline` defined by fit points.""" + return global_bspline_interpolation(points, degree, method=method) + + @staticmethod + def ellipse_approximation(ellipse: ConstructionEllipse, num: int = 16) -> BSpline: + """Returns an ellipse approximation as :class:`BSpline` with `num` + control points. + + """ + return global_bspline_interpolation( + ellipse.vertices(ellipse.params(num)), degree=2 + ) + + @staticmethod + def arc_approximation(arc: ConstructionArc, num: int = 16) -> BSpline: + """Returns an arc approximation as :class:`BSpline` with `num` + control points. + + """ + return global_bspline_interpolation(arc.vertices(arc.angles(num)), degree=2) + + @staticmethod + def from_ellipse(ellipse: ConstructionEllipse) -> BSpline: + """Returns the ellipse as :class:`BSpline` of 2nd degree with as few + control points as possible. + + """ + return rational_bspline_from_ellipse(ellipse, segments=1) + + @staticmethod + def from_arc(arc: ConstructionArc) -> BSpline: + """Returns the arc as :class:`BSpline` of 2nd degree with as few control + points as possible. + + """ + return rational_bspline_from_arc( + arc.center, arc.radius, arc.start_angle, arc.end_angle, segments=1 + ) + + @staticmethod + def from_nurbs_python_curve(curve) -> BSpline: + """Interface to the `NURBS-Python `_ + package. + + Returns a :class:`BSpline` object from a :class:`geomdl.BSpline.Curve` + object. + + """ + return BSpline( + control_points=curve.ctrlpts, + order=curve.order, + knots=curve.knotvector, + weights=curve.weights, + ) + + def reverse(self) -> BSpline: + """Returns a new :class:`BSpline` object with reversed control point + order. + + """ + + def reverse_knots(): + for k in reversed(normalize_knots(self.knots())): + yield 1.0 - k + + return self.__class__( + control_points=reversed(self.control_points), + order=self.order, + knots=reverse_knots(), + weights=reversed(self.weights()) if self.is_rational else None, + ) + + def knots(self) -> Sequence[float]: + """Returns a tuple of `knot`_ values as floats, the knot vector + **always** has order + count values (n + p + 2 in text book notation). + + """ + return self._basis.knots + + def weights(self) -> Sequence[float]: + """Returns a tuple of weights values as floats, one for each control + point or an empty tuple. + + """ + return self._basis.weights + + def approximate(self, segments: int = 20) -> Iterable[Vec3]: + """Approximates curve by vertices as :class:`Vec3` objects, vertices + count = segments + 1. + + """ + return self.evaluator.points(self.params(segments)) + + def params(self, segments: int) -> Iterable[float]: + """Yield evenly spaced parameters for given segment count.""" + # works for clamped and unclamped curves + knots = self.knots() + lower_bound = knots[self.order - 1] + upper_bound = knots[self.count] + return np.linspace(lower_bound, upper_bound, segments + 1) + + def flattening(self, distance: float, segments: int = 4) -> Iterator[Vec3]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments between two knots, if the + distance from the center of the approximation segment to the curve is + bigger than `distance` the segment will be subdivided. + + Args: + distance: maximum distance from the projected curve point onto the + segment chord. + segments: minimum segment count between two knots + + """ + + def subdiv(s: Vec3, e: Vec3, start_t: float, end_t: float): + mid_t = (start_t + end_t) * 0.5 + m = evaluator.point(mid_t) + try: + _dist = distance_point_line_3d(m, s, e) + except ZeroDivisionError: # s == e + _dist = 0 + if _dist < distance: + yield e + else: + yield from subdiv(s, m, start_t, mid_t) + yield from subdiv(m, e, mid_t, end_t) + + evaluator = self.evaluator + knots: list[float] = self.knots() # type: ignore + if self.is_clamped: + lower_bound = 0.0 + else: + lower_bound = knots[self.order - 1] + knots = knots[: self.count + 1] + + knots = list(set(knots)) + knots.sort() + t = lower_bound + start_point = evaluator.point(t) + yield start_point + for t1 in knots[1:]: + delta = (t1 - t) / segments + while t < t1: + next_t = t + delta + if math.isclose(next_t, t1): + next_t = t1 + end_point = evaluator.point(next_t) + yield from subdiv(start_point, end_point, t, next_t) + t = next_t + start_point = end_point + + def point(self, t: float) -> Vec3: + """Returns point for parameter `t`. + + Args: + t: parameter in range [0, max_t] + + """ + return self.evaluator.point(t) + + def points(self, t: Iterable[float]) -> Iterable[Vec3]: + """Yields points for parameter vector `t`. + + Args: + t: parameters in range [0, max_t] + + """ + return self.evaluator.points(t) + + def derivative(self, t: float, n: int = 2) -> list[Vec3]: + """Return point and derivatives up to `n` <= degree for parameter `t`. + + e.g. n=1 returns point and 1st derivative. + + Args: + t: parameter in range [0, max_t] + n: compute all derivatives up to n <= degree + + Returns: + n+1 values as :class:`Vec3` objects + + """ + return self.evaluator.derivative(t, n) + + def derivatives(self, t: Iterable[float], n: int = 2) -> Iterable[list[Vec3]]: + """Yields points and derivatives up to `n` <= degree for parameter + vector `t`. + + e.g. n=1 returns point and 1st derivative. + + Args: + t: parameters in range [0, max_t] + n: compute all derivatives up to n <= degree + + Returns: + List of n+1 values as :class:`Vec3` objects + + """ + return self.evaluator.derivatives(t, n) + + def insert_knot(self, t: float) -> BSpline: + """Insert an additional knot, without altering the shape of the curve. + Returns a new :class:`BSpline` object. + + Args: + t: position of new knot 0 < t < max_t + + """ + if self._basis.is_rational: + raise TypeError("Rational B-splines not supported.") + + knots = list(self._basis.knots) + cpoints = list(self._control_points) + p = self.degree + + def new_point(index: int) -> Vec3: + a = (t - knots[index]) / (knots[index + p] - knots[index]) + return cpoints[index - 1] * (1 - a) + cpoints[index] * a + + if t <= 0.0 or t >= self.max_t: + raise DXFValueError("Invalid position t") + + k = self._basis.find_span(t) + if k < p: + raise DXFValueError("Invalid position t") + + cpoints[k - p + 1 : k] = [new_point(i) for i in range(k - p + 1, k + 1)] + knots.insert(k + 1, t) # knot[k] <= t < knot[k+1] + return BSpline(cpoints, self.order, knots) + + def knot_refinement(self, u: Iterable[float]) -> BSpline: + """Insert multiple knots, without altering the shape of the curve. + Returns a new :class:`BSpline` object. + + Args: + u: vector of new knots t and for each t: 0 < t < max_t + + """ + spline = self + for t in u: + spline = spline.insert_knot(t) + return spline + + def transform(self, m: Matrix44) -> BSpline: + """Returns a new :class:`BSpline` object transformed by a + :class:`Matrix44` transformation matrix. + + """ + cpoints = m.transform_vertices(self.control_points) + return BSpline(cpoints, self.order, self.knots(), self.weights()) + + def bezier_decomposition(self) -> Iterable[list[Vec3]]: + """Decompose a non-rational B-spline into multiple Bézier curves. + + This is the preferred method to represent the most common non-rational + B-splines of 3rd degree by cubic Bézier curves, which are often supported + by render backends. + + Returns: + Yields control points of Bézier curves, each Bézier segment + has degree+1 control points e.g. B-spline of 3rd degree yields + cubic Bézier curves of 4 control points. + + """ + # Source: "The NURBS Book": Algorithm A5.6 + if self._basis.is_rational: + raise TypeError("Rational B-splines not supported.") + if not self.is_clamped: + raise TypeError("Clamped B-Spline required.") + + n = self.count - 1 + p = self.degree + knots = self._basis.knots # U + control_points = self._control_points # Pw + alphas = [0.0] * len(knots) + + m = n + p + 1 + a = p + b = p + 1 + bezier_points = list(control_points[0 : p + 1]) # Qw + + while b < m: + next_bezier_points = [NULLVEC] * (p + 1) + i = b + while b < m and math.isclose(knots[b + 1], knots[b]): + b += 1 + mult = b - i + 1 + if mult < p: + numer = knots[b] - knots[a] + for j in range(p, mult, -1): + alphas[j - mult - 1] = numer / (knots[a + j] - knots[a]) + r = p - mult + for j in range(1, r + 1): + save = r - j + s = mult + j + for k in range(p, s - 1, -1): + alpha = alphas[k - s] + bezier_points[k] = bezier_points[k] * alpha + bezier_points[ + k - 1 + ] * (1.0 - alpha) + if b < m: + next_bezier_points[save] = bezier_points[p] + yield bezier_points + + if b < m: + for i in range(p - mult, p + 1): + next_bezier_points[i] = control_points[b - p + i] + a = b + b += 1 + bezier_points = next_bezier_points + + def cubic_bezier_approximation( + self, level: int = 3, segments: Optional[int] = None + ) -> Iterable[Bezier4P]: + """Approximate arbitrary B-splines (degree != 3 and/or rational) by + multiple segments of cubic Bézier curves. The choice of cubic Bézier + curves is based on the widely support of this curves by many render + backends. For cubic non-rational B-splines, which is maybe the most + common used B-spline, is :meth:`bezier_decomposition` the better choice. + + 1. approximation by `level`: an educated guess, the first level of + approximation segments is based on the count of control points + and their distribution along the B-spline, every additional level + is a subdivision of the previous level. + + E.g. a B-Spline of 8 control points has 7 segments at the first level, + 14 at the 2nd level and 28 at the 3rd level, a level >= 3 is recommended. + + 2. approximation by a given count of evenly distributed approximation + segments. + + Args: + level: subdivision level of approximation segments (ignored if + argument `segments` is not ``None``) + segments: absolute count of approximation segments + + Returns: + Yields control points of cubic Bézier curves as :class:`Bezier4P` + objects + + """ + if segments is None: + points = list(self.points(self.approximation_params(level))) + else: + points = list(self.approximate(segments)) + from .bezier_interpolation import cubic_bezier_interpolation + + return cubic_bezier_interpolation(points) + + def approximation_params(self, level: int = 3) -> Sequence[float]: + """Returns an educated guess, the first level of approximation + segments is based on the count of control points and their distribution + along the B-spline, every additional level is a subdivision of the + previous level. + + E.g. a B-Spline of 8 control points has 7 segments at the first level, + 14 at the 2nd level and 28 at the 3rd level. + + """ + params = list(create_t_vector(self._control_points, "chord")) + if len(params) == 0: + return params + if self.max_t != 1.0: + max_t = self.max_t + params = [p * max_t for p in params] + for _ in range(level - 1): + params = list(subdivide_params(params)) + return params + + +def subdivide_params(p: list[float]) -> Iterable[float]: + for i in range(len(p) - 1): + yield p[i] + yield (p[i] + p[i + 1]) / 2.0 + yield p[-1] + + +def open_uniform_bspline( + control_points: Iterable[UVec], + order: int = 4, + weights: Optional[Iterable[float]] = None, +) -> BSpline: + """Creates an open uniform (periodic) `B-spline`_ curve (`open curve`_). + + This is an unclamped curve, which means the curve passes none of the + control points. + + Args: + control_points: iterable of control points as :class:`Vec3` compatible + objects + order: spline order (degree + 1) + weights: iterable of weight values + + """ + _control_points = Vec3.tuple(control_points) + knots = uniform_knot_vector(len(_control_points), order, normalize=False) + return BSpline(control_points, order=order, knots=knots, weights=weights) + + +def closed_uniform_bspline( + control_points: Iterable[UVec], + order: int = 4, + weights: Optional[Iterable[float]] = None, +) -> BSpline: + """Creates a closed uniform (periodic) `B-spline`_ curve (`open curve`_). + + This B-spline does not pass any of the control points. + + Args: + control_points: iterable of control points as :class:`Vec3` compatible + objects + order: spline order (degree + 1) + weights: iterable of weight values + + """ + _control_points = Vec3.list(control_points) + _control_points.extend(_control_points[: order - 1]) + if weights is not None: + weights = list(weights) + weights.extend(weights[: order - 1]) + return open_uniform_bspline(_control_points, order, weights) + + +def rational_bspline_from_arc( + center: Vec3 = (0, 0), + radius: float = 1, + start_angle: float = 0, + end_angle: float = 360, + segments: int = 1, +) -> BSpline: + """Returns a rational B-splines for a circular 2D arc. + + Args: + center: circle center as :class:`Vec3` compatible object + radius: circle radius + start_angle: start angle in degrees + end_angle: end angle in degrees + segments: count of spline segments, at least one segment for each + quarter (90 deg), default is 1, for as few as needed. + + """ + center = Vec3(center) + radius = float(radius) + + start_rad = math.radians(start_angle % 360) + end_rad = start_rad + math.radians(arc_angle_span_deg(start_angle, end_angle)) + control_points, weights, knots = nurbs_arc_parameters(start_rad, end_rad, segments) + return BSpline( + control_points=(center + (p * radius) for p in control_points), + weights=weights, + knots=knots, + order=3, + ) + + +PI_2 = math.pi / 2.0 + + +def rational_bspline_from_ellipse( + ellipse: ConstructionEllipse, segments: int = 1 +) -> BSpline: + """Returns a rational B-splines for an elliptic arc. + + Args: + ellipse: ellipse parameters as :class:`~ezdxf.math.ConstructionEllipse` + object + segments: count of spline segments, at least one segment for each + quarter (π/2), default is 1, for as few as needed. + + """ + start_angle = ellipse.start_param % math.tau + end_angle = start_angle + ellipse.param_span + + def transform_control_points() -> Iterable[Vec3]: + center = Vec3(ellipse.center) + x_axis = ellipse.major_axis + y_axis = ellipse.minor_axis + for p in control_points: + yield center + x_axis * p.x + y_axis * p.y + + control_points, weights, knots = nurbs_arc_parameters( + start_angle, end_angle, segments + ) + return BSpline( + control_points=transform_control_points(), + weights=weights, + knots=knots, + order=3, + ) + + +def nurbs_arc_parameters(start_angle: float, end_angle: float, segments: int = 1): + """Returns a rational B-spline parameters for a circular 2D arc with center + at (0, 0) and a radius of 1. + + Args: + start_angle: start angle in radians + end_angle: end angle in radians + segments: count of segments, at least one segment for each quarter (π/2) + + Returns: + control_points, weights, knots + + """ + # Source: https://www.researchgate.net/publication/283497458_ONE_METHOD_FOR_REPRESENTING_AN_ARC_OF_ELLIPSE_BY_A_NURBS_CURVE/citation/download + if segments < 1: + raise ValueError("Invalid argument segments (>= 1).") + delta_angle = end_angle - start_angle + arc_count = max(math.ceil(delta_angle / PI_2), segments) + + segment_angle = delta_angle / arc_count + segment_angle_2 = segment_angle / 2 + arc_weight = math.cos(segment_angle_2) + + # First control point + control_points = [Vec3(math.cos(start_angle), math.sin(start_angle))] + weights = [1.0] + + angle = start_angle + d = 1.0 / math.cos(segment_angle / 2.0) + for _ in range(arc_count): + # next control point between points on arc + angle += segment_angle_2 + control_points.append(Vec3(math.cos(angle) * d, math.sin(angle) * d)) + weights.append(arc_weight) + + # next control point on arc + angle += segment_angle_2 + control_points.append(Vec3(math.cos(angle), math.sin(angle))) + weights.append(1.0) + + # Knot vector calculation for B-spline of order=3 + # Clamped B-Spline starts with `order` 0.0 knots and + # ends with `order` 1.0 knots + knots = [0.0, 0.0, 0.0] + step = 1.0 / ((max(len(control_points) + 1, 4) - 4) / 2.0 + 1.0) + g = step + while g < 1.0: + knots.extend((g, g)) + g += step + knots.extend([1.0] * (required_knot_values(len(control_points), 3) - len(knots))) + + return control_points, weights, knots + + +def bspline_basis(u: float, index: int, degree: int, knots: Sequence[float]) -> float: + """B-spline basis_vector function. + + Simple recursive implementation for testing and comparison. + + Args: + u: curve parameter in range [0, max(knots)] + index: index of control point + degree: degree of B-spline + knots: knots vector + + Returns: + float: basis_vector value N_i,p(u) + + """ + cache: dict[tuple[int, int], float] = {} + u = float(u) + + def N(i: int, p: int) -> float: + try: + return cache[(i, p)] + except KeyError: + if p == 0: + retval = 1 if knots[i] <= u < knots[i + 1] else 0.0 + else: + dominator = knots[i + p] - knots[i] + f1 = (u - knots[i]) / dominator * N(i, p - 1) if dominator else 0.0 + + dominator = knots[i + p + 1] - knots[i + 1] + f2 = ( + (knots[i + p + 1] - u) / dominator * N(i + 1, p - 1) + if dominator + else 0.0 + ) + + retval = f1 + f2 + cache[(i, p)] = retval + return retval + + return N(int(index), int(degree)) + + +def bspline_basis_vector( + u: float, count: int, degree: int, knots: Sequence[float] +) -> list[float]: + """Create basis_vector vector at parameter u. + + Used with the bspline_basis() for testing and comparison. + + Args: + u: curve parameter in range [0, max(knots)] + count: control point count (n + 1) + degree: degree of B-spline (order = degree + 1) + knots: knot vector + + Returns: + list[float]: basis_vector vector, len(basis_vector) == count + + """ + assert len(knots) == (count + degree + 1) + basis: list[float] = [ + bspline_basis(u, index, degree, knots) for index in range(count) + ] + # pick up last point ??? why is this necessary ??? + if math.isclose(u, knots[-1]): + basis[-1] = 1.0 + return basis diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/bulge.py b/.venv/lib/python3.12/site-packages/ezdxf/math/bulge.py new file mode 100644 index 0000000..2aeef76 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/bulge.py @@ -0,0 +1,185 @@ +# Copyright (c) 2018-2022 Manfred Moitzi +# License: MIT License +# source: http://www.lee-mac.com/bulgeconversion.html +# source: http://www.afralisp.net/archive/lisp/Bulges1.htm +from __future__ import annotations +from typing import Any +import math +from ezdxf.math import Vec2, UVec + + +__all__ = [ + "bulge_to_arc", + "bulge_3_points", + "bulge_center", + "bulge_radius", + "arc_to_bulge", + "bulge_from_radius_and_chord", + "bulge_from_arc_angle", +] + + +def polar(p: Any, angle: float, distance: float) -> Vec2: + """Returns the point at a specified `angle` and `distance` from point `p`. + + Args: + p: point as :class:`Vec2` compatible object + angle: angle in radians + distance: distance + + """ + return Vec2(p) + Vec2.from_angle(angle, distance) + + +def angle(p1: Any, p2: Any) -> float: + """Returns angle a line defined by two endpoints and x-axis in radians. + + Args: + p1: start point as :class:`Vec2` compatible object + p2: end point as :class:`Vec2` compatible object + + """ + return (Vec2(p2) - Vec2(p1)).angle + + +def arc_to_bulge( + center: UVec, start_angle: float, end_angle: float, radius: float +) -> tuple[Vec2, Vec2, float]: + """Returns bulge parameters from arc parameters. + + Args: + center: circle center point as :class:`Vec2` compatible object + start_angle: start angle in radians + end_angle: end angle in radians + radius: circle radius + + Returns: + tuple: (start_point, end_point, bulge) + + """ + start_point = polar(center, start_angle, radius) + end_point = polar(center, end_angle, radius) + pi2 = math.pi * 2 + a = math.fmod((pi2 + (end_angle - start_angle)), pi2) / 4.0 + bulge = math.sin(a) / math.cos(a) + return start_point, end_point, bulge + + +def bulge_3_points(start_point: UVec, end_point: UVec, point: UVec) -> float: + """Returns bulge value defined by three points. + + Based on 3-Points to Bulge by `Lee Mac`_. + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + point: arbitrary point as :class:`Vec2` compatible object + + """ + a = (math.pi - angle(point, start_point) + angle(point, end_point)) / 2 + return math.sin(a) / math.cos(a) + + +def bulge_to_arc( + start_point: UVec, end_point: UVec, bulge: float +) -> tuple[Vec2, float, float, float]: + """Returns arc parameters from bulge parameters. + + The arcs defined by bulge values of :class:`~ezdxf.entities.LWPolyline` + and 2D :class:`~ezdxf.entities.Polyline` entities start at the vertex which + includes the bulge value and ends at the following vertex. + + Based on Bulge to Arc by `Lee Mac`_. + + Args: + start_point: start vertex as :class:`Vec2` compatible object + end_point: end vertex as :class:`Vec2` compatible object + bulge: bulge value + + Returns: + Tuple: (center, start_angle, end_angle, radius) + + """ + r = signed_bulge_radius(start_point, end_point, bulge) + a = angle(start_point, end_point) + (math.pi / 2 - math.atan(bulge) * 2) + c = polar(start_point, a, r) + if bulge < 0: + return c, angle(c, end_point), angle(c, start_point), abs(r) + else: + return c, angle(c, start_point), angle(c, end_point), abs(r) + + +def bulge_center(start_point: UVec, end_point: UVec, bulge: float) -> Vec2: + """Returns center of arc described by the given bulge parameters. + + Based on Bulge Center by `Lee Mac`_. + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + bulge: bulge value as float + + + """ + start_point = Vec2(start_point) + a = angle(start_point, end_point) + (math.pi / 2.0 - math.atan(bulge) * 2.0) + return start_point + Vec2.from_angle( + a, signed_bulge_radius(start_point, end_point, bulge) + ) + + +def signed_bulge_radius( + start_point: UVec, end_point: UVec, bulge: float +) -> float: + return ( + Vec2(start_point).distance(Vec2(end_point)) + * (1.0 + (bulge * bulge)) + / 4.0 + / bulge + ) + + +def bulge_radius(start_point: UVec, end_point: UVec, bulge: float) -> float: + """Returns radius of arc defined by the given bulge parameters. + + Based on Bulge Radius by `Lee Mac`_ + + Args: + start_point: start point as :class:`Vec2` compatible object + end_point: end point as :class:`Vec2` compatible object + bulge: bulge value + + """ + return abs(signed_bulge_radius(start_point, end_point, bulge)) + + +def bulge_from_radius_and_chord(radius: float, chord: float) -> float: + """Returns the bulge value for the given arc radius and chord length. + Returns 0 if the radius is zero or the radius is too small for the given + chord length to create an arc. + + Args: + radius: arc radius + chord: chord length + + """ + # https://github.com/mozman/ezdxf/discussions/758 + try: + x = chord / (2.0 * radius) + except ZeroDivisionError: + return 0.0 + try: + return x / (1.0 + math.sqrt(1.0 - x * x)) + except ValueError: # domain error + return 0.0 + + +def bulge_from_arc_angle(angle: float) -> float: + """Returns the bulge value for the given arc angle. + + Args: + angle: arc angle in radians + + """ + # https://github.com/mozman/ezdxf/discussions/758 + return math.tan(angle / 4.0) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/circle.py b/.venv/lib/python3.12/site-packages/ezdxf/math/circle.py new file mode 100644 index 0000000..1f25a51 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/circle.py @@ -0,0 +1,249 @@ +# Copyright (c) 2010-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterator, Iterable +import math +import numpy as np + +from ezdxf.math import Vec2, UVec +from .line import ConstructionRay, ConstructionLine +from .bbox import BoundingBox2d + + +HALF_PI = math.pi / 2.0 + +__all__ = ["ConstructionCircle"] + + +class ConstructionCircle: + """Construction tool for 2D circles. + + Args: + center: center point as :class:`Vec2` compatible object + radius: circle radius > `0` + + """ + + def __init__(self, center: UVec, radius: float = 1.0): + self.center = Vec2(center) + self.radius = float(radius) + if self.radius <= 0.0: + raise ValueError("Radius has to be > 0.") + + def __str__(self) -> str: + """Returns string representation of circle + "ConstructionCircle(center, radius)". + """ + return f"ConstructionCircle({self.center}, {self.radius})" + + @staticmethod + def from_3p(p1: UVec, p2: UVec, p3: UVec) -> ConstructionCircle: + """Creates a circle from three points, all points have to be compatible + to :class:`Vec2` class. + """ + _p1 = Vec2(p1) + _p2 = Vec2(p2) + _p3 = Vec2(p3) + ray1 = ConstructionRay(_p1, _p2) + ray2 = ConstructionRay(_p1, _p3) + center_ray1 = ray1.orthogonal(_p1.lerp(_p2)) + center_ray2 = ray2.orthogonal(_p1.lerp(_p3)) + center = center_ray1.intersect(center_ray2) + return ConstructionCircle(center, center.distance(_p1)) + + @property + def bounding_box(self) -> BoundingBox2d: + """2D bounding box of circle as :class:`BoundingBox2d` object.""" + rvec = Vec2((self.radius, self.radius)) + return BoundingBox2d((self.center - rvec, self.center + rvec)) + + def translate(self, dx: float, dy: float) -> None: + """Move circle about `dx` in x-axis and about `dy` in y-axis. + + Args: + dx: translation in x-axis + dy: translation in y-axis + + """ + self.center += Vec2((dx, dy)) + + def point_at(self, angle: float) -> Vec2: + """Returns point on circle at `angle` as :class:`Vec2` object. + + Args: + angle: angle in radians, angle goes counter + clockwise around the z-axis, x-axis = 0 deg. + + """ + return self.center + Vec2.from_angle(angle, self.radius) + + def vertices(self, angles: Iterable[float]) -> Iterable[Vec2]: + """Yields vertices of the circle for iterable `angles`. + + Args: + angles: iterable of angles as radians, angle goes counter-clockwise + around the z-axis, x-axis = 0 deg. + + """ + center = self.center + radius = self.radius + for angle in angles: + yield center + Vec2.from_angle(angle, radius) + + def flattening(self, sagitta: float) -> Iterator[Vec2]: + """Approximate the circle by vertices, argument `sagitta` is the + max. distance from the center of an arc segment to the center of its + chord. Returns a closed polygon where the start vertex is coincident + with the end vertex! + """ + from .arc import arc_segment_count + + count = arc_segment_count(self.radius, math.tau, sagitta) + yield from self.vertices(np.linspace(0.0, math.tau, count + 1)) + + def inside(self, point: UVec) -> bool: + """Returns ``True`` if `point` is inside circle.""" + return self.radius >= self.center.distance(Vec2(point)) + + def tangent(self, angle: float) -> ConstructionRay: + """Returns tangent to circle at `angle` as :class:`ConstructionRay` + object. + + Args: + angle: angle in radians + + """ + point_on_circle = self.point_at(angle) + ray = ConstructionRay(self.center, point_on_circle) + return ray.orthogonal(point_on_circle) + + def intersect_ray( + self, ray: ConstructionRay, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of circle and `ray` as sequence of + :class:`Vec2` objects. + + Args: + ray: intersection ray + abs_tol: absolute tolerance for tests (e.g. test for tangents) + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 ray is a tangent to circle + 2 ray intersects with the circle + =========== ================================== + + """ + assert isinstance(ray, ConstructionRay) + ortho_ray = ray.orthogonal(self.center) + intersection_point = ray.intersect(ortho_ray) + dist = self.center.distance(intersection_point) + result = [] + # Intersect in two points: + if dist < self.radius: + # Ray goes through center point: + if math.isclose(dist, 0.0, abs_tol=abs_tol): + angle = ortho_ray.angle + alpha = HALF_PI + else: + # The exact direction of angle (all 4 quadrants Q1-Q4) is + # important: ortho_ray.angle is only correct at the center point + angle = (intersection_point - self.center).angle + alpha = math.acos( + intersection_point.distance(self.center) / self.radius + ) + result.append(self.point_at(angle + alpha)) + result.append(self.point_at(angle - alpha)) + # Ray is a tangent of the circle: + elif math.isclose(dist, self.radius, abs_tol=abs_tol): + result.append(intersection_point) + # else: No intersection + return tuple(result) + + def intersect_line( + self, line: ConstructionLine, abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of circle and `line` as sequence of + :class:`Vec2` objects. + + Args: + line: intersection line + abs_tol: absolute tolerance for tests (e.g. test for tangents) + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 line intersects or touches the circle at one point + 2 line intersects the circle at two points + =========== ================================== + + """ + assert isinstance(line, ConstructionLine) + return [ + point + for point in self.intersect_ray(line.ray, abs_tol=abs_tol) + if is_point_in_line_range(line.start, line.end, point) + ] + + def intersect_circle( + self, other: "ConstructionCircle", abs_tol: float = 1e-10 + ) -> Sequence[Vec2]: + """Returns intersection points of two circles as sequence of + :class:`Vec2` objects. + + Args: + other: intersection circle + abs_tol: absolute tolerance for tests + + Returns: + tuple of :class:`Vec2` objects + + =========== ================================== + tuple size Description + =========== ================================== + 0 no intersection + 1 circle touches the `other` circle at one point + 2 circle intersects with the `other` circle + =========== ================================== + + """ + assert isinstance(other, ConstructionCircle) + r1 = self.radius + r2 = other.radius + d = self.center.distance(other.center) + if d < abs_tol: + # concentric circles do not intersect by definition + return tuple() + + d_max = r1 + r2 + d_min = math.fabs(r1 - r2) + if d_min <= d <= d_max: + angle = (other.center - self.center).angle + # Circles touches at one point: + if math.isclose(d, d_max, abs_tol=abs_tol): + return (self.point_at(angle),) + if math.isclose(d, d_min, abs_tol=abs_tol): + if r1 >= r2: + return (self.point_at(angle),) + return (self.point_at(angle + math.pi),) + else: # Circles intersect in two points: + # Law of Cosines: + alpha = math.acos((r2 * r2 - r1 * r1 - d * d) / (-2.0 * r1 * d)) + return tuple(self.vertices((angle + alpha, angle - alpha))) + return tuple() + + +def is_point_in_line_range(start: Vec2, end: Vec2, point: Vec2) -> bool: + length = (end - start).magnitude + if (point - start).magnitude > length: + return False + return (point - end).magnitude <= length diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/clipping.py b/.venv/lib/python3.12/site-packages/ezdxf/math/clipping.py new file mode 100644 index 0000000..c219188 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/clipping.py @@ -0,0 +1,938 @@ +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence, Optional, Iterator, Callable +from typing_extensions import Protocol +import math +import enum + +from ezdxf.math import ( + Vec2, + UVec, + intersection_line_line_2d, + is_point_in_polygon_2d, + has_clockwise_orientation, + point_to_line_relation, + TOLERANCE, + BoundingBox2d, +) +from ezdxf.tools import take2, pairwise + + +__all__ = [ + "greiner_hormann_union", + "greiner_hormann_difference", + "greiner_hormann_intersection", + "Clipping", + "ConvexClippingPolygon2d", + "ConcaveClippingPolygon2d", + "ClippingRect2d", + "InvertedClippingPolygon2d", + "CohenSutherlandLineClipping2d", +] + + +class Clipping(Protocol): + def clip_polygon(self, polygon: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polygon.""" + + def clip_polyline(self, polyline: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polyline.""" + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + """Returns the parts of the clipped line.""" + + def is_inside(self, point: Vec2) -> bool: + """Returns ``True`` if `point` is inside the clipping path.""" + + +def _clip_polyline( + polyline: Sequence[Vec2], + line_clipper: Callable[[Vec2, Vec2], Sequence[tuple[Vec2, Vec2]]], + abs_tol: float, +) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polyline.""" + if len(polyline) < 2: + return [] + result: list[Vec2] = [] + parts: list[list[Vec2]] = [] + next_start = polyline[0] + for end in polyline[1:]: + start = next_start + next_start = end + for clipped_line in line_clipper(start, end): + if len(clipped_line) != 2: + continue + if result: + clip_start, clip_end = clipped_line + if result[-1].isclose(clip_start, abs_tol=abs_tol): + result.append(clip_end) + continue + parts.append(result) + result = list(clipped_line) + if result: + parts.append(result) + return parts + + +class ConvexClippingPolygon2d: + """The clipping path is an arbitrary convex 2D polygon.""" + + def __init__(self, vertices: Iterable[Vec2], ccw_check=True, abs_tol=TOLERANCE): + self.abs_tol = abs_tol + clip = list(vertices) + if len(clip) > 1: + if clip[0].isclose(clip[-1], abs_tol=self.abs_tol): + clip.pop() + if len(clip) < 3: + raise ValueError("more than 3 vertices as clipping polygon required") + if ccw_check and has_clockwise_orientation(clip): + clip.reverse() + self._clipping_polygon: list[Vec2] = clip + + def clip_polyline(self, polyline: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polyline.""" + return _clip_polyline(polyline, self.clip_line, abs_tol=self.abs_tol) + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + """Returns the parts of the clipped line.""" + + def is_inside(point: Vec2) -> bool: + # is point left of line: + return (clip_end.x - clip_start.x) * (point.y - clip_start.y) - ( + clip_end.y - clip_start.y + ) * (point.x - clip_start.x) >= 0.0 + + def edge_intersection(default: Vec2) -> Vec2: + ip = intersection_line_line_2d( + (edge_start, edge_end), (clip_start, clip_end), abs_tol=self.abs_tol + ) + if ip is None: + return default + return ip + + # The clipping polygon is always treated as a closed polyline! + clip_start = self._clipping_polygon[-1] + edge_start = start + edge_end = end + for clip_end in self._clipping_polygon: + if is_inside(edge_start): + if not is_inside(edge_end): + edge_end = edge_intersection(edge_end) + elif is_inside(edge_end): + if not is_inside(edge_start): + edge_start = edge_intersection(edge_start) + else: + return tuple() + clip_start = clip_end + return ((edge_start, edge_end),) + + def clip_polygon(self, polygon: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polygon. A polygon is a closed polyline.""" + + def is_inside(point: Vec2) -> bool: + # is point left of line: + return (clip_end.x - clip_start.x) * (point.y - clip_start.y) - ( + clip_end.y - clip_start.y + ) * (point.x - clip_start.x) > 0.0 + + def edge_intersection() -> None: + ip = intersection_line_line_2d( + (edge_start, edge_end), (clip_start, clip_end), abs_tol=self.abs_tol + ) + if ip is not None: + clipped.append(ip) + + # The clipping polygon is always treated as a closed polyline! + clip_start = self._clipping_polygon[-1] + clipped = list(polygon) + for clip_end in self._clipping_polygon: + # next clipping edge to test: clip_start -> clip_end + if not clipped: # no subject vertices left to test + break + + vertices = clipped.copy() + if len(vertices) > 1 and vertices[0].isclose( + vertices[-1], abs_tol=self.abs_tol + ): + vertices.pop() + + clipped.clear() + edge_start = vertices[-1] + for edge_end in vertices: + # next polygon edge to test: edge_start -> edge_end + if is_inside(edge_end): + if not is_inside(edge_start): + edge_intersection() + clipped.append(edge_end) + elif is_inside(edge_start): + edge_intersection() + edge_start = edge_end + clip_start = clip_end + return (clipped,) + + def is_inside(self, point: Vec2) -> bool: + """Returns ``True`` if `point` is inside the clipping polygon.""" + return is_point_in_polygon_2d(point, self._clipping_polygon) >= 0 + + +class ClippingRect2d: + """The clipping path is an axis-aligned rectangle, where all sides are parallel to + the x- and y-axis. + """ + + def __init__(self, bottom_left: Vec2, top_right: Vec2, abs_tol=TOLERANCE): + self.abs_tol = abs_tol + self._bbox = BoundingBox2d((bottom_left, top_right)) + bottom_left = self._bbox.extmin + top_right = self._bbox.extmax + self._clipping_polygon = ConvexClippingPolygon2d( + [ + bottom_left, + Vec2(top_right.x, bottom_left.y), + top_right, + Vec2(bottom_left.x, top_right.y), + ], + ccw_check=False, + abs_tol=self.abs_tol, + ) + self._line_clipper = CohenSutherlandLineClipping2d( + self._bbox.extmin, self._bbox.extmax + ) + + def clip_polygon(self, polygon: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polygon. A polygon is a closed polyline.""" + return self._clipping_polygon.clip_polygon(polygon) + + def clip_polyline(self, polyline: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polyline.""" + return _clip_polyline(polyline, self.clip_line, self.abs_tol) + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + """Returns the clipped line.""" + result = self._line_clipper.clip_line(start, end) + if len(result) == 2: + return (result,) # type: ignore + return tuple() + + def is_inside(self, point: Vec2) -> bool: + """Returns ``True`` if `point` is inside the clipping rectangle.""" + return self._bbox.inside(point) + + def has_intersection(self, other: BoundingBox2d) -> bool: + """Returns ``True`` if `other` bounding box intersects the clipping rectangle.""" + return self._bbox.has_intersection(other) + + +class ConcaveClippingPolygon2d: + """The clipping path is an arbitrary concave 2D polygon.""" + + def __init__(self, vertices: Iterable[Vec2], abs_tol=TOLERANCE): + self.abs_tol = abs_tol + clip = list(vertices) + if len(clip) > 1: + if clip[0].isclose(clip[-1], abs_tol=self.abs_tol): + clip.pop() + if len(clip) < 3: + raise ValueError("more than 3 vertices as clipping polygon required") + # open polygon; clockwise or counter-clockwise oriented vertices + self._clipping_polygon = clip + self._bbox = BoundingBox2d(clip) + + def is_inside(self, point: Vec2) -> bool: + """Returns ``True`` if `point` is inside the clipping polygon.""" + if not self._bbox.inside(point): + return False + return ( + is_point_in_polygon_2d(point, self._clipping_polygon, abs_tol=self.abs_tol) + >= 0 + ) + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + """Returns the clipped line.""" + abs_tol = self.abs_tol + line = (start, end) + if not self._bbox.has_overlap(BoundingBox2d(line)): + return tuple() + + intersections = polygon_line_intersections_2d(self._clipping_polygon, line) + start_is_inside = is_point_in_polygon_2d(start, self._clipping_polygon) >= 0 + if len(intersections) == 0: + if start_is_inside: + return (line,) + return tuple() + end_is_inside = ( + is_point_in_polygon_2d(end, self._clipping_polygon, abs_tol=abs_tol) >= 0 + ) + if end_is_inside and not intersections[-1].isclose(end, abs_tol=abs_tol): + # last inside-segment ends at end + intersections.append(end) + if start_is_inside and not intersections[0].isclose(start, abs_tol=abs_tol): + # first inside-segment begins at start + intersections.insert(0, start) + + # REMOVE duplicate intersection points at the beginning and the end - + # these are caused by clipping at the connection point of two edges. + # KEEP duplicate intersection points in between - these are caused by the + # coincident edges of inverted clipping polygons. These intersections points + # are required for the inside/outside rule to work properly! + if len(intersections) > 1 and intersections[0].isclose( + intersections[1], abs_tol=abs_tol + ): + intersections.pop(0) + if len(intersections) > 1 and intersections[-1].isclose( + intersections[-2], abs_tol=abs_tol + ): + intersections.pop() + + if has_collinear_edge(self._clipping_polygon, start, end): + # slow detection: doesn't work with inside/outside rule! + # test if mid-point of intersection-segment is inside the polygon. + # intersection-segment collinear with a polygon edge is inside! + segments: list[tuple[Vec2, Vec2]] = [] + for a, b in pairwise(intersections): + if a.isclose(b, abs_tol=abs_tol): # ignore zero-length segments + continue + if ( + is_point_in_polygon_2d( + a.lerp(b), self._clipping_polygon, abs_tol=abs_tol + ) + >= 0 + ): + segments.append((a, b)) + return segments + + # inside/outside rule + # intersection segments: + # (0, 1) outside (2, 3) outside (4, 5) ... + return list(take2(intersections)) + + def clip_polyline(self, polyline: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polyline.""" + abs_tol = self.abs_tol + segments: list[list[Vec2]] = [] + for start, end in pairwise(polyline): + for a, b in self.clip_line(start, end): + if segments: + last_seg = segments[-1] + if last_seg[-1].isclose(a, abs_tol=abs_tol): + last_seg.append(b) + continue + segments.append([a, b]) + return segments + + def clip_polygon(self, polygon: Sequence[Vec2]) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped polygon. A polygon is a closed polyline.""" + vertices = list(polygon) + abs_tol = self.abs_tol + if len(vertices) > 1: + if vertices[0].isclose(vertices[-1], abs_tol=abs_tol): + vertices.pop() + if len(vertices) < 3: + return tuple() + polygon_box = BoundingBox2d(vertices) + if not self._bbox.has_intersection(polygon_box): + return tuple() # polygons do not overlap + result = clip_arbitrary_polygons(self._clipping_polygon, vertices) + if len(result) == 0: + is_outside = any( + is_point_in_polygon_2d(v, self._clipping_polygon, abs_tol=abs_tol) < 0 + for v in vertices + ) + if is_outside: + return tuple() + return (vertices,) + # return (self._clipping_polygon.copy(),) + return result + + +def clip_arbitrary_polygons( + clipper: list[Vec2], subject: list[Vec2] +) -> Sequence[Sequence[Vec2]]: + """Returns the parts of the clipped subject. Both polygons can be concave + + Args: + clipper: clipping window closed polygon + subject: closed polygon to clip + + """ + # Caching of gh_clipper is not possible, because both GHPolygons get modified! + gh_clipper = GHPolygon.from_vec2(clipper) + gh_subject = GHPolygon.from_vec2(subject) + return gh_clipper.intersection(gh_subject) + + +def has_collinear_edge(polygon: list[Vec2], start: Vec2, end: Vec2) -> bool: + """Returns ``True`` if `polygon` has any collinear edge to line `start->end`.""" + a = polygon[-1] + rel_a = point_to_line_relation(a, start, end) + for b in polygon: + rel_b = point_to_line_relation(b, start, end) + if rel_a == 0 and rel_b == 0: + return True + a = b + rel_a = rel_b + return False + + +def polygon_line_intersections_2d( + polygon: list[Vec2], line: tuple[Vec2, Vec2], abs_tol: float = TOLERANCE +) -> list[Vec2]: + """Returns all intersections of polygon with line. + All intersections points are ordered from start to end of line. + Start and end points are not included if not explicit intersection points. + + .. Note:: + + Returns duplicate intersections points when the line intersects at + the connection point of two polygon edges! + + """ + intersection_points: list[Vec2] = [] + start, end = line + size = len(polygon) + for index in range(size): + a = polygon[index - 1] + b = polygon[index] + ip = intersection_line_line_2d((a, b), line, virtual=False, abs_tol=abs_tol) + if ip is None: + continue + # Note: do not remove duplicate vertices, because inverted clipping polygons + # have coincident clipping edges inside the clipping polygon! #1101 + if ip.isclose(a, abs_tol=abs_tol): + a_prev = polygon[index - 2] + rel_prev = point_to_line_relation(a_prev, start, end, abs_tol=abs_tol) + rel_next = point_to_line_relation(b, start, end, abs_tol=abs_tol) + if rel_prev == rel_next: + continue + # edge case: line intersects "exact" in point b + elif ip.isclose(b, abs_tol=abs_tol): + b_next = polygon[(index + 1) % size] + rel_prev = point_to_line_relation(a, start, end, abs_tol=abs_tol) + rel_next = point_to_line_relation(b_next, start, end, abs_tol=abs_tol) + if rel_prev == rel_next: + continue + intersection_points.append(ip) + + intersection_points.sort(key=lambda ip: ip.distance(start)) + return intersection_points + + +class InvertedClippingPolygon2d(ConcaveClippingPolygon2d): + """This class represents an inverted clipping path. Everything between the inner + polygon and the outer extents is considered as inside. The inner clipping path is + an arbitrary 2D polygon. + + .. Important:: + + The `outer_bounds` must be larger than the content to clip to work correctly. + + """ + + def __init__( + self, + inner_polygon: Iterable[Vec2], + outer_bounds: BoundingBox2d, + abs_tol=TOLERANCE, + ): + self.abs_tol = abs_tol + clip = list(inner_polygon) + if len(clip) > 1: + if not clip[0].isclose(clip[-1], abs_tol=abs_tol): # close inner_polygon + clip.append(clip[0]) + if len(clip) < 4: + raise ValueError("more than 3 vertices as clipping polygon required") + # requirements for inner_polygon: + # arbitrary polygon (convex or concave) + # closed polygon (first vertex == last vertex) + # clockwise or counter-clockwise oriented vertices + self._clipping_polygon = make_inverted_clipping_polygon( + clip, outer_bounds, abs_tol + ) + self._bbox = outer_bounds + + +def make_inverted_clipping_polygon( + inner_polygon: list[Vec2], outer_bounds: BoundingBox2d, abs_tol=TOLERANCE +) -> list[Vec2]: + """Creates a closed inverted clipping polygon by connecting the inner polygon with + the surrounding rectangle at their closest vertices. + """ + assert outer_bounds.has_data is True + inner_polygon = inner_polygon.copy() + if inner_polygon[0].isclose(inner_polygon[-1], abs_tol=abs_tol): + inner_polygon.pop() + assert len(inner_polygon) > 2 + outer_rect = list(outer_bounds.rect_vertices()) # counter-clockwise + outer_rect.reverse() # clockwise + ci, co = find_closest_vertices(inner_polygon, outer_rect) + result = inner_polygon[ci:] + result.extend(inner_polygon[: ci + 1]) + result.extend(outer_rect[co:]) + result.extend(outer_rect[: co + 1]) + result.append(result[0]) + return result + + +def find_closest_vertices( + vertices0: list[Vec2], vertices1: list[Vec2] +) -> tuple[int, int]: + """Returns the indices of the closest vertices of both lists.""" + min_dist = math.inf + result: tuple[int, int] = 0, 0 + for i0, v0 in enumerate(vertices0): + for i1, v1 in enumerate(vertices1): + distance = v0.distance(v1) + if distance < min_dist: + min_dist = distance + result = i0, i1 + return result + + +# Based on the paper "Efficient Clipping of Arbitrary Polygons" by +# Günther Greiner and Kai Hormann, +# ACM Transactions on Graphics 1998;17(2):71-83 +# Available at: http://www.inf.usi.ch/hormann/papers/Greiner.1998.ECO.pdf + + +class _Node: + def __init__( + self, + vtx: Vec2, + alpha: float = 0.0, + intersect=False, + entry=True, + checked=False, + ): + self.vtx = vtx + + # Reference to the next vertex of the polygon + self.next: _Node = None # type: ignore + + # Reference to the previous vertex of the polygon + self.prev: _Node = None # type: ignore + + # Reference to the corresponding intersection vertex in the other polygon + self.neighbor: _Node = None # type: ignore + + # True if intersection is an entry point, False if exit + self.entry: bool = entry + + # Intersection point's relative distance from previous vertex + self.alpha: float = alpha + + # True if vertex is an intersection + self.intersect: bool = intersect + + # True if the vertex has been checked (last phase) + self.checked: bool = checked + + def set_checked(self): + self.checked = True + if self.neighbor and not self.neighbor.checked: + self.neighbor.set_checked() + + +class IntersectionError(Exception): + pass + + +class GHPolygon: + first: _Node = None # type: ignore + max_x: float = 1e6 + + def add(self, node: _Node): + """Add a polygon vertex node.""" + + self.max_x = max(self.max_x, node.vtx.x) + if self.first is None: + self.first = node + self.first.next = node + self.first.prev = node + else: # insert as last node + first = self.first + last = first.prev + first.prev = node + node.next = first + node.prev = last + last.next = node + + @staticmethod + def build(vertices: Iterable[UVec]) -> GHPolygon: + """Build a new GHPolygon from an iterable of vertices.""" + return GHPolygon.from_vec2(Vec2.list(vertices)) + + @staticmethod + def from_vec2(vertices: Sequence[Vec2]) -> GHPolygon: + """Build a new GHPolygon from an iterable of vertices.""" + polygon = GHPolygon() + for v in vertices: + polygon.add(_Node(v)) + return polygon + + @staticmethod + def insert(vertex: _Node, start: _Node, end: _Node): + """Insert and sort an intersection node. + + This function inserts an intersection node between two other + start- and end node of an edge. The start and end node cannot be + an intersection node (that is, they must be actual vertex nodes of + the original polygon). If there are multiple intersection nodes + between the start- and end node, then the new node is inserted + based on its alpha value. + """ + curr = start + while curr != end and curr.alpha < vertex.alpha: + curr = curr.next + + vertex.next = curr + prev = curr.prev + vertex.prev = prev + prev.next = vertex + curr.prev = vertex + + def __iter__(self) -> Iterator[_Node]: + assert self.first is not None + s = self.first + while True: + yield s + s = s.next + if s is self.first: + return + + @property + def first_intersect(self) -> Optional[_Node]: + for v in self: + if v.intersect and not v.checked: + return v + return None + + @property + def points(self) -> list[Vec2]: + points = [v.vtx for v in self] + if not points[0].isclose(points[-1]): + points.append(points[0]) + return points + + def unprocessed(self): + for v in self: + if v.intersect and not v.checked: + return True + return False + + def union(self, clip: GHPolygon) -> list[list[Vec2]]: + return self.clip(clip, False, False) + + def intersection(self, clip: GHPolygon) -> list[list[Vec2]]: + return self.clip(clip, True, True) + + def difference(self, clip: GHPolygon) -> list[list[Vec2]]: + return self.clip(clip, False, True) + + # pylint: disable=too-many-branches + def clip(self, clip: GHPolygon, s_entry, c_entry) -> list[list[Vec2]]: + """Clip this polygon using another one as a clipper. + + This is where the algorithm is executed. It allows you to make + a UNION, INTERSECT or DIFFERENCE operation between two polygons. + + Given two polygons A, B the following operations may be performed: + + A|B ... A OR B (Union of A and B) + A&B ... A AND B (Intersection of A and B) + A\\B ... A - B + B\\A ... B - A + + The entry records store the direction the algorithm should take when + it arrives at that entry point in an intersection. Depending on the + operation requested, the direction is set as follows for entry points + (f=forward, b=backward; exit points are always set to the opposite): + + Entry + A B + ----- + A|B b b + A&B f f + A\\B b f + B\\A f b + + f = True, b = False when stored in the entry record + """ + # Phase 1: Find intersections + for subject_vertex in self: + if not subject_vertex.intersect: + for clipper_vertex in clip: + if not clipper_vertex.intersect: + ip, us, uc = line_intersection( + subject_vertex.vtx, + next_vertex_node(subject_vertex.next).vtx, + clipper_vertex.vtx, + next_vertex_node(clipper_vertex.next).vtx, + ) + if ip is None: + continue + subject_node = _Node(ip, us, intersect=True, entry=False) + clipper_node = _Node(ip, uc, intersect=True, entry=False) + subject_node.neighbor = clipper_node + clipper_node.neighbor = subject_node + + self.insert( + subject_node, + subject_vertex, + next_vertex_node(subject_vertex.next), + ) + clip.insert( + clipper_node, + clipper_vertex, + next_vertex_node(clipper_vertex.next), + ) + + # Phase 2: Identify entry/exit points + s_entry ^= is_inside_polygon(self.first.vtx, clip) + for subject_vertex in self: + if subject_vertex.intersect: + subject_vertex.entry = s_entry + s_entry = not s_entry + + c_entry ^= is_inside_polygon(clip.first.vtx, self) + for clipper_vertex in clip: + if clipper_vertex.intersect: + clipper_vertex.entry = c_entry + c_entry = not c_entry + + # Phase 3: Construct clipped polygons + clipped_polygons: list[list[Vec2]] = [] + while self.unprocessed(): + current: _Node = self.first_intersect # type: ignore + clipped: list[Vec2] = [current.vtx] + while True: + current.set_checked() + if current.entry: + while True: + current = current.next + clipped.append(current.vtx) + if current.intersect: + break + else: + while True: + current = current.prev + clipped.append(current.vtx) + if current.intersect: + break + + current = current.neighbor + if current.checked: + break + clipped_polygons.append(clipped) + return clipped_polygons + + +def next_vertex_node(v: _Node) -> _Node: + """Return the next non-intersecting vertex after the one specified.""" + c = v + while c.intersect: + c = c.next + return c + + +def is_inside_polygon(vertex: Vec2, polygon: GHPolygon) -> bool: + """Returns ``True`` if `vertex` is inside `polygon`.""" + # Possible issue: are points on the boundary inside or outside the polygon? + # this version: inside + return is_point_in_polygon_2d(vertex, polygon.points, abs_tol=TOLERANCE) >= 0 + + +_ERROR = None, 0, 0 + + +def line_intersection( + s1: Vec2, s2: Vec2, c1: Vec2, c2: Vec2, tol: float = TOLERANCE +) -> tuple[Optional[Vec2], float, float]: + """Returns the intersection point between two lines. + + This special implementation excludes the line end points as intersection + points! + + Algorithm based on: http://paulbourke.net/geometry/lineline2d/ + """ + den = (c2.y - c1.y) * (s2.x - s1.x) - (c2.x - c1.x) * (s2.y - s1.y) + if abs(den) < tol: + return _ERROR + us = ((c2.x - c1.x) * (s1.y - c1.y) - (c2.y - c1.y) * (s1.x - c1.x)) / den + lwr = 0.0 + tol + upr = 1.0 - tol + # Line end points are excluded as intersection points: + # us =~ 0.0; us =~ 1.0 + if not (lwr < us < upr): + return _ERROR + # uc =~ 0.0; uc =~ 1.0 + uc = ((s2.x - s1.x) * (s1.y - c1.y) - (s2.y - s1.y) * (s1.x - c1.x)) / den + if lwr < uc < upr: + return ( + Vec2(s1.x + us * (s2.x - s1.x), s1.y + us * (s2.y - s1.y)), + us, + uc, + ) + return _ERROR + + +class BooleanOperation(enum.Enum): + UNION = "union" + DIFFERENCE = "difference" + INTERSECTION = "intersection" + + +def greiner_hormann_intersection( + p1: Iterable[UVec], p2: Iterable[UVec] +) -> list[list[Vec2]]: + """Returns the INTERSECTION of polygon `p1` & polygon `p2`. + This algorithm works only for polygons with real intersection points + and line end points on face edges are not considered as such intersection + points! + + """ + return greiner_hormann(p1, p2, BooleanOperation.INTERSECTION) + + +def greiner_hormann_difference( + p1: Iterable[UVec], p2: Iterable[UVec] +) -> list[list[Vec2]]: + """Returns the DIFFERENCE of polygon `p1` - polygon `p2`. + This algorithm works only for polygons with real intersection points + and line end points on face edges are not considered as such intersection + points! + + """ + return greiner_hormann(p1, p2, BooleanOperation.DIFFERENCE) + + +def greiner_hormann_union(p1: Iterable[UVec], p2: Iterable[UVec]) -> list[list[Vec2]]: + """Returns the UNION of polygon `p1` | polygon `p2`. + This algorithm works only for polygons with real intersection points + and line end points on face edges are not considered as such intersection + points! + + """ + return greiner_hormann(p1, p2, BooleanOperation.UNION) + + +def greiner_hormann( + p1: Iterable[UVec], p2: Iterable[UVec], op: BooleanOperation +) -> list[list[Vec2]]: + """Implements a 2d clipping function to perform 3 boolean operations: + + - UNION: p1 | p2 ... p1 OR p2 + - INTERSECTION: p1 & p2 ... p1 AND p2 + - DIFFERENCE: p1 \\ p2 ... p1 - p2 + + Based on the paper "Efficient Clipping of Arbitrary Polygons" by + Günther Greiner and Kai Hormann. + This algorithm works only for polygons with real intersection points + and line end points on face edges are not considered as such intersection + points! + + """ + polygon1 = GHPolygon.build(p1) + polygon2 = GHPolygon.build(p2) + + if op == BooleanOperation.UNION: + return polygon1.union(polygon2) + elif op == BooleanOperation.DIFFERENCE: + return polygon1.difference(polygon2) + elif op == BooleanOperation.INTERSECTION: + return polygon1.intersection(polygon2) + raise ValueError(f"unknown or unsupported boolean operation: {op}") + + +LEFT = 0x1 +RIGHT = 0x2 +BOTTOM = 0x4 +TOP = 0x8 + + +class CohenSutherlandLineClipping2d: + """Cohen-Sutherland 2D line clipping algorithm, source: + https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm + + Args: + w_min: bottom-left corner of the clipping rectangle + w_max: top-right corner of the clipping rectangle + + """ + + __slots__ = ("x_min", "x_max", "y_min", "y_max") + + def __init__(self, w_min: Vec2, w_max: Vec2) -> None: + self.x_min, self.y_min = w_min + self.x_max, self.y_max = w_max + + def encode(self, x: float, y: float) -> int: + code: int = 0 + if x < self.x_min: + code |= LEFT + elif x > self.x_max: + code |= RIGHT + if y < self.y_min: + code |= BOTTOM + elif y > self.y_max: + code |= TOP + return code + + def clip_line(self, p0: Vec2, p1: Vec2) -> Sequence[Vec2]: + """Returns the clipped line part as tuple[Vec2, Vec2] or an empty tuple. + + Args: + p0: start-point of the line to clip + p1: end-point of the line to clip + + """ + x0, y0 = p0 + x1, y1 = p1 + code0 = self.encode(x0, y0) + code1 = self.encode(x1, y1) + x = x0 + y = y0 + while True: + if not code0 | code1: # ACCEPT + # bitwise OR is 0: both points inside window; trivially accept and + # exit loop: + return Vec2(x0, y0), Vec2(x1, y1) + if code0 & code1: # REJECT + # bitwise AND is not 0: both points share an outside zone (LEFT, + # RIGHT, TOP, or BOTTOM), so both must be outside window; + # exit loop + return tuple() + + # failed both tests, so calculate the line segment to clip + # from an outside point to an intersection with clip edge + # At least one endpoint is outside the clip rectangle; pick it + code = code1 if code1 > code0 else code0 + + # Now find the intersection point; + # use formulas: + # slope = (y1 - y0) / (x1 - x0) + # x = x0 + (1 / slope) * (ym - y0), where ym is y_min or y_max + # y = y0 + slope * (xm - x0), where xm is x_min or x_max + # No need to worry about divide-by-zero because, in each case, the + # code bit being tested guarantees the denominator is non-zero + if code & TOP: # point is above the clip window + x = x0 + (x1 - x0) * (self.y_max - y0) / (y1 - y0) + y = self.y_max + elif code & BOTTOM: # point is below the clip window + x = x0 + (x1 - x0) * (self.y_min - y0) / (y1 - y0) + y = self.y_min + elif code & RIGHT: # point is to the right of clip window + y = y0 + (y1 - y0) * (self.x_max - x0) / (x1 - x0) + x = self.x_max + elif code & LEFT: # point is to the left of clip window + y = y0 + (y1 - y0) * (self.x_min - x0) / (x1 - x0) + x = self.x_min + + if code == code0: + x0 = x + y0 = y + code0 = self.encode(x0, y0) + else: + x1 = x + y1 = y + code1 = self.encode(x1, y1) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/clustering.py b/.venv/lib/python3.12/site-packages/ezdxf/math/clustering.py new file mode 100644 index 0000000..1dbda32 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/clustering.py @@ -0,0 +1,141 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, Iterable, Optional +import random +import statistics +import itertools +import operator +from collections import defaultdict +from functools import reduce + +from ezdxf.math import AnyVec, Vec3, spherical_envelope +from ezdxf.math.rtree import RTree + +__all__ = [ + "dbscan", + "k_means", + "average_cluster_radius", + "average_intra_cluster_distance", +] + + +def dbscan( + points: list[AnyVec], + *, + radius: float, + min_points: int = 4, + rtree: Optional[RTree] = None, + max_node_size: int = 5, +) -> list[list[AnyVec]]: + """DBSCAN clustering. + + https://en.wikipedia.org/wiki/DBSCAN + + Args: + points: list of points to cluster + radius: radius of the dense regions + min_points: minimum number of points that needs to be within the + `radius` for a point to be a core point (must be >= 2) + rtree: optional :class:`~ezdxf.math.rtree.RTree` + max_node_size: max node size for internally created RTree + + Returns: + list of clusters, each cluster is a list of points + + """ + if min_points < 2: + raise ValueError("min_points must be >= 2") + if rtree is None: + rtree = RTree(points, max_node_size) + + clusters: list[set[AnyVec]] = [] + point_set = set(points) + while len(point_set): + point = point_set.pop() + todo = {point} + cluster = {point} # the cluster has only a single entry if noise + clusters.append(cluster) + while len(todo): + chk_point = todo.pop() + neighbors = set(rtree.points_in_sphere(chk_point, radius)) + if len(neighbors) < min_points: + continue + cluster.add(chk_point) + point_set.discard(chk_point) + todo |= neighbors.intersection(point_set) + + return [list(cluster) for cluster in clusters] + + +def k_means( + points: list[AnyVec], k: int, max_iter: int = 10 +) -> list[list[AnyVec]]: + """K-means clustering. + + https://en.wikipedia.org/wiki/K-means_clustering + + Args: + points: list of points to cluster + k: number of clusters + max_iter: max iterations + + Returns: + list of clusters, each cluster is a list of points + + """ + + def classify(centroids: Iterable[AnyVec]): + new_clusters: dict[AnyVec, list[AnyVec]] = defaultdict(list) + tree = RTree(centroids) + for point in points: + nn, _ = tree.nearest_neighbor(point) + new_clusters[nn].append(point) + return new_clusters + + def recenter() -> Iterator[AnyVec]: + for cluster_points in clusters.values(): + yield Vec3.sum(cluster_points) / len(cluster_points) + if len(clusters) < k: # refill centroids if required + yield from random.sample(points, k - len(clusters)) + + def is_equal_clustering(old_clusters, new_clusters): + def hash_list(lst): + lst.sort() + return reduce(operator.xor, map(hash, lst)) + + h1 = sorted(map(hash_list, old_clusters.values())) + h2 = sorted(map(hash_list, new_clusters.values())) + return h1 == h2 + + if not (1 < k < len(points)): + raise ValueError( + "invalid argument k: must be in range [2, len(points)-1]" + ) + clusters: dict[AnyVec, list[AnyVec]] = classify(random.sample(points, k)) + for _ in range(max_iter): + new_clusters = classify(recenter()) + if is_equal_clustering(clusters, new_clusters): + break + clusters = new_clusters + return list(clusters.values()) + + +def average_intra_cluster_distance(clusters: list[list[AnyVec]]) -> float: + """Returns the average point-to-point intra cluster distance.""" + + return statistics.mean( + [ + p.distance(q) + for cluster in clusters + for (p, q) in itertools.combinations(cluster, 2) + ] + ) + + +def average_cluster_radius(clusters: list[list[AnyVec]]) -> float: + """Returns the average cluster radius.""" + + return statistics.mean( + [spherical_envelope(cluster)[1] for cluster in clusters] + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/construct2d.py b/.venv/lib/python3.12/site-packages/ezdxf/math/construct2d.py new file mode 100644 index 0000000..48e30d7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/construct2d.py @@ -0,0 +1,380 @@ +# Copyright (c) 2011-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence + +from functools import partial +import math +import numpy as np +import numpy.typing as npt + +from ezdxf.math import ( + Vec3, + Vec2, + UVec, + Matrix44, + X_AXIS, + Y_AXIS, + arc_angle_span_rad, +) + +TOLERANCE = 1e-10 +RADIANS_90 = math.pi / 2.0 +RADIANS_180 = math.pi +RADIANS_270 = RADIANS_90 * 3.0 +RADIANS_360 = 2.0 * math.pi + +__all__ = [ + "closest_point", + "convex_hull_2d", + "distance_point_line_2d", + "is_convex_polygon_2d", + "is_axes_aligned_rectangle_2d", + "is_point_on_line_2d", + "is_point_left_of_line", + "point_to_line_relation", + "enclosing_angles", + "sign", + "area", + "np_area", + "circle_radius_3p", + "TOLERANCE", + "has_matrix_2d_stretching", + "decdeg2dms", + "ellipse_param_span", +] + + +def sign(f: float) -> float: + """Return sign of float `f` as -1 or +1, 0 returns +1""" + return -1.0 if f < 0.0 else +1.0 + + +def decdeg2dms(value: float) -> tuple[float, float, float]: + """Return decimal degrees as tuple (Degrees, Minutes, Seconds).""" + mnt, sec = divmod(value * 3600.0, 60.0) + deg, mnt = divmod(mnt, 60.0) + return deg, mnt, sec + + +def ellipse_param_span(start_param: float, end_param: float) -> float: + """Returns the counter-clockwise params span of an elliptic arc from start- + to end param. + + Returns the param span in the range [0, 2π], 2π is a full ellipse. + Full ellipse handling is a special case, because normalization of params + which describe a full ellipse would return 0 if treated as regular params. + e.g. (0, 2π) → 2π, (0, -2π) → 2π, (π, -π) → 2π. + Input params with the same value always return 0 by definition: + (0, 0) → 0, (-π, -π) → 0, (2π, 2π) → 0. + + Alias to function: :func:`ezdxf.math.arc_angle_span_rad` + + """ + return arc_angle_span_rad(float(start_param), float(end_param)) + + +def closest_point(base: UVec, points: Iterable[UVec]) -> Vec3 | None: + """Returns the closest point to a give `base` point. + + Args: + base: base point as :class:`Vec3` compatible object + points: iterable of points as :class:`Vec3` compatible object + + """ + base = Vec3(base) + min_dist: float | None = None + found: Vec3 | None = None + for point in points: + p = Vec3(point) + dist = base.distance(p) + if (min_dist is None) or (dist < min_dist): + min_dist = dist + found = p + return found + + +def convex_hull_2d(points: Iterable[UVec]) -> list[Vec2]: + """Returns the 2D convex hull of given `points`. + + Returns a closed polyline, first vertex is equal to the last vertex. + + Args: + points: iterable of points, z-axis is ignored + + """ + + # Source: https://massivealgorithms.blogspot.com/2019/01/convex-hull-sweep-line.html?m=1 + def cross(o: Vec2, a: Vec2, b: Vec2) -> float: + return (a - o).det(b - o) + + vertices = Vec2.list(set(points)) + vertices.sort() + if len(vertices) < 3: + raise ValueError("Convex hull calculation requires 3 or more unique points.") + + n: int = len(vertices) + hull: list[Vec2] = [Vec2()] * (2 * n) + k: int = 0 + i: int + for i in range(n): + while k >= 2 and cross(hull[k - 2], hull[k - 1], vertices[i]) <= 0.0: + k -= 1 + hull[k] = vertices[i] + k += 1 + t: int = k + 1 + for i in range(n - 2, -1, -1): + while k >= t and cross(hull[k - 2], hull[k - 1], vertices[i]) <= 0.0: + k -= 1 + hull[k] = vertices[i] + k += 1 + return hull[:k] + + +def enclosing_angles(angle, start_angle, end_angle, ccw=True, abs_tol=TOLERANCE): + isclose = partial(math.isclose, abs_tol=abs_tol) + + s = start_angle % math.tau + e = end_angle % math.tau + a = angle % math.tau + if isclose(s, e): + return isclose(s, a) + + if s < e: + r = s < a < e + else: + r = not (e < a < s) + return r if ccw else not r + + +def is_point_on_line_2d( + point: Vec2, start: Vec2, end: Vec2, ray=True, abs_tol=TOLERANCE +) -> bool: + """Returns ``True`` if `point` is on `line`. + + Args: + point: 2D point to test as :class:`Vec2` + start: line definition point as :class:`Vec2` + end: line definition point as :class:`Vec2` + ray: if ``True`` point has to be on the infinite ray, if ``False`` + point has to be on the line segment + abs_tol: tolerance for on the line test + + """ + point_x, point_y = point + start_x, start_y = start + end_x, end_y = end + on_line = ( + math.fabs( + (end_y - start_y) * point_x + - (end_x - start_x) * point_y + + (end_x * start_y - end_y * start_x) + ) + <= abs_tol + ) + if not on_line or ray: + return on_line + else: + if start_x > end_x: + start_x, end_x = end_x, start_x + if not (start_x - abs_tol <= point_x <= end_x + abs_tol): + return False + if start_y > end_y: + start_y, end_y = end_y, start_y + if not (start_y - abs_tol <= point_y <= end_y + abs_tol): + return False + return True + + +def point_to_line_relation( + point: Vec2, start: Vec2, end: Vec2, abs_tol=TOLERANCE +) -> int: + """Returns ``-1`` if `point` is left `line`, ``+1`` if `point` is right of + `line` and ``0`` if `point` is on the `line`. The `line` is defined by two + vertices given as arguments `start` and `end`. + + Args: + point: 2D point to test as :class:`Vec2` + start: line definition point as :class:`Vec2` + end: line definition point as :class:`Vec2` + abs_tol: tolerance for minimum distance to line + + """ + rel = (end.x - start.x) * (point.y - start.y) - (end.y - start.y) * ( + point.x - start.x + ) + if abs(rel) <= abs_tol: + return 0 + elif rel < 0: + return +1 + else: + return -1 + + +def is_point_left_of_line(point: Vec2, start: Vec2, end: Vec2, colinear=False) -> bool: + """Returns ``True`` if `point` is "left of line" defined by `start-` and + `end` point, a colinear point is also "left of line" if argument `colinear` + is ``True``. + + Args: + point: 2D point to test as :class:`Vec2` + start: line definition point as :class:`Vec2` + end: line definition point as :class:`Vec2` + colinear: a colinear point is also "left of line" if ``True`` + + """ + rel = point_to_line_relation(point, start, end) + if colinear: + return rel < 1 + else: + return rel < 0 + + +def distance_point_line_2d(point: Vec2, start: Vec2, end: Vec2) -> float: + """Returns the normal distance from `point` to 2D line defined by `start-` + and `end` point. + """ + # wikipedia: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line. + if start.isclose(end): + raise ZeroDivisionError("Not a line.") + return math.fabs((start - point).det(end - point)) / (end - start).magnitude + + +def circle_radius_3p(a: Vec3, b: Vec3, c: Vec3) -> float: + ba = b - a + ca = c - a + cb = c - b + upper = ba.magnitude * ca.magnitude * cb.magnitude + lower = ba.cross(ca).magnitude * 2.0 + return upper / lower + + +def area(vertices: Iterable[UVec]) -> float: + """Returns the area of a polygon. + + Returns the projected area in the xy-plane for any vertices (z-axis will be ignored). + + """ + # TODO: how to do all this in numpy efficiently? + + vec2s = Vec2.list(vertices) + if len(vec2s) < 3: + return 0.0 + + # close polygon: + if not vec2s[0].isclose(vec2s[-1]): + vec2s.append(vec2s[0]) + return np_area(np.array([(v.x, v.y) for v in vec2s], dtype=np.float64)) + + +def np_area(vertices: npt.NDArray) -> float: + """Returns the area of a polygon. + + Returns the projected area in the xy-plane, the z-axis will be ignored. + The polygon has to be closed (first vertex == last vertex) and should have 3 or more + corner vertices to return a valid result. + + Args: + vertices: numpy array [:, n], n > 1 + + """ + p1x = vertices[:-1, 0] + p2x = vertices[1:, 0] + p1y = vertices[:-1, 1] + p2y = vertices[1:, 1] + return np.abs(np.sum(p1x * p2y - p1y * p2x)) * 0.5 + + +def has_matrix_2d_stretching(m: Matrix44) -> bool: + """Returns ``True`` if matrix `m` performs a non-uniform xy-scaling. + Uniform scaling is not stretching in this context. + + Does not check if the target system is a cartesian coordinate system, use the + :class:`~ezdxf.math.Matrix44` property :attr:`~ezdxf.math.Matrix44.is_cartesian` + for that. + """ + ux = m.transform_direction(X_AXIS) + uy = m.transform_direction(Y_AXIS) + return not math.isclose(ux.magnitude_square, uy.magnitude_square) + + +def is_convex_polygon_2d(polygon: list[Vec2], *, strict=False, epsilon=1e-6) -> bool: + """Returns ``True`` if the 2D `polygon` is convex. + + This function supports open and closed polygons with clockwise or counter-clockwise + vertex orientation. + + Coincident vertices will always be skipped and if argument `strict` is ``True``, + polygons with collinear vertices are not considered as convex. + + This solution works only for simple non-self-intersecting polygons! + + """ + # TODO: Cython implementation + if len(polygon) < 3: + return False + + global_sign: int = 0 + current_sign: int = 0 + prev = polygon[-1] + prev_prev = polygon[-2] + for vertex in polygon: + if vertex.isclose(prev): # skip coincident vertices + continue + + det = (prev - vertex).det(prev_prev - prev) + if abs(det) >= epsilon: + current_sign = -1 if det < 0.0 else +1 + if not global_sign: + global_sign = current_sign + # do all determinants have the same sign? + if global_sign != current_sign: + return False + elif strict: # collinear vertices + return False + + prev_prev = prev + prev = vertex + return bool(global_sign) + + +def is_axes_aligned_rectangle_2d(points: list[Vec2]) -> bool: + """Returns ``True`` if the given points represent a rectangle aligned with the + coordinate system axes. + + The sides of the rectangle must be parallel to the x- and y-axes of the coordinate + system. The rectangle can be open or closed (first point == last point) and + oriented clockwise or counter-clockwise. Only works with 4 or 5 vertices, rectangles + that have sides with collinear edges are not considered rectangles. + + .. versionadded:: 1.2.0 + + """ + + def is_horizontal(a: Vec2, b: Vec2) -> bool: + return math.isclose(a.y, b.y) + + def is_vertical(a: Vec2, b: Vec2): + return math.isclose(a.x, b.x) + + count = len(points) + if points[0].isclose(points[-1]): + count -= 1 + if count != 4: + return False + p0, p1, p2, p3, *_ = points + if ( + is_horizontal(p0, p1) + and is_vertical(p1, p2) + and is_horizontal(p2, p3) + and is_vertical(p3, p0) + ): + return True + if ( + is_horizontal(p1, p2) + and is_vertical(p2, p3) + and is_horizontal(p3, p0) + and is_vertical(p0, p1) + ): + return True + return False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/construct3d.py b/.venv/lib/python3.12/site-packages/ezdxf/math/construct3d.py new file mode 100644 index 0000000..f8058e4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/construct3d.py @@ -0,0 +1,769 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterable, Optional, Iterator +from enum import IntEnum +import math +from ezdxf.math import ( + Vec3, + Vec2, + Matrix44, + X_AXIS, + Y_AXIS, + Z_AXIS, + AnyVec, + UVec, +) + + +__all__ = [ + "is_planar_face", + "subdivide_face", + "subdivide_ngons", + "Plane", + "PlaneLocationState", + "normal_vector_3p", + "safe_normal_vector", + "distance_point_line_3d", + "intersection_line_line_3d", + "intersection_ray_polygon_3d", + "intersection_line_polygon_3d", + "basic_transformation", + "best_fit_normal", + "BarycentricCoordinates", + "linear_vertex_spacing", + "has_matrix_3d_stretching", + "spherical_envelope", + "inscribe_circle_tangent_length", + "bending_angle", + "split_polygon_by_plane", + "is_face_normal_pointing_outwards", +] +PI2 = math.pi / 2.0 + + +def is_planar_face(face: Sequence[Vec3], abs_tol=1e-9) -> bool: + """Returns ``True`` if sequence of vectors is a planar face. + + Args: + face: sequence of :class:`~ezdxf.math.Vec3` objects + abs_tol: tolerance for normals check + + """ + if len(face) < 3: + return False + if len(face) == 3: + return True + first_normal = None + for index in range(len(face) - 2): + a, b, c = face[index : index + 3] + try: + normal = (b - a).cross(c - b).normalize() + except ZeroDivisionError: # colinear edge + continue + if first_normal is None: + first_normal = normal + elif not first_normal.isclose(normal, abs_tol=abs_tol): + return False + if first_normal is not None: + return True + return False + + +def subdivide_face( + face: Sequence[Vec3], quads: bool = True +) -> Iterator[Sequence[Vec3]]: + """Subdivides faces by subdividing edges and adding a center vertex. + + Args: + face: a sequence of :class:`Vec3` + quads: create quad faces if ``True`` else create triangles + + """ + if len(face) < 3: + raise ValueError("3 or more vertices required.") + + len_face: int = len(face) + mid_pos = Vec3.sum(face) / len_face + subdiv_location: list[Vec3] = [ + face[i].lerp(face[(i + 1) % len_face]) for i in range(len_face) + ] + + for index, vertex in enumerate(face): + if quads: + yield vertex, subdiv_location[index], mid_pos, subdiv_location[ + index - 1 + ] + else: + yield subdiv_location[index - 1], vertex, mid_pos + yield vertex, subdiv_location[index], mid_pos + + +def subdivide_ngons( + faces: Iterable[Sequence[Vec3]], + max_vertex_count=4, +) -> Iterator[Sequence[Vec3]]: + """Subdivides faces into triangles by adding a center vertex. + + Args: + faces: iterable of faces as sequence of :class:`Vec3` + max_vertex_count: subdivide only ngons with more vertices + + """ + for face in faces: + if len(face) <= max_vertex_count: + yield Vec3.tuple(face) + else: + mid_pos = Vec3.sum(face) / len(face) + for index, vertex in enumerate(face): + yield face[index - 1], vertex, mid_pos + + +def normal_vector_3p(a: Vec3, b: Vec3, c: Vec3) -> Vec3: + """Returns normal vector for 3 points, which is the normalized cross + product for: :code:`a->b x a->c`. + """ + return (b - a).cross(c - a).normalize() + + +def safe_normal_vector(vertices: Sequence[Vec3]) -> Vec3: + """Safe function to detect the normal vector for a face or polygon defined + by 3 or more `vertices`. + + """ + if len(vertices) < 3: + raise ValueError("3 or more vertices required") + a, b, c, *_ = vertices + try: # fast path + return (b - a).cross(c - a).normalize() + except ZeroDivisionError: # safe path, can still raise ZeroDivisionError + return best_fit_normal(vertices) + + +def best_fit_normal(vertices: Iterable[UVec]) -> Vec3: + """Returns the "best fit" normal for a plane defined by three or more + vertices. This function tolerates imperfect plane vertices. Safe function + to detect the extrusion vector of flat arbitrary polygons. + + """ + # Source: https://gamemath.com/book/geomprims.html#plane_best_fit (9.5.3) + _vertices = Vec3.list(vertices) + if len(_vertices) < 3: + raise ValueError("3 or more vertices required") + first = _vertices[0] + if not first.isclose(_vertices[-1]): + _vertices.append(first) # close polygon + prev_x, prev_y, prev_z = first.xyz + nx = 0.0 + ny = 0.0 + nz = 0.0 + for v in _vertices[1:]: + x, y, z = v.xyz + nx += (prev_z + z) * (prev_y - y) + ny += (prev_x + x) * (prev_z - z) + nz += (prev_y + y) * (prev_x - x) + prev_x = x + prev_y = y + prev_z = z + return Vec3(nx, ny, nz).normalize() + + +def distance_point_line_3d(point: Vec3, start: Vec3, end: Vec3) -> float: + """Returns the normal distance from a `point` to a 3D line. + + Args: + point: point to test + start: start point of the 3D line + end: end point of the 3D line + + """ + if start.isclose(end): + raise ZeroDivisionError("Not a line.") + v1 = point - start + # point projected onto line start to end: + v2 = (end - start).project(v1) + # Pythagoras: + diff = v1.magnitude_square - v2.magnitude_square + if diff <= 0.0: + # This should not happen (abs(v1) > abs(v2)), but floating point + # imprecision at very small values makes it possible! + return 0.0 + else: + return math.sqrt(diff) + + +def intersection_line_line_3d( + line1: Sequence[Vec3], + line2: Sequence[Vec3], + virtual: bool = True, + abs_tol: float = 1e-10, +) -> Optional[Vec3]: + """ + Returns the intersection point of two 3D lines, returns ``None`` if lines + do not intersect. + + Args: + line1: first line as tuple of two points as :class:`Vec3` objects + line2: second line as tuple of two points as :class:`Vec3` objects + virtual: ``True`` returns any intersection point, ``False`` returns only + real intersection points + abs_tol: absolute tolerance for comparisons + + """ + from ezdxf.math import intersection_ray_ray_3d, BoundingBox + + res = intersection_ray_ray_3d(line1, line2, abs_tol) + if len(res) != 1: + return None + + point = res[0] + if virtual: + return point + if BoundingBox(line1).inside(point) and BoundingBox(line2).inside(point): + return point + return None + + +def basic_transformation( + move: UVec = (0, 0, 0), + scale: UVec = (1, 1, 1), + z_rotation: float = 0, +) -> Matrix44: + """Returns a combined transformation matrix for translation, scaling and + rotation about the z-axis. + + Args: + move: translation vector + scale: x-, y- and z-axis scaling as float triplet, e.g. (2, 2, 1) + z_rotation: rotation angle about the z-axis in radians + + """ + sx, sy, sz = Vec3(scale) + m = Matrix44.scale(sx, sy, sz) + if z_rotation: + m *= Matrix44.z_rotate(z_rotation) + translate = Vec3(move) + if not translate.is_null: + m *= Matrix44.translate(translate.x, translate.y, translate.z) + return m + + +PLANE_EPSILON = 1e-9 + + +class PlaneLocationState(IntEnum): + COPLANAR = 0 # all the vertices are within the plane + FRONT = 1 # all the vertices are in front of the plane + BACK = 2 # all the vertices are at the back of the plane + SPANNING = 3 # some vertices are in front, some in the back + + +class Plane: + """Construction tool for 3D planes. + + Represents a plane in 3D space as a normal vector and the perpendicular + distance from the origin. + """ + + __slots__ = ("_normal", "_distance_from_origin") + + def __init__(self, normal: Vec3, distance: float): + assert normal.is_null is False, "invalid plane normal" + self._normal = normal + # the (perpendicular) distance of the plane from (0, 0, 0) + self._distance_from_origin = distance + + @property + def normal(self) -> Vec3: + """Normal vector of the plane.""" + return self._normal + + @property + def distance_from_origin(self) -> float: + """The (perpendicular) distance of the plane from origin (0, 0, 0).""" + return self._distance_from_origin + + @property + def vector(self) -> Vec3: + """Returns the location vector.""" + return self._normal * self._distance_from_origin + + @classmethod + def from_3p(cls, a: Vec3, b: Vec3, c: Vec3) -> "Plane": + """Returns a new plane from 3 points in space.""" + try: + n = (b - a).cross(c - a).normalize() + except ZeroDivisionError: + raise ValueError("undefined plane: colinear vertices") + return Plane(n, n.dot(a)) + + @classmethod + def from_vector(cls, vector: UVec) -> "Plane": + """Returns a new plane from the given location vector.""" + v = Vec3(vector) + try: + return Plane(v.normalize(), v.magnitude) + except ZeroDivisionError: + raise ValueError("invalid NULL vector") + + def __copy__(self) -> "Plane": + """Returns a copy of the plane.""" + return self.__class__(self._normal, self._distance_from_origin) + + copy = __copy__ + + def __repr__(self): + return f"Plane({repr(self._normal)}, {self._distance_from_origin})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Plane): + return NotImplemented + return self.vector == other.vector + + def signed_distance_to(self, v: Vec3) -> float: + """Returns signed distance of vertex `v` to plane, if distance is > 0, + `v` is in 'front' of plane, in direction of the normal vector, if + distance is < 0, `v` is at the 'back' of the plane, in the opposite + direction of the normal vector. + + """ + return self._normal.dot(v) - self._distance_from_origin + + def distance_to(self, v: Vec3) -> float: + """Returns absolute (unsigned) distance of vertex `v` to plane.""" + return math.fabs(self.signed_distance_to(v)) + + def is_coplanar_vertex(self, v: Vec3, abs_tol=1e-9) -> bool: + """Returns ``True`` if vertex `v` is coplanar, distance from plane to + vertex `v` is 0. + """ + return self.distance_to(v) < abs_tol + + def is_coplanar_plane(self, p: "Plane", abs_tol=1e-9) -> bool: + """Returns ``True`` if plane `p` is coplanar, normal vectors in same or + opposite direction. + """ + n_is_close = self._normal.isclose + return n_is_close(p._normal, abs_tol=abs_tol) or n_is_close( + -p._normal, abs_tol=abs_tol + ) + + def intersect_line( + self, start: Vec3, end: Vec3, *, coplanar=True, abs_tol=PLANE_EPSILON + ) -> Optional[Vec3]: + """Returns the intersection point of the 3D line from `start` to `end` + and this plane or ``None`` if there is no intersection. If the argument + `coplanar` is ``False`` the start- or end point of the line are ignored + as intersection points. + + """ + state0 = self.vertex_location_state(start, abs_tol) + state1 = self.vertex_location_state(end, abs_tol) + if state0 is state1: + return None + if not coplanar and ( + state0 is PlaneLocationState.COPLANAR + or state1 is PlaneLocationState.COPLANAR + ): + return None + n = self.normal + weight = (self.distance_from_origin - n.dot(start)) / n.dot(end - start) + return start.lerp(end, weight) + + def intersect_ray(self, origin: Vec3, direction: Vec3) -> Optional[Vec3]: + """Returns the intersection point of the infinite 3D ray defined by + `origin` and the `direction` vector and this plane or ``None`` if there + is no intersection. A coplanar ray does not intersect the plane! + + """ + n = self.normal + try: + weight = (self.distance_from_origin - n.dot(origin)) / n.dot( + direction + ) + except ZeroDivisionError: + return None + return origin + (direction * weight) + + def vertex_location_state( + self, vertex: Vec3, abs_tol=PLANE_EPSILON + ) -> PlaneLocationState: + """Returns the :class:`PlaneLocationState` of the given `vertex` in + relative to this plane. + + """ + distance = self._normal.dot(vertex) - self._distance_from_origin + if distance < -abs_tol: + return PlaneLocationState.BACK + elif distance > abs_tol: + return PlaneLocationState.FRONT + else: + return PlaneLocationState.COPLANAR + + +def split_polygon_by_plane( + polygon: Iterable[Vec3], + plane: Plane, + *, + coplanar=True, + abs_tol=PLANE_EPSILON, +) -> tuple[Sequence[Vec3], Sequence[Vec3]]: + """Split a convex `polygon` by the given `plane`. + + Returns a tuple of front- and back vertices (front, back). + Returns also coplanar polygons if the + argument `coplanar` is ``True``, the coplanar vertices goes into either + front or back depending on their orientation with respect to this plane. + + """ + polygon_type = PlaneLocationState.COPLANAR + vertex_types: list[PlaneLocationState] = [] + front_vertices: list[Vec3] = [] + back_vertices: list[Vec3] = [] + vertices = list(polygon) + w = plane.distance_from_origin + normal = plane.normal + + # Classify each point as well as the entire polygon into one of four classes: + # COPLANAR, FRONT, BACK, SPANNING = FRONT + BACK + for vertex in vertices: + vertex_type = plane.vertex_location_state(vertex, abs_tol) + polygon_type |= vertex_type # type: ignore + vertex_types.append(vertex_type) + + # Put the polygon in the correct list, splitting it when necessary. + if polygon_type == PlaneLocationState.COPLANAR: + if coplanar: + polygon_normal = best_fit_normal(vertices) + if normal.dot(polygon_normal) > 0: + front_vertices = vertices + else: + back_vertices = vertices + elif polygon_type == PlaneLocationState.FRONT: + front_vertices = vertices + elif polygon_type == PlaneLocationState.BACK: + back_vertices = vertices + elif polygon_type == PlaneLocationState.SPANNING: + len_vertices = len(vertices) + for index in range(len_vertices): + next_index = (index + 1) % len_vertices + vertex_type = vertex_types[index] + next_vertex_type = vertex_types[next_index] + vertex = vertices[index] + next_vertex = vertices[next_index] + if vertex_type != PlaneLocationState.BACK: # FRONT or COPLANAR + front_vertices.append(vertex) + if vertex_type != PlaneLocationState.FRONT: # BACK or COPLANAR + back_vertices.append(vertex) + if (vertex_type | next_vertex_type) == PlaneLocationState.SPANNING: + interpolation_weight = (w - normal.dot(vertex)) / normal.dot( + next_vertex - vertex + ) + plane_intersection_point = vertex.lerp( + next_vertex, interpolation_weight + ) + front_vertices.append(plane_intersection_point) + back_vertices.append(plane_intersection_point) + if len(front_vertices) < 3: + front_vertices = [] + if len(back_vertices) < 3: + back_vertices = [] + return tuple(front_vertices), tuple(back_vertices) + + +def intersection_line_polygon_3d( + start: Vec3, + end: Vec3, + polygon: Iterable[Vec3], + *, + coplanar=True, + boundary=True, + abs_tol=PLANE_EPSILON, +) -> Optional[Vec3]: + """Returns the intersection point of the 3D line form `start` to `end` and + the given `polygon`. + + Args: + start: start point of 3D line as :class:`Vec3` + end: end point of 3D line as :class:`Vec3` + polygon: 3D polygon as iterable of :class:`Vec3` + coplanar: if ``True`` a coplanar start- or end point as intersection + point is valid + boundary: if ``True`` an intersection point at the polygon boundary line + is valid + abs_tol: absolute tolerance for comparisons + + """ + vertices = list(polygon) + if len(vertices) < 3: + raise ValueError("3 or more vertices required") + try: + normal = safe_normal_vector(vertices) + except ZeroDivisionError: + return None + plane = Plane(normal, normal.dot(vertices[0])) + ip = plane.intersect_line(start, end, coplanar=coplanar, abs_tol=abs_tol) + if ip is None: + return None + return _is_intersection_point_inside_3d_polygon( + ip, vertices, normal, boundary, abs_tol + ) + + +def intersection_ray_polygon_3d( + origin: Vec3, + direction: Vec3, + polygon: Iterable[Vec3], + *, + boundary=True, + abs_tol=PLANE_EPSILON, +) -> Optional[Vec3]: + """Returns the intersection point of the infinite 3D ray defined by `origin` + and the `direction` vector and the given `polygon`. + + Args: + origin: origin point of the 3D ray as :class:`Vec3` + direction: direction vector of the 3D ray as :class:`Vec3` + polygon: 3D polygon as iterable of :class:`Vec3` + boundary: if ``True`` intersection points at the polygon boundary line + are valid + abs_tol: absolute tolerance for comparisons + + """ + + vertices = list(polygon) + if len(vertices) < 3: + raise ValueError("3 or more vertices required") + try: + normal = safe_normal_vector(vertices) + except ZeroDivisionError: + return None + plane = Plane(normal, normal.dot(vertices[0])) + ip = plane.intersect_ray(origin, direction) + if ip is None: + return None + return _is_intersection_point_inside_3d_polygon( + ip, vertices, normal, boundary, abs_tol + ) + + +def _is_intersection_point_inside_3d_polygon( + ip: Vec3, vertices: list[Vec3], normal: Vec3, boundary: bool, abs_tol: float +): + from ezdxf.math import is_point_in_polygon_2d, OCS + + ocs = OCS(normal) + ocs_vertices = Vec2.list(ocs.points_from_wcs(vertices)) + state = is_point_in_polygon_2d( + Vec2(ocs.from_wcs(ip)), ocs_vertices, abs_tol=abs_tol + ) + if state > 0 or (boundary and state == 0): + return ip + return None + + +class BarycentricCoordinates: + """Barycentric coordinate calculation. + + The arguments `a`, `b` and `c` are the cartesian coordinates of an arbitrary + triangle in 3D space. The barycentric coordinates (b1, b2, b3) define the + linear combination of `a`, `b` and `c` to represent the point `p`:: + + p = a * b1 + b * b2 + c * b3 + + This implementation returns the barycentric coordinates of the normal + projection of `p` onto the plane defined by (a, b, c). + + These barycentric coordinates have some useful properties: + + - if all barycentric coordinates (b1, b2, b3) are in the range [0, 1], then + the point `p` is inside the triangle (a, b, c) + - if one of the coordinates is negative, the point `p` is outside the + triangle + - the sum of b1, b2 and b3 is always 1 + - the center of "mass" has the barycentric coordinates (1/3, 1/3, 1/3) = + (a + b + c)/3 + + """ + + # Source: https://gamemath.com/book/geomprims.html#triangle_barycentric_space + + def __init__(self, a: UVec, b: UVec, c: UVec): + self.a = Vec3(a) + self.b = Vec3(b) + self.c = Vec3(c) + self._e1 = self.c - self.b + self._e2 = self.a - self.c + self._e3 = self.b - self.a + e1xe2 = self._e1.cross(self._e2) + self._n = e1xe2.normalize() + self._denom = e1xe2.dot(self._n) + if abs(self._denom) < 1e-9: + raise ValueError("invalid triangle") + + def from_cartesian(self, p: UVec) -> Vec3: + p = Vec3(p) + n = self._n + denom = self._denom + d1 = p - self.a + d2 = p - self.b + d3 = p - self.c + b1 = self._e1.cross(d3).dot(n) / denom + b2 = self._e2.cross(d1).dot(n) / denom + b3 = self._e3.cross(d2).dot(n) / denom + return Vec3(b1, b2, b3) + + def to_cartesian(self, b: UVec) -> Vec3: + b1, b2, b3 = Vec3(b).xyz + return self.a * b1 + self.b * b2 + self.c * b3 + + +def linear_vertex_spacing(start: Vec3, end: Vec3, count: int) -> list[Vec3]: + """Returns `count` evenly spaced vertices from `start` to `end`.""" + if count <= 2: + return [start, end] + distance = end - start + if distance.is_null: + return [start] * count + + vertices = [start] + step = distance.normalize(distance.magnitude / (count - 1)) + for _ in range(1, count - 1): + start += step + vertices.append(start) + vertices.append(end) + return vertices + + +def has_matrix_3d_stretching(m: Matrix44) -> bool: + """Returns ``True`` if matrix `m` performs a non-uniform xyz-scaling. + Uniform scaling is not stretching in this context. + + Does not check if the target system is a cartesian coordinate system, use the + :class:`~ezdxf.math.Matrix44` property :attr:`~ezdxf.math.Matrix44.is_cartesian` + for that. + """ + ux_mag_sqr = m.transform_direction(X_AXIS).magnitude_square + uy = m.transform_direction(Y_AXIS) + uz = m.transform_direction(Z_AXIS) + return not math.isclose( + ux_mag_sqr, uy.magnitude_square + ) or not math.isclose(ux_mag_sqr, uz.magnitude_square) + + +def spherical_envelope(points: Sequence[UVec]) -> tuple[Vec3, float]: + """Calculate the spherical envelope for the given points. Returns the + centroid (a.k.a. geometric center) and the radius of the enclosing sphere. + + .. note:: + + The result does not represent the minimal bounding sphere! + + """ + centroid = Vec3.sum(points) / len(points) + radius = max(centroid.distance(p) for p in points) + return centroid, radius + + +def inscribe_circle_tangent_length( + dir1: Vec3, dir2: Vec3, radius: float +) -> float: + """Returns the tangent length of an inscribe-circle of the given `radius`. + The direction `dir1` and `dir2` define two intersection tangents, + The tangent length is the distance from the intersection point of the + tangents to the touching point on the inscribe-circle. + + """ + alpha = dir1.angle_between(dir2) + beta = PI2 - (alpha / 2.0) + if math.isclose(abs(beta), PI2): + return 0.0 + return abs(math.tan(beta) * radius) + + +def bending_angle(dir1: Vec3, dir2: Vec3, normal=Z_AXIS) -> float: + """Returns the bending angle from `dir1` to `dir2` in radians. + + The normal vector is required to detect the bending orientation, + an angle > 0 bends to the "left" an angle < 0 bends to the "right". + + """ + angle = dir1.angle_between(dir2) + nn = dir1.cross(dir2) + if nn.isclose(normal) or nn.is_null: + return angle + elif nn.isclose(-normal): + return -angle + raise ValueError("invalid normal vector") + + +def any_vertex_inside_face(vertices: Sequence[Vec3]) -> Vec3: + """Returns a vertex from the "inside" of the given face. + """ + # Triangulation is for concave shapes important! + from ezdxf.math.triangulation import mapbox_earcut_3d + it = mapbox_earcut_3d(vertices) + return Vec3.sum(next(it)) / 3.0 + + +def front_faces_intersect_face_normal( + faces: Sequence[Sequence[Vec3]], + face: Sequence[Vec3], + *, + abs_tol=PLANE_EPSILON, +) -> int: + """Returns the count of intersections of the normal-vector of the given + `face` with the `faces` in front of this `face`. + + A counter-clockwise vertex order is assumed! + + """ + def is_face_in_front_of_detector(vertices: Sequence[Vec3]) -> bool: + if len(vertices) < 3: + return False + return any( + detector_plane.signed_distance_to(v) > abs_tol for v in vertices + ) + + # face-normal for counter-clockwise vertex order + face_normal = safe_normal_vector(face) + origin = any_vertex_inside_face(face) + detector_plane = Plane(face_normal, face_normal.dot(origin)) + + # collect all faces with at least one vertex in front of the detection plane + front_faces = (f for f in faces if is_face_in_front_of_detector(f)) + + # The detector face is excluded by the + # is_face_in_front_of_detector() function! + + intersection_points: set[Vec3] = set() + for face in front_faces: + ip = intersection_ray_polygon_3d( + origin, face_normal, face, boundary=True, abs_tol=abs_tol + ) + if ip is None: + continue + if detector_plane.signed_distance_to(ip) > abs_tol: + # Only count unique intersections points, the ip could lie on an + # edge (2 ips) or even a corner vertex (3 or more ips). + intersection_points.add(ip.round(6)) + return len(intersection_points) + + +def is_face_normal_pointing_outwards( + faces: Sequence[Sequence[Vec3]], + face: Sequence[Vec3], + *, + abs_tol=PLANE_EPSILON, +) -> bool: + """Returns ``True`` if the face-normal for the given `face` of a + closed surface is pointing outwards. A counter-clockwise vertex order is + assumed, for faces with clockwise vertex order the result is inverted, + therefore ``False`` is pointing outwards. + + This function does not check if the `faces` are a closed surface. + + """ + return ( + front_faces_intersect_face_normal(faces, face, abs_tol=abs_tol) % 2 == 0 + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/cspline.py b/.venv/lib/python3.12/site-packages/ezdxf/math/cspline.py new file mode 100644 index 0000000..f4cfcef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/cspline.py @@ -0,0 +1,40 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable +import numpy as np + +from ezdxf.math import Vec3 + + +class CSpline: + """ + In numerical analysis, a cubic Hermite spline or cubic Hermite interpolator + is a spline where each piece is a third-degree polynomial specified in + Hermite form, that is, by its values and first derivatives at the end points + of the corresponding domain interval. + + Source: https://en.wikipedia.org/wiki/Cubic_Hermite_spline + """ + + # https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline + def __init__(self, p0: Vec3, p1: Vec3, m0: Vec3, m1: Vec3): + self.p0 = p0 + self.p1 = p1 + self.m0 = m0 + self.m1 = m1 + + def point(self, t: float) -> Vec3: + t2 = t * t + t3 = t2 * t + h00 = t3 * 2.0 - t2 * 3.0 + 1.0 + h10 = -t3 * 2.0 + t2 * 3.0 + h01 = t3 - t2 * 2.0 + t + h11 = t3 - t2 + return self.p0 * h00 + self.p1 * h10 + self.m0 * h01 + self.m1 * h11 + + +def approximate(csplines: Iterable[CSpline], count) -> Iterable[Vec3]: + for cspline in csplines: + for t in np.linspace(0.0, 1.0, count): + yield cspline.point(t) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/curvetools.py b/.venv/lib/python3.12/site-packages/ezdxf/math/curvetools.py new file mode 100644 index 0000000..8081914 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/curvetools.py @@ -0,0 +1,286 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Union, Sequence, TypeVar +import math +from ezdxf.math import ( + BSpline, + Bezier4P, + Bezier3P, + UVec, + Vec3, + Vec2, + AnyVec, + BoundingBox, +) +from ezdxf.math.linalg import cubic_equation + +__all__ = [ + "bezier_to_bspline", + "quadratic_to_cubic_bezier", + "have_bezier_curves_g1_continuity", + "AnyBezier", + "reverse_bezier_curves", + "split_bezier", + "quadratic_bezier_from_3p", + "cubic_bezier_from_3p", + "cubic_bezier_bbox", + "quadratic_bezier_bbox", + "intersection_ray_cubic_bezier_2d", +] + + +T = TypeVar("T", bound=AnyVec) + +AnyBezier = Union[Bezier3P, Bezier4P] + + +def quadratic_to_cubic_bezier(curve: Bezier3P) -> Bezier4P: + """Convert quadratic Bèzier curves (:class:`ezdxf.math.Bezier3P`) into + cubic Bèzier curves (:class:`ezdxf.math.Bezier4P`). + + """ + start, control, end = curve.control_points + control_1 = start + 2 * (control - start) / 3 + control_2 = end + 2 * (control - end) / 3 + return Bezier4P((start, control_1, control_2, end)) + + +def bezier_to_bspline(curves: Iterable[AnyBezier]) -> BSpline: + """Convert multiple quadratic or cubic Bèzier curves into a single cubic + B-spline. + + For good results the curves must be lined up seamlessly, i.e. the starting + point of the following curve must be the same as the end point of the + previous curve. G1 continuity or better at the connection points of the + Bézier curves is required to get best results. + + """ + + # Source: https://math.stackexchange.com/questions/2960974/convert-continuous-bezier-curve-to-b-spline + def get_points(bezier: AnyBezier): + points = bezier.control_points + if len(points) < 4: + return quadratic_to_cubic_bezier(bezier).control_points + else: + return points + + bezier_curve_points = [get_points(c) for c in curves] + if len(bezier_curve_points) == 0: + raise ValueError("one or more Bézier curves required") + # Control points of the B-spline are the same as of the Bézier curves. + # Remove duplicate control points at start and end of the curves. + control_points = list(bezier_curve_points[0]) + for c in bezier_curve_points[1:]: + control_points.extend(c[1:]) + knots = [0, 0, 0, 0] # multiplicity of the 1st and last control point is 4 + n = len(bezier_curve_points) + for k in range(1, n): + knots.extend((k, k, k)) # multiplicity of the inner control points is 3 + knots.extend((n, n, n, n)) + return BSpline(control_points, order=4, knots=knots) + + +def have_bezier_curves_g1_continuity( + b1: AnyBezier, b2: AnyBezier, g1_tol: float = 1e-4 +) -> bool: + """Return ``True`` if the given adjacent Bézier curves have G1 continuity. + """ + b1_pnts = tuple(b1.control_points) + b2_pnts = tuple(b2.control_points) + + if not b1_pnts[-1].isclose(b2_pnts[0]): + return False # start- and end point are not close enough + + try: + te = (b1_pnts[-1] - b1_pnts[-2]).normalize() + except ZeroDivisionError: + return False # tangent calculation not possible + + try: + ts = (b2_pnts[1] - b2_pnts[0]).normalize() + except ZeroDivisionError: + return False # tangent calculation not possible + + # 0 = normal; 1 = same direction; -1 = opposite direction + return math.isclose(te.dot(ts), 1.0, abs_tol=g1_tol) + + +def reverse_bezier_curves(curves: list[AnyBezier]) -> list[AnyBezier]: + curves = list(c.reverse() for c in curves) + curves.reverse() + return curves + + +def split_bezier( + control_points: Sequence[T], t: float +) -> tuple[list[T], list[T]]: + """Split a Bèzier curve at parameter `t`. + + Returns the control points for two new Bèzier curves of the same degree + and type as the input curve. (source: `pomax-1`_) + + Args: + control_points: of the Bèzier curve as :class:`Vec2` or :class:`Vec3` + objects. Requires 3 points for a quadratic curve, 4 points for a + cubic curve , ... + t: parameter where to split the curve in the range [0, 1] + + .. _pomax-1: https://pomax.github.io/bezierinfo/#splitting + + """ + if len(control_points) < 2: + raise ValueError("2 or more control points required") + if t < 0.0 or t > 1.0: + raise ValueError("parameter `t` must be in range [0, 1]") + left: list[T] = [] + right: list[T] = [] + + def split(points: Sequence[T]): + n: int = len(points) - 1 + left.append(points[0]) + right.append(points[n]) + if n == 0: + return + split( + tuple(points[i] * (1.0 - t) + points[i + 1] * t for i in range(n)) + ) + + split(control_points) + return left, right + + +def quadratic_bezier_from_3p(p1: UVec, p2: UVec, p3: UVec) -> Bezier3P: + """Returns a quadratic Bèzier curve :class:`Bezier3P` from three points. + The curve starts at `p1`, goes through `p2` and ends at `p3`. + (source: `pomax-2`_) + + .. _pomax-2: https://pomax.github.io/bezierinfo/#pointcurves + + """ + + def u_func(t: float) -> float: + mt = 1.0 - t + mt2 = mt * mt + return mt2 / (t * t + mt2) + + def ratio(t: float) -> float: + t2 = t * t + mt = 1.0 - t + mt2 = mt * mt + return abs((t2 + mt2 - 1.0) / (t2 + mt2)) + + s = Vec3(p1) + b = Vec3(p2) + e = Vec3(p3) + d1 = (s - b).magnitude + d2 = (e - b).magnitude + t = d1 / (d1 + d2) + u = u_func(t) + c = s * u + e * (1.0 - u) + a = b + (b - c) / ratio(t) + return Bezier3P([s, a, e]) + + +def cubic_bezier_from_3p(p1: UVec, p2: UVec, p3: UVec) -> Bezier4P: + """Returns a cubic Bèzier curve :class:`Bezier4P` from three points. + The curve starts at `p1`, goes through `p2` and ends at `p3`. + (source: `pomax-2`_) + """ + qbez = quadratic_bezier_from_3p(p1, p2, p3) + return quadratic_to_cubic_bezier(qbez) + + +def cubic_bezier_bbox(curve: Bezier4P, *, abs_tol=1e-12) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` of a cubic Bézier curve + of type :class:`~ezdxf.math.Bezier4P`. + """ + cp = curve.control_points + points: list[Vec3] = [cp[0], cp[3]] + for p1, p2, p3, p4 in zip(*cp): + a = 3.0 * (-p1 + 3.0 * p2 - 3.0 * p3 + p4) + b = 6.0 * (p1 - 2.0 * p2 + p3) + c = 3.0 * (p2 - p1) + if abs(a) < abs_tol: + if abs(b) < abs_tol: + t = -c # or skip this case? + else: + t = -c / b + if 0.0 < t < 1.0: + points.append((curve.point(t))) + continue + + try: + sqrt_bb4ac = math.sqrt(b * b - 4.0 * a * c) + except ValueError: # domain error + continue + aa = 2.0 * a + t = (-b + sqrt_bb4ac) / aa + if 0.0 < t < 1.0: + points.append(curve.point(t)) + t = (-b - sqrt_bb4ac) / aa + if 0.0 < t < 1.0: + points.append(curve.point(t)) + return BoundingBox(points) + + +def quadratic_bezier_bbox(curve: Bezier3P, *, abs_tol=1e-12) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` of a quadratic Bézier curve + of type :class:`~ezdxf.math.Bezier3P`. + """ + return cubic_bezier_bbox(quadratic_to_cubic_bezier(curve), abs_tol=abs_tol) + + +def _bezier4poly(a: float, b: float, c: float, d: float): + a3 = a * 3.0 + b3 = b * 3.0 + c3 = c * 3.0 + return -a + b3 - c3 + d, a3 - b * 6.0 + c3, -a3 + b3, a + + +# noinspection PyPep8Naming +def intersection_params_ray_cubic_bezier( + p0: AnyVec, p1: AnyVec, cp: Sequence[AnyVec] +) -> list[float]: + """Returns the parameters of the intersection points between the ray defined + by two points `p0` and `p1` and the cubic Bézier curve defined by four + control points `cp`. + """ + A = p1.y - p0.y + B = p0.x - p1.x + C = p0.x * (p0.y - p1.y) + p0.y * (p1.x - p0.x) + + c0, c1, c2, c3 = cp + bx = _bezier4poly(c0.x, c1.x, c2.x, c3.x) + by = _bezier4poly(c0.y, c1.y, c2.y, c3.y) + return sorted( + v + for v in cubic_equation( + A * bx[0] + B * by[0], + A * bx[1] + B * by[1], + A * bx[2] + B * by[2], + A * bx[3] + B * by[3] + C, + ) + if 0.0 <= v <= 1.0 + ) + + +def intersection_ray_cubic_bezier_2d( + p0: UVec, + p1: UVec, + curve: Bezier4P, +) -> Sequence[Vec2]: + """Returns the intersection points between the `ray` defined by two points + `p0` and `p1` and the given cubic Bézier `curve`. Ignores the z-axis of 3D + curves. + + Returns 0-3 intersection points as :class:`Vec2` objects in the + order start- to end point of the curve. + + """ + return Vec2.tuple( + curve.point(t) + for t in intersection_params_ray_cubic_bezier( + Vec2(p0), Vec2(p1), curve.control_points + ) + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/ellipse.py b/.venv/lib/python3.12/site-packages/ezdxf/math/ellipse.py new file mode 100644 index 0000000..996c9e4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/ellipse.py @@ -0,0 +1,599 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Any +import numpy as np + +import math +from ezdxf.math import ( + Vec3, + UVec, + NULLVEC, + X_AXIS, + Z_AXIS, + OCS, + Matrix44, + arc_angle_span_rad, + distance_point_line_3d, + enclosing_angles, +) + +if TYPE_CHECKING: + from ezdxf.layouts import BaseLayout + from ezdxf.entities import Ellipse + +__all__ = [ + "ConstructionEllipse", + "angle_to_param", + "param_to_angle", + "rytz_axis_construction", +] +QUARTER_PARAMS = [0, math.pi * 0.5, math.pi, math.pi * 1.5] +HALF_PI = math.pi / 2.0 + + +class ConstructionEllipse: + """Construction tool for 3D ellipsis. + + Args: + center: 3D center point + major_axis: major axis as 3D vector + extrusion: normal vector of ellipse plane + ratio: ratio of minor axis to major axis + start_param: start param in radians + end_param: end param in radians + ccw: is counter-clockwise flag - swaps start- and end param if ``False`` + + """ + + def __init__( + self, + center: UVec = NULLVEC, + major_axis: UVec = X_AXIS, + extrusion: UVec = Z_AXIS, + ratio: float = 1, + start_param: float = 0, + end_param: float = math.tau, + ccw: bool = True, + ): + self.center = Vec3(center) + self.major_axis = Vec3(major_axis) + if self.major_axis.isclose(NULLVEC): + raise ValueError(f"Invalid major axis (null vector).") + self.extrusion = Vec3(extrusion) + if self.major_axis.isclose(NULLVEC): + raise ValueError(f"Invalid extrusion vector (null vector).") + self.ratio = float(ratio) + self.start_param = float(start_param) + self.end_param = float(end_param) + if not ccw: + self.start_param, self.end_param = self.end_param, self.start_param + self.minor_axis = minor_axis(self.major_axis, self.extrusion, self.ratio) + + @classmethod + def from_arc( + cls, + center: UVec = NULLVEC, + radius: float = 1, + extrusion: UVec = Z_AXIS, + start_angle: float = 0, + end_angle: float = 360, + ccw: bool = True, + ) -> ConstructionEllipse: + """Returns :class:`ConstructionEllipse` from arc or circle. + + Arc and Circle parameters defined in OCS. + + Args: + center: center in OCS + radius: arc or circle radius + extrusion: OCS extrusion vector + start_angle: start angle in degrees + end_angle: end angle in degrees + ccw: arc curve goes counter clockwise from start to end if ``True`` + """ + radius = abs(radius) + if NULLVEC.isclose(extrusion): + raise ValueError(f"Invalid extrusion: {str(extrusion)}") + ratio = 1.0 + ocs = OCS(extrusion) + center = ocs.to_wcs(center) + # Major axis along the OCS x-axis. + major_axis = ocs.to_wcs(Vec3(radius, 0, 0)) + # No further adjustment of start- and end angle required. + start_param = math.radians(start_angle) + end_param = math.radians(end_angle) + return cls( + center, + major_axis, + extrusion, + ratio, + start_param, + end_param, + bool(ccw), + ) + + def __copy__(self): + return self.__class__( + self.center, + self.major_axis, + self.extrusion, + self.ratio, + self.start_param, + self.end_param, + ) + + @property + def start_point(self) -> Vec3: + """Returns start point of ellipse as Vec3.""" + return vertex( + self.start_param, + self.major_axis, + self.minor_axis, + self.center, + self.ratio, + ) + + @property + def end_point(self) -> Vec3: + """Returns end point of ellipse as Vec3.""" + return vertex( + self.end_param, + self.major_axis, + self.minor_axis, + self.center, + self.ratio, + ) + + def dxfattribs(self) -> dict[str, Any]: + """Returns required DXF attributes to build an ELLIPSE entity. + + Entity ELLIPSE has always a ratio in range from 1e-6 to 1. + + """ + if self.ratio > 1: + e = self.__copy__() + e.swap_axis() + else: + e = self + return { + "center": e.center, + "major_axis": e.major_axis, + "extrusion": e.extrusion, + "ratio": max(e.ratio, 1e-6), + "start_param": e.start_param, + "end_param": e.end_param, + } + + def main_axis_points(self) -> Iterable[Vec3]: + """Yields main axis points of ellipse in the range from start- to end + param. + """ + start = self.start_param + end = self.end_param + for param in QUARTER_PARAMS: + if enclosing_angles(param, start, end): + yield vertex( + param, + self.major_axis, + self.minor_axis, + self.center, + self.ratio, + ) + + def transform(self, m: Matrix44) -> None: + """Transform ellipse in place by transformation matrix `m`.""" + new_center = m.transform(self.center) + # 2021-01-28 removed % math.tau + old_start_param = start_param = self.start_param + old_end_param = end_param = self.end_param + old_minor_axis = minor_axis(self.major_axis, self.extrusion, self.ratio) + new_major_axis, new_minor_axis = m.transform_directions( + (self.major_axis, old_minor_axis) + ) + # Original ellipse parameters stay untouched until end of transformation + dot_product = new_major_axis.normalize().dot(new_minor_axis.normalize()) + if abs(dot_product) > 1e-6: + new_major_axis, new_minor_axis, new_ratio = rytz_axis_construction( + new_major_axis, new_minor_axis + ) + new_extrusion = new_major_axis.cross(new_minor_axis).normalize() + adjust_params = True + else: + # New axis are nearly orthogonal: + new_ratio = new_minor_axis.magnitude / new_major_axis.magnitude + # New normal vector: + new_extrusion = new_major_axis.cross(new_minor_axis).normalize() + # Calculate exact minor axis: + new_minor_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) + adjust_params = False + + if adjust_params and not math.isclose(start_param, end_param, abs_tol=1e-9): + # open ellipse, adjusting start- and end parameter + x_axis = new_major_axis.normalize() + y_axis = new_minor_axis.normalize() + # TODO: use ellipse_param_span()? + # 2021-01-28 this is possibly the source of errors! + old_param_span = (end_param - start_param) % math.tau + + def param(vec: "Vec3") -> float: + dy = y_axis.dot(vec) / new_ratio # adjust to circle + dx = x_axis.dot(vec) + return math.atan2(dy, dx) % math.tau + + # transformed start- and end point of old ellipse + start_point = m.transform( + vertex( + start_param, + self.major_axis, + old_minor_axis, + self.center, + self.ratio, + ) + ) + end_point = m.transform( + vertex( + end_param, + self.major_axis, + old_minor_axis, + self.center, + self.ratio, + ) + ) + + start_param = param(start_point - new_center) + end_param = param(end_point - new_center) + + # Test if drawing the correct side of the curve + if not math.isclose(old_param_span, math.pi, abs_tol=1e-9): + # Equal param span check works well, except for a span of exact + # pi (180 deg). + # TODO: use ellipse_param_span()? + # 2021-01-28 this is possibly the source of errors! + new_param_span = (end_param - start_param) % math.tau + if not math.isclose(old_param_span, new_param_span, abs_tol=1e-9): + start_param, end_param = end_param, start_param + else: # param span is exact pi (180 deg) + # expensive but it seem to work: + old_chk_point = m.transform( + vertex( + mid_param(old_start_param, old_end_param), + self.major_axis, + old_minor_axis, + self.center, + self.ratio, + ) + ) + new_chk_point = vertex( + mid_param(start_param, end_param), + new_major_axis, + new_minor_axis, + new_center, + new_ratio, + ) + if not old_chk_point.isclose(new_chk_point, abs_tol=1e-9): + start_param, end_param = end_param, start_param + + if new_ratio > 1: + new_major_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) + new_ratio = 1.0 / new_ratio + new_minor_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) + if not (math.isclose(start_param, 0) and math.isclose(end_param, math.tau)): + start_param -= HALF_PI + end_param -= HALF_PI + + # TODO: remove normalize start- and end params? + # 2021-01-28 this is possibly the source of errors! + start_param = start_param % math.tau + end_param = end_param % math.tau + if math.isclose(start_param, end_param): + start_param = 0.0 + end_param = math.tau + + self.center = new_center + self.major_axis = new_major_axis + self.minor_axis = new_minor_axis + self.extrusion = new_extrusion + self.ratio = new_ratio + self.start_param = start_param + self.end_param = end_param + + @property + def param_span(self) -> float: + """Returns the counter-clockwise params span from start- to end param, + see also :func:`ezdxf.math.ellipse_param_span` for more information. + + """ + return arc_angle_span_rad(self.start_param, self.end_param) + + def params(self, num: int) -> Iterable[float]: + """Returns `num` params from start- to end param in counter-clockwise + order. + + All params are normalized in the range from [0, 2π). + + """ + yield from get_params(self.start_param, self.end_param, num) + + def vertices(self, params: Iterable[float]) -> Iterable[Vec3]: + """Yields vertices on ellipse for iterable `params` in WCS. + + Args: + params: param values in the range from [0, 2π) in radians, + param goes counter-clockwise around the extrusion vector, + major_axis = local x-axis = 0 rad. + + """ + center = self.center + ratio = self.ratio + x_axis = self.major_axis.normalize() + y_axis = self.minor_axis.normalize() + radius_x = self.major_axis.magnitude + radius_y = radius_x * ratio + + for param in params: + x = math.cos(param) * radius_x * x_axis + y = math.sin(param) * radius_y * y_axis + yield center + x + y + + def flattening(self, distance: float, segments: int = 4) -> Iterable[Vec3]: + """Adaptive recursive flattening. The argument `segments` is the + minimum count of approximation segments, if the distance from the center + of the approximation segment to the curve is bigger than `distance` the + segment will be subdivided. Returns a closed polygon for a full ellipse: + start vertex == end vertex. + + Args: + distance: maximum distance from the projected curve point onto the + segment chord. + segments: minimum segment count + + """ + + def vertex_(p: float) -> Vec3: + x = math.cos(p) * radius_x * x_axis + y = math.sin(p) * radius_y * y_axis + return self.center + x + y + + def subdiv(s: Vec3, e: Vec3, s_param: float, e_param: float): + m_param = (s_param + e_param) * 0.5 + m = vertex_(m_param) + d = distance_point_line_3d(m, s, e) + if d < distance: + yield e + else: + yield from subdiv(s, m, s_param, m_param) + yield from subdiv(m, e, m_param, e_param) + + x_axis = self.major_axis.normalize() + y_axis = self.minor_axis.normalize() + radius_x = self.major_axis.magnitude + radius_y = radius_x * self.ratio + + delta = self.param_span / segments + if delta == 0.0: + return + + param = self.start_param % math.tau + if math.isclose(self.end_param, math.tau): + end_param = math.tau + else: + end_param = self.end_param % math.tau + + if math.isclose(param, end_param): + return + elif param > end_param: + end_param += math.tau + + start_point = vertex_(param) + yield start_point + while param < end_param: + next_end_param = param + delta + if math.isclose(next_end_param, end_param): + next_end_param = end_param + end_point = vertex_(next_end_param) + yield from subdiv(start_point, end_point, param, next_end_param) + param = next_end_param + start_point = end_point + + def params_from_vertices(self, vertices: Iterable[UVec]) -> Iterable[float]: + """Yields ellipse params for all given `vertices`. + + The vertex don't have to be exact on the ellipse curve or in the range + from start- to end param or even in the ellipse plane. Param is + calculated from the intersection point of the ray projected on the + ellipse plane from the center of the ellipse through the vertex. + + .. warning:: + + An input for start- and end vertex at param 0 and 2π return + unpredictable results because of floating point inaccuracy, + sometimes 0 and sometimes 2π. + + """ + x_axis = self.major_axis.normalize() + y_axis = self.minor_axis.normalize() + ratio = self.ratio + center = self.center + for v in Vec3.generate(vertices): + v -= center + yield math.atan2(y_axis.dot(v) / ratio, x_axis.dot(v)) % math.tau + + def tangents(self, params: Iterable[float]) -> Iterable[Vec3]: + """Yields tangents on ellipse for iterable `params` in WCS as direction + vectors. + + Args: + params: param values in the range from [0, 2π] in radians, param + goes counter-clockwise around the extrusion vector, + major_axis = local x-axis = 0 rad. + + """ + ratio = self.ratio + x_axis = self.major_axis.normalize() + y_axis = self.minor_axis.normalize() + + for param in params: + x = -math.sin(param) * x_axis + y = math.cos(param) * ratio * y_axis + yield (x + y).normalize() + + def swap_axis(self) -> None: + """Swap axis and adjust start- and end parameter.""" + self.major_axis = self.minor_axis + ratio = 1.0 / self.ratio + self.ratio = max(ratio, 1e-6) + self.minor_axis = minor_axis(self.major_axis, self.extrusion, self.ratio) + + start_param = self.start_param + end_param = self.end_param + if math.isclose(start_param, 0) and math.isclose(end_param, math.tau): + return + self.start_param = (start_param - HALF_PI) % math.tau + self.end_param = (end_param - HALF_PI) % math.tau + + def add_to_layout(self, layout: BaseLayout, dxfattribs=None) -> Ellipse: + """Add ellipse as DXF :class:`~ezdxf.entities.Ellipse` entity to a + layout. + + Args: + layout: destination layout as :class:`~ezdxf.layouts.BaseLayout` + object + dxfattribs: additional DXF attributes for the ELLIPSE entity + + """ + from ezdxf.entities import Ellipse + + dxfattribs = dict(dxfattribs or {}) + dxfattribs.update(self.dxfattribs()) + e = Ellipse.new(dxfattribs=dxfattribs, doc=layout.doc) + layout.add_entity(e) + return e + + def to_ocs(self) -> ConstructionEllipse: + """Returns ellipse parameters as OCS representation. + + OCS elevation is stored in :attr:`center.z`. + + """ + ocs = OCS(self.extrusion) + return self.__class__( + center=ocs.from_wcs(self.center), + major_axis=ocs.from_wcs(self.major_axis).replace(z=0.0), + ratio=self.ratio, + start_param=self.start_param, + end_param=self.end_param, + ) + + +def mid_param(start: float, end: float) -> float: + if end < start: + end += math.tau + return (start + end) / 2.0 + + +def minor_axis(major_axis: Vec3, extrusion: Vec3, ratio: float) -> Vec3: + return extrusion.cross(major_axis).normalize(major_axis.magnitude * ratio) + + +def vertex( + param: float, major_axis: Vec3, minor_axis: Vec3, center: Vec3, ratio: float +) -> Vec3: + x_axis = major_axis.normalize() + y_axis = minor_axis.normalize() + radius_x = major_axis.magnitude + radius_y = radius_x * ratio + x = math.cos(param) * radius_x * x_axis + y = math.sin(param) * radius_y * y_axis + return center + x + y + + +def get_params(start: float, end: float, num: int) -> Iterable[float]: + """Returns `num` params from start- to end param in counter-clockwise order. + + All params are normalized in the range from [0, 2π). + + """ + if num < 2: + raise ValueError("num >= 2") + if end <= start: + end += math.tau + + for param in np.linspace(start, end, num): + yield param % math.tau + + +def angle_to_param(ratio: float, angle: float) -> float: + """Returns ellipse parameter for argument `angle`. + + Args: + ratio: minor axis to major axis ratio as stored in the ELLIPSE entity + (always <= 1). + angle: angle between major axis and line from center to point on the + ellipse + + Returns: + the ellipse parameter in the range [0, 2π) + """ + return math.atan2(math.sin(angle) / ratio, math.cos(angle)) % math.tau + + +def param_to_angle(ratio: float, param: float) -> float: + """Returns circle angle from ellipse parameter for argument `angle`. + + Args: + ratio: minor axis to major axis ratio as stored in the ELLIPSE entity + (always <= 1). + param: ellipse parameter between major axis and point on the ellipse + curve + + Returns: + the circle angle in the range [0, 2π) + """ + return math.atan2(math.sin(param) * ratio, math.cos(param)) + + +def rytz_axis_construction(d1: Vec3, d2: Vec3) -> tuple[Vec3, Vec3, float]: + """The Rytz’s axis construction is a basic method of descriptive Geometry + to find the axes, the semi-major axis and semi-minor axis, starting from two + conjugated half-diameters. + + Source: `Wikipedia `_ + + Given conjugated diameter `d1` is the vector from center C to point P and + the given conjugated diameter `d2` is the vector from center C to point Q. + Center of ellipse is always ``(0, 0, 0)``. This algorithm works for + 2D/3D vectors. + + Args: + d1: conjugated semi-major axis as :class:`Vec3` + d2: conjugated semi-minor axis as :class:`Vec3` + + Returns: + Tuple of (major axis, minor axis, ratio) + + """ + Q = Vec3(d1) # vector CQ + # calculate vector CP', location P' + if math.isclose(d1.z, 0, abs_tol=1e-9) and math.isclose(d2.z, 0, abs_tol=1e-9): + # Vec3.orthogonal() works only for vectors in the xy-plane! + P1 = Vec3(d2).orthogonal(ccw=False) + else: + extrusion = d1.cross(d2) + P1 = extrusion.cross(d2).normalize(d2.magnitude) + + D = P1.lerp(Q) # vector CD, location D, midpoint of P'Q + radius = D.magnitude + radius_vector = (Q - P1).normalize(radius) # direction vector P'Q + A = D - radius_vector # vector CA, location A + B = D + radius_vector # vector CB, location B + if A.isclose(NULLVEC) or B.isclose(NULLVEC): + raise ArithmeticError("Conjugated axis required, invalid source data.") + major_axis_length = (A - Q).magnitude + minor_axis_length = (B - Q).magnitude + if math.isclose(major_axis_length, 0.0) or math.isclose(minor_axis_length, 0.0): + raise ArithmeticError("Conjugated axis required, invalid source data.") + ratio = minor_axis_length / major_axis_length + major_axis = B.normalize(major_axis_length) + minor_axis = A.normalize(minor_axis_length) + return major_axis, minor_axis, ratio diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/eulerspiral.py b/.venv/lib/python3.12/site-packages/ezdxf/math/eulerspiral.py new file mode 100644 index 0000000..acc4671 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/eulerspiral.py @@ -0,0 +1,136 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable +from ezdxf.math import Vec3 +from ezdxf.math.bspline import global_bspline_interpolation, BSpline + +__all__ = ["EulerSpiral"] + + +def powers(base: float, count: int) -> list[float]: + assert count > 2, "requires count > 2" + values = [1.0, base] + next_value = base + for _ in range(count - 2): + next_value *= base + values.append(next_value) + return values + + +def _params(length: float, segments: int) -> Iterable[float]: + delta_l = float(length) / float(segments) + for index in range(0, segments + 1): + yield delta_l * index + + +class EulerSpiral: + """ + This class represents an euler spiral (clothoid) for `curvature` (Radius of + curvature). + + This is a parametric curve, which always starts at the origin = ``(0, 0)``. + + Args: + curvature: radius of curvature + + """ + + def __init__(self, curvature: float = 1.0): + curvature = float(curvature) + self.curvature = curvature # Radius of curvature + self.curvature_powers: list[float] = powers(curvature, 19) + self._cache: dict[float, Vec3] = {} # coordinates cache + + def radius(self, t: float) -> float: + """Get radius of circle at distance `t`.""" + if t > 0.0: + return self.curvature_powers[2] / t + else: + return 0.0 # radius = infinite + + def tangent(self, t: float) -> Vec3: + """Get tangent at distance `t` as :class:`Vec3` object.""" + angle = t ** 2 / (2.0 * self.curvature_powers[2]) + return Vec3.from_angle(angle) + + def distance(self, radius: float) -> float: + """Get distance L from origin for `radius`.""" + return self.curvature_powers[2] / float(radius) + + def point(self, t: float) -> Vec3: + """Get point at distance `t` as :class:`Vec3`.""" + + def term(length_power, curvature_power, const): + return t ** length_power / ( + const * self.curvature_powers[curvature_power] + ) + + if t not in self._cache: + y = ( + term(3, 2, 6.0) + - term(7, 6, 336.0) + + term(11, 10, 42240.0) + - term(15, 14, 9676800.0) + + term(19, 18, 3530096640.0) + ) + x = ( + t + - term(5, 4, 40.0) + + term(9, 8, 3456.0) + - term(13, 12, 599040.0) + + term(17, 16, 175472640.0) + ) + self._cache[t] = Vec3(x, y) + return self._cache[t] + + def approximate(self, length: float, segments: int) -> Iterable[Vec3]: + """Approximate curve of length with line segments. + Generates segments+1 vertices as :class:`Vec3` objects. + + """ + for t in _params(length, segments): + yield self.point(t) + + def circle_center(self, t: float) -> Vec3: + """Get circle center at distance `t`.""" + p = self.point(t) + r = self.radius(t) + return p + self.tangent(t).normalize(r).orthogonal() + + def bspline( + self, + length: float, + segments: int = 10, + degree: int = 3, + method: str = "uniform", + ) -> BSpline: + """Approximate euler spiral as B-spline. + + Args: + length: length of euler spiral + segments: count of fit points for B-spline calculation + degree: degree of BSpline + method: calculation method for parameter vector t + + Returns: + :class:`BSpline` + + """ + length = float(length) + fit_points = list(self.approximate(length, segments=segments)) + derivatives = [ + # Scaling derivatives by chord length (< real length) is suggested + # by Piegl & Tiller. + self.tangent(t).normalize(length) + for t in _params(length, segments) + ] + spline = global_bspline_interpolation( + fit_points, degree, method=method, tangents=derivatives + ) + return BSpline( + spline.control_points, + spline.order, + # Scale knot values to length: + [v * length for v in spline.knots()], + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/legacy.py b/.venv/lib/python3.12/site-packages/ezdxf/math/legacy.py new file mode 100644 index 0000000..61b23e3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/legacy.py @@ -0,0 +1,417 @@ +# Copyright (c) 2018-2024, Manfred Moitzi +# License: MIT License +# legacy.py code is replaced by numpy - exists just for benchmarking, testing and nostalgia +from __future__ import annotations +from typing import Iterable, cast +from itertools import repeat +import reprlib + +from .linalg import Matrix, MatrixData, NDArray, Solver + +__all__ = [ + "gauss_vector_solver", + "gauss_matrix_solver", + "gauss_jordan_solver", + "gauss_jordan_inverse", + "LUDecomposition", +] + + +def copy_float_matrix(A) -> MatrixData: + if isinstance(A, Matrix): + A = A.matrix + return [[float(v) for v in row] for row in A] + + +def gauss_vector_solver(A: MatrixData | NDArray, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by a nxn Matrix A . x = B, + right-hand side quantities as vector B with n elements by the + `Gauss-Elimination`_ algorithm, which is faster than the `Gauss-Jordan`_ + algorithm. The speed improvement is more significant for solving multiple + right-hand side quantities as matrix at once. + + Reference implementation for error checking. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], [a21, a22, ..., a2n], + ... [an1, an2, ..., ann]] + B: vector [b1, b2, ..., bn] + + Returns: + vector as list of floats + + Raises: + ZeroDivisionError: singular matrix + + """ + # copy input data + A = copy_float_matrix(A) + B = list(B) + num = len(A) + if len(A[0]) != num: + raise ValueError("A square nxn matrix A is required.") + if len(B) != num: + raise ValueError( + "Item count of vector B has to be equal to matrix A row count." + ) + + # inplace modification of A & B + _build_upper_triangle(A, B) + return _backsubstitution(A, B) + + +def gauss_matrix_solver(A: MatrixData | NDArray, B: MatrixData | NDArray) -> Matrix: + """Solves the linear equation system given by a nxn Matrix A . x = B, + right-hand side quantities as nxm Matrix B by the `Gauss-Elimination`_ + algorithm, which is faster than the `Gauss-Jordan`_ algorithm. + + Reference implementation for error checking. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], [a21, a22, ..., a2n], + ... [an1, an2, ..., ann]] + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], ... [bn1, bn2, ..., bnm]] + + Returns: + matrix as :class:`Matrix` object + + Raises: + ZeroDivisionError: singular matrix + + """ + # copy input data + matrix_a = copy_float_matrix(A) + matrix_b = copy_float_matrix(B) + num = len(matrix_a) + if len(matrix_a[0]) != num: + raise ValueError("A square nxn matrix A is required.") + if len(matrix_b) != num: + raise ValueError("Row count of matrices A and B has to match.") + + # inplace modification of A & B + _build_upper_triangle(matrix_a, matrix_b) + + columns = Matrix(matrix=matrix_b).cols() + result = Matrix() + for col in columns: + result.append_col(_backsubstitution(matrix_a, col)) + + return result + + +def _build_upper_triangle(A: MatrixData, B: list) -> None: + """Build upper triangle for backsubstitution. Modifies A and B inplace! + + Args: + A: row major matrix + B: vector of floats or row major matrix + + """ + num = len(A) + try: + b_col_count = len(B[0]) + except TypeError: + b_col_count = 1 + + for i in range(0, num): + # Search for maximum in this column + max_element = abs(A[i][i]) + max_row = i + for row in range(i + 1, num): + value = abs(A[row][i]) + if value > max_element: + max_element = value + max_row = row + + # Swap maximum row with current row + A[max_row], A[i] = A[i], A[max_row] + B[max_row], B[i] = B[i], B[max_row] + + # Make all rows below this one 0 in current column + for row in range(i + 1, num): + c = -A[row][i] / A[i][i] + for col in range(i, num): + if i == col: + A[row][col] = 0 + else: + A[row][col] += c * A[i][col] + if b_col_count == 1: + B[row] += c * B[i] + else: + for col in range(b_col_count): + B[row][col] += c * B[i][col] + + +def _backsubstitution(A: MatrixData, B: list[float]) -> list[float]: + """Solve equation A . x = B for an upper triangular matrix A by + backsubstitution. + + Args: + A: row major matrix + B: vector of floats + + """ + num = len(A) + x = [0.0] * num + for i in range(num - 1, -1, -1): + x[i] = B[i] / A[i][i] + for row in range(i - 1, -1, -1): + B[row] -= A[row][i] * x[i] + return x + + +def gauss_jordan_solver( + A: MatrixData | NDArray, B: MatrixData | NDArray +) -> tuple[Matrix, Matrix]: + """Solves the linear equation system given by a nxn Matrix A . x = B, + right-hand side quantities as nxm Matrix B by the `Gauss-Jordan`_ algorithm, + which is the slowest of all, but it is very reliable. Returns a copy of the + modified input matrix `A` and the result matrix `x`. + + Internally used for matrix inverse calculation. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], [a21, a22, ..., a2n], + ... [an1, an2, ..., ann]] + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], ... [bn1, bn2, ..., bnm]] + + Returns: + 2-tuple of :class:`Matrix` objects + + Raises: + ZeroDivisionError: singular matrix + + """ + # copy input data + matrix_a = copy_float_matrix(A) + matrix_b = copy_float_matrix(B) + + n = len(matrix_a) + m = len(matrix_b[0]) + + if len(matrix_a[0]) != n: + raise ValueError("A square nxn matrix A is required.") + if len(matrix_b) != n: + raise ValueError("Row count of matrices A and B has to match.") + + icol = 0 + irow = 0 + col_indices = [0] * n + row_indices = [0] * n + ipiv = [0] * n + + for i in range(n): + big = 0.0 + for j in range(n): + if ipiv[j] != 1: + for k in range(n): + if ipiv[k] == 0: + if abs(matrix_a[j][k]) >= big: + big = abs(matrix_a[j][k]) + irow = j + icol = k + + ipiv[icol] += 1 + if irow != icol: + matrix_a[irow], matrix_a[icol] = matrix_a[icol], matrix_a[irow] + matrix_b[irow], matrix_b[icol] = matrix_b[icol], matrix_b[irow] + + row_indices[i] = irow + col_indices[i] = icol + + pivinv = 1.0 / matrix_a[icol][icol] + matrix_a[icol][icol] = 1.0 + matrix_a[icol] = [v * pivinv for v in matrix_a[icol]] + matrix_b[icol] = [v * pivinv for v in matrix_b[icol]] + for row in range(n): + if row == icol: + continue + dum = matrix_a[row][icol] + matrix_a[row][icol] = 0.0 + for col in range(n): + matrix_a[row][col] -= matrix_a[icol][col] * dum + for col in range(m): + matrix_b[row][col] -= matrix_b[icol][col] * dum + + for i in range(n - 1, -1, -1): + irow = row_indices[i] + icol = col_indices[i] + if irow != icol: + for _row in matrix_a: + _row[irow], _row[icol] = _row[icol], _row[irow] + return Matrix(matrix=matrix_a), Matrix(matrix=matrix_b) + + +def gauss_jordan_inverse(A: MatrixData) -> Matrix: + """Returns the inverse of matrix `A` as :class:`Matrix` object. + + .. hint:: + + For small matrices (n<10) is this function faster than + LUDecomposition(m).inverse() and as fast even if the decomposition is + already done. + + Raises: + ZeroDivisionError: singular matrix + + """ + if isinstance(A, Matrix): + matrix_a = A.matrix + else: + matrix_a = list(A) + nrows = len(matrix_a) + return gauss_jordan_solver(matrix_a, list(repeat([0.0], nrows)))[0] + + +class LUDecomposition(Solver): + """Represents a `LU decomposition`_ matrix of A, raise :class:`ZeroDivisionError` + for a singular matrix. + + This algorithm is a little bit faster than the `Gauss-Elimination`_ + algorithm using CPython and much faster when using pypy. + + The :attr:`LUDecomposition.matrix` attribute gives access to the matrix data + as list of rows like in the :class:`Matrix` class, and the :attr:`LUDecomposition.index` + attribute gives access to the swapped row indices. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], [a21, a22, ..., a2n], + ... [an1, an2, ..., ann]] + + raises: + ZeroDivisionError: singular matrix + + """ + + __slots__ = ("matrix", "index", "_det") + + def __init__(self, A: MatrixData | NDArray): + lu: MatrixData = copy_float_matrix(A) + n: int = len(lu) + det: float = 1.0 + index: list[int] = [] + + # find max value for each row, raises ZeroDivisionError for singular matrix! + scaling: list[float] = [1.0 / max(abs(v) for v in row) for row in lu] + + for k in range(n): + big: float = 0.0 + imax: int = k + for i in range(k, n): + temp: float = scaling[i] * abs(lu[i][k]) + if temp > big: + big = temp + imax = i + + if k != imax: + for col in range(n): + temp = lu[imax][col] + lu[imax][col] = lu[k][col] + lu[k][col] = temp + + det = -det + scaling[imax] = scaling[k] + + index.append(imax) + for i in range(k + 1, n): + temp = lu[i][k] / lu[k][k] + lu[i][k] = temp + for j in range(k + 1, n): + lu[i][j] -= temp * lu[k][j] + + self.index: list[int] = index + self.matrix: MatrixData = lu + self._det: float = det + + def __str__(self) -> str: + return str(self.matrix) + + def __repr__(self) -> str: + return f"{self.__class__} {reprlib.repr(self.matrix)}" + + @property + def nrows(self) -> int: + """Count of matrix rows (and cols).""" + return len(self.matrix) + + def solve_vector(self, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by the nxn Matrix A . x = B, + right-hand side quantities as vector B with n elements. + + Args: + B: vector [b1, b2, ..., bn] + + Returns: + vector as list of floats + + """ + X: list[float] = [float(v) for v in B] + lu: MatrixData = self.matrix + index: list[int] = self.index + n: int = self.nrows + ii: int = 0 + + if len(X) != n: + raise ValueError( + "Item count of vector B has to be equal to matrix row count." + ) + + for i in range(n): + ip: int = index[i] + sum_: float = X[ip] + X[ip] = X[i] + if ii != 0: + for j in range(ii - 1, i): + sum_ -= lu[i][j] * X[j] + elif sum_ != 0.0: + ii = i + 1 + X[i] = sum_ + + for row in range(n - 1, -1, -1): + sum_ = X[row] + for col in range(row + 1, n): + sum_ -= lu[row][col] * X[col] + X[row] = sum_ / lu[row][row] + return X + + def solve_matrix(self, B: MatrixData | NDArray) -> Matrix: + """Solves the linear equation system given by the nxn Matrix A . x = B, + right-hand side quantities as nxm Matrix B. + + Args: + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], + ... [bn1, bn2, ..., bnm]] + + Returns: + matrix as :class:`Matrix` object + + """ + if not isinstance(B, Matrix): + matrix_b = Matrix(matrix=[list(row) for row in B]) + else: + matrix_b = cast(Matrix, B) + + if matrix_b.nrows != self.nrows: + raise ValueError("Row count of self and matrix B has to match.") + + return Matrix( + matrix=[self.solve_vector(col) for col in matrix_b.cols()] + ).transpose() + + def inverse(self) -> Matrix: + """Returns the inverse of matrix as :class:`Matrix` object, + raise :class:`ZeroDivisionError` for a singular matrix. + + """ + return self.solve_matrix(Matrix.identity(shape=(self.nrows, self.nrows)).matrix) + + def determinant(self) -> float: + """Returns the determinant of matrix, raises :class:`ZeroDivisionError` + if matrix is singular. + + """ + det: float = self._det + lu: MatrixData = self.matrix + for i in range(self.nrows): + det *= lu[i][i] + return det diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/linalg.py b/.venv/lib/python3.12/site-packages/ezdxf/math/linalg.py new file mode 100644 index 0000000..4a3d00d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/linalg.py @@ -0,0 +1,854 @@ +# Copyright (c) 2018-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Tuple, + List, + Sequence, + Any, + cast, + Optional, +) +from typing_extensions import TypeAlias +import abc + +from functools import lru_cache +from itertools import repeat +import math +import reprlib + +import numpy as np +import numpy.typing as npt +from ezdxf.acc import USE_C_EXT + + +__all__ = [ + "Matrix", + "Solver", + "numpy_vector_solver", + "numpy_matrix_solver", + "NumpySolver", + "tridiagonal_vector_solver", + "tridiagonal_matrix_solver", + "detect_banded_matrix", + "compact_banded_matrix", + "BandedMatrixLU", + "banded_matrix", + "quadratic_equation", + "cubic_equation", + "binomial_coefficient", +] + + +def zip_to_list(*args) -> Iterable[list]: + for e in zip(*args): # returns immutable tuples + yield list(e) # need mutable list + + +MatrixData: TypeAlias = List[List[float]] +FrozenMatrixData: TypeAlias = Tuple[Tuple[float, ...]] +Shape: TypeAlias = Tuple[int, int] +NDArray: TypeAlias = npt.NDArray[np.float64] + + +def copy_float_matrix(A) -> MatrixData: + if isinstance(A, Matrix): + A = A.matrix + return [[float(v) for v in row] for row in A] + + +@lru_cache(maxsize=128) +def binomial_coefficient(k: int, i: int) -> float: + # (c) Onur Rauf Bingol , NURBS-Python, MIT-License + """Computes the binomial coefficient (denoted by `k choose i`). + + Please see the following website for details: + http://mathworld.wolfram.com/BinomialCoefficient.html + + Args: + k: size of the set of distinct elements + i: size of the subsets + + """ + # Special case + if i > k: + return float(0) + # Compute binomial coefficient + k_fact: int = math.factorial(k) + i_fact: int = math.factorial(i) + k_i_fact: int = math.factorial(k - i) + return float(k_fact / (k_i_fact * i_fact)) + + +class Matrix: + """Basic matrix implementation based :class:`numpy.ndarray`. Matrix data is stored in + row major order, this means in a list of rows, where each row is a list of floats. + + Initialization: + + - Matrix(shape=(rows, cols)) ... new matrix filled with zeros + - Matrix(matrix[, shape=(rows, cols)]) ... from copy of matrix and optional reshape + - Matrix([[row_0], [row_1], ..., [row_n]]) ... from Iterable[Iterable[float]] + - Matrix([a1, a2, ..., an], shape=(rows, cols)) ... from Iterable[float] and shape + + .. versionchanged:: 1.2 + Implementation based on :class:`numpy.ndarray`. + + Attributes: + matrix: matrix data as :class:`numpy.ndarray` + + """ + + __slots__ = ("matrix", "abs_tol") + + def __init__( + self, + items: Any = None, + shape: Optional[Shape] = None, + matrix: Optional[MatrixData | NDArray] = None, + ): + self.abs_tol: float = 1e-12 + self.matrix: NDArray = np.array((), dtype=np.float64) + if matrix is not None: + self.matrix = np.array(matrix, dtype=np.float64) + return + + if items is None: + if shape is not None: + self.matrix = np.zeros(shape) + else: # items is None, shape is None + return + elif isinstance(items, Matrix): + if shape is None: + shape = items.shape + self.matrix = items.matrix.reshape(shape).copy() + else: + items = list(items) + try: + self.matrix = np.array([list(row) for row in items], dtype=np.float64) + except TypeError: + if shape is not None: + self.matrix = np.array(list(items), dtype=np.float64).reshape(shape) + + def __iter__(self) -> NDArray: + return np.ravel(self.matrix) + + def __copy__(self) -> "Matrix": + m = Matrix(matrix=self.matrix.copy()) + m.abs_tol = self.abs_tol + return m + + def __str__(self) -> str: + return str(self.matrix) + + def __repr__(self) -> str: + return f"Matrix({reprlib.repr(self.matrix)})" + + @staticmethod + def reshape(items: Iterable[float], shape: Shape) -> Matrix: + """Returns a new matrix for iterable `items` in the configuration of + `shape`. + """ + return Matrix(matrix=np.array(list(items), dtype=np.float64).reshape(shape)) + + @property + def nrows(self) -> int: + """Count of matrix rows.""" + return self.matrix.shape[0] + + @property + def ncols(self) -> int: + """Count of matrix columns.""" + return self.matrix.shape[1] + + @property + def shape(self) -> Shape: + """Shape of matrix as (n, m) tuple for n rows and m columns.""" + return self.matrix.shape # type: ignore + + def row(self, index: int) -> list[float]: + """Returns row `index` as list of floats.""" + return list(self.matrix[index]) + + def col(self, index: int) -> list[float]: + """Return column `index` as list of floats.""" + return list(self.matrix[:, index]) + + def diag(self, index: int) -> list[float]: + """Returns diagonal `index` as list of floats. + + An `index` of 0 specifies the main diagonal, negative values + specifies diagonals below the main diagonal and positive values + specifies diagonals above the main diagonal. + + e.g. given a 4x4 matrix: + + - index 0 is [00, 11, 22, 33], + - index -1 is [10, 21, 32] and + - index +1 is [01, 12, 23] + + """ + return list(self.matrix.diagonal(index)) + + def rows(self) -> list[list[float]]: + """Return a list of all rows.""" + return list(list(r) for r in self.matrix) + + def cols(self) -> list[list[float]]: + """Return a list of all columns.""" + return [list(self.col(i)) for i in range(self.ncols)] + + def set_row(self, index: int, items: float | Iterable[float] = 1.0) -> None: + """Set row values to a fixed value or from an iterable of floats.""" + if isinstance(items, (float, int)): + items = [float(items)] * self.ncols + items = list(items) + if len(items) != self.ncols: + raise ValueError("Invalid item count") + self.matrix[index] = items + + def set_col(self, index: int, items: float | Iterable[float] = 1.0) -> None: + """Set column values to a fixed value or from an iterable of floats.""" + if isinstance(items, (float, int)): + items = [float(items)] * self.nrows + self.matrix[:, index] = list(items) + + def set_diag(self, index: int = 0, items: float | Iterable[float] = 1.0) -> None: + """Set diagonal values to a fixed value or from an iterable of floats. + + An `index` of ``0`` specifies the main diagonal, negative values + specifies diagonals below the main diagonal and positive values + specifies diagonals above the main diagonal. + + e.g. given a 4x4 matrix: + index ``0`` is [00, 11, 22, 33], + index ``-1`` is [10, 21, 32] and + index ``+1`` is [01, 12, 23] + + """ + if isinstance(items, (float, int)): + items = repeat(float(items)) + + col_offset: int = max(index, 0) + row_offset: int = abs(min(index, 0)) + + for index, value in zip(range(max(self.nrows, self.ncols)), items): + try: + self.matrix[index + row_offset, index + col_offset] = value + except IndexError: + return + + @classmethod + def identity(cls, shape: Shape) -> Matrix: + """Returns the identity matrix for configuration `shape`.""" + m = Matrix(shape=shape) + m.set_diag(0, 1.0) + return m + + def append_row(self, items: Sequence[float]) -> None: + """Append a row to the matrix.""" + if self.matrix.size == 0: + self.matrix = np.array([items], dtype=np.float64) + elif len(items) == self.ncols: + self.matrix = np.r_[self.matrix, items] + else: + raise ValueError("Invalid item count.") + + def append_col(self, items: Sequence[float]) -> None: + """Append a column to the matrix.""" + if self.matrix.size == 0: + self.matrix = np.array([[item] for item in items], dtype=np.float64) + elif len(items) == self.nrows: + self.matrix = np.c_[self.matrix, items] + else: + raise ValueError("Invalid item count.") + + def freeze(self) -> Matrix: + """Returns a frozen matrix, all data is stored in immutable tuples.""" + m = self.__copy__() + m.matrix.flags.writeable = False + return m + + def __getitem__(self, item: tuple[int, int]) -> float: + """Get value by (row, col) index tuple, fancy slicing as known from + numpy is not supported. + + """ + return float(self.matrix[item]) + + def __setitem__(self, item: tuple[int, int], value: float): + """Set value by (row, col) index tuple, fancy slicing as known from + numpy is not supported. + + """ + self.matrix[item] = value + + def __eq__(self, other: object) -> bool: + """Returns ``True`` if matrices are equal.""" + if not isinstance(other, Matrix): + raise TypeError("Matrix class required.") + if self.shape != other.shape: + raise TypeError("Matrices have different shapes.") + return bool(np.all(self.matrix == other.matrix)) + + def isclose(self, other: object) -> bool: + """Returns ``True`` if matrices are close to equal, tolerance value for + comparison is adjustable by the attribute :attr:`Matrix.abs_tol`. + + """ + if not isinstance(other, Matrix): + raise TypeError("Matrix class required.") + if self.shape != other.shape: + raise TypeError("Matrices have different shapes.") + return bool(np.all(np.isclose(self.matrix, other.matrix, atol=self.abs_tol))) + + def __mul__(self, other: Matrix | float) -> Matrix: + """Matrix multiplication by another matrix or a float, returns a new + matrix. + + """ + if isinstance(other, Matrix): + return Matrix(matrix=np.matmul(self.matrix, other.matrix)) + else: + matrix = Matrix(matrix=self.matrix * float(other)) + return matrix + + __imul__ = __mul__ + + def __add__(self, other: Matrix | float) -> Matrix: + """Matrix addition by another matrix or a float, returns a new matrix.""" + if isinstance(other, Matrix): + return Matrix(matrix=self.matrix + other.matrix) + else: + return Matrix(matrix=self.matrix + float(other)) + + __iadd__ = __add__ + + def __sub__(self, other: Matrix | float) -> Matrix: + """Matrix subtraction by another matrix or a float, returns a new + matrix. + + """ + if isinstance(other, Matrix): + return Matrix(matrix=self.matrix - other.matrix) + else: + return Matrix(matrix=self.matrix - float(other)) + + __isub__ = __sub__ + + def transpose(self) -> Matrix: + """Returns a new transposed matrix.""" + return Matrix(matrix=self.matrix.T) + + def inverse(self) -> Matrix: + """Returns inverse of matrix as new object.""" + if self.nrows != self.ncols: + raise TypeError("Inverse of non-square matrix not supported.") + try: + return Matrix(matrix=np.linalg.inv(self.matrix)) + except np.linalg.LinAlgError: + raise ZeroDivisionError + + def determinant(self) -> float: + """Returns determinant of matrix, raises :class:`ZeroDivisionError` + if matrix is singular. + + """ + return float(np.linalg.det(self.matrix)) + + +class Solver(abc.ABC): + @abc.abstractmethod + def solve_matrix(self, B: MatrixData | NDArray) -> Matrix: + ... + + @abc.abstractmethod + def solve_vector(self, B: Iterable[float]) -> list[float]: + ... + + +def quadratic_equation(a: float, b: float, c: float, abs_tol=1e-12) -> Sequence[float]: + """Returns the solution for the quadratic equation ``a*x^2 + b*x + c = 0``. + + Returns 0-2 solutions as a tuple of floats. + """ + if abs(a) < abs_tol: + if abs(b) < abs_tol: + return (-c,) + return (-c / b,) + try: + discriminant = math.sqrt(b**2 - 4 * a * c) + except ValueError: # domain error, sqrt of a negative number + return tuple() + return ((-b + discriminant) / (2.0 * a)), ((-b - discriminant) / (2.0 * a)) + + +# noinspection PyPep8Naming +def cubic_equation(a: float, b: float, c: float, d: float) -> Sequence[float]: + """Returns the solution for the cubic equation ``a*x^3 + b*x^2 + c*x + d = 0``. + + Returns 0-3 solutions as a tuple of floats. + """ + if abs(a) < 1e-12: + try: + return quadratic_equation(b, c, d) + except ArithmeticError: # complex solution + return tuple() + A = b / a + B = c / a + C = d / a + AA = A * A + A3 = A / 3.0 + + Q = (3.0 * B - AA) / 9.0 + R = (9.0 * A * B - 27.0 * C - 2.0 * (AA * A)) / 54.0 + QQQ = Q * Q * Q + D = QQQ + (R * R) # polynomial discriminant + + if D >= 0.0: # complex or duplicate roots + sqrtD = math.sqrt(D) + exp = 1.0 / 3.0 + S = math.copysign(1.0, R + sqrtD) * math.pow(abs(R + sqrtD), exp) + T = math.copysign(1.0, R - sqrtD) * math.pow(abs(R - sqrtD), exp) + ST = S + T + if S - T: # is complex + return (-A3 + ST,) # real root + else: + ST_2 = ST / 2.0 + return ( + -A3 + ST, # real root + -A3 - ST_2, # real part of complex root + -A3 - ST_2, # real part of complex root + ) + + th = math.acos(R / math.sqrt(-QQQ)) + sqrtQ2 = math.sqrt(-Q) * 2.0 + return ( + sqrtQ2 * math.cos(th / 3.0) - A3, + sqrtQ2 * math.cos((th + 2.0 * math.pi) / 3.0) - A3, + sqrtQ2 * math.cos((th + 4.0 * math.pi) / 3.0) - A3, + ) + + +def numpy_matrix_solver(A: MatrixData | NDArray, B: MatrixData | NDArray) -> Matrix: + """Solves the linear equation system given by a nxn Matrix A . x = B by the + numpy.linalg.solve() function. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], ... [an1, an2, ..., ann]] + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], ... [bn1, bn2, ..., bnm]] + + Raises: + numpy.linalg.LinAlgError: singular matrix + + """ + mat_A = np.array(A, dtype=np.float64) + mat_B = np.array(B, dtype=np.float64) + return Matrix(matrix=np.linalg.solve(mat_A, mat_B)) + + +def numpy_vector_solver(A: MatrixData | NDArray, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by a nxn Matrix A . x = B, + right-hand side quantities as vector B with n elements by the numpy.linalg.solve() + function. + + Args: + A: matrix [[a11, a12, ..., a1n], [a21, a22, ..., a2n], ... [an1, an2, ..., ann]] + B: vector [b1, b2, ..., bn] + + Raises: + numpy.linalg.LinAlgError: singular matrix + + """ + mat_A = np.array(A, dtype=np.float64) + mat_B = np.array([[float(v)] for v in B], dtype=np.float64) + return list(np.ravel(np.linalg.solve(mat_A, mat_B))) + + +class NumpySolver(Solver): + """Replaces in v1.2 the :class:`LUDecomposition` solver.""" + + def __init__(self, A: MatrixData | NDArray) -> None: + self.mat_A = np.array(A, dtype=np.float64) + + def solve_matrix(self, B: MatrixData | NDArray) -> Matrix: + """ + Solves the linear equation system given by the nxn Matrix + A . x = B, right-hand side quantities as nxm Matrix B. + + Args: + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], + ... [bn1, bn2, ..., bnm]] + + Raises: + numpy.linalg.LinAlgError: singular matrix + + """ + mat_B = np.array(B, dtype=np.float64) + return Matrix(matrix=np.linalg.solve(self.mat_A, mat_B)) + + def solve_vector(self, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by the nxn Matrix + A . x = B, right-hand side quantities as vector B with n elements. + + Args: + B: vector [b1, b2, ..., bn] + + Raises: + numpy.linalg.LinAlgError: singular matrix + + """ + mat_B = np.array([[float(v)] for v in B], dtype=np.float64) + return list(np.ravel(np.linalg.solve(self.mat_A, mat_B))) + + +def tridiagonal_vector_solver(A: MatrixData, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by a tri-diagonal nxn Matrix + A . x = B, right-hand side quantities as vector B. Matrix A is diagonal + matrix defined by 3 diagonals [-1 (a), 0 (b), +1 (c)]. + + Note: a0 is not used but has to be present, cn-1 is also not used and must + not be present. + + If an :class:`ZeroDivisionError` exception occurs, the equation system can + possibly be solved by :code:`BandedMatrixLU(A, 1, 1).solve_vector(B)` + + Args: + A: diagonal matrix [[a0..an-1], [b0..bn-1], [c0..cn-1]] :: + + [[b0, c0, 0, 0, ...], + [a1, b1, c1, 0, ...], + [0, a2, b2, c2, ...], + ... ] + + B: iterable of floats [[b1, b1, ..., bn] + + Returns: + list of floats + + Raises: + ZeroDivisionError: singular matrix + + """ + a, b, c = [list(v) for v in A] + return _solve_tridiagonal_matrix(a, b, c, list(B)) + + +def tridiagonal_matrix_solver( + A: MatrixData | NDArray, B: MatrixData | NDArray +) -> Matrix: + """Solves the linear equation system given by a tri-diagonal nxn Matrix + A . x = B, right-hand side quantities as nxm Matrix B. Matrix A is diagonal + matrix defined by 3 diagonals [-1 (a), 0 (b), +1 (c)]. + + Note: a0 is not used but has to be present, cn-1 is also not used and must + not be present. + + If an :class:`ZeroDivisionError` exception occurs, the equation system + can possibly be solved by :code:`BandedMatrixLU(A, 1, 1).solve_vector(B)` + + Args: + A: diagonal matrix [[a0..an-1], [b0..bn-1], [c0..cn-1]] :: + + [[b0, c0, 0, 0, ...], + [a1, b1, c1, 0, ...], + [0, a2, b2, c2, ...], + ... ] + + B: matrix [[b11, b12, ..., b1m], + [b21, b22, ..., b2m], + ... + [bn1, bn2, ..., bnm]] + + Returns: + matrix as :class:`Matrix` object + + Raises: + ZeroDivisionError: singular matrix + + """ + a, b, c = [list(v) for v in A] + if not isinstance(B, Matrix): + matrix_b = Matrix(matrix=[list(row) for row in B]) + else: + matrix_b = cast(Matrix, B) + if matrix_b.nrows != len(b): + raise ValueError("Row count of matrices A and B has to match.") + + return Matrix( + matrix=[_solve_tridiagonal_matrix(a, b, c, col) for col in matrix_b.cols()] + ).transpose() + + +def _solve_tridiagonal_matrix( + a: list[float], b: list[float], c: list[float], r: list[float] +) -> list[float]: + """Solves the linear equation system given by a tri-diagonal + Matrix(a, b, c) . x = r. + + Matrix configuration:: + + [[b0, c0, 0, 0, ...], + [a1, b1, c1, 0, ...], + [0, a2, b2, c2, ...], + ... ] + + Args: + a: lower diagonal [a0 .. an-1], a0 is not used but has to be present + b: central diagonal [b0 .. bn-1] + c: upper diagonal [c0 .. cn-1], cn-1 is not used and must not be present + r: right-hand side quantities + + Returns: + vector x as list of floats + + Raises: + ZeroDivisionError: singular matrix + + """ + n: int = len(a) + u: list[float] = [0.0] * n + gam: list[float] = [0.0] * n + bet: float = b[0] + u[0] = r[0] / bet + for j in range(1, n): + gam[j] = c[j - 1] / bet + bet = b[j] - a[j] * gam[j] + u[j] = (r[j] - a[j] * u[j - 1]) / bet + + for j in range((n - 2), -1, -1): + u[j] -= gam[j + 1] * u[j + 1] + return u + + +def banded_matrix(A: Matrix, check_all=True) -> tuple[Matrix, int, int]: + """Transform matrix A into a compact banded matrix representation. + Returns compact representation as :class:`Matrix` object and + lower- and upper band count m1 and m2. + + Args: + A: input :class:`Matrix` + check_all: check all diagonals if ``True`` or abort testing + after first all zero diagonal if ``False``. + + """ + m1, m2 = detect_banded_matrix(A, check_all) + m = compact_banded_matrix(A, m1, m2) + return m, m1, m2 + + +def detect_banded_matrix(A: Matrix, check_all=True) -> tuple[int, int]: + """Returns lower- and upper band count m1 and m2. + + Args: + A: input :class:`Matrix` + check_all: check all diagonals if ``True`` or abort testing + after first all zero diagonal if ``False``. + + """ + + def detect_m2() -> int: + m2: int = 0 + for d in range(1, A.ncols): + if any(A.diag(d)): + m2 = d + elif not check_all: + break + return m2 + + def detect_m1() -> int: + m1: int = 0 + for d in range(1, A.nrows): + if any(A.diag(-d)): + m1 = d + elif not check_all: + break + return m1 + + return detect_m1(), detect_m2() + + +def compact_banded_matrix(A: Matrix, m1: int, m2: int) -> Matrix: + """Returns compact banded matrix representation as :class:`Matrix` object. + + Args: + A: matrix to transform + m1: lower band count, excluding main matrix diagonal + m2: upper band count, excluding main matrix diagonal + + """ + if A.nrows != A.ncols: + raise TypeError("Square matrix required.") + + m = Matrix() + + for d in range(m1, 0, -1): + col = [0.0] * d + col.extend(A.diag(-d)) + m.append_col(col) + + m.append_col(A.diag(0)) + + for d in range(1, m2 + 1): + col = A.diag(d) + col.extend([0.0] * d) + m.append_col(col) + return m + + +class BandedMatrixLU(Solver): + """Represents a LU decomposition of a compact banded matrix.""" + + def __init__(self, A: Matrix, m1: int, m2: int): + lu_decompose = _lu_decompose + if USE_C_EXT: + # import error shows an installation issue + from ezdxf.acc.np_support import lu_decompose # type: ignore + + self.m1: int = int(m1) + self.m2: int = int(m2) + self.upper, self.lower, self.index = lu_decompose(A.matrix, self.m1, self.m2) + + @property + def nrows(self) -> int: + """Count of matrix rows.""" + return self.upper.shape[0] + + def solve_vector(self, B: Iterable[float]) -> list[float]: + """Solves the linear equation system given by the banded nxn Matrix + A . x = B, right-hand side quantities as vector B with n elements. + + Args: + B: vector [b1, b2, ..., bn] + + Returns: + vector as list of floats + + """ + + solve_vector_banded_matrix = _solve_vector_banded_matrix + if USE_C_EXT: + # import error shows an installation issue + from ezdxf.acc.np_support import solve_vector_banded_matrix # type: ignore + + x: NDArray = np.array(B, dtype=np.float64) + if len(x) != self.nrows: + raise ValueError( + "Item count of vector B has to be equal to matrix row count." + ) + return list( + solve_vector_banded_matrix( + x, self.upper, self.lower, self.index, self.m1, self.m2 + ) + ) + + def solve_matrix(self, B: MatrixData | NDArray) -> Matrix: + """ + Solves the linear equation system given by the banded nxn Matrix + A . x = B, right-hand side quantities as nxm Matrix B. + + Args: + B: matrix [[b11, b12, ..., b1m], [b21, b22, ..., b2m], + ... [bn1, bn2, ..., bnm]] + + Returns: + matrix as :class:`Matrix` object + + """ + matrix_b = Matrix(matrix=B) + if matrix_b.nrows != self.nrows: + raise ValueError("Row count of self and matrix B has to match.") + + return Matrix( + matrix=[self.solve_vector(col) for col in matrix_b.cols()] + ).transpose() + + +def _lu_decompose(A: NDArray, m1: int, m2: int) -> tuple[NDArray, NDArray, NDArray]: + # upper triangle of LU decomposition + upper: NDArray = np.array(A, dtype=np.float64) + + # lower triangle of LU decomposition + n: int = upper.shape[0] + lower: NDArray = np.zeros((n, m1), dtype=np.float64) + index: NDArray = np.zeros((n,), dtype=np.int64) + + mm: int = m1 + m2 + 1 + l: int = m1 + for i in range(m1): + for j in range(m1 - i, mm): + upper[i][j - l] = upper[i][j] + l -= 1 + for j in range(mm - l - 1, mm): + upper[i][j] = 0.0 + + l = m1 + for k in range(n): + dum = upper[k][0] + i = k + if l < n: + l += 1 + for j in range(k + 1, l): + if abs(upper[j][0]) > abs(dum): + dum = upper[j][0] + i = j + index[k] = i + 1 + if i != k: + for j in range(mm): + upper[k][j], upper[i][j] = upper[i][j], upper[k][j] + + for i in range(k + 1, l): + dum = upper[i][0] / upper[k][0] + lower[k][i - k - 1] = dum + for j in range(1, mm): + upper[i][j - 1] = upper[i][j] - dum * upper[k][j] + upper[i][mm - 1] = 0.0 + return upper, lower, index + + +def _solve_vector_banded_matrix( + x: NDArray, + upper: NDArray, + lower: NDArray, + index: NDArray, + m1: int, + m2: int, +) -> NDArray: + """Solves the linear equation system given by the banded nxn Matrix + A . x = B, right-hand side quantities as vector B with n elements. + + Args: + B: vector [b1, b2, ..., bn] + + Returns: + vector as list of floats + + """ + n: int = upper.shape[0] + if x.shape[0] != n: + raise ValueError("Item count of vector B has to be equal to matrix row count.") + + al: NDArray = lower + au: NDArray = upper + mm: int = m1 + m2 + 1 + l: int = m1 + for k in range(n): + j = index[k] - 1 + if j != k: + x[k], x[j] = x[j], x[k] + if l < n: + l += 1 + for j in range(k + 1, l): + x[j] -= al[k][j - k - 1] * x[k] + + l = 1 + for i in range(n - 1, -1, -1): + dum = x[i] + for k in range(1, l): + dum -= au[i][k] * x[k + i] + x[i] = dum / au[i][0] + if l < mm: + l += 1 + + return x diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/line.py b/.venv/lib/python3.12/site-packages/ezdxf/math/line.py new file mode 100644 index 0000000..fb6e756 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/line.py @@ -0,0 +1,314 @@ +# Copyright (c) 2010-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Optional +import math +from ezdxf.math import Vec2, intersection_line_line_2d, UVec +from .construct2d import is_point_left_of_line, TOLERANCE +from .bbox import BoundingBox2d + + +__all__ = ["ConstructionRay", "ConstructionLine", "ParallelRaysError"] + + +class ParallelRaysError(ArithmeticError): + pass + + +HALF_PI = math.pi / 2.0 +THREE_PI_HALF = 1.5 * math.pi +DOUBLE_PI = math.pi * 2.0 +ABS_TOL = 1e-12 + + +class ConstructionRay: + """Construction tool for infinite 2D rays. + + Args: + p1: definition point 1 + p2: ray direction as 2nd point or ``None`` + angle: ray direction as angle in radians or ``None`` + + """ + + def __init__( + self, p1: UVec, p2: Optional[UVec] = None, angle: Optional[float] = None + ): + self._location = Vec2(p1) + self._angle: Optional[float] + self._slope: Optional[float] + self._yof0: Optional[float] + self._direction: Vec2 + self._is_vertical: bool + self._is_horizontal: bool + + if p2 is not None: + p2_ = Vec2(p2) + if self._location.x < p2_.x: + self._direction = (p2_ - self._location).normalize() + else: + self._direction = (self._location - p2_).normalize() + self._angle = self._direction.angle + elif angle is not None: + self._angle = angle + self._direction = Vec2.from_angle(angle) + else: + raise ValueError("p2 or angle required.") + + if abs(self._direction.x) <= ABS_TOL: + self._slope = None + self._yof0 = None + else: + self._slope = self._direction.y / self._direction.x + self._yof0 = self._location.y - self._slope * self._location.x + self._is_vertical = self._slope is None + self._is_horizontal = abs(self._direction.y) <= ABS_TOL + + @property + def location(self) -> Vec2: + """Location vector as :class:`Vec2`.""" + return self._location + + @property + def direction(self) -> Vec2: + """Direction vector as :class:`Vec2`.""" + return self._direction + + @property + def slope(self) -> Optional[float]: + """Slope of ray or ``None`` if vertical.""" + return self._slope + + @property + def angle(self) -> float: + """Angle between x-axis and ray in radians.""" + if self._angle is None: + return self._direction.angle + else: + return self._angle + + @property + def angle_deg(self) -> float: + """Angle between x-axis and ray in degrees.""" + return math.degrees(self.angle) + + @property + def is_vertical(self) -> bool: + """``True`` if ray is vertical (parallel to y-axis).""" + return self._is_vertical + + @property + def is_horizontal(self) -> bool: + """``True`` if ray is horizontal (parallel to x-axis).""" + return self._is_horizontal + + def __repr__(self) -> str: + return ( + "ConstructionRay(p1=({0.location.x:.3f}, {0.location.y:.3f}), " + "angle={0.angle:.5f})".format(self) + ) + + def is_parallel(self, other: ConstructionRay) -> bool: + """Returns ``True`` if rays are parallel.""" + if self._is_vertical: + return other._is_vertical + if other._is_vertical: + return False + if self._is_horizontal: + return other._is_horizontal + # guards above guarantee that no slope is None + return math.isclose(self._slope, other._slope, abs_tol=ABS_TOL) # type: ignore + + def intersect(self, other: ConstructionRay) -> Vec2: + """Returns the intersection point as ``(x, y)`` tuple of `self` and + `other`. + + Raises: + ParallelRaysError: if rays are parallel + + """ + ray1 = self + ray2 = other + if ray1.is_parallel(ray2): + raise ParallelRaysError("Rays are parallel") + + if ray1._is_vertical: + x = ray1._location.x + if ray2.is_horizontal: + y = ray2._location.y + else: + y = ray2.yof(x) + elif ray2._is_vertical: + x = ray2._location.x + if ray1.is_horizontal: + y = ray1._location.y + else: + y = ray1.yof(x) + elif ray1._is_horizontal: + y = ray1._location.y + x = ray2.xof(y) + elif ray2._is_horizontal: + y = ray2._location.y + x = ray1.xof(y) + else: + # calc intersection with the 'straight-line-equation' + # based on y(x) = y0 + x*slope + # guards above guarantee that no slope is None + x = (ray1._yof0 - ray2._yof0) / (ray2._slope - ray1._slope) # type: ignore + y = ray1.yof(x) + return Vec2((x, y)) + + def orthogonal(self, location: UVec) -> ConstructionRay: + """Returns orthogonal ray at `location`.""" + return ConstructionRay(location, angle=self.angle + HALF_PI) + + def yof(self, x: float) -> float: + """Returns y-value of ray for `x` location. + + Raises: + ArithmeticError: for vertical rays + + """ + if self._is_vertical: + raise ArithmeticError + # guard above guarantee that slope is not None + return self._yof0 + float(x) * self._slope # type: ignore + + def xof(self, y: float) -> float: + """Returns x-value of ray for `y` location. + + Raises: + ArithmeticError: for horizontal rays + + """ + if self._is_vertical: # slope == None + return self._location.x + elif not self._is_horizontal: # slope != None & slope != 0 + return (float(y) - self._yof0) / self._slope # type: ignore + else: + raise ArithmeticError + + def bisectrix(self, other: ConstructionRay) -> ConstructionRay: + """Bisectrix between `self` and `other`.""" + intersection = self.intersect(other) + alpha = (self.angle + other.angle) / 2.0 + return ConstructionRay(intersection, angle=alpha) + + +class ConstructionLine: + """Construction tool for 2D lines. + + The :class:`ConstructionLine` class is similar to :class:`ConstructionRay`, + but has a start- and endpoint. The direction of line goes from start- to + endpoint, "left of line" is always in relation to this line direction. + + Args: + start: start point of line as :class:`Vec2` compatible object + end: end point of line as :class:`Vec2` compatible object + + """ + + def __init__(self, start: UVec, end: UVec): + self.start = Vec2(start) + self.end = Vec2(end) + + def __repr__(self) -> str: + return "ConstructionLine({0.start}, {0.end})".format(self) + + @property + def bounding_box(self) -> BoundingBox2d: + """bounding box of line as :class:`BoundingBox2d` object.""" + return BoundingBox2d((self.start, self.end)) + + def translate(self, dx: float, dy: float) -> None: + """ + Move line about `dx` in x-axis and about `dy` in y-axis. + + Args: + dx: translation in x-axis + dy: translation in y-axis + + """ + v = Vec2(dx, dy) + self.start += v + self.end += v + + @property + def sorted_points(self): + return ( + (self.end, self.start) + if self.start > self.end + else (self.start, self.end) + ) + + @property + def ray(self): + """collinear :class:`ConstructionRay`.""" + return ConstructionRay(self.start, self.end) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ConstructionLine): + raise TypeError(type(other)) + return self.sorted_points == other.sorted_points + + def __lt__(self, other: object) -> bool: + if not isinstance(other, ConstructionLine): + raise TypeError(type(other)) + return self.sorted_points < other.sorted_points + + def length(self) -> float: + """Returns length of line.""" + return (self.end - self.start).magnitude + + def midpoint(self) -> Vec2: + """Returns mid point of line.""" + return self.start.lerp(self.end) + + @property + def is_vertical(self) -> bool: + """``True`` if line is vertical.""" + return math.isclose(self.start.x, self.end.x) + + @property + def is_horizontal(self) -> bool: + """``True`` if line is horizontal.""" + return math.isclose(self.start.y, self.end.y) + + def inside_bounding_box(self, point: UVec) -> bool: + """Returns ``True`` if `point` is inside of line bounding box.""" + return self.bounding_box.inside(point) + + def intersect( + self, other: ConstructionLine, abs_tol: float = TOLERANCE + ) -> Optional[Vec2]: + """Returns the intersection point of to lines or ``None`` if they have + no intersection point. + + Args: + other: other :class:`ConstructionLine` + abs_tol: tolerance for distance check + + """ + return intersection_line_line_2d( + (self.start, self.end), + (other.start, other.end), + virtual=False, + abs_tol=abs_tol, + ) + + def has_intersection( + self, other: ConstructionLine, abs_tol: float = TOLERANCE + ) -> bool: + """Returns ``True`` if has intersection with `other` line.""" + return self.intersect(other, abs_tol=abs_tol) is not None + + def is_point_left_of_line(self, point: UVec, colinear=False) -> bool: + """Returns ``True`` if `point` is left of construction line in relation + to the line direction from start to end. + + If `colinear` is ``True``, a colinear point is also left of the line. + + """ + return is_point_left_of_line( + point, self.start, self.end, colinear=colinear + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/offset2d.py b/.venv/lib/python3.12/site-packages/ezdxf/math/offset2d.py new file mode 100644 index 0000000..306e4b4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/offset2d.py @@ -0,0 +1,75 @@ +# Copyright (c) 2019-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable +from ezdxf.math import Vec2, UVec +from ezdxf.math.line import ConstructionRay, ParallelRaysError + + +__all__ = ["offset_vertices_2d"] + + +def offset_vertices_2d( + vertices: Iterable[UVec], offset: float, closed: bool = False +) -> Iterable[Vec2]: + """Yields vertices of the offset line to the shape defined by `vertices`. + The source shape consist of straight segments and is located in the xy-plane, + the z-axis of input vertices is ignored. Takes closed shapes into account if + argument `closed` is ``True``, which yields intersection of first and last + offset segment as first vertex for a closed shape. For closed shapes the + first and last vertex can be equal, else an implicit closing segment from + last to first vertex is added. A shape with equal first and last vertex is + not handled automatically as closed shape. + + .. warning:: + + Adjacent collinear segments in `opposite` directions, same as a turn by + 180 degree (U-turn), leads to unexpected results. + + Args: + vertices: source shape defined by vertices + offset: line offset perpendicular to direction of shape segments defined + by vertices order, offset > ``0`` is 'left' of line segment, + offset < ``0`` is 'right' of line segment + closed: ``True`` to handle as closed shape + + """ + _vertices = Vec2.list(vertices) + if len(_vertices) < 2: + raise ValueError("2 or more vertices required.") + + if closed and not _vertices[0].isclose(_vertices[-1]): + # append first vertex as last vertex to close shape + _vertices.append(_vertices[0]) + + # create offset segments + offset_segments = list() + for start, end in zip(_vertices[:-1], _vertices[1:]): + offset_vec = (end - start).orthogonal().normalize(offset) + offset_segments.append((start + offset_vec, end + offset_vec)) + + if closed: # insert last segment also as first segment + offset_segments.insert(0, offset_segments[-1]) + + # first offset vertex = start point of first segment for open shapes + if not closed: + yield offset_segments[0][0] + + # yield intersection points of offset_segments + if len(offset_segments) > 1: + for (start1, end1), (start2, end2) in zip( + offset_segments[:-1], offset_segments[1:] + ): + try: # the usual case + yield ConstructionRay(start1, end1).intersect( + ConstructionRay(start2, end2) + ) + except ParallelRaysError: # collinear segments + yield end1 + if not end1.isclose(start2): # it's an U-turn (180 deg) + # creates an additional vertex! + yield start2 + + # last offset vertex = end point of last segment for open shapes + if not closed: + yield offset_segments[-1][1] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/parametrize.py b/.venv/lib/python3.12/site-packages/ezdxf/math/parametrize.py new file mode 100644 index 0000000..81d08ba --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/parametrize.py @@ -0,0 +1,255 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence +import math +from ezdxf.math import Vec3 +from .bezier_interpolation import ( + tangents_cubic_bezier_interpolation, + cubic_bezier_interpolation, +) +from .construct2d import circle_radius_3p + +__all__ = [ + "estimate_tangents", + "estimate_end_tangent_magnitude", + "create_t_vector", + "chord_length", +] + + +def create_t_vector(fit_points: list[Vec3], method: str) -> list[float]: + if method == "uniform": + return uniform_t_vector(len(fit_points)) + elif method in ("distance", "chord"): + return distance_t_vector(fit_points) + elif method in ("centripetal", "sqrt_chord"): + return centripetal_t_vector(fit_points) + elif method == "arc": + return arc_t_vector(fit_points) + else: + raise ValueError("Unknown method: {}".format(method)) + + +def uniform_t_vector(length: int) -> list[float]: + n = float(length - 1) + return [t / n for t in range(length)] + + +def distance_t_vector(fit_points: list[Vec3]) -> list[float]: + return _normalize_distances(list(linear_distances(fit_points))) + + +def centripetal_t_vector(fit_points: list[Vec3]) -> list[float]: + distances = [ + math.sqrt(p1.distance(p2)) for p1, p2 in zip(fit_points, fit_points[1:]) + ] + return _normalize_distances(distances) + + +def _normalize_distances(distances: Sequence[float]) -> list[float]: + total_length = sum(distances) + if abs(total_length) <= 1e-12: + return [] + params: list[float] = [0.0] + s = 0.0 + for d in distances[:-1]: + s += d + params.append(s / total_length) + params.append(1.0) + return params + + +def linear_distances(points: Iterable[Vec3]) -> Iterable[float]: + prev = None + for p in points: + if prev is None: + prev = p + continue + yield prev.distance(p) + prev = p + + +def chord_length(points: Iterable[Vec3]) -> float: + return sum(linear_distances(points)) + + +def arc_t_vector(fit_points: list[Vec3]) -> list[float]: + distances = list(arc_distances(fit_points)) + return _normalize_distances(distances) + + +def arc_distances(fit_points: list[Vec3]) -> Iterable[float]: + p = fit_points + + def _radii() -> Iterable[float]: + for i in range(len(p) - 2): + try: + radius = circle_radius_3p(p[i], p[i + 1], p[i + 2]) + except ZeroDivisionError: + radius = 0.0 + yield radius + + r: list[float] = list(_radii()) + if len(r) == 0: + return + r.append(r[-1]) # 2x last radius + for k in range(0, len(p) - 1): + distance = (p[k + 1] - p[k]).magnitude + rk = r[k] + if math.isclose(rk, 0): + yield distance + else: + yield math.asin(distance / 2.0 / rk) * 2.0 * rk + + +def estimate_tangents( + points: list[Vec3], method: str = "5-points", normalize=True +) -> list[Vec3]: + """Estimate tangents for curve defined by given fit points. + Calculated tangents are normalized (unit-vectors). + + Available tangent estimation methods: + + - "3-points": 3 point interpolation + - "5-points": 5 point interpolation + - "bezier": tangents from an interpolated cubic bezier curve + - "diff": finite difference + + Args: + points: start-, end- and passing points of curve + method: tangent estimation method + normalize: normalize tangents if ``True`` + + Returns: + tangents as list of :class:`Vec3` objects + + """ + method = method.lower() + if method.startswith("bez"): + return tangents_cubic_bezier_interpolation(points, normalize=normalize) + elif method.startswith("3-p"): + return tangents_3_point_interpolation(points, normalize=normalize) + elif method.startswith("5-p"): + return tangents_5_point_interpolation(points, normalize=normalize) + elif method.startswith("dif"): + return finite_difference_interpolation(points, normalize=normalize) + else: + raise ValueError(f"Unknown method: {method}") + + +def estimate_end_tangent_magnitude( + points: list[Vec3], method: str = "chord" +) -> tuple[float, float]: + """Estimate tangent magnitude of start- and end tangents. + + Available estimation methods: + + - "chord": total chord length, curve approximation by straight segments + - "arc": total arc length, curve approximation by arcs + - "bezier-n": total length from cubic bezier curve approximation, n + segments per section + + Args: + points: start-, end- and passing points of curve + method: tangent magnitude estimation method + + """ + if method == "chord": + total_length = sum(p0.distance(p1) for p0, p1 in zip(points, points[1:])) + return total_length, total_length + elif method == "arc": + total_length = sum(arc_distances(points)) + return total_length, total_length + elif method.startswith("bezier-"): + count = int(method[7:]) + s = 0.0 + for curve in cubic_bezier_interpolation(points): + s += sum(linear_distances(curve.approximate(count))) + return s, s + else: + raise ValueError(f"Unknown tangent magnitude calculation method: {method}") + + +def tangents_3_point_interpolation( + fit_points: list[Vec3], method: str = "chord", normalize=True +) -> list[Vec3]: + """Returns from 3 points interpolated and optional normalized tangent + vectors. + """ + q = [Q1 - Q0 for Q0, Q1 in zip(fit_points, fit_points[1:])] + t = list(create_t_vector(fit_points, method)) + delta_t = [t1 - t0 for t0, t1 in zip(t, t[1:])] + d = [qk / dtk for qk, dtk in zip(q, delta_t)] + alpha = [dt0 / (dt0 + dt1) for dt0, dt1 in zip(delta_t, delta_t[1:])] + tangents: list[Vec3] = [Vec3()] # placeholder + tangents.extend( + [(1.0 - alpha[k]) * d[k] + alpha[k] * d[k + 1] for k in range(len(d) - 1)] + ) + tangents[0] = 2.0 * d[0] - tangents[1] + tangents.append(2.0 * d[-1] - tangents[-1]) + if normalize: + tangents = [v.normalize() for v in tangents] + return tangents + + +def tangents_5_point_interpolation( + fit_points: list[Vec3], normalize=True +) -> list[Vec3]: + """Returns from 5 points interpolated and optional normalized tangent + vectors. + """ + n = len(fit_points) + q = _delta_q(fit_points) + + alpha = list() + for k in range(n): + v1 = (q[k - 1].cross(q[k])).magnitude + v2 = (q[k + 1].cross(q[k + 2])).magnitude + alpha.append(v1 / (v1 + v2)) + + tangents = [] + for k in range(n): + vk = (1.0 - alpha[k]) * q[k] + alpha[k] * q[k + 1] + tangents.append(vk) + if normalize: + tangents = [v.normalize() for v in tangents] + return tangents + + +def _delta_q(points: list[Vec3]) -> list[Vec3]: + n = len(points) + q = [Vec3()] # placeholder + q.extend([points[k + 1] - points[k] for k in range(n - 1)]) + q[0] = 2.0 * q[1] - q[2] + q.append(2.0 * q[n - 1] - q[n - 2]) # q[n] + q.append(2.0 * q[n] - q[n - 1]) # q[n+1] + q.append(2.0 * q[0] - q[1]) # q[-1] + return q + + +def finite_difference_interpolation( + fit_points: list[Vec3], normalize=True +) -> list[Vec3]: + f = 2.0 + p = fit_points + + t = [(p[1] - p[0]) / f] + for k in range(1, len(fit_points) - 1): + t.append((p[k] - p[k - 1]) / f + (p[k + 1] - p[k]) / f) + t.append((p[-1] - p[-2]) / f) + if normalize: + t = [v.normalize() for v in t] + return t + + +def cardinal_interpolation(fit_points: list[Vec3], tension: float) -> list[Vec3]: + # https://en.wikipedia.org/wiki/Cubic_Hermite_spline + def tangent(p0, p1): + return (p0 - p1).normalize(1.0 - tension) + + t = [tangent(fit_points[0], fit_points[1])] + for k in range(1, len(fit_points) - 1): + t.append(tangent(fit_points[k + 1], fit_points[k - 1])) + t.append(tangent(fit_points[-1], fit_points[-2])) + return t diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/perlin.py b/.venv/lib/python3.12/site-packages/ezdxf/math/perlin.py new file mode 100644 index 0000000..c3a2fe8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/perlin.py @@ -0,0 +1,426 @@ +# Copyright (c) 2008, Casey Duncan (casey dot duncan at gmail dot com) +# see LICENSE.txt for details +"""Noise functions for procedural generation of content + +Contains native code implementations of Perlin improved noise (with +fBm capabilities) and Perlin simplex noise. Also contains a fast +"fake noise" implementation in GLSL for execution in shaders. + +Copyright (c) 2008, Casey Duncan (casey dot duncan at gmail dot com) +""" +__version__ = "1.2.1" + +from math import floor, fmod, sqrt +from random import randint + +# 3D Gradient vectors +# fmt: off +_GRAD3 = ( + (1, 1, 0), (-1, 1, 0), (1, -1, 0), (-1, -1, 0), + (1, 0, 1), (-1, 0, 1), (1, 0, -1), (-1, 0, -1), + (0, 1, 1), (0, -1, 1), (0, 1, -1), (0, -1, -1), + (1, 1, 0), (0, -1, 1), (-1, 1, 0), (0, -1, -1), +) +# fmt: on + +# 4D Gradient vectors +# fmt: off +_GRAD4 = ( + (0, 1, 1, 1), (0, 1, 1, -1), (0, 1, -1, 1), (0, 1, -1, -1), + (0, -1, 1, 1), (0, -1, 1, -1), (0, -1, -1, 1), (0, -1, -1, -1), + (1, 0, 1, 1), (1, 0, 1, -1), (1, 0, -1, 1), (1, 0, -1, -1), + (-1, 0, 1, 1), (-1, 0, 1, -1), (-1, 0, -1, 1), (-1, 0, -1, -1), + (1, 1, 0, 1), (1, 1, 0, -1), (1, -1, 0, 1), (1, -1, 0, -1), + (-1, 1, 0, 1), (-1, 1, 0, -1), (-1, -1, 0, 1), (-1, -1, 0, -1), + (1, 1, 1, 0), (1, 1, -1, 0), (1, -1, 1, 0), (1, -1, -1, 0), + (-1, 1, 1, 0), (-1, 1, -1, 0), (-1, -1, 1, 0), (-1, -1, -1, 0) +) +# fmt: on + +# A lookup table to traverse the simplex around a given point in 4D. +# Details can be found where this table is used, in the 4D noise method. +# fmt: off +_SIMPLEX = ( + (0, 1, 2, 3), (0, 1, 3, 2), (0, 0, 0, 0), (0, 2, 3, 1), (0, 0, 0, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (1, 2, 3, 0), (0, 2, 1, 3), (0, 0, 0, 0), + (0, 3, 1, 2), (0, 3, 2, 1), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), + (1, 3, 2, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (1, 2, 0, 3), + (0, 0, 0, 0), (1, 3, 0, 2), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), + (2, 3, 0, 1), (2, 3, 1, 0), (1, 0, 2, 3), (1, 0, 3, 2), (0, 0, 0, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (2, 0, 3, 1), (0, 0, 0, 0), (2, 1, 3, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (2, 0, 1, 3), (0, 0, 0, 0), + (0, 0, 0, 0), (0, 0, 0, 0), (3, 0, 1, 2), (3, 0, 2, 1), (0, 0, 0, 0), + (3, 1, 2, 0), (2, 1, 0, 3), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), + (3, 1, 0, 2), (0, 0, 0, 0), (3, 2, 0, 1), (3, 2, 1, 0) +) +# fmt: on +# Simplex skew constants +_F2 = 0.5 * (sqrt(3.0) - 1.0) +_G2 = (3.0 - sqrt(3.0)) / 6.0 +_F3 = 1.0 / 3.0 +_G3 = 1.0 / 6.0 + +# fmt: off +_permutation = ( + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, + 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, + 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, + 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, + 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, + 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, + 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, + 172, 9, 129, 22, 39, 253, 9, 98, 108, 110, 79, 113, 224, 232, 178, 185, + 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, + 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, + 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, + 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, + 78, 66, 215, 61, 156, 180 +) +# fmt: on + + +class BaseNoise: + """Noise abstract base class""" + period = len(_permutation) + # Double permutation array so we don't need to wrap + permutation = _permutation * 2 + + def __init__(self, period=None, permutation_table=None): + """Initialize the noise generator. With no arguments, the default + period and permutation table are used (256). The default permutation + table generates the exact same noise pattern each time. + + An integer period can be specified, to generate a random permutation + table with period elements. The period determines the (integer) + interval that the noise repeats, which is useful for creating tiled + textures. period should be a power-of-two, though this is not + enforced. Note that the speed of the noise algorithm is independent of + the period size, though larger periods mean a larger table, which + consume more memory. + + A permutation table consisting of an iterable sequence of whole + numbers can be specified directly. This should have a power-of-two + length. Typical permutation tables are a sequence of unique integers in + the range [0,period) in random order, though other arrangements could + prove useful, they will not be "pure" simplex noise. The largest + element in the sequence must be no larger than period-1. + + period and permutation_table may not be specified together. + """ + if period is not None and permutation_table is not None: + raise ValueError( + "Can specify either period or permutation_table, not both" + ) + if period is not None: + self.randomize(period) + elif permutation_table is not None: + self.permutation = tuple(permutation_table) * 2 + self.period = len(permutation_table) + + def randomize(self, period=None): + """Randomize the permutation table used by the noise functions. This + makes them generate a different noise pattern for the same inputs. + """ + if period is not None: + self.period = period + perm = list(range(self.period)) + perm_right = self.period - 1 + for i in list(perm): + j = randint(0, perm_right) + perm[i], perm[j] = perm[j], perm[i] + self.permutation = tuple(perm) * 2 + + +class SimplexNoise(BaseNoise): + """Perlin simplex noise generator + + Adapted from Stefan Gustavson's Java implementation described here: + + http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + + To summarize: + + "In 2001, Ken Perlin presented 'simplex noise', a replacement for his classic + noise algorithm. Classic 'Perlin noise' won him an academy award and has + become an ubiquitous procedural primitive for computer graphics over the + years, but in hindsight it has quite a few limitations. Ken Perlin himself + designed simplex noise specifically to overcome those limitations, and he + spent a lot of good thinking on it. Therefore, it is a better idea than his + original algorithm. A few of the more prominent advantages are: + + * Simplex noise has a lower computational complexity and requires fewer + multiplications. + * Simplex noise scales to higher dimensions (4D, 5D and up) with much less + computational cost, the complexity is O(N) for N dimensions instead of + the O(2^N) of classic Noise. + * Simplex noise has no noticeable directional artifacts. Simplex noise has + a well-defined and continuous gradient everywhere that can be computed + quite cheaply. + * Simplex noise is easy to implement in hardware." + """ + + def noise2(self, x, y): + """2D Perlin simplex noise. + + Return a floating point value from -1 to 1 for the given x, y coordinate. + The same value is always returned for a given x, y pair unless the + permutation table changes (see randomize above). + """ + # Skew input space to determine which simplex (triangle) we are in + s = (x + y) * _F2 + i = floor(x + s) + j = floor(y + s) + t = (i + j) * _G2 + x0 = x - (i - t) # "Unskewed" distances from cell origin + y0 = y - (j - t) + + if x0 > y0: + i1 = 1 + j1 = 0 # Lower triangle, XY order: (0,0)->(1,0)->(1,1) + else: + i1 = 0 + j1 = 1 # Upper triangle, YX order: (0,0)->(0,1)->(1,1) + + x1 = x0 - i1 + _G2 # Offsets for middle corner in (x,y) unskewed coords + y1 = y0 - j1 + _G2 + x2 = ( + x0 + _G2 * 2.0 - 1.0 + ) # Offsets for last corner in (x,y) unskewed coords + y2 = y0 + _G2 * 2.0 - 1.0 + + # Determine hashed gradient indices of the three simplex corners + perm = self.permutation + ii = int(i) % self.period + jj = int(j) % self.period + gi0 = perm[ii + perm[jj]] % 12 + gi1 = perm[ii + i1 + perm[jj + j1]] % 12 + gi2 = perm[ii + 1 + perm[jj + 1]] % 12 + + # Calculate the contribution from the three corners + tt = 0.5 - x0 ** 2 - y0 ** 2 + if tt > 0: + g = _GRAD3[gi0] + noise = tt ** 4 * (g[0] * x0 + g[1] * y0) + else: + noise = 0.0 + + tt = 0.5 - x1 ** 2 - y1 ** 2 + if tt > 0: + g = _GRAD3[gi1] + noise += tt ** 4 * (g[0] * x1 + g[1] * y1) + + tt = 0.5 - x2 ** 2 - y2 ** 2 + if tt > 0: + g = _GRAD3[gi2] + noise += tt ** 4 * (g[0] * x2 + g[1] * y2) + + return noise * 70.0 # scale noise to [-1, 1] + + def noise3(self, x, y, z): + """3D Perlin simplex noise. + + Return a floating point value from -1 to 1 for the given x, y, z coordinate. + The same value is always returned for a given x, y, z pair unless the + permutation table changes (see randomize above). + """ + # Skew the input space to determine which simplex cell we're in + s = (x + y + z) * _F3 + i = floor(x + s) + j = floor(y + s) + k = floor(z + s) + t = (i + j + k) * _G3 + x0 = x - (i - t) # "Unskewed" distances from cell origin + y0 = y - (j - t) + z0 = z - (k - t) + + # For the 3D case, the simplex shape is a slightly irregular tetrahedron. + # Determine which simplex we are in. + if x0 >= y0: + if y0 >= z0: + i1 = 1 + j1 = 0 + k1 = 0 + i2 = 1 + j2 = 1 + k2 = 0 + elif x0 >= z0: + i1 = 1 + j1 = 0 + k1 = 0 + i2 = 1 + j2 = 0 + k2 = 1 + else: + i1 = 0 + j1 = 0 + k1 = 1 + i2 = 1 + j2 = 0 + k2 = 1 + else: # x0 < y0 + if y0 < z0: + i1 = 0 + j1 = 0 + k1 = 1 + i2 = 0 + j2 = 1 + k2 = 1 + elif x0 < z0: + i1 = 0 + j1 = 1 + k1 = 0 + i2 = 0 + j2 = 1 + k2 = 1 + else: + i1 = 0 + j1 = 1 + k1 = 0 + i2 = 1 + j2 = 1 + k2 = 0 + + # Offsets for remaining corners + x1 = x0 - i1 + _G3 + y1 = y0 - j1 + _G3 + z1 = z0 - k1 + _G3 + x2 = x0 - i2 + 2.0 * _G3 + y2 = y0 - j2 + 2.0 * _G3 + z2 = z0 - k2 + 2.0 * _G3 + x3 = x0 - 1.0 + 3.0 * _G3 + y3 = y0 - 1.0 + 3.0 * _G3 + z3 = z0 - 1.0 + 3.0 * _G3 + + # Calculate the hashed gradient indices of the four simplex corners + perm = self.permutation + ii = int(i) % self.period + jj = int(j) % self.period + kk = int(k) % self.period + gi0 = perm[ii + perm[jj + perm[kk]]] % 12 + gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12 + gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12 + gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12 + + # Calculate the contribution from the four corners + noise = 0.0 + tt = 0.6 - x0 ** 2 - y0 ** 2 - z0 ** 2 + if tt > 0: + g = _GRAD3[gi0] + noise = tt ** 4 * (g[0] * x0 + g[1] * y0 + g[2] * z0) + else: + noise = 0.0 + + tt = 0.6 - x1 ** 2 - y1 ** 2 - z1 ** 2 + if tt > 0: + g = _GRAD3[gi1] + noise += tt ** 4 * (g[0] * x1 + g[1] * y1 + g[2] * z1) + + tt = 0.6 - x2 ** 2 - y2 ** 2 - z2 ** 2 + if tt > 0: + g = _GRAD3[gi2] + noise += tt ** 4 * (g[0] * x2 + g[1] * y2 + g[2] * z2) + + tt = 0.6 - x3 ** 2 - y3 ** 2 - z3 ** 2 + if tt > 0: + g = _GRAD3[gi3] + noise += tt ** 4 * (g[0] * x3 + g[1] * y3 + g[2] * z3) + + return noise * 32.0 + + +def lerp(t, a, b): + return a + t * (b - a) + + +def grad3(hash, x, y, z): + g = _GRAD3[hash % 16] + return x * g[0] + y * g[1] + z * g[2] + + +class TileableNoise(BaseNoise): + """Tileable implementation of Perlin "improved" noise. This + is based on the reference implementation published here: + + http://mrl.nyu.edu/~perlin/noise/ + """ + + def noise3(self, x, y, z, repeat, base=0.0): + """Tileable 3D noise. + + repeat specifies the integer interval in each dimension + when the noise pattern repeats. + + base allows a different texture to be generated for + the same repeat interval. + """ + i = int(fmod(floor(x), repeat)) + j = int(fmod(floor(y), repeat)) + k = int(fmod(floor(z), repeat)) + ii = (i + 1) % repeat + jj = (j + 1) % repeat + kk = (k + 1) % repeat + if base: + i += base + j += base + k += base + ii += base + jj += base + kk += base + + x -= floor(x) + y -= floor(y) + z -= floor(z) + fx = x ** 3 * (x * (x * 6 - 15) + 10) + fy = y ** 3 * (y * (y * 6 - 15) + 10) + fz = z ** 3 * (z * (z * 6 - 15) + 10) + + perm = self.permutation + A = perm[i] + AA = perm[A + j] + AB = perm[A + jj] + B = perm[ii] + BA = perm[B + j] + BB = perm[B + jj] + + return lerp( + fz, + lerp( + fy, + lerp( + fx, + grad3(perm[AA + k], x, y, z), + grad3(perm[BA + k], x - 1, y, z), + ), + lerp( + fx, + grad3(perm[AB + k], x, y - 1, z), + grad3(perm[BB + k], x - 1, y - 1, z), + ), + ), + lerp( + fy, + lerp( + fx, + grad3(perm[AA + kk], x, y, z - 1), + grad3(perm[BA + kk], x - 1, y, z - 1), + ), + lerp( + fx, + grad3(perm[AB + kk], x, y - 1, z - 1), + grad3(perm[BB + kk], x - 1, y - 1, z - 1), + ), + ), + ) + + +_simplex = SimplexNoise() +snoise2 = _simplex.noise2 +snoise3 = _simplex.noise3 +_tileable = TileableNoise() +tnoise3 = _tileable.noise3 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/polyline.py b/.venv/lib/python3.12/site-packages/ezdxf/math/polyline.py new file mode 100644 index 0000000..c1b60e2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/polyline.py @@ -0,0 +1,474 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Tuple, + Iterator, + Sequence, + Dict, +) +import abc +from typing_extensions import Protocol, TypeAlias +import numpy as np + +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + NULLVEC, + intersection_line_line_2d, + BoundingBox2d, + intersection_line_line_3d, + BoundingBox, + AbstractBoundingBox, +) + + +import bisect + + +__all__ = [ + "ConstructionPolyline", + "ApproxParamT", + "intersect_polylines_2d", + "intersect_polylines_3d", +] + +REL_TOL = 1e-9 + + +class ConstructionPolyline(Sequence): + """Construction tool for 3D polylines. + + A polyline construction tool to measure, interpolate and divide anything + that can be approximated or flattened into vertices. + This is an immutable data structure which supports the :class:`Sequence` + interface. + + Args: + vertices: iterable of polyline vertices + close: ``True`` to close the polyline (first vertex == last vertex) + rel_tol: relative tolerance for floating point comparisons + + Example to measure or divide a SPLINE entity:: + + import ezdxf + from ezdxf.math import ConstructionPolyline + + doc = ezdxf.readfile("your.dxf") + msp = doc.modelspace() + spline = msp.query("SPLINE").first + if spline is not None: + polyline = ConstructionPolyline(spline.flattening(0.01)) + print(f"Entity {spline} has an approximated length of {polyline.length}") + # get dividing points with a distance of 1.0 drawing unit to each other + points = list(polyline.divide_by_length(1.0)) + + """ + + def __init__( + self, + vertices: Iterable[UVec], + close: bool = False, + rel_tol: float = REL_TOL, + ): + self._rel_tol = float(rel_tol) + v3list: list[Vec3] = Vec3.list(vertices) + self._vertices: list[Vec3] = v3list + if close and len(v3list) > 2: + if not v3list[0].isclose(v3list[-1], rel_tol=self._rel_tol): + v3list.append(v3list[0]) + + self._distances: list[float] = _distances(v3list) + + def __len__(self) -> int: + """len(self)""" + return len(self._vertices) + + def __iter__(self) -> Iterator[Vec3]: + """iter(self)""" + return iter(self._vertices) + + def __getitem__(self, item): + """vertex = self[item]""" + if isinstance(item, int): + return self._vertices[item] + else: # slice + return self.__class__(self._vertices[item], rel_tol=self._rel_tol) + + @property + def length(self) -> float: + """Returns the overall length of the polyline.""" + if self._distances: + return self._distances[-1] + return 0.0 + + @property + def is_closed(self) -> bool: + """Returns ``True`` if the polyline is closed + (first vertex == last vertex). + """ + if len(self._vertices) > 2: + return self._vertices[0].isclose( + self._vertices[-1], rel_tol=self._rel_tol + ) + return False + + def data(self, index: int) -> tuple[float, float, Vec3]: + """Returns the tuple (distance from start, distance from previous vertex, + vertex). All distances measured along the polyline. + """ + vertices = self._vertices + if not vertices: + raise ValueError("empty polyline") + distances = self._distances + + if index == 0: + return 0.0, 0.0, vertices[0] + prev_distance = distances[index - 1] + current_distance = distances[index] + vertex = vertices[index] + return current_distance, current_distance - prev_distance, vertex + + def index_at(self, distance: float) -> int: + """Returns the data index of the exact or next data entry for the given + `distance`. Returns the index of last entry if `distance` > :attr:`length`. + + """ + if distance <= 0.0: + return 0 + if distance >= self.length: + return max(0, len(self) - 1) + return self._index_at(distance) + + def _index_at(self, distance: float) -> int: + # fast method without any checks + return bisect.bisect_left(self._distances, distance) + + def vertex_at(self, distance: float) -> Vec3: + """Returns the interpolated vertex at the given `distance` from the + start of the polyline. + """ + if distance < 0.0 or distance > self.length: + raise ValueError("distance out of range") + if len(self._vertices) < 2: + raise ValueError("not enough vertices for interpolation") + return self._vertex_at(distance) + + def _vertex_at(self, distance: float) -> Vec3: + # fast method without any checks + vertices = self._vertices + distances = self._distances + index1 = self._index_at(distance) + if index1 == 0: + return vertices[0] + index0 = index1 - 1 + distance1 = distances[index1] + distance0 = distances[index0] + # skip coincident vertices: + while index0 > 0 and distance0 == distance1: + index0 -= 1 + distance0 = distances[index0] + if distance0 == distance1: + raise ArithmeticError("internal interpolation error") + + factor = (distance - distance0) / (distance1 - distance0) + return vertices[index0].lerp(vertices[index1], factor=factor) + + def divide(self, count: int) -> Iterator[Vec3]: + """Returns `count` interpolated vertices along the polyline. + Argument `count` has to be greater than 2 and the start- and end + vertices are always included. + + """ + if count < 2: + raise ValueError(f"invalid count: {count}") + vertex_at = self._vertex_at + for distance in np.linspace(0.0, self.length, count): + yield vertex_at(distance) + + def divide_by_length( + self, length: float, force_last: bool = False + ) -> Iterator[Vec3]: + """Returns interpolated vertices along the polyline. Each vertex has a + fix distance `length` from its predecessor. Yields the last vertex if + argument `force_last` is ``True`` even if the last distance is not equal + to `length`. + + """ + if length <= 0.0: + raise ValueError(f"invalid length: {length}") + if len(self._vertices) < 2: + raise ValueError("not enough vertices for interpolation") + + total_length: float = self.length + vertex_at = self._vertex_at + distance: float = 0.0 + + vertex: Vec3 = NULLVEC + while distance <= total_length: + vertex = vertex_at(distance) + yield vertex + distance += length + + if force_last and not vertex.isclose(self._vertices[-1]): + yield self._vertices[-1] + + +def _distances(vertices: Iterable[Vec3]) -> list[float]: + # distance from start vertex of the polyline to the vertex + current_station: float = 0.0 + distances: list[float] = [] + prev_vertex = Vec3() + for vertex in vertices: + if distances: + distant_vec = vertex - prev_vertex + current_station += distant_vec.magnitude + distances.append(current_station) + else: + distances.append(current_station) + prev_vertex = vertex + return distances + + +class SupportsPointMethod(Protocol): + def point(self, t: float) -> UVec: + ... + + +class ApproxParamT: + """Approximation tool for parametrized curves. + + - approximate parameter `t` for a given distance from the start of the curve + - approximate the distance for a given parameter `t` from the start of the curve + + These approximations can be applied to all parametrized curves which provide + a :meth:`point` method, like :class:`Bezier4P`, :class:`Bezier3P` and + :class:`BSpline`. + + The approximation is based on equally spaced parameters from 0 to `max_t` + for a given segment count. + The :meth:`flattening` method can not be used for the curve approximation, + because the required parameter `t` is not logged by the flattening process. + + Args: + curve: curve object, requires a method :meth:`point` + max_t: the max. parameter value + segments: count of approximation segments + + """ + + def __init__( + self, + curve: SupportsPointMethod, + *, + max_t: float = 1.0, + segments: int = 100, + ): + assert hasattr(curve, "point") + assert segments > 0 + self._polyline = ConstructionPolyline( + curve.point(t) for t in np.linspace(0.0, max_t, segments + 1) + ) + self._max_t = max_t + self._step = max_t / segments + + @property + def max_t(self) -> float: + return self._max_t + + @property + def polyline(self) -> ConstructionPolyline: + return self._polyline + + def param_t(self, distance: float): + """Approximate parameter t for the given `distance` from the start of + the curve. + """ + poly = self._polyline + if distance >= poly.length: + return self._max_t + + t_step = self._step + i = poly.index_at(distance) + station, d0, _ = poly.data(i) + t = t_step * i # t for station + if d0 > 1e-12: + t -= t_step * (station - distance) / d0 + return min(self._max_t, t) + + def distance(self, t: float) -> float: + """Approximate the distance from the start of the curve to the point + `t` on the curve. + """ + if t <= 0.0: + return 0.0 + poly = self._polyline + if t >= self._max_t: + return poly.length + + step = self._step + index = int(t / step) + 1 + station, d0, _ = poly.data(index) + return station - d0 * (step * index - t) / step + + +def intersect_polylines_2d( + p1: Sequence[Vec2], p2: Sequence[Vec2], abs_tol=1e-10 +) -> list[Vec2]: + """Returns the intersection points for two polylines as list of :class:`Vec2` + objects, the list is empty if no intersection points exist. + Does not return self intersection points of `p1` or `p2`. + Duplicate intersection points are removed from the result list, but the list + does not have a particular order! You can sort the result list by + :code:`result.sort()` to introduce an order. + + Args: + p1: first polyline as sequence of :class:`Vec2` objects + p2: second polyline as sequence of :class:`Vec2` objects + abs_tol: absolute tolerance for comparisons + + """ + intersect = _PolylineIntersection2d(p1, p2, abs_tol) + intersect.execute() + return intersect.intersections + + +def intersect_polylines_3d( + p1: Sequence[Vec3], p2: Sequence[Vec3], abs_tol=1e-10 +) -> list[Vec3]: + """Returns the intersection points for two polylines as list of :class:`Vec3` + objects, the list is empty if no intersection points exist. + Does not return self intersection points of `p1` or `p2`. + Duplicate intersection points are removed from the result list, but the list + does not have a particular order! You can sort the result list by + :code:`result.sort()` to introduce an order. + + Args: + p1: first polyline as sequence of :class:`Vec3` objects + p2: second polyline as sequence of :class:`Vec3` objects + abs_tol: absolute tolerance for comparisons + + """ + intersect = _PolylineIntersection3d(p1, p2, abs_tol) + intersect.execute() + return intersect.intersections + + +def divide(a: int, b: int) -> tuple[int, int, int, int]: + m = (a + b) // 2 + return a, m, m, b + + +TCache: TypeAlias = Dict[Tuple[int, int, int], AbstractBoundingBox] + + +class _PolylineIntersection: + p1: Sequence + p2: Sequence + + def __init__(self) -> None: + # At each recursion level the bounding box for each half of the + # polyline will be created two times, using a cache is an advantage: + self.bbox_cache: TCache = {} + + @abc.abstractmethod + def bbox(self, points: Sequence) -> AbstractBoundingBox: + ... + + @abc.abstractmethod + def line_intersection(self, s1: int, e1: int, s2: int, e2: int) -> None: + ... + + def execute(self) -> None: + l1: int = len(self.p1) + l2: int = len(self.p2) + if l1 < 2 or l2 < 2: # polylines with only one vertex + return + self.intersect(0, l1 - 1, 0, l2 - 1) + + def overlap(self, s1: int, e1: int, s2: int, e2: int) -> bool: + e1 += 1 + e2 += 1 + # If one part of the polylines has less than 2 vertices no intersection + # calculation is required: + if e1 - s1 < 2 or e2 - s2 < 2: + return False + + cache = self.bbox_cache + key1 = (1, s1, e1) + bbox1 = cache.get(key1) + if bbox1 is None: + bbox1 = self.bbox(self.p1[s1:e1]) + cache[key1] = bbox1 + + key2 = (2, s2, e2) + bbox2 = cache.get(key2) + if bbox2 is None: + bbox2 = self.bbox(self.p2[s2:e2]) + cache[key2] = bbox2 + return bbox1.has_overlap(bbox2) + + def intersect(self, s1: int, e1: int, s2: int, e2: int) -> None: + assert e1 > s1 and e2 > s2 + if e1 - s1 == 1 and e2 - s2 == 1: + self.line_intersection(s1, e1, s2, e2) + return + s1_a, e1_b, s1_c, e1_d = divide(s1, e1) + s2_a, e2_b, s2_c, e2_d = divide(s2, e2) + + if self.overlap(s1_a, e1_b, s2_a, e2_b): + self.intersect(s1_a, e1_b, s2_a, e2_b) + if self.overlap(s1_a, e1_b, s2_c, e2_d): + self.intersect(s1_a, e1_b, s2_c, e2_d) + if self.overlap(s1_c, e1_d, s2_a, e2_b): + self.intersect(s1_c, e1_d, s2_a, e2_b) + if self.overlap(s1_c, e1_d, s2_c, e2_d): + self.intersect(s1_c, e1_d, s2_c, e2_d) + + +class _PolylineIntersection2d(_PolylineIntersection): + def __init__(self, p1: Sequence[Vec2], p2: Sequence[Vec2], abs_tol=1e-10): + super().__init__() + self.p1 = p1 + self.p2 = p2 + self.intersections: list[Vec2] = [] + self.abs_tol = abs_tol + + def bbox(self, points: Sequence) -> AbstractBoundingBox: + return BoundingBox2d(points) + + def line_intersection(self, s1: int, e1: int, s2: int, e2: int) -> None: + line1 = self.p1[s1], self.p1[e1] + line2 = self.p2[s2], self.p2[e2] + p = intersection_line_line_2d( + line1, line2, virtual=False, abs_tol=self.abs_tol + ) + if p is not None and not any( + p.isclose(ip, abs_tol=self.abs_tol) for ip in self.intersections + ): + self.intersections.append(p) + + +class _PolylineIntersection3d(_PolylineIntersection): + def __init__(self, p1: Sequence[Vec3], p2: Sequence[Vec3], abs_tol=1e-10): + super().__init__() + self.p1 = p1 + self.p2 = p2 + self.intersections: list[Vec3] = [] + self.abs_tol = abs_tol + + def bbox(self, points: Sequence) -> AbstractBoundingBox: + return BoundingBox(points) + + def line_intersection(self, s1: int, e1: int, s2: int, e2: int) -> None: + line1 = self.p1[s1], self.p1[e1] + line2 = self.p2[s2], self.p2[e2] + p = intersection_line_line_3d( + line1, line2, virtual=False, abs_tol=self.abs_tol + ) + if p is not None and not any( + p.isclose(ip, abs_tol=self.abs_tol) for ip in self.intersections + ): + self.intersections.append(p) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/rtree.py b/.venv/lib/python3.12/site-packages/ezdxf/math/rtree.py new file mode 100644 index 0000000..ed90033 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/rtree.py @@ -0,0 +1,327 @@ +# Copyright (c) 2022, Manfred Moitzi +# License: MIT License +# Immutable spatial search tree based on the SsTree implementation of the book +# "Advanced Algorithms and Data Structures" +# - SsTree JavaScript source code: +# (c) 2019, Marcello La Rocca, released under the GNU Affero General Public License v3.0 +# https://github.com/mlarocca/AlgorithmsAndDataStructuresInAction/tree/master/JavaScript/src/ss_tree +# - Research paper of Antonin Guttman: +# http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf +from __future__ import annotations +import statistics +from typing import Iterator, Callable, Sequence, Iterable, TypeVar, Generic +import abc +import math + +from ezdxf.math import BoundingBox, Vec2, Vec3, spherical_envelope + +__all__ = ["RTree"] + +INF = float("inf") + +T = TypeVar("T", Vec2, Vec3) + + +class Node(abc.ABC, Generic[T]): + __slots__ = ("bbox",) + + def __init__(self, bbox: BoundingBox): + self.bbox: BoundingBox = bbox + + @abc.abstractmethod + def __len__(self) -> int: ... + + @abc.abstractmethod + def __iter__(self) -> Iterator[T]: ... + + @abc.abstractmethod + def contains(self, point: T) -> bool: ... + + @abc.abstractmethod + def _nearest_neighbor( + self, target: T, nn: T = None, nn_dist: float = INF + ) -> tuple[T, float]: ... + + @abc.abstractmethod + def points_in_sphere(self, center: T, radius: float) -> Iterator[T]: ... + + @abc.abstractmethod + def points_in_bbox(self, bbox: BoundingBox) -> Iterator[T]: ... + + def nearest_neighbor(self, target: T) -> tuple[T, float]: + return self._nearest_neighbor(target) + + +class LeafNode(Node[T]): + __slots__ = ("points", "bbox") + + def __init__(self, points: list[T]): + self.points = tuple(points) + super().__init__(BoundingBox(self.points)) + + def __len__(self): + return len(self.points) + + def __iter__(self) -> Iterator[T]: + return iter(self.points) + + def contains(self, point: T) -> bool: + return any(point.isclose(p) for p in self.points) + + def _nearest_neighbor( + self, target: T, nn: T = None, nn_dist: float = INF + ) -> tuple[T, float]: + distance, point = min((target.distance(p), p) for p in self.points) + if distance < nn_dist: + nn, nn_dist = point, distance + return nn, nn_dist + + def points_in_sphere(self, center: T, radius: float) -> Iterator[T]: + return (p for p in self.points if center.distance(p) <= radius) + + def points_in_bbox(self, bbox: BoundingBox) -> Iterator[T]: + return (p for p in self.points if bbox.inside(p)) + + +class InnerNode(Node[T]): + __slots__ = ("children", "bbox") + + def __init__(self, children: Sequence[Node[T]]): + super().__init__(BoundingBox()) + self.children = tuple(children) + for child in self.children: + # build union of all child bounding boxes + self.bbox.extend([child.bbox.extmin, child.bbox.extmax]) + + def __len__(self) -> int: + return sum(len(c) for c in self.children) + + def __iter__(self) -> Iterator[T]: + for child in self.children: + yield from iter(child) + + def contains(self, point: T) -> bool: + for child in self.children: + if child.bbox.inside(point) and child.contains(point): + return True + return False + + def _nearest_neighbor( + self, target: T, nn: T = None, nn_dist: float = INF + ) -> tuple[T, float]: + closest_child = find_closest_child(self.children, target) + nn, nn_dist = closest_child._nearest_neighbor(target, nn, nn_dist) + for child in self.children: + if child is closest_child: + continue + # is target inside the child bounding box + nn_dist in all directions + if grow_box(child.bbox, nn_dist).inside(target): + point, distance = child._nearest_neighbor(target, nn, nn_dist) + if distance < nn_dist: + nn = point + nn_dist = distance + return nn, nn_dist + + def points_in_sphere(self, center: T, radius: float) -> Iterator[T]: + for child in self.children: + if is_sphere_intersecting_bbox( + Vec3(center), radius, child.bbox.center, child.bbox.size + ): + yield from child.points_in_sphere(center, radius) + + def points_in_bbox(self, bbox: BoundingBox) -> Iterator[T]: + for child in self.children: + if bbox.has_overlap(child.bbox): + yield from child.points_in_bbox(bbox) + + +class RTree(Generic[T]): + """Immutable spatial search tree loosely based on `R-trees`_. + + The search tree is buildup once at initialization and immutable afterwards, + because rebuilding the tree after inserting or deleting nodes is very costly + and makes the implementation very complex. + + Without the ability to alter the content the restrictions which forces the tree + balance at growing and shrinking of the original `R-trees`_, are ignored, like the + fixed minimum and maximum node size. + + This class uses internally only 3D bounding boxes, but also supports + :class:`Vec2` as well as :class:`Vec3` objects as input data, but point + types should not be mixed in a search tree. + + The point objects keep their type and identity and the returned points of + queries can be compared by the ``is`` operator for identity to the input + points. + + The implementation requires a maximum node size of at least 2 and + does not support empty trees! + + Raises: + ValueError: max. node size too small or no data given + + .. _R-trees: https://en.wikipedia.org/wiki/R-tree + + """ + + __slots__ = ("_root",) + + def __init__(self, points: Iterable[T], max_node_size: int = 5): + if max_node_size < 2: + raise ValueError("max node size must be > 1") + _points = list(points) + if len(_points) == 0: + raise ValueError("no points given") + self._root = make_node(_points, max_node_size, box_split) + + def __len__(self): + """Returns the count of points in the search tree.""" + return len(self._root) + + def __iter__(self) -> Iterator[T]: + """Yields all points in the search tree.""" + yield from iter(self._root) + + def contains(self, point: T) -> bool: + """Returns ``True`` if `point` exists, the comparison is done by the + :meth:`isclose` method and not by the identity operator ``is``. + """ + return self._root.contains(point) + + def nearest_neighbor(self, target: T) -> tuple[T, float]: + """Returns the closest point to the `target` point and the distance + between these points. + """ + return self._root.nearest_neighbor(target) + + def points_in_sphere(self, center: T, radius: float) -> Iterator[T]: + """Returns all points in the range of the given sphere including the + points at the boundary. + """ + return self._root.points_in_sphere(center, radius) + + def points_in_bbox(self, bbox: BoundingBox) -> Iterator[T]: + """Returns all points in the range of the given bounding box including + the points at the boundary. + """ + return self._root.points_in_bbox(bbox) + + def avg_leaf_size(self, spread: float = 1.0) -> float: + """Returns the average size of the leaf bounding boxes. + The size of a leaf bounding box is the maximum size in all dimensions. + Excludes outliers of sizes beyond mean + standard deviation * spread. + Returns 0.0 if less than two points in tree. + """ + sizes: list[float] = [ + max(leaf.bbox.size.xyz) for leaf in collect_leafs(self._root) + ] + return average_exclusive_outliers(sizes, spread) + + def avg_spherical_envelope_radius(self, spread: float = 1.0) -> float: + """Returns the average radius of spherical envelopes of the leaf nodes. + Excludes outliers with radius beyond mean + standard deviation * spread. + Returns 0.0 if less than two points in tree. + """ + radii: list[float] = [ + spherical_envelope(leaf.points)[1] for leaf in collect_leafs(self._root) + ] + return average_exclusive_outliers(radii, spread) + + def avg_nn_distance(self, spread: float = 1.0) -> float: + """Returns the average of the nearest neighbor distances inside (!) + leaf nodes. Excludes outliers with a distance beyond the overall + mean + standard deviation * spread. Returns 0.0 if less than two points + in tree. + + .. warning:: + + This is a brute force check with O(n!) for each leaf node, where n + is the point count of the leaf node. + + """ + distances: list[float] = [] + for leaf in collect_leafs(self._root): + distances.extend(nearest_neighbor_distances(leaf.points)) + return average_exclusive_outliers(distances, spread) + + +def make_node( + points: list[T], + max_size: int, + split_strategy: Callable[[list[T], int], Sequence[Node]], +) -> Node[T]: + if len(points) > max_size: + return InnerNode(split_strategy(points, max_size)) + else: + return LeafNode(points) + + +def box_split(points: list[T], max_size: int) -> Sequence[Node[T]]: + n = len(points) + size: tuple[float, float, float] = BoundingBox(points).size.xyz + dim = size.index(max(size)) + points.sort(key=lambda vec: vec[dim]) + k = math.ceil(n / max_size) + return tuple( + make_node(points[i : i + k], max_size, box_split) for i in range(0, n, k) + ) + + +def is_sphere_intersecting_bbox( + centroid: Vec3, radius: float, center: Vec3, size: Vec3 +) -> bool: + distance = centroid - center + intersection_distance = size * 0.5 + Vec3(radius, radius, radius) + # non-intersection is more often likely: + if abs(distance.x) > intersection_distance.x: + return False + if abs(distance.y) > intersection_distance.y: + return False + if abs(distance.z) > intersection_distance.z: + return False + return True + + +def find_closest_child(children: Sequence[Node[T]], point: T) -> Node[T]: + def distance(child: Node) -> float: + return point.distance(child.bbox.center) + + assert len(children) > 0 + return min(children, key=distance) + + +def grow_box(box: BoundingBox, dist: float) -> BoundingBox: + bbox = box.copy() + bbox.grow(dist) + return bbox + + +def average_exclusive_outliers(values: list[float], spread: float) -> float: + if len(values) < 2: + return 0.0 + stdev = statistics.stdev(values) + mean = sum(values) / len(values) + max_value = mean + stdev * spread + values = [value for value in values if value <= max_value] + if len(values): + return sum(values) / len(values) + return 0.0 + + +def collect_leafs(node: Node[T]) -> Iterable[LeafNode[T]]: + """Yields all leaf nodes below the given node.""" + if isinstance(node, LeafNode): + yield node + elif isinstance(node, InnerNode): + for child in node.children: + yield from collect_leafs(child) + + +def nearest_neighbor_distances(points: Sequence[T]) -> list[float]: + """Brute force calculation of nearest neighbor distances with a + complexity of O(n!). + """ + return [ + min(point.distance(p) for p in points[index + 1 :]) + for index, point in enumerate(points[:-1]) + ] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/shape.py b/.venv/lib/python3.12/site-packages/ezdxf/math/shape.py new file mode 100644 index 0000000..5966d26 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/shape.py @@ -0,0 +1,140 @@ +# Copyright (c) 2019-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional, Iterator, TYPE_CHECKING, overload +import math +from ezdxf.math import Vec2, UVec, Matrix44 + + +__all__ = ["Shape2d"] + +if TYPE_CHECKING: + from ezdxf.math import BoundingBox2d + + +class Shape2d: + """Construction tools for 2D shapes. + + A 2D geometry object as list of :class:`Vec2` objects, vertices can be + moved, rotated and scaled. + + Args: + vertices: iterable of :class:`Vec2` compatible objects. + + """ + + def __init__(self, vertices: Optional[Iterable[UVec]] = None): + from ezdxf.npshapes import NumpyPoints2d + + _vec2: Iterator[Vec2] | None = None + if vertices is not None: + _vec2 = Vec2.generate(vertices) + self.np_vertices = NumpyPoints2d(_vec2) + + @property + def vertices(self) -> list[Vec2]: + return self.np_vertices.vertices() + + @property + def bounding_box(self) -> BoundingBox2d: + """Returns the bounding box of the shape.""" + return self.np_vertices.bbox() + + def copy(self) -> Shape2d: + clone = self.__class__() + clone.np_vertices = self.np_vertices.clone() + return clone + + __copy__ = copy + + def translate(self, vector: UVec) -> None: + """Translate shape about `vector`.""" + offset = Vec2(vector) + self.np_vertices.transform_inplace(Matrix44.translate(offset.x, offset.y, 0)) + + def scale(self, sx: float = 1.0, sy: float = 1.0) -> None: + """Scale shape about `sx` in x-axis and `sy` in y-axis.""" + self.np_vertices.transform_inplace(Matrix44.scale(sx, sy, 1)) + + def scale_uniform(self, scale: float) -> None: + """Scale shape uniform about `scale` in x- and y-axis.""" + self.np_vertices.transform_inplace(Matrix44.scale(scale, scale, 1)) + + def rotate(self, angle: float, center: Optional[UVec] = None) -> None: + """Rotate shape around rotation `center` about `angle` in degrees.""" + self.rotate_rad(math.radians(angle), center) + + def rotate_rad(self, angle: float, center: Optional[UVec] = None) -> None: + """Rotate shape around rotation `center` about `angle` in radians.""" + m = Matrix44.z_rotate(angle) + if center is not None: + p = Vec2(center) + m = ( + Matrix44.translate(-p.x, -p.y, 0) + @ m + @ Matrix44.translate(p.x, p.y, 0) + ) + self.np_vertices.transform_inplace(m) + + def offset(self, offset: float, closed: bool = False) -> Shape2d: + """Returns a new offset shape, for more information see also + :func:`ezdxf.math.offset_vertices_2d` function. + + Args: + offset: line offset perpendicular to direction of shape segments + defined by vertices order, offset > ``0`` is 'left' of line + segment, offset < ``0`` is 'right' of line segment + closed: ``True`` to handle as closed shape + + """ + from ezdxf.math.offset2d import offset_vertices_2d + + return self.__class__( + offset_vertices_2d( + self.np_vertices.vertices(), offset=offset, closed=closed + ) + ) + + def convex_hull(self) -> Shape2d: + """Returns convex hull as new shape.""" + from ezdxf.math.construct2d import convex_hull_2d + + return self.__class__(convex_hull_2d(self.np_vertices.vertices())) + + # Sequence interface + def __len__(self) -> int: + """Returns `count` of vertices.""" + return len(self.np_vertices) + + @overload + def __getitem__(self, item: int) -> Vec2: ... + @overload + def __getitem__(self, item: slice) -> list[Vec2]: ... + def __getitem__(self, item: int | slice) -> Vec2|list[Vec2]: + """Get vertex by index `item`, supports ``list`` like slicing.""" + np_vertices = self.np_vertices.np_vertices() + if isinstance(item, int): + return Vec2(np_vertices[item]) + else: + return Vec2.list(np_vertices[item]) + + def append(self, vertex: UVec) -> None: + """Append single `vertex`. + + Args: + vertex: vertex as :class:`Vec2` compatible object + + """ + self.extend((vertex,)) + + def extend(self, vertices: Iterable[UVec]) -> None: + """Append multiple `vertices`. + + Args: + vertices: iterable of vertices as :class:`Vec2` compatible objects + + """ + from ezdxf.npshapes import NumpyPoints2d + + new_vertices = self.np_vertices.vertices() + Vec2.list(vertices) + self.np_vertices = NumpyPoints2d(new_vertices) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/transformtools.py b/.venv/lib/python3.12/site-packages/ezdxf/math/transformtools.py new file mode 100644 index 0000000..164c673 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/transformtools.py @@ -0,0 +1,327 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING +import math +from ezdxf.math import ( + Vec3, + Vec2, + UVec, + X_AXIS, + Y_AXIS, + Z_AXIS, + Matrix44, + sign, + OCS, + arc_angle_span_rad, +) + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic + +__all__ = [ + "TransformError", + "NonUniformScalingError", + "InsertTransformationError", + "transform_extrusion", + "transform_thickness_and_extrusion_without_ocs", + "OCSTransform", + "WCSTransform", + "InsertCoordinateSystem", +] + +_PLACEHOLDER_OCS = OCS() +DEG = 180.0 / math.pi # radians to degrees +RADIANS = math.pi / 180.0 # degrees to radians + + +class TransformError(Exception): + pass + + +class NonUniformScalingError(TransformError): + pass + + +class InsertTransformationError(TransformError): + pass + + +def transform_thickness_and_extrusion_without_ocs( + entity: DXFGraphic, m: Matrix44 +) -> None: + if entity.dxf.hasattr("thickness"): + thickness = entity.dxf.thickness + reflection = sign(thickness) + thickness = m.transform_direction(entity.dxf.extrusion * thickness) + entity.dxf.thickness = thickness.magnitude * reflection + entity.dxf.extrusion = thickness.normalize() + elif entity.dxf.hasattr("extrusion"): # without thickness? + extrusion = m.transform_direction(entity.dxf.extrusion) + entity.dxf.extrusion = extrusion.normalize() + + +def transform_extrusion(extrusion: UVec, m: Matrix44) -> tuple[Vec3, bool]: + """Transforms the old `extrusion` vector into a new extrusion vector. + Returns the new extrusion vector and a boolean value: ``True`` if the new + OCS established by the new extrusion vector has a uniform scaled xy-plane, + else ``False``. + + The new extrusion vector is perpendicular to plane defined by the + transformed x- and y-axis. + + Args: + extrusion: extrusion vector of the old OCS + m: transformation matrix + + Returns: + + """ + ocs = OCS(extrusion) + ocs_x_axis_in_wcs = ocs.to_wcs(X_AXIS) + ocs_y_axis_in_wcs = ocs.to_wcs(Y_AXIS) + x_axis, y_axis = m.transform_directions((ocs_x_axis_in_wcs, ocs_y_axis_in_wcs)) + + # Check for uniform scaled xy-plane: + is_uniform = math.isclose( + x_axis.magnitude_square, y_axis.magnitude_square, abs_tol=1e-9 + ) + new_extrusion = x_axis.cross(y_axis).normalize() + return new_extrusion, is_uniform + + +class OCSTransform: + def __init__(self, extrusion: Vec3 | None = None, m: Matrix44 | None = None): + if m is None: + self.m = Matrix44() + else: + self.m = m + self.scale_uniform: bool = True + if extrusion is None: # fill in dummy values + self._reset_ocs(_PLACEHOLDER_OCS, _PLACEHOLDER_OCS, True) + else: + new_extrusion, scale_uniform = transform_extrusion(extrusion, m) + self._reset_ocs(OCS(extrusion), OCS(new_extrusion), scale_uniform) + + def _reset_ocs(self, old_ocs: OCS, new_ocs: OCS, scale_uniform: bool) -> None: + self.old_ocs = old_ocs + self.new_ocs = new_ocs + self.scale_uniform = scale_uniform + + @property + def old_extrusion(self) -> Vec3: + return self.old_ocs.uz + + @property + def new_extrusion(self) -> Vec3: + return self.new_ocs.uz + + @classmethod + def from_ocs( + cls, old: OCS, new: OCS, m: Matrix44, scale_uniform=True + ) -> OCSTransform: + ocs = cls(m=m) + ocs._reset_ocs(old, new, scale_uniform) + return ocs + + def transform_length(self, length: UVec, reflection=1.0) -> float: + """Returns magnitude of `length` direction vector transformed from + old OCS into new OCS including `reflection` correction applied. + """ + return self.m.transform_direction(self.old_ocs.to_wcs(length)).magnitude * sign( + reflection + ) + + def transform_width(self, width: float) -> float: + """Transform the width of a linear OCS entity from the old OCS + into the new OCS. (LWPOLYLINE!) + """ + abs_width = abs(width) + if abs_width > 1e-12: # assume a uniform scaling! + return max( + self.transform_length((abs_width, 0, 0)), + self.transform_length((0, abs_width, 0)), + ) + return 0.0 + + transform_scale_factor = transform_length + + def transform_ocs_direction(self, direction: Vec3) -> Vec3: + """Transform an OCS direction from the old OCS into the new OCS.""" + # OCS origin is ALWAYS the WCS origin! + old_wcs_direction = self.old_ocs.to_wcs(direction) + new_wcs_direction = self.m.transform_direction(old_wcs_direction) + return self.new_ocs.from_wcs(new_wcs_direction) + + def transform_thickness(self, thickness: float) -> float: + """Transform the thickness attribute of an OCS entity from the old OCS + into the new OCS. + + Thickness is always applied in the z-axis direction of the OCS + a.k.a. extrusion vector. + + """ + # Only the z-component of the thickness vector transformed into the + # new OCS is relevant for the extrusion in the direction of the new + # OCS z-axis. + # Input and output thickness can be negative! + new_ocs_thickness = self.transform_ocs_direction(Vec3(0, 0, thickness)) + return new_ocs_thickness.z + + def transform_vertex(self, vertex: UVec) -> Vec3: + """Returns vertex transformed from old OCS into new OCS.""" + return self.new_ocs.from_wcs(self.m.transform(self.old_ocs.to_wcs(vertex))) + + def transform_2d_vertex(self, vertex: UVec, elevation: float) -> Vec2: + """Returns 2D vertex transformed from old OCS into new OCS.""" + v = Vec3(vertex).replace(z=elevation) + return Vec2(self.new_ocs.from_wcs(self.m.transform(self.old_ocs.to_wcs(v)))) + + def transform_direction(self, direction: UVec) -> Vec3: + """Returns direction transformed from old OCS into new OCS.""" + return self.new_ocs.from_wcs( + self.m.transform_direction(self.old_ocs.to_wcs(direction)) + ) + + def transform_angle(self, angle: float) -> float: + """Returns angle (in radians) from old OCS transformed into new OCS.""" + return self.transform_direction(Vec3.from_angle(angle)).angle + + def transform_deg_angle(self, angle: float) -> float: + """Returns angle (in degrees) from old OCS transformed into new OCS.""" + return self.transform_angle(angle * RADIANS) * DEG + + def transform_ccw_arc_angles(self, start: float, end: float) -> tuple[float, float]: + """Returns arc start- and end angle (in radians) from old OCS + transformed into new OCS in counter-clockwise orientation. + """ + old_angle_span = arc_angle_span_rad(start, end) # always >= 0 + new_start = self.transform_angle(start) + new_end = self.transform_angle(end) + if math.isclose(old_angle_span, math.pi): # semicircle + old_angle_span = 1.0 # arbitrary angle span + check = self.transform_angle(start + old_angle_span) + new_angle_span = arc_angle_span_rad(new_start, check) + elif math.isclose(old_angle_span, math.tau): + # preserve full circle span + return new_start, new_start + math.tau + else: + new_angle_span = arc_angle_span_rad(new_start, new_end) + + # 2022-07-07: relative tolerance reduced from 1e-9 to 1e-8 for issue #702 + if math.isclose(old_angle_span, new_angle_span, rel_tol=1e-8): + return new_start, new_end + else: # reversed angle orientation + return new_end, new_start + + def transform_ccw_arc_angles_deg( + self, start: float, end: float + ) -> tuple[float, float]: + """Returns start- and end angle (in degrees) from old OCS transformed + into new OCS in counter-clockwise orientation. + """ + start, end = self.transform_ccw_arc_angles(start * RADIANS, end * RADIANS) + return start * DEG, end * DEG + + def transform_scale_vector(self, vec: Vec3) -> Vec3: + ocs = self.old_ocs + ux, uy, uz = self.m.transform_directions((ocs.ux, ocs.uy, ocs.uz)) + x_scale = ux.magnitude * vec.x + y_scale = uy.magnitude * vec.y + z_scale = uz.magnitude * vec.z + expected_uy = uz.cross(ux).normalize() + if not expected_uy.isclose(uy.normalize(), abs_tol=1e-12): + # new y-axis points into opposite direction: + y_scale = -y_scale + return Vec3(x_scale, y_scale, z_scale) + + +class WCSTransform: + def __init__(self, m: Matrix44): + self.m = m + new_x = m.transform_direction(X_AXIS) + new_y = m.transform_direction(Y_AXIS) + new_z = m.transform_direction(Z_AXIS) + new_x_mag_squ = new_x.magnitude_square + self.has_uniform_xy_scaling = math.isclose( + new_x_mag_squ, new_y.magnitude_square + ) + self.has_uniform_xyz_scaling = self.has_uniform_xy_scaling and math.isclose( + new_x_mag_squ, new_z.magnitude_square + ) + self.uniform_scale = self.transform_length(1.0) + + def transform_length(self, value: float, axis: str = "x") -> float: + if axis == "x": + v = Vec3(value, 0, 0) + elif axis == "y": + v = Vec3(0, value, 0) + elif axis == "z": + v = Vec3(0, 0, value) + else: + raise ValueError(f"invalid axis '{axis}'") + return self.m.transform_direction(v).magnitude + + +class InsertCoordinateSystem: + def __init__( + self, + insert: UVec, + scale: tuple[float, float, float], + rotation: float, + extrusion: UVec, + ): + """Defines an INSERT coordinate system. + + Args: + insert: insertion location + scale: scaling factors for x-, y- and z-axis + rotation: rotation angle around the extrusion vector in degrees + extrusion: extrusion vector which defines the :ref:`OCS` + + """ + self.insert = Vec3(insert) + self.scale_factor_x = float(scale[0]) + self.scale_factor_y = float(scale[1]) + self.scale_factor_z = float(scale[2]) + self.rotation = float(rotation) + self.extrusion = Vec3(extrusion) + + def transform(self, m: Matrix44, tol=1e-9) -> InsertCoordinateSystem: + """Returns the transformed INSERT coordinate system. + + Args: + m: transformation matrix + tol: tolerance value + + """ + ocs = OCS(self.extrusion) + + # Transform source OCS axis into the target coordinate system: + ux, uy, uz = m.transform_directions((ocs.ux, ocs.uy, ocs.uz)) + + # Calculate new axis scaling factors: + x_scale = ux.magnitude * self.scale_factor_x + y_scale = uy.magnitude * self.scale_factor_y + z_scale = uz.magnitude * self.scale_factor_z + + ux = ux.normalize() + uy = uy.normalize() + uz = uz.normalize() + # check for orthogonal x-, y- and z-axis + if abs(ux.dot(uz)) > tol or abs(ux.dot(uy)) > tol or abs(uz.dot(uy)) > tol: + raise InsertTransformationError("Non-orthogonal target system.") + + # expected y-axis for an orthogonal right-handed coordinate system: + expected_uy = uz.cross(ux) + if not expected_uy.isclose(uy, abs_tol=tol): + # new y-axis points into opposite direction: + y_scale = -y_scale + + ocs_transform = OCSTransform.from_ocs(OCS(self.extrusion), OCS(uz), m) + return InsertCoordinateSystem( + insert=ocs_transform.transform_vertex(self.insert), + scale=(x_scale, y_scale, z_scale), + rotation=ocs_transform.transform_deg_angle(self.rotation), + extrusion=uz, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/triangulation.py b/.venv/lib/python3.12/site-packages/ezdxf/math/triangulation.py new file mode 100644 index 0000000..6030b38 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/triangulation.py @@ -0,0 +1,106 @@ +# Copyright (c) 2022-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Iterator, Sequence +import ezdxf +from ezdxf.math import Vec2, UVec, Vec3, safe_normal_vector, OCS + +from ._mapbox_earcut import earcut + +if ezdxf.options.use_c_ext: + try: + from ezdxf.acc.mapbox_earcut import earcut # type: ignore + except ImportError: + pass + +__all__ = [ + "mapbox_earcut_2d", + "mapbox_earcut_3d", +] + + +def mapbox_earcut_2d( + exterior: Iterable[UVec], holes: Iterable[Iterable[UVec]] | None = None +) -> list[Sequence[Vec2]]: + """Mapbox triangulation algorithm with hole support for 2D polygons. + + Implements a modified ear slicing algorithm, optimized by z-order + curve hashing and extended to handle holes, twisted polygons, degeneracies + and self-intersections in a way that doesn't guarantee correctness of + triangulation, but attempts to always produce acceptable results for + practical data. + + Source: https://github.com/mapbox/earcut + + Args: + exterior: exterior polygon as iterable of :class:`Vec2` objects + holes: iterable of holes as iterable of :class:`Vec2` objects, a hole + with single point represents a `Steiner point`_. + + Returns: + yields the result as 3-tuples of :class:`Vec2` objects + + .. _Steiner point: https://en.wikipedia.org/wiki/Steiner_point_(computational_geometry) + + """ + points = Vec2.list(exterior) + if len(points) == 0: + return [] + holes_: list[list[Vec2]] = [] + if holes: + holes_ = [Vec2.list(hole) for hole in holes] + return earcut(points, holes_) + + +def mapbox_earcut_3d( + exterior: Iterable[UVec], holes: Iterable[Iterable[UVec]] | None = None +) -> Iterator[Sequence[Vec3]]: + """Mapbox triangulation algorithm with hole support for flat 3D polygons. + + Implements a modified ear slicing algorithm, optimized by z-order + curve hashing and extended to handle holes, twisted polygons, degeneracies + and self-intersections in a way that doesn't guarantee correctness of + triangulation, but attempts to always produce acceptable results for + practical data. + + Source: https://github.com/mapbox/earcut + + Args: + exterior: exterior polygon as iterable of :class:`Vec3` objects + holes: iterable of holes as iterable of :class:`Vec3` objects, a hole + with single point represents a `Steiner point`_. + + Returns: + yields the result as 3-tuples of :class:`Vec3` objects + + Raise: + TypeError: invalid input data type + ZeroDivisionError: normal vector calculation failed + + """ + polygon = Vec3.list(exterior) + if len(polygon) == 0: + return + + if polygon[0].isclose(polygon[-1]): + polygon.pop() + count = len(polygon) + if count < 3: + return + if count == 3: + yield polygon[0], polygon[1], polygon[2] + return + + ocs = OCS(safe_normal_vector(polygon)) + elevation = ocs.from_wcs(polygon[0]).z + exterior_ocs = list(ocs.points_from_wcs(polygon)) + holes_ocs: list[list[Vec3]] = [] + if holes: + holes_ocs = [list(ocs.points_from_wcs(hole)) for hole in holes] + + # Vec3 supports the _Point protocol in _mapbox_earcut.py + # required attributes: x, y + for triangle in earcut(exterior_ocs, holes_ocs): + yield tuple( + ocs.points_to_wcs(Vec3(v.x, v.y, elevation) for v in triangle) + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/math/ucs.py b/.venv/lib/python3.12/site-packages/ezdxf/math/ucs.py new file mode 100644 index 0000000..4d51aaa --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/math/ucs.py @@ -0,0 +1,517 @@ +# Copyright (c) 2018-2024 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Sequence, Iterable, Optional, Iterator +from ezdxf.math import Vec3, UVec, X_AXIS, Y_AXIS, Z_AXIS, Matrix44 +from ezdxf.colors import RGB + +if TYPE_CHECKING: + from ezdxf.layouts import BaseLayout + +__all__ = ["OCS", "UCS", "PassTroughUCS"] + + +def render_axis( + layout: BaseLayout, + start: UVec, + points: Sequence[UVec], + colors: RGB = RGB(1, 3, 5), +) -> None: + for point, color in zip(points, colors): + layout.add_line(start, point, dxfattribs={"color": color}) + + +_1_OVER_64 = 1.0 / 64.0 + + +class OCS: + """Establish an :ref:`OCS` for a given extrusion vector. + + Args: + extrusion: extrusion vector. + + """ + + def __init__(self, extrusion: UVec = Z_AXIS): + Az = Vec3(extrusion).normalize() + self.transform = not Az.isclose(Z_AXIS) + if self.transform: + if (abs(Az.x) < _1_OVER_64) and (abs(Az.y) < _1_OVER_64): + Ax = Y_AXIS.cross(Az) + else: + Ax = Z_AXIS.cross(Az) + Ax = Ax.normalize() + Ay = Az.cross(Ax).normalize() + self.matrix = Matrix44.ucs(Ax, Ay, Az) + + @property + def ux(self) -> Vec3: + """x-axis unit vector""" + return self.matrix.ux if self.transform else X_AXIS + + @property + def uy(self) -> Vec3: + """y-axis unit vector""" + return self.matrix.uy if self.transform else Y_AXIS + + @property + def uz(self) -> Vec3: + """z-axis unit vector""" + return self.matrix.uz if self.transform else Z_AXIS + + def from_wcs(self, point: UVec) -> Vec3: + """Returns OCS vector for WCS `point`.""" + p3 = Vec3(point) + if self.transform: + return self.matrix.ocs_from_wcs(p3) + else: + return p3 + + def points_from_wcs(self, points: Iterable[UVec]) -> Iterator[Vec3]: + """Returns iterable of OCS vectors from WCS `points`.""" + _points = Vec3.generate(points) + if self.transform: + from_wcs = self.matrix.ocs_from_wcs + for point in _points: + yield from_wcs(point) + else: + yield from _points + + def to_wcs(self, point: UVec) -> Vec3: + """Returns WCS vector for OCS `point`.""" + if self.transform: + return self.matrix.ocs_to_wcs(point) + else: + return Vec3(point) + + def points_to_wcs(self, points: Iterable[UVec]) -> Iterator[Vec3]: + """Returns iterable of WCS vectors for OCS `points`.""" + _points = Vec3.generate(points) + if self.transform: + to_wcs = self.matrix.ocs_to_wcs + for point in _points: + yield to_wcs(point) + else: + yield from _points + + def render_axis( + self, + layout: BaseLayout, + length: float = 1, + colors: RGB = RGB(1, 3, 5), + ) -> None: + """Render axis as 3D lines into a `layout`.""" + render_axis( + layout, + start=(0, 0, 0), + points=( + self.to_wcs(X_AXIS * length), + self.to_wcs(Y_AXIS * length), + self.to_wcs(Z_AXIS * length), + ), + colors=colors, + ) + + +class UCS: + """Establish a user coordinate system (:ref:`UCS`). The UCS is defined by + the origin and two unit vectors for the x-, y- or z-axis, all axis in + :ref:`WCS`. The missing axis is the cross product of the given axis. + + If x- and y-axis are ``None``: ux = ``(1, 0, 0)``, uy = ``(0, 1, 0)``, + uz = ``(0, 0, 1)``. + + Unit vectors don't have to be normalized, normalization is done at + initialization, this is also the reason why scaling gets lost by copying or + rotating. + + Args: + origin: defines the UCS origin in world coordinates + ux: defines the UCS x-axis as vector in :ref:`WCS` + uy: defines the UCS y-axis as vector in :ref:`WCS` + uz: defines the UCS z-axis as vector in :ref:`WCS` + + """ + + def __init__( + self, + origin: UVec = (0, 0, 0), + ux: Optional[UVec] = None, + uy: Optional[UVec] = None, + uz: Optional[UVec] = None, + ): + if ux is None and uy is None: + _ux: Vec3 = X_AXIS + _uy: Vec3 = Y_AXIS + _uz: Vec3 = Z_AXIS + elif ux is None: + _uy = Vec3(uy).normalize() + _uz = Vec3(uz).normalize() + _ux = Vec3(uy).cross(uz).normalize() + elif uy is None: + _ux = Vec3(ux).normalize() + _uz = Vec3(uz).normalize() + _uy = Vec3(uz).cross(ux).normalize() + elif uz is None: + _ux = Vec3(ux).normalize() + _uy = Vec3(uy).normalize() + _uz = Vec3(ux).cross(uy).normalize() + else: # all axis are given + _ux = Vec3(ux).normalize() + _uy = Vec3(uy).normalize() + _uz = Vec3(uz).normalize() + + self.matrix: Matrix44 = Matrix44.ucs(_ux, _uy, _uz, Vec3(origin)) + + @property + def ux(self) -> Vec3: + """x-axis unit vector""" + return self.matrix.ux + + @property + def uy(self) -> Vec3: + """y-axis unit vector""" + return self.matrix.uy + + @property + def uz(self) -> Vec3: + """z-axis unit vector""" + return self.matrix.uz + + @property + def origin(self) -> Vec3: + """Returns the origin""" + return self.matrix.origin + + @origin.setter + def origin(self, v: UVec) -> None: + """Set origin.""" + self.matrix.origin = v + + def copy(self) -> UCS: + """Returns a copy of this UCS.""" + return UCS(self.origin, self.ux, self.uy, self.uz) + + def to_wcs(self, point: Vec3) -> Vec3: + """Returns WCS point for UCS `point`.""" + return self.matrix.transform(point) + + def points_to_wcs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + """Returns iterable of WCS vectors for UCS `points`.""" + return self.matrix.transform_vertices(points) + + def direction_to_wcs(self, vector: Vec3) -> Vec3: + """Returns WCS direction for UCS `vector` without origin adjustment.""" + return self.matrix.transform_direction(vector) + + def from_wcs(self, point: Vec3) -> Vec3: + """Returns UCS point for WCS `point`.""" + return self.matrix.ucs_vertex_from_wcs(point) + + def points_from_wcs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + """Returns iterable of UCS vectors from WCS `points`.""" + from_wcs = self.from_wcs + for point in points: + yield from_wcs(point) + + def direction_from_wcs(self, vector: Vec3) -> Vec3: + """Returns UCS vector for WCS `vector` without origin adjustment.""" + return self.matrix.ucs_direction_from_wcs(vector) + + def to_ocs(self, point: Vec3) -> Vec3: + """Returns OCS vector for UCS `point`. + + The :class:`OCS` is defined by the z-axis of the :class:`UCS`. + + """ + wpoint = self.to_wcs(point) + return OCS(self.uz).from_wcs(wpoint) + + def points_to_ocs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + """Returns iterable of OCS vectors for UCS `points`. + + The :class:`OCS` is defined by the z-axis of the :class:`UCS`. + + Args: + points: iterable of UCS vertices + + """ + wcs = self.to_wcs + ocs = OCS(self.uz) + for point in points: + yield ocs.from_wcs(wcs(point)) + + def to_ocs_angle_deg(self, angle: float) -> float: + """Transforms `angle` from current UCS to the parent coordinate system + (most likely the WCS) including the transformation to the OCS + established by the extrusion vector :attr:`UCS.uz`. + + Args: + angle: in UCS in degrees + + """ + return self.ucs_direction_to_ocs_direction( + Vec3.from_deg_angle(angle) + ).angle_deg + + def to_ocs_angle_rad(self, angle: float) -> float: + """Transforms `angle` from current UCS to the parent coordinate system + (most likely the WCS) including the transformation to the OCS + established by the extrusion vector :attr:`UCS.uz`. + + Args: + angle: in UCS in radians + + """ + return self.ucs_direction_to_ocs_direction(Vec3.from_angle(angle)).angle + + def ucs_direction_to_ocs_direction(self, direction: Vec3) -> Vec3: + """Transforms UCS `direction` vector into OCS direction vector of the + parent coordinate system (most likely the WCS), target OCS is defined by + the UCS z-axis. + """ + return OCS(self.uz).from_wcs(self.direction_to_wcs(direction)) + + def rotate(self, axis: UVec, angle: float) -> UCS: + """Returns a new rotated UCS, with the same origin as the source UCS. + The rotation vector is located in the origin and has :ref:`WCS` + coordinates e.g. (0, 0, 1) is the WCS z-axis as rotation vector. + + Args: + axis: arbitrary rotation axis as vector in :ref:`WCS` + angle: rotation angle in radians + + """ + t = Matrix44.axis_rotate(Vec3(axis), angle) + ux, uy, uz = t.transform_vertices([self.ux, self.uy, self.uz]) + return UCS(origin=self.origin, ux=ux, uy=uy, uz=uz) + + def rotate_local_x(self, angle: float) -> UCS: + """Returns a new rotated UCS, rotation axis is the local x-axis. + + Args: + angle: rotation angle in radians + + """ + t = Matrix44.axis_rotate(self.ux, angle) + uy, uz = t.transform_vertices([self.uy, self.uz]) + return UCS(origin=self.origin, ux=self.ux, uy=uy, uz=uz) + + def rotate_local_y(self, angle: float) -> UCS: + """Returns a new rotated UCS, rotation axis is the local y-axis. + + Args: + angle: rotation angle in radians + + """ + t = Matrix44.axis_rotate(self.uy, angle) + ux, uz = t.transform_vertices([self.ux, self.uz]) + return UCS(origin=self.origin, ux=ux, uy=self.uy, uz=uz) + + def rotate_local_z(self, angle: float) -> UCS: + """Returns a new rotated UCS, rotation axis is the local z-axis. + + Args: + angle: rotation angle in radians + + """ + t = Matrix44.axis_rotate(self.uz, angle) + ux, uy = t.transform_vertices([self.ux, self.uy]) + return UCS(origin=self.origin, ux=ux, uy=uy, uz=self.uz) + + def shift(self, delta: UVec) -> UCS: + """Shifts current UCS by `delta` vector and returns `self`. + + Args: + delta: shifting vector + + """ + self.origin += Vec3(delta) + return self + + def moveto(self, location: UVec) -> UCS: + """Place current UCS at new origin `location` and returns `self`. + + Args: + location: new origin in WCS + + """ + self.origin = Vec3(location) + return self + + def transform(self, m: Matrix44) -> UCS: + """General inplace transformation interface, returns `self` (floating + interface). + + Args: + m: 4x4 transformation matrix (:class:`ezdxf.math.Matrix44`) + + """ + self.matrix *= m + return self + + @property + def is_cartesian(self) -> bool: + """Returns ``True`` if cartesian coordinate system.""" + return self.matrix.is_cartesian + + @staticmethod + def from_x_axis_and_point_in_xy( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the x-axis vector + and an arbitrary point in the xy-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: x-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the xy-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + x_axis = Vec3(axis) + z_axis = x_axis.cross(Vec3(point) - origin) + return UCS(origin=origin, ux=x_axis, uz=z_axis) + + @staticmethod + def from_x_axis_and_point_in_xz( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the x-axis vector + and an arbitrary point in the xz-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: x-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the xz-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + x_axis = Vec3(axis) + xz_vector = Vec3(point) - origin + y_axis = xz_vector.cross(x_axis) + return UCS(origin=origin, ux=x_axis, uy=y_axis) + + @staticmethod + def from_y_axis_and_point_in_xy( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the y-axis vector + and an arbitrary point in the xy-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: y-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the xy-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + y_axis = Vec3(axis) + xy_vector = Vec3(point) - origin + z_axis = xy_vector.cross(y_axis) + return UCS(origin=origin, uy=y_axis, uz=z_axis) + + @staticmethod + def from_y_axis_and_point_in_yz( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the y-axis vector + and an arbitrary point in the yz-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: y-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the yz-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + y_axis = Vec3(axis) + yz_vector = Vec3(point) - origin + x_axis = yz_vector.cross(y_axis) + return UCS(origin=origin, ux=x_axis, uy=y_axis) + + @staticmethod + def from_z_axis_and_point_in_xz( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the z-axis vector + and an arbitrary point in the xz-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: z-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the xz-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + z_axis = Vec3(axis) + y_axis = z_axis.cross(Vec3(point) - origin) + return UCS(origin=origin, uy=y_axis, uz=z_axis) + + @staticmethod + def from_z_axis_and_point_in_yz( + origin: UVec, axis: UVec, point: UVec + ) -> UCS: + """Returns a new :class:`UCS` defined by the origin, the z-axis vector + and an arbitrary point in the yz-plane. + + Args: + origin: UCS origin as (x, y, z) tuple in :ref:`WCS` + axis: z-axis vector as (x, y, z) tuple in :ref:`WCS` + point: arbitrary point unlike the origin in the yz-plane as + (x, y, z) tuple in :ref:`WCS` + + """ + z_axis = Vec3(axis) + yz_vector = Vec3(point) - origin + x_axis = yz_vector.cross(z_axis) + return UCS(origin=origin, ux=x_axis, uz=z_axis) + + def render_axis( + self, + layout: BaseLayout, + length: float = 1, + colors: RGB = RGB(1, 3, 5), + ): + """Render axis as 3D lines into a `layout`.""" + render_axis( + layout, + start=self.origin, + points=( + self.to_wcs(X_AXIS * length), + self.to_wcs(Y_AXIS * length), + self.to_wcs(Z_AXIS * length), + ), + colors=colors, + ) + + +class PassTroughUCS(UCS): + """UCS is equal to the WCS and OCS (extrusion = 0, 0, 1)""" + + def __init__(self): + super().__init__() + + def to_wcs(self, point: Vec3) -> Vec3: + return point + + def points_to_wcs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + return iter(points) + + def to_ocs(self, point: Vec3) -> Vec3: + return point + + def points_to_ocs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + return iter(points) + + def to_ocs_angle_deg(self, angle: float) -> float: + return angle + + def to_ocs_angle_rad(self, angle: float) -> float: + return angle + + def from_wcs(self, point: Vec3) -> Vec3: + return point + + def points_from_wcs(self, points: Iterable[Vec3]) -> Iterator[Vec3]: + return iter(points) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/messenger.py b/.venv/lib/python3.12/site-packages/ezdxf/messenger.py new file mode 100644 index 0000000..0531086 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/messenger.py @@ -0,0 +1,19 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from ezdxf.document import Drawing + + +class Messenger: + def __init__(self, doc: Drawing) -> None: + self.doc = doc + self.entitydb = doc.entitydb + + def broadcast(self, message_type: int, data: Any = None) -> None: + """Broadcast a message to all entities in the entity database.""" + # Receiver can change the entity database while processing the message. + for entity in list(self.entitydb.values()): + entity.notify(message_type, data) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/msgtypes.py b/.venv/lib/python3.12/site-packages/ezdxf/msgtypes.py new file mode 100644 index 0000000..29c6c86 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/msgtypes.py @@ -0,0 +1,9 @@ +# Copyright (c) 2014, Manfred Moitzi +# License: MIT License +# This module defines all message types for the internal messaging system: +# - ezdxf.messenger +# - DXFEntity.notify() + + +# Notify all entities to apply pending/temporary changes. +COMMIT_PENDING_CHANGES = 1 \ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/ezdxf/npshapes.py b/.venv/lib/python3.12/site-packages/ezdxf/npshapes.py new file mode 100644 index 0000000..686d000 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/npshapes.py @@ -0,0 +1,619 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Optional, Iterator, Sequence +from typing_extensions import Self, TypeAlias +import abc + +import numpy as np +import numpy.typing as npt + +from ezdxf.math import ( + Matrix44, + UVec, + Vec2, + Vec3, + has_clockwise_orientation, + Bezier3P, + Bezier4P, + BoundingBox2d, + BoundingBox, +) +from ezdxf.path import ( + Path, + Command, + PathElement, + LineTo, + MoveTo, + Curve3To, + Curve4To, + nesting, +) + +try: + from ezdxf.acc import np_support +except ImportError: + np_support = None + +__all__ = [ + "NumpyPath2d", + "NumpyPoints2d", + "NumpyPoints3d", + "NumpyShapesException", + "EmptyShapeError", + "to_qpainter_path", + "to_matplotlib_path", + "single_paths", + "orient_paths", +] + +# comparing Command. to ints is very slow +CMD_MOVE_TO = int(Command.MOVE_TO) +CMD_LINE_TO = int(Command.LINE_TO) +CMD_CURVE3_TO = int(Command.CURVE3_TO) +CMD_CURVE4_TO = int(Command.CURVE4_TO) + + +class NumpyShapesException(Exception): + pass + + +class EmptyShapeError(NumpyShapesException): + pass + + +CommandNumpyType: TypeAlias = np.int8 +VertexNumpyType: TypeAlias = np.float64 +EMPTY_SHAPE = np.array([], dtype=VertexNumpyType) +NO_COMMANDS = np.array([], dtype=CommandNumpyType) + + +class NumpyShape2d(abc.ABC): + """This is an optimization to store many 2D paths and polylines in a compact way + without sacrificing basic functions like transformation and bounding box calculation. + """ + + _vertices: npt.NDArray[VertexNumpyType] = EMPTY_SHAPE + + def extents(self) -> tuple[Vec2, Vec2]: + """Returns the extents of the bounding box as tuple (extmin, extmax).""" + v = self._vertices + if len(v) > 0: + return Vec2(v.min(0)), Vec2(v.max(0)) + else: + raise EmptyShapeError("empty shape has no extends") + + @abc.abstractmethod + def clone(self) -> Self: + ... + + def np_vertices(self) -> npt.NDArray[VertexNumpyType]: + return self._vertices + + def transform_inplace(self, m: Matrix44) -> None: + """Transforms the vertices of the shape inplace.""" + v = self._vertices + if len(v) == 0: + return + m.transform_array_inplace(v, 2) + + def vertices(self) -> list[Vec2]: + """Returns the shape vertices as list of :class:`Vec2` + e.g. [Vec2(1, 2), Vec2(3, 4), ...] + """ + return [Vec2(v) for v in self._vertices] + + def to_tuples(self) -> list[tuple[float, float]]: + """Returns the shape vertices as list of 2-tuples + e.g. [(1, 2), (3, 4), ...] + """ + return [tuple(v) for v in self._vertices] + + def to_list(self) -> list[list[float]]: + """Returns the shape vertices as list of lists + e.g. [[1, 2], [3, 4], ...] + """ + return self._vertices.tolist() + + def bbox(self) -> BoundingBox2d: + """Returns the bounding box of all vertices.""" + return BoundingBox2d(self.extents()) + + +class NumpyPoints2d(NumpyShape2d): + """Represents an array of 2D points stored as a ndarray.""" + + def __init__(self, points: Optional[Iterable[Vec2 | Vec3]]) -> None: + if points: + self._vertices = np.array( + [(v.x, v.y) for v in points], dtype=VertexNumpyType + ) + + def clone(self) -> Self: + clone = self.__class__(None) + clone._vertices = self._vertices.copy() + return clone + + __copy__ = clone + + def __len__(self) -> int: + return len(self._vertices) + + +class NumpyPath2d(NumpyShape2d): + """Represents a 2D path, the path control vertices and commands are stored as ndarray. + + This class cannot build paths from scratch and is therefore not a drop-in replacement + for the :class:`ezdxf.path.Path` class. Operations like transform and reverse are + done inplace to utilize the `numpy` capabilities. This behavior is different from the + :class:`ezdxf.path.Path` class!!! + + Construct new paths by the :class:`Path` class and convert them to + :class:`NumpyPath2d` instances:: + + path = Path((0, 0)) + path.line_to((50, 70)) + ... + path2d = NumpyPath2d(path) + + """ + + _commands: npt.NDArray[CommandNumpyType] + + def __init__(self, path: Optional[Path]) -> None: + if path is None: + self._vertices = EMPTY_SHAPE + self._commands = NO_COMMANDS + return + # (v.x, v.y) is 4x faster than Vec2(v), see profiling/numpy_array_setup.py + vertices = [(v.x, v.y) for v in path.control_vertices()] + if len(vertices) == 0: + try: # control_vertices() does not return the start point of empty paths + vertices = [Vec2(path.start)] + except IndexError: + vertices = [] + self._vertices = np.array(vertices, dtype=VertexNumpyType) + self._commands = np.array(path.command_codes(), dtype=CommandNumpyType) + + def __len__(self) -> int: + return len(self._commands) + + @property + def start(self) -> Vec2: + """Returns the start point as :class:`~ezdxf.math.Vec2` instance.""" + return Vec2(self._vertices[0]) + + @property + def end(self) -> Vec2: + """Returns the end point as :class:`~ezdxf.math.Vec2` instance.""" + return Vec2(self._vertices[-1]) + + def control_vertices(self) -> list[Vec2]: + return [Vec2(v) for v in self._vertices] + + def clone(self) -> Self: + clone = self.__class__(None) + clone._commands = self._commands.copy() + clone._vertices = self._vertices.copy() + return clone + + __copy__ = clone + + def command_codes(self) -> list[int]: + """Internal API.""" + return list(self._commands) + + def commands(self) -> Iterator[PathElement]: + vertices = self.vertices() + index = 1 + for cmd in self._commands: + if cmd == CMD_LINE_TO: + yield LineTo(vertices[index]) + index += 1 + elif cmd == CMD_CURVE3_TO: + yield Curve3To(vertices[index + 1], vertices[index]) + index += 2 + elif cmd == CMD_CURVE4_TO: + yield Curve4To( + vertices[index + 2], vertices[index], vertices[index + 1] + ) + index += 3 + elif cmd == CMD_MOVE_TO: + yield MoveTo(vertices[index]) + index += 1 + + def to_path(self) -> Path: + """Returns a new :class:`ezdxf.path.Path` instance.""" + vertices = [Vec3(v) for v in self._vertices] + commands = [Command(c) for c in self._commands] + return Path.from_vertices_and_commands(vertices, commands) + + @classmethod + def from_vertices( + cls, vertices: Iterable[Vec2 | Vec3], close: bool = False + ) -> Self: + new_path = cls(None) + vertices = list(vertices) + if len(vertices) == 0: + return new_path + if close and not vertices[0].isclose(vertices[-1]): + vertices.append(vertices[0]) + # (v.x, v.y) is 4x faster than Vec2(v), see profiling/numpy_array_setup.py + points = [(v.x, v.y) for v in vertices] + new_path._vertices = np.array(points, dtype=VertexNumpyType) + new_path._commands = np.full( + len(points) - 1, fill_value=CMD_LINE_TO, dtype=CommandNumpyType + ) + return new_path + + @property + def has_sub_paths(self) -> bool: + """Returns ``True`` if the path is a :term:`Multi-Path` object that + contains multiple sub-paths. + + """ + return CMD_MOVE_TO in self._commands + + @property + def is_closed(self) -> bool: + """Returns ``True`` if the start point is close to the end point.""" + if len(self._vertices) > 1: + return self.start.isclose(self.end) + return False + + @property + def has_lines(self) -> bool: + """Returns ``True`` if the path has any line segments.""" + return CMD_LINE_TO in self._commands + + @property + def has_curves(self) -> bool: + """Returns ``True`` if the path has any curve segments.""" + return CMD_CURVE3_TO in self._commands or CMD_CURVE4_TO in self._commands + + def sub_paths(self) -> list[Self]: + """Yield all sub-paths as :term:`Single-Path` objects. + + It's safe to call :meth:`sub_paths` on any path-type: + :term:`Single-Path`, :term:`Multi-Path` and :term:`Empty-Path`. + + """ + + def append_sub_path() -> None: + s: Self = self.__class__(None) + s._vertices = vertices[vtx_start_index : vtx_index + 1] # .copy() ? + s._commands = commands[cmd_start_index:cmd_index] # .copy() ? + sub_paths.append(s) + + commands = self._commands + if len(commands) == 0: + return [] + if CMD_MOVE_TO not in commands: + return [self] + + sub_paths: list[Self] = [] + vertices = self._vertices + vtx_start_index = 0 + vtx_index = 0 + cmd_start_index = 0 + cmd_index = 0 + for cmd in commands: + if cmd == CMD_LINE_TO: + vtx_index += 1 + elif cmd == CMD_CURVE3_TO: + vtx_index += 2 + elif cmd == CMD_CURVE4_TO: + vtx_index += 3 + elif cmd == CMD_MOVE_TO: + append_sub_path() + # MOVE_TO target vertex is the start vertex of the following path. + vtx_index += 1 + vtx_start_index = vtx_index + cmd_start_index = cmd_index + 1 + cmd_index += 1 + + if commands[-1] != CMD_MOVE_TO: + append_sub_path() + return sub_paths + + def has_clockwise_orientation(self) -> bool: + """Returns ``True`` if 2D path has clockwise orientation. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + if self.has_sub_paths: + raise TypeError("can't detect orientation of a multi-path object") + if np_support is None: + return has_clockwise_orientation(self.vertices()) + else: + return np_support.has_clockwise_orientation(self._vertices) + + def reverse(self) -> Self: + """Reverse path orientation inplace.""" + commands = self._commands + if not len(self._commands): + return self + if commands[-1] == CMD_MOVE_TO: + # The last move_to will become the first move_to. + # A move_to as first command just moves the start point and can be + # removed! + # There are never two consecutive MOVE_TO commands in a Path! + self._commands = np.flip(commands[:-1]).copy() + self._vertices = np.flip(self._vertices[:-1, ...], axis=0).copy() + else: + self._commands = np.flip(commands).copy() + self._vertices = np.flip(self._vertices, axis=0).copy() + return self + + def clockwise(self) -> Self: + """Apply clockwise orientation inplace. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + if not self.has_clockwise_orientation(): + self.reverse() + return self + + def counter_clockwise(self) -> Self: + """Apply counter-clockwise orientation inplace. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + + if self.has_clockwise_orientation(): + self.reverse() + return self + + def flattening(self, distance: float, segments: int = 4) -> Iterator[Vec2]: + """Flatten path to vertices as :class:`Vec2` instances.""" + if not len(self._commands): + return + + vertices = self.vertices() + start = vertices[0] + yield start + index = 1 + for cmd in self._commands: + if cmd == CMD_LINE_TO or cmd == CMD_MOVE_TO: + end_location = vertices[index] + index += 1 + yield end_location + elif cmd == CMD_CURVE3_TO: + ctrl, end_location = vertices[index : index + 2] + index += 2 + pts = Vec2.generate( + Bezier3P((start, ctrl, end_location)).flattening(distance, segments) + ) + next(pts) # skip first vertex + yield from pts + elif cmd == CMD_CURVE4_TO: + ctrl1, ctrl2, end_location = vertices[index : index + 3] + index += 3 + pts = Vec2.generate( + Bezier4P((start, ctrl1, ctrl2, end_location)).flattening( + distance, segments + ) + ) + next(pts) # skip first vertex + yield from pts + else: + raise ValueError(f"Invalid command: {cmd}") + start = end_location + + # Appending single commands (line_to, move_to, curve3_to, curve4_to) is not + # efficient, because numpy arrays do not grow dynamically, they are reallocated for + # every single command! + # Construct paths as ezdxf.path.Path and convert them to NumpyPath2d. + # Concatenation of NumpyPath2d objects is faster than extending Path objects + + def extend(self, paths: Sequence[NumpyPath2d]) -> None: + """Extend an existing path by appending additional paths. The paths are + connected by MOVE_TO commands if the end- and start point of sequential paths + are not coincident (multi-path). + """ + if not len(paths): + return + if not len(self._commands): + first = paths[0] + paths = paths[1:] + else: + first = self + + vertices: list[np.ndarray] = [first._vertices] + commands: list[np.ndarray] = [first._commands] + end: Vec2 = first.end + + for next_path in paths: + if len(next_path._commands) == 0: + continue + if not end.isclose(next_path.start): + commands.append(np.array((CMD_MOVE_TO,), dtype=CommandNumpyType)) + vertices.append(next_path._vertices) + else: + vertices.append(next_path._vertices[1:]) + end = next_path.end + commands.append(next_path._commands) + self._vertices = np.concatenate(vertices, axis=0) + self._commands = np.concatenate(commands) + + @staticmethod + def concatenate(paths: Sequence[NumpyPath2d]) -> NumpyPath2d: + """Returns a new path of concatenated paths. The paths are connected by + MOVE_TO commands if the end- and start point of sequential paths are not + coincident (multi-path). + """ + + if not paths: + return NumpyPath2d(None) + first = paths[0].clone() + first.extend(paths[1:]) + return first + + +def to_qpainter_path(paths: Iterable[NumpyPath2d]): + """Convert the given `paths` into a single :class:`QPainterPath`.""" + from ezdxf.addons.xqt import QPainterPath, QPointF + + paths = list(paths) + if len(paths) == 0: + raise ValueError("one or more paths required") + + qpath = QPainterPath() + for path in paths: + points = [QPointF(v.x, v.y) for v in path.vertices()] + qpath.moveTo(points[0]) + index = 1 + for cmd in path.command_codes(): + # using Command. slows down this function by a factor of 4!!! + if cmd == CMD_LINE_TO: + qpath.lineTo(points[index]) + index += 1 + elif cmd == CMD_CURVE3_TO: + qpath.quadTo(points[index], points[index + 1]) + index += 2 + elif cmd == CMD_CURVE4_TO: + qpath.cubicTo(points[index], points[index + 1], points[index + 2]) + index += 3 + elif cmd == CMD_MOVE_TO: + qpath.moveTo(points[index]) + index += 1 + return qpath + + +MPL_MOVETO = 1 +MPL_LINETO = 2 +MPL_CURVE3 = 3 +MPL_CURVE4 = 4 + +MPL_CODES = [ + (0,), # dummy + (MPL_LINETO,), + (MPL_CURVE3, MPL_CURVE3), + (MPL_CURVE4, MPL_CURVE4, MPL_CURVE4), + (MPL_MOVETO,), +] + + +def to_matplotlib_path(paths: Iterable[NumpyPath2d], *, detect_holes=False): + """Convert the given `paths` into a single :class:`matplotlib.path.Path`. + + Matplotlib requires counter-clockwise oriented outside paths and clockwise oriented + holes. Set the `detect_holes` argument to ``True`` if this path orientation is not + yet satisfied. + """ + from matplotlib.path import Path + + paths = list(paths) + if len(paths) == 0: + raise ValueError("one or more paths required") + + if detect_holes: + # path orientation for holes is important, see #939 + paths = orient_paths(paths) + + vertices: list[np.ndarray] = [] + codes: list[int] = [] + for path in paths: + vertices.append(path.np_vertices()) + codes.append(MPL_MOVETO) + for cmd in path.command_codes(): + codes.extend(MPL_CODES[cmd]) + points = np.concatenate(vertices) + try: + return Path(points, codes) + except Exception as e: + raise ValueError(f"matplotlib.path.Path({str(points)}, {str(codes)}): {str(e)}") + + +def single_paths(paths: Iterable[NumpyPath2d]) -> list[NumpyPath2d]: + single_paths_: list[NumpyPath2d] = [] + for p in paths: + sub_paths = p.sub_paths() + if sub_paths: + single_paths_.extend(sub_paths) + return single_paths_ + + +def orient_paths(paths: list[NumpyPath2d]) -> list[NumpyPath2d]: + """Returns a new list of paths, with outer paths oriented counter-clockwise and + holes oriented clockwise. + """ + sub_paths: list[NumpyPath2d] = single_paths(paths) + if len(sub_paths) < 2: + return paths + + polygons = nesting.make_polygon_structure(sub_paths) + outer_paths: list[NumpyPath2d] + holes: list[NumpyPath2d] + outer_paths, holes = nesting.winding_deconstruction(polygons) + + path: NumpyPath2d + for path in outer_paths: + path.counter_clockwise() + for path in holes: + path.clockwise() + return outer_paths + holes + + +class NumpyShape3d(abc.ABC): + """This is an optimization to store many 3D paths and polylines in a compact way + without sacrificing basic functions like transformation and bounding box calculation. + """ + + _vertices: npt.NDArray[VertexNumpyType] = EMPTY_SHAPE + + def extents(self) -> tuple[Vec3, Vec3]: + """Returns the extents of the bounding box as tuple (extmin, extmax).""" + v = self._vertices + if len(v) > 0: + return Vec3(v.min(0)), Vec3(v.max(0)) + else: + raise EmptyShapeError("empty shape has no extends") + + @abc.abstractmethod + def clone(self) -> Self: + ... + + def np_vertices(self) -> npt.NDArray[VertexNumpyType]: + return self._vertices + + def transform_inplace(self, m: Matrix44) -> None: + """Transforms the vertices of the shape inplace.""" + v = self._vertices + if len(v) == 0: + return + m.transform_array_inplace(v, 3) + + def vertices(self) -> list[Vec3]: + """Returns the shape vertices as list of :class:`Vec3`.""" + return [Vec3(v) for v in self._vertices] + + def bbox(self) -> BoundingBox: + """Returns the bounding box of all vertices.""" + return BoundingBox(self.extents()) + + +class NumpyPoints3d(NumpyShape3d): + """Represents an array of 3D points stored as a ndarray.""" + + def __init__(self, points: Optional[Iterable[UVec]]) -> None: + if points: + self._vertices = np.array( + [Vec3(v).xyz for v in points], dtype=VertexNumpyType + ) + + def clone(self) -> Self: + clone = self.__class__(None) + clone._vertices = self._vertices.copy() + return clone + + __copy__ = clone + + def __len__(self) -> int: + return len(self._vertices) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/path/__init__.py new file mode 100644 index 0000000..414169b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +# +# Ezdxf user: DO NOT IMPORT FROM ezdxf.path.* MODULES! +# import all Path() related classes and functions from ezdxf.path +# +# from ezdxf.path import Path, make_path, +# +from .commands import * +from .path import * +from .converter import * +from .tools import * +from .nesting import * +from .shapes import * diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..2f033cb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/commands.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/commands.cpython-312.pyc new file mode 100644 index 0000000..ca0330f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/commands.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/converter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/converter.cpython-312.pyc new file mode 100644 index 0000000..0d908ff Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/converter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/nesting.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/nesting.cpython-312.pyc new file mode 100644 index 0000000..74e953f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/nesting.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/path.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/path.cpython-312.pyc new file mode 100644 index 0000000..fd72d91 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/path.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/shapes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/shapes.cpython-312.pyc new file mode 100644 index 0000000..b1715e5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/shapes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/tools.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/tools.cpython-312.pyc new file mode 100644 index 0000000..db32293 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/path/__pycache__/tools.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/commands.py b/.venv/lib/python3.12/site-packages/ezdxf/path/commands.py new file mode 100644 index 0000000..0fbd86c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/commands.py @@ -0,0 +1,64 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import enum +from typing import NamedTuple, Union + +from ezdxf.math import Vec2, Vec3 + +__all__ = [ + "Command", + "AnyCurve", + "PathElement", + "LineTo", + "Curve3To", + "Curve4To", + "MoveTo", +] + + +@enum.unique +class Command(enum.IntEnum): + LINE_TO = 1 # (LINE_TO, end vertex) + CURVE3_TO = 2 # (CURVE3_TO, end vertex, ctrl) quadratic bezier + CURVE4_TO = 3 # (CURVE4_TO, end vertex, ctrl1, ctrl2) cubic bezier + MOVE_TO = 4 # (MOVE_TO, end vertex), creates a gap and starts a sub-path + + +class LineTo(NamedTuple): + end: Vec2|Vec3 + + @property + def type(self): + return Command.LINE_TO + + +class MoveTo(NamedTuple): + end: Vec2|Vec3 + + @property + def type(self): + return Command.MOVE_TO + + +class Curve3To(NamedTuple): + end: Vec2|Vec3 + ctrl: Vec2|Vec3 + + @property + def type(self): + return Command.CURVE3_TO + + +class Curve4To(NamedTuple): + end: Vec2|Vec3 + ctrl1: Vec2|Vec3 + ctrl2: Vec2|Vec3 + + @property + def type(self): + return Command.CURVE4_TO + + +AnyCurve = (Command.CURVE3_TO, Command.CURVE4_TO) +PathElement = Union[LineTo, Curve3To, Curve4To, MoveTo] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/converter.py b/.venv/lib/python3.12/site-packages/ezdxf/path/converter.py new file mode 100644 index 0000000..89c1f98 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/converter.py @@ -0,0 +1,960 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + List, + Iterable, + Iterator, + Union, + Optional, + Callable, + Type, + TypeVar, +) +from typing_extensions import TypeAlias +from functools import singledispatch, partial +import logging + +from ezdxf.math import ( + ABS_TOL, + Vec2, + Vec3, + NULLVEC, + Z_AXIS, + OCS, + Bezier3P, + Bezier4P, + ConstructionEllipse, + BSpline, + have_bezier_curves_g1_continuity, + fit_points_to_cad_cv, + UVec, + Matrix44, +) +from ezdxf.lldxf import const +from ezdxf.entities import ( + LWPolyline, + Polyline, + Hatch, + Line, + Spline, + Ellipse, + Arc, + Circle, + Solid, + Trace, + Face3d, + Viewport, + Image, + Helix, + Wipeout, + MPolygon, + BoundaryPaths, + AbstractBoundaryPath, + PolylinePath, + EdgePath, + LineEdge, + ArcEdge, + EllipseEdge, + SplineEdge, +) +from ezdxf.entities.polygon import DXFPolygon +from .path import Path +from .commands import Command +from . import tools +from .nesting import group_paths + +__all__ = [ + "make_path", + "to_lines", + "to_polylines3d", + "to_lwpolylines", + "to_polylines2d", + "to_hatches", + "to_mpolygons", + "to_bsplines_and_vertices", + "to_splines_and_polylines", + "from_hatch", + "from_hatch_ocs", + "from_hatch_boundary_path", + "from_hatch_edge_path", + "from_hatch_polyline_path", + "from_vertices", +] + +MAX_DISTANCE = 0.01 +MIN_SEGMENTS = 4 +G1_TOL = 1e-4 +TPolygon = TypeVar("TPolygon", Hatch, MPolygon) +BoundaryFactory = Callable[[BoundaryPaths, Path, int], None] +logger = logging.getLogger("ezdxf") + + +@singledispatch +def make_path(entity, segments: int = 1, level: int = 4) -> Path: + """Factory function to create a single :class:`Path` object from a DXF + entity. + + Args: + entity: DXF entity + segments: minimal count of cubic Bézier-curves for elliptical arcs + level: subdivide level for SPLINE approximation + + Raises: + TypeError: for unsupported DXF types + + """ + # Complete documentation is path.rst, because Sphinx auto-function + # renders for each overloaded function a signature, which is ugly + # and wrong signatures for multiple overloaded function + # e.g. 3 equal signatures for type Solid. + raise TypeError(f"unsupported DXF type: {entity.dxftype()}") + + +@make_path.register(LWPolyline) +def _from_lwpolyline(lwpolyline: LWPolyline, **kwargs) -> Path: + path = Path() + tools.add_2d_polyline( + path, + lwpolyline.get_points("xyb"), + close=lwpolyline.closed, + ocs=lwpolyline.ocs(), + elevation=lwpolyline.dxf.elevation, + segments=kwargs.get("segments", 1), + ) + return path + + +@make_path.register(Polyline) +def _from_polyline(polyline: Polyline, **kwargs) -> Path: + if polyline.is_polygon_mesh or polyline.is_poly_face_mesh: + raise TypeError("Unsupported DXF type PolyMesh or PolyFaceMesh") + + path = Path() + if len(polyline.vertices) == 0: + return path + + if polyline.is_3d_polyline: + return from_vertices(polyline.points(), polyline.is_closed) + + points = [vertex.format("xyb") for vertex in polyline.vertices] + ocs = polyline.ocs() + if polyline.dxf.hasattr("elevation"): + elevation = Vec3(polyline.dxf.elevation).z + else: + # the elevation attribute is mandatory, but if it's missing + # take the elevation value of the first vertex. + elevation = Vec3(polyline.vertices[0].dxf.location).z + tools.add_2d_polyline( + path, + points, + close=polyline.is_closed, + ocs=ocs, + elevation=elevation, + segments=kwargs.get("segments", 1), + ) + return path + + +@make_path.register(Helix) +@make_path.register(Spline) +def _from_spline(spline: Spline, **kwargs) -> Path: + level = kwargs.get("level", 4) + path = Path() + tools.add_spline(path, spline.construction_tool(), level=level, reset=True) + return path + + +@make_path.register(Ellipse) +def _from_ellipse(ellipse: Ellipse, **kwargs) -> Path: + segments = kwargs.get("segments", 1) + path = Path() + tools.add_ellipse(path, ellipse.construction_tool(), segments=segments, reset=True) + return path + + +@make_path.register(Line) +def _from_line(line: Line, **kwargs) -> Path: + path = Path(line.dxf.start) + path.line_to(line.dxf.end) + return path + + +@make_path.register(Arc) +def _from_arc(arc: Arc, **kwargs) -> Path: + segments = kwargs.get("segments", 1) + path = Path() + radius = abs(arc.dxf.radius) + if radius > 1e-12: + ellipse = ConstructionEllipse.from_arc( + center=arc.dxf.center, + radius=radius, + extrusion=arc.dxf.extrusion, + start_angle=arc.dxf.start_angle, + end_angle=arc.dxf.end_angle, + ) + tools.add_ellipse(path, ellipse, segments=segments, reset=True) + return path + + +@make_path.register(Circle) +def _from_circle(circle: Circle, **kwargs) -> Path: + segments = kwargs.get("segments", 1) + path = Path() + radius = abs(circle.dxf.radius) + if radius > 1e-12: + ellipse = ConstructionEllipse.from_arc( + center=circle.dxf.center, + radius=radius, + extrusion=circle.dxf.extrusion, + ) + tools.add_ellipse(path, ellipse, segments=segments, reset=True) + return path + + +@make_path.register(Face3d) +@make_path.register(Trace) +@make_path.register(Solid) +def _from_quadrilateral(solid: "Solid", **kwargs) -> Path: + vertices = solid.wcs_vertices() + return from_vertices(vertices, close=True) + + +@make_path.register(Viewport) +def _from_viewport(vp: "Viewport", **kwargs) -> Path: + if vp.has_extended_clipping_path: + handle = vp.dxf.clipping_boundary_handle + if handle != "0" and vp.doc: # exist + db = vp.doc.entitydb + if db: # exist + # Many DXF entities can define a clipping path: + clipping_entity = vp.doc.entitydb.get(handle) + if clipping_entity: # exist + return make_path(clipping_entity, **kwargs) + # Return bounding box: + return from_vertices(vp.clipping_rect_corners(), close=True) + + +@make_path.register(Wipeout) +@make_path.register(Image) +def _from_image(image: "Image", **kwargs) -> Path: + return from_vertices(image.boundary_path_wcs(), close=True) + + +@make_path.register(MPolygon) +@make_path.register(Hatch) +def _from_hatch(hatch: Hatch, **kwargs) -> Path: + ocs = hatch.ocs() + elevation = hatch.dxf.elevation.z + offset = NULLVEC + if isinstance(hatch, MPolygon): + offset = hatch.dxf.get("offset_vector", NULLVEC) + try: + paths = [ + from_hatch_boundary_path(boundary, ocs, elevation, offset=offset) + for boundary in hatch.paths + ] + except const.DXFStructureError: + # TODO: fix problems beforehand in audit process? see issue #1081 + logger.warning(f"invalid data in {str(hatch)}") + return Path() + # looses the boundary path state: + return tools.to_multi_path(paths) + + +def from_hatch(hatch: DXFPolygon, offset: Vec3 = NULLVEC) -> Iterator[Path]: + """Yield all HATCH/MPOLYGON boundary paths as separated :class:`Path` objects in WCS + coordinates. + """ + ocs = hatch.ocs() + elevation = hatch.dxf.elevation.z + for boundary in hatch.paths: + p = from_hatch_boundary_path(boundary, ocs, elevation=elevation, offset=offset) + if p.has_sub_paths: + yield from p.sub_paths() + else: + yield p + + +def from_hatch_ocs(hatch: DXFPolygon, offset: Vec3 = NULLVEC) -> Iterator[Path]: + """Yield all HATCH/MPOLYGON boundary paths as separated :class:`Path` objects in OCS + coordinates. Elevation and offset is applied to all vertices. + + .. versionadded:: 1.1 + + """ + elevation = hatch.dxf.elevation.z + for boundary in hatch.paths: + p = from_hatch_boundary_path(boundary, elevation=elevation, offset=offset) + if p.has_sub_paths: + yield from p.sub_paths() + else: + yield p + + +def from_hatch_boundary_path( + boundary: AbstractBoundaryPath, + ocs: Optional[OCS] = None, + elevation: float = 0, + offset: Vec3 = NULLVEC, # ocs offset! +) -> Path: + """Returns a :class:`Path` object from a :class:`~ezdxf.entities.Hatch` + polyline- or edge path. + """ + if isinstance(boundary, EdgePath): + p = from_hatch_edge_path(boundary, ocs, elevation) + elif isinstance(boundary, PolylinePath): + p = from_hatch_polyline_path(boundary, ocs, elevation) + else: + raise TypeError(type(boundary)) + + if offset and ocs is not None: # only for MPOLYGON + # assume offset is in OCS + offset = ocs.to_wcs(offset.replace(z=elevation)) + p = p.transform(Matrix44.translate(offset.x, offset.y, offset.z)) + + # attach path type information + p.user_data = const.BoundaryPathState.from_flags(boundary.path_type_flags) + return p + + +def from_hatch_polyline_path( + polyline: PolylinePath, ocs: Optional[OCS] = None, elevation: float = 0 +) -> Path: + """Returns a :class:`Path` object from a :class:`~ezdxf.entities.Hatch` + polyline path. + """ + path = Path() + tools.add_2d_polyline( + path, + polyline.vertices, # list[(x, y, bulge)] + close=polyline.is_closed, + ocs=ocs or OCS(), + elevation=elevation, + ) + return path + + +def from_hatch_edge_path( + edges: EdgePath, + ocs: Optional[OCS] = None, + elevation: float = 0, +) -> Path: + """Returns a :class:`Path` object from a :class:`~ezdxf.entities.Hatch` + edge path. + + """ + + def line(edge: LineEdge): + start = wcs(edge.start) + end = wcs(edge.end) + segment = Path(start) + segment.line_to(end) + return segment + + def arc(edge: ArcEdge): + x, y, *_ = edge.center + # from_arc() requires OCS data: + # Note: clockwise oriented arcs are converted to counter + # clockwise arcs at the loading stage! + # See: ezdxf.entities.boundary_paths.ArcEdge.load_tags() + ellipse = ConstructionEllipse.from_arc( + center=(x, y, elevation), + radius=edge.radius, + extrusion=extrusion, + start_angle=edge.start_angle, + end_angle=edge.end_angle, + ) + segment = Path() + tools.add_ellipse(segment, ellipse, reset=True) + return segment + + def ellipse(edge: EllipseEdge): + ocs_ellipse = edge.construction_tool() + # ConstructionEllipse has WCS representation: + # Note: clockwise oriented ellipses are converted to counter + # clockwise ellipses at the loading stage! + # See: ezdxf.entities.boundary_paths.EllipseEdge.load_tags() + ellipse = ConstructionEllipse( + center=wcs(ocs_ellipse.center.replace(z=float(elevation))), + major_axis=wcs_tangent(ocs_ellipse.major_axis), + ratio=ocs_ellipse.ratio, + extrusion=extrusion, + start_param=ocs_ellipse.start_param, + end_param=ocs_ellipse.end_param, + ) + segment = Path() + tools.add_ellipse(segment, ellipse, reset=True) + return segment + + def spline(edge: SplineEdge): + control_points = [wcs(p) for p in edge.control_points] + if len(control_points) == 0: + fit_points = [wcs(p) for p in edge.fit_points] + if len(fit_points): + bspline = from_fit_points(edge, fit_points) + else: + # No control points and no fit points: + # DXF structure error + return + else: + bspline = from_control_points(edge, control_points) + segment = Path() + tools.add_spline(segment, bspline, reset=True) + return segment + + def from_fit_points(edge: SplineEdge, fit_points): + tangents = None + if edge.start_tangent and edge.end_tangent: + tangents = ( + wcs_tangent(edge.start_tangent), + wcs_tangent(edge.end_tangent), + ) + return fit_points_to_cad_cv( # only a degree of 3 is supported + fit_points, + tangents=tangents, + ) + + def from_control_points(edge: SplineEdge, control_points): + return BSpline( + control_points=control_points, + order=edge.degree + 1, + knots=edge.knot_values, + weights=edge.weights if edge.weights else None, + ) + + def wcs(vertex: UVec) -> Vec3: + return _wcs(Vec3(vertex[0], vertex[1], elevation)) + + def wcs_tangent(vertex: UVec) -> Vec3: + return _wcs(Vec3(vertex[0], vertex[1], 0)) + + def _wcs(vec3: Vec3) -> Vec3: + if ocs and ocs.transform: + return ocs.to_wcs(vec3) + else: + return vec3 + + extrusion = ocs.uz if ocs else Z_AXIS + path = Path() + loop: Optional[Path] = None + for edge in edges: + next_segment: Optional[Path] = None + if isinstance(edge, LineEdge): + next_segment = line(edge) + elif isinstance(edge, ArcEdge): + if abs(edge.radius) > ABS_TOL: + next_segment = arc(edge) + elif isinstance(edge, EllipseEdge): + if not Vec2(edge.major_axis).is_null: + next_segment = ellipse(edge) + elif isinstance(edge, SplineEdge): + next_segment = spline(edge) + else: + raise TypeError(type(edge)) + + if next_segment is None: + continue + + if loop is None: + loop = next_segment + continue + + if loop.end.isclose(next_segment.start): + # end of current loop connects to the start of the next segment + loop.append_path(next_segment) + elif loop.end.isclose(next_segment.end): + # end of current loop connects to the end of the next segment + loop.append_path(next_segment.reversed()) + elif loop.start.isclose(next_segment.end): + # start of the current loop connects to the end of the next segment + next_segment.append_path(loop) + loop = next_segment + elif loop.start.isclose(next_segment.start): + # start of the current loop connects to the start of the next segment + loop = loop.reversed() + loop.append_path(next_segment) + else: # gap between current loop and next segment + if loop.is_closed: # start a new loop + path.extend_multi_path(loop) + loop = next_segment # start a new loop + # behavior changed in version v0.18 based on issue #706: + else: # close the gap by a straight line and append the segment + loop.append_path(next_segment) + + if loop is not None: + loop.close() + path.extend_multi_path(loop) + return path # multi path + + +def from_vertices(vertices: Iterable[UVec], close=False) -> Path: + """Returns a :class:`Path` object from the given `vertices`.""" + _vertices = Vec3.list(vertices) + if len(_vertices) < 2: + return Path() + path = Path(start=_vertices[0]) + for vertex in _vertices[1:]: + if not path.end.isclose(vertex): + path.line_to(vertex) + if close: + path.close() + return path + + +def to_lwpolylines( + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> Iterator[LWPolyline]: + """Convert the given `paths` into :class:`~ezdxf.entities.LWPolyline` + entities. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + paths: iterable of :class:`Path` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + iterable of :class:`~ezdxf.entities.LWPolyline` objects + + """ + if isinstance(paths, Path): + paths = [paths] + else: + paths = list(paths) + if len(paths) == 0: + return + extrusion = Vec3(extrusion) + reference_point = Vec3(paths[0].start) + dxfattribs = dict(dxfattribs or {}) + if not Z_AXIS.isclose(extrusion): + ocs, elevation = _get_ocs(extrusion, reference_point) + paths = tools.transform_paths_to_ocs(paths, ocs) + dxfattribs["elevation"] = elevation + dxfattribs["extrusion"] = extrusion + elif reference_point.z != 0: + dxfattribs["elevation"] = reference_point.z + + for path in tools.single_paths(paths): + if len(path) > 0: + p = LWPolyline.new(dxfattribs=dxfattribs) + p.append_points(path.flattening(distance, segments), format="xy") + yield p + + +def _get_ocs(extrusion: Vec3, reference_point: Vec3) -> tuple[OCS, float]: + ocs = OCS(extrusion) + elevation = ocs.from_wcs(reference_point).z + return ocs, elevation + + +def to_polylines2d( + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> Iterator[Polyline]: + """Convert the given `paths` into 2D :class:`~ezdxf.entities.Polyline` + entities. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + paths: iterable of :class:`Path` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + iterable of 2D :class:`~ezdxf.entities.Polyline` objects + + """ + if isinstance(paths, Path): + paths = [paths] + else: + paths = list(paths) + if len(paths) == 0: + return + extrusion = Vec3(extrusion) + reference_point = Vec3(paths[0].start) + dxfattribs = dict(dxfattribs or {}) + if not Z_AXIS.isclose(extrusion): + ocs, elevation = _get_ocs(extrusion, reference_point) + paths = tools.transform_paths_to_ocs(paths, ocs) + dxfattribs["elevation"] = Vec3(0, 0, elevation) + dxfattribs["extrusion"] = extrusion + elif reference_point.z != 0: + dxfattribs["elevation"] = Vec3(0, 0, reference_point.z) + + for path in tools.single_paths(paths): + if len(path) > 0: + p = Polyline.new(dxfattribs=dxfattribs) + p.append_vertices(path.flattening(distance, segments)) + p.new_seqend() + yield p + + +def to_hatches( + paths: Iterable[Path], + *, + edge_path: bool = True, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + g1_tol: float = G1_TOL, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> Iterator[Hatch]: + """Convert the given `paths` into :class:`~ezdxf.entities.Hatch` entities. + Uses LWPOLYLINE paths for boundaries without curves and edge paths, build + of LINE and SPLINE edges, as boundary paths for boundaries including curves. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + paths: iterable of :class:`Path` objects + edge_path: ``True`` for edge paths build of LINE and SPLINE edges, + ``False`` for only LWPOLYLINE paths as boundary paths + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve to flatten LWPOLYLINE paths + g1_tol: tolerance for G1 continuity check to separate SPLINE edges + extrusion: extrusion vector to all paths + dxfattribs: additional DXF attribs + + Returns: + iterable of :class:`~ezdxf.entities.Hatch` objects + + """ + boundary_factory: BoundaryFactory + if edge_path: + # noinspection PyTypeChecker + boundary_factory = partial( + build_edge_path, distance=distance, segments=segments, g1_tol=g1_tol + ) + else: + # noinspection PyTypeChecker + boundary_factory = partial( + build_poly_path, distance=distance, segments=segments + ) + + yield from _polygon_converter(Hatch, paths, boundary_factory, extrusion, dxfattribs) + + +def to_mpolygons( + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> Iterator[MPolygon]: + """Convert the given `paths` into :class:`~ezdxf.entities.MPolygon` entities. + In contrast to HATCH, MPOLYGON supports only polyline boundary paths. + All curves will be approximated. + + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + paths: iterable of :class:`Path` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve to flatten LWPOLYLINE paths + extrusion: extrusion vector to all paths + dxfattribs: additional DXF attribs + + Returns: + iterable of :class:`~ezdxf.entities.MPolygon` objects + + """ + # noinspection PyTypeChecker + boundary_factory: BoundaryFactory = partial( + build_poly_path, distance=distance, segments=segments + ) + dxfattribs = dict(dxfattribs or {}) + dxfattribs.setdefault("fill_color", const.BYLAYER) + + yield from _polygon_converter( + MPolygon, paths, boundary_factory, extrusion, dxfattribs + ) + + +def build_edge_path( + boundaries: BoundaryPaths, + path: Path, + flags: int, + distance: float, + segments: int, + g1_tol: float, +): + if path.has_curves: # Edge path with LINE and SPLINE edges + edge_path = boundaries.add_edge_path(flags) + for edge in to_bsplines_and_vertices(path, g1_tol=g1_tol): + if isinstance(edge, BSpline): + edge_path.add_spline( + control_points=edge.control_points, + degree=edge.degree, + knot_values=edge.knots(), + ) + else: # add LINE edges + prev = edge[0] + for p in edge[1:]: + edge_path.add_line(prev, p) + prev = p + else: # Polyline boundary path + boundaries.add_polyline_path( + Vec2.generate(path.flattening(distance, segments)), flags=flags + ) + + +def build_poly_path( + boundaries: BoundaryPaths, + path: Path, + flags: int, + distance: float, + segments: int, +): + boundaries.add_polyline_path( + # Vec2 removes the z-axis, which would be interpreted as bulge value! + Vec2.generate(path.flattening(distance, segments)), + flags=flags, + ) + + +def _polygon_converter( + cls: Type[TPolygon], + paths: Iterable[Path], + add_boundary: BoundaryFactory, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> Iterator[TPolygon]: + if isinstance(paths, Path): + paths = [paths] + else: + paths = list(paths) + if len(paths) == 0: + return + + extrusion = Vec3(extrusion) + reference_point = paths[0].start + _dxfattribs: dict = dict(dxfattribs or {}) + if not Z_AXIS.isclose(extrusion): + ocs, elevation = _get_ocs(extrusion, reference_point) + paths = tools.transform_paths_to_ocs(paths, ocs) + _dxfattribs["elevation"] = Vec3(0, 0, elevation) + _dxfattribs["extrusion"] = extrusion + elif reference_point.z != 0: + _dxfattribs["elevation"] = Vec3(0, 0, reference_point.z) + _dxfattribs.setdefault("solid_fill", 1) + _dxfattribs.setdefault("pattern_name", "SOLID") + _dxfattribs.setdefault("color", const.BYLAYER) + + for group in group_paths(tools.single_paths(paths)): + if len(group) == 0: + continue + polygon = cls.new(dxfattribs=_dxfattribs) + boundaries = polygon.paths + external = group[0] + external.close() + add_boundary(boundaries, external, 1) + for hole in group[1:]: + hole.close() + add_boundary(boundaries, hole, 0) + yield polygon + + +def to_polylines3d( + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + dxfattribs=None, +) -> Iterator[Polyline]: + """Convert the given `paths` into 3D :class:`~ezdxf.entities.Polyline` + entities. + + Args: + paths: iterable of :class:`Path` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + dxfattribs: additional DXF attribs + + Returns: + iterable of 3D :class:`~ezdxf.entities.Polyline` objects + + """ + if isinstance(paths, Path): + paths = [paths] + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["flags"] = const.POLYLINE_3D_POLYLINE + for path in tools.single_paths(paths): + if len(path) > 0: + p = Polyline.new(dxfattribs=dxfattribs) + p.append_vertices(path.flattening(distance, segments)) + p.new_seqend() + yield p + + +def to_lines( + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + dxfattribs=None, +) -> Iterator[Line]: + """Convert the given `paths` into :class:`~ezdxf.entities.Line` entities. + + Args: + paths: iterable of :class:`Path` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + dxfattribs: additional DXF attribs + + Returns: + iterable of :class:`~ezdxf.entities.Line` objects + + """ + if isinstance(paths, Path): + paths = [paths] + dxfattribs = dict(dxfattribs or {}) + prev_vertex = None + for path in tools.single_paths(paths): + if len(path) == 0: + continue + for vertex in path.flattening(distance, segments): + if prev_vertex is None: + prev_vertex = vertex + continue + dxfattribs["start"] = prev_vertex + dxfattribs["end"] = vertex + yield Line.new(dxfattribs=dxfattribs) + prev_vertex = vertex + prev_vertex = None + + +PathParts: TypeAlias = Union[BSpline, List[Vec3]] + + +def to_bsplines_and_vertices(path: Path, g1_tol: float = G1_TOL) -> Iterator[PathParts]: + """Convert a :class:`Path` object into multiple cubic B-splines and + polylines as lists of vertices. Breaks adjacent Bèzier without G1 + continuity into separated B-splines. + + Args: + path: :class:`Path` objects + g1_tol: tolerance for G1 continuity check + + Returns: + :class:`~ezdxf.math.BSpline` and lists of :class:`~ezdxf.math.Vec3` + + """ + from ezdxf.math import bezier_to_bspline + + def to_vertices(): + points = [polyline[0][0]] + for line in polyline: + points.append(line[1]) + return points + + def to_bspline(): + b1 = bezier[0] + _g1_continuity_curves = [b1] + for b2 in bezier[1:]: + if have_bezier_curves_g1_continuity(b1, b2, g1_tol): + _g1_continuity_curves.append(b2) + else: + yield bezier_to_bspline(_g1_continuity_curves) + _g1_continuity_curves = [b2] + b1 = b2 + + if _g1_continuity_curves: + yield bezier_to_bspline(_g1_continuity_curves) + + curves = [] + for path in tools.single_paths([path]): + prev = path.start + for cmd in path: + if cmd.type == Command.CURVE3_TO: + curve = Bezier3P([prev, cmd.ctrl, cmd.end]) # type: ignore + elif cmd.type == Command.CURVE4_TO: + curve = Bezier4P([prev, cmd.ctrl1, cmd.ctrl2, cmd.end]) # type: ignore + elif cmd.type == Command.LINE_TO: + curve = (prev, cmd.end) + else: + raise ValueError + curves.append(curve) + prev = cmd.end + + bezier: list = [] + polyline: list = [] + for curve in curves: + if isinstance(curve, tuple): + if bezier: + yield from to_bspline() + bezier.clear() + polyline.append(curve) + else: + if polyline: + yield to_vertices() + polyline.clear() + bezier.append(curve) + + if bezier: + yield from to_bspline() + if polyline: + yield to_vertices() + + +def to_splines_and_polylines( + paths: Iterable[Path], + *, + g1_tol: float = G1_TOL, + dxfattribs=None, +) -> Iterator[Union[Spline, Polyline]]: + """Convert the given `paths` into :class:`~ezdxf.entities.Spline` and 3D + :class:`~ezdxf.entities.Polyline` entities. + + Args: + paths: iterable of :class:`Path` objects + g1_tol: tolerance for G1 continuity check + dxfattribs: additional DXF attribs + + Returns: + iterable of :class:`~ezdxf.entities.Line` objects + + """ + if isinstance(paths, Path): + paths = [paths] + dxfattribs = dict(dxfattribs or {}) + + for path in tools.single_paths(paths): + for data in to_bsplines_and_vertices(path, g1_tol): + if isinstance(data, BSpline): + spline = Spline.new(dxfattribs=dxfattribs) + spline.apply_construction_tool(data) + yield spline + else: + attribs = dict(dxfattribs) + attribs["flags"] = const.POLYLINE_3D_POLYLINE + polyline = Polyline.new(dxfattribs=dxfattribs) + polyline.append_vertices(data) + polyline.new_seqend() + yield polyline diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/nesting.py b/.venv/lib/python3.12/site-packages/ezdxf/path/nesting.py new file mode 100644 index 0000000..335d911 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/nesting.py @@ -0,0 +1,185 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +""" +This module provides "nested Polygon" detection for multiple paths. + +Terminology +----------- + +exterior + creates a filled area, has counter-clockwise (ccw) winding + exterior := Path + +hole + creates an unfilled area, has clockwise winding (cw), + hole := Polygon + +polygon + list of nested paths: + polygon without a hole: [path] + polygon with 1 hole: [path, [path]] + polygon with 2 separated holes: [path, [path], [path]] + polygon with 2 nested holes: [path, [path, [path]]] + + polygon := [exterior, *hole] + +The result is a list of polygons: + +1 polygon returns: [[ext-path]] +2 separated polygons returns: [[ext-path], [ext-path, [hole-path]]] + +A hole is just another polygon, some render backends may require a distinct winding +order for nested paths like: ccw-cw-ccw-cw... + +[Exterior-ccw, + [Hole-Exterior-cw, + [Sub-Hole-ccw], + [Sub-Hole-ccw], + ], + [Hole-Exterior-cw], + [Hole-Exterior-cw], +] + +The implementation has to do some expensive tests, like check if a path is +inside of another path or if paths do overlap. A goal is to reduce this costs +by using proxy objects: + +Bounding Box Proxy +------------------ + +This implementation uses the bounding box of the path as proxy object, this is very fast +but not accurate, but can handle most of the real world scenarios, in the assumption +that most HATCHES are created from non-overlapping boundary paths. +Overlap detection and resolving is not possible. + +The input paths have to implement the SupportsBoundingBox protocol, which requires +only a method bbox() that returns a BoundingBox2d instance for the path. + +Sort by Area +------------ + +It is not possible for a path to contain another path with a larger area. + +""" +from __future__ import annotations +from typing import ( + Tuple, + Optional, + List, + Iterable, + Sequence, + Iterator, + TypeVar, +) +from typing_extensions import TypeAlias +from collections import namedtuple +from ezdxf.math import AbstractBoundingBox +from ezdxf.protocols import SupportsBoundingBox + + +__all__ = [ + "make_polygon_structure", + "winding_deconstruction", + "group_paths", + "flatten_polygons", +] + + +T = TypeVar("T", bound=SupportsBoundingBox) + +Polygon: TypeAlias = Tuple[T, Optional[List["Polygon"]]] +BoxStruct = namedtuple("BoxStruct", "bbox, path") + + +def make_polygon_structure(paths: Iterable[T]) -> list[Polygon]: + """Returns a recursive polygon structure from iterable `paths`, uses 2D + bounding boxes as fast detection objects. + + """ + + # Implements fast bounding box construction and fast inside check. + def area(item: BoxStruct) -> float: + size = item.bbox.size + return size.x * size.y + + def separate( + exterior: AbstractBoundingBox, candidates: list[BoxStruct] + ) -> tuple[list[BoxStruct], list[BoxStruct]]: + holes: list[BoxStruct] = [] + outside: list[BoxStruct] = [] + for candidate in candidates: + # Fast inside check: + (holes if exterior.inside(candidate.bbox.center) else outside).append( + candidate + ) + return holes, outside + + def polygon_structure(outside: list[BoxStruct]) -> list[list]: + polygons = [] + while outside: + exterior = outside.pop() # path with the largest area + # Get holes inside of exterior and returns the remaining paths + # outside of exterior: + holes, outside = separate(exterior.bbox, outside) + if holes: + # build nested hole structure: + # the largest hole could contain the smaller holes, + # and so on ... + holes = polygon_structure(holes) # type: ignore + polygons.append([exterior, *holes]) + return polygons + + def as_nested_paths(polygons) -> list: + return [ + polygon.path if isinstance(polygon, BoxStruct) else as_nested_paths(polygon) + for polygon in polygons + ] + + boxed_paths = [] + for path in paths: + bbox = path.bbox() + if bbox.has_data: + boxed_paths.append(BoxStruct(bbox, path)) + boxed_paths.sort(key=area) + return as_nested_paths(polygon_structure(boxed_paths)) + + +def winding_deconstruction( + polygons: list[Polygon], +) -> tuple[list[T], list[T]]: + """Flatten the nested polygon structure in a tuple of two lists, + the first list contains the paths which should be counter-clockwise oriented + and the second list contains the paths which should be clockwise oriented. + + The paths are not converted to this orientation. + + """ + + def deconstruct(polygons_, level): + for polygon in polygons_: + if isinstance(polygon, Sequence): + deconstruct(polygon, level + 1) + else: + # level 0 is the list of polygons + # level 1 = ccw, 2 = cw, 3 = ccw, 4 = cw, ... + (ccw_paths if (level % 2) else cw_paths).append(polygon) + + cw_paths: list[T] = [] + ccw_paths: list[T] = [] + deconstruct(polygons, 0) + return ccw_paths, cw_paths + + +def flatten_polygons(polygons: Polygon) -> Iterator[T]: + """Yield a flat representation of the given nested polygons.""" + for polygon in polygons: + if isinstance(polygon, Sequence): + yield from flatten_polygons(polygon) # type: ignore + else: + yield polygon # type: ignore # T + + +def group_paths(paths: Iterable[T]) -> list[list[T]]: + """Group separated paths and their inner holes as flat lists.""" + polygons = make_polygon_structure(paths) + return [list(flatten_polygons(polygon)) for polygon in polygons] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/path.py b/.venv/lib/python3.12/site-packages/ezdxf/path/path.py new file mode 100644 index 0000000..f154faf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/path.py @@ -0,0 +1,507 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Optional, + Iterator, + Iterable, + Any, + Callable, +) +from typing_extensions import Self +from ezdxf.math import ( + Vec3, + NULLVEC, + OCS, + Bezier3P, + Bezier4P, + Matrix44, + has_clockwise_orientation, + UVec, + BoundingBox, +) + +from .commands import ( + Command, + LineTo, + MoveTo, + Curve3To, + Curve4To, + PathElement, +) + +__all__ = ["Path"] + +MAX_DISTANCE = 0.01 +MIN_SEGMENTS = 4 +G1_TOL = 1e-4 +_slots = ("_vertices", "_start_index", "_commands", "_has_sub_paths", "_user_data") + + +class Path: + __slots__ = _slots + + def __init__(self, start: UVec = NULLVEC): + # stores all command vertices in a contiguous list: + self._vertices: list[Vec3] = [Vec3(start)] + # start index of each command + self._start_index: list[int] = [] + self._commands: list[Command] = [] + self._has_sub_paths = False + self._user_data: Any = None # should be immutable data! + + @classmethod + def from_vertices_and_commands( + cls, vertices: list[Vec3], command_codes: list[Command], user_data: Any = None + ) -> Self: + """Create path instances from a list of vertices and a list of commands.""" + # Used for fast conversion from NumpyPath2d to Path. + # This is "hacky" but also 8x faster than the correct way using only public + # methods and properties. + new_path = cls() + if len(vertices) == 0: + return new_path + new_path._vertices = vertices + new_path._commands = command_codes + new_path._start_index = make_vertex_index(command_codes) + new_path._has_sub_paths = any(cmd == Command.MOVE_TO for cmd in command_codes) + new_path._user_data = user_data + return new_path + + def transform(self, m: Matrix44) -> Self: + """Returns a new transformed path. + + Args: + m: transformation matrix of type :class:`~ezdxf.math.Matrix44` + + """ + new_path = self.clone() + new_path._vertices = list(m.transform_vertices(self._vertices)) + return new_path + + def bbox(self) -> BoundingBox: + """Returns the bounding box of all control vertices as + :class:`~ezdxf.math.BoundingBox` instance. + """ + return BoundingBox(self.control_vertices()) + + def __len__(self) -> int: + """Returns count of path elements.""" + return len(self._commands) + + def __getitem__(self, item) -> PathElement: + """Returns the path element at given index, slicing is not supported.""" + if isinstance(item, slice): + raise TypeError("slicing not supported") + cmd = self._commands[item] + index = self._start_index[item] + vertices = self._vertices + if cmd == Command.MOVE_TO: + return MoveTo(vertices[index]) + if cmd == Command.LINE_TO: + return LineTo(vertices[index]) + if cmd == Command.CURVE3_TO: # end, ctrl + return Curve3To(vertices[index + 1], vertices[index]) + if cmd == Command.CURVE4_TO: + return Curve4To( # end, ctrl1, ctrl2 + vertices[index + 2], + vertices[index], + vertices[index + 1], + ) + raise ValueError(f"Invalid command: {cmd}") + + def __iter__(self) -> Iterator[PathElement]: + return (self[i] for i in range(len(self._commands))) + + def commands(self) -> list[PathElement]: + """Returns all path elements as list.""" + return list(self.__iter__()) + + def __copy__(self) -> Self: + """Returns a new copy of :class:`Path` with shared immutable data.""" + copy = self.__class__() + # vertices itself are immutable - no copying required + copy._vertices = self._vertices.copy() + self._copy_properties(copy) + return copy + + def _copy_properties(self, clone: Path) -> None: + assert len(self._vertices) == len(clone._vertices) + clone._commands = self._commands.copy() + clone._start_index = self._start_index.copy() + clone._has_sub_paths = self._has_sub_paths + # copy by reference: user data should be immutable data! + clone._user_data = self._user_data + + clone = __copy__ + + @property + def user_data(self) -> Any: + """Attach arbitrary user data to a :class:`Path` object. + The user data is copied by reference, no deep copy is applied + therefore a mutable state is shared between copies. + """ + return self._user_data + + @user_data.setter + def user_data(self, data: Any): + self._user_data = data + + @property + def start(self) -> Vec3: + """:class:`Path` start point, resetting the start point of an empty + path is possible. + """ + return self._vertices[0] + + @start.setter + def start(self, location: UVec) -> None: + if self._commands: + raise ValueError("Requires an empty path.") + else: + self._vertices[0] = Vec3(location) + + @property + def end(self) -> Vec3: + """:class:`Path` end point.""" + return self._vertices[-1] + + def control_vertices(self) -> list[Vec3]: + """Yields all path control vertices in consecutive order.""" + if self._commands: + return list(self._vertices) + return [] + + def command_codes(self) -> list[int]: + """Internal API.""" + return list(self._commands) + + @property + def is_closed(self) -> bool: + """Returns ``True`` if the start point is close to the end point.""" + vertices = self._vertices + if len(vertices) > 1: + return vertices[0].isclose(vertices[-1]) + return False + + @property + def has_lines(self) -> bool: + """Returns ``True`` if the path has any line segments.""" + return Command.LINE_TO in self._commands + + @property + def has_curves(self) -> bool: + """Returns ``True`` if the path has any curve segments.""" + return ( + Command.CURVE4_TO in self._commands or Command.CURVE3_TO in self._commands + ) + + @property + def has_sub_paths(self) -> bool: + """Returns ``True`` if the path is a :term:`Multi-Path` object that + contains multiple sub-paths. + + """ + return self._has_sub_paths + + def has_clockwise_orientation(self) -> bool: + """Returns ``True`` if 2D path has clockwise orientation, ignores + z-axis of all control vertices. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + if self.has_sub_paths: + raise TypeError("can't detect orientation of a multi-path object") + return has_clockwise_orientation(self._vertices) + + def append_path_element(self, cmd: PathElement) -> None: + """Append a single path element.""" + t = cmd.type + if t == Command.LINE_TO: + self.line_to(cmd.end) + elif t == Command.MOVE_TO: + self.move_to(cmd.end) + elif t == Command.CURVE3_TO: + self.curve3_to(cmd.end, cmd.ctrl) # type: ignore + elif t == Command.CURVE4_TO: + self.curve4_to(cmd.end, cmd.ctrl1, cmd.ctrl2) # type: ignore + else: + raise ValueError(f"Invalid command: {t}") + + def line_to(self, location: UVec) -> None: + """Add a line from actual path end point to `location`.""" + self._commands.append(Command.LINE_TO) + self._start_index.append(len(self._vertices)) + self._vertices.append(Vec3(location)) + + def move_to(self, location: UVec) -> None: + """Start a new sub-path at `location`. This creates a gap between the + current end-point and the start-point of the new sub-path. This converts + the instance into a :term:`Multi-Path` object. + + If the :meth:`move_to` command is the first command, the start point of + the path will be reset to `location`. + + """ + commands = self._commands + if not commands: + self._vertices[0] = Vec3(location) + return + self._has_sub_paths = True + if commands[-1] == Command.MOVE_TO: + # replace last move to command + commands.pop() + self._vertices.pop() + self._start_index.pop() + commands.append(Command.MOVE_TO) + self._start_index.append(len(self._vertices)) + self._vertices.append(Vec3(location)) + + def curve3_to(self, location: UVec, ctrl: UVec) -> None: + """Add a quadratic Bèzier-curve from actual path end point to + `location`, `ctrl` is the control point for the quadratic Bèzier-curve. + """ + self._commands.append(Command.CURVE3_TO) + self._start_index.append(len(self._vertices)) + self._vertices.extend((Vec3(ctrl), Vec3(location))) + + def curve4_to(self, location: UVec, ctrl1: UVec, ctrl2: UVec) -> None: + """Add a cubic Bèzier-curve from actual path end point to `location`, + `ctrl1` and `ctrl2` are the control points for the cubic Bèzier-curve. + """ + self._commands.append(Command.CURVE4_TO) + self._start_index.append(len(self._vertices)) + self._vertices.extend((Vec3(ctrl1), Vec3(ctrl2), Vec3(location))) + + def close(self) -> None: + """Close path by adding a line segment from the end point to the start + point. + """ + if not self.is_closed: + self.line_to(self.start) + + def close_sub_path(self) -> None: + """Close last sub-path by adding a line segment from the end point to + the start point of the last sub-path. Behaves like :meth:`close` for + :term:`Single-Path` instances. + """ + if self.has_sub_paths: + start_point = self._start_of_last_sub_path() + assert ( + start_point is not None + ), "internal error: required MOVE_TO command not found" + if not self.end.isclose(start_point): + self.line_to(start_point) + else: + self.close() + + def _start_of_last_sub_path(self) -> Optional[Vec3]: + move_to = Command.MOVE_TO + commands = self._commands + index = len(commands) - 1 + # The first command at index 0 is never MOVE_TO! + while index > 0: + if commands[index] == move_to: + return self._vertices[self._start_index[index]] + index -= 1 + return None + + def reversed(self) -> Self: + """Returns a new :class:`Path` with reversed commands and control + vertices. + + """ + path = self.clone() + if not path._commands: + return path + if path._commands[-1] == Command.MOVE_TO: + # The last move_to will become the first move_to. + # A move_to as first command just moves the start point and can be + # removed! + # There are never two consecutive MOVE_TO commands in a Path! + path._commands.pop() + path._vertices.pop() + path._start_index.pop() + path._has_sub_paths = any( # is still a multi-path? + cmd == Command.MOVE_TO for cmd in path._commands + ) + path._commands.reverse() + path._vertices.reverse() + path._start_index = make_vertex_index(path._commands) + return path + + def clockwise(self) -> Self: + """Returns new :class:`Path` in clockwise orientation. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + if self.has_clockwise_orientation(): + return self.clone() + else: + return self.reversed() + + def counter_clockwise(self) -> Self: + """Returns new :class:`Path` in counter-clockwise orientation. + + Raises: + TypeError: can't detect orientation of a :term:`Multi-Path` object + + """ + + if self.has_clockwise_orientation(): + return self.reversed() + else: + return self.clone() + + def approximate(self, segments: int = 20) -> Iterator[Vec3]: + """Approximate path by vertices, `segments` is the count of + approximation segments for each Bézier curve. + + Does not yield any vertices for empty paths, where only a start point + is present! + + Approximation of :term:`Multi-Path` objects is possible, but gaps are + indistinguishable from line segments. + + """ + + def curve3(p0: Vec3, p1: Vec3, p2: Vec3) -> Iterator[Vec3]: + return iter(Bezier3P((p0, p1, p2)).approximate(segments)) + + def curve4(p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3) -> Iterator[Vec3]: + return iter(Bezier4P((p0, p1, p2, p3)).approximate(segments)) + + return self._approximate(curve3, curve4) + + def flattening(self, distance: float, segments: int = 4) -> Iterator[Vec3]: + """Approximate path by vertices and use adaptive recursive flattening + to approximate Bèzier curves. The argument `segments` is the + minimum count of approximation segments for each curve, if the distance + from the center of the approximation segment to the curve is bigger than + `distance` the segment will be subdivided. + + Does not yield any vertices for empty paths, where only a start point + is present! + + Flattening of :term:`Multi-Path` objects is possible, but gaps are + indistinguishable from line segments. + + Args: + distance: maximum distance from the center of the curve to the + center of the line segment between two approximation points to + determine if a segment should be subdivided. + segments: minimum segment count per Bézier curve + + """ + + def curve3(p0: Vec3, p1: Vec3, p2: Vec3) -> Iterator[Vec3]: + if distance == 0.0: + raise ValueError(f"invalid max distance: 0.0") + return iter(Bezier3P((p0, p1, p2)).flattening(distance, segments)) + + def curve4(p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3) -> Iterator[Vec3]: + if distance == 0.0: + raise ValueError(f"invalid max distance: 0.0") + return iter(Bezier4P((p0, p1, p2, p3)).flattening(distance, segments)) + + return self._approximate(curve3, curve4) + + def _approximate(self, curve3: Callable, curve4: Callable) -> Iterator[Vec3]: + if not self._commands: + return + + start = self._vertices[0] + yield start + + vertices = self._vertices + for si, cmd in zip(self._start_index, self._commands): + if cmd == Command.LINE_TO or cmd == Command.MOVE_TO: + end_location = vertices[si] + yield end_location + elif cmd == Command.CURVE3_TO: + ctrl, end_location = vertices[si : si + 2] + pts = curve3(start, ctrl, end_location) + next(pts) # skip first vertex + yield from pts + elif cmd == Command.CURVE4_TO: + ctrl1, ctrl2, end_location = vertices[si : si + 3] + pts = curve4(start, ctrl1, ctrl2, end_location) + next(pts) # skip first vertex + yield from pts + else: + raise ValueError(f"Invalid command: {cmd}") + start = end_location + + def to_wcs(self, ocs: OCS, elevation: float) -> None: + """Transform path from given `ocs` to WCS coordinates inplace.""" + self._vertices = list( + ocs.to_wcs(v.replace(z=float(elevation))) for v in self._vertices + ) + + def sub_paths(self) -> Iterator[Self]: + """Yield all sub-paths as :term:`Single-Path` objects. + + It's safe to call :meth:`sub_paths` on any path-type: + :term:`Single-Path`, :term:`Multi-Path` and :term:`Empty-Path`. + + """ + path = self.__class__(start=self.start) + path._user_data = self._user_data + move_to = Command.MOVE_TO + for cmd in self.commands(): + if cmd.type == move_to: + yield path + path = self.__class__(start=cmd.end) + path._user_data = self._user_data + else: + path.append_path_element(cmd) + yield path + + def extend_multi_path(self, path: Path) -> None: + """Extend the path by another path. The source path is automatically a + :term:`Multi-Path` object, even if the previous end point matches the + start point of the appended path. Ignores paths without any commands + (empty paths). + + """ + if len(path): + self.move_to(path.start) + for cmd in path.commands(): + self.append_path_element(cmd) + + def append_path(self, path: Path) -> None: + """Append another path to this path. Adds a :code:`self.line_to(path.start)` + if the end of this path != the start of appended path. + + """ + if len(path) == 0: + return # do not append an empty path + if self._commands: + if not self.end.isclose(path.start): + self.line_to(path.start) + else: + self.start = path.start + for cmd in path.commands(): + self.append_path_element(cmd) + + +CMD_SIZE = { + Command.MOVE_TO: 1, + Command.LINE_TO: 1, + Command.CURVE3_TO: 2, + Command.CURVE4_TO: 3, +} + + +def make_vertex_index(command_codes: Iterable[Command]) -> list[int]: + cmd_size = CMD_SIZE + start: int = 1 + start_index: list[int] = [] + for code in command_codes: + start_index.append(start) + start += cmd_size[code] + return start_index diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/shapes.py b/.venv/lib/python3.12/site-packages/ezdxf/path/shapes.py new file mode 100644 index 0000000..012601f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/shapes.py @@ -0,0 +1,306 @@ +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +import math +from ezdxf.math import ( + cubic_bezier_arc_parameters, + Matrix44, + UVec, + basic_transformation, + Vec3, +) +from ezdxf.render import forms +from .path import Path +from . import converter + +__all__ = [ + "unit_circle", + "elliptic_transformation", + "rect", + "ngon", + "wedge", + "star", + "gear", + "helix", +] + + +def unit_circle( + start_angle: float = 0, + end_angle: float = math.tau, + segments: int = 1, + transform: Matrix44 | None = None, +) -> Path: + """Returns a unit circle as a :class:`Path` object, with the center at + (0, 0, 0) and the radius of 1 drawing unit. + + The arc spans from the start- to the end angle in counter-clockwise + orientation. The end angle has to be greater than the start angle and the + angle span has to be greater than 0. + + Args: + start_angle: start angle in radians + end_angle: end angle in radians (end_angle > start_angle!) + segments: count of Bèzier-curve segments, default is one segment for + each arc quarter (π/2) + transform: transformation Matrix applied to the unit circle + + """ + path = Path() + start_flag = True + for start, ctrl1, ctrl2, end in cubic_bezier_arc_parameters( + start_angle, end_angle, segments + ): + if start_flag: + path.start = start + start_flag = False + path.curve4_to(end, ctrl1, ctrl2) + if transform is None: + return path + else: + return path.transform(transform) + + +def wedge( + start_angle: float, + end_angle: float, + segments: int = 1, + transform: Matrix44 | None = None, +) -> Path: + """Returns a wedge as a :class:`Path` object, with the center at + (0, 0, 0) and the radius of 1 drawing unit. + + The arc spans from the start- to the end angle in counter-clockwise + orientation. The end angle has to be greater than the start angle and the + angle span has to be greater than 0. + + Args: + start_angle: start angle in radians + end_angle: end angle in radians (end_angle > start_angle!) + segments: count of Bèzier-curve segments, default is one segment for + each arc quarter (π/2) + transform: transformation Matrix applied to the wedge + + """ + path = Path() + start_flag = True + for start, ctrl1, ctrl2, end in cubic_bezier_arc_parameters( + start_angle, end_angle, segments + ): + if start_flag: + path.line_to(start) + start_flag = False + path.curve4_to(end, ctrl1, ctrl2) + path.line_to((0, 0, 0)) + if transform is None: + return path + else: + return path.transform(transform) + + +def elliptic_transformation( + center: UVec = (0, 0, 0), + radius: float = 1, + ratio: float = 1, + rotation: float = 0, +) -> Matrix44: + """Returns the transformation matrix to transform a unit circle into + an arbitrary circular- or elliptic arc. + + Example how to create an ellipse with a major axis length of 3, a minor + axis length 1.5 and rotated about 90°:: + + m = elliptic_transformation(radius=3, ratio=0.5, rotation=math.pi / 2) + ellipse = shapes.unit_circle(transform=m) + + Args: + center: curve center in WCS + radius: radius of the major axis in drawing units + ratio: ratio of minor axis to major axis + rotation: rotation angle about the z-axis in radians + + """ + if radius < 1e-6: + raise ValueError(f"invalid radius: {radius}") + if ratio < 1e-6: + raise ValueError(f"invalid ratio: {ratio}") + scale_x = radius + scale_y = radius * ratio + return basic_transformation(center, (scale_x, scale_y, 1), rotation) + + +def rect( + width: float = 1, height: float = 1, transform: Matrix44 | None = None +) -> Path: + """Returns a closed rectangle as a :class:`Path` object, with the center at + (0, 0, 0) and the given `width` and `height` in drawing units. + + Args: + width: width of the rectangle in drawing units, width > 0 + height: height of the rectangle in drawing units, height > 0 + transform: transformation Matrix applied to the rectangle + + """ + if width < 1e-9: + raise ValueError(f"invalid width: {width}") + if height < 1e-9: + raise ValueError(f"invalid height: {height}") + + w2 = float(width) / 2.0 + h2 = float(height) / 2.0 + path = converter.from_vertices( + [(w2, h2), (-w2, h2), (-w2, -h2), (w2, -h2)], close=True + ) + if transform is None: + return path + else: + return path.transform(transform) + + +def ngon( + count: int, + length: float | None = None, + radius: float = 1.0, + transform: Matrix44 | None = None, +) -> Path: + """Returns a `regular polygon `_ + a :class:`Path` object, with the center at (0, 0, 0). + The polygon size is determined by the edge `length` or the circum `radius` + argument. If both are given `length` has higher priority. Default size is + a `radius` of 1. The ngon starts with the first vertex is on the x-axis! + The base geometry is created by function :func:`ezdxf.render.forms.ngon`. + + Args: + count: count of polygon corners >= 3 + length: length of polygon side + radius: circum radius, default is 1 + transform: transformation Matrix applied to the ngon + + """ + vertices = forms.ngon(count, length=length, radius=radius) + if transform is not None: + vertices = transform.transform_vertices(vertices) + return converter.from_vertices(vertices, close=True) + + +def star(count: int, r1: float, r2: float, transform: Matrix44 | None = None) -> Path: + """Returns a `star shape `_ as + a :class:`Path` object, with the center at (0, 0, 0). + + Argument `count` defines the count of star spikes, `r1` defines the radius + of the "outer" vertices and `r2` defines the radius of the "inner" vertices, + but this does not mean that `r1` has to be greater than `r2`. + The star shape starts with the first vertex is on the x-axis! + The base geometry is created by function :func:`ezdxf.render.forms.star`. + + Args: + count: spike count >= 3 + r1: radius 1 + r2: radius 2 + transform: transformation Matrix applied to the star + + """ + vertices = forms.star(count, r1=r1, r2=r2) + if transform is not None: + vertices = transform.transform_vertices(vertices) + return converter.from_vertices(vertices, close=True) + + +def gear( + count: int, + top_width: float, + bottom_width: float, + height: float, + outside_radius: float, + transform: Matrix44 | None = None, +) -> Path: + """ + Returns a `gear `_ (cogwheel) shape as + a :class:`Path` object, with the center at (0, 0, 0). + The base geometry is created by function :func:`ezdxf.render.forms.gear`. + + .. warning:: + + This function does not create correct gears for mechanical engineering! + + Args: + count: teeth count >= 3 + top_width: teeth width at outside radius + bottom_width: teeth width at base radius + height: teeth height; base radius = outside radius - height + outside_radius: outside radius + transform: transformation Matrix applied to the gear shape + + """ + vertices = forms.gear(count, top_width, bottom_width, height, outside_radius) + if transform is not None: + vertices = transform.transform_vertices(vertices) + return converter.from_vertices(vertices, close=True) + + +def helix( + radius: float, + pitch: float, + turns: float, + ccw=True, + segments: int = 4, +) -> Path: + """ + Returns a `helix `_ as + a :class:`Path` object. + The center of the helix is always (0, 0, 0), a positive `pitch` value + creates a helix along the +z-axis, a negative value along the -z-axis. + + Args: + radius: helix radius + pitch: the height of one complete helix turn + turns: count of turns + ccw: creates a counter-clockwise turning (right-handed) helix if ``True`` + segments: cubic Bezier segments per turn + + """ + + # Source of algorithm: https://www.arc.id.au/HelixDrawing.html + def bezier_ctrl_points(b, angle, segments): + zz = 0.0 + z_step = angle / segments * p + z_step_2 = z_step * 0.5 + for _, v1, v2, v3 in cubic_bezier_arc_parameters(0, angle, segments): + yield ( + Vec3(v1.x * rx, v1.y * ry, zz + z_step_2 - b), + Vec3(v2.x * rx, v2.y * ry, zz + z_step_2 + b), + Vec3(v3.x * rx, v3.y * ry, zz + z_step), + ) + zz += z_step + + def param_b(alpha: float) -> float: + cos_a = math.cos(alpha) + b_1 = (1.0 - cos_a) * (3.0 - cos_a) * alpha * p + b_2 = math.sin(alpha) * (4.0 - cos_a) * math.tan(alpha) + return b_1 / b_2 + + rx = radius + ry = radius + if not ccw: + ry = -ry + path = Path(start=(radius, 0, 0)) + + p = pitch / math.tau + b = param_b(math.pi / segments) + full_turns = int(math.floor(turns)) + if full_turns > 0: + curve_params = list(bezier_ctrl_points(b, math.tau, segments)) + for _ in range(full_turns): + z = Vec3(0, 0, path.end.z) + for v1, v2, v3 in curve_params: + path.curve4_to(z + v3, z + v1, z + v2) + + reminder = turns - full_turns + if reminder > 1e-6: + segments = math.ceil(reminder * 4) + b = param_b(reminder * math.pi / segments) + z = Vec3(0, 0, path.end.z) + for v1, v2, v3 in bezier_ctrl_points(b, math.tau * reminder, segments): + path.curve4_to(z + v3, z + v1, z + v2) + + return path diff --git a/.venv/lib/python3.12/site-packages/ezdxf/path/tools.py b/.venv/lib/python3.12/site-packages/ezdxf/path/tools.py new file mode 100644 index 0000000..6338a7f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/path/tools.py @@ -0,0 +1,1017 @@ +# Copyright (c) 2020-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + Optional, + Sequence, +) +import math +import numpy as np + +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + Z_AXIS, + OCS, + UCS, + Matrix44, + BoundingBox, + ConstructionEllipse, + cubic_bezier_from_ellipse, + Bezier4P, + Bezier3P, + BSpline, + reverse_bezier_curves, + bulge_to_arc, + linear_vertex_spacing, + inscribe_circle_tangent_length, + cubic_bezier_arc_parameters, + cubic_bezier_bbox, + quadratic_bezier_bbox, +) +from ezdxf.math.triangulation import mapbox_earcut_2d +from ezdxf.query import EntityQuery + +from .path import Path +from .commands import Command +from . import converter, nesting + +if TYPE_CHECKING: + from ezdxf.query import EntityQuery + from ezdxf.eztypes import GenericLayoutType + + +__all__ = [ + "bbox", + "precise_bbox", + "fit_paths_into_box", + "transform_paths", + "transform_paths_to_ocs", + "render_lwpolylines", + "render_polylines2d", + "render_polylines3d", + "render_lines", + "render_hatches", + "render_mpolygons", + "render_splines_and_polylines", + "add_bezier4p", + "add_bezier3p", + "add_ellipse", + "add_2d_polyline", + "add_spline", + "to_multi_path", + "single_paths", + "have_close_control_vertices", + "lines_to_curve3", + "lines_to_curve4", + "fillet", + "polygonal_fillet", + "chamfer", + "chamfer2", + "triangulate", + "is_rectangular", +] + +MAX_DISTANCE = 0.01 +MIN_SEGMENTS = 4 +G1_TOL = 1e-4 +IS_CLOSE_TOL = 1e-10 + + +def to_multi_path(paths: Iterable[Path]) -> Path: + """Returns a multi-path object from all given paths and their sub-paths. + Ignores paths without any commands (empty paths). + """ + multi_path = Path() + for p in paths: + multi_path.extend_multi_path(p) + return multi_path + + +def single_paths(paths: Iterable[Path]) -> Iterable[Path]: + """Yields all given paths and their sub-paths as single path objects.""" + for p in paths: + if p.has_sub_paths: + yield from p.sub_paths() + else: + yield p + + +def transform_paths(paths: Iterable[Path], m: Matrix44) -> list[Path]: + """Transform multiple path objects at once by transformation + matrix `m`. Returns a list of the transformed path objects. + + Args: + paths: iterable of :class:`Path` or :class:`Path2d` objects + m: transformation matrix of type :class:`~ezdxf.math.Matrix44` + + """ + return [p.transform(m) for p in paths] + + +def transform_paths_to_ocs(paths: Iterable[Path], ocs: OCS) -> list[Path]: + """Transform multiple :class:`Path` objects at once from WCS to OCS. + Returns a list of the transformed :class:`Path` objects. + + Args: + paths: iterable of :class:`Path` or :class:`Path2d` objects + ocs: OCS transformation of type :class:`~ezdxf.math.OCS` + + """ + t = ocs.matrix.copy() + t.transpose() + return transform_paths(paths, t) + + +def bbox(paths: Iterable[Path], *, fast=False) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` for the given paths. + + Args: + paths: iterable of :class:`Path` or :class:`Path2d` objects + fast: calculates the precise bounding box of Bèzier curves if + ``False``, otherwise uses the control points of Bézier curves to + determine their bounding box. + + """ + box = BoundingBox() + for p in paths: + if fast: + box.extend(p.control_vertices()) + else: + bb = precise_bbox(p) + if bb.has_data: + box.extend((bb.extmin, bb.extmax)) + return box + + +def precise_bbox(path: Path) -> BoundingBox: + """Returns the precise :class:`~ezdxf.math.BoundingBox` for the given paths.""" + if len(path) == 0: # empty path + return BoundingBox() + start = path.start + points: list[Vec3] = [start] + for cmd in path.commands(): + if cmd.type == Command.LINE_TO: + points.append(cmd.end) + elif cmd.type == Command.CURVE4_TO: + bb = cubic_bezier_bbox( + Bezier4P((start, cmd.ctrl1, cmd.ctrl2, cmd.end)) # type: ignore + ) + points.append(bb.extmin) + points.append(bb.extmax) + elif cmd.type == Command.CURVE3_TO: + bb = quadratic_bezier_bbox(Bezier3P((start, cmd.ctrl, cmd.end))) # type: ignore + points.append(bb.extmin) + points.append(bb.extmax) + elif cmd.type == Command.MOVE_TO: + points.append(cmd.end) + start = cmd.end + + return BoundingBox(points) + + +def fit_paths_into_box( + paths: Iterable[Path], + size: tuple[float, float, float], + uniform: bool = True, + source_box: Optional[BoundingBox] = None, +) -> list[Path]: + """Scale the given `paths` to fit into a box of the given `size`, + so that all path vertices are inside these borders. + If `source_box` is ``None`` the default source bounding box is calculated + from the control points of the `paths`. + + `Note:` if the target size has a z-size of 0, the `paths` are + projected into the xy-plane, same is true for the x-size, projects into + the yz-plane and the y-size, projects into and xz-plane. + + Args: + paths: iterable of :class:`~ezdxf.path.Path` objects + size: target box size as tuple of x-, y- and z-size values + uniform: ``True`` for uniform scaling + source_box: pass precalculated source bounding box, or ``None`` to + calculate the default source bounding box from the control vertices + + """ + paths = list(paths) + if len(paths) == 0: + return paths + if source_box is None: + current_box = bbox(paths, fast=True) + else: + current_box = source_box + if not current_box.has_data or current_box.size == (0, 0, 0): + return paths + target_size = Vec3(size) + if target_size == (0, 0, 0) or min(target_size) < 0: + raise ValueError("invalid target size") + + if uniform: + sx, sy, sz = _get_uniform_scaling(current_box.size, target_size) + else: + sx, sy, sz = _get_non_uniform_scaling(current_box.size, target_size) + m = Matrix44.scale(sx, sy, sz) + return transform_paths(paths, m) + + +def _get_uniform_scaling(current_size: Vec3, target_size: Vec3): + TOL = 1e-6 + scale_x = math.inf + if current_size.x > TOL and target_size.x > TOL: + scale_x = target_size.x / current_size.x + scale_y = math.inf + if current_size.y > TOL and target_size.y > TOL: + scale_y = target_size.y / current_size.y + scale_z = math.inf + if current_size.z > TOL and target_size.z > TOL: + scale_z = target_size.z / current_size.z + + uniform_scale = min(scale_x, scale_y, scale_z) + if uniform_scale is math.inf: + raise ArithmeticError("internal error") + scale_x = uniform_scale if target_size.x > TOL else 0 + scale_y = uniform_scale if target_size.y > TOL else 0 + scale_z = uniform_scale if target_size.z > TOL else 0 + return scale_x, scale_y, scale_z + + +def _get_non_uniform_scaling(current_size: Vec3, target_size: Vec3): + TOL = 1e-6 + scale_x = 1.0 + if current_size.x > TOL: + scale_x = target_size.x / current_size.x + scale_y = 1.0 + if current_size.y > TOL: + scale_y = target_size.y / current_size.y + scale_z = 1.0 + if current_size.z > TOL: + scale_z = target_size.z / current_size.z + return scale_x, scale_y, scale_z + + +# Path to entity converter and render utilities: + + +def render_lwpolylines( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as + :class:`~ezdxf.entities.LWPolyline` entities. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path` or :class:`Path2d` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + lwpolylines = list( + converter.to_lwpolylines( + paths, + distance=distance, + segments=segments, + extrusion=extrusion, + dxfattribs=dxfattribs, + ) + ) + for lwpolyline in lwpolylines: + layout.add_entity(lwpolyline) + return EntityQuery(lwpolylines) + + +def render_polylines2d( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + distance: float = 0.01, + segments: int = 4, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as 2D + :class:`~ezdxf.entities.Polyline` entities. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector.The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path` or :class:`Path2d` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + polylines2d = list( + converter.to_polylines2d( + paths, + distance=distance, + segments=segments, + extrusion=extrusion, + dxfattribs=dxfattribs, + ) + ) + for polyline2d in polylines2d: + layout.add_entity(polyline2d) + return EntityQuery(polylines2d) + + +def render_hatches( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + edge_path: bool = True, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + g1_tol: float = G1_TOL, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as + :class:`~ezdxf.entities.Hatch` entities. + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path` or :class:`Path2d` objects + edge_path: ``True`` for edge paths build of LINE and SPLINE edges, + ``False`` for only LWPOLYLINE paths as boundary paths + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve to flatten polyline paths + g1_tol: tolerance for G1 continuity check to separate SPLINE edges + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + hatches = list( + converter.to_hatches( + paths, + edge_path=edge_path, + distance=distance, + segments=segments, + g1_tol=g1_tol, + extrusion=extrusion, + dxfattribs=dxfattribs, + ) + ) + for hatch in hatches: + layout.add_entity(hatch) + return EntityQuery(hatches) + + +def render_mpolygons( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + extrusion: UVec = Z_AXIS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as + :class:`~ezdxf.entities.MPolygon` entities. The MPOLYGON entity supports + only polyline boundary paths. All curves will be approximated. + + The `extrusion` vector is applied to all paths, all vertices are projected + onto the plane normal to this extrusion vector. The default extrusion vector + is the WCS z-axis. The plane elevation is the distance from the WCS origin + to the start point of the first path. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path` or :class:`Path2d` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve to flatten polyline paths + extrusion: extrusion vector for all paths + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + polygons = list( + converter.to_mpolygons( + paths, + distance=distance, + segments=segments, + extrusion=extrusion, + dxfattribs=dxfattribs, + ) + ) + for polygon in polygons: + layout.add_entity(polygon) + return EntityQuery(polygons) + + +def render_polylines3d( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as 3D + :class:`~ezdxf.entities.Polyline` entities. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path`or :class:`Path2d` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + + polylines3d = list( + converter.to_polylines3d( + paths, + distance=distance, + segments=segments, + dxfattribs=dxfattribs, + ) + ) + for polyline3d in polylines3d: + layout.add_entity(polyline3d) + return EntityQuery(polylines3d) + + +def render_lines( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + distance: float = MAX_DISTANCE, + segments: int = MIN_SEGMENTS, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as + :class:`~ezdxf.entities.Line` entities. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path`or :class:`Path2d` objects + distance: maximum distance, see :meth:`Path.flattening` + segments: minimum segment count per Bézier curve + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + lines = list( + converter.to_lines( + paths, + distance=distance, + segments=segments, + dxfattribs=dxfattribs, + ) + ) + for line in lines: + layout.add_entity(line) + return EntityQuery(lines) + + +def render_splines_and_polylines( + layout: GenericLayoutType, + paths: Iterable[Path], + *, + g1_tol: float = G1_TOL, + dxfattribs=None, +) -> EntityQuery: + """Render the given `paths` into `layout` as :class:`~ezdxf.entities.Spline` + and 3D :class:`~ezdxf.entities.Polyline` entities. + + Args: + layout: the modelspace, a paperspace layout or a block definition + paths: iterable of :class:`Path`or :class:`Path2d` objects + g1_tol: tolerance for G1 continuity check + dxfattribs: additional DXF attribs + + Returns: + created entities in an :class:`~ezdxf.query.EntityQuery` object + + """ + entities = list( + converter.to_splines_and_polylines( + paths, + g1_tol=g1_tol, + dxfattribs=dxfattribs, + ) + ) + for entity in entities: + layout.add_entity(entity) + return EntityQuery(entities) + + +def add_ellipse( + path: Path, ellipse: ConstructionEllipse, segments=1, reset=True +) -> None: + """Add an elliptical arc as multiple cubic Bèzier-curves to the given + `path`, use :meth:`~ezdxf.math.ConstructionEllipse.from_arc` constructor + of class :class:`~ezdxf.math.ConstructionEllipse` to add circular arcs. + + Auto-detect the connection point to the given `path`, if neither the start- + nor the end point of the ellipse is close to the path end point, a line from + the path end point to the ellipse start point will be added automatically + (see :func:`add_bezier4p`). + + By default, the start of an **empty** path is set to the start point of + the ellipse, setting argument `reset` to ``False`` prevents this + behavior. + + Args: + path: :class:`~ezdxf.path.Path` object + ellipse: ellipse parameters as :class:`~ezdxf.math.ConstructionEllipse` + object + segments: count of Bèzier-curve segments, at least one segment for + each quarter (pi/2), ``1`` for as few as possible. + reset: set start point to start of ellipse if path is empty + + """ + if abs(ellipse.param_span) < 1e-9: + return + if len(path) == 0 and reset: + path.start = ellipse.start_point + add_bezier4p(path, cubic_bezier_from_ellipse(ellipse, segments)) + + +def add_bezier4p(path: Path, curves: Iterable[Bezier4P]) -> None: + """Add multiple cubic Bèzier-curves to the given `path`. + + Auto-detect the connection point to the given `path`, if neither the start- + nor the end point of the curves is close to the path end point, a line from + the path end point to the start point of the first curve will be added + automatically. + + """ + rel_tol = 1e-15 + abs_tol = 0.0 + curves = list(curves) + if not len(curves): + return + end = curves[-1].control_points[-1] + if path.end.isclose(end): + # connect to new curves end point + curves = reverse_bezier_curves(curves) + + for curve in curves: + start, ctrl1, ctrl2, end = curve.control_points + if not start.isclose(path.end): + path.line_to(start) + + # add linear bezier segments as LINE_TO commands + if start.isclose(ctrl1, rel_tol=rel_tol, abs_tol=abs_tol) and end.isclose( + ctrl2, rel_tol=rel_tol, abs_tol=abs_tol + ): + path.line_to(end) + else: + path.curve4_to(end, ctrl1, ctrl2) + + +def add_bezier3p(path: Path, curves: Iterable[Bezier3P]) -> None: + """Add multiple quadratic Bèzier-curves to the given `path`. + + Auto-detect the connection point to the given `path`, if neither the start- + nor the end point of the curves is close to the path end point, a line from + the path end point to the start point of the first curve will be added + automatically. + + """ + rel_tol = 1e-15 + abs_tol = 0.0 + curves = list(curves) + if not len(curves): + return + end = curves[-1].control_points[-1] + if path.end.isclose(end): + # connect to new curves end point + curves = reverse_bezier_curves(curves) + + for curve in curves: + start, ctrl, end = curve.control_points + if not start.isclose(path.end, rel_tol=rel_tol, abs_tol=abs_tol): + path.line_to(start) + + if start.isclose(ctrl, rel_tol=rel_tol, abs_tol=abs_tol) or end.isclose( + ctrl, rel_tol=rel_tol, abs_tol=abs_tol + ): + path.line_to(end) + else: + path.curve3_to(end, ctrl) + + +def add_2d_polyline( + path: Path, + points: Iterable[Sequence[float]], + close: bool, + ocs: OCS, + elevation: float, + segments: int = 1, +) -> None: + """Internal API to add 2D polylines which may include bulges to an + **empty** path. + + """ + + def bulge_to(p1: Vec3, p2: Vec3, bulge: float, segments: int): + if p1.isclose(p2, rel_tol=IS_CLOSE_TOL, abs_tol=0): + return + # each cubic_bezier adds 3 segments, need 1 minimum + num_bez = math.ceil(segments / 3) + center, start_angle, end_angle, radius = bulge_to_arc(p1, p2, bulge) + # normalize angles into range 0 .. 2pi + start_angle = start_angle % math.tau + end_angle = end_angle % math.tau + if start_angle > end_angle: + end_angle += math.tau + angles = list(np.linspace(start_angle, end_angle, num_bez + 1)) + curves = [] + for i in range(num_bez): + ellipse = ConstructionEllipse.from_arc( + center, + radius, + Z_AXIS, + math.degrees(angles[i]), + math.degrees(angles[i + 1]), + ) + curves.extend(list(cubic_bezier_from_ellipse(ellipse))) + curve0 = curves[0] + cp0 = curve0.control_points[0] + if cp0.isclose(p2, rel_tol=IS_CLOSE_TOL, abs_tol=0): + curves = reverse_bezier_curves(curves) + add_bezier4p(path, curves) + + if len(path): + raise ValueError("Requires an empty path.") + + prev_point: Optional[Vec3] = None + prev_bulge: float = 0 + for x, y, bulge in points: + # Bulge values near 0 but != 0 cause crashes! #329 + if abs(bulge) < 1e-6: + bulge = 0 + point = Vec3(x, y) + if prev_point is None: + path.start = point + prev_point = point + prev_bulge = bulge + continue + + if prev_bulge: + bulge_to(prev_point, point, prev_bulge, segments) + else: + path.line_to(point) + prev_point = point + prev_bulge = bulge + + if close and not path.start.isclose(path.end, rel_tol=IS_CLOSE_TOL, abs_tol=0): + if prev_bulge: + bulge_to(path.end, path.start, prev_bulge, segments) + else: + path.line_to(path.start) + + if ocs.transform or elevation: + path.to_wcs(ocs, elevation) + + +def add_spline(path: Path, spline: BSpline, level=4, reset=True) -> None: + """Add a B-spline as multiple cubic Bèzier-curves. + + Non-rational B-splines of 3rd degree gets a perfect conversion to + cubic Bézier curves with a minimal count of curve segments, all other + B-spline require much more curve segments for approximation. + + Auto-detect the connection point to the given `path`, if neither the start- + nor the end point of the B-spline is close to the path end point, a line + from the path end point to the start point of the B-spline will be added + automatically. (see :meth:`add_bezier4p`). + + By default, the start of an **empty** path is set to the start point of + the spline, setting argument `reset` to ``False`` prevents this + behavior. + + Args: + path: :class:`~ezdxf.path.Path` object + spline: B-spline parameters as :class:`~ezdxf.math.BSpline` object + level: subdivision level of approximation segments + reset: set start point to start of spline if path is empty + + """ + if len(path) == 0 and reset: + path.start = spline.point(0) + curves: Iterable[Bezier4P] + if spline.degree == 3 and not spline.is_rational and spline.is_clamped: + curves = [Bezier4P(points) for points in spline.bezier_decomposition()] + else: + curves = spline.cubic_bezier_approximation(level=level) + add_bezier4p(path, curves) + + +def have_close_control_vertices( + a: Path, b: Path, *, rel_tol=1e-9, abs_tol=1e-12 +) -> bool: + """Returns ``True`` if the control vertices of given paths are close.""" + return all( + cp_a.isclose(cp_b, rel_tol=rel_tol, abs_tol=abs_tol) + for cp_a, cp_b in zip(a.control_vertices(), b.control_vertices()) + ) + + +def lines_to_curve3(path: Path) -> Path: + """Replaces all lines by quadratic Bézier curves. + Returns a new :class:`Path` instance. + """ + return _all_lines_to_curve(path, count=3) + + +def lines_to_curve4(path: Path) -> Path: + """Replaces all lines by cubic Bézier curves. + Returns a new :class:`Path` instance. + """ + return _all_lines_to_curve(path, count=4) + + +def _all_lines_to_curve(path: Path, count: int = 4) -> Path: + assert count == 4 or count == 3, f"invalid count: {count}" + + cmds = path.commands() + size = len(cmds) + if size == 0: # empty path + return Path() + start = path.start + line_to = Command.LINE_TO + new_path = Path(path.start) + for cmd in cmds: + if cmd.type == line_to: + if start.isclose(cmd.end): + if size == 1: + # Path has only one LINE_TO command which should not be + # removed: + # 1. may represent a point + # 2. removing the last segment turns the path into + # an empty path - unexpected behavior? + new_path.append_path_element(cmd) + return new_path + # else remove line segment (start==end) + else: + vertices = linear_vertex_spacing(start, cmd.end, count) + if count == 3: + new_path.curve3_to(vertices[2], ctrl=vertices[1]) + else: # count == 4 + new_path.curve4_to( + vertices[3], + ctrl1=vertices[1], + ctrl2=vertices[2], + ) + else: + new_path.append_path_element(cmd) + start = cmd.end + return new_path + + +def _get_local_fillet_ucs(p0, p1, p2, radius) -> tuple[Vec3, float, UCS]: + dir1 = (p0 - p1).normalize() + dir2 = (p2 - p1).normalize() + if dir1.isclose(dir2) or dir1.isclose(-dir2): + raise ZeroDivisionError + + # arc start- and end points: + angle = dir1.angle_between(dir2) + tangent_length = inscribe_circle_tangent_length(dir1, dir2, radius) + # starting point of the fillet arc + arc_start_point = p1 + (dir1 * tangent_length) + + # create local coordinate system: + # origin = center of the fillet arc + # x-axis = arc_center -> arc_start_point + local_z_axis = dir2.cross(dir1) + # radius_vec points from arc_start_point to the center of the fillet arc + radius_vec = local_z_axis.cross(-dir1).normalize(radius) + arc_center = arc_start_point + radius_vec + ucs = UCS(origin=arc_center, ux=-radius_vec, uz=local_z_axis) + return arc_start_point, math.pi - angle, ucs + + +def fillet(points: Sequence[Vec3], radius: float) -> Path: + """Returns a :class:`Path` with circular fillets of given `radius` between + straight line segments. + + Args: + points: coordinates of the line segments + radius: fillet radius + + """ + if len(points) < 3: + raise ValueError("at least 3 not coincident points required") + if radius <= 0: + raise ValueError(f"invalid radius: {radius}") + lines = [(p0, p1) for p0, p1 in zip(points, points[1:])] + p = Path(points[0]) + for (p0, p1), (p2, p3) in zip(lines, lines[1:]): + try: + start_point, angle, ucs = _get_local_fillet_ucs(p0, p1, p3, radius) + except ZeroDivisionError: + p.line_to(p1) + continue + + # add path elements: + p.line_to(start_point) + for params in cubic_bezier_arc_parameters(0, angle): + # scale arc parameters by radius: + bez_points = tuple(ucs.points_to_wcs(v * radius for v in params)) + p.curve4_to(bez_points[-1], bez_points[1], bez_points[2]) + p.line_to(points[-1]) + return p + + +def _segment_count(angle: float, count: int) -> int: + count = max(4, count) + return max(int(angle / (math.tau / count)), 1) + + +def polygonal_fillet(points: Sequence[Vec3], radius: float, count: int = 32) -> Path: + """ + Returns a :class:`Path` with polygonal fillets of given `radius` between + straight line segments. The `count` argument defines the vertex count of the + fillet for a full circle. + + Args: + points: coordinates of the line segments + radius: fillet radius + count: polygon vertex count for a full circle, minimum is 4 + + """ + if len(points) < 3: + raise ValueError("at least 3 not coincident points required") + if radius <= 0: + raise ValueError(f"invalid radius: {radius}") + lines = [(p0, p1) for p0, p1 in zip(points, points[1:])] + p = Path(points[0]) + for (p0, p1), (p2, p3) in zip(lines, lines[1:]): + try: + _, angle, ucs = _get_local_fillet_ucs(p0, p1, p3, radius) + except ZeroDivisionError: + p.line_to(p1) + continue + segments = _segment_count(angle, count) + delta = angle / segments + # add path elements: + for i in range(segments + 1): + radius_vec = Vec3.from_angle(i * delta, radius) + p.line_to(ucs.to_wcs(radius_vec)) + + p.line_to(points[-1]) + return p + + +def chamfer(points: Sequence[Vec3], length: float) -> Path: + """ + Returns a :class:`Path` with chamfers of given `length` between + straight line segments. + + Args: + points: coordinates of the line segments + length: chamfer length + + """ + if len(points) < 3: + raise ValueError("at least 3 not coincident points required") + lines = [(p0, p1) for p0, p1 in zip(points, points[1:])] + p = Path(points[0]) + for (p0, p1), (p2, p3) in zip(lines, lines[1:]): + # p1 is p2 ! + try: + dir1 = (p0 - p1).normalize() + dir2 = (p3 - p2).normalize() + if dir1.isclose(dir2) or dir1.isclose(-dir2): + raise ZeroDivisionError + angle = dir1.angle_between(dir2) / 2.0 + a = abs((length / 2.0) / math.sin(angle)) + except ZeroDivisionError: + p.line_to(p1) + continue + p.line_to(p1 + (dir1 * a)) + p.line_to(p2 + (dir2 * a)) + p.line_to(points[-1]) + return p + + +def chamfer2(points: Sequence[Vec3], a: float, b: float) -> Path: + """ + Returns a :class:`Path` with chamfers at the given distances `a` and `b` + from the segment points between straight line segments. + + Args: + points: coordinates of the line segments + a: distance of the chamfer start point to the segment point + b: distance of the chamfer end point to the segment point + + """ + if len(points) < 3: + raise ValueError("at least 3 non-coincident points required") + lines = [(p0, p1) for p0, p1 in zip(points, points[1:])] + p = Path(points[0]) + for (p0, p1), (p2, p3) in zip(lines, lines[1:]): + # p1 is p2 ! + try: + dir1 = (p0 - p1).normalize() + dir2 = (p3 - p2).normalize() + if dir1.isclose(dir2) or dir1.isclose(-dir2): + raise ZeroDivisionError + except ZeroDivisionError: + p.line_to(p1) + continue + p.line_to(p1 + (dir1 * a)) + p.line_to(p2 + (dir2 * b)) + p.line_to(points[-1]) + return p + + +def triangulate( + paths: Iterable[Path], max_sagitta: float = 0.01, min_segments: int = 16 +) -> Iterator[Sequence[Vec2]]: + """Tessellate nested 2D paths into triangle-faces. For 3D paths the + projection onto the xy-plane will be triangulated. + + Args: + paths: iterable of nested Path instances + max_sagitta: maximum distance from the center of the curve to the + center of the line segment between two approximation points to determine if + a segment should be subdivided. + min_segments: minimum segment count per Bézier curve + + """ + for polygon in nesting.group_paths(single_paths(paths)): + exterior = polygon[0].flattening(max_sagitta, min_segments) + holes = [p.flattening(max_sagitta, min_segments) for p in polygon[1:]] + yield from mapbox_earcut_2d(exterior, holes) + + +def is_rectangular(path: Path, aligned=True) -> bool: + """Returns ``True`` if `path` is a rectangular quadrilateral (square or + rectangle). If the argument `aligned` is ``True`` all sides of the + quadrilateral have to be parallel to the x- and y-axis. + """ + points = path.control_vertices() + if len(points) < 4: + return False + if points[0].isclose(points[-1]): + points.pop() + if len(points) != 4: + return False + + if aligned: + first_side = points[1] - points[0] + if not (abs(first_side.x) < 1e-12 or abs(first_side.y) < 1e-12): + return False + + # horizontal sides + v1 = points[0].distance(points[1]) + v2 = points[2].distance(points[3]) + if not math.isclose(v1, v2): + return False + # vertical sides + v1 = points[1].distance(points[2]) + v2 = points[3].distance(points[0]) + if not math.isclose(v1, v2): + return False + # diagonals + v1 = points[0].distance(points[2]) + v2 = points[1].distance(points[3]) + if not math.isclose(v1, v2): + return False + + return True diff --git a/.venv/lib/python3.12/site-packages/ezdxf/protocols.py b/.venv/lib/python3.12/site-packages/ezdxf/protocols.py new file mode 100644 index 0000000..34a7556 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/protocols.py @@ -0,0 +1,96 @@ +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Iterable, Any +from typing_extensions import Protocol, runtime_checkable +from ezdxf.query import EntityQuery + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic, DXFEntity + from ezdxf.entities.temporary_transform import TemporaryTransformation + from ezdxf.math import Matrix44, AbstractBoundingBox + + +# Protocol implemented for: +# - DXFTagStorage +# - ACAD_PROXY_ENTITY +# - INSERT +# - DIMENSION +# - LEADER +# - MLEADER +# - MLINE +# - ProxyGraphic +# - DXFGraphicProxy (drawing add-on) +# - DXFTagStorage +# - ACAD_TABLE (table content loader) + + +@runtime_checkable +class SupportsVirtualEntities(Protocol): + """The virtual entities protocol is used to disassemble complex entities + into DXF primitives like LINE, ARC, ... as REQUIREMENT to render these + entities. Which means the entity does not have :func:`ezdxf.path.make_path` + support, except the text entities TEXT, ATTRIB and MTEXT. + + Optional DECONSTRUCTION of entities into DXF primitives like LWPOLYLINE + into LINE and ARC entities is NOT the intended usage of this protocol! + + This protocol is for consistent internal usage and does not replace + the :meth:`virtual_entities` methods! + + """ + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: ... + + +def virtual_entities(entity: SupportsVirtualEntities) -> Iterator[DXFGraphic]: + if isinstance(entity, SupportsVirtualEntities): + return entity.__virtual_entities__() + else: + raise TypeError( + f"{type(entity)!r} does not support the __virtual_entities__ protocol" + ) + + +def query_virtual_entities(entity: SupportsVirtualEntities) -> EntityQuery: + return EntityQuery(virtual_entities(entity)) + + +@runtime_checkable +class ReferencedBlocks(Protocol): + def __referenced_blocks__(self) -> Iterable[str]: + """Returns the handles to the BLOCK_RECORD entities for all BLOCK + definitions used by an entity. + """ + + +class SupportsTransform(Protocol): + def transform(self, m: Matrix44) -> DXFGraphic: + """Raises NotImplementedError() if transformation is not supported.""" + + +_EMPTY_TUPLE: tuple = tuple() + + +def referenced_blocks(entity: DXFEntity) -> Iterable[str]: + """Returns the handles to the BLOCK_RECORD entities for all BLOCK + definitions used by an entity. + """ + if isinstance(entity, ReferencedBlocks): + return entity.__referenced_blocks__() + else: + return _EMPTY_TUPLE + + +class SupportsBoundingBox(Protocol): + def bbox(self) -> AbstractBoundingBox: ... + + +@runtime_checkable +class SupportsTemporaryTransformation(Protocol): + def temporary_transformation(self) -> TemporaryTransformation: ... + + +class SupportsMessages(Protocol): + def notify(self, message_type: int, data: Any = None) -> None: + """Internal messaging system.""" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/proxygraphic.py b/.venv/lib/python3.12/site-packages/ezdxf/proxygraphic.py new file mode 100644 index 0000000..75ed91a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/proxygraphic.py @@ -0,0 +1,979 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Optional, + Iterable, + Iterator, + cast, + Sequence, + Any, +) +import sys +import struct +import math +from enum import IntEnum +from itertools import repeat +from ezdxf.lldxf import const +from ezdxf.tools.binarydata import bytes_to_hexstr, ByteStream, BitStream +from ezdxf import colors +from ezdxf.math import ( + Vec3, + Vec2, + Matrix44, + Z_AXIS, + ConstructionCircle, + ConstructionArc, + OCS, + UCS, + X_AXIS, +) +from ezdxf.entities import factory +import logging + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tags import Tags + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import ( + DXFGraphic, + Polymesh, + Polyface, + Polyline, + Hatch, + LWPolyline, + ) + +logger = logging.getLogger("ezdxf") + +CHUNK_SIZE = 127 + + +class ProxyGraphicError(Exception): + pass + + +def load_proxy_graphic( + tags: Tags, length_code: int = 160, data_code: int = 310 +) -> Optional[bytes]: + binary_data = [ + tag.value + for tag in tags.pop_tags(codes=(length_code, data_code)) + if tag.code == data_code + ] + return b"".join(binary_data) if len(binary_data) else None + + +def export_proxy_graphic( + data: bytes, + tagwriter: AbstractTagWriter, + length_code: int = 160, + data_code: int = 310, +) -> None: + # Do not export proxy graphic for DXF R12 files + assert tagwriter.dxfversion > const.DXF12 + + length = len(data) + if length == 0: + return + + tagwriter.write_tag2(length_code, length) + index = 0 + while index < length: + hex_str = bytes_to_hexstr(data[index : index + CHUNK_SIZE]) + tagwriter.write_tag2(data_code, hex_str) + index += CHUNK_SIZE + + +def has_prim_traits(flags: int) -> bool: + return bool(flags & 0xFFFF) + + +def prims_have_colors(flags: int) -> bool: + return bool(flags & 0x0001) + + +def prims_have_layers(flags: int) -> bool: + return bool(flags & 0x0002) + + +def prims_have_linetypes(flags: int) -> bool: + return bool(flags & 0x0004) + + +def prims_have_markers(flags: int) -> bool: + return bool(flags & 0x0020) + + +def prims_have_visibilities(flags: int) -> bool: + return bool(flags & 0x0040) + + +def prims_have_normals(flags: int) -> bool: + return bool(flags & 0x0080) + + +def prims_have_orientation(flags: int) -> bool: + return bool(flags & 0x0400) + + +TRAIT_TESTER = { + "colors": (prims_have_colors, "RL"), + "layers": (prims_have_layers, "RL"), + "linetypes": (prims_have_linetypes, "RL"), + "markers": (prims_have_markers, "RL"), + "visibilities": (prims_have_visibilities, "RL"), + "normals": (prims_have_normals, "3RD"), +} + + +def read_prim_traits( + bs: ByteStream, types: Sequence[str], prim_flags: int, count: int +) -> dict: + def read_float_list(): + return [bs.read_long() for _ in range(count)] + + def read_vertices(): + return [Vec3(bs.read_vertex()) for _ in range(count)] + + data = dict() + for t in types: + test_trait, data_type = TRAIT_TESTER[t] + if test_trait(prim_flags): + if data_type == "3RD": + data[t] = read_vertices() + elif data_type == "RL": + data[t] = read_float_list() + else: + raise TypeError(data_type) + return data + + +def read_mesh_traits( + bs: ByteStream, edge_count: int, face_count: int, vertex_count: int +): + # Traits data format: + # all entries are optional + # traits: dict[str, dict] + # "edges": dict[str, list] + # "colors": list[int] + # "layers": list[int] as layer ids + # "linetypes": list[int] as linetype ids + # "markers": list[int] + # "visibilities": list[int] + # "faces": dict[str, list] + # "colors": list[int] + # "layers": list[int] as layer ids + # "markers": list[int] + # "normals": list[Vec3] + # "visibilities": list[int] + # "vertices": dict + # "normals": list[Vec3] + # "orientation": bool + traits = dict() + edge_flags = bs.read_long() + if has_prim_traits(edge_flags): + traits["edges"] = read_prim_traits( + bs, + ["colors", "layers", "linetypes", "markers", "visibilities"], + edge_flags, + edge_count, + ) + face_flags = bs.read_long() + if has_prim_traits(face_flags): + traits["faces"] = read_prim_traits( + bs, + ["colors", "layers", "markers", "normals", "visibilities"], + face_flags, + face_count, + ) + + # Note: DXF entities PolyFaceMesh and Mesh do not support vertex normals! + # disable useless reading process by vertex_count = 0 + if vertex_count > 0: + vertex_flags = bs.read_long() + if has_prim_traits(vertex_flags): + vertices = dict() + if prims_have_normals(vertex_flags): + vertices["normals"] = [ + Vec3(bs.read_vertex()) for _ in range(vertex_count) + ] + if prims_have_orientation(vertex_flags): + vertices["orientation"] = bool(bs.read_long()) # type: ignore + traits["vertices"] = vertices + return traits + + +class ProxyGraphicTypes(IntEnum): + EXTENTS = 1 + CIRCLE = 2 + CIRCLE_3P = 3 + CIRCULAR_ARC = 4 + CIRCULAR_ARC_3P = 5 + POLYLINE = 6 + POLYGON = 7 + MESH = 8 + SHELL = 9 + TEXT = 10 + TEXT2 = 11 + XLINE = 12 + RAY = 13 + ATTRIBUTE_COLOR = 14 + UNUSED_15 = 15 + ATTRIBUTE_LAYER = 16 + UNUSED_17 = 17 + ATTRIBUTE_LINETYPE = 18 + ATTRIBUTE_MARKER = 19 + ATTRIBUTE_FILL = 20 + UNUSED_21 = 21 + ATTRIBUTE_TRUE_COLOR = 22 + ATTRIBUTE_LINEWEIGHT = 23 + ATTRIBUTE_LTSCALE = 24 + ATTRIBUTE_THICKNESS = 25 + ATTRIBUTE_PLOT_STYLE_NAME = 26 + PUSH_CLIP = 27 + POP_CLIP = 28 + PUSH_MATRIX = 29 + PUSH_MATRIX2 = 30 + POP_MATRIX = 31 + POLYLINE_WITH_NORMALS = 32 + LWPOLYLINE = 33 + ATTRIBUTE_MATERIAL = 34 + ATTRIBUTE_MAPPER = 35 + UNICODE_TEXT = 36 + UNKNOWN_37 = 37 + UNICODE_TEXT2 = 38 + ELLIPTIC_ARC = 44 # found in test data of issue #832 + + +class ProxyGraphic: + def __init__( + self, data: bytes, doc: Optional[Drawing] = None, *, dxfversion=const.DXF2000 + ): + self._doc = doc + self._factory = factory.new + self._buffer: bytes = data + self._index: int = 8 + self.dxfversion = doc.dxfversion if doc else dxfversion + self.encoding: str = "cp1252" if self.dxfversion < const.DXF2007 else "utf-8" + self.color: int = const.BYLAYER + self.layer: str = "0" + self.linetype: str = "BYLAYER" + self.marker_index: int = 0 + self.fill: bool = False + self.true_color: Optional[int] = None + self.lineweight: int = const.LINEWEIGHT_DEFAULT + self.ltscale: float = 1.0 + self.thickness: float = 0.0 + # Layer list in storage order + self.layers: list[str] = [] + # Linetypes list in storage order + self.linetypes: list[str] = [] + # List of text styles, with font name as key + self.textstyles: dict[str, str] = dict() + self.required_fonts: set[str] = set() + self.matrices: list[Matrix44] = [] + + if self._doc: + self.layers = list(layer.dxf.name for layer in self._doc.layers) + self.linetypes = list(linetype.dxf.name for linetype in self._doc.linetypes) + self.textstyles = { + style.dxf.font: style.dxf.name for style in self._doc.styles + } + self.encoding = self._doc.encoding + + def info(self) -> Iterable[tuple[int, int, str]]: + index = self._index + buffer = self._buffer + while index < len(buffer): + size, type_ = struct.unpack_from("<2L", self._buffer, offset=index) + try: + name = ProxyGraphicTypes(type_).name + except ValueError: + name = f"UNKNOWN_TYPE_{type_}" + yield index, size, name + index += size + + def virtual_entities(self) -> Iterator[DXFGraphic]: + return self.__virtual_entities__() + + def __virtual_entities__(self) -> Iterator[DXFGraphic]: + """Implements the SupportsVirtualEntities protocol.""" + try: + yield from self.unsafe_virtual_entities() + except Exception as e: + raise ProxyGraphicError(f"Proxy graphic error: {str(e)}") + + def unsafe_virtual_entities(self) -> Iterable[DXFGraphic]: + def transform(entity): + if self.matrices: + return entity.transform(self.matrices[-1]) + else: + return entity + + index = self._index + buffer = self._buffer + while index < len(buffer): + size, type_ = struct.unpack_from("<2L", self._buffer, offset=index) + try: + name = ProxyGraphicTypes(type_).name.lower() + except ValueError: + logger.debug(f"Unsupported Type Code: {type_}") + index += size + continue + method = getattr(self, name, None) + if method: + result = method(self._buffer[index + 8 : index + size]) + if isinstance(result, tuple): + for entity in result: + yield transform(entity) + elif result: + yield transform(result) + if result: # reset fill after each graphic entity + self.fill = False + else: + logger.debug(f"Unsupported feature ProxyGraphic.{name}()") + index += size + + def push_matrix(self, data: bytes): + values = struct.unpack("<16d", data) + m = Matrix44(values) + m.transpose() + self.matrices.append(m) + + def pop_matrix(self, data: bytes): + if self.matrices: + self.matrices.pop() + + def reset_colors(self): + self.color = const.BYLAYER + self.true_color = None + + def attribute_color(self, data: bytes): + self.reset_colors() + self.color = struct.unpack(" 256: + self.color = const.BYLAYER + + def attribute_layer(self, data: bytes): + if self._doc: + index = struct.unpack(" const.MAX_VALID_LINEWEIGHT: + self.lineweight = max(lw - 0x100000000, const.LINEWEIGHT_DEFAULT) + else: + self.lineweight = lw + + def attribute_ltscale(self, data: bytes): + self.ltscale = struct.unpack("= "AC1024": # R2010+ + if flag & 1024: + num_vertex_ids = bs.read_bit_long() + if flag & 32: + num_width = bs.read_bit_long() + # ignore DXF R13/14 special vertex order + + vertices: list[tuple[float, float]] = [bs.read_raw_double(2)] # type: ignore + prev_point = vertices[-1] + for _ in range(num_points - 1): + x = bs.read_bit_double_default(default=prev_point[0]) # type: ignore + y = bs.read_bit_double_default(default=prev_point[1]) # type: ignore + prev_point = (x, y) + vertices.append(prev_point) + bulges: list[float] = [bs.read_bit_double() for _ in range(num_bulges)] + vertex_ids: list[int] = [bs.read_bit_long() for _ in range(num_vertex_ids)] + widths: list[tuple[float, float]] = [ + (bs.read_bit_double(), bs.read_bit_double()) for _ in range(num_width) + ] + if len(bulges) == 0: + bulges = list(repeat(0, num_points)) + if len(widths) == 0: + widths = list(repeat((0, 0), num_points)) + points: list[Sequence[float]] = [] + for v, w, b in zip(vertices, widths, bulges): + points.append((v[0], v[1], w[0], w[1], b)) + lwpolyline = cast("LWPolyline", self._factory("LWPOLYLINE", dxfattribs=attribs)) + lwpolyline.set_points(points) + lwpolyline.closed = is_closed + return lwpolyline + + def mesh(self, data: bytes): + # Limitations of the PolyFacMesh entity: + # - all VERTEX entities have to reside on the same layer + # - does not support vertex normals + # - all faces have the same color (no face record) + + logger.warning("Untested proxy graphic entity: MESH - Need examples!") + bs = ByteStream(data) + rows, columns = bs.read_struct("<2L") + total_edge_count = (rows - 1) * columns + (columns - 1) * rows + total_face_count = (rows - 1) * (columns - 1) + total_vertex_count = rows * columns + vertices = [Vec3(bs.read_vertex()) for _ in range(total_vertex_count)] + + traits = dict() + try: + traits = read_mesh_traits( + bs, total_edge_count, total_face_count, vertex_count=0 + ) + except struct.error: + logger.error("Structure error while parsing traits for MESH proxy graphic") + if traits: + # apply traits + pass + + # create PolyMesh entity + attribs = self._build_dxf_attribs() + attribs["m_count"] = rows + attribs["n_count"] = columns + attribs["flags"] = const.POLYLINE_3D_POLYMESH + polymesh = cast("Polymesh", self._factory("POLYLINE", dxfattribs=attribs)) + polymesh.append_vertices(vertices) + return polymesh + + def shell(self, data: bytes): + # Limitations of the PolyFacMesh entity: + # - all VERTEX entities have to reside on the same layer + # - does not support vertex normals + bs = ByteStream(data) + attribs = self._build_dxf_attribs() + attribs["flags"] = const.POLYLINE_POLYFACE + polyface = cast("Polyface", self._factory("POLYLINE", dxfattribs=attribs)) + total_vertex_count = bs.read_long() + vertices = [Vec3(bs.read_vertex()) for _ in range(total_vertex_count)] + face_entry_count = bs.read_long() + faces = [] + read_count: int = 0 + total_face_count: int = 0 + total_edge_count: int = 0 + while read_count < face_entry_count: + edge_count = abs(bs.read_signed_long()) + read_count += 1 + edge_count + face_indices = [bs.read_long() for _ in range(edge_count)] + face = [vertices[index] for index in face_indices] + total_face_count += 1 + total_edge_count += edge_count + faces.append(face) + + traits = dict() + try: + traits = read_mesh_traits( + bs, total_edge_count, total_face_count, vertex_count=0 + ) + except struct.error: + logger.error("Structure error while parsing traits for SHELL proxy graphic") + polyface.append_faces(faces) + if traits: + face_traits = traits.get("faces") + if face_traits: + face_colors = face_traits.get("colors") + if face_colors: + logger.warning( + "Untested proxy graphic feature for SHELL: " + "apply face colors - Need examples!" + ) + assert isinstance(face_colors, list) + _apply_face_colors(polyface, face_colors) + polyface.optimize() + return polyface + + def text(self, data: bytes): + return self._text(data, unicode=False) + + def unicode_text(self, data: bytes): + return self._text(data, unicode=True) + + def _text(self, data: bytes, unicode: bool = False): + bs = ByteStream(data) + start_point = Vec3(bs.read_vertex()) + normal = Vec3(bs.read_vertex()) + text_direction = Vec3(bs.read_vertex()) + height, width_factor, oblique_angle = bs.read_struct("<3d") + text = "" + if unicode: + try: + text = bs.read_padded_unicode_string() + except UnicodeDecodeError as e: + logger.debug(f"ProxyGraphic._text(unicode=True); {str(e)}") + else: + try: + text = bs.read_padded_string(self.encoding) + except UnicodeDecodeError as e: + logger.debug( + f"ProxyGraphic._text(unicode=False); encoding={self.encoding}; {str(e)}" + ) + attribs = self._build_dxf_attribs() + attribs["insert"] = start_point + attribs["text"] = text + attribs["height"] = height + attribs["width"] = width_factor + attribs["rotation"] = text_direction.angle_deg + attribs["oblique"] = math.degrees(oblique_angle) + attribs["extrusion"] = normal + return self._factory("TEXT", dxfattribs=attribs) + + def text2(self, data: bytes): + encoding = self.encoding + bs = ByteStream(data) + start_point = Vec3(bs.read_vertex()) + normal = Vec3(bs.read_vertex()) + text_direction = Vec3(bs.read_vertex()) + text = "" + try: + text = bs.read_padded_string(encoding=encoding) + except UnicodeDecodeError as e: + logger.debug(f"ProxyGraphic.text2(); text; encoding={encoding}; {str(e)}") + + ignore_length_of_string, raw = bs.read_struct("<2l") + ( + height, + width_factor, + oblique_angle, + tracking_percentage, + ) = bs.read_struct("<4d") + ( + is_backwards, + is_upside_down, + is_vertical, + is_underline, + is_overline, + ) = bs.read_struct("<5L") + font_filename: str = "TXT.SHX" + big_font_filename: str = "" + try: + font_filename = bs.read_padded_string(encoding=encoding) + big_font_filename = bs.read_padded_string(encoding=encoding) + except UnicodeDecodeError as e: + logger.debug( + f"ProxyGraphic.text2(); fonts; encoding='{encoding}'; {str(e)}" + ) + + attribs = self._build_dxf_attribs() + attribs["insert"] = start_point + attribs["text"] = text + attribs["height"] = height + attribs["width"] = width_factor + attribs["rotation"] = text_direction.angle_deg + attribs["oblique"] = math.degrees(oblique_angle) + attribs["style"] = self._get_style(font_filename, big_font_filename) + attribs["text_generation_flag"] = 2 * is_backwards + 4 * is_upside_down + attribs["extrusion"] = normal + return self._factory("TEXT", dxfattribs=attribs) + + def unicode_text2(self, data: bytes): + bs = ByteStream(data) + start_point = Vec3(bs.read_vertex()) + normal = Vec3(bs.read_vertex()) + text_direction = Vec3(bs.read_vertex()) + text = "" + try: + text = bs.read_padded_unicode_string() + except UnicodeDecodeError as e: + logger.debug(f"ProxyGraphic.unicode_text2(); text; {str(e)}") + + ignore_length_of_string, ignore_raw = bs.read_struct("<2l") + ( + height, + width_factor, + oblique_angle, + tracking_percentage, + ) = bs.read_struct("<4d") + ( + is_backwards, + is_upside_down, + is_vertical, + is_underline, + is_overline, + ) = bs.read_struct("<5L") + is_bold, is_italic, charset, pitch = bs.read_struct("<4L") + + type_face: str = "" + font_filename: str = "TXT.SHX" + big_font_filename: str = "" + try: + type_face = bs.read_padded_unicode_string() + font_filename = bs.read_padded_unicode_string() + big_font_filename = bs.read_padded_unicode_string() + except UnicodeDecodeError as e: + logger.debug(f"ProxyGraphic.unicode_text2(); fonts; {str(e)}") + + attribs = self._build_dxf_attribs() + attribs["insert"] = start_point + attribs["text"] = text + attribs["height"] = height + attribs["width"] = width_factor + attribs["rotation"] = text_direction.angle_deg + attribs["oblique"] = math.degrees(oblique_angle) + attribs["style"] = self._get_style(font_filename, big_font_filename) + attribs["text_generation_flag"] = 2 * is_backwards + 4 * is_upside_down + attribs["extrusion"] = normal + return self._factory("TEXT", dxfattribs=attribs) + + def xline(self, data: bytes): + return self._xline(data, "XLINE") + + def ray(self, data: bytes): + return self._xline(data, "RAY") + + def _xline(self, data: bytes, type_: str): + logger.warning("Untested proxy graphic entity: RAY/XLINE - Need examples!") + bs = ByteStream(data) + attribs = self._build_dxf_attribs() + start_point = Vec3(bs.read_vertex()) + other_point = Vec3(bs.read_vertex()) + attribs["start"] = start_point + attribs["unit_vector"] = (other_point - start_point).normalize() + return self._factory(type_, dxfattribs=attribs) + + def _get_style(self, font: str, bigfont: str) -> str: + self.required_fonts.add(font) + if font in self.textstyles: + style = self.textstyles[font] + else: + style = font + if self._doc and not self._doc.styles.has_entry(style): + self._doc.styles.new( + font, dxfattribs={"font": font, "bigfont": bigfont} + ) + self.textstyles[font] = style + return style + + @staticmethod + def _load_vertices(data: bytes, load_normal=False) -> tuple[list[Vec3], Vec3]: + normal = Z_AXIS + bs = ByteStream(data) + count = bs.read_long() + if load_normal: + count += 1 + vertices: list[Vec3] = [] + while count > 0: + vertices.append(Vec3(bs.read_struct("<3d"))) + count -= 1 + if load_normal: + normal = vertices.pop() + return vertices, normal + + def _build_dxf_attribs(self) -> dict[str, Any]: + attribs: dict[str, Any] = dict() + if self.layer != "0": + attribs["layer"] = self.layer + if self.color != const.BYLAYER: + attribs["color"] = self.color + if self.linetype != "BYLAYER": + attribs["linetype"] = self.linetype + if self.lineweight != const.LINEWEIGHT_DEFAULT: + attribs["lineweight"] = self.lineweight + if self.ltscale != 1.0: + attribs["ltscale"] = self.ltscale + if self.true_color is not None: + attribs["true_color"] = self.true_color + return attribs + + +class ProxyGraphicDebugger(ProxyGraphic): + def __init__(self, data: bytes, doc: Optional[Drawing] = None, debug_stream=None): + super(ProxyGraphicDebugger, self).__init__(data, doc) + if debug_stream is None: + debug_stream = sys.stdout + self._debug_stream = debug_stream + + def log_entities(self): + self.log_separator(char="=", newline=False) + self.log_message("Create virtual DXF entities:") + self.log_separator(newline=False) + for entity in self.virtual_entities(): + self.log_message(f"\n * {entity.dxftype()}") + self.log_message(f" * {entity.graphic_properties()}\n") + self.log_separator(char="=") + + def log_commands(self): + self.log_separator(char="=", newline=False) + self.log_message("Raw proxy commands:") + self.log_separator(newline=False) + for index, size, cmd in self.info(): + self.log_message(f"Command: {cmd} Index: {index} Size: {size}") + self.log_separator(char="=") + + def log_separator(self, char="-", newline=True): + self.log_message(char * 79) + if newline: + self.log_message("") + + def log_message(self, msg: str): + print(msg, file=self._debug_stream) + + def log_state(self): + self.log_message("> " + self.get_state()) + + def get_state(self) -> str: + return ( + f"ly: '{self.layer}', clr: {self.color}, lt: {self.linetype}, " + f"lw: {self.lineweight}, ltscale: {self.ltscale}, " + f"rgb: {self.true_color}, fill: {self.fill}" + ) + + def attribute_color(self, data: bytes): + self.log_message("Command: set COLOR") + super().attribute_color(data) + self.log_state() + + def attribute_layer(self, data: bytes): + self.log_message("Command: set LAYER") + super().attribute_layer(data) + self.log_state() + + def attribute_linetype(self, data: bytes): + self.log_message("Command: set LINETYPE") + super().attribute_linetype(data) + self.log_state() + + def attribute_true_color(self, data: bytes): + self.log_message("Command: set TRUE-COLOR") + super().attribute_true_color(data) + self.log_state() + + def attribute_lineweight(self, data: bytes): + self.log_message("Command: set LINEWEIGHT") + super().attribute_lineweight(data) + self.log_state() + + def attribute_ltscale(self, data: bytes): + self.log_message("Command: set LTSCALE") + super().attribute_ltscale(data) + self.log_state() + + def attribute_fill(self, data: bytes): + self.log_message("Command: set FILL") + super().attribute_fill(data) + self.log_state() + + +def _apply_face_colors(polyface: Polyface, colors: list[int]) -> None: + color_count: int = len(colors) + if color_count == 0: + return + + index: int = 0 + for vertex in polyface.vertices: + if vertex.is_face_record: + vertex.dxf.color = colors[index] + index += 1 + if index >= color_count: + return + + +def _get_elevation(vertices) -> float: + if vertices: + return vertices[0].z + return 0.0 + + +def is_2d_polyline(vertices: list[Vec3]) -> bool: + if len(vertices) < 1: + return True + z = vertices[0].z + return all(math.isclose(z, v.z) for v in vertices) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/py.typed b/.venv/lib/python3.12/site-packages/ezdxf/py.typed new file mode 100644 index 0000000..5f3ea3d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/py.typed @@ -0,0 +1,2 @@ +# Instruct type checkers to look for inline type annotations in this package. +# See PEP 561. diff --git a/.venv/lib/python3.12/site-packages/ezdxf/query.py b/.venv/lib/python3.12/site-packages/ezdxf/query.py new file mode 100644 index 0000000..ff92008 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/query.py @@ -0,0 +1,631 @@ +# Purpose: Query language and manipulation object for DXF entities +# Copyright (c) 2013-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + Callable, + Hashable, + Sequence, + Union, + Optional, +) +import re +import operator +from collections import abc + +from ezdxf.entities.dxfentity import DXFEntity +from ezdxf.groupby import groupby +from ezdxf.math import Vec3, Vec2 +from ezdxf.queryparser import EntityQueryParser + + +class _AttributeDescriptor: + def __init__(self, name: str): + self.name = name + + def __get__(self, obj, objtype=None): + return obj.__getitem__(self.name) + + def __set__(self, obj, value): + obj.__setitem__(self.name, value) + + def __delete__(self, obj): + obj.__delitem__(self.name) + + +class EntityQuery(abc.Sequence): + """EntityQuery is a result container, which is filled with dxf entities + matching the query string. It is possible to add entities to the container + (extend), remove entities from the container and to filter the container. + + Query String + ============ + + QueryString := EntityQuery ("[" AttribQuery "]")* + + The query string is the combination of two queries, first the required + entity query and second the optional attribute query, enclosed in square + brackets. + + Entity Query + ------------ + + The entity query is a whitespace separated list of DXF entity names or the + special name ``*``. Where ``*`` means all DXF entities, exclude some entity + types by appending their names with a preceding ``!`` (e.g. all entities + except LINE = ``* !LINE``). All DXF names have to be uppercase. + + Attribute Query + --------------- + + The attribute query is used to select DXF entities by its DXF attributes. + The attribute query is an addition to the entity query and matches only if + the entity already match the entity query. + The attribute query is a boolean expression, supported operators are: + + - not: !term is true, if term is false + - and: term & term is true, if both terms are true + - or: term | term is true, if one term is true + - and arbitrary nested round brackets + + Attribute selection is a term: "name comparator value", where name is a DXF + entity attribute in lowercase, value is a integer, float or double quoted + string, valid comparators are: + + - "==" equal "value" + - "!=" not equal "value" + - "<" lower than "value" + - "<=" lower or equal than "value" + - ">" greater than "value" + - ">=" greater or equal than "value" + - "?" match regular expression "value" + - "!?" does not match regular expression "value" + + Query Result + ------------ + + The EntityQuery() class based on the abstract Sequence() class, contains all + DXF entities of the source collection, which matches one name of the entity + query AND the whole attribute query. If a DXF entity does not have or + support a required attribute, the corresponding attribute search term is + false. + + Examples: + + - 'LINE[text ? ".*"]' is always empty, because the LINE entity has no + text attribute. + - 'LINE CIRCLE[layer=="construction"]' => all LINE and CIRCLE entities + on layer "construction" + - '*[!(layer=="construction" & color<7)]' => all entities except those + on layer == "construction" and color < 7 + + """ + + layer = _AttributeDescriptor("layer") + color = _AttributeDescriptor("color") + linetype = _AttributeDescriptor("linetype") + lineweight = _AttributeDescriptor("lineweight") + ltscale = _AttributeDescriptor("ltscale") + invisible = _AttributeDescriptor("invisible") + true_color = _AttributeDescriptor("true_color") + transparency = _AttributeDescriptor("transparency") + + def __init__( + self, entities: Optional[Iterable[DXFEntity]] = None, query: str = "*" + ): + """ + Setup container with entities matching the initial query. + + Args: + entities: sequence of wrapped DXF entities (at least GraphicEntity class) + query: query string, see class documentation + + """ + # Selected DXF attribute for operator selection: + self.selected_dxf_attribute: str = "" + # Text selection mode, but only for operator comparisons: + self.ignore_case = True + + self.entities: list[DXFEntity] + if entities is None: + self.entities = [] + elif query == "*": + self.entities = list(entities) + else: + match = entity_matcher(query) + self.entities = [entity for entity in entities if match(entity)] + + def __len__(self) -> int: + """Returns count of DXF entities.""" + return len(self.entities) + + def __iter__(self) -> Iterator[DXFEntity]: + """Returns iterable of DXFEntity objects.""" + return iter(self.entities) + + def __getitem__(self, item): + """Returns DXFEntity at index `item`, supports negative indices and + slicing. Returns all entities which support a specific DXF attribute, + if `item` is a DXF attribute name as string. + """ + if isinstance(item, str): + return self._get_entities_with_supported_attribute(item) + return self.entities.__getitem__(item) + + def __setitem__(self, key, value): + """Set the DXF attribute `key` for all supported DXF entities to `value`. + """ + if not isinstance(key, str): + raise TypeError("key has to be a string (DXF attribute name)") + self._set_dxf_attribute_for_all(key, value) + + def __delitem__(self, key): + """Discard the DXF attribute `key` from all supported DXF entities.""" + if not isinstance(key, str): + raise TypeError("key has to be a string (DXF attribute name)") + self._discard_dxf_attribute_for_all(key) + + def purge(self) -> EntityQuery: + """Remove destroyed entities.""" + self.entities = [e for e in self.entities if e.is_alive] + return self # fluent interface + + def _get_entities_with_supported_attribute( + self, attribute: str + ) -> EntityQuery: + query = self.__class__( + e for e in self.entities if e.dxf.is_supported(attribute) + ) + query.selected_dxf_attribute = attribute + return query + + def _set_dxf_attribute_for_all(self, key, value): + for e in self.entities: + try: + e.dxf.set(key, value) + except AttributeError: # ignore unsupported attributes + pass + # But raises ValueError/TypeError for invalid values! + + def _discard_dxf_attribute_for_all(self, key): + for e in self.entities: + e.dxf.discard(key) + + def __eq__(self, other): + """Equal selector (self == other). + Returns all entities where the selected DXF attribute is equal to + `other`. + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.eq) + + def __ne__(self, other): + """Not equal selector (self != other). Returns all entities where the + selected DXF attribute is not equal to `other`. + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.ne) + + def __lt__(self, other): + """Less than selector (self < other). Returns all entities where the + selected DXF attribute is less than `other`. + + Raises: + TypeError: for vector based attributes like `center` or `insert` + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.lt, vectors=False) + + def __gt__(self, other): + """Greater than selector (self > other). Returns all entities where the + selected DXF attribute is greater than `other`. + + Raises: + TypeError: for vector based attributes like `center` or `insert` + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.gt, vectors=False) + + def __le__(self, other): + """Less equal selector (self <= other). Returns all entities where the + selected DXF attribute is less or equal `other`. + + Raises: + TypeError: for vector based attributes like `center` or `insert` + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.le, vectors=False) + + def __ge__(self, other): + """Greater equal selector (self >= other). Returns all entities where + the selected DXF attribute is greater or equal `other`. + + Raises: + TypeError: for vector based attributes like `center` or `insert` + """ + if not self.selected_dxf_attribute: + raise TypeError("no DXF attribute selected") + return self._select_by_operator(other, operator.ge, vectors=False) + + def __or__(self, other): + """Union operator, see :meth:`union`.""" + if isinstance(other, EntityQuery): + return self.union(other) + return NotImplemented + + def __and__(self, other): + """Intersection operator, see :meth:`intersection`.""" + if isinstance(other, EntityQuery): + return self.intersection(other) + return NotImplemented + + def __sub__(self, other): + """Difference operator, see :meth:`difference`.""" + if isinstance(other, EntityQuery): + return self.difference(other) + return NotImplemented + + def __xor__(self, other): + """Symmetric difference operator, see :meth:`symmetric_difference`.""" + if isinstance(other, EntityQuery): + return self.symmetric_difference(other) + return NotImplemented + + def _select_by_operator(self, value, op, vectors=True) -> EntityQuery: + attribute = self.selected_dxf_attribute + if self.ignore_case and isinstance(value, str): + value = value.lower() + + query = self.__class__() + query.selected_dxf_attribute = attribute + entities = query.entities + if attribute: + for entity in self.entities: + try: + entity_value = entity.dxf.get_default(attribute) + except AttributeError: + continue + if not vectors and isinstance(entity_value, (Vec2, Vec3)): + raise TypeError( + f"unsupported operation '{str(op.__name__)}' for DXF " + f"attribute {attribute}" + ) + if self.ignore_case and isinstance(entity_value, str): + entity_value = entity_value.lower() + if op(entity_value, value): + entities.append(entity) + return query + + def match(self, pattern: str) -> EntityQuery: + """Returns all entities where the selected DXF attribute matches the + regular expression `pattern`. + + Raises: + TypeError: for non-string based attributes + + """ + + def match(value, regex): + if isinstance(value, str): + return regex.match(value) is not None + raise TypeError( + f"cannot apply regular expression to DXF attribute: " + f"{self.selected_dxf_attribute}" + ) + + return self._regex_match(pattern, match) + + def _regex_match(self, pattern: str, func) -> EntityQuery: + ignore_case = self.ignore_case + self.ignore_case = False # deactivate string manipulation + re_flags = re.IGNORECASE if ignore_case else 0 + + # always match whole pattern + if not pattern.endswith("$"): + pattern += "$" + result = self._select_by_operator( + re.compile(pattern, flags=re_flags), func + ) + self.ignore_case = ignore_case # restore state + return result + + @property + def first(self): + """First entity or ``None``.""" + if len(self.entities): + return self.entities[0] + else: + return None + + @property + def last(self): + """Last entity or ``None``.""" + if len(self.entities): + return self.entities[-1] + else: + return None + + def extend( + self, + entities: Iterable[DXFEntity], + query: str = "*", + ) -> EntityQuery: + """Extent the :class:`EntityQuery` container by entities matching an + additional query. + + """ + self.entities = self.union(self.__class__(entities, query)).entities + return self # fluent interface + + def remove(self, query: str = "*") -> EntityQuery: + """Remove all entities from :class:`EntityQuery` container matching this + additional query. + + """ + self.entities = self.difference( + self.__class__(self.entities, query) + ).entities + return self # fluent interface + + def query(self, query: str = "*") -> EntityQuery: + """Returns a new :class:`EntityQuery` container with all entities + matching this additional query. + + Raises: + pyparsing.ParseException: query string parsing error + + """ + return self.__class__(self.entities, query) + + def groupby( + self, + dxfattrib: str = "", + key: Optional[Callable[[DXFEntity], Hashable]] = None, + ) -> dict[Hashable, list[DXFEntity]]: + """Returns a dict of entity lists, where entities are grouped by a DXF + attribute or a key function. + + Args: + dxfattrib: grouping DXF attribute as string like ``'layer'`` + key: key function, which accepts a DXFEntity as argument, returns + grouping key of this entity or ``None`` for ignore this object. + Reason for ignoring: a queried DXF attribute is not supported by + this entity + + """ + return groupby(self.entities, dxfattrib, key) + + def filter(self, func: Callable[[DXFEntity], bool]) -> EntityQuery: + """Returns a new :class:`EntityQuery` with all entities from this + container for which the callable `func` returns ``True``. + + Build your own operator to filter by attributes which are not DXF + attributes or to build complex queries:: + + result = msp.query().filter( + lambda e: hasattr(e, "rgb") and e.rbg == (0, 0, 0) + ) + """ + return self.__class__(filter(func, self.entities)) + + def union(self, other: EntityQuery) -> EntityQuery: + """Returns a new :class:`EntityQuery` with entities from `self` and + `other`. All entities are unique - no duplicates. + """ + return self.__class__(set(self.entities) | set(other.entities)) + + def intersection(self, other: EntityQuery) -> EntityQuery: + """Returns a new :class:`EntityQuery` with entities common to `self` + and `other`. + """ + return self.__class__(set(self.entities) & set(other.entities)) + + def difference(self, other: EntityQuery) -> EntityQuery: + """Returns a new :class:`EntityQuery` with all entities from `self` that + are not in `other`. + """ + return self.__class__(set(self.entities) - set(other.entities)) + + def symmetric_difference(self, other: EntityQuery) -> EntityQuery: + """Returns a new :class:`EntityQuery` with entities in either `self` or + `other` but not both. + """ + return self.__class__(set(self.entities) ^ set(other.entities)) + + +def entity_matcher(query: str) -> Callable[[DXFEntity], bool]: + query_args = EntityQueryParser.parseString(query, parseAll=True) + entity_matcher_ = build_entity_name_matcher(query_args.EntityQuery) + attrib_matcher = build_entity_attributes_matcher( + query_args.AttribQuery, query_args.AttribQueryOptions + ) + + def matcher(entity: DXFEntity) -> bool: + return entity_matcher_(entity) and attrib_matcher(entity) + + return matcher + + +def build_entity_name_matcher( + names: Sequence[str], +) -> Callable[[DXFEntity], bool]: + def match(e: DXFEntity) -> bool: + return _match(e.dxftype()) + + _match = name_matcher(query=" ".join(names)) + return match + + +class Relation: + CMP_OPERATORS = { + "==": operator.eq, + "!=": operator.ne, + "<": operator.lt, + "<=": operator.le, + ">": operator.gt, + ">=": operator.ge, + "?": lambda e, regex: regex.match(e) is not None, + "!?": lambda e, regex: regex.match(e) is None, + } + VALID_CMP_OPERATORS = frozenset(CMP_OPERATORS.keys()) + + def __init__(self, relation: Sequence, ignore_case: bool): + name, op, value = relation + self.dxf_attrib = name + self.compare = Relation.CMP_OPERATORS[op] + self.convert_case = to_lower if ignore_case else lambda x: x + + re_flags = re.IGNORECASE if ignore_case else 0 + if "?" in op: + self.value = re.compile( + value + "$", flags=re_flags + ) # always match whole pattern + else: + self.value = self.convert_case(value) + + def evaluate(self, entity: DXFEntity) -> bool: + try: + value = self.convert_case(entity.dxf.get_default(self.dxf_attrib)) + return self.compare(value, self.value) + except AttributeError: # entity does not support this attribute + return False + except ValueError: # entity supports this attribute, but has no value for it + return False + + +def to_lower(value): + return value.lower() if hasattr(value, "lower") else value + + +class BoolExpression: + OPERATORS = { + "&": operator.and_, + "|": operator.or_, + } + + def __init__(self, tokens: Sequence): + self.tokens = tokens + + def __iter__(self): + return iter(self.tokens) + + def evaluate(self, entity: DXFEntity) -> bool: + if isinstance( + self.tokens, Relation + ): # expression is just one relation, no bool operations + return self.tokens.evaluate(entity) + + values = [] # first in, first out + operators = [] # first in, first out + for token in self.tokens: + if hasattr(token, "evaluate"): + values.append(token.evaluate(entity)) + else: # bool operator + operators.append(token) + values.reverse() + for op in operators: # as queue -> first in, first out + if op == "!": + value = not values.pop() + else: + value = BoolExpression.OPERATORS[op](values.pop(), values.pop()) + values.append(value) + return values.pop() + + +def _compile_tokens( + tokens: Union[str, Sequence], ignore_case: bool +) -> Union[str, Relation, BoolExpression]: + def is_relation(tokens: Sequence) -> bool: + return len(tokens) == 3 and tokens[1] in Relation.VALID_CMP_OPERATORS + + if isinstance(tokens, str): # bool operator as string + return tokens + + tokens = tuple(tokens) + if is_relation(tokens): + return Relation(tokens, ignore_case) + else: + return BoolExpression( + [_compile_tokens(token, ignore_case) for token in tokens] + ) + + +def build_entity_attributes_matcher( + tokens: Sequence, options: str +) -> Callable[[DXFEntity], bool]: + if not len(tokens): + return lambda x: True + ignore_case = "i" == options # at this time just one option is supported + expr = BoolExpression(_compile_tokens(tokens, ignore_case)) # type: ignore + + def match_bool_expr(entity: DXFEntity) -> bool: + return expr.evaluate(entity) + + return match_bool_expr + + +def unique_entities(entities: Iterable[DXFEntity]) -> Iterator[DXFEntity]: + """Yield all unique entities, order of all entities will be preserved.""" + done: set[DXFEntity] = set() + for entity in entities: + if entity not in done: + done.add(entity) + yield entity + + +def name_query(names: Iterable[str], query: str = "*") -> Iterator[str]: + """Filters `names` by `query` string. The `query` string of entity names + divided by spaces. The special name "*" matches any given name, a + preceding "!" means exclude this name. Excluding names is only useful if + the match any name is also given (e.g. "LINE !CIRCLE" is equal to just + "LINE", where "* !CIRCLE" matches everything except CIRCLE"). + + Args: + names: iterable of names to test + query: query string of entity names separated by spaces + + Returns: yield matching names + + """ + match = name_matcher(query) + return (name for name in names if match(name)) + + +def name_matcher(query: str = "*") -> Callable[[str], bool]: + def match(e: str) -> bool: + if take_all: + return e not in exclude + else: + return e in include + + match_strings = set(query.upper().split()) + take_all = False + exclude = set() + include = set() + for name in match_strings: + if name == "*": + take_all = True + elif name.startswith("!"): + exclude.add(name[1:]) + else: + include.add(name) + + return match + + +def new( + entities: Optional[Iterable[DXFEntity]] = None, query: str = "*" +) -> EntityQuery: + """Start a new query based on sequence `entities`. The `entities` argument + has to be an iterable of :class:`~ezdxf.entities.DXFEntity` or inherited + objects and returns an :class:`EntityQuery` object. + + """ + return EntityQuery(entities, query) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/queryparser.py b/.venv/lib/python3.12/site-packages/ezdxf/queryparser.py new file mode 100644 index 0000000..ab77a1f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/queryparser.py @@ -0,0 +1,78 @@ +# Copyright (c) 2013-2021, Manfred Moitzi +# License: MIT-License +# mypy: ignore_errors=True +""" +EntityQueryParser implemented with the pyparsing module created by Paul T. McGuire. + +QueryString := EntityQuery ("[" AttribQuery "]" "i"?)* + +The QueryString consist of two queries, first the required entity query and the second optional attribute query, +enclosed in square brackets an optional appended "i" indicates ignore case for string queries. + +1. EntityQuery (required) + +The EntityQuery is a whitespace separated list of names (DXF entity names) or the special name "*". + +2. AttribQuery (optional) + +The AttribQuery is a boolean expression, supported boolean operators are: + + - '!' not: !term if true, if tern is false. + - '&' and: term & term is true, if both terms are true. + - '|' or: term | term is true, if one term is true. + +The query itself consist of a name a comparator and a value, like "color < 7". +Supported comparators are: + + - '==': equal + - '!=': not equal + - '<': lower than + - '<=': lower or equal than + - '>': greater than + - '>=': greater or equal than + - '?': match a regular expression + - '!?': does not match a regular expression + +Values can be integers, floats or strings, strings have to be quoted ("I am a string" or 'I am a string'). + +examples: + 'LINE CIRCLE[layer=="construction"]' => all LINE and CIRCLE entities on layer "construction" + '*[!(layer=="construction" & color<7)]' => all entities except those on layer == "construction" and color < 7 + 'LINE[layer=="construction"]i' => all lines on layer named 'construction' with case insensitivity, "CoNsTrUcTiOn" is valid +""" + +from pyparsing import * + +LBRK = Suppress("[") +RBRK = Suppress("]") + +number = Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?") +number.addParseAction(lambda t: float(t[0])) # convert to float +string_ = quotedString.addParseAction(lambda t: t[0][1:-1]) # remove quotes + +EntityName = Word(alphanums + "_") +# ExcludeEntityName = Word(alphanums + '_!') +ExcludeEntityName = Regex(r"[!][\w]+") +AttribName = Word(alphanums + "_") +Relation = oneOf(["==", "!=", "<", "<=", ">", ">=", "?", "!?"]) + +AttribValue = string_ | number +AttribQuery = Group(AttribName + Relation + AttribValue) +EntityNames = Group( + (Literal("*") + ZeroOrMore(ExcludeEntityName)) | OneOrMore(EntityName) +).setResultsName("EntityQuery") + +InfixBoolQuery = infixNotation( + AttribQuery, + ( + ("!", 1, opAssoc.RIGHT), + ("&", 2, opAssoc.LEFT), + ("|", 2, opAssoc.LEFT), + ), +).setResultsName("AttribQuery") + +AttribQueryOptions = Literal("i").setResultsName("AttribQueryOptions") + +EntityQueryParser = EntityNames + Optional( + LBRK + InfixBoolQuery + RBRK + Optional(AttribQueryOptions) +) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/r12strict.py b/.venv/lib/python3.12/site-packages/ezdxf/r12strict.py new file mode 100644 index 0000000..69c6a1c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/r12strict.py @@ -0,0 +1,258 @@ +# Copyright (c) 2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import string +from ezdxf import const +from ezdxf.lldxf.types import dxftag +from ezdxf.entities import XData, DXFEntity, is_graphic_entity +from ezdxf.document import Drawing +from ezdxf.sections.table import Table + +__all__ = ["make_acad_compatible", "translate_names", "clean", "R12NameTranslator"] + + +def make_acad_compatible(doc: Drawing) -> None: + """Apply all DXF R12 requirements, so Autodesk products will load the document.""" + if doc.dxfversion != const.DXF12: + raise const.DXFVersionError( + f"expected DXF document version R12, got: {doc.acad_release}" + ) + clean(doc) + translate_names(doc) + + +def translate_names(doc: Drawing) -> None: + r"""Translate table and block names into strict DXF R12 names. + + ACAD Releases upto 14 limit names to 31 characters in length and all names are + uppercase. Names can include the letters A to Z, the numerals 0 to 9, and the + special characters, dollar sign ($), underscore (_), hyphen (-) and the + asterix (\*) as first character for special names like anonymous blocks. + + Most applications do not care about that and work fine with longer names and + any characters used in names for some exceptions, but of course Autodesk + applications are very picky about that. + + .. note:: + + This is a destructive process and modifies the internals of the DXF document. + + """ + if doc.dxfversion != const.DXF12: + raise const.DXFVersionError( + f"expected DXF document version R12, got: {doc.acad_release}" + ) + _R12StrictRename(doc).execute() + + +def clean(doc: Drawing) -> None: + """Removes all features that are not supported for DXF R12 by Autodesk products.""" + if doc.dxfversion != const.DXF12: + raise const.DXFVersionError( + f"expected DXF document version R12, got: {doc.acad_release}" + ) + _remove_table_xdata(doc.appids) + _remove_table_xdata(doc.linetypes) + _remove_table_xdata(doc.layers) + _remove_table_xdata(doc.styles) + _remove_table_xdata(doc.dimstyles) + _remove_table_xdata(doc.ucs) + _remove_table_xdata(doc.views) + _remove_table_xdata(doc.viewports) + _remove_legacy_blocks(doc) + + +def _remove_table_xdata(table: Table) -> None: + """Autodesk products do not accept XDATA in table entries for DXF R12.""" + for entry in list(table): + entry.xdata = None + + +def _remove_legacy_blocks(doc: Drawing) -> None: + """Due to bad conversion some DXF files contain after loading the blocks + "$MODEL_SPACE" and "$PAPER_SPACE". This function removes these empty blocks, + because they will clash with the translated layout names of "*Model_Space" and + "*Paper_Space". + """ + for name in ("$MODEL_SPACE", "$PAPER_SPACE"): + try: + doc.blocks.delete_block(name, safe=False) + except const.DXFKeyError: + pass + + +class R12NameTranslator: + r"""Translate table and block names into strict DXF R12 names. + + ACAD Releases upto 14 limit names to 31 characters in length and all names are + uppercase. Names can include the letters A to Z, the numerals 0 to 9, and the + special characters, dollar sign ($), underscore (_), hyphen (-) and the + asterix (\*) as first character for special names like anonymous blocks. + + """ + + VALID_R12_NAME_CHARS = set(string.ascii_uppercase + string.digits + "$_-") + + def __init__(self) -> None: + self.translated_names: dict[str, str] = {} + self.used_r12_names: set[str] = set() + + def reset(self) -> None: + self.translated_names.clear() + self.used_r12_names.clear() + + def translate(self, name: str) -> str: + name = name.upper() + r12_name = self.translated_names.get(name) + if r12_name is None: + r12_name = self._name_sanitizer(name, self.VALID_R12_NAME_CHARS) + r12_name = self._get_unique_r12_name(r12_name) + self.translated_names[name] = r12_name + return r12_name + + def _get_unique_r12_name(self, name: str) -> str: + name0 = name + counter = 0 + while name in self.used_r12_names: + ext = str(counter) + name = name0[: (31 - len(ext))] + ext + counter += 1 + self.used_r12_names.add(name) + return name + + @staticmethod + def _name_sanitizer(name: str, valid_chars: set[str]) -> str: + # `name` has to be upper case! + if not name: + return "" + new_name = "".join( + (char if char in valid_chars else "_") for char in name[:31] + ) + # special names like anonymous blocks or the "*ACTIVE" viewport configuration + if name[0] == "*": + return "*" + new_name[1:31] + else: + return new_name + + +COMMON_ATTRIBS = ["layer", "linetype", "style", "tag", "name", "dimstyle"] +DIMSTYLE_ATTRIBS = ["dimblk", "dimblk1", "dimblk2"] +LAYER_ATTRIBS = ["linetype"] +BLOCK_ATTRIBS = ["layer"] + + +class _R12StrictRename: + def __init__(self, doc: Drawing) -> None: + assert doc.dxfversion == const.DXF12, "expected DXF version R12" + self.doc = doc + self.translator = R12NameTranslator() + + def execute(self) -> None: + self.process_tables() + self.process_header_vars() + self.process_entities() + + def process_tables(self) -> None: + tables = self.doc.tables + self.rename_table_entries(tables.appids) + self.rename_table_entries(tables.linetypes) + self.rename_table_entries(tables.layers) + self.process_table_entries(tables.layers, LAYER_ATTRIBS) + self.rename_table_entries(tables.styles) + self.rename_table_entries(tables.dimstyles) + self.process_table_entries(tables.dimstyles, DIMSTYLE_ATTRIBS) + self.rename_table_entries(tables.ucs) + self.rename_table_entries(tables.views) + self.rename_vports() + self.rename_block_layouts() + self.process_blocks() + + def rename_table_entries(self, table: Table) -> None: + translate = self.translator.translate + for entry in list(table): + name = entry.dxf.name + entry.dxf.name = translate(name) + table.replace(name, entry) + # XDATA for table entries is not accepted by Autodesk products for R12, + # but for consistency a translation is applied + if entry.xdata: + self.translate_xdata(entry.xdata) + + def rename_vports(self): + translate = self.translator.translate + for config in list(self.doc.viewports.entries.values()): + if not config: # multiple entries in a sequence + continue + old_name = config[0].dxf.name + new_name = translate(old_name) + for entry in config: + entry.dxf.name = new_name + self.doc.viewports.replace(old_name, config) + + def process_table_entries(self, table: Table, attribute_names: list[str]) -> None: + for entry in table: + self.translate_entity_attributes(entry, attribute_names) + + def rename_block_layouts(self) -> None: + translate = self.translator.translate + blocks = self.doc.blocks + for name in blocks.block_names(): + blocks.rename_block(name, translate(name)) + + def process_blocks(self): + for block_record in self.doc.block_records: + block = block_record.block + self.translate_entity_attributes(block, BLOCK_ATTRIBS) + if block.xdata: + self.translate_xdata(block.xdata) + + def process_header_vars(self) -> None: + header = self.doc.header + translate = self.translator.translate + + for key in ( + "$CELTYPE", + "$CLAYER", + "$DIMBLK", + "$DIMBLK1", + "$DIMBLK2", + "$DIMSTYLE", + "$UCSNAME", + "$PUCSNAME", + "$TEXTSTYLE", + ): + value = self.doc.header.get(key) + if value: + header[key] = translate(value) + + def process_entities(self) -> None: + for entity in self.doc.entitydb.values(): + if not is_graphic_entity(entity): + continue + if entity.MIN_DXF_VERSION_FOR_EXPORT > const.DXF12: + continue + if entity.xdata: + self.translate_xdata(entity.xdata) + self.translate_entity_attributes(entity, COMMON_ATTRIBS) + + def translate_entity_attributes( + self, entity: DXFEntity, attribute_names: list[str] + ) -> None: + translate = self.translator.translate + for attrib_name in attribute_names: + if not entity.dxf.hasattr(attrib_name): + continue + name = entity.dxf.get(attrib_name) + if name: + entity.dxf.set(attrib_name, translate(name)) + + def translate_xdata(self, xdata: XData) -> None: + translate = self.translator.translate + for tags in xdata.data.values(): + for index, (code, value) in enumerate(tags): + # 1001: APPID + # 1003: layer name + if code == 1001 or code == 1003: + tags[index] = dxftag(code, translate(value)) + xdata.update_keys() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/recover.py b/.venv/lib/python3.12/site-packages/ezdxf/recover.py new file mode 100644 index 0000000..167643a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/recover.py @@ -0,0 +1,868 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations + +import string +import typing +from typing import ( + TYPE_CHECKING, + BinaryIO, + Iterable, + Iterator, + Callable, + Union, + Optional, +) +import itertools +import re +from collections import defaultdict +from pathlib import Path +import logging + +from ezdxf.lldxf import const +from ezdxf.lldxf import repair +from ezdxf.lldxf.encoding import ( + has_dxf_unicode, + decode_dxf_unicode, + has_mif_encoding, + decode_mif_to_unicode, +) +from ezdxf.lldxf.types import ( + DXFTag, + DXFVertex, + DXFBinaryTag, + POINT_CODES, + BINARY_DATA, + TYPE_TABLE, + MAX_GROUP_CODE, +) +from ezdxf.lldxf.tags import group_tags, Tags +from ezdxf.lldxf.validator import entity_structure_validator +from ezdxf.tools.codepage import toencoding +from ezdxf.audit import Auditor, AuditError + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.eztypes import SectionDict + +__all__ = ["read", "readfile"] + +EXCLUDE_STRUCTURE_CHECK = { + "SECTION", + "ENDSEC", + "EOF", + "TABLE", + "ENDTAB", + "ENDBLK", + "SEQEND", +} +logger = logging.getLogger("ezdxf") + + +def readfile( + filename: Union[str, Path], errors: str = "surrogateescape" +) -> tuple[Drawing, Auditor]: + """Read a DXF document from file system similar to :func:`ezdxf.readfile`, + but this function will repair as many flaws as possible, runs the required + audit process automatically the DXF document and the :class:`Auditor`. + + Args: + filename: file-system name of the DXF document to load + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + filename = str(filename) + with open(filename, mode="rb") as fp: + doc, auditor = read(fp, errors=errors) + doc.filename = filename + return doc, auditor + + +def read(stream: BinaryIO, errors: str = "surrogateescape") -> tuple[Drawing, Auditor]: + """Read a DXF document from a binary-stream similar to :func:`ezdxf.read`, + but this function will detect the text encoding automatically and repair + as many flaws as possible, runs the required audit process afterwards + and returns the DXF document and the :class:`Auditor`. + + Args: + stream: data stream to load in binary read mode + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + recover_tool = Recover.run(stream, errors=errors) + return _load_and_audit_document(recover_tool) + + +def explore( + filename: Union[str, Path], errors: str = "ignore" +) -> tuple[Drawing, Auditor]: + """Read a DXF document from file system similar to :func:`readfile`, + but this function will use a special tag loader, which tries to recover the + tag stream if invalid tags occur. This function is intended to load + corrupted DXF files and should only be used to explore such files, data loss + is very likely. + + Args: + filename: file-system name of the DXF document to load + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: for invalid or corrupted DXF structures + UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs + + """ + filename = str(filename) + with open(filename, mode="rb") as fp: + recover_tool = Recover.run(fp, errors=errors, loader=synced_bytes_loader) + doc, auditor = _load_and_audit_document(recover_tool) + doc.filename = filename + return doc, auditor + + +def _load_and_audit_document(recover_tool) -> tuple[Drawing, Auditor]: + from ezdxf.document import Drawing + + doc = Drawing() + doc._load_section_dict(recover_tool.section_dict) + + auditor = Auditor(doc) + for code, msg in recover_tool.errors: + auditor.add_error(code, msg) + for code, msg in recover_tool.fixes: + auditor.fixed_error(code, msg) + auditor.run() + return doc, auditor + + +# noinspection PyMethodMayBeStatic +class Recover: + """Loose coupled recovering tools.""" + + def __init__(self, loader: Optional[Callable] = None): + # different tag loading strategies can be used: + # - bytes_loader(): expects a valid low level structure + # - synced_bytes_loader(): loads everything which looks like a tag + # and skip other content (dangerous!) + self.tag_loader = loader or bytes_loader + + # The main goal of all efforts, a Drawing compatible dict of sections: + self.section_dict: "SectionDict" = dict() + + # Store error messages from low level processes + self.errors: list[tuple[int, str]] = [] + self.fixes: list[tuple[int, str]] = [] + + # Detected DXF version + self.dxfversion = const.DXF12 + + @classmethod + def run( + cls, + stream: BinaryIO, + loader: Optional[Callable] = None, + errors: str = "surrogateescape", + ) -> Recover: + """Execute the recover process.""" + recover_tool = Recover(loader) + tags = recover_tool.load_tags(stream, errors) + sections = recover_tool.rebuild_sections(tags) + recover_tool.load_section_dict(sections) + tables = recover_tool.section_dict.get("TABLES") + if tables: + tables = recover_tool.rebuild_tables(tables) # type: ignore + recover_tool.section_dict["TABLES"] = tables + if recover_tool.dxfversion > "AC1009": + recover_tool.recover_rootdict() + recover_tool.fix_broken_layout_links() + section_dict = recover_tool.section_dict + + is_r12 = recover_tool.dxfversion <= "AC1009" + for name, entities in section_dict.items(): + if name in {"TABLES", "BLOCKS", "OBJECTS", "ENTITIES"}: + section_dict[name] = list( + recover_tool.check_entities(entities, is_r12) # type: ignore + ) + + return recover_tool + + def load_tags(self, stream: BinaryIO, errors: str) -> Iterator[DXFTag]: + return safe_tag_loader( + stream, self.tag_loader, messages=self.errors, errors=errors + ) + + def rebuild_sections(self, tags: Iterable[DXFTag]) -> list[list[DXFTag]]: + """Collect tags between SECTION and ENDSEC or next SECTION tag + as list of DXFTag objects, collects tags outside of sections + as an extra section. + + Returns: + List of sections as list of DXFTag() objects, the last section + contains orphaned tags found outside of sections + + """ + + # Invalid placed DXF entities are removed in the audit process! + def close_section(): + # ENDSEC tag is not collected + nonlocal collector, inside_section + if inside_section: + sections.append(collector) + else: # missing SECTION + # ignore this tag, it is even not an orphan + self.fixes.append( + ( + AuditError.MISSING_SECTION_TAG, + "DXF structure error: missing SECTION tag.", + ) + ) + collector = [] + inside_section = False + + def open_section(): + nonlocal inside_section + if inside_section: # missing ENDSEC + self.fixes.append( + ( + AuditError.MISSING_ENDSEC_TAG, + "DXF structure error: missing ENDSEC tag.", + ) + ) + close_section() + collector.append(tag) + inside_section = True + + def process_structure_tag(): + if value == "SECTION": + open_section() + elif value == "ENDSEC": + close_section() + elif value == "EOF": + if inside_section: + self.fixes.append( + ( + AuditError.MISSING_ENDSEC_TAG, + "DXF structure error: missing ENDSEC tag.", + ) + ) + close_section() + else: + collect() + + def collect(): + if inside_section: + collector.append(tag) + else: + self.fixes.append( + ( + AuditError.FOUND_TAG_OUTSIDE_SECTION, + f"DXF structure error: found tag outside section: " + f"({code}, {value})", + ) + ) + orphans.append(tag) + + orphans: list[DXFTag] = [] + sections: list[list[DXFTag]] = [] + collector: list[DXFTag] = [] + inside_section = False + for tag in tags: + code, value = tag + if code == 0: + process_structure_tag() + else: + collect() + + sections.append(orphans) + return sections + + def load_section_dict(self, sections: list[list[DXFTag]]) -> None: + """Merge sections of same type.""" + + def add_section(name: str, tags) -> None: + if name in section_dict: + section_dict[name].extend(tags[2:]) + else: + section_dict[name] = tags + + def _build_section_dict(d: dict) -> None: + for name, section in d.items(): + if name in const.MANAGED_SECTIONS: + self.section_dict[name] = list(group_tags(section, 0)) + + def _remove_unsupported_sections(d: dict): + for name in ("CLASSES", "OBJECTS", "ACDSDATA"): + if name in d: + del d[name] + self.fixes.append( + ( + AuditError.REMOVED_UNSUPPORTED_SECTION, + f"Removed unsupported {name} section for DXF R12.", + ) + ) + + # Last section could be orphaned tags: + orphans = sections.pop() + if orphans and orphans[0] == (0, "SECTION"): + # The last section contains not the orphaned tags: + sections.append(orphans) + orphans = [] + + section_dict: "SectionDict" = dict() + for section in sections: + code, name = section[1] + if code == 2: + add_section(name, section) + else: # invalid section name tag e.g. (2, "HEADER") + self.fixes.append( + ( + AuditError.MISSING_SECTION_NAME_TAG, + "DXF structure error: missing section name tag, ignore section.", + ) + ) + + header = section_dict.setdefault( + "HEADER", + [ + DXFTag(0, "SECTION"), # type: ignore + DXFTag(2, "HEADER"), # type: ignore + ], + ) + self.rescue_orphaned_header_vars(header, orphans) # type: ignore + self.dxfversion = _detect_dxf_version(header) + if self.dxfversion <= const.DXF12: + _remove_unsupported_sections(section_dict) + _build_section_dict(section_dict) + + def rebuild_tables(self, tables: list[Tags]) -> list[Tags]: + """Rebuild TABLES section.""" + + # Note: the recover module does not report invalid placed table entries, + # it just recovers them. The "normal" loading process ignore these + # misplaced table entries and logs a warning. + + def append_table(name: str): + if name not in content: + return + + head = heads.get(name) + if head: + tables.append(head) + else: + # The new table head gets a valid handle from Auditor. + tables.append(Tags([DXFTag(0, "TABLE"), DXFTag(2, name)])) + tables.extend(content[name]) + tables.append(Tags([DXFTag(0, "ENDTAB")])) + + heads = dict() + content = defaultdict(list) + valid_tables = set(const.TABLE_NAMES_ACAD_ORDER) + + for entry in tables: + name = entry[0].value.upper() + if name == "TABLE": + try: + table_name = entry[1].value.upper() + except (IndexError, AttributeError): + pass + else: + heads[table_name] = entry + elif name in valid_tables: + content[name].append(entry) + tables = [Tags([DXFTag(0, "SECTION"), DXFTag(2, "TABLES")])] + + names = list(const.TABLE_NAMES_ACAD_ORDER) + if self.dxfversion <= const.DXF12: + # Ignore BLOCK_RECORD table + names.remove("BLOCK_RECORD") + if "BLOCK_RECORD" in content: + self.fixes.append( + ( + AuditError.REMOVED_UNSUPPORTED_TABLE, + f"Removed unsupported BLOCK_RECORD table for DXF R12.", + ) + ) + + for name in names: + append_table(name) + return tables + + def rescue_orphaned_header_vars( + self, header: list[DXFTag], orphans: Iterable[DXFTag] + ) -> None: + var_name = None + for tag in orphans: + code, value = tag + if code == 9: + var_name = tag + elif var_name is not None: + header.append(var_name) + header.append(tag) + var_name = None + + def check_entities(self, entities: list[Tags], is_r12: bool) -> Iterator[Tags]: + subclass_markers = (100,) + for entity in entities: + _, dxftype = entity[0] + if dxftype in EXCLUDE_STRUCTURE_CHECK: + yield entity + else: + # raises DXFStructureError() for invalid entities + tags = Tags(entity_structure_validator(entity)) + if is_r12: + # subclass markers (100, ...) in DXF R12 files confuses the + # ezdxf parser #1106 + tags.remove_tags(subclass_markers) + yield tags + + def recover_rootdict(self): + objects = self.section_dict.get("OBJECTS") + if not objects or len(objects) < 2: + return # empty OBJECTS section + # index 0 is [DXFTag(0, 'SECTION'), DXFTag(2, 'OBJECTS')], this is a + # requirement to be stored in the section_dict! + if _is_rootdict(objects[1]): + return # everything is fine + index, rootdict = _find_rootdict(objects) + if index: # make rootdict to first entity in OBJECTS section + objects[index] = objects[1] + objects[1] = rootdict + try: + handle = rootdict.get_handle() + except const.DXFValueError: + handle = "None" + self.fixes.append( + ( + AuditError.MISPLACED_ROOT_DICT, + f"Recovered misplaced root DICTIONARY(#{handle}).", + ) + ) + + def fix_broken_layout_links(self): + """Fixes broke links (block_record_handle) between LAYOUT and BLOCK_RECORD + entities. See issue #997 for more information. + """ + pass + + +def _detect_dxf_version(header: list) -> str: + next_is_dxf_version = False + for tag in header: + if next_is_dxf_version: + dxfversion = str(tag[1]).strip() + if re.fullmatch(r"AC[0-9]{4}", dxfversion): + return dxfversion + else: + break + if tag == (9, "$ACADVER"): + next_is_dxf_version = True + return const.DXF12 + + +def _is_rootdict(entity: Tags) -> bool: + if entity[0] != (0, "DICTIONARY"): + return False + # The entry "ACAD_GROUP" in the rootdict is absolutely necessary! + return any(tag == (3, "ACAD_GROUP") for tag in entity) + + +def _find_rootdict(objects: list[Tags]) -> tuple[int, Tags]: + for index, entity in enumerate(objects): + if _is_rootdict(entity): + return index, entity + return 0, Tags() + + +def safe_tag_loader( + stream: BinaryIO, + loader: Optional[Callable] = None, + messages: Optional[list] = None, + errors: str = "surrogateescape", +) -> Iterator[DXFTag]: + """Yields :class:``DXFTag`` objects from a bytes `stream` + (untrusted external source), skips all comment tags (group code == 999). + + - Fixes unordered and invalid vertex tags. + - Pass :func:`synced_bytes_loader` as argument `loader` to brute force + load invalid tag structure. + + Args: + stream: input data stream as bytes + loader: low level tag loader, default loader is :func:`bytes_loader` + messages: list to store error messages + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + """ + if loader is None: + loader = bytes_loader + tags, detector_stream = itertools.tee(loader(stream), 2) + encoding = detect_encoding(detector_stream) + + # Apply repair filter: + tags = repair.tag_reorder_layer(tags) + tags = repair.filter_invalid_point_codes(tags) # type: ignore + tags = repair.filter_invalid_handles(tags) + return byte_tag_compiler(tags, encoding, messages=messages, errors=errors) + + +INT_PATTERN_S = re.compile(r"[+-]?\d+") +INT_PATTERN_B = re.compile(rb"[+-]?\d+") + + +def _search_int(s: Union[str, bytes]) -> int: + """Emulate the behavior of the C function stoll(), which just stop + converting strings to integers at the first invalid char without raising + an exception. e.g. "42xyz" is a valid integer 42 + + """ + res = re.search( + INT_PATTERN_S if isinstance(s, str) else INT_PATTERN_B, s # type: ignore + ) + if res: + s = res.group() + return int(s) + + +FLOAT_PATTERN_S = re.compile(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?") +FLOAT_PATTERN_B = re.compile(rb"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?") + + +def _search_float(s: Union[str, bytes]) -> float: + """Emulate the behavior of the C function stod(), which just stop + converting strings to doubles at the first invalid char without raising + an exception. e.g. "47.11xyz" is a valid double 47.11 + + """ + res = re.search( + FLOAT_PATTERN_S if isinstance(s, str) else FLOAT_PATTERN_B, s # type: ignore + ) + if res: + s = res.group() + return float(s) + + +@typing.no_type_check +def bytes_loader(stream: BinaryIO) -> Iterator[DXFTag]: + """Yields :class:``DXFTag`` objects from a bytes `stream` + (untrusted external source), skips all comment tags (group code == 999). + + ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always a + raw bytes value without line endings. Works with file system streams and + :class:`BytesIO` streams. + + Raises: + DXFStructureError: Found invalid group code. + + """ + eof = False + line = 1 + readline = stream.readline + while not eof: + code = readline() + # ByteIO(): empty strings indicates EOF - does not raise an exception + if code: + try: + code = int(code) + except ValueError: + try: # harder to find an int + code = _search_int(code) + except ValueError: + code = code.decode(errors="ignore").rstrip("\r\n") + raise const.DXFStructureError( + f'Invalid group code "{code}" at line {line}.' + ) + else: + return + + value = readline() + # ByteIO(): empty strings indicates EOF + if value: + value = value.rstrip(b"\r\n") + if code == 0 and value == b"EOF": + eof = True + if code != 999: + yield DXFTag(code, value) + line += 2 + else: + return + + +def synced_bytes_loader(stream: BinaryIO) -> Iterator[DXFTag]: + """Yields :class:``DXFTag`` objects from a bytes `stream` + (untrusted external source), skips all comment tags (group code == 999). + + ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always a + raw bytes value without line endings. Works with file system streams and + :class:`BytesIO` streams. + + Does not raise DXFStructureError on invalid group codes, instead skips + lines until a valid group code or EOF is found. + + This can remove invalid lines before group codes, but can not + detect invalid lines between group code and tag value. + + """ + code = 999 + upper_boundary = MAX_GROUP_CODE + 1 + readline = stream.readline + while True: + seeking_valid_group_code = True + while seeking_valid_group_code: + code = readline() # type: ignore + if code: + try: # hard to find an int + code = _search_int(code) # type: ignore + except ValueError: + pass + else: + if 0 <= code < upper_boundary: + seeking_valid_group_code = False + else: + return # empty string is EOF + value = readline() + if value: + if code != 999: + yield DXFTag(code, value.rstrip(b"\r\n")) + else: + return # empty string is EOF + + +DWGCODEPAGE = b"$DWGCODEPAGE" +ACADVER = b"$ACADVER" + + +def _strip_whitespace(s: str) -> str: + ws = set(string.whitespace) + return "".join([c for c in s if c not in ws]) + + +def detect_encoding(tags: Iterable[DXFTag]) -> str: + """Detect text encoding from header variables $DWGCODEPAGE and $ACADVER + out of a stream of DXFTag objects. + + Assuming a malformed DXF file: + + The header variables could reside outside of the HEADER section, + an ENDSEC tag is not a reliable fact that no $DWGCODEPAGE or + $ACADVER header variable will show up in the remaining tag stream. + + Worst case: DXF file without a $ACADVER var, and a $DWGCODEPAGE + unequal to "ANSI_1252" at the end of the file. + + """ + encoding = None + dxfversion = None + next_tag = None + + for code, value in tags: + if code == 9: + if value == DWGCODEPAGE: + next_tag = DWGCODEPAGE # e.g. (3, "ANSI_1252") + elif value == ACADVER: + next_tag = ACADVER # e.g. (1, "AC1012") + elif code == 3 and next_tag == DWGCODEPAGE: + encoding = toencoding(value.decode(const.DEFAULT_ENCODING)) + next_tag = None + elif code == 1 and next_tag == ACADVER: + dxfversion = value.decode(const.DEFAULT_ENCODING) + next_tag = None + + if encoding and dxfversion: + return "utf8" if dxfversion >= const.DXF2007 else encoding + + return const.DEFAULT_ENCODING + + +@typing.no_type_check +def byte_tag_compiler( + tags: Iterable[DXFTag], + encoding=const.DEFAULT_ENCODING, + messages: Optional[list] = None, + errors: str = "surrogateescape", +) -> Iterator[DXFTag]: + """Compiles DXF tag values imported by bytes_loader() into Python types. + + Raises DXFStructureError() for invalid float values and invalid coordinate + values. + + Expects DXF coordinates written in x, y[, z] order, see function + :func:`safe_tag_loader` for usage with applied repair filters. + + Args: + tags: DXF tag generator, yielding tag values as bytes like bytes_loader() + encoding: text encoding + messages: list to store error messages + errors: specify decoding error handler + + - "surrogateescape" to preserve possible binary data (default) + - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data + - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data + + Raises: + DXFStructureError: Found invalid DXF tag or unexpected coordinate order. + + """ + + def error_msg(tag): + code = tag.code + value = tag.value.decode(encoding) + return f'Invalid tag ({code}, "{value}") near line: {line}.' + + def recover_int(s: Union[str, bytes]) -> int: + if isinstance(s, bytes): + s = s.decode(encoding="utf8", errors="ignore") + value = _search_int(s) + msg = f'recovered invalid integer value "{s}" near line {line} as "{value}"' + messages.append((AuditError.INVALID_INTEGER_VALUE, msg)) + logger.warning(msg) + return value + + def recover_float(s: Union[str, bytes]) -> float: + if isinstance(s, bytes): + s = s.decode(encoding="utf8", errors="ignore") + s = _strip_whitespace(s) + value = _search_float(s) + msg = f'recovered invalid floating point value "{s}" near line {line} as "{value}"' + messages.append((AuditError.INVALID_FLOATING_POINT_VALUE, msg)) + logger.warning(msg) + return value + + assert isinstance(encoding, str) + assert isinstance(errors, str) + + if messages is None: + messages = [] + tags = iter(tags) + undo_tag = None + line = 0 + while True: + try: + if undo_tag is not None: + x = undo_tag + undo_tag = None + else: + x = next(tags) + line += 2 + code = x.code + if code in POINT_CODES: + y = next(tags) # y coordinate is mandatory + line += 2 + # e.g. y-code for x-code=10 is 20 + if y.code != code + 10: + raise const.DXFStructureError( + f"Missing required y-coordinate near line: {line}." + ) + # optional z coordinate + z = next(tags) + line += 2 + try: + # is it a z-coordinate like (30, 0.0) for base x-code=10 + if z.code == code + 20: + try: + point = ( + float(x.value), + float(y.value), + float(z.value), + ) + except ValueError: # search for any float values + point = ( + recover_float(x.value), + recover_float(y.value), + recover_float(z.value), + ) + else: + try: + point = (float(x.value), float(y.value)) + except ValueError: # search for any float values + point = ( + recover_float(x.value), + recover_float(y.value), + ) + undo_tag = z + except ValueError: + raise const.DXFStructureError( + f"Invalid floating point values near line: {line}." + ) + yield DXFVertex(code, point) + elif code in BINARY_DATA: + # maybe pre compiled in low level tagger (binary DXF) + if isinstance(x, DXFBinaryTag): + tag = x + else: + try: + tag = DXFBinaryTag.from_string(code, x.value) + except ValueError: + raise const.DXFStructureError( + f"Invalid binary data near line: {line}." + ) + yield tag + else: # just a single tag + type_ = TYPE_TABLE.get(code, str) + value: bytes = x.value + if type_ is str: + if code == 0: + # remove white space from structure tags + value = x.value.strip().upper() + try: # 2 stages to document decoding errors + str_ = value.decode(encoding, errors="strict") + except UnicodeDecodeError: + str_ = value.decode(encoding, errors=errors) + messages.append( + ( + AuditError.DECODING_ERROR, + f"Fixed unicode decoding error near line {line}", + ) + ) + + # exclude structure tags (code == 0): + if code: + # Convert DXF-Unicode notation "\U+xxxx" to unicode + if has_dxf_unicode(str_): + str_ = decode_dxf_unicode(str_) + # Convert MIF notation "\M+cxxxx" to unicode + elif has_mif_encoding(str_): + str_ = decode_mif_to_unicode(str_) + yield DXFTag(code, str_) + else: + try: + # fast path for int and float + yield DXFTag(code, type_(value)) + except ValueError: + # slow path - e.g. ProE stores int values as floats :(( + if type_ is int: + try: + yield DXFTag(code, recover_int(x.value)) + except ValueError: + raise const.DXFStructureError(error_msg(x)) + elif type_ is float: + try: + yield DXFTag(code, recover_float(x.value)) + except ValueError: + raise const.DXFStructureError(error_msg(x)) + else: + raise const.DXFStructureError(error_msg(x)) + except StopIteration: + return diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/render/__init__.py new file mode 100644 index 0000000..ada19c1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/__init__.py @@ -0,0 +1,30 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from .arrows import ARROWS +from .r12spline import R12Spline +from .curves import Bezier, EulerSpiral, Spline, random_2d_path, random_3d_path +from .mesh import ( + MeshBuilder, + MeshVertexMerger, + MeshTransformer, + MeshAverageVertexMerger, + MeshDiagnose, + FaceOrientationDetector, + MeshBuilderError, + NonManifoldMeshError, + MultipleMeshesError, + NodeMergingError, + DegeneratedPathError, +) +from .trace import TraceBuilder +from .mleader import ( + MultiLeaderBuilder, + MultiLeaderMTextBuilder, + MultiLeaderBlockBuilder, + ConnectionSide, + HorizontalConnection, + VerticalConnection, + LeaderType, + TextAlignment, + BlockAlignment, +) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..ae119b3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/_linetypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/_linetypes.cpython-312.pyc new file mode 100644 index 0000000..e1dc4b9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/_linetypes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/abstract_mtext_renderer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/abstract_mtext_renderer.cpython-312.pyc new file mode 100644 index 0000000..3c9765d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/abstract_mtext_renderer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/arrows.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/arrows.cpython-312.pyc new file mode 100644 index 0000000..4492be4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/arrows.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/curves.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/curves.cpython-312.pyc new file mode 100644 index 0000000..4d24a03 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/curves.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_base.cpython-312.pyc new file mode 100644 index 0000000..a2440ed Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_base.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_curved.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_curved.cpython-312.pyc new file mode 100644 index 0000000..5b7c676 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_curved.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_diameter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_diameter.cpython-312.pyc new file mode 100644 index 0000000..b9eb8c4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_diameter.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_linear.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_linear.cpython-312.pyc new file mode 100644 index 0000000..90eeaae Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_linear.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_ordinate.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_ordinate.cpython-312.pyc new file mode 100644 index 0000000..203c91c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_ordinate.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_radius.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_radius.cpython-312.pyc new file mode 100644 index 0000000..afdee27 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dim_radius.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dimension.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dimension.cpython-312.pyc new file mode 100644 index 0000000..7081dbc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/dimension.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/forms.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/forms.cpython-312.pyc new file mode 100644 index 0000000..da58ec6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/forms.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/hatching.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/hatching.cpython-312.pyc new file mode 100644 index 0000000..001bfea Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/hatching.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/leader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/leader.cpython-312.pyc new file mode 100644 index 0000000..f8a7151 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/leader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/linetypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/linetypes.cpython-312.pyc new file mode 100644 index 0000000..3845769 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/linetypes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mesh.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mesh.cpython-312.pyc new file mode 100644 index 0000000..a18dfa2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mesh.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mleader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mleader.cpython-312.pyc new file mode 100644 index 0000000..6640223 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mleader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mline.cpython-312.pyc new file mode 100644 index 0000000..c4c167a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/mline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/point.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/point.cpython-312.pyc new file mode 100644 index 0000000..699a966 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/point.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/polyline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/polyline.cpython-312.pyc new file mode 100644 index 0000000..be97c54 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/polyline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/r12spline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/r12spline.cpython-312.pyc new file mode 100644 index 0000000..e916e41 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/r12spline.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/trace.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/trace.cpython-312.pyc new file mode 100644 index 0000000..6ef3440 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/render/__pycache__/trace.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/_linetypes.py b/.venv/lib/python3.12/site-packages/ezdxf/render/_linetypes.py new file mode 100644 index 0000000..ac8a019 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/_linetypes.py @@ -0,0 +1,76 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Tuple, Iterable, Sequence +from typing_extensions import TypeAlias +import math +from ezdxf.math import Vec3, UVec + +LineSegment: TypeAlias = Tuple[Vec3, Vec3] + + +class _LineTypeRenderer: + """Renders a line segment as multiple short segments according to the given + line pattern. + + In contrast to the DXF line pattern is this pattern simplified and follow + the rule line-gap-line-gap-... a line of length 0 is a point. + The pattern should end with a gap (even count) and the dash length is in + drawing units. + + Args: + dashes: sequence of floats, line-gap-line-gap-... + + """ + # Get the simplified line pattern by LineType.simplified_line_pattern() + def __init__(self, dashes: Sequence[float]): + self._dashes = dashes + self._dash_count: int = len(dashes) + self.is_solid: bool = True + self._current_dash: int = 0 + self._current_dash_length: float = 0.0 + if self._dash_count > 1: + self.is_solid = False + self._current_dash_length = self._dashes[0] + self._is_dash = True + + def line_segment(self, start: UVec, end: UVec) -> Iterable[LineSegment]: + """Yields the line from `start` to `end` according to stored line + pattern as short segments. Yields only the lines and points not the + gaps. + + """ + _start = Vec3(start) + _end = Vec3(end) + if self.is_solid or _start.isclose(_end): + yield _start, _end + return + + segment_vec = _end - _start + segment_length = segment_vec.magnitude + segment_dir = segment_vec / segment_length # normalize + + for is_dash, dash_length in self._render_dashes(segment_length): + _end = _start + segment_dir * dash_length + if is_dash: + yield _start, _end + _start = _end + + def _render_dashes(self, length: float) -> Iterable[tuple[bool, float]]: + if length <= self._current_dash_length: + self._current_dash_length -= length + yield self._is_dash, length + if math.isclose(self._current_dash_length, 0.0): + self._cycle_dashes() + else: + # Avoid deep recursions! + while length > self._current_dash_length: + length -= self._current_dash_length + yield from self._render_dashes(self._current_dash_length) + if length > 0.0: + yield from self._render_dashes(length) + + def _cycle_dashes(self): + self._current_dash = (self._current_dash + 1) % self._dash_count + self._current_dash_length = self._dashes[self._current_dash] + self._is_dash = not self._is_dash diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/abstract_mtext_renderer.py b/.venv/lib/python3.12/site-packages/ezdxf/render/abstract_mtext_renderer.py new file mode 100644 index 0000000..8802423 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/abstract_mtext_renderer.py @@ -0,0 +1,296 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License + +# This is the abstract link between the text layout engine implemented in +# ezdxf.tools.text_layout and a concrete MTEXT renderer implementation like +# MTextExplode or ComplexMTextRenderer. +from __future__ import annotations +from typing import Sequence, Optional +import abc +from ezdxf.lldxf import const +from ezdxf import colors +from ezdxf.entities.mtext import MText, MTextColumns +from ezdxf.enums import ( + MTextParagraphAlignment, +) +from ezdxf.fonts import fonts +from ezdxf.tools import text_layout as tl +from ezdxf.tools.text import ( + MTextParser, + MTextContext, + TokenType, + ParagraphProperties, + estimate_mtext_extents, +) + +__all__ = ["AbstractMTextRenderer"] + +ALIGN = { + MTextParagraphAlignment.LEFT: tl.ParagraphAlignment.LEFT, + MTextParagraphAlignment.RIGHT: tl.ParagraphAlignment.RIGHT, + MTextParagraphAlignment.CENTER: tl.ParagraphAlignment.CENTER, + MTextParagraphAlignment.JUSTIFIED: tl.ParagraphAlignment.JUSTIFIED, + MTextParagraphAlignment.DISTRIBUTED: tl.ParagraphAlignment.JUSTIFIED, + MTextParagraphAlignment.DEFAULT: tl.ParagraphAlignment.LEFT, +} + +ATTACHMENT_POINT_TO_ALIGN = { + const.MTEXT_TOP_LEFT: tl.ParagraphAlignment.LEFT, + const.MTEXT_MIDDLE_LEFT: tl.ParagraphAlignment.LEFT, + const.MTEXT_BOTTOM_LEFT: tl.ParagraphAlignment.LEFT, + const.MTEXT_TOP_CENTER: tl.ParagraphAlignment.CENTER, + const.MTEXT_MIDDLE_CENTER: tl.ParagraphAlignment.CENTER, + const.MTEXT_BOTTOM_CENTER: tl.ParagraphAlignment.CENTER, + const.MTEXT_TOP_RIGHT: tl.ParagraphAlignment.RIGHT, + const.MTEXT_MIDDLE_RIGHT: tl.ParagraphAlignment.RIGHT, + const.MTEXT_BOTTOM_RIGHT: tl.ParagraphAlignment.RIGHT, +} + +STACKING = { + "^": tl.Stacking.OVER, + "/": tl.Stacking.LINE, + "#": tl.Stacking.SLANTED, +} + + +def make_default_tab_stops(cap_height: float, width: float) -> list[tl.TabStop]: + tab_stops = [] + step = 4.0 * cap_height + pos = step + while pos < width: + tab_stops.append(tl.TabStop(pos, tl.TabStopType.LEFT)) + pos += step + return tab_stops + + +def append_default_tab_stops( + tab_stops: list[tl.TabStop], default_stops: Sequence[tl.TabStop] +) -> None: + last_pos = 0.0 + if tab_stops: + last_pos = tab_stops[-1].pos + tab_stops.extend(stop for stop in default_stops if stop.pos > last_pos) + + +def make_tab_stops( + cap_height: float, + width: float, + tab_stops: Sequence, + default_stops: Sequence[tl.TabStop], +) -> list[tl.TabStop]: + _tab_stops = [] + for stop in tab_stops: + if isinstance(stop, str): + value = float(stop[1:]) + if stop[0] == "c": + kind = tl.TabStopType.CENTER + else: + kind = tl.TabStopType.RIGHT + else: + kind = tl.TabStopType.LEFT + value = float(stop) + pos = value * cap_height + if pos < width: + _tab_stops.append(tl.TabStop(pos, kind)) + + append_default_tab_stops(_tab_stops, default_stops) + return _tab_stops + + +def get_stroke(ctx: MTextContext) -> int: + stroke = 0 + if ctx.underline: + stroke += tl.Stroke.UNDERLINE + if ctx.strike_through: + stroke += tl.Stroke.STRIKE_THROUGH + if ctx.overline: + stroke += tl.Stroke.OVERLINE + if ctx.continue_stroke: + stroke += tl.Stroke.CONTINUE + return stroke + + +def new_paragraph( + cells: list, + ctx: MTextContext, + cap_height: float, + line_spacing: float = 1, + width: float = 0, + default_stops: Optional[Sequence[tl.TabStop]] = None, +): + if cells: + p = ctx.paragraph + align = ALIGN.get(p.align, tl.ParagraphAlignment.LEFT) + left = p.left * cap_height + right = p.right * cap_height + first = left + p.indent * cap_height # relative to left + _default_stops: Sequence[tl.TabStop] = default_stops or [] + tab_stops = _default_stops + if p.tab_stops: + tab_stops = make_tab_stops(cap_height, width, p.tab_stops, _default_stops) + paragraph = tl.Paragraph( + align=align, + indent=(first, left, right), + line_spacing=line_spacing, + tab_stops=tab_stops, + ) + paragraph.append_content(cells) + else: + paragraph = tl.EmptyParagraph( # type: ignore + cap_height=ctx.cap_height, line_spacing=line_spacing + ) + return paragraph + + +def super_glue(): + return tl.NonBreakingSpace(width=0, min_width=0, max_width=0) + + +def defined_width(mtext: MText) -> float: + width = mtext.dxf.get("width", 0.0) + if width < 1e-6: + width, height = estimate_mtext_extents(mtext) + return width + + +def column_heights(columns: MTextColumns) -> list[Optional[float]]: + heights: list[Optional[float]] + if columns.heights: # dynamic manual + heights = list(columns.heights) + # last height has to be auto height = None + heights[-1] = None + return heights + # static, dynamic auto + defined_height = abs(columns.defined_height) + if defined_height < 1e-6: + return [None] + return [defined_height] * columns.count + + +class AbstractMTextRenderer(abc.ABC): + def __init__(self) -> None: + self._font_cache: dict[tuple[str, float, float], fonts.AbstractFont] = {} + + @abc.abstractmethod + def word(self, test: str, ctx: MTextContext) -> tl.ContentCell: + ... + + @abc.abstractmethod + def fraction(self, data: tuple[str, str, str], ctx: MTextContext) -> tl.ContentCell: + ... + + @abc.abstractmethod + def get_font_face(self, mtext: MText) -> fonts.FontFace: + ... + + @abc.abstractmethod + def make_bg_renderer(self, mtext: MText) -> tl.ContentRenderer: + ... + + def make_mtext_context(self, mtext: MText) -> MTextContext: + ctx = MTextContext() + ctx.paragraph = ParagraphProperties( + align=ATTACHMENT_POINT_TO_ALIGN.get( # type: ignore + mtext.dxf.attachment_point, tl.ParagraphAlignment.LEFT + ) + ) + ctx.font_face = self.get_font_face(mtext) + ctx.cap_height = mtext.dxf.char_height + ctx.aci = mtext.dxf.color + rgb = mtext.rgb + if rgb is not None: + ctx.rgb = colors.RGB(*rgb) + return ctx + + def get_font(self, ctx: MTextContext) -> fonts.AbstractFont: + ttf = fonts.find_font_file_name(ctx.font_face) # 1st call is very slow + key = (ttf, ctx.cap_height, ctx.width_factor) + font = self._font_cache.get(key) + if font is None: + font = fonts.make_font(ttf, ctx.cap_height, ctx.width_factor) + self._font_cache[key] = font + return font + + def get_stroke(self, ctx: MTextContext) -> int: + return get_stroke(ctx) + + def get_stacking(self, type_: str) -> tl.Stacking: + return STACKING.get(type_, tl.Stacking.LINE) + + def space_width(self, ctx: MTextContext) -> float: + return self.get_font(ctx).space_width() + + def space(self, ctx: MTextContext): + return tl.Space(width=self.space_width(ctx)) + + def tabulator(self, ctx: MTextContext): + return tl.Tabulator(width=self.space_width(ctx)) + + def non_breaking_space(self, ctx: MTextContext): + return tl.NonBreakingSpace(width=self.space_width(ctx)) + + def layout_engine(self, mtext: MText) -> tl.Layout: + initial_cap_height = mtext.dxf.char_height + line_spacing = mtext.dxf.line_spacing_factor + + def append_paragraph(): + paragraph = new_paragraph( + cells, + ctx, + initial_cap_height, + line_spacing, + width, + default_stops, + ) + layout.append_paragraphs([paragraph]) + cells.clear() + + bg_renderer = self.make_bg_renderer(mtext) + width = defined_width(mtext) + default_stops = make_default_tab_stops(initial_cap_height, width) + layout = tl.Layout(width=width) + if mtext.has_columns: + columns = mtext.columns + assert columns is not None + for height in column_heights(columns): + layout.append_column( + width=columns.width, + height=height, + gutter=columns.gutter_width, + renderer=bg_renderer, + ) + else: + # column with auto height and default width + layout.append_column(renderer=bg_renderer) + + content = mtext.all_columns_raw_content() + ctx = self.make_mtext_context(mtext) + cells: list[tl.Cell] = [] + for token in MTextParser(content, ctx): + ctx = token.ctx + if token.type == TokenType.NEW_PARAGRAPH: + append_paragraph() + elif token.type == TokenType.NEW_COLUMN: + append_paragraph() + layout.next_column() + elif token.type == TokenType.SPACE: + cells.append(self.space(ctx)) + elif token.type == TokenType.NBSP: + cells.append(self.non_breaking_space(ctx)) + elif token.type == TokenType.TABULATOR: + cells.append(self.tabulator(ctx)) + elif token.type == TokenType.WORD: + if cells and isinstance(cells[-1], (tl.Text, tl.Fraction)): + # Create an unbreakable connection between those two parts. + cells.append(super_glue()) + cells.append(self.word(token.data, ctx)) + elif token.type == TokenType.STACK: + if cells and isinstance(cells[-1], (tl.Text, tl.Fraction)): + # Create an unbreakable connection between those two parts. + cells.append(super_glue()) + cells.append(self.fraction(token.data, ctx)) + + if cells: + append_paragraph() + + return layout diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/arrows.py b/.venv/lib/python3.12/site-packages/ezdxf/render/arrows.py new file mode 100644 index 0000000..1f7b68e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/arrows.py @@ -0,0 +1,626 @@ +# Copyright (c) 2019-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Iterator +from ezdxf.math import Vec2, Shape2d, NULLVEC, UVec +from .forms import open_arrow, arrow2 + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic + from ezdxf.sections.blocks import BlocksSection + from ezdxf.eztypes import GenericLayoutType + +DEFAULT_ARROW_ANGLE = 18.924644 +DEFAULT_BETA = 45.0 + + +# The base arrow is oriented for the right hand side ->| of the dimension line, +# reverse is the left hand side |<-. +class BaseArrow: + def __init__(self, vertices: Iterable[UVec]): + self.shape = Shape2d(vertices) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + pass + + def place(self, insert: UVec, angle: float): + self.shape.rotate(angle) + self.shape.translate(insert) + + +class NoneStroke(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + super().__init__([Vec2(insert)]) + + +class ObliqueStroke(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + self.size = size + s2 = size / 2 + # shape = [center, lower left, upper right] + super().__init__([Vec2((-s2, -s2)), Vec2((s2, s2))]) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_line( + start=self.shape[0], end=self.shape[1], dxfattribs=dxfattribs + ) + + +class ArchTick(ObliqueStroke): + def render(self, layout: GenericLayoutType, dxfattribs=None): + width = self.size * 0.15 + dxfattribs = dxfattribs or {} + if layout.dxfversion > "AC1009": + dxfattribs["const_width"] = width + layout.add_lwpolyline( + self.shape, format="xy", dxfattribs=dxfattribs # type: ignore + ) + else: + dxfattribs["default_start_width"] = width + dxfattribs["default_end_width"] = width + layout.add_polyline2d(self.shape, dxfattribs=dxfattribs) # type: ignore + + +class ClosedArrowBlank(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + super().__init__(open_arrow(size, angle=DEFAULT_ARROW_ANGLE)) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + if layout.dxfversion > "AC1009": + polyline = layout.add_lwpolyline( + points=self.shape, dxfattribs=dxfattribs # type: ignore + ) + else: + polyline = layout.add_polyline2d( # type: ignore + points=self.shape, dxfattribs=dxfattribs # type: ignore + ) + polyline.close(True) + + +class ClosedArrow(ClosedArrowBlank): + def render(self, layout: GenericLayoutType, dxfattribs=None): + super().render(layout, dxfattribs) + end_point = self.shape[0].lerp(self.shape[2]) + + layout.add_line( + start=self.shape[1], end=end_point, dxfattribs=dxfattribs + ) + + +class ClosedArrowFilled(ClosedArrow): + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_solid( + points=self.shape, # type: ignore + dxfattribs=dxfattribs, + ) + + +class _OpenArrow(BaseArrow): + def __init__( + self, + arrow_angle: float, + insert: UVec, + size: float = 1.0, + angle: float = 0, + ): + points = list(open_arrow(size, angle=arrow_angle)) + points.append((-1, 0)) + super().__init__(points) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + if layout.dxfversion > "AC1009": + layout.add_lwpolyline(points=self.shape[:-1], dxfattribs=dxfattribs) + else: + layout.add_polyline2d(points=self.shape[:-1], dxfattribs=dxfattribs) + layout.add_line( + start=self.shape[1], end=self.shape[-1], dxfattribs=dxfattribs + ) + + +class OpenArrow(_OpenArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + super().__init__(DEFAULT_ARROW_ANGLE, insert, size, angle) + + +class OpenArrow30(_OpenArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + super().__init__(30, insert, size, angle) + + +class OpenArrow90(_OpenArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + super().__init__(90, insert, size, angle) + + +class Circle(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + self.radius = size / 2 + # shape = [center point, connection point] + super().__init__( + [ + Vec2((0, 0)), + Vec2((-self.radius, 0)), + Vec2((-size, 0)), + ] + ) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_circle( + center=self.shape[0], radius=self.radius, dxfattribs=dxfattribs + ) + + +class Origin(Circle): + def render(self, layout: GenericLayoutType, dxfattribs=None): + super().render(layout, dxfattribs) + layout.add_line( + start=self.shape[0], end=self.shape[2], dxfattribs=dxfattribs + ) + + +class CircleBlank(Circle): + def render(self, layout: GenericLayoutType, dxfattribs=None): + super().render(layout, dxfattribs) + layout.add_line( + start=self.shape[1], end=self.shape[2], dxfattribs=dxfattribs + ) + + +class Origin2(Circle): + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_circle( + center=self.shape[0], radius=self.radius, dxfattribs=dxfattribs + ) + layout.add_circle( + center=self.shape[0], radius=self.radius / 2, dxfattribs=dxfattribs + ) + layout.add_line( + start=self.shape[1], end=self.shape[2], dxfattribs=dxfattribs + ) + + +class DotSmall(Circle): + def render(self, layout: GenericLayoutType, dxfattribs=None): + center = self.shape[0] + d = Vec2((self.radius / 2, 0)) + p1 = center - d + p2 = center + d + dxfattribs = dxfattribs or {} + if layout.dxfversion > "AC1009": + dxfattribs["const_width"] = self.radius + layout.add_lwpolyline( + [(p1, 1), (p2, 1)], + format="vb", + close=True, + dxfattribs=dxfattribs, + ) + else: + dxfattribs["default_start_width"] = self.radius + dxfattribs["default_end_width"] = self.radius + polyline = layout.add_polyline2d( + points=[p1, p2], close=True, dxfattribs=dxfattribs + ) + polyline[0].dxf.bulge = 1 + polyline[1].dxf.bulge = 1 + + +class Dot(DotSmall): + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_line( + start=self.shape[1], end=self.shape[2], dxfattribs=dxfattribs + ) + super().render(layout, dxfattribs) + + +class Box(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + # shape = [lower_left, lower_right, upper_right, upper_left, connection point] + s2 = size / 2 + super().__init__( + [ + Vec2((-s2, -s2)), + Vec2((+s2, -s2)), + Vec2((+s2, +s2)), + Vec2((-s2, +s2)), + Vec2((-s2, 0)), + Vec2((-size, 0)), + ] + ) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + if layout.dxfversion > "AC1009": + polyline = layout.add_lwpolyline( + points=self.shape[0:4], dxfattribs=dxfattribs + ) + else: + polyline = layout.add_polyline2d( # type: ignore + points=self.shape[0:4], dxfattribs=dxfattribs + ) + polyline.close(True) + layout.add_line( + start=self.shape[4], end=self.shape[5], dxfattribs=dxfattribs + ) + + +class BoxFilled(Box): + def render(self, layout: GenericLayoutType, dxfattribs=None): + def solid_order(): + v = self.shape.vertices + return [v[0], v[1], v[3], v[2]] + + layout.add_solid(points=solid_order(), dxfattribs=dxfattribs) + layout.add_line( + start=self.shape[4], end=self.shape[5], dxfattribs=dxfattribs + ) + + +class Integral(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + self.radius = size * 0.3535534 + self.angle = angle + # shape = [center, left_center, right_center] + super().__init__( + [ + Vec2((0, 0)), + Vec2((-self.radius, 0)), + Vec2((self.radius, 0)), + ] + ) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + angle = self.angle + layout.add_arc( + center=self.shape[1], + radius=self.radius, + start_angle=-90 + angle, + end_angle=angle, + dxfattribs=dxfattribs, + ) + layout.add_arc( + center=self.shape[2], + radius=self.radius, + start_angle=90 + angle, + end_angle=180 + angle, + dxfattribs=dxfattribs, + ) + + +class DatumTriangle(BaseArrow): + REVERSE_ANGLE = 180 + + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + d = 0.577350269 * size # tan(30) + # shape = [upper_corner, lower_corner, connection_point] + super().__init__( + [ + Vec2((0, d)), + Vec2((0, -d)), + Vec2((-size, 0)), + ] + ) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + if layout.dxfversion > "AC1009": + polyline = layout.add_lwpolyline( + points=self.shape, dxfattribs=dxfattribs # type: ignore + ) + else: + polyline = layout.add_polyline2d( # type: ignore + points=self.shape, dxfattribs=dxfattribs # type: ignore + ) + polyline.close(True) + + +class DatumTriangleFilled(DatumTriangle): + def render(self, layout: GenericLayoutType, dxfattribs=None): + layout.add_solid(points=self.shape, dxfattribs=dxfattribs) # type: ignore + + +class _EzArrow(BaseArrow): + def __init__(self, insert: UVec, size: float = 1.0, angle: float = 0): + points = list(arrow2(size, angle=DEFAULT_ARROW_ANGLE)) + points.append((-1, 0)) + super().__init__(points) + self.place(insert, angle) + + def render(self, layout: GenericLayoutType, dxfattribs=None): + if layout.dxfversion > "AC1009": + polyline = layout.add_lwpolyline( + self.shape[:-1], dxfattribs=dxfattribs + ) + else: + polyline = layout.add_polyline2d( # type: ignore + self.shape[:-1], dxfattribs=dxfattribs + ) + polyline.close(True) + + +class EzArrowBlank(_EzArrow): + def render(self, layout: GenericLayoutType, dxfattribs=None): + super().render(layout, dxfattribs) + layout.add_line( + start=self.shape[-2], end=self.shape[-1], dxfattribs=dxfattribs + ) + + +class EzArrow(_EzArrow): + def render(self, layout: GenericLayoutType, dxfattribs=None): + super().render(layout, dxfattribs) + layout.add_line( + start=self.shape[1], end=self.shape[-1], dxfattribs=dxfattribs + ) + + +class EzArrowFilled(_EzArrow): + def render(self, layout: GenericLayoutType, dxfattribs=None): + points = self.shape.vertices + layout.add_solid( + [points[0], points[1], points[3], points[2]], dxfattribs=dxfattribs + ) + layout.add_line( + start=self.shape[-2], end=self.shape[-1], dxfattribs=dxfattribs + ) + + +class _Arrows: + closed_filled = "" + dot = "DOT" + dot_small = "DOTSMALL" + dot_blank = "DOTBLANK" + origin_indicator = "ORIGIN" + origin_indicator_2 = "ORIGIN2" + open = "OPEN" + right_angle = "OPEN90" + open_30 = "OPEN30" + closed = "CLOSED" + dot_smallblank = "SMALL" + none = "NONE" + oblique = "OBLIQUE" + box_filled = "BOXFILLED" + box = "BOXBLANK" + closed_blank = "CLOSEDBLANK" + datum_triangle_filled = "DATUMFILLED" + datum_triangle = "DATUMBLANK" + integral = "INTEGRAL" + architectural_tick = "ARCHTICK" + # ezdxf special arrows + ez_arrow = "EZ_ARROW" + ez_arrow_blank = "EZ_ARROW_BLANK" + ez_arrow_filled = "EZ_ARROW_FILLED" + + CLASSES = { + closed_filled: ClosedArrowFilled, + dot: Dot, + dot_small: DotSmall, + dot_blank: CircleBlank, + origin_indicator: Origin, + origin_indicator_2: Origin2, + open: OpenArrow, + right_angle: OpenArrow90, + open_30: OpenArrow30, + closed: ClosedArrow, + dot_smallblank: Circle, + none: NoneStroke, + oblique: ObliqueStroke, + box_filled: BoxFilled, + box: Box, + closed_blank: ClosedArrowBlank, + datum_triangle: DatumTriangle, + datum_triangle_filled: DatumTriangleFilled, + integral: Integral, + architectural_tick: ArchTick, + ez_arrow: EzArrow, + ez_arrow_blank: EzArrowBlank, + ez_arrow_filled: EzArrowFilled, + } + # arrows with origin at dimension line start/end + ORIGIN_ZERO = { + architectural_tick, + oblique, + dot_small, + dot_smallblank, + integral, + none, + } + + __acad__ = { + closed_filled, + dot, + dot_small, + dot_blank, + origin_indicator, + origin_indicator_2, + open, + right_angle, + open_30, + closed, + dot_smallblank, + none, + oblique, + box_filled, + box, + closed_blank, + datum_triangle, + datum_triangle_filled, + integral, + architectural_tick, + } + __ezdxf__ = { + ez_arrow, + ez_arrow_blank, + ez_arrow_filled, + } + __all_arrows__ = __acad__ | __ezdxf__ + + EXTENSIONS_ALLOWED = { + architectural_tick, + oblique, + none, + dot_smallblank, + integral, + dot_small, + } + + def is_acad_arrow(self, item: str) -> bool: + """Returns ``True`` if `item` is a standard AutoCAD arrow.""" + return item.upper() in self.__acad__ + + def is_ezdxf_arrow(self, item: str) -> bool: + """Returns ``True`` if `item` is a special `ezdxf` arrow.""" + return item.upper() in self.__ezdxf__ + + def has_extension_line(self, name): + """Returns ``True`` if the arrow `name` supports extension lines.""" + return name in self.EXTENSIONS_ALLOWED + + def __contains__(self, item: str) -> bool: + """Returns `True` if `item` is an arrow managed by this class.""" + if item is None: + return False + return item.upper() in self.__all_arrows__ + + def create_block(self, blocks: BlocksSection, name: str) -> str: + """Creates the BLOCK definition for arrow `name`.""" + block_name = self.block_name(name) + if block_name not in blocks: + block = blocks.new(block_name) + arrow = self.arrow_shape(name, insert=(0, 0), size=1, rotation=0) + arrow.render(block, dxfattribs={"color": 0, "linetype": "BYBLOCK"}) + return block_name + + def arrow_handle(self, blocks: BlocksSection, name: str) -> str: + """Returns the BLOCK_RECORD handle for arrow `name`.""" + arrow_name = self.arrow_name(name) + block_name = self.create_block(blocks, arrow_name) + block = blocks.get(block_name) + return block.block_record_handle + + def block_name(self, name: str) -> str: + """Returns the block name.""" + if not self.is_acad_arrow(name): # common BLOCK definition + # e.g. Dimension.dxf.bkl = 'EZ_ARROW' == Insert.dxf.name + return name.upper() + elif name == "": + # special AutoCAD arrow symbol 'CLOSED_FILLED' has no name + # ezdxf uses blocks for ALL arrows, but '_' (closed filled) as block name? + return "_CLOSEDFILLED" # Dimension.dxf.bkl = '' != Insert.dxf.name = '_CLOSED_FILLED' + else: + # add preceding '_' to AutoCAD arrow symbol names + # Dimension.dxf.bkl = 'DOT' != Insert.dxf.name = '_DOT' + return "_" + name.upper() + + def arrow_name(self, block_name: str) -> str: + """Returns the arrow name.""" + if block_name.startswith("_"): + name = block_name[1:].upper() + if name == "CLOSEDFILLED": + return "" + elif self.is_acad_arrow(name): + return name + return block_name + + def insert_arrow( + self, + layout: GenericLayoutType, + name: str, + insert: UVec = NULLVEC, + size: float = 1.0, + rotation: float = 0, + *, + dxfattribs=None, + ) -> Vec2: + """Insert arrow as block reference into `layout`.""" + block_name = self.create_block(layout.doc.blocks, name) + + dxfattribs = dict(dxfattribs or {}) + dxfattribs["rotation"] = rotation + dxfattribs["xscale"] = size + dxfattribs["yscale"] = size + layout.add_blockref(block_name, insert=insert, dxfattribs=dxfattribs) + return connection_point( + name, insert=insert, scale=size, rotation=rotation + ) + + def render_arrow( + self, + layout: GenericLayoutType, + name: str, + insert: UVec = NULLVEC, + size: float = 1.0, + rotation: float = 0, + *, + dxfattribs=None, + ) -> Vec2: + """Render arrow as basic DXF entities into `layout`.""" + dxfattribs = dict(dxfattribs or {}) + arrow = self.arrow_shape(name, insert, size, rotation) + arrow.render(layout, dxfattribs) + return connection_point( + name, insert=insert, scale=size, rotation=rotation + ) + + def virtual_entities( + self, + name: str, + insert: UVec = NULLVEC, + size: float = 0.625, + rotation: float = 0, + *, + dxfattribs=None, + ) -> Iterator[DXFGraphic]: + """Returns all arrow components as virtual DXF entities.""" + from ezdxf.layouts import VirtualLayout + + if name in self: + layout = VirtualLayout() + ARROWS.render_arrow( + layout, + name, + insert=insert, + size=size, + rotation=rotation, + dxfattribs=dxfattribs, + ) + yield from iter(layout) + + def arrow_shape( + self, name: str, insert: UVec, size: float, rotation: float + ) -> BaseArrow: + """Returns an instance of the shape management class for arrow `name`.""" + # size depending shapes + name = name.upper() + if name == self.dot_small: + size *= 0.25 + elif name == self.dot_smallblank: + size *= 0.5 + cls = self.CLASSES[name] + return cls(insert, size, rotation) + + +def connection_point( + arrow_name: str, insert: UVec, scale: float = 1.0, rotation: float = 0.0 +) -> Vec2: + """Returns the connection point for `arrow_name`.""" + insert = Vec2(insert) + if ARROWS.arrow_name(arrow_name) in _Arrows.ORIGIN_ZERO: + return insert + else: + return insert - Vec2.from_deg_angle(rotation, scale) + + +def arrow_length(arrow_name: str, scale: float = 1.0) -> float: + """Returns the scaled arrow length of `arrow_name`.""" + if ARROWS.arrow_name(arrow_name) in _Arrows.ORIGIN_ZERO: + return 0.0 + else: + return scale + + +ARROWS: _Arrows = _Arrows() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/curves.py b/.venv/lib/python3.12/site-packages/ezdxf/render/curves.py new file mode 100644 index 0000000..9edd7e6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/curves.py @@ -0,0 +1,504 @@ +# Copyright (c) 2010-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional +import random +import math +from ezdxf.math import ( + Vec3, + Vec2, + UVec, + Matrix44, + perlin, + Bezier4P, + global_bspline_interpolation, + BSpline, + open_uniform_bspline, + closed_uniform_bspline, + EulerSpiral as _EulerSpiral, +) + +if TYPE_CHECKING: + from ezdxf.layouts import BaseLayout + + +def rnd(max_value): + return max_value / 2.0 - random.random() * max_value + + +def rnd_perlin(max_value, walker): + r = perlin.snoise2(walker.x, walker.y) + return max_value / 2.0 - r * max_value + + +def random_2d_path( + steps: int = 100, + max_step_size: float = 1.0, + max_heading: float = math.pi / 2, + retarget: int = 20, +) -> Iterable[Vec2]: + """Returns a random 2D path as iterable of :class:`~ezdxf.math.Vec2` + objects. + + Args: + steps: count of vertices to generate + max_step_size: max step size + max_heading: limit heading angle change per step to ± max_heading/2 in + radians + retarget: specifies steps before changing global walking target + + """ + max_ = max_step_size * steps + + def next_global_target(): + return Vec2((rnd(max_), rnd(max_))) + + walker = Vec2(0, 0) + target = next_global_target() + for i in range(steps): + if i % retarget == 0: + target = target + next_global_target() + angle = (target - walker).angle + heading = angle + rnd_perlin(max_heading, walker) + length = max_step_size * random.random() + walker = walker + Vec2.from_angle(heading, length) + yield walker + + +def random_3d_path( + steps: int = 100, + max_step_size: float = 1.0, + max_heading: float = math.pi / 2.0, + max_pitch: float = math.pi / 8.0, + retarget: int = 20, +) -> Iterable[Vec3]: + """Returns a random 3D path as iterable of :class:`~ezdxf.math.Vec3` + objects. + + Args: + steps: count of vertices to generate + max_step_size: max step size + max_heading: limit heading angle change per step to ± max_heading/2, + rotation about the z-axis in radians + max_pitch: limit pitch angle change per step to ± max_pitch/2, rotation + about the x-axis in radians + retarget: specifies steps before changing global walking target + + """ + max_ = max_step_size * steps + + def next_global_target(): + return Vec3((rnd(max_), rnd(max_), rnd(max_))) + + walker = Vec3() + target = next_global_target() + for i in range(steps): + if i % retarget == 0: + target = target + next_global_target() + angle = (target - walker).angle + length = max_step_size * random.random() + heading_angle = angle + rnd_perlin(max_heading, walker) + next_step = Vec3.from_angle(heading_angle, length) + pitch_angle = rnd_perlin(max_pitch, walker) + walker += Matrix44.x_rotate(pitch_angle).transform(next_step) + yield walker + + +class Bezier: + """Render a bezier curve as 2D/3D :class:`~ezdxf.entities.Polyline`. + + The :class:`Bezier` class is implemented with multiple segments, each + segment is an optimized 4 point bezier curve, the 4 control points of the + curve are: the start point (1) and the end point (4), point (2) is start + point + start vector and point (3) is end point + end vector. Each segment + has its own approximation count. + + .. seealso:: + + The new :mod:`ezdxf.path` package provides many advanced construction tools + based on the :class:`~ezdxf.path.Path` class. + + """ + + class Segment: + def __init__( + self, + start: UVec, + end: UVec, + start_tangent: UVec, + end_tangent: UVec, + segments: int, + ): + self.start = Vec3(start) + self.end = Vec3(end) + self.start_tangent = Vec3( + start_tangent + ) # as vector, from start point + self.end_tangent = Vec3(end_tangent) # as vector, from end point + self.segments = segments + + def approximate(self) -> Iterable[Vec3]: + control_points = [ + self.start, + self.start + self.start_tangent, + self.end + self.end_tangent, + self.end, + ] + bezier = Bezier4P(control_points) + return bezier.approximate(self.segments) + + def __init__(self) -> None: + # fit point, first control vector, second control vector, segment count + self.points: list[ + tuple[Vec3, Optional[Vec3], Optional[Vec3], Optional[int]] + ] = [] + + def start(self, point: UVec, tangent: UVec) -> None: + """Set start point and start tangent. + + Args: + point: start point + tangent: start tangent as vector, example: (5, 0, 0) means a + horizontal tangent with a length of 5 drawing units + """ + self.points.append((Vec3(point), None, tangent, None)) + + def append( + self, + point: UVec, + tangent1: UVec, + tangent2: Optional[UVec] = None, + segments: int = 20, + ): + """Append a control point with two control tangents. + + Args: + point: control point + tangent1: first tangent as vector "left" of the control point + tangent2: second tangent as vector "right" of the control point, + if omitted `tangent2` = `-tangent1` + segments: count of line segments for the polyline approximation, + count of line segments from the previous control point to the + appended control point. + + """ + tangent1 = Vec3(tangent1) + if tangent2 is None: + tangent2 = -tangent1 + else: + tangent2 = Vec3(tangent2) + self.points.append((Vec3(point), tangent1, tangent2, int(segments))) + + def _build_bezier_segments(self) -> Iterable[Segment]: + if len(self.points) > 1: + for from_point, to_point in zip(self.points[:-1], self.points[1:]): + start_point = from_point[0] + start_tangent = from_point[2] # tangent2 + end_point = to_point[0] + end_tangent = to_point[1] # tangent1 + count = to_point[3] + yield Bezier.Segment( + start_point, end_point, start_tangent, end_tangent, count # type: ignore + ) + else: + raise ValueError("Two or more points needed!") + + def render( + self, + layout: BaseLayout, + force3d: bool = False, + dxfattribs=None, + ) -> None: + """Render Bezier curve as 2D/3D :class:`~ezdxf.entities.Polyline`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + force3d: force 3D polyline rendering + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + points: list[Vec3] = [] + for segment in self._build_bezier_segments(): + points.extend(segment.approximate()) + if force3d or any(p[2] for p in points): + layout.add_polyline3d(points, dxfattribs=dxfattribs) + else: + layout.add_polyline2d(points, dxfattribs=dxfattribs) + + +class Spline: + """This class can be used to render B-splines into DXF R12 files as + approximated :class:`~ezdxf.entities.Polyline` entities. + The advantage of this class over the :class:`R12Spline` class is, + that this is a real 3D curve, which means that the B-spline vertices do + have to be located in a flat plane, and no :ref:`UCS` class is needed to + place the curve in 3D space. + + .. seealso:: + + The newer :class:`~ezdxf.math.BSpline` class provides the + advanced vertex interpolation method :meth:`~ezdxf.math.BSpline.flattening`. + + """ + + def __init__( + self, points: Optional[Iterable[UVec]] = None, segments: int = 100 + ): + """ + Args: + points: spline definition points + segments: count of line segments for approximation, vertex count is + `segments` + 1 + + """ + if points is None: + points = [] + self.points: list[Vec3] = Vec3.list(points) + self.segments = int(segments) + + def subdivide(self, segments: int = 4) -> None: + """Calculate overall segment count, where segments is the sub-segment + count, `segments` = 4, means 4 line segments between two definition + points e.g. 4 definition points and 4 segments = 12 overall segments, + useful for fit point rendering. + + Args: + segments: sub-segments count between two definition points + + """ + self.segments = (len(self.points) - 1) * segments + + def render_as_fit_points( + self, + layout: BaseLayout, + degree: int = 3, + method: str = "chord", + dxfattribs: Optional[dict] = None, + ) -> None: + """Render a B-spline as 2D/3D :class:`~ezdxf.entities.Polyline`, where + the definition points are fit points. + + - 2D spline vertices uses: :meth:`~ezdxf.layouts.BaseLayout.add_polyline2d` + - 3D spline vertices uses: :meth:`~ezdxf.layouts.BaseLayout.add_polyline3d` + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + degree: degree of B-spline (order = `degree` + 1) + method: "uniform", "distance"/"chord", "centripetal"/"sqrt_chord" or + "arc" calculation method for parameter t + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = global_bspline_interpolation( + self.points, degree=degree, method=method + ) + vertices = list(spline.approximate(self.segments)) + if any(vertex.z != 0.0 for vertex in vertices): + layout.add_polyline3d(vertices, dxfattribs=dxfattribs) + else: + layout.add_polyline2d(vertices, dxfattribs=dxfattribs) + + render = render_as_fit_points + + def render_open_bspline( + self, layout: BaseLayout, degree: int = 3, dxfattribs=None + ) -> None: + """Render an open uniform B-spline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = BSpline(self.points, order=degree + 1) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + def render_uniform_bspline( + self, layout: BaseLayout, degree: int = 3, dxfattribs=None + ) -> None: + """Render a uniform B-spline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = open_uniform_bspline(self.points, order=degree + 1) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + def render_closed_bspline( + self, layout: BaseLayout, degree: int = 3, dxfattribs=None + ) -> None: + """Render a closed uniform B-spline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = closed_uniform_bspline(self.points, order=degree + 1) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + def render_open_rbspline( + self, + layout: BaseLayout, + weights: Iterable[float], + degree: int = 3, + dxfattribs=None, + ) -> None: + """Render a rational open uniform BSpline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + weights: list of weights, requires a weight value (float) for each + definition point. + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = BSpline(self.points, order=degree + 1, weights=weights) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + def render_uniform_rbspline( + self, + layout: BaseLayout, + weights: Iterable[float], + degree: int = 3, + dxfattribs=None, + ) -> None: + """Render a rational uniform B-spline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + weights: list of weights, requires a weight value (float) for each + definition point. + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = closed_uniform_bspline( + self.points, order=degree + 1, weights=weights + ) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + def render_closed_rbspline( + self, + layout: BaseLayout, + weights: Iterable[float], + degree: int = 3, + dxfattribs=None, + ) -> None: + """Render a rational B-spline as 3D :class:`~ezdxf.entities.Polyline`. + Definition points are control points. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + weights: list of weights, requires a weight value (float) for each + definition point. + degree: degree of B-spline (order = `degree` + 1) + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + spline = closed_uniform_bspline( + self.points, order=degree + 1, weights=weights + ) + layout.add_polyline3d( + list(spline.approximate(self.segments)), dxfattribs=dxfattribs + ) + + +class EulerSpiral: + """Render an `euler spiral `_ + as a 3D :class:`~ezdxf.entities.Polyline` or a + :class:`~ezdxf.entities.Spline` entity. + + This is a parametric curve, which always starts at the origin (0, 0). + + """ + + def __init__(self, curvature: float = 1): + """ + Args: + curvature: Radius of curvature + + """ + self.spiral = _EulerSpiral(float(curvature)) + + def render_polyline( + self, + layout: BaseLayout, + length: float = 1, + segments: int = 100, + matrix: Optional[Matrix44] = None, + dxfattribs=None, + ): + """Render curve as :class:`~ezdxf.entities.Polyline`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + length: length measured along the spiral curve from its initial position + segments: count of line segments to use, vertex count is `segments` + 1 + matrix: transformation matrix as :class:`~ezdxf.math.Matrix44` + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + Returns: + :class:`~ezdxf.entities.Polyline` + + """ + points = self.spiral.approximate(length, segments) + if matrix is not None: + points = matrix.transform_vertices(points) + return layout.add_polyline3d(list(points), dxfattribs=dxfattribs) + + def render_spline( + self, + layout: BaseLayout, + length: float = 1, + fit_points: int = 10, + degree: int = 3, + matrix: Optional[Matrix44] = None, + dxfattribs=None, + ): + """ + Render curve as :class:`~ezdxf.entities.Spline`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + length: length measured along the spiral curve from its initial position + fit_points: count of spline fit points to use + degree: degree of B-spline + matrix: transformation matrix as :class:`~ezdxf.math.Matrix44` + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Spline` + + Returns: + :class:`~ezdxf.entities.Spline` + + """ + spline = self.spiral.bspline(length, fit_points, degree=degree) + points = spline.control_points + if matrix is not None: + points = matrix.transform_vertices(points) + return layout.add_open_spline( + control_points=points, + degree=spline.degree, + knots=spline.knots(), + dxfattribs=dxfattribs, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_base.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_base.py new file mode 100644 index 0000000..1639758 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_base.py @@ -0,0 +1,1350 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Optional, + Any, + cast, +) +import math +import abc +from ezdxf.math import ( + Vec3, + Vec2, + UVec, + ConstructionLine, + ConstructionBox, + ConstructionArc, +) +from ezdxf.math import UCS, PassTroughUCS, xround, Z_AXIS +from ezdxf.lldxf import const +from ezdxf.enums import TextEntityAlignment +from ezdxf._options import options +from ezdxf.lldxf.const import DXFValueError, DXFUndefinedBlockError +from ezdxf.tools import suppress_zeros +from ezdxf.render.arrows import ARROWS +from ezdxf.entities import DimStyleOverride, Dimension + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import Textstyle + from ezdxf.eztypes import GenericLayoutType + + +class TextBox(ConstructionBox): + """Text boundaries representation.""" + + def __init__( + self, + center: Vec2 = Vec2(0, 0), + width: float = 0.0, + height: float = 0.0, + angle: float = 0.0, + hgap: float = 0.0, # horizontal gap - width + vgap: float = 0.0, # vertical gap - height + ): + super().__init__(center, width + 2.0 * hgap, height + 2.0 * vgap, angle) + + +PLUS_MINUS = "±" +_TOLERANCE_COMMON = r"\A{align};{txt}{{\H{fac:.2f}x;" +TOLERANCE_TEMPLATE1 = _TOLERANCE_COMMON + r"{tol}}}" +TOLERANCE_TEMPLATE2 = _TOLERANCE_COMMON + r"\S{upr}^ {lwr};}}" +LIMITS_TEMPLATE = r"{{\H{fac:.2f}x;\S{upr}^ {lwr};}}" + + +def OptionalVec2(v) -> Optional[Vec2]: + if v is not None: + return Vec2(v) + else: + return None + + +def sign_char(value: float) -> str: + if value < 0.0: + return "-" + elif value > 0: + return "+" + else: + return " " + + +def format_text( + value: float, + dimrnd: Optional[float] = None, + dimdec: int = 2, + dimzin: int = 0, + dimdsep: str = ".", +) -> str: + if dimrnd is not None: + value = xround(value, dimrnd) + + if dimdec is None: + fmt = "{:f}" + # Remove pending zeros for undefined decimal places: + # '{:f}'.format(0) -> '0.000000' + dimzin = dimzin | 8 + else: + fmt = "{:." + str(dimdec) + "f}" + text = fmt.format(value) + + leading = bool(dimzin & 4) + pending = bool(dimzin & 8) + text = suppress_zeros(text, leading, pending) + if dimdsep != ".": + text = text.replace(".", dimdsep) + return text + + +def apply_dimpost(text: str, dimpost: str) -> str: + if "<>" in dimpost: + fmt = dimpost.replace("<>", "{}", 1) + return fmt.format(text) + else: + raise DXFValueError(f'Invalid dimpost string: "{dimpost}"') + + +class Tolerance: # and Limits + def __init__( + self, + dim_style: DimStyleOverride, + cap_height: float = 1.0, + width_factor: float = 1.0, + dim_scale: float = 1.0, + ): + self.text_width_factor = width_factor + self.dim_scale = dim_scale + get = dim_style.get + # Appends tolerances to dimension text. + # enabling DIMTOL disables DIMLIM. + self.has_tolerance = bool(get("dimtol", 0)) + self.has_limits = False + if not self.has_tolerance: + # Limits generates dimension limits as the default text. + self.has_limits = bool(get("dimlim", 0)) + + # Scale factor for the text height of fractions and tolerance values + # relative to the dimension text height + self.text_scale_factor: float = get("dimtfac", 0.5) + + self.text_decimal_separator = dim_style.get_decimal_separator() + + # Default MTEXT line spacing for tolerances (BricsCAD) + self.line_spacing: float = 1.35 + + # Sets the minimum (or lower) tolerance limit for dimension text when + # DIMTOL or DIMLIM is on. + # DIMTM accepts signed values. + # If DIMTOL is on and DIMTP and DIMTM are set to the same value, a + # tolerance value is drawn. + # If DIMTM and DIMTP values differ, the upper tolerance is drawn above + # the lower, and a plus sign is added to the DIMTP value if it is + # positive. + # For DIMTM, the program uses the negative of the value you enter + # (adding a minus sign if you specify a positive number and a plus sign + # if you specify a negative number). + self.minimum: float = get("dimtm", 0.0) + + # Sets the maximum (or upper) tolerance limit for dimension text when + # DIMTOL or DIMLIM is on. + # DIMTP accepts signed values. + # If DIMTOL is on and DIMTP and DIMTM are set to the same value, a + # tolerance value is drawn. + # If DIMTM and DIMTP values differ, the upper tolerance is drawn above + # the lower and a plus sign is added to the DIMTP value if it is + # positive. + self.maximum: float = get("dimtp", 0.0) + + # Number of decimal places to display in tolerance values + # Same value for linear and angular measurements! + self.decimal_places: int = get("dimtdec", 2) + + # Vertical justification for tolerance values relative to the nominal dimension text + # 0 = Bottom + # 1 = Middle + # 2 = Top + self.valign: int = get("dimtolj", 0) + + # Same as DIMZIN for tolerances (self.text_suppress_zeros) + # Same value for linear and angular measurements! + self.suppress_zeros: int = get("dimtzin", 0) + self.text: str = "" + self.text_height: float = 0.0 + self.text_width: float = 0.0 + self.text_upper: str = "" + self.text_lower: str = "" + self.char_height: float = cap_height * self.text_scale_factor * self.dim_scale + if self.has_tolerance: + self.init_tolerance() + elif self.has_limits: + self.init_limits() + + @property + def enabled(self) -> bool: + return self.has_tolerance or self.has_limits + + def disable(self): + self.has_tolerance = False + self.has_limits = False + + def init_tolerance(self): + # The tolerance values are stored in the dimension style, they are + # independent from the actual measurement: + # Single tolerance value +/- value + if self.minimum == self.maximum: + self.text_height = self.char_height + self.text_width = self.get_text_width(self.text, self.text) + else: # 2 stacked values: +upper tolerance -lower tolerance + # requires 2 text lines + self.text_height = self.char_height + (self.text_height * self.line_spacing) + self.text_width = self.get_text_width(self.text_upper, self.text_lower) + self.update_tolerance_text(self.maximum, self.minimum) + + def update_tolerance_text(self, tol_upper: float, tol_lower: float): + if tol_upper == tol_lower: + self.text = PLUS_MINUS + self.format_text(abs(tol_upper)) + else: + self.text_upper = sign_char(tol_upper) + self.format_text(abs(tol_upper)) + self.text_lower = sign_char(tol_lower * -1) + self.format_text( + abs(tol_lower) + ) + + def init_limits(self): + # self.text is always an empty string (default value) + # Limit text are always 2 stacked numbers and requires the actual + # measurement! + self.text_height = self.char_height + (self.text_height * self.line_spacing) + + def format_text(self, value: float) -> str: + """Rounding and text formatting of tolerance `value`, removes leading + and trailing zeros if necessary. + + """ + # dimpost is not applied to limits or tolerances! + return format_text( + value=value, + dimrnd=None, + dimdec=self.decimal_places, + dimzin=self.suppress_zeros, + dimdsep=self.text_decimal_separator, + ) + + def get_text_width(self, upr: str, lwr: str) -> float: + """Returns the text width of the tolerance (upr/lwr) in drawing units.""" + # todo: use matplotlib support + count = max(len(upr), len(lwr)) + return self.text_height * self.text_width_factor * count + + def compile_mtext(self, text: str) -> str: + if self.has_tolerance: + align = max(int(self.valign), 0) + align = min(align, 2) + if not self.text: + text = TOLERANCE_TEMPLATE2.format( + align=align, + txt=text, + fac=self.text_scale_factor, + upr=self.text_upper, + lwr=self.text_lower, + ) + else: + text = TOLERANCE_TEMPLATE1.format( + align=align, + txt=text, + fac=self.text_scale_factor, + tol=self.text, + ) + elif self.has_limits: + text = LIMITS_TEMPLATE.format( + upr=self.text_upper, + lwr=self.text_lower, + fac=self.text_scale_factor, + ) + return text + + def update_limits(self, measurement: float) -> None: + upper_limit = measurement + self.maximum + lower_limit = measurement - self.minimum + self.text_upper = self.format_text(upper_limit) + self.text_lower = self.format_text(lower_limit) + self.text_width = self.get_text_width(self.text_upper, self.text_lower) + + +class ExtensionLines: + default_lineweight: int = const.LINEWEIGHT_BYBLOCK + + def __init__(self, dim_style: DimStyleOverride, default_color: int, scale: float): + get = dim_style.get + self.color: int = get("dimclre", default_color) # ACI + self.linetype1: str = get("dimltex1", "") + self.linetype2: str = get("dimltex2", "") + self.lineweight: int = get("dimlwe", self.default_lineweight) + self.suppress1: bool = bool(get("dimse1", 0)) + self.suppress2: bool = bool(get("dimse2", 0)) + + # Extension of extension line above the dimension line, in extension + # line direction in most cases perpendicular to dimension line + # (oblique!) + self.extension_above: float = get("dimexe", 0.0) * scale + + # Distance of extension line from the measurement point in extension + # line direction + self.offset: float = get("dimexo", 0.0) * scale + + # Fixed length extension line, length above dimension line is still + # self.ext_line_extension + self.has_fixed_length: bool = bool(get("dimfxlon", 0)) + + # Length below the dimension line: + self.length_below: float = get("dimfxl", self.extension_above) * scale + + def dxfattribs(self, num: int = 1) -> Any: + """Returns default dimension line DXF attributes as dict.""" + attribs: dict[str, Any] = {"color": self.color} + if num == 1: + linetype = self.linetype1 + elif num == 2: + linetype = self.linetype2 + else: + raise ValueError(f"invalid argument num:{num}") + + if linetype: + attribs["linetype"] = linetype + if self.lineweight != self.default_lineweight: + attribs["lineweight"] = self.lineweight + return attribs + + +class DimensionLine: + default_lineweight: int = const.LINEWEIGHT_BYBLOCK + + def __init__(self, dim_style: DimStyleOverride, default_color: int, scale: float): + get = dim_style.get + self.color: int = get("dimclrd", default_color) # ACI + + # Dimension line extension, along the dimension line direction ('left' + # and 'right') + self.extension: float = get("dimdle", 0.0) * scale + self.linetype: str = get("dimltype", "") + self.lineweight: int = get("dimlwd", self.default_lineweight) + + # Suppress first part of the dimension line + self.suppress1: bool = bool(get("dimsd1", 0)) + + # Suppress second part of the dimension line + self.suppress2: bool = bool(get("dimsd2", 0)) + + # Controls whether a dimension line is drawn between the extension lines + # even when the text is placed outside. + # For radius and diameter dimensions (when DIMTIX is off), draws a + # dimension line inside the circle or arc and places the text, + # arrowheads, and leader outside. + # 0 = no dimension line + # 1 = draw dimension line + # not supported yet - ezdxf behaves like option 1 + self.has_dim_line_if_text_outside: bool = bool(get("dimtofl", 1)) + + def dxfattribs(self) -> Any: + """Returns default dimension line DXF attributes as dict.""" + attribs: dict[str, Any] = {"color": self.color} + if self.linetype: + attribs["linetype"] = self.linetype + if self.lineweight != self.default_lineweight: + attribs["lineweight"] = self.lineweight + return attribs + + +class Arrows: + def __init__(self, dim_style: DimStyleOverride, color: int, scale: float): + get = dim_style.get + self.color: int = get("dimclrd", color) + self.tick_size: float = get("dimtsz", 0.0) * scale + self.arrow1_name: str = "" # empty string is a closed filled arrow + self.arrow2_name: str = "" # empty string is a closed filled arrow + self.arrow_size: float = get("dimasz", 0.25) * scale + self.suppress1 = False # ezdxf only + self.suppress2 = False # ezdxf only + + if self.tick_size > 0.0: + # Use oblique strokes as 'arrows', disables usual 'arrows' and user + # defined blocks tick size is per definition double the size of + # arrow size adjust arrow size to reuse the 'oblique' arrow block + self.arrow_size = self.tick_size * 2.0 + else: + # Arrow name or block name if user defined arrow + ( + self.arrow1_name, + self.arrow2_name, + ) = dim_style.get_arrow_names() + + @property + def has_ticks(self) -> bool: + return self.tick_size > 0.0 + + def dxfattribs(self) -> Any: + return {"color": self.color} + + +class Measurement: + def __init__( + self, + dim_style: DimStyleOverride, + color: int, + scale: float, + ): + # update this values in method Measurement.update() + # raw measured value + self.raw_value: float = 0.0 + # scaled measured value + self.value: float = 0.0 + # Final formatted dimension text + self.text: str = "" + + dimension = dim_style.dimension + doc = dimension.doc + assert doc is not None, "valid DXF document required" + + # ezdxf specific attributes beyond DXF reference, therefore not stored + # in the DXF file (DSTYLE). + # Some of these are just an rendering effect, which will be ignored by + # CAD applications if they modify the DIMENSION entity + + # User location override as UCS coordinates, stored as text_midpoint in + # the DIMENSION entity + self.user_location: Optional[Vec2] = OptionalVec2( + dim_style.pop("user_location", None) + ) + + # User location override relative to dimline center if True + self.relative_user_location: bool = dim_style.pop( + "relative_user_location", False + ) + + # Shift text away from default text location - implemented as user + # location override without leader + # Shift text along in text direction: + self.text_shift_h: float = dim_style.pop("text_shift_h", 0.0) + # Shift text perpendicular to text direction: + self.text_shift_v: float = dim_style.pop("text_shift_v", 0.0) + # End of ezdxf specific attributes + + get = dim_style.get + # ezdxf locates attachment points always in the text center. + # Fixed predefined value for ezdxf rendering: + self.text_attachment_point: int = 5 + + # Ignored by ezdxf: + self.horizontal_direction: Optional[float] = dimension.get_dxf_attrib( + "horizontal_direction", None + ) + + # Dimension measurement factor: + self.measurement_factor: float = get("dimlfac", 1.0) + + # Text style + style_name: str = get("dimtxsty", options.default_dimension_text_style) + if style_name not in doc.tables.styles: + style_name = "Standard" + self.text_style_name: str = style_name + text_style = get_text_style(doc, style_name) + self.text_height: float = get_char_height(dim_style, text_style) * scale + self.text_width_factor: float = text_style.get_dxf_attrib("width", 1.0) + self.stored_dim_text = dimension.dxf.text + + # text_gap: gap between dimension line an dimension text + self.text_gap: float = get("dimgap", 0.625) * scale + + # User defined text rotation - overrides everything: + self.user_text_rotation: float = dimension.get_dxf_attrib("text_rotation", None) + # calculated text rotation + self.text_rotation: float = self.user_text_rotation + self.text_color: int = get("dimclrt", color) # ACI + self.text_round: Optional[float] = get("dimrnd", None) + self.decimal_places: int = get("dimdec", 2) + self.angular_decimal_places: int = get("dimadec", 2) + + # Controls the suppression of zeros in the primary unit value. + # Values 0-3 affect feet-and-inch dimensions only and are not supported + # 4 (Bit 3) = Suppresses leading zeros in decimal dimensions, + # e.g. 0.5000 becomes .5000 + # 8 (Bit 4) = Suppresses trailing zeros in decimal dimensions, + # e.g. 12.5000 becomes 12.5 + # 12 (Bit 3+4) = Suppresses both leading and trailing zeros, + # e.g. 0.5000 becomes .5) + self.suppress_zeros: int = get("dimzin", 8) + + # special setting for angular dimensions (dimzin << 2) & 3 + # 0 = Displays all leading and trailing zeros + # 1 = Suppresses leading zeros (for example, 0.5000 becomes .5000) + # 2 = Suppresses trailing zeros (for example, 12.5000 becomes 12.5) + # 3 = Suppresses leading and trailing zeros (for example, 0.5000 becomes .5) + self.angular_suppress_zeros: int = get("dimazin", 2) + + # decimal separator char, default is ",": + self.decimal_separator: str = dim_style.get_decimal_separator() + + self.text_post_process_format: str = get("dimpost", "") + # text_fill: + # 0 = None + # 1 = Background + # 2 = DIMTFILLCLR + self.text_fill: int = get("dimtfill", 0) + self.text_fill_color: int = get("dimtfillclr", 1) # ACI + self.text_box_fill_scale: float = 1.1 + + # text_halign: + # 0 = center + # 1 = left + # 2 = right + # 3 = above ext1 + # 4 = above ext2 + self.text_halign: int = get("dimjust", 0) + + # text_valign: + # 0 = center + # 1 = above + # 2 = farthest away? + # 3 = JIS; + # 4 = below + # Options 2, 3 are ignored by ezdxf + self.text_valign: int = get("dimtad", 0) + + # Controls the vertical position of dimension text above or below the + # dimension line, when DIMTAD = 0. + # The magnitude of the vertical offset of text is the product of the + # text height (+gap?) and DIMTVP. + # Setting DIMTVP to 1.0 is equivalent to setting DIMTAD = 1. + self.text_vertical_position: float = get("dimtvp", 0.0) + + # Move text freely: + # 0 = Moves the dimension line with dimension text + # 1 = Adds a leader when dimension text is moved + # 2 = Allows text to be moved freely without a leader + self.text_movement_rule: int = get("dimtmove", 2) + + self.has_leader: bool = ( + self.user_location is not None and self.text_movement_rule == 1 + ) + + # text_rotation is 0 if dimension text is 'inside', ezdxf defines + # 'inside' as at the default text location: + self.text_inside_horizontal: bool = get("dimtih", 0) + + # text_rotation is 0 if dimension text is 'outside', ezdxf defines + # 'outside' as NOT at the default text location: + self.text_outside_horizontal: bool = get("dimtoh", 0) + + # Force text location 'inside', even if the text should be moved + # 'outside': + self.force_text_inside: bool = bool(get("dimtix", 0)) + + # How dimension text and arrows are arranged when space is not + # sufficient to place both 'inside': + # 0 = Places both text and arrows outside extension lines + # 1 = Moves arrows first, then text + # 2 = Moves text first, then arrows + # 3 = Moves either text or arrows, whichever fits best + # not supported - ezdxf behaves like 2 + self.text_fitting_rule: int = get("dimatfit", 2) + + # Units for all dimension types except Angular. + # 1 = Scientific + # 2 = Decimal + # 3 = Engineering + # 4 = Architectural (always displayed stacked) + # 5 = Fractional (always displayed stacked) + # not supported - ezdxf behaves like 2 + self.length_unit: int = get("dimlunit", 2) + + # Fraction format when DIMLUNIT is set to 4 (Architectural) or + # 5 (Fractional). + # 0 = Horizontal stacking + # 1 = Diagonal stacking + # 2 = Not stacked (for example, 1/2) + self.fraction_format: int = get("dimfrac", 0) # not supported + + # Units format for angular dimensions + # 0 = Decimal degrees + # 1 = Degrees/minutes/seconds + # 2 = Grad + # 3 = Radians + self.angle_units: int = get("dimaunit", 0) + + self.has_arc_length_prefix: bool = False + if get("dimarcsym", 2) == 0: + self.has_arc_length_prefix = True + + # Text_outside is only True if really placed outside of default text + # location + # remark: user defined text location is always outside per definition + # (not by real location) + self.text_is_outside: bool = False + + # Final calculated or overridden dimension text location + self.text_location: Vec2 = Vec2(0, 0) + + # True if dimension text doesn't fit between extension lines + self.is_wide_text: bool = False + + # Text rotation was corrected to make upside down text better readable + self.has_upside_down_correction: bool = False + + @property + def text_is_inside(self): + return not self.text_is_outside + + @property + def has_relative_text_movement(self): + return bool(self.text_shift_h or self.text_shift_v) + + def apply_text_shift(self, location: Vec2, text_rotation: float) -> Vec2: + """Add `self.text_shift_h` and `sel.text_shift_v` to point `location`, + shifting along and perpendicular to text orientation defined by + `text_rotation`. + + Args: + location: location point + text_rotation: text rotation in degrees + + Returns: new location + + """ + shift_vec = Vec2((self.text_shift_h, self.text_shift_v)) + location += shift_vec.rotate_deg(text_rotation) + return location + + @property + def vertical_placement(self) -> float: + """Returns vertical placement of dimension text as 1 for above, 0 for + center and -1 for below dimension line. + + """ + if self.text_valign == 0: + return 0 + elif self.text_valign == 4: + return -1 + else: + return 1 + + def text_vertical_distance(self) -> float: + """Returns the vertical distance for dimension line to text midpoint. + Positive values are above the line, negative values are below the line. + + """ + if self.text_valign == 0: + return self.text_height * self.text_vertical_position + else: + return (self.text_height / 2.0 + self.text_gap) * self.vertical_placement + + def text_width(self, text: str) -> float: + """ + Return width of `text` in drawing units. + + """ + # todo: use matplotlib support + char_width = self.text_height * self.text_width_factor + return len(text) * char_width + + def text_override(self, measurement: float) -> str: + """Create dimension text for `measurement` in drawing units and applies + text overriding properties. + + """ + text = self.stored_dim_text + if text == " ": # suppresses text + return "" + elif text == "" or text == "<>": # measured distance + return self.format_text(measurement) + else: # user override + return text + + def location_override(self, location: UVec, leader=False, relative=False) -> None: + """Set user defined dimension text location. ezdxf defines a user + defined location per definition as 'outside'. + + Args: + location: text midpoint + leader: use leader or not (movement rules) + relative: is location absolute (in UCS) or relative to dimension + line center. + + """ + self.user_location = Vec2(location) + self.text_movement_rule = 1 if leader else 2 + self.relative_user_location = relative + self.text_is_outside = True + + def dxfattribs(self) -> Any: + return {"color": self.text_color} + + @abc.abstractmethod + def update(self, raw_measurement_value: float) -> None: + """Update raw measurement value, scaled measurement value and + dimension text. + + """ + + @abc.abstractmethod + def format_text(self, value: float) -> str: + """Rounding and text formatting of `value`, removes leading and + trailing zeros if necessary. + + """ + + +class LengthMeasurement(Measurement): + def update(self, raw_measurement_value: float) -> None: + """Update raw measurement value, scaled measurement value and + dimension text. + """ + self.raw_value = raw_measurement_value + self.value = raw_measurement_value * self.measurement_factor + self.text = self.text_override(self.value) + + def format_text(self, value: float) -> str: + """Rounding and text formatting of `value`, removes leading and + trailing zeros if necessary. + + """ + text = format_text( + value, + self.text_round, + self.decimal_places, + self.suppress_zeros, + self.decimal_separator, + ) + if self.text_post_process_format: + text = apply_dimpost(text, self.text_post_process_format) + return text + + +class Geometry: + """ + Geometry layout entities are located in the OCS defined by the extrusion + vector of the DIMENSION entity and the z-axis of the OCS + point 'text_midpoint' (group code 11). + + """ + + def __init__( + self, + dimension: Dimension, + ucs: UCS, + layout: "GenericLayoutType", + ): + assert dimension.doc is not None, "valid DXF document required" + self.dimension: Dimension = dimension + self.doc: Drawing = dimension.doc + self.dxfversion: str = self.doc.dxfversion + self.supports_dxf_r2000: bool = self.dxfversion >= "AC1015" + self.supports_dxf_r2007: bool = self.dxfversion >= "AC1021" + self.ucs: UCS = ucs + self.extrusion: Vec3 = ucs.uz + self.requires_extrusion: bool = not self.extrusion.isclose(Z_AXIS) + self.layout: GenericLayoutType = layout + self._text_box: TextBox = TextBox() + + @property + def has_text_box(self) -> bool: + return self._text_box.width > 0.0 and self._text_box.height > 0.0 + + def set_layout(self, layout: GenericLayoutType) -> None: + self.layout = layout + + def set_text_box(self, text_box: TextBox) -> None: + self._text_box = text_box + + def has_block(self, name: str) -> bool: + return name in self.doc.blocks + + def add_arrow_blockref( + self, + name: str, + insert: Vec2, + size: float, + rotation: float, + dxfattribs, + ) -> None: + # OCS of the arrow blocks is defined by the DIMENSION entity! + # Therefore remove OCS elevation, the elevation is defined by the + # DIMENSION 'text_midpoint' (group code 11) and do not set 'extrusion' + # either! + insert = self.ucs.to_ocs(Vec3(insert)).vec2 + rotation = self.ucs.to_ocs_angle_deg(rotation) + self.layout.add_arrow_blockref(name, insert, size, rotation, dxfattribs) + + def add_blockref( + self, + name: str, + insert: Vec2, + rotation: float, + dxfattribs, + ) -> None: + # OCS of the arrow blocks is defined by the DIMENSION entity! + # Therefore remove OCS elevation, the elevation is defined by the + # DIMENSION 'text_midpoint' (group code 11) and do not set 'extrusion' + # either! + insert = self.ucs.to_ocs(Vec3(insert)).vec2 + dxfattribs["rotation"] = self.ucs.to_ocs_angle_deg(rotation) + self.layout.add_blockref(name, insert, dxfattribs) + + def add_text(self, text: str, pos: Vec2, rotation: float, dxfattribs) -> None: + dxfattribs["rotation"] = self.ucs.to_ocs_angle_deg(rotation) + entity = self.layout.add_text(text, dxfattribs=dxfattribs) + # OCS of the measurement text is defined by the DIMENSION entity! + # Therefore remove OCS elevation, the elevation is defined by the + # DIMENSION 'text_midpoint' (group code 11) and do not set 'extrusion' + # either! + entity.set_placement( + self.ucs.to_ocs(Vec3(pos)).vec2, + align=TextEntityAlignment.MIDDLE_CENTER, + ) + + def add_mtext(self, text: str, pos: Vec2, rotation: float, dxfattribs) -> None: + # OCS of the measurement text is defined by the DIMENSION entity! + # Therefore remove OCS elevation, the elevation is defined by the + # DIMENSION 'text_midpoint' (group code 11) and do not set 'extrusion' + # either! + dxfattribs["rotation"] = self.ucs.to_ocs_angle_deg(rotation) + dxfattribs["insert"] = self.ucs.to_ocs(Vec3(pos)).vec2 + self.layout.add_mtext(text, dxfattribs) + + def add_defpoints(self, points: Iterable[Vec2]) -> None: + attribs = { + "layer": "Defpoints", + } + for point in points: + # Despite the fact that the POINT entity has WCS coordinates, + # the coordinates of defpoints in DIMENSION entities have OCS + # coordinates. + location = self.ucs.to_ocs(Vec3(point)).replace(z=0.0) + self.layout.add_point(location, dxfattribs=attribs) + + def add_line( + self, + start: Vec2, + end: Vec2, + dxfattribs, + remove_hidden_lines=False, + ) -> None: + """Add a LINE entity to the geometry layout. Removes parts of the line + hidden by dimension text if `remove_hidden_lines` is True. + + Args: + start: start point of line + end: end point of line + dxfattribs: additional or overridden DXF attributes + remove_hidden_lines: removes parts of the line hidden by dimension + text if ``True`` + + """ + + def add_line_to_block(start, end): + # LINE is handled like an OCS entity !? + self.layout.add_line( + to_ocs(Vec3(start)).vec2, + to_ocs(Vec3(end)).vec2, + dxfattribs=dxfattribs, + ) + + def order(a: Vec2, b: Vec2) -> tuple[Vec2, Vec2]: + if (start - a).magnitude < (start - b).magnitude: + return a, b + else: + return b, a + + to_ocs = self.ucs.to_ocs + if remove_hidden_lines and self.has_text_box: + text_box = self._text_box + start_inside = int(text_box.is_inside(start)) + end_inside = int(text_box.is_inside(end)) + inside = start_inside + end_inside + if inside == 2: # start and end inside text_box + return # do not draw line + elif inside == 1: # one point inside text_box or on a border line + intersection_points = text_box.intersect(ConstructionLine(start, end)) + if len(intersection_points) == 1: + # one point inside one point outside -> one intersection point + p1 = intersection_points[0] + else: + # second point on a text box border line + p1, _ = order(*intersection_points) + p2 = start if end_inside else end + add_line_to_block(p1, p2) + return + else: + intersection_points = text_box.intersect(ConstructionLine(start, end)) + if len(intersection_points) == 2: + # sort intersection points by distance to start point + p1, p2 = order(intersection_points[0], intersection_points[1]) + # line[start-p1] - gap - line[p2-end] + add_line_to_block(start, p1) + add_line_to_block(p2, end) + return + # else: fall through + add_line_to_block(start, end) + + def add_arc( + self, + center: Vec2, + radius: float, + start_angle: float, + end_angle: float, + dxfattribs=None, + remove_hidden_lines=False, + ) -> None: + """Add a ARC entity to the geometry layout. Removes parts of the arc + hidden by dimension text if `remove_hidden_lines` is True. + + Args: + center: center of arc + radius: radius of arc + start_angle: start angle in radians + end_angle: end angle in radians + dxfattribs: additional or overridden DXF attributes + remove_hidden_lines: removes parts of the arc hidden by dimension + text if ``True`` + + """ + + def add_arc(s: float, e: float) -> None: + """Add ARC entity to geometry block.""" + self.layout.add_arc( + center=ocs_center, + radius=radius, + start_angle=math.degrees(ocs_angle(s)), + end_angle=math.degrees(ocs_angle(e)), + dxfattribs=dxfattribs, + ) + + # OCS of the ARC is defined by the DIMENSION entity! + # Therefore remove OCS elevation, the elevation is defined by the + # DIMENSION 'text_midpoint' (group code 11) and do not set 'extrusion' + # either! + ocs_center = self.ucs.to_ocs(Vec3(center)).vec2 + ocs_angle = self.ucs.to_ocs_angle_rad + if remove_hidden_lines and self.has_text_box: + for start, end in visible_arcs( + center, + radius, + start_angle, + end_angle, + self._text_box, + ): + add_arc(start, end) + else: + add_arc(start_angle, end_angle) + + +class BaseDimensionRenderer: + """Base rendering class for DIMENSION entities.""" + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + self.dimension: Dimension = dimension + self.geometry = self.init_geometry(dimension, ucs) + + # DimStyleOverride object, manages dimension style overriding + self.dim_style: DimStyleOverride + if override: + self.dim_style = override + else: + self.dim_style = DimStyleOverride(dimension) + + # --------------------------------------------- + # GENERAL PROPERTIES + # --------------------------------------------- + self.default_color: int = self.dimension.dxf.color # ACI + self.default_layer: str = self.dimension.dxf.layer + + get = self.dim_style.get + # Overall scaling of DIMENSION entity: + self.dim_scale: float = get("dimscale", 1.0) + if abs(self.dim_scale) < 1e-9: + self.dim_scale = 1.0 + + # Controls drawing of circle or arc center marks and center lines, for + # DIMDIAMETER and DIMRADIUS, the center mark is drawn only if you place + # the dimension line outside the circle or arc. + # 0 = No center marks or lines are drawn + # <0 = Center lines are drawn + # >0 = Center marks are drawn + self.dim_center_marks: int = get("dimcen", 0) + + self.measurement = self.init_measurement(self.default_color, self.dim_scale) + self.dimension_line: DimensionLine = self.init_dimension_line( + self.default_color, self.dim_scale + ) + self.arrows: Arrows = self.init_arrows(self.default_color, self.dim_scale) + # Suppress arrow rendering - only rendering is suppressed (rendering + # effect). + # All placing related calculations are done without this settings. + # Used for multi point linear dimensions to avoid double rendering of + # non arrow ticks. These are ezdxf specific attributes! + self.arrows.suppress1 = self.dim_style.pop("suppress_arrow1", False) + self.arrows.suppress2 = self.dim_style.pop("suppress_arrow2", False) + + self.extension_lines: ExtensionLines = self.init_extension_lines( + self.default_color, self.dim_scale + ) + # tolerances have to be initialized after measurement: + self.tol: Tolerance = self.init_tolerance(self.dim_scale, self.measurement) + + # Update text height + self.measurement.text_height = max( + self.measurement.text_height, self.tol.text_height + ) + + def init_geometry(self, dimension: Dimension, ucs: Optional[UCS] = None): + from ezdxf.layouts import VirtualLayout + + return Geometry(dimension, ucs or PassTroughUCS(), VirtualLayout()) + + def init_tolerance(self, scale: float, measurement: Measurement) -> Tolerance: + return Tolerance( + self.dim_style, + cap_height=measurement.text_height, + width_factor=measurement.text_width_factor, + dim_scale=scale, + ) + + def init_extension_lines(self, color: int, scale: float) -> ExtensionLines: + return ExtensionLines(self.dim_style, color, scale) + + def init_dimension_line(self, color: int, scale: float) -> DimensionLine: + return DimensionLine(self.dim_style, color, scale) + + def init_arrows(self, color: int, scale: float) -> Arrows: + return Arrows(self.dim_style, color, scale) + + def init_measurement(self, color: int, scale: float) -> Measurement: + return LengthMeasurement(self.dim_style, color, scale) + + def init_text_box(self) -> TextBox: + measurement = self.measurement + return TextBox( + center=measurement.text_location, + width=self.total_text_width(), + height=measurement.text_height, + angle=measurement.text_rotation or 0.0, + # The currently used monospaced abstract font, returns a too large + # text width. + # Therefore, the horizontal text gap is ignored at all - yet! + hgap=0.0, + # Arbitrary choice to reduce the too large vertical gap! + vgap=measurement.text_gap * 0.75, + ) + + def get_required_defpoint(self, name: str) -> Vec2: + return get_required_defpoint(self.dimension, name) + + def render(self, block: GenericLayoutType): + # Block entities are located in the OCS defined by the extrusion vector + # of the DIMENSION entity and the z-axis of the OCS point + # 'text_midpoint' (group code 11). + self.geometry.set_layout(block) + # Tolerance requires MTEXT support, switch off rendering of tolerances + # and limits + if not self.geometry.supports_dxf_r2000: + self.tol.disable() + + def total_text_width(self) -> float: + width = 0.0 + text = self.measurement.text + if text: + if self.tol.has_limits: # only limits are displayed + width = self.tol.text_width + else: + width = self.measurement.text_width(text) + if self.tol.has_tolerance: + width += self.tol.text_width + return width + + def default_attributes(self) -> dict[str, Any]: + """Returns default DXF attributes as dict.""" + return { + "layer": self.default_layer, + "color": self.default_color, + } + + def location_override(self, location: UVec, leader=False, relative=False) -> None: + """Set user defined dimension text location. ezdxf defines a user + defined location per definition as 'outside'. + + Args: + location: text midpoint + leader: use leader or not (movement rules) + relative: is location absolute (in UCS) or relative to dimension + line center. + + """ + self.dim_style.set_location(location, leader, relative) + self.measurement.location_override(location, leader, relative) + + def add_line( + self, + start: Vec2, + end: Vec2, + dxfattribs, + remove_hidden_lines=False, + ) -> None: + """Add a LINE entity to the dimension BLOCK. Remove parts of the line + hidden by dimension text if `remove_hidden_lines` is True. + + Args: + start: start point of line + end: end point of line + dxfattribs: additional or overridden DXF attributes + remove_hidden_lines: removes parts of the line hidden by dimension + text if ``True`` + + """ + + attribs = self.default_attributes() + if dxfattribs: + attribs.update(dxfattribs) + self.geometry.add_line(start, end, dxfattribs, remove_hidden_lines) + + def add_arc( + self, + center: Vec2, + radius: float, + start_angle: float, + end_angle: float, + dxfattribs=None, + remove_hidden_lines=False, + ) -> None: + """Add a ARC entity to the geometry layout. Remove parts of the arc + hidden by dimension text if `remove_hidden_lines` is True. + + Args: + center: center of arc + radius: radius of arc + start_angle: start angle in radians + end_angle: end angle in radians + dxfattribs: additional or overridden DXF attributes + remove_hidden_lines: removes parts of the arc hidden by dimension + text if ``True`` + + """ + attribs = self.default_attributes() + if dxfattribs: + attribs.update(dxfattribs) + self.geometry.add_arc( + center, radius, start_angle, end_angle, attribs, remove_hidden_lines + ) + + def add_blockref( + self, + name: str, + insert: Vec2, + rotation: float, + scale: float, + dxfattribs, + ) -> None: + """ + Add block references and standard arrows to the dimension BLOCK. + + Args: + name: block or arrow name + insert: insertion point in UCS + rotation: rotation angle in degrees in UCS (x-axis is 0 degrees) + scale: scaling factor for x- and y-direction + dxfattribs: additional or overridden DXF attributes + + """ + attribs = self.default_attributes() + if dxfattribs: + attribs.update(dxfattribs) + + if name in ARROWS: + # generates automatically BLOCK definitions for arrows if needed + self.geometry.add_arrow_blockref(name, insert, scale, rotation, attribs) + else: + if name is None or not self.geometry.has_block(name): + raise DXFUndefinedBlockError(f'Undefined block: "{name}"') + if scale != 1.0: + attribs["xscale"] = scale + attribs["yscale"] = scale + self.geometry.add_blockref(name, insert, rotation, attribs) + + def add_text(self, text: str, pos: Vec2, rotation: float, dxfattribs) -> None: + """ + Add TEXT (DXF R12) or MTEXT (DXF R2000+) entity to the dimension BLOCK. + + Args: + text: text as string + pos: insertion location in UCS + rotation: rotation angle in degrees in UCS (x-axis is 0 degrees) + dxfattribs: additional or overridden DXF attributes + + """ + geometry = self.geometry + measurement = self.measurement + attribs = self.default_attributes() + attribs["style"] = measurement.text_style_name + attribs["color"] = measurement.text_color + + if geometry.supports_dxf_r2000: # use MTEXT entity + attribs["char_height"] = measurement.text_height + attribs["attachment_point"] = measurement.text_attachment_point + if measurement.text_fill: + attribs["box_fill_scale"] = measurement.text_box_fill_scale + attribs["bg_fill_color"] = measurement.text_fill_color + attribs["bg_fill"] = 3 if measurement.text_fill == 1 else 1 + + if dxfattribs: + attribs.update(dxfattribs) + geometry.add_mtext(text, pos, rotation, dxfattribs=attribs) + else: # use TEXT entity + attribs["height"] = measurement.text_height + if dxfattribs: + attribs.update(dxfattribs) + geometry.add_text(text, pos, rotation, dxfattribs=attribs) + + def add_leader(self, p1: Vec2, p2: Vec2, p3: Vec2): + """ + Add simple leader line from p1 to p2 to p3. + + Args: + p1: target point + p2: first text point + p3: second text point + + """ + # use only color and ignore linetype! + dxfattribs = {"color": self.dimension_line.color} + self.add_line(p1, p2, dxfattribs) + self.add_line(p2, p3, dxfattribs) + + def transform_ucs_to_wcs(self) -> None: + """Transforms dimension definition points into WCS or if required into + OCS. + + Can not be called in __init__(), because inherited classes may be need + unmodified values. + + """ + pass + + def finalize(self) -> None: + self.transform_ucs_to_wcs() + if self.geometry.requires_extrusion: + self.dimension.dxf.extrusion = self.geometry.extrusion + + +def order_leader_points(p1: Vec2, p2: Vec2, p3: Vec2) -> tuple[Vec2, Vec2]: + if (p1 - p2).magnitude > (p1 - p3).magnitude: + return p3, p2 + else: + return p2, p3 + + +def get_center_leader_points( + target_point: Vec2, text_box: TextBox, leg_length: float +) -> tuple[Vec2, Vec2]: + """Returns the leader points of the "leg" for a vertical centered leader.""" + c0, c1, c2, c3 = text_box.corners + # c3-------c2 + # left leg /---x text x---\ right leg + # / c0-------c1 \ + left_center = c0.lerp(c3) + right_center = c1.lerp(c2) + connection_point = left_center + leg_vector = (c0 - c1).normalize(leg_length) + if target_point.distance(left_center) > target_point.distance(right_center): + connection_point = right_center + leg_vector = -leg_vector + # leader line: target_point -> leg_point -> connection_point + # The text gap between the text and the connection point is already included + # in the text_box corners! + # Do not order leader points! + return connection_point + leg_vector, connection_point + + +def get_required_defpoint(dim: Dimension, name: str) -> Vec2: + dxf = dim.dxf + if dxf.hasattr(name): # has to exist, ignore default value! + return Vec2(dxf.get(name)) + raise const.DXFMissingDefinitionPoint(name) + + +def visible_arcs( + center: Vec2, + radius: float, + start_angle: float, + end_angle: float, + box: ConstructionBox, +) -> list[tuple[float, float]]: + """Returns the visible parts of an arc intersecting with a construction box + as (start angle, end angle) tuples. + + Args: + center: center of the arc + radius: radius of the arc + start_angle: start angle of arc in radians + end_angle: end angle of arc in radians + box: construction box which may intersect the arc + + """ + + intersection_angles: list[float] = [] # angles are in the range 0 to 2pi + start_angle %= math.tau + end_angle %= math.tau + arc = ConstructionArc( + center, radius, math.degrees(start_angle), math.degrees(end_angle) + ) + for line in box.border_lines(): + for intersection_point in arc.intersect_line(line): + angle = (intersection_point - center).angle % math.tau + if not intersection_angles: + intersection_angles.append(angle) + # new angle should be different than the last added angle: + elif not math.isclose(intersection_angles[-1], angle): + intersection_angles.append(angle) + # Arc has to intersect the box in exact two locations! + if len(intersection_angles) == 2: + if start_angle > end_angle: # arc passes 0 degrees + intersection_angles = [ + (a if a >= start_angle else a + math.tau) for a in intersection_angles + ] + intersection_angles.sort() + return [ + (start_angle, intersection_angles[0]), + (intersection_angles[1], end_angle), + ] + else: + # Ignore cases where the start- or the end point is inside the box. + # Ignore cases where the box touches the arc in one point. + return [(start_angle, end_angle)] + + +def get_text_style(doc: "Drawing", name: str) -> Textstyle: + assert doc is not None, "valid DXF document required" + get_style = doc.tables.styles.get + try: + style = get_style(name) + except const.DXFTableEntryError: + style = get_style("Standard") + return cast("Textstyle", style) + + +def get_char_height(dim_style: DimStyleOverride, text_style: Textstyle) -> float: + """Unscaled character height defined by text style or DIMTXT.""" + height: float = text_style.dxf.get("height", 0.0) + if height == 0.0: # variable text height (not fixed) + height = dim_style.get("dimtxt", 1.0) + return height + + +def compile_mtext(measurement: Measurement, tol: Tolerance) -> str: + text = measurement.text + if tol.enabled: + text = tol.compile_mtext(text) + return text diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_curved.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_curved.py new file mode 100644 index 0000000..a40f5ba --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_curved.py @@ -0,0 +1,977 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from abc import abstractmethod +import logging +import math + +from ezdxf.math import ( + Vec2, + Vec3, + NULLVEC, + UCS, + decdeg2dms, + arc_angle_span_rad, + xround, +) +from ezdxf.entities import DimStyleOverride, Dimension, DXFEntity +from .dim_base import ( + BaseDimensionRenderer, + get_required_defpoint, + format_text, + apply_dimpost, + Tolerance, + Measurement, + LengthMeasurement, + compile_mtext, + order_leader_points, + get_center_leader_points, +) +from ezdxf.render.arrows import ARROWS, arrow_length +from ezdxf.tools.text import is_upside_down_text_angle +from ezdxf.math import intersection_line_line_2d + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +__all__ = ["AngularDimension", "Angular3PDimension", "ArcLengthDimension"] +logger = logging.getLogger("ezdxf") + +ARC_PREFIX = "( " + + +def has_required_attributes(entity: DXFEntity, attrib_names: list[str]): + has = entity.dxf.hasattr + return all(has(attrib_name) for attrib_name in attrib_names) + + +GRAD = 200.0 / math.pi +DEG = 180.0 / math.pi + + +def format_angular_text( + value: float, + angle_units: int, + dimrnd: Optional[float], + dimdec: int, + dimzin: int, + dimdsep: str, +) -> str: + def decimal_format(_value: float) -> str: + return format_text( + _value, + dimrnd=dimrnd, + dimdec=dimdec, + dimzin=dimzin, + dimdsep=dimdsep, + ) + + def dms_format(_value: float) -> str: + if dimrnd is not None: + _value = xround(_value, dimrnd) + d, m, s = decdeg2dms(_value) + if dimdec > 4: + places = dimdec - 5 + s = round(s, places) + return f"{d:.0f}°{m:.0f}'{decimal_format(s)}\"" + if dimdec > 2: + return f"{d:.0f}°{m:.0f}'{s:.0f}\"" + if dimdec > 0: + return f"{d:.0f}°{m:.0f}'" + return f"{d:.0f}°" + + # angular_unit: + # 0 = Decimal degrees + # 1 = Degrees/minutes/seconds + # 2 = Grad + # 3 = Radians + text = "" + if angle_units == 0: + text = decimal_format(value * DEG) + "°" + elif angle_units == 1: + text = dms_format(value * DEG) + elif angle_units == 2: + text = decimal_format(value * GRAD) + "g" + elif angle_units == 3: + text = decimal_format(value) + "r" + return text + + +_ANGLE_UNITS = [ + DEG, + DEG, + GRAD, + 1.0, +] + + +def to_radians(value: float, dimaunit: int) -> float: + try: + return value / _ANGLE_UNITS[dimaunit] + except IndexError: + return value / DEG + + +class AngularTolerance(Tolerance): + def __init__( + self, + dim_style: DimStyleOverride, + cap_height: float = 1.0, + width_factor: float = 1.0, + dim_scale: float = 1.0, + angle_units: int = 0, + ): + self.angular_units = angle_units + super().__init__(dim_style, cap_height, width_factor, dim_scale) + # Tolerance values are interpreted in dimaunit: + # dimtp 1 means 1 degree for dimaunit = 0 or 1, but 1 radians for + # dimaunit = 3 + # format_text() requires radians as input: + self.update_tolerance_text( + to_radians(self.maximum, angle_units), + to_radians(self.minimum, angle_units), + ) + + def format_text(self, value: float) -> str: + """Rounding and text formatting of tolerance `value`, removes leading + and trailing zeros if necessary. + + """ + return format_angular_text( + value=value, + angle_units=self.angular_units, + dimrnd=None, + dimdec=self.decimal_places, + dimzin=self.suppress_zeros, + dimdsep=self.text_decimal_separator, + ) + + def update_limits(self, measurement: float) -> None: + # measurement is in radians, tolerance values are interpreted in + # dimaunit: dimtp 1 means 1 degree for dimaunit = 0 or 1, + # but 1 radians for dimaunit = 3 + # format_text() requires radians as input: + upper_limit = measurement + to_radians(self.maximum, self.angular_units) + lower_limit = measurement - to_radians(self.minimum, self.angular_units) + self.text_upper = self.format_text(upper_limit) + self.text_lower = self.format_text(lower_limit) + self.text_width = self.get_text_width(self.text_upper, self.text_lower) + + +class AngleMeasurement(Measurement): + def update(self, raw_measurement_value: float) -> None: + self.raw_value = raw_measurement_value + self.value = raw_measurement_value + self.text = self.text_override(raw_measurement_value) + + def format_text(self, value: float) -> str: + text = format_angular_text( + value=value, + angle_units=self.angle_units, + dimrnd=None, + dimdec=self.angular_decimal_places, + dimzin=self.angular_suppress_zeros << 2, # convert to dimzin value + dimdsep=self.decimal_separator, + ) + if self.text_post_process_format: + text = apply_dimpost(text, self.text_post_process_format) + return text + + +def fits_into_arc_span(length: float, radius: float, arc_span: float) -> bool: + required_arc_span: float = length / radius + return arc_span > required_arc_span + + +class _CurvedDimensionLine(BaseDimensionRenderer): + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + super().__init__(dimension, ucs, override) + # Common parameters for all sub-classes: + # Use hidden line detection for dimension line: + # Disable expensive hidden line calculation if possible! + self.remove_hidden_lines_of_dimline = True + self.center_of_arc: Vec2 = self.get_center_of_arc() + self.dim_line_radius: float = self.get_dim_line_radius() + self.ext1_dir: Vec2 = self.get_ext1_dir() + self.start_angle_rad: float = self.ext1_dir.angle + self.ext2_dir: Vec2 = self.get_ext2_dir() + self.end_angle_rad: float = self.ext2_dir.angle + + # Angle between extension lines for all curved dimensions: + # equal to the angle measurement of angular dimensions + self.arc_angle_span_rad: float = arc_angle_span_rad( + self.start_angle_rad, self.end_angle_rad + ) + self.center_angle_rad = ( + self.start_angle_rad + self.arc_angle_span_rad / 2.0 + ) + + # Additional required parameters but calculated later by sub-classes: + self.ext1_start = Vec2() # start of 1st extension line + self.ext2_start = Vec2() # start of 2nd extension line + + # Class specific setup: + self.update_measurement() + if self.tol.has_limits: + self.tol.update_limits(self.measurement.value) + + # Text width and -height is required first, text location and -rotation + # are not valid yet: + self.text_box = self.init_text_box() + + # Place arrows outside? + self.arrows_outside = False + + self.setup_text_and_arrow_fitting() + self.setup_text_location() + + # update text box location and -rotation: + self.text_box.center = self.measurement.text_location + self.text_box.angle = self.measurement.text_rotation + self.geometry.set_text_box(self.text_box) + + # Update final text location in the DIMENSION entity: + self.dimension.dxf.text_midpoint = self.measurement.text_location + + @property + def ocs_center_of_arc(self) -> Vec3: + return self.geometry.ucs.to_ocs(Vec3(self.center_of_arc)) + + @property + def dim_midpoint(self) -> Vec2: + """Return the midpoint of the dimension line.""" + return self.center_of_arc + Vec2.from_angle( + self.center_angle_rad, self.dim_line_radius + ) + + @abstractmethod + def update_measurement(self) -> None: + """Setup measurement text.""" + ... + + @abstractmethod + def get_ext1_dir(self) -> Vec2: + """Return the direction of the 1st extension line == start angle.""" + ... + + @abstractmethod + def get_ext2_dir(self) -> Vec2: + """Return the direction of the 2nd extension line == end angle.""" + ... + + @abstractmethod + def get_center_of_arc(self) -> Vec2: + """Return the center of the arc.""" + ... + + @abstractmethod + def get_dim_line_radius(self) -> float: + """Return the distance from the center of the arc to the dimension line + location + """ + ... + + @abstractmethod + def get_defpoints(self) -> list[Vec2]: + ... + + def transform_ucs_to_wcs(self) -> None: + """Transforms dimension definition points into WCS or if required into + OCS. + """ + + def from_ucs(attr, func): + if dxf.is_supported(attr): + point = dxf.get(attr, NULLVEC) + dxf.set(attr, func(point)) + + dxf = self.dimension.dxf + ucs = self.geometry.ucs + from_ucs("defpoint", ucs.to_wcs) + from_ucs("defpoint2", ucs.to_wcs) + from_ucs("defpoint3", ucs.to_wcs) + from_ucs("defpoint4", ucs.to_wcs) + from_ucs("defpoint5", ucs.to_wcs) + from_ucs("text_midpoint", ucs.to_ocs) + + def default_location(self, shift: float = 0.0) -> Vec2: + radius = ( + self.dim_line_radius + + self.measurement.text_vertical_distance() + + shift + ) + text_radial_dir = Vec2.from_angle(self.center_angle_rad) + return self.center_of_arc + text_radial_dir * radius + + def setup_text_and_arrow_fitting(self) -> None: + # self.text_box.width includes the gaps between text and dimension line + # Is the measurement text without the arrows too wide to fit between the + # extension lines? + self.measurement.is_wide_text = not fits_into_arc_span( + self.text_box.width, self.dim_line_radius, self.arc_angle_span_rad + ) + + required_text_and_arrows_space: float = ( + # The suppression of the arrows is not taken into account: + self.text_box.width + + 2.0 * self.arrows.arrow_size + ) + + # dimatfit: measurement text fitting rule is ignored! + # Place arrows outside? + self.arrows_outside = not fits_into_arc_span( + required_text_and_arrows_space, + self.dim_line_radius, + self.arc_angle_span_rad, + ) + # Place measurement text outside? + self.measurement.text_is_outside = not fits_into_arc_span( + required_text_and_arrows_space * 1.1, # add some extra space + self.dim_line_radius, + self.arc_angle_span_rad, + ) + + if ( + self.measurement.text_is_outside + and self.measurement.user_text_rotation is None + ): + # Intersection of the measurement text with the dimension line is + # not possible: + self.remove_hidden_lines_of_dimline = False + + def setup_text_location(self) -> None: + """Setup geometric text properties (location, rotation) and the TextBox + object. + """ + # dimtix: measurement.force_text_inside is ignored + # dimtih: measurement.text_inside_horizontal is ignored + # dimtoh: measurement.text_outside_horizontal is ignored + + # text radial direction = center -> text + text_radial_dir: Vec2 # text "vertical" direction + measurement = self.measurement + + # determine text location: + at_default_location: bool = measurement.user_location is None + has_text_shifting: bool = bool( + measurement.text_shift_h or measurement.text_shift_v + ) + if at_default_location: + # place text in the "horizontal" center of the dimension line at the + # default location defined by measurement.text_valign (dimtad): + text_radial_dir = Vec2.from_angle(self.center_angle_rad) + shift_text_upwards: float = 0.0 + if measurement.text_is_outside: + # reset vertical alignment to "above" + measurement.text_valign = 1 + if measurement.is_wide_text: + # move measurement text "above" the extension line endings: + shift_text_upwards = self.extension_lines.extension_above + measurement.text_location = self.default_location( + shift=shift_text_upwards + ) + if ( + measurement.text_valign > 0 and not has_text_shifting + ): # not in the center and no text shifting is applied + # disable expensive hidden line calculation + self.remove_hidden_lines_of_dimline = False + else: + # apply dimtmove: measurement.text_movement_rule + user_location = measurement.user_location + assert isinstance(user_location, Vec2) + if measurement.relative_user_location: + user_location += self.dim_midpoint + measurement.text_location = user_location + if measurement.text_movement_rule == 0: + # Moves the dimension line with dimension text and + # aligns the text direction perpendicular to the connection + # line from the arc center to the text center: + self.dim_line_radius = ( + self.center_of_arc - user_location + ).magnitude + # Attributes about the text and arrow fitting have to be + # updated now: + self.setup_text_and_arrow_fitting() + elif measurement.text_movement_rule == 1: + # Adds a leader when dimension text, text direction is + # "horizontal" or user text rotation if given. + # Leader location is defined by dimtad (text_valign): + # "center" - connects to the left or right center of the text + # "below" - add a line below the text + if measurement.user_text_rotation is None: + # override text rotation + measurement.user_text_rotation = 0.0 + measurement.text_is_outside = True # by definition + elif measurement.text_movement_rule == 2: + # Allows text to be moved freely without a leader and + # aligns the text direction perpendicular to the connection + # line from the arc center to the text center: + measurement.text_is_outside = True # by definition + text_radial_dir = ( + measurement.text_location - self.center_of_arc + ).normalize() + + # set text "horizontal": + text_tangential_dir = text_radial_dir.orthogonal(ccw=False) + + if at_default_location and has_text_shifting: + # Apply text relative shift (ezdxf only feature) + if measurement.text_shift_h: + measurement.text_location += ( + text_tangential_dir * measurement.text_shift_h + ) + if measurement.text_shift_v: + measurement.text_location += ( + text_radial_dir * measurement.text_shift_v + ) + + # apply user text rotation; rotation in degrees: + if measurement.user_text_rotation is None: + rotation = text_tangential_dir.angle_deg + else: + rotation = measurement.user_text_rotation + + if not self.geometry.requires_extrusion: + # todo: extrusion vector (0, 0, -1)? + # Practically all DIMENSION entities are 2D entities, + # where OCS == WCS, check WCS text orientation: + wcs_angle = self.geometry.ucs.to_ocs_angle_deg(rotation) + if is_upside_down_text_angle(wcs_angle): + measurement.has_upside_down_correction = True + rotation += 180.0 # apply to UCS rotation! + measurement.text_rotation = rotation + + def get_leader_points(self) -> tuple[Vec2, Vec2]: + # Leader location is defined by dimtad (text_valign): + # "center": + # - connects to the left or right vertical center of the text + # - distance between text and leader line is measurement.text_gap (dimgap) + # and is already included in the text_box corner points + # - length of "leg": arrows.arrow_size + # "below" - add a line below the text + if self.measurement.text_valign == 0: # "center" + return get_center_leader_points( + self.dim_midpoint, self.text_box, self.arrows.arrow_size + ) + else: # "below" + c0, c1, c2, c3 = self.text_box.corners + if self.measurement.has_upside_down_correction: + p1, p2 = c2, c3 + else: + p1, p2 = c0, c1 + return order_leader_points(self.dim_midpoint, p1, p2) + + def render(self, block: GenericLayoutType) -> None: + """Main method to create dimension geometry of basic DXF entities in the + associated BLOCK layout. + + Args: + block: target BLOCK for rendering + + """ + super().render(block) + self.add_extension_lines() + adjust_start_angle, adjust_end_angle = self.add_arrows() + + measurement = self.measurement + if measurement.text: + if self.geometry.supports_dxf_r2000: + text = compile_mtext(measurement, self.tol) + else: + text = measurement.text + self.add_measurement_text( + text, measurement.text_location, measurement.text_rotation + ) + if measurement.has_leader: + p1, p2 = self.get_leader_points() + self.add_leader(self.dim_midpoint, p1, p2) + self.add_dimension_line(adjust_start_angle, adjust_end_angle) + self.geometry.add_defpoints(self.get_defpoints()) + + def add_extension_lines(self) -> None: + ext_lines = self.extension_lines + if not ext_lines.suppress1: + self._add_ext_line( + self.ext1_start, self.ext1_dir, ext_lines.dxfattribs(1) + ) + if not ext_lines.suppress2: + self._add_ext_line( + self.ext2_start, self.ext2_dir, ext_lines.dxfattribs(2) + ) + + def _add_ext_line(self, start: Vec2, direction: Vec2, dxfattribs) -> None: + ext_lines = self.extension_lines + center = self.center_of_arc + radius = self.dim_line_radius + ext_above = ext_lines.extension_above + is_inside = (start - center).magnitude > radius + + if ext_lines.has_fixed_length: + ext_below = ext_lines.length_below + if is_inside: + ext_below, ext_above = ext_above, ext_below + start = center + direction * (radius - ext_below) + else: + offset = ext_lines.offset + if is_inside: + ext_above = -ext_above + offset = -offset + start += direction * offset + end = center + direction * (radius + ext_above) + self.add_line(start, end, dxfattribs=dxfattribs) + + def add_arrows(self) -> tuple[float, float]: + """Add arrows or ticks to dimension. + + Returns: dimension start- and end angle offsets to adjust the + dimension line + + """ + arrows = self.arrows + attribs = arrows.dxfattribs() + radius = self.dim_line_radius + if abs(radius) < 1e-12: + return 0.0, 0.0 + + start = self.center_of_arc + self.ext1_dir * radius + end = self.center_of_arc + self.ext2_dir * radius + angle1 = self.ext1_dir.orthogonal().angle_deg + angle2 = self.ext2_dir.orthogonal().angle_deg + outside = self.arrows_outside + arrow1 = not arrows.suppress1 + arrow2 = not arrows.suppress2 + start_angle_offset = 0.0 + end_angle_offset = 0.0 + if arrows.tick_size > 0.0: # oblique stroke, but double the size + if arrow1: + self.add_blockref( + ARROWS.oblique, + insert=start, + rotation=angle1, + scale=arrows.tick_size * 2.0, + dxfattribs=attribs, + ) + if arrow2: + self.add_blockref( + ARROWS.oblique, + insert=end, + rotation=angle2, + scale=arrows.tick_size * 2.0, + dxfattribs=attribs, + ) + else: + arrow_size = arrows.arrow_size + # Note: The arrow blocks are correct as they are! + # The arrow head is tilted to match the connection point of the + # dimension line (even for datum arrows). + # tilting angle = 1/2 of the arc angle defined by the arrow length + arrow_tilt: float = arrow_size / radius * 0.5 * DEG + start_angle = angle1 + 180.0 + end_angle = angle2 + if outside: + start_angle += 180.0 + end_angle += 180.0 + arrow_tilt = -arrow_tilt + scale = arrow_size + if arrow1: + self.add_blockref( + arrows.arrow1_name, + insert=start, + scale=scale, + rotation=start_angle + arrow_tilt, + dxfattribs=attribs, + ) # reverse + if arrow2: + self.add_blockref( + arrows.arrow2_name, + insert=end, + scale=scale, + rotation=end_angle - arrow_tilt, + dxfattribs=attribs, + ) + if not outside: + # arrows inside extension lines: + # adjust angles for the remaining dimension line + if arrow1: + start_angle_offset = ( + arrow_length(arrows.arrow1_name, arrow_size) / radius + ) + if arrow2: + end_angle_offset = ( + arrow_length(arrows.arrow2_name, arrow_size) / radius + ) + return start_angle_offset, end_angle_offset + + def add_dimension_line( + self, + start_offset: float, + end_offset: float, + ) -> None: + # Start- and end angle adjustments have to be limited between the + # extension lines. + # Negative offset extends the dimension line outside! + start_angle: float = self.start_angle_rad + end_angle: float = self.end_angle_rad + arrows = self.arrows + size = arrows.arrow_size + radius = self.dim_line_radius + max_adjustment: float = abs(self.arc_angle_span_rad) / 2.0 + + if start_offset > max_adjustment: + start_offset = 0.0 + if end_offset > max_adjustment: + end_offset = 0.0 + + self.add_arc( + self.center_of_arc, + radius, + start_angle + start_offset, + end_angle - end_offset, + dxfattribs=self.dimension_line.dxfattribs(), + # hidden line detection if text is not placed outside: + remove_hidden_lines=self.remove_hidden_lines_of_dimline, + ) + if self.arrows_outside and not arrows.has_ticks: + # add arrow extension lines + start_offset, end_offset = arrow_offset_angles( + arrows.arrow1_name, size, radius + ) + self.add_arrow_extension_line( + start_angle - end_offset, + start_angle - start_offset, + ) + start_offset, end_offset = arrow_offset_angles( + arrows.arrow1_name, size, radius + ) + self.add_arrow_extension_line( + end_angle + start_offset, + end_angle + end_offset, + ) + + def add_arrow_extension_line(self, start_angle: float, end_angle: float): + self.add_arc( + self.center_of_arc, + self.dim_line_radius, + start_angle=start_angle, + end_angle=end_angle, + dxfattribs=self.dimension_line.dxfattribs(), + ) + + def add_measurement_text( + self, dim_text: str, pos: Vec2, rotation: float + ) -> None: + """Add measurement text to dimension BLOCK. + + Args: + dim_text: dimension text + pos: text location + rotation: text rotation in degrees + + """ + attribs = self.measurement.dxfattribs() + self.add_text(dim_text, pos=pos, rotation=rotation, dxfattribs=attribs) + + +class _AngularCommonBase(_CurvedDimensionLine): + def init_tolerance( + self, scale: float, measurement: Measurement + ) -> Tolerance: + return AngularTolerance( + self.dim_style, + cap_height=measurement.text_height, + width_factor=measurement.text_width_factor, + dim_scale=scale, + angle_units=measurement.angle_units, + ) + + def init_measurement(self, color: int, scale: float) -> Measurement: + return AngleMeasurement( + self.dim_style, self.default_color, self.dim_scale + ) + + def update_measurement(self) -> None: + self.measurement.update(self.arc_angle_span_rad) + + +class AngularDimension(_AngularCommonBase): + """ + Angular dimension line renderer. The dimension line is defined by two lines. + + Supported render types: + + - default location above + - default location center + - user defined location, text aligned with dimension line + - user defined location horizontal text + + Args: + dimension: DIMENSION entity + ucs: user defined coordinate system + override: dimension style override management object + + """ + + # Required defpoints: + # defpoint = start point of 1st leg (group code 10) + # defpoint4 = end point of 1st leg (group code 15) + # defpoint3 = start point of 2nd leg (group code 14) + # defpoint2 = end point of 2nd leg (group code 13) + # defpoint5 = location of dimension line (group code 16) + + # unsupported or ignored features (at least by BricsCAD): + # dimtih: text inside horizontal + # dimtoh: text outside horizontal + # dimjust: text position horizontal + # dimdle: dimline extension + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + self.leg1_start = get_required_defpoint(dimension, "defpoint") + self.leg1_end = get_required_defpoint(dimension, "defpoint4") + self.leg2_start = get_required_defpoint(dimension, "defpoint3") + self.leg2_end = get_required_defpoint(dimension, "defpoint2") + self.dim_line_location = get_required_defpoint(dimension, "defpoint5") + super().__init__(dimension, ucs, override) + # The extension line parameters depending on the location of the + # dimension line related to the definition point. + # Detect the extension start point. + # Which definition point is closer to the dimension line: + self.ext1_start = detect_closer_defpoint( + direction=self.ext1_dir, + base=self.dim_line_location, + p1=self.leg1_start, + p2=self.leg1_end, + ) + self.ext2_start = detect_closer_defpoint( + direction=self.ext2_dir, + base=self.dim_line_location, + p1=self.leg2_start, + p2=self.leg2_end, + ) + + def get_defpoints(self) -> list[Vec2]: + return [ + self.leg1_start, + self.leg1_end, + self.leg2_start, + self.leg2_end, + self.dim_line_location, + ] + + def get_center_of_arc(self) -> Vec2: + center = intersection_line_line_2d( + (self.leg1_start, self.leg1_end), + (self.leg2_start, self.leg2_end), + ) + if center is None: + logger.warning( + f"Invalid colinear or parallel angle legs found in {self.dimension})" + ) + # This case can not be created by the GUI in BricsCAD, but DXF + # files can contain any shit! + # The interpolation of the end-points is an arbitrary choice and + # maybe not the best choice! + center = self.leg1_end.lerp(self.leg2_end) + return center + + def get_dim_line_radius(self) -> float: + return (self.dim_line_location - self.center_of_arc).magnitude + + def get_ext1_dir(self) -> Vec2: + center = self.center_of_arc + start = ( + self.leg1_end + if self.leg1_start.isclose(center) + else self.leg1_start + ) + return (start - center).normalize() + + def get_ext2_dir(self) -> Vec2: + center = self.center_of_arc + start = ( + self.leg2_end + if self.leg2_start.isclose(center) + else self.leg2_start + ) + return (start - center).normalize() + + +class Angular3PDimension(_AngularCommonBase): + """ + Angular dimension line renderer. The dimension line is defined by three + points. + + Supported render types: + + - default location above + - default location center + - user defined location, text aligned with dimension line + - user defined location horizontal text + + Args: + dimension: DIMENSION entity + ucs: user defined coordinate system + override: dimension style override management object + + """ + + # Required defpoints: + # defpoint = location of dimension line (group code 10) + # defpoint2 = 1st leg (group code 13) + # defpoint3 = 2nd leg (group code 14) + # defpoint4 = center of angle (group code 15) + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + self.dim_line_location = get_required_defpoint(dimension, "defpoint") + self.leg1_start = get_required_defpoint(dimension, "defpoint2") + self.leg2_start = get_required_defpoint(dimension, "defpoint3") + self.center_of_arc = get_required_defpoint(dimension, "defpoint4") + super().__init__(dimension, ucs, override) + self.ext1_start = self.leg1_start + self.ext2_start = self.leg2_start + + def get_defpoints(self) -> list[Vec2]: + return [ + self.dim_line_location, + self.leg1_start, + self.leg2_start, + self.center_of_arc, + ] + + def get_center_of_arc(self) -> Vec2: + return self.center_of_arc + + def get_dim_line_radius(self) -> float: + return (self.dim_line_location - self.center_of_arc).magnitude + + def get_ext1_dir(self) -> Vec2: + return (self.leg1_start - self.center_of_arc).normalize() + + def get_ext2_dir(self) -> Vec2: + return (self.leg2_start - self.center_of_arc).normalize() + + +class ArcLengthMeasurement(LengthMeasurement): + def format_text(self, value: float) -> str: + text = format_text( + value=value, + dimrnd=self.text_round, + dimdec=self.decimal_places, + dimzin=self.suppress_zeros, + dimdsep=self.decimal_separator, + ) + if self.has_arc_length_prefix: + text = ARC_PREFIX + text + if self.text_post_process_format: + text = apply_dimpost(text, self.text_post_process_format) + return text + + +class ArcLengthDimension(_CurvedDimensionLine): + """Arc length dimension line renderer. + Requires DXF R2004. + + Supported render types: + + - default location above + - default location center + - user defined location, text aligned with dimension line + - user defined location horizontal text + + Args: + dimension: DXF entity DIMENSION + ucs: user defined coordinate system + override: dimension style override management object + + """ + + # Required defpoints: + # defpoint = location of dimension line (group code 10) + # defpoint2 = 1st arc point (group code 13) + # defpoint3 = 2nd arc point (group code 14) + # defpoint4 = center of arc (group code 15) + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + self.dim_line_location = get_required_defpoint(dimension, "defpoint") + self.leg1_start = get_required_defpoint(dimension, "defpoint2") + self.leg2_start = get_required_defpoint(dimension, "defpoint3") + self.center_of_arc = get_required_defpoint(dimension, "defpoint4") + self.arc_radius = (self.leg1_start - self.center_of_arc).magnitude + super().__init__(dimension, ucs, override) + self.ext1_start = self.leg1_start + self.ext2_start = self.leg2_start + + def get_defpoints(self) -> list[Vec2]: + return [ + self.dim_line_location, + self.leg1_start, + self.leg2_start, + self.center_of_arc, + ] + + def init_measurement(self, color: int, scale: float) -> Measurement: + return ArcLengthMeasurement( + self.dim_style, self.default_color, self.dim_scale + ) + + def get_center_of_arc(self) -> Vec2: + return self.center_of_arc + + def get_dim_line_radius(self) -> float: + return (self.dim_line_location - self.center_of_arc).magnitude + + def get_ext1_dir(self) -> Vec2: + return (self.leg1_start - self.center_of_arc).normalize() + + def get_ext2_dir(self) -> Vec2: + return (self.leg2_start - self.center_of_arc).normalize() + + def update_measurement(self) -> None: + angle = arc_angle_span_rad(self.start_angle_rad, self.end_angle_rad) + arc_length = angle * self.arc_radius + self.measurement.update(arc_length) + + +def detect_closer_defpoint( + direction: Vec2, base: Vec2, p1: Vec2, p2: Vec2 +) -> Vec2: + # Calculate the projected distance onto the (normalized) direction vector: + d0 = direction.dot(base) + d1 = direction.dot(p1) + d2 = direction.dot(p2) + # Which defpoint is closer to the base point (d0)? + if abs(d1 - d0) <= abs(d2 - d0): + return p1 + return p2 + + +def arrow_offset_angles( + arrow_name: str, size: float, radius: float +) -> tuple[float, float]: + start_offset: float = 0.0 + end_offset: float = size / radius + length = arrow_length(arrow_name, size) + if length > 0.0: + start_offset = length / radius + end_offset *= 2.0 + return start_offset, end_offset diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_diameter.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_diameter.py new file mode 100644 index 0000000..0a53c87 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_diameter.py @@ -0,0 +1,175 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.math import Vec2, UCS +from ezdxf.entities.dimstyleoverride import DimStyleOverride + +from .dim_radius import ( + RadiusDimension, + add_center_mark, + Measurement, + RadiusMeasurement, +) + +if TYPE_CHECKING: + from ezdxf.entities import Dimension + +PREFIX = "Ø" + + +class DiameterDimension(RadiusDimension): + """ + Diameter dimension line renderer. + + Supported render types: + - default location inside, text aligned with diameter dimension line + - default location inside horizontal text + - default location outside, text aligned with diameter dimension line + - default location outside horizontal text + - user defined location, text aligned with diameter dimension line + - user defined location horizontal text + + Args: + dimension: DXF entity DIMENSION + ucs: user defined coordinate system + override: dimension style override management object + + """ + + def init_measurement(self, color: int, scale: float) -> Measurement: + return RadiusMeasurement(self.dim_style, color, scale, PREFIX) + + def _center(self): + return Vec2(self.dimension.dxf.defpoint).lerp( + self.dimension.dxf.defpoint4 + ) + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + # Diameter dimension has the same styles for inside text as radius dimension, except for the + # measurement text + super().__init__(dimension, ucs, override) + self.point_on_circle2 = Vec2(self.dimension.dxf.defpoint) + + def add_text( + self, text: str, pos: Vec2, rotation: float, dxfattribs + ) -> None: + # escape diameter sign + super().add_text(text.replace(PREFIX, "%%c"), pos, rotation, dxfattribs) + + def get_default_text_location(self) -> Vec2: + """Returns default text midpoint based on `text_valign` and + `text_outside`. + """ + measurement = self.measurement + if measurement.text_is_outside and measurement.text_outside_horizontal: + return super().get_default_text_location() + + text_direction = Vec2.from_deg_angle(measurement.text_rotation) + vertical_direction = text_direction.orthogonal(ccw=True) + vertical_distance = measurement.text_vertical_distance() + if measurement.text_is_inside: + text_midpoint = self.center + else: + hdist = ( + self._total_text_width / 2.0 + + self.arrows.arrow_size + + measurement.text_gap + ) + text_midpoint = self.point_on_circle + (self.dim_line_vec * hdist) + return text_midpoint + (vertical_direction * vertical_distance) + + def _add_arrow_1(self, rotate=False): + if not self.arrows.suppress1: + return self.add_arrow(self.point_on_circle, rotate=rotate) + else: + return self.point_on_circle + + def _add_arrow_2(self, rotate=True): + if not self.arrows.suppress2: + return self.add_arrow(self.point_on_circle2, rotate=rotate) + else: + return self.point_on_circle2 + + def render_default_location(self) -> None: + """Create dimension geometry at the default dimension line locations.""" + measurement = self.measurement + if measurement.text_is_outside: + connection_point1 = self._add_arrow_1(rotate=True) + if self.outside_text_force_dimline: + self.add_diameter_dim_line( + connection_point1, self._add_arrow_2() + ) + else: + add_center_mark(self) + if measurement.text_outside_horizontal: + self.add_horiz_ext_line_default(connection_point1) + else: + self.add_radial_ext_line_default(connection_point1) + else: + connection_point1 = self._add_arrow_1(rotate=False) + if measurement.text_movement_rule == 1: + # move text, add leader -> dimline from text to point on circle + self.add_radial_dim_line_from_text( + self.center, connection_point1 + ) + add_center_mark(self) + else: + # dimline from center to point on circle + self.add_diameter_dim_line( + connection_point1, self._add_arrow_2() + ) + + def render_user_location(self) -> None: + """Create dimension geometry at user defined dimension locations.""" + measurement = self.measurement + preserve_outside = measurement.text_is_outside + leader = measurement.text_movement_rule != 2 + if not leader: + # render dimension line like text inside + measurement.text_is_outside = False + # add arrow symbol (block references) + connection_point1 = self._add_arrow_1( + rotate=measurement.text_is_outside + ) + + if measurement.text_is_outside: + if self.outside_text_force_dimline: + self.add_radial_dim_line(self.point_on_circle) + else: + add_center_mark(self) + if measurement.text_outside_horizontal: + self.add_horiz_ext_line_user(connection_point1) + else: + self.add_radial_ext_line_user(connection_point1) + else: + if measurement.text_inside_horizontal: + self.add_horiz_ext_line_user(connection_point1) + else: + if measurement.text_movement_rule == 2: # move text, no leader! + # dimline across the circle + connection_point2 = self._add_arrow_2(rotate=True) + self.add_line( + connection_point1, + connection_point2, + dxfattribs=self.dimension_line.dxfattribs(), + remove_hidden_lines=True, + ) + else: + # move text, add leader -> dimline from text to point on circle + self.add_radial_dim_line_from_text( + measurement.user_location, connection_point1 + ) + add_center_mark(self) + + measurement.text_is_outside = preserve_outside + + def add_diameter_dim_line(self, start: Vec2, end: Vec2) -> None: + """Add diameter dimension line.""" + attribs = self.dimension_line.dxfattribs() + self.add_line(start, end, dxfattribs=attribs, remove_hidden_lines=True) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_linear.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_linear.py new file mode 100644 index 0000000..d52b671 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_linear.py @@ -0,0 +1,649 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, cast, Optional +import math +from ezdxf.math import Vec3, Vec2, UVec, ConstructionRay, UCS +from ezdxf.render.arrows import ARROWS, connection_point +from ezdxf.entities.dimstyleoverride import DimStyleOverride + +from .dim_base import ( + BaseDimensionRenderer, + LengthMeasurement, + Measurement, + compile_mtext, + order_leader_points, +) + +if TYPE_CHECKING: + from ezdxf.entities import Dimension + from ezdxf.eztypes import GenericLayoutType + + +class LinearDimension(BaseDimensionRenderer): + """Linear dimension line renderer, used for horizontal, vertical, rotated + and aligned DIMENSION entities. + + Args: + dimension: DXF entity DIMENSION + ucs: user defined coordinate system + override: dimension style override management object + + """ + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + super().__init__(dimension, ucs, override) + measurement = self.measurement + if measurement.text_movement_rule == 0: + # moves the dimension line with dimension text, this makes no sense + # for ezdxf (just set `base` argument) + measurement.text_movement_rule = 2 + + self.oblique_angle: float = self.dimension.get_dxf_attrib( + "oblique_angle", 90 + ) + self.dim_line_angle: float = self.dimension.get_dxf_attrib("angle", 0) + self.dim_line_angle_rad: float = math.radians(self.dim_line_angle) + self.ext_line_angle: float = self.dim_line_angle + self.oblique_angle + self.ext_line_angle_rad: float = math.radians(self.ext_line_angle) + + # text is aligned to dimension line + measurement.text_rotation = self.dim_line_angle + # text above extension line, is always aligned with extension lines + if measurement.text_halign in (3, 4): + measurement.text_rotation = self.ext_line_angle + + self.ext1_line_start = Vec2(self.dimension.dxf.defpoint2) + self.ext2_line_start = Vec2(self.dimension.dxf.defpoint3) + + ext1_ray = ConstructionRay( + self.ext1_line_start, angle=self.ext_line_angle_rad + ) + ext2_ray = ConstructionRay( + self.ext2_line_start, angle=self.ext_line_angle_rad + ) + dim_line_ray = ConstructionRay( + self.dimension.dxf.defpoint, angle=self.dim_line_angle_rad + ) + + self.dim_line_start: Vec2 = dim_line_ray.intersect(ext1_ray) + self.dim_line_end: Vec2 = dim_line_ray.intersect(ext2_ray) + self.dim_line_center: Vec2 = self.dim_line_start.lerp(self.dim_line_end) + + if self.dim_line_start == self.dim_line_end: + self.dim_line_vec = Vec2.from_angle(self.dim_line_angle_rad) + else: + self.dim_line_vec = ( + self.dim_line_end - self.dim_line_start + ).normalize() + + # set dimension defpoint to expected location - 3D vertex required! + self.dimension.dxf.defpoint = Vec3(self.dim_line_start) + + raw_measurement = (self.dim_line_end - self.dim_line_start).magnitude + measurement.update(raw_measurement) + + # only for linear dimension in multi point mode + self.multi_point_mode = self.dim_style.pop("multi_point_mode", False) + + # 1 .. move wide text up + # 2 .. move wide text down + # None .. ignore + self.move_wide_text: Optional[bool] = self.dim_style.pop( + "move_wide_text", None + ) + + # actual text width in drawing units + self._total_text_width: float = 0 + + # arrows + self.required_arrows_space: float = ( + 2 * self.arrows.arrow_size + measurement.text_gap + ) + self.arrows_outside: bool = self.required_arrows_space > raw_measurement + + # text location and rotation + if measurement.text: + # text width and required space + self._total_text_width = self.total_text_width() + if self.tol.has_limits: + # limits show the upper and lower limit of the measurement as + # stacked values and with the size of tolerances + self.tol.update_limits(self.measurement.value) + + if self.multi_point_mode: + # ezdxf has total control about vertical text position in multi + # point mode + measurement.text_vertical_position = 0.0 + + if ( + measurement.text_valign == 0 + and abs(measurement.text_vertical_position) < 0.7 + ): + # vertical centered text needs also space for arrows + required_space = ( + self._total_text_width + 2 * self.arrows.arrow_size + ) + else: + required_space = self._total_text_width + measurement.is_wide_text = required_space > raw_measurement + + if not measurement.force_text_inside: + # place text outside if wide text and not forced inside + measurement.text_is_outside = measurement.is_wide_text + elif measurement.is_wide_text and measurement.text_halign < 3: + # center wide text horizontal + measurement.text_halign = 0 + + # use relative text shift to move wide text up or down in multi + # point mode + if ( + self.multi_point_mode + and measurement.is_wide_text + and self.move_wide_text + ): + shift_value = measurement.text_height + measurement.text_gap + if self.move_wide_text == 1: # move text up + measurement.text_shift_v = shift_value + if ( + measurement.vertical_placement == -1 + ): # text below dimension line + # shift again + measurement.text_shift_v += shift_value + elif self.move_wide_text == 2: # move text down + measurement.text_shift_v = -shift_value + if ( + measurement.vertical_placement == 1 + ): # text above dimension line + # shift again + measurement.text_shift_v -= shift_value + + # get final text location - no altering after this line + measurement.text_location = self.get_text_location() + + # text rotation override + rotation: float = measurement.text_rotation + if measurement.user_text_rotation is not None: + rotation = measurement.user_text_rotation + elif ( + measurement.text_is_outside + and measurement.text_outside_horizontal + ): + rotation = 0.0 + elif ( + measurement.text_is_inside + and measurement.text_inside_horizontal + ): + rotation = 0.0 + measurement.text_rotation = rotation + + text_box = self.init_text_box() + self.geometry.set_text_box(text_box) + if measurement.has_leader: + p1, p2, *_ = text_box.corners + self.leader1, self.leader2 = order_leader_points( + self.dim_line_center, p1, p2 + ) + # not exact what BricsCAD (AutoCAD) expect, but close enough + self.dimension.dxf.text_midpoint = self.leader1 + else: + # write final text location into DIMENSION entity + self.dimension.dxf.text_midpoint = measurement.text_location + + def init_measurement(self, color: int, scale: float) -> Measurement: + return LengthMeasurement( + self.dim_style, self.default_color, self.dim_scale + ) + + def render(self, block: GenericLayoutType) -> None: + """Main method to create dimension geometry of basic DXF entities in the + associated BLOCK layout. + + Args: + block: target BLOCK for rendering + + """ + # call required to setup some requirements + super().render(block) + + # add extension line 1 + ext_lines = self.extension_lines + measurement = self.measurement + if not ext_lines.suppress1: + above_ext_line1 = measurement.text_halign == 3 + start, end = self.extension_line_points( + self.ext1_line_start, self.dim_line_start, above_ext_line1 + ) + self.add_line(start, end, dxfattribs=ext_lines.dxfattribs(1)) + + # add extension line 2 + if not ext_lines.suppress2: + above_ext_line2 = measurement.text_halign == 4 + start, end = self.extension_line_points( + self.ext2_line_start, self.dim_line_end, above_ext_line2 + ) + self.add_line(start, end, dxfattribs=ext_lines.dxfattribs(2)) + + # add arrow symbols (block references), also adjust dimension line start + # and end point + dim_line_start, dim_line_end = self.add_arrows() + + # add dimension line + self.add_dimension_line(dim_line_start, dim_line_end) + + # add measurement text as last entity to see text fill properly + if measurement.text: + if self.geometry.supports_dxf_r2000: + text = compile_mtext(measurement, self.tol) + else: + text = measurement.text + self.add_measurement_text( + text, measurement.text_location, measurement.text_rotation + ) + if measurement.has_leader: + self.add_leader( + self.dim_line_center, self.leader1, self.leader2 + ) + + # add POINT entities at definition points + self.geometry.add_defpoints( + [self.dim_line_start, self.ext1_line_start, self.ext2_line_start] + ) + + def get_text_location(self) -> Vec2: + """Get text midpoint in UCS from user defined location or default text + location. + + """ + # apply relative text shift as user location override without leader + measurement = self.measurement + if measurement.has_relative_text_movement: + location = self.default_text_location() + location = measurement.apply_text_shift( + location, measurement.text_rotation + ) + self.location_override(location) + + if measurement.user_location is not None: + location = measurement.user_location + if measurement.relative_user_location: + location = self.dim_line_center + location + # define overridden text location as outside + measurement.text_is_outside = True + else: + location = self.default_text_location() + + return location + + def default_text_location(self) -> Vec2: + """Calculate default text location in UCS based on `self.text_halign`, + `self.text_valign` and `self.text_outside` + + """ + start = self.dim_line_start + end = self.dim_line_end + measurement = self.measurement + halign = measurement.text_halign + # positions the text above and aligned with the first/second extension line + ext_lines = self.extension_lines + if halign in (3, 4): + # horizontal location + hdist = measurement.text_gap + measurement.text_height / 2.0 + hvec = self.dim_line_vec * hdist + location = (start if halign == 3 else end) - hvec + # vertical location + vdist = ext_lines.extension_above + self._total_text_width / 2.0 + location += Vec2.from_deg_angle(self.ext_line_angle).normalize( + vdist + ) + else: + # relocate outside text to center location + if measurement.text_is_outside: + halign = 0 + + if halign == 0: + location = self.dim_line_center # center of dimension line + else: + hdist = ( + self._total_text_width / 2.0 + + self.arrows.arrow_size + + measurement.text_gap + ) + if ( + halign == 1 + ): # positions the text next to the first extension line + location = start + (self.dim_line_vec * hdist) + else: # positions the text next to the second extension line + location = end - (self.dim_line_vec * hdist) + + if measurement.text_is_outside: # move text up + vdist = ( + ext_lines.extension_above + + measurement.text_gap + + measurement.text_height / 2.0 + ) + else: + # distance from extension line to text midpoint + vdist = measurement.text_vertical_distance() + location += self.dim_line_vec.orthogonal().normalize(vdist) + + return location + + def add_arrows(self) -> tuple[Vec2, Vec2]: + """ + Add arrows or ticks to dimension. + + Returns: dimension line connection points + + """ + arrows = self.arrows + attribs = arrows.dxfattribs() + start = self.dim_line_start + end = self.dim_line_end + outside = self.arrows_outside + arrow1 = not arrows.suppress1 + arrow2 = not arrows.suppress2 + + if arrows.tick_size > 0.0: # oblique stroke, but double the size + if arrow1: + self.add_blockref( + ARROWS.oblique, + insert=start, + rotation=self.dim_line_angle, + scale=arrows.tick_size * 2.0, + dxfattribs=attribs, + ) + if arrow2: + self.add_blockref( + ARROWS.oblique, + insert=end, + rotation=self.dim_line_angle, + scale=arrows.tick_size * 2.0, + dxfattribs=attribs, + ) + else: + scale = arrows.arrow_size + start_angle = self.dim_line_angle + 180.0 + end_angle = self.dim_line_angle + if outside: + start_angle, end_angle = end_angle, start_angle + + if arrow1: + self.add_blockref( + arrows.arrow1_name, + insert=start, + scale=scale, + rotation=start_angle, + dxfattribs=attribs, + ) # reverse + if arrow2: + self.add_blockref( + arrows.arrow2_name, + insert=end, + scale=scale, + rotation=end_angle, + dxfattribs=attribs, + ) + + if not outside: + # arrows inside extension lines: adjust connection points for + # the remaining dimension line + if arrow1: + start = connection_point( + arrows.arrow1_name, start, scale, start_angle + ) + if arrow2: + end = connection_point( + arrows.arrow2_name, end, scale, end_angle + ) + else: + # add additional extension lines to arrows placed outside of + # dimension extension lines + self.add_arrow_extension_lines() + return start, end + + def add_arrow_extension_lines(self): + """Add extension lines to arrows placed outside of dimension extension + lines. Called by `self.add_arrows()`. + + """ + + def has_arrow_extension(name: str) -> bool: + return ( + (name is not None) + and (name in ARROWS) + and (name not in ARROWS.ORIGIN_ZERO) + ) + + attribs = self.dimension_line.dxfattribs() + arrows = self.arrows + start = self.dim_line_start + end = self.dim_line_end + arrow_size = arrows.arrow_size + + if not arrows.suppress1 and has_arrow_extension(arrows.arrow1_name): + self.add_line( + start - self.dim_line_vec * arrow_size, + start - self.dim_line_vec * (2 * arrow_size), + dxfattribs=attribs, + ) + + if not arrows.suppress2 and has_arrow_extension(arrows.arrow2_name): + self.add_line( + end + self.dim_line_vec * arrow_size, + end + self.dim_line_vec * (2 * arrow_size), + dxfattribs=attribs, + ) + + def add_measurement_text( + self, dim_text: str, pos: Vec2, rotation: float + ) -> None: + """Add measurement text to dimension BLOCK. + + Args: + dim_text: dimension text + pos: text location + rotation: text rotation in degrees + + """ + self.add_text(dim_text, pos, rotation, dict()) + + def add_dimension_line(self, start: Vec2, end: Vec2) -> None: + """Add dimension line to dimension BLOCK, adds extension DIMDLE if + required, and uses DIMSD1 or DIMSD2 to suppress first or second part of + dimension line. Removes line parts hidden by dimension text. + + Args: + start: dimension line start + end: dimension line end + + """ + dim_line = self.dimension_line + arrows = self.arrows + extension = self.dim_line_vec * dim_line.extension + ticks = arrows.has_ticks + if ticks or ARROWS.has_extension_line(arrows.arrow1_name): + start = start - extension + if ticks or ARROWS.has_extension_line(arrows.arrow2_name): + end = end + extension + + attribs = dim_line.dxfattribs() + + if dim_line.suppress1 or dim_line.suppress2: + # TODO: results not as expected, but good enough + # center should take into account text location + center = start.lerp(end) + if not dim_line.suppress1: + self.add_line( + start, center, dxfattribs=attribs, remove_hidden_lines=True + ) + if not dim_line.suppress2: + self.add_line( + center, end, dxfattribs=attribs, remove_hidden_lines=True + ) + else: + self.add_line( + start, end, dxfattribs=attribs, remove_hidden_lines=True + ) + + def extension_line_points( + self, start: Vec2, end: Vec2, text_above_extline=False + ) -> tuple[Vec2, Vec2]: + """Adjust start and end point of extension line by dimension variables + DIMEXE, DIMEXO, DIMEXFIX, DIMEXLEN. + + Args: + start: start point of extension line (measurement point) + end: end point at dimension line + text_above_extline: True if text is above and aligned with extension line + + Returns: adjusted start and end point + + """ + if start == end: + direction = Vec2.from_deg_angle(self.ext_line_angle) + else: + direction = (end - start).normalize() + if self.extension_lines.has_fixed_length: + start = end - (direction * self.extension_lines.length_below) + else: + start = start + direction * self.extension_lines.offset + extension = self.extension_lines.extension_above + if text_above_extline: + extension += self._total_text_width + end = end + direction * extension + return start, end + + def transform_ucs_to_wcs(self) -> None: + """Transforms dimension definition points into WCS or if required into + OCS. + + Can not be called in __init__(), because inherited classes may be need + unmodified values. + + """ + + def from_ucs(attr, func): + point = self.dimension.get_dxf_attrib(attr) + self.dimension.set_dxf_attrib(attr, func(point)) + + ucs = self.geometry.ucs + from_ucs("defpoint", ucs.to_wcs) + from_ucs("defpoint2", ucs.to_wcs) + from_ucs("defpoint3", ucs.to_wcs) + from_ucs("text_midpoint", ucs.to_ocs) + self.dimension.dxf.angle = ucs.to_ocs_angle_deg( + self.dimension.dxf.angle + ) + + +CAN_SUPPRESS_ARROW1 = { + ARROWS.dot, + ARROWS.dot_small, + ARROWS.dot_blank, + ARROWS.origin_indicator, + ARROWS.origin_indicator_2, + ARROWS.dot_smallblank, + ARROWS.none, + ARROWS.oblique, + ARROWS.box_filled, + ARROWS.box, + ARROWS.integral, + ARROWS.architectural_tick, +} + + +def sort_projected_points( + points: Iterable[UVec], angle: float = 0 +) -> list[Vec2]: + direction = Vec2.from_deg_angle(angle) + projected_vectors = [(direction.project(Vec2(p)), p) for p in points] + return [p for projection, p in sorted(projected_vectors)] + + +def multi_point_linear_dimension( + layout: GenericLayoutType, + base: UVec, + points: Iterable[UVec], + angle: float = 0, + ucs: Optional[UCS] = None, + avoid_double_rendering: bool = True, + dimstyle: str = "EZDXF", + override: Optional[dict] = None, + dxfattribs=None, + discard=False, +) -> None: + """Creates multiple DIMENSION entities for each point pair in `points`. + Measurement points will be sorted by appearance on the dimension line + vector. + + Args: + layout: target layout (model space, paper space or block) + base: base point, any point on the dimension line vector will do + points: iterable of measurement points + angle: dimension line rotation in degrees (0=horizontal, 90=vertical) + ucs: user defined coordinate system + avoid_double_rendering: removes first extension line and arrow of + following DIMENSION entity + dimstyle: dimension style name + override: dictionary of overridden dimension style attributes + dxfattribs: DXF attributes for DIMENSION entities + discard: discard rendering result for friendly CAD applications like + BricsCAD to get a native and likely better rendering result. + (does not work with AutoCAD) + + """ + + def suppress_arrow1(dimstyle_override) -> bool: + arrow_name1, arrow_name2 = dimstyle_override.get_arrow_names() + if (arrow_name1 is None) or (arrow_name1 in CAN_SUPPRESS_ARROW1): + return True + else: + return False + + points = sort_projected_points(points, angle) + base = Vec2(base) + override = override or {} + override["dimtix"] = 1 # do not place measurement text outside + override["dimtvp"] = 0 # do not place measurement text outside + override["multi_point_mode"] = True + # 1 .. move wide text up; 2 .. move wide text down; None .. ignore + # moving text down, looks best combined with text fill bg: DIMTFILL = 1 + move_wide_text = 1 + _suppress_arrow1 = False + first_run = True + + for p1, p2 in zip(points[:-1], points[1:]): + _override = dict(override) + _override["move_wide_text"] = move_wide_text + if avoid_double_rendering and not first_run: + _override["dimse1"] = 1 + _override["suppress_arrow1"] = _suppress_arrow1 + + style = layout.add_linear_dim( + Vec3(base), + Vec3(p1), + Vec3(p2), + angle=angle, + dimstyle=dimstyle, + override=_override, + dxfattribs=dxfattribs, + ) + if first_run: + _suppress_arrow1 = suppress_arrow1(style) + + renderer = cast(LinearDimension, style.render(ucs, discard=discard)) + if renderer.measurement.is_wide_text: + # after wide text switch moving direction + if move_wide_text == 1: + move_wide_text = 2 + else: + move_wide_text = 1 + else: # reset to move text up + move_wide_text = 1 + first_run = False diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_ordinate.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_ordinate.py new file mode 100644 index 0000000..e534d69 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_ordinate.py @@ -0,0 +1,209 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +import logging +import math + +from ezdxf.math import Vec2, UCS, NULLVEC +from ezdxf.lldxf import const +from ezdxf.entities import DimStyleOverride, Dimension +from .dim_base import ( + BaseDimensionRenderer, + get_required_defpoint, + compile_mtext, +) + +if TYPE_CHECKING: + from ezdxf.eztypes import GenericLayoutType + +__all__ = ["OrdinateDimension"] +logger = logging.getLogger("ezdxf") + + +class OrdinateDimension(BaseDimensionRenderer): + # Required defpoints: + # defpoint = origin (group code 10) + # defpoint2 = feature location (group code 13) + # defpoint3 = end of leader (group code 14) + # user text location is ignored (group code 11) and replaced by default + # location calculated by the ezdxf renderer: + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + # The local coordinate system is defined by origin and the + # horizontal_direction in OCS: + self.origin_ocs: Vec2 = get_required_defpoint(dimension, "defpoint") + self.feature_location_ocs: Vec2 = get_required_defpoint( + dimension, "defpoint2" + ) + self.end_of_leader_ocs: Vec2 = get_required_defpoint( + dimension, "defpoint3" + ) + # Horizontal direction in clockwise orientation, see DXF reference + # for group code 51: + self.horizontal_dir = -dimension.dxf.get("horizontal_direction", 0.0) + self.rotation = math.radians(self.horizontal_dir) + self.local_x_axis = Vec2.from_angle(self.rotation) + self.local_y_axis = self.local_x_axis.orthogonal() + self.x_type = bool( # x-type is set! + dimension.dxf.get("dimtype", 0) & const.DIM_ORDINATE_TYPE + ) + super().__init__(dimension, ucs, override) + + # Measurement directions can be opposite to local x- or y-axis + self.leader_vec_ocs = self.end_of_leader_ocs - self.feature_location_ocs + leader_x_vec = self.local_x_axis.project(self.leader_vec_ocs) + leader_y_vec = self.local_y_axis.project(self.leader_vec_ocs) + try: + self.measurement_direction: Vec2 = leader_x_vec.normalize() + except ZeroDivisionError: + self.measurement_direction = Vec2(1, 0) + try: + self.measurement_orthogonal: Vec2 = leader_y_vec.normalize() + except ZeroDivisionError: + self.measurement_orthogonal = Vec2(0, 1) + + if not self.x_type: + self.measurement_direction, self.measurement_orthogonal = ( + self.measurement_orthogonal, + self.measurement_direction, + ) + + self.update_measurement() + if self.tol.has_limits: + self.tol.update_limits(self.measurement.value) + + # Text width and -height is required first, text location and -rotation + # are not valid yet: + self.text_box = self.init_text_box() + + # Set text location and rotation: + self.measurement.text_location = self.get_default_text_location() + self.measurement.text_rotation = self.get_default_text_rotation() + + # Update text box location and -rotation: + self.text_box.center = self.measurement.text_location + self.text_box.angle = self.measurement.text_rotation + self.geometry.set_text_box(self.text_box) + + # Update final text location in the DIMENSION entity: + self.dimension.dxf.text_midpoint = self.measurement.text_location + + def get_default_text_location(self) -> Vec2: + if self.x_type: + text_vertical_shifting_dir = -self.local_x_axis + else: + text_vertical_shifting_dir = self.local_y_axis + + # user text location is not supported and ignored: + return ( + self.end_of_leader_ocs + + self.measurement_orthogonal * (self.text_box.width * 0.5) + + text_vertical_shifting_dir + * self.measurement.text_vertical_distance() + ) + + def get_default_text_rotation(self) -> float: + # user text rotation is not supported and ignored: + return (90.0 if self.x_type else 0.0) + self.horizontal_dir + + def update_measurement(self) -> None: + feature_location_vec: Vec2 = self.feature_location_ocs - self.origin_ocs + # ordinate measurement is always absolute: + self.measurement.update( + self.local_x_axis.project(feature_location_vec).magnitude + if self.x_type + else self.local_y_axis.project(feature_location_vec).magnitude + ) + + def get_defpoints(self) -> list[Vec2]: + return [ + self.origin_ocs, + self.feature_location_ocs, + self.end_of_leader_ocs, + ] + + def transform_ucs_to_wcs(self) -> None: + """Transforms dimension definition points into WCS or if required into + OCS. + """ + + def from_ucs(attr, func): + point = dxf.get(attr, NULLVEC) + dxf.set(attr, func(point)) + + dxf = self.dimension.dxf + ucs = self.geometry.ucs + from_ucs("defpoint", ucs.to_wcs) + from_ucs("defpoint2", ucs.to_wcs) + from_ucs("defpoint3", ucs.to_wcs) + from_ucs("text_midpoint", ucs.to_ocs) + + # Horizontal direction in clockwise orientation, see DXF reference + # for group code 51: + dxf.horizontal_direction = -ucs.to_ocs_angle_deg(self.horizontal_dir) + + def render(self, block: GenericLayoutType) -> None: + """Main method to create dimension geometry of basic DXF entities in the + associated BLOCK layout. + + Args: + block: target BLOCK for rendering + + """ + super().render(block) + self.add_ordinate_leader() + measurement = self.measurement + if measurement.text: + if self.geometry.supports_dxf_r2000: + text = compile_mtext(measurement, self.tol) + else: + text = measurement.text + self.add_measurement_text( + text, measurement.text_location, measurement.text_rotation + ) + self.geometry.add_defpoints(self.get_defpoints()) + + def add_ordinate_leader(self) -> None: + # DXF attributes from first extension line not from dimension line! + attribs = self.extension_lines.dxfattribs(1) + # The ordinate leader is normal to the measurement direction. + # leader direction and text direction: + direction = self.measurement_orthogonal + leg_size = self.arrows.arrow_size * 2.0 + # /---1---TEXT + # x----0----/ + # d0 = distance from feature location (x) to 1st upward junction + d0 = direction.project(self.leader_vec_ocs).magnitude - 2.0 * leg_size + + start0 = ( + self.feature_location_ocs + direction * self.extension_lines.offset + ) + end0 = self.feature_location_ocs + direction * max(leg_size, d0) + start1 = self.end_of_leader_ocs - direction * leg_size + end1 = self.end_of_leader_ocs + if self.measurement.vertical_placement != 0: + end1 += direction * self.text_box.width + + self.add_line(start0, end0, dxfattribs=attribs) + self.add_line(end0, start1, dxfattribs=attribs) + self.add_line(start1, end1, dxfattribs=attribs) + + def add_measurement_text( + self, dim_text: str, pos: Vec2, rotation: float + ) -> None: + """Add measurement text to dimension BLOCK. + + Args: + dim_text: dimension text + pos: text location + rotation: text rotation in degrees + + """ + attribs = self.measurement.dxfattribs() + self.add_text(dim_text, pos=pos, rotation=rotation, dxfattribs=attribs) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dim_radius.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_radius.py new file mode 100644 index 0000000..a347bfe --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dim_radius.py @@ -0,0 +1,488 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional + +from ezdxf.math import Vec2, UCS, UVec +from ezdxf.tools import normalize_text_angle +from ezdxf.render.arrows import ARROWS, connection_point +from ezdxf.entities.dimstyleoverride import DimStyleOverride +from ezdxf.lldxf.const import DXFInternalEzdxfError +from ezdxf.render.dim_base import ( + BaseDimensionRenderer, + Measurement, + LengthMeasurement, + compile_mtext, +) + +if TYPE_CHECKING: + from ezdxf.entities import Dimension + from ezdxf.eztypes import GenericLayoutType + + +class RadiusMeasurement(LengthMeasurement): + def __init__( + self, dim_style: DimStyleOverride, color: int, scale: float, prefix: str + ): + super().__init__(dim_style, color, scale) + self.text_prefix = prefix + + def text_override(self, measurement: float) -> str: + text = super().text_override(measurement) + if text and text[0] != self.text_prefix: + text = self.text_prefix + text + return text + + +class RadiusDimension(BaseDimensionRenderer): + """ + Radial dimension line renderer. + + Supported render types: + - default location inside, text aligned with radial dimension line + - default location inside horizontal text + - default location outside, text aligned with radial dimension line + - default location outside horizontal text + - user defined location, text aligned with radial dimension line + - user defined location horizontal text + + Args: + dimension: DXF entity DIMENSION + ucs: user defined coordinate system + override: dimension style override management object + + """ + + # Super class of DiameterDimension + def _center(self): + return Vec2(self.dimension.dxf.defpoint) + + def __init__( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + super().__init__(dimension, ucs, override) + dimtype = self.dimension.dimtype + measurement = self.measurement + if dimtype == 3: + self.is_diameter_dim = True + elif dimtype == 4: + self.is_radius_dim = True + else: + raise DXFInternalEzdxfError(f"Invalid dimension type {dimtype}") + + self.center: Vec2 = self._center() # override in diameter dimension + self.point_on_circle: Vec2 = Vec2(self.dimension.dxf.defpoint4) + # modify parameters for special scenarios + if measurement.user_location is None: + if ( + measurement.text_is_inside + and measurement.text_inside_horizontal + and measurement.text_movement_rule == 1 + ): # move text, add leader + # use algorithm for user define dimension line location + measurement.user_location = self.center.lerp( + self.point_on_circle + ) + measurement.text_valign = 0 # text vertical centered + + direction = self.point_on_circle - self.center + self.dim_line_vec = direction.normalize() + self.dim_line_angle = self.dim_line_vec.angle_deg + self.radius = direction.magnitude + # get_measurement() works for radius and diameter dimension + measurement.update(self.dimension.get_measurement()) + self.outside_default_distance = self.radius + 2 * self.arrows.arrow_size + self.outside_default_defpoint = self.center + ( + self.dim_line_vec * self.outside_default_distance + ) + self.outside_text_force_dimline = bool(self.dim_style.get("dimtofl", 1)) + # final dimension text (without limits or tolerance) + + # default location is outside, if not forced to be inside + measurement.text_is_outside = not measurement.force_text_inside + # text_outside: user defined location, overrides default location + if measurement.user_location is not None: + measurement.text_is_outside = self.is_location_outside( + measurement.user_location + ) + + self._total_text_width: float = 0.0 + if measurement.text: + # text width and required space + self._total_text_width = self.total_text_width() + if self.tol.has_limits: + # limits show the upper and lower limit of the measurement as + # stacked values and with the size of tolerances + self.tol.update_limits(measurement.value) + + # default rotation is angle of dimension line, from center to point on circle. + rotation = self.dim_line_angle + if measurement.text_is_outside and measurement.text_outside_horizontal: + rotation = 0.0 + elif measurement.text_is_inside and measurement.text_inside_horizontal: + rotation = 0.0 + + # final absolute text rotation (x-axis=0) + measurement.text_rotation = normalize_text_angle( + rotation, fix_upside_down=True + ) + + # final text location + measurement.text_location = self.get_text_location() + self.geometry.set_text_box(self.init_text_box()) + # write final text location into DIMENSION entity + if measurement.user_location: + self.dimension.dxf.text_midpoint = measurement.user_location + # default locations + elif ( + measurement.text_is_outside and measurement.text_outside_horizontal + ): + self.dimension.dxf.text_midpoint = self.outside_default_defpoint + else: + self.dimension.dxf.text_midpoint = measurement.text_location + + def init_measurement(self, color: int, scale: float) -> Measurement: + return RadiusMeasurement(self.dim_style, color, scale, "R") + + def get_text_location(self) -> Vec2: + """Returns text midpoint from user defined location or default text + location. + """ + if self.measurement.user_location is not None: + return self.get_user_defined_text_location() + else: + return self.get_default_text_location() + + def get_default_text_location(self) -> Vec2: + """Returns default text midpoint based on `text_valign` and + `text_outside` + """ + measurement = self.measurement + if measurement.text_is_outside and measurement.text_outside_horizontal: + hdist = self._total_text_width / 2.0 + if ( + measurement.vertical_placement == 0 + ): # shift text horizontal if vertical centered + hdist += self.arrows.arrow_size + angle = self.dim_line_angle % 360.0 # normalize 0 .. 360 + if 90.0 < angle <= 270.0: + hdist = -hdist + return self.outside_default_defpoint + Vec2( + (hdist, measurement.text_vertical_distance()) + ) + + text_direction = Vec2.from_deg_angle(measurement.text_rotation) + vertical_direction = text_direction.orthogonal(ccw=True) + vertical_distance = measurement.text_vertical_distance() + if measurement.text_is_inside: + hdist = (self.radius - self.arrows.arrow_size) / 2.0 + text_midpoint = self.center + (self.dim_line_vec * hdist) + else: + hdist = ( + self._total_text_width / 2.0 + + self.arrows.arrow_size + + measurement.text_gap + ) + text_midpoint = self.point_on_circle + (self.dim_line_vec * hdist) + return text_midpoint + (vertical_direction * vertical_distance) + + def get_user_defined_text_location(self) -> Vec2: + """Returns text midpoint for user defined dimension location.""" + measurement = self.measurement + assert isinstance(measurement.user_location, Vec2) + text_outside_horiz = ( + measurement.text_is_outside and measurement.text_outside_horizontal + ) + text_inside_horiz = ( + measurement.text_is_inside and measurement.text_inside_horizontal + ) + if text_outside_horiz or text_inside_horiz: + hdist = self._total_text_width / 2.0 + if ( + measurement.vertical_placement == 0 + ): # shift text horizontal if vertical centered + hdist += self.arrows.arrow_size + if measurement.user_location.x <= self.point_on_circle.x: + hdist = -hdist + vdist = measurement.text_vertical_distance() + return measurement.user_location + Vec2((hdist, vdist)) + else: + text_normal_vec = Vec2.from_deg_angle( + measurement.text_rotation + ).orthogonal() + return ( + measurement.user_location + + text_normal_vec * measurement.text_vertical_distance() + ) + + def is_location_outside(self, location: Vec2) -> bool: + radius = (location - self.center).magnitude + return radius > self.radius + + def render(self, block: GenericLayoutType) -> None: + """Create dimension geometry of basic DXF entities in the associated + BLOCK layout. + """ + # call required to setup some requirements + super().render(block) + measurement = self.measurement + if not self.dimension_line.suppress1: + if measurement.user_location is not None: + self.render_user_location() + else: + self.render_default_location() + + # add measurement text as last entity to see text fill properly + if measurement.text: + if self.geometry.supports_dxf_r2000: + text = compile_mtext(self.measurement, self.tol) + else: + text = measurement.text + self.add_measurement_text( + text, measurement.text_location, measurement.text_rotation + ) + + # add POINT entities at definition points + self.geometry.add_defpoints([self.center, self.point_on_circle]) + + def render_default_location(self) -> None: + """Create dimension geometry at the default dimension line locations.""" + measurement = self.measurement + if not self.arrows.suppress1: + arrow_connection_point = self.add_arrow( + self.point_on_circle, rotate=measurement.text_is_outside + ) + else: + arrow_connection_point = self.point_on_circle + + if measurement.text_is_outside: + if self.outside_text_force_dimline: + self.add_radial_dim_line(self.point_on_circle) + else: + add_center_mark(self) + if measurement.text_outside_horizontal: + self.add_horiz_ext_line_default(arrow_connection_point) + else: + self.add_radial_ext_line_default(arrow_connection_point) + else: + if measurement.text_movement_rule == 1: + # move text, add leader -> dimline from text to point on circle + self.add_radial_dim_line_from_text( + self.center.lerp(self.point_on_circle), + arrow_connection_point, + ) + add_center_mark(self) + else: + # dimline from center to point on circle + self.add_radial_dim_line(arrow_connection_point) + + def render_user_location(self) -> None: + """Create dimension geometry at user defined dimension locations.""" + measurement = self.measurement + preserve_outside = measurement.text_is_outside + leader = measurement.text_movement_rule != 2 + if not leader: + measurement.text_is_outside = ( + False # render dimension line like text inside + ) + # add arrow symbol (block references) + if not self.arrows.suppress1: + arrow_connection_point = self.add_arrow( + self.point_on_circle, rotate=measurement.text_is_outside + ) + else: + arrow_connection_point = self.point_on_circle + if measurement.text_is_outside: + if self.outside_text_force_dimline: + self.add_radial_dim_line(self.point_on_circle) + else: + add_center_mark(self) + if measurement.text_outside_horizontal: + self.add_horiz_ext_line_user(arrow_connection_point) + else: + self.add_radial_ext_line_user(arrow_connection_point) + else: + if measurement.text_inside_horizontal: + self.add_horiz_ext_line_user(arrow_connection_point) + else: + if measurement.text_movement_rule == 2: # move text, no leader! + # dimline from center to point on circle + self.add_radial_dim_line(arrow_connection_point) + else: + # move text, add leader -> dimline from text to point on circle + self.add_radial_dim_line_from_text( + measurement.user_location, arrow_connection_point + ) + add_center_mark(self) + + measurement.text_is_outside = preserve_outside + + def add_arrow(self, location, rotate: bool) -> Vec2: + """Add arrow or tick to dimension line, returns dimension line connection point.""" + arrows = self.arrows + attribs = arrows.dxfattribs() + + arrow_name = arrows.arrow1_name + if arrows.tick_size > 0.0: # oblique stroke, but double the size + self.add_blockref( + ARROWS.oblique, + insert=location, + rotation=self.dim_line_angle, + scale=arrows.tick_size * 2.0, + dxfattribs=attribs, + ) + else: + scale = arrows.arrow_size + angle = self.dim_line_angle + if rotate: + angle += 180.0 + + self.add_blockref( + arrow_name, + insert=location, + scale=scale, + rotation=angle, + dxfattribs=attribs, + ) + location = connection_point(arrow_name, location, scale, angle) + return location + + def add_radial_dim_line(self, end: UVec) -> None: + """Add radial dimension line.""" + attribs = self.dimension_line.dxfattribs() + self.add_line( + self.center, end, dxfattribs=attribs, remove_hidden_lines=True + ) + + def add_radial_dim_line_from_text(self, start, end: UVec) -> None: + """Add radial dimension line, starting point at the measurement text.""" + attribs = self.dimension_line.dxfattribs() + hshift = self._total_text_width / 2 + if self.measurement.vertical_placement != 0: # not center + hshift = -hshift + self.add_line( + start + self.dim_line_vec * hshift, + end, + dxfattribs=attribs, + remove_hidden_lines=False, + ) + + def add_horiz_ext_line_default(self, start: UVec) -> None: + """Add horizontal outside extension line from start for default + locations. + """ + attribs = self.dimension_line.dxfattribs() + self.add_line(start, self.outside_default_defpoint, dxfattribs=attribs) + if self.measurement.vertical_placement == 0: + hdist = self.arrows.arrow_size + else: + hdist = self._total_text_width + angle = self.dim_line_angle % 360.0 # normalize 0 .. 360 + if 90 < angle <= 270: + hdist = -hdist + end = self.outside_default_defpoint + Vec2((hdist, 0)) + self.add_line(self.outside_default_defpoint, end, dxfattribs=attribs) + + def add_horiz_ext_line_user(self, start: UVec) -> None: + """Add horizontal extension line from start for user defined locations.""" + measurement = self.measurement + assert isinstance(measurement.user_location, Vec2) + attribs = self.dimension_line.dxfattribs() + self.add_line(start, measurement.user_location, dxfattribs=attribs) + if measurement.vertical_placement == 0: + hdist = self.arrows.arrow_size + else: + hdist = self._total_text_width + if measurement.user_location.x <= self.point_on_circle.x: + hdist = -hdist + end = measurement.user_location + Vec2((hdist, 0)) + self.add_line(measurement.user_location, end, dxfattribs=attribs) + + def add_radial_ext_line_default(self, start: UVec) -> None: + """Add radial outside extension line from start for default locations.""" + attribs = self.dimension_line.dxfattribs() + length = self.measurement.text_gap + self._total_text_width + end = start + self.dim_line_vec * length + self.add_line(start, end, dxfattribs=attribs, remove_hidden_lines=True) + + def add_radial_ext_line_user(self, start: UVec) -> None: + """Add radial outside extension line from start for user defined location.""" + attribs = self.dimension_line.dxfattribs() + length = self._total_text_width / 2.0 + if self.measurement.vertical_placement == 0: + length = -length + end = self.measurement.user_location + self.dim_line_vec * length + self.add_line(start, end, dxfattribs=attribs) + + def add_measurement_text( + self, dim_text: str, pos: Vec2, rotation: float + ) -> None: + """Add measurement text to dimension BLOCK.""" + attribs = self.measurement.dxfattribs() + self.add_text(dim_text, pos=pos, rotation=rotation, dxfattribs=attribs) + + def transform_ucs_to_wcs(self) -> None: + """ + Transforms dimension definition points into WCS or if required into OCS. + + Can not be called in __init__(), because inherited classes may be need unmodified values. + + """ + + def from_ucs(attr, func): + point = self.dimension.get_dxf_attrib(attr) + self.dimension.set_dxf_attrib(attr, func(point)) + + ucs = self.geometry.ucs + from_ucs("defpoint", ucs.to_wcs) + from_ucs("defpoint4", ucs.to_wcs) + from_ucs("text_midpoint", ucs.to_ocs) + + +def add_center_mark(dim: RadiusDimension) -> None: + """Add center mark/lines to radius and diameter dimensions. + + Args: + dim: RadiusDimension or DiameterDimension renderer + """ + dim_type = dim.dimension.dimtype + if dim_type == 4: # Radius Dimension + radius = dim.measurement.raw_value + elif dim_type == 3: # Diameter Dimension + radius = dim.measurement.raw_value / 2.0 + else: + raise TypeError(f"Invalid dimension type: {dim_type}") + + mark_size = dim.dim_style.get("dimcen", 0) + if mark_size == 0: + return + + center_lines = False + if mark_size < 0: + mark_size = abs(mark_size) + center_lines = True + center = Vec2(dim.center) + + # draw center mark + mark_x_vec = Vec2((mark_size, 0)) + mark_y_vec = Vec2((0, mark_size)) + # use only color and ignore linetype! + dxfattribs = {"color": dim.dimension_line.color} + dim.add_line(center - mark_x_vec, center + mark_x_vec, dxfattribs) + dim.add_line(center - mark_y_vec, center + mark_y_vec, dxfattribs) + + if center_lines: + size = mark_size + radius + if size < 2 * mark_size: + return # not enough space for center lines + start_x_vec = mark_x_vec * 2 + start_y_vec = mark_y_vec * 2 + end_x_vec = Vec2((size, 0)) + end_y_vec = Vec2((0, size)) + dim.add_line(center + start_x_vec, center + end_x_vec, dxfattribs) + dim.add_line(center - start_x_vec, center - end_x_vec, dxfattribs) + dim.add_line(center + start_y_vec, center + end_y_vec, dxfattribs) + dim.add_line(center - start_y_vec, center - end_y_vec, dxfattribs) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/dimension.py b/.venv/lib/python3.12/site-packages/ezdxf/render/dimension.py new file mode 100644 index 0000000..d9b3c6f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/dimension.py @@ -0,0 +1,118 @@ +# Copyright (c) 2018-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional + +from ezdxf.math import UCS +from ezdxf.lldxf.const import DXFValueError +from ezdxf.entities.dimstyleoverride import DimStyleOverride + +from .dim_base import BaseDimensionRenderer +from .dim_curved import AngularDimension, Angular3PDimension, ArcLengthDimension +from .dim_diameter import DiameterDimension +from .dim_linear import LinearDimension +from .dim_ordinate import OrdinateDimension +from .dim_radius import RadiusDimension + + +if TYPE_CHECKING: + from ezdxf.entities import Dimension + + +class DimensionRenderer: + def dispatch( + self, override: DimStyleOverride, ucs: Optional[UCS] = None + ) -> BaseDimensionRenderer: + dimension = override.dimension + dim_type = dimension.dimtype + dxf_type = dimension.dxftype() + if dxf_type == "ARC_DIMENSION": + return self.arc_length(dimension, ucs, override) + elif dxf_type == "LARGE_RADIAL_DIMENSION": + return self.large_radial(dimension, ucs, override) + elif dim_type in (0, 1): + return self.linear(dimension, ucs, override) + elif dim_type == 2: + return self.angular(dimension, ucs, override) + elif dim_type == 3: + return self.diameter(dimension, ucs, override) + elif dim_type == 4: + return self.radius(dimension, ucs, override) + elif dim_type == 5: + return self.angular3p(dimension, ucs, override) + elif dim_type == 6: + return self.ordinate(dimension, ucs, override) + else: + raise DXFValueError(f"Unknown DIMENSION type: {dim_type}") + + def linear( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for linear dimension lines: horizontal, vertical and rotated""" + return LinearDimension(dimension, ucs, override) + + def angular( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for angular dimension defined by two lines.""" + return AngularDimension(dimension, ucs, override) + + def diameter( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for diameter dimension""" + return DiameterDimension(dimension, ucs, override) + + def radius( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for radius dimension""" + return RadiusDimension(dimension, ucs, override) + + def large_radial( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for large radial dimension""" + raise NotImplementedError() + + def angular3p( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for angular dimension defined by three points.""" + return Angular3PDimension(dimension, ucs, override) + + def ordinate( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for ordinate dimension.""" + return OrdinateDimension(dimension, ucs, override) + + def arc_length( + self, + dimension: Dimension, + ucs: Optional[UCS] = None, + override: Optional[DimStyleOverride] = None, + ): + """Call renderer for arc length dimension.""" + return ArcLengthDimension(dimension, ucs, override) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/forms.py b/.venv/lib/python3.12/site-packages/ezdxf/render/forms.py new file mode 100644 index 0000000..2ec4a2b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/forms.py @@ -0,0 +1,1434 @@ +# Copyright (c) 2018-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence, Iterator, Callable, Optional +import math +from enum import IntEnum +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + Matrix44, + global_bspline_interpolation, + EulerSpiral, + arc_angle_span_rad, + NULLVEC, + Z_AXIS, + X_AXIS, + UCS, + intersection_ray_ray_3d, +) +from ezdxf.render.mesh import MeshVertexMerger, MeshTransformer + + +__all__ = [ + "circle", + "ellipse", + "euler_spiral", + "square", + "box", + "open_arrow", + "arrow2", + "ngon", + "star", + "gear", + "turtle", + "translate", + "rotate", + "scale", + "close_polygon", + "helix", + "cube", + "extrude", + "extrude_twist_scale", + "sweep", + "cylinder", + "cylinder_2p", + "from_profiles_linear", + "from_profiles_spline", + "spline_interpolation", + "spline_interpolated_profiles", + "cone", + "cone_2p", + "rotation_form", + "sphere", + "torus", + "reference_frame_z", + "reference_frame_ext", + "make_next_reference_frame", +] + + +def circle( + count: int, radius: float = 1, elevation: float = 0, close: bool = False +) -> Iterable[Vec3]: + """Create polygon vertices for a `circle `_ + with the given `radius` and approximated by `count` vertices, `elevation` + is the z-axis for all vertices. + + Args: + count: count of polygon vertices + radius: circle radius + elevation: z-axis for all vertices + close: yields first vertex also as last vertex if ``True``. + + Returns: + vertices in counter-clockwise orientation as :class:`~ezdxf.math.Vec3` + objects + + """ + radius = float(radius) + delta = math.tau / count + alpha = 0.0 + for index in range(count): + x = math.cos(alpha) * radius + y = math.sin(alpha) * radius + yield Vec3(x, y, elevation) + alpha += delta + + if close: + yield Vec3(radius, 0, elevation) + + +def ellipse( + count: int, + rx: float = 1, + ry: float = 1, + start_param: float = 0, + end_param: float = math.tau, + elevation: float = 0, +) -> Iterable[Vec3]: + """Create polygon vertices for an `ellipse `_ + with given `rx` as x-axis radius and `ry` as y-axis radius approximated by + `count` vertices, `elevation` is the z-axis for all vertices. + The ellipse goes from `start_param` to `end_param` in counter clockwise + orientation. + + Args: + count: count of polygon vertices + rx: ellipse x-axis radius + ry: ellipse y-axis radius + start_param: start of ellipse in range [0, 2π] + end_param: end of ellipse in range [0, 2π] + elevation: z-axis for all vertices + + Returns: + vertices in counter clockwise orientation as :class:`~ezdxf.math.Vec3` + objects + + """ + rx = float(rx) + ry = float(ry) + start_param = float(start_param) + end_param = float(end_param) + count = int(count) + delta = (end_param - start_param) / (count - 1) + cos = math.cos + sin = math.sin + for param in range(count): + alpha = start_param + param * delta + yield Vec3(cos(alpha) * rx, sin(alpha) * ry, elevation) + + +def euler_spiral( + count: int, length: float = 1, curvature: float = 1, elevation: float = 0 +) -> Iterable[Vec3]: + """Create polygon vertices for an `euler spiral `_ + of a given `length` and radius of curvature. This is a parametric curve, + which always starts at the origin (0, 0). + + Args: + count: count of polygon vertices + length: length of curve in drawing units + curvature: radius of curvature + elevation: z-axis for all vertices + + Returns: + vertices as :class:`~ezdxf.math.Vec3` objects + + """ + spiral = EulerSpiral(curvature=curvature) + for vertex in spiral.approximate(length, count - 1): + yield vertex.replace(z=elevation) + + +def square(size: float = 1.0, center=False) -> tuple[Vec3, Vec3, Vec3, Vec3]: + """Returns 4 vertices for a square with a side length of the given `size`. + The center of the square in (0, 0) if `center` is ``True`` otherwise + the lower left corner is (0, 0), upper right corner is (`size`, `size`). + """ + if center: + a = size / 2.0 + return Vec3(-a, -a), Vec3(a, -a), Vec3(a, a), Vec3(-a, a) + else: + return Vec3(0, 0), Vec3(size, 0), Vec3(size, size), Vec3(0, size) + + +def box( + sx: float = 1.0, sy: float = 1.0, center=False +) -> tuple[Vec3, Vec3, Vec3, Vec3]: + """Returns 4 vertices for a box with a width of `sx` by and a height of + `sy`. The center of the box in (0, 0) if `center` is ``True`` otherwise + the lower left corner is (0, 0), upper right corner is (`sx`, `sy`). + """ + if center: + a = sx / 2.0 + b = sy / 2.0 + return Vec3(-a, -b), Vec3(a, -b), Vec3(a, b), Vec3(-a, b) + else: + return Vec3(0, 0), Vec3(sx, 0), Vec3(sx, sy), Vec3(0, sy) + + +def open_arrow(size: float = 1.0, angle: float = 30.0) -> tuple[Vec3, Vec3, Vec3]: + """Returns 3 vertices for an open arrow `<` with a length of the given + `size`, argument `angle` defines the enclosing angle in degrees. + Vertex order: upward end vertex, tip (0, 0) , downward end vertex (counter- + clockwise order) + + Args: + size: length of arrow + angle: enclosing angle in degrees + + """ + h = math.sin(math.radians(angle / 2.0)) * size + return Vec3(-size, h), Vec3(0, 0), Vec3(-size, -h) + + +def arrow2( + size: float = 1.0, angle: float = 30.0, beta: float = 45.0 +) -> tuple[Vec3, Vec3, Vec3, Vec3]: + """Returns 4 vertices for an arrow with a length of the given `size`, and + an enclosing `angle` in degrees and a slanted back side defined by angle + `beta`:: + + **** + **** * + **** * + **** angle X******************** + **** * +beta + **** * + **** + + **** + **** * + **** * + **** angle X*************** + **** * -beta + **** * + **** + + Vertex order: upward end vertex, tip (0, 0), downward end vertex, bottom + vertex `X` (anti clockwise order). + + Bottom vertex `X` is also the connection point to a continuation line. + + Args: + size: length of arrow + angle: enclosing angle in degrees + beta: angle if back side in degrees + + """ + h = math.sin(math.radians(angle / 2.0)) * size + back_step = math.tan(math.radians(beta)) * h + return ( + Vec3(-size, h), + Vec3(0, 0), + Vec3(-size, -h), + Vec3(-size + back_step, 0), + ) + + +def ngon( + count: int, + length: Optional[float] = None, + radius: Optional[float] = None, + rotation: float = 0.0, + elevation: float = 0.0, + close: bool = False, +) -> Iterable[Vec3]: + """Returns the corner vertices of a `regular polygon `_. + The polygon size is determined by the edge `length` or the circum `radius` + argument. If both are given `length` has the higher priority. + + Args: + count: count of polygon corners >= 3 + length: length of polygon side + radius: circum radius + rotation: rotation angle in radians + elevation: z-axis for all vertices + close: yields first vertex also as last vertex if ``True``. + + Returns: + vertices as :class:`~ezdxf.math.Vec3` objects + + """ + if count < 3: + raise ValueError("Argument `count` has to be greater than 2.") + if length is not None: + if length <= 0.0: + raise ValueError("Argument `length` has to be greater than 0.") + radius = length / 2.0 / math.sin(math.pi / count) + elif radius is not None: + if radius <= 0.0: + raise ValueError("Argument `radius` has to be greater than 0.") + else: + raise ValueError("Argument `length` or `radius` required.") + + delta = math.tau / count + angle = rotation + first = None + cos = math.cos + sin = math.sin + for _ in range(count): + v = Vec3(radius * cos(angle), radius * sin(angle), elevation) + if first is None: + first = v + yield v + angle += delta + + if close: + yield first + + +def star( + count: int, + r1: float, + r2: float, + rotation: float = 0.0, + elevation: float = 0.0, + close: bool = False, +) -> Iterable[Vec3]: + """Returns the corner vertices for a `star shape `_. + + The shape has `count` spikes, `r1` defines the radius of the "outer" + vertices and `r2` defines the radius of the "inner" vertices, + but this does not mean that `r1` has to be greater than `r2`. + + Args: + count: spike count >= 3 + r1: radius 1 + r2: radius 2 + rotation: rotation angle in radians + elevation: z-axis for all vertices + close: yields first vertex also as last vertex if ``True``. + + Returns: + vertices as :class:`~ezdxf.math.Vec3` objects + + """ + if count < 3: + raise ValueError("Argument `count` has to be greater than 2.") + if r1 <= 0.0: + raise ValueError("Argument `r1` has to be greater than 0.") + if r2 <= 0.0: + raise ValueError("Argument `r2` has to be greater than 0.") + + corners1 = ngon( + count, radius=r1, rotation=rotation, elevation=elevation, close=False + ) + corners2 = ngon( + count, + radius=r2, + rotation=math.pi / count + rotation, + elevation=elevation, + close=False, + ) + first = None + for s1, s2 in zip(corners1, corners2): + if first is None: + first = s1 + yield s1 + yield s2 + + if close: + yield first + + +class _Gear(IntEnum): + TOP_START = 0 + TOP_END = 1 + BOTTOM_START = 2 + BOTTOM_END = 3 + + +def gear( + count: int, + top_width: float, + bottom_width: float, + height: float, + outside_radius: float, + elevation: float = 0, + close: bool = False, +) -> Iterable[Vec3]: + """Returns the corner vertices of a `gear shape `_ + (cogwheel). + + .. warning:: + + This function does not create correct gears for mechanical engineering! + + Args: + count: teeth count >= 3 + top_width: teeth width at outside radius + bottom_width: teeth width at base radius + height: teeth height; base radius = outside radius - height + outside_radius: outside radius + elevation: z-axis for all vertices + close: yields first vertex also as last vertex if True. + + Returns: + vertices in counter clockwise orientation as :class:`~ezdxf.math.Vec3` + objects + + """ + if count < 3: + raise ValueError("Argument `count` has to be greater than 2.") + if outside_radius <= 0.0: + raise ValueError("Argument `radius` has to be greater than 0.") + if top_width <= 0.0: + raise ValueError("Argument `width` has to be greater than 0.") + if bottom_width <= 0.0: + raise ValueError("Argument `width` has to be greater than 0.") + if height <= 0.0: + raise ValueError("Argument `height` has to be greater than 0.") + if height >= outside_radius: + raise ValueError("Argument `height` has to be smaller than `radius`") + + base_radius = outside_radius - height + alpha_top = math.asin(top_width / 2.0 / outside_radius) # angle at tooth top + alpha_bottom = math.asin(bottom_width / 2.0 / base_radius) # angle at tooth bottom + alpha_difference = ( + alpha_bottom - alpha_top + ) / 2.0 # alpha difference at start and end of tooth + beta = (math.tau - count * alpha_bottom) / count + angle = -alpha_top / 2.0 # center of first tooth is in x-axis direction + state = _Gear.TOP_START + first = None + cos = math.cos + sin = math.sin + for _ in range(4 * count): + if state == _Gear.TOP_START or state == _Gear.TOP_END: + radius = outside_radius + else: + radius = base_radius + v = Vec3(radius * cos(angle), radius * sin(angle), elevation) + + if state == _Gear.TOP_START: + angle += alpha_top + elif state == _Gear.TOP_END: + angle += alpha_difference + elif state == _Gear.BOTTOM_START: + angle += beta + elif state == _Gear.BOTTOM_END: + angle += alpha_difference + + if first is None: + first = v + yield v + + state += 1 # type: ignore + if state > _Gear.BOTTOM_END: + state = _Gear.TOP_START + + if close: + yield first + + +def turtle(commands: str, start=Vec2(0, 0), angle: float = 0) -> Iterator[Vec2]: + """Returns the 2D vertices of a polyline created by turtle-graphic like + commands: + + - ```` - go units forward in current direction and yield vertex + - ``r`` - turn right in degrees, a missing angle is 90 deg + - ``l`` - turn left in degrees, a missing angle is 90 deg + - ``@,`` - go relative , and yield vertex + + The command string ``"10 l 10 l 10"`` returns the 4 corner vertices of a + square with a side length of 10 drawing units. + + Args: + commands: command string, commands are separated by spaces + start: starting point, default is (0, 0) + angle: starting direction, default is 0 deg + + """ + + cursor = start + yield cursor + for cmd in commands.split(" "): + cmd = cmd.strip() + if cmd[0] == "l": + if len(cmd) == 1: + angle += 90 + else: + angle += float(cmd[1:]) + elif cmd[0] == "r": + if len(cmd) == 1: + angle -= 90 + else: + angle -= float(cmd[1:]) + elif cmd[0] == "@": + x, y = cmd[1:].split(",") + cursor += Vec2(float(x), float(y)) + yield cursor + else: + cursor += Vec2.from_deg_angle(angle, float(cmd)) + yield cursor + + +def translate(vertices: Iterable[UVec], vec: UVec = (0, 0, 0)) -> Iterable[Vec3]: + """Translate `vertices` along `vec`, faster than a Matrix44 transformation. + + Args: + vertices: iterable of vertices + vec: translation vector + + Returns: yields transformed vertices + + """ + _vec = Vec3(vec) + for p in vertices: + yield _vec + p + + +def rotate( + vertices: Iterable[UVec], angle: float = 0.0, deg: bool = True +) -> Iterable[Vec3]: + """Rotate `vertices` about to z-axis at to origin (0, 0), faster than a + Matrix44 transformation. + + Args: + vertices: iterable of vertices + angle: rotation angle + deg: True if angle in degrees, False if angle in radians + + Returns: yields transformed vertices + + """ + if deg: + return (Vec3(v).rotate_deg(angle) for v in vertices) + else: + return (Vec3(v).rotate(angle) for v in vertices) + + +def scale(vertices: Iterable[UVec], scaling=(1.0, 1.0, 1.0)) -> Iterable[Vec3]: + """Scale `vertices` around the origin (0, 0), faster than a Matrix44 + transformation. + + Args: + vertices: iterable of vertices + scaling: scale factors as tuple of floats for x-, y- and z-axis + + Returns: yields scaled vertices + + """ + sx, sy, sz = scaling + for v in Vec3.generate(vertices): + yield Vec3(v.x * sx, v.y * sy, v.z * sz) + + +def close_polygon( + vertices: Iterable[Vec3], rel_tol: float = 1e-9, abs_tol: float = 1e-12 +) -> list[Vec3]: + """Returns list of :class:`~ezdxf.math.Vec3`, where the first vertex is + equal to the last vertex. + """ + polygon: list[Vec3] = list(vertices) + if not polygon[0].isclose(polygon[-1], rel_tol=rel_tol, abs_tol=abs_tol): + polygon.append(polygon[0]) + return polygon + + +def helix( + radius: float, + pitch: float, + turns: float, + resolution: int = 16, + ccw=True, +) -> Iterator[Vec3]: + """Yields the vertices of a `helix `_. + The center of the helix is always (0, 0), a positive `pitch` value + creates a helix along the +z-axis, a negative value along the -z-axis. + + Args: + radius: helix radius + pitch: the height of one complete helix turn + turns: count of turns + resolution: vertices per turn + ccw: creates a counter-clockwise turning (right-handed) helix if ``True`` + + """ + step: float = 1.0 / max(resolution, 1) + if not ccw: + step = -step + total_step_count = int(turns / abs(step)) + for index in range(total_step_count + 1): + t = step * index + angle = t * math.tau + x = math.cos(angle) * radius + y = math.sin(angle) * radius + yield Vec3(x, y, abs(t) * pitch) + + +# 8 corner vertices +_cube_vertices = [ + Vec3(0, 0, 0), + Vec3(1, 0, 0), + Vec3(1, 1, 0), + Vec3(0, 1, 0), + Vec3(0, 0, 1), + Vec3(1, 0, 1), + Vec3(1, 1, 1), + Vec3(0, 1, 1), +] + +# 8 corner vertices, 'mass' center in (0, 0, 0) +_cube0_vertices = [ + Vec3(-0.5, -0.5, -0.5), + Vec3(+0.5, -0.5, -0.5), + Vec3(+0.5, +0.5, -0.5), + Vec3(-0.5, +0.5, -0.5), + Vec3(-0.5, -0.5, +0.5), + Vec3(+0.5, -0.5, +0.5), + Vec3(+0.5, +0.5, +0.5), + Vec3(-0.5, +0.5, +0.5), +] + +# 6 cube faces +cube_faces = [ + [0, 3, 2, 1], # bottom, normal = -Z + [1, 2, 6, 5], # right, normal = +X + [3, 7, 6, 2], # back, normal = +Y + [0, 4, 7, 3], # left, normal = -X + [0, 1, 5, 4], # front, normal = -Y + [4, 5, 6, 7], # top, normal = +Z +] + + +def cube(center: bool = True) -> MeshTransformer: + """Create a `cube `_ as + :class:`~ezdxf.render.MeshTransformer` object. + + Args: + center: 'mass' center of cube, ``(0, 0, 0)`` if ``True``, else first + corner at ``(0, 0, 0)`` + + Returns: :class:`~ezdxf.render.MeshTransformer` + + """ + mesh = MeshTransformer() + vertices = _cube0_vertices if center else _cube_vertices + mesh.add_mesh(vertices=vertices, faces=cube_faces) # type: ignore + return mesh + + +def extrude( + profile: Iterable[UVec], path: Iterable[UVec], close=True, caps=False +) -> MeshTransformer: + """Extrude a `profile` polygon along a `path` polyline, the vertices of + `profile` should be in counter-clockwise order. + The sweeping profile will not be rotated at extrusion! + + Args: + profile: sweeping profile as list of (x, y, z) tuples in + counter-clockwise order + path: extrusion path as list of (x, y, z) tuples + close: close profile polygon if ``True`` + caps: close hull with top- and bottom faces (ngons) + + Returns: :class:`~ezdxf.render.MeshTransformer` + + """ + mesh = MeshVertexMerger() + sweeping_profile = Vec3.list(profile) + if close: + sweeping_profile = close_polygon(sweeping_profile) + + extrusion_path = Vec3.list(path) + if caps: + mesh.add_face(reversed(sweeping_profile[:-1])) + start_point = extrusion_path[0] + for target_point in extrusion_path[1:]: + translation_vector = target_point - start_point + target_profile = [vec + translation_vector for vec in sweeping_profile] + for face in _quad_connection_faces(sweeping_profile, target_profile): + mesh.add_face(face) + sweeping_profile = target_profile + start_point = target_point + if caps: + mesh.add_face(sweeping_profile[:-1]) + return MeshTransformer.from_builder(mesh) + + +def _partial_path_factors(path: list[Vec3]) -> list[float]: + partial_lengths = [v1.distance(v2) for v1, v2 in zip(path, path[1:])] + total_length = sum(partial_lengths) + factors = [0.0] + partial_sum = 0.0 + for pl in partial_lengths: + partial_sum += pl + factors.append(partial_sum / total_length) + return factors + + +def _divide_path_into_steps(path: Sequence[Vec3], max_step_size: float) -> list[Vec3]: + new_path: list[Vec3] = [path[0]] + for v0, v1 in zip(path, path[1:]): + segment_vec = v1 - v0 + length = segment_vec.magnitude + if length > max_step_size: + parts = int(math.ceil(length / max_step_size)) + step = segment_vec * (1.0 / parts) + for _ in range(parts - 1): + v0 += step + new_path.append(v0) + new_path.append(v1) + return new_path + + +def extrude_twist_scale( + profile: Iterable[UVec], + path: Iterable[UVec], + *, + twist: float = 0.0, + scale: float = 1.0, + step_size: float = 1.0, + close=True, + caps=False, + quads=True, +) -> MeshTransformer: + """Extrude a `profile` polygon along a `path` polyline, the vertices of + `profile` should be in counter-clockwise order. + This implementation can scale and twist the sweeping profile along the + extrusion path. The `path` segment points are fix points, the + `max_step_size` is used to create intermediate profiles between this + fix points. The `max_step_size` is adapted for each + segment to create equally spaced distances. + The twist angle is the rotation angle in radians and the scale `argument` + defines the scale factor of the final profile. + The twist angle and scaling factor of the intermediate profiles will be + linear interpolated between the start and end values. + + Args: + profile: sweeping profile as list of (x, y, z) tuples in + counter-clockwise order + path: extrusion path as list of (x, y, z) tuples + twist: rotate sweeping profile up to the given end rotation angle in + radians + scale: scale sweeping profile gradually from 1.0 to given value + step_size: rough distance between automatically created intermediate + profiles, the step size is adapted to the distances between the + path segment points, a value od 0.0 disables creating intermediate + profiles + close: close profile polygon if ``True`` + caps: close hull with top- and bottom faces (ngons) + quads: use quads for "sweeping" faces if ``True`` else triangles, + the top and bottom faces are always ngons + + Returns: :class:`~ezdxf.render.MeshTransformer` + + """ + + def matrix(fac: float) -> Matrix44: + current_scale = 1.0 + (scale - 1.0) * fac + current_rotation = twist * fac + translation = target_point - start_point + scale_cos_a = current_scale * math.cos(current_rotation) + scale_sin_a = current_scale * math.sin(current_rotation) + # fmt: off + return Matrix44([ + scale_cos_a, scale_sin_a, 0.0, 0.0, + -scale_sin_a, scale_cos_a, 0.0, 0.0, + 0.0, 0.0, current_scale, 0.0, + translation.x, translation.y, translation.z, 1.0 + ]) + # fmt: on + + mesh = MeshVertexMerger() + sweeping_profile = Vec3.list(profile) + if close: + sweeping_profile = close_polygon(sweeping_profile) + if caps: + mesh.add_face(reversed(sweeping_profile[:-1])) + # create extrusion path with intermediate points + extrusion_path = Vec3.list(path) + if step_size != 0.0: + extrusion_path = _divide_path_into_steps(extrusion_path, step_size) + # create progress factors for each step along the extrusion path + factors = _partial_path_factors(extrusion_path) + start_point = extrusion_path[0] + prev_profile = sweeping_profile + face_generator = _quad_connection_faces if quads else _tri_connection_faces + for target_point, factor in zip(extrusion_path[1:], factors[1:]): + target_profile = list(matrix(factor).transform_vertices(sweeping_profile)) + for face in face_generator(prev_profile, target_profile): + mesh.add_face(face) + prev_profile = target_profile + if caps: + mesh.add_face(prev_profile[:-1]) + return MeshTransformer.from_builder(mesh) + + +def cylinder( + count: int = 16, + radius: float = 1.0, + top_radius: Optional[float] = None, + top_center: UVec = (0, 0, 1), + *, + caps=True, +) -> MeshTransformer: + """Create a `cylinder `_ as + :class:`~ezdxf.render.MeshTransformer` object, the base center is fixed in + the origin (0, 0, 0). + + Args: + count: profiles edge count + radius: radius for bottom profile + top_radius: radius for top profile, if ``None`` top_radius == radius + top_center: location vector for the center of the top profile + caps: close hull with top- and bottom faces (ngons) + + """ + if top_radius is None: + top_radius = radius + + if math.isclose(top_radius, 0.0): # pyramid/cone + return cone(count=count, radius=radius, apex=top_center) + + base_profile = list(circle(count, radius, close=True)) + top_profile = list(translate(circle(count, top_radius, close=True), top_center)) + return from_profiles_linear( + [base_profile, top_profile], + close=False, + quads=True, + caps=caps, + ) + + +def cylinder_2p( + count: int = 16, + radius: float = 1, + base_center: UVec = (0, 0, 0), + top_center: UVec = (0, 0, 1), + *, + caps=True, +) -> MeshTransformer: + """Creates a `cylinder `_ as + :class:`~ezdxf.render.MeshTransformer` object from two points, + `base_center` is the center of the base circle and, `top_center` the center + of the top circle. + + Args: + count: cylinder profile edge count + radius: radius for bottom profile + base_center: center of base circle + top_center: center of top circle + caps: close hull with top- and bottom faces (ngons) + + Raises: + ValueError: the cylinder orientation cannot be detected (base center == top center) + + """ + origin = Vec3(base_center) + heading = Vec3(top_center) - origin + if heading.is_null: + raise ValueError( + "cylinder orientation cannot be detected (base center == top center)" + ) + mesh = cylinder(count, radius, top_center=(0, 0, heading.magnitude), caps=caps) + try: + ucs = UCS(origin=origin, uy=Z_AXIS.cross(heading), uz=heading) + except ZeroDivisionError: + # heading vector is parallel to the z-axis + ucs = UCS(origin=origin, ux=X_AXIS, uz=heading) + mesh.transform(ucs.matrix) + return mesh + + +def from_profiles_linear( + profiles: Sequence[Sequence[Vec3]], + *, + close=True, + quads=True, + caps=False, +) -> MeshTransformer: + """Returns a :class:`~ezdxf.render.MeshTransformer` instance from linear + connected `profiles`. + + Args: + profiles: list of profiles + close: close profile polygon if ``True`` + quads: use quadrilaterals as connection faces if ``True`` else triangles + caps: close hull with top- and bottom faces (ngons) + + """ + mesh = MeshVertexMerger() + if close: + profiles = [close_polygon(p) for p in profiles] + if caps: + mesh.add_face(reversed(profiles[0])) # for correct outside pointing normals + face_generator = _quad_connection_faces if quads else _tri_connection_faces + for p0, p1 in zip(profiles, profiles[1:]): + for face in face_generator(p0, p1): + mesh.add_face(face) + if caps: + mesh.add_face(profiles[-1]) + return MeshTransformer.from_builder(mesh) + + +def spline_interpolation( + vertices: Iterable[UVec], + degree: int = 3, + method: str = "chord", + subdivide: int = 4, +) -> list[Vec3]: + """B-spline interpolation, vertices are fit points for the spline + definition. + + Only method 'uniform', yields vertices at fit points. + + Args: + vertices: fit points + degree: degree of B-spline + method: "uniform", "chord"/"distance", "centripetal"/"sqrt_chord" or + "arc" calculation method for parameter t + subdivide: count of sub vertices + 1, e.g. 4 creates 3 sub-vertices + + Returns: list of vertices + + """ + vertices = list(vertices) + spline = global_bspline_interpolation(vertices, degree=degree, method=method) + return list(spline.approximate(segments=(len(vertices) - 1) * subdivide)) + + +def spline_interpolated_profiles( + profiles: Sequence[Sequence[Vec3]], subdivide: int = 4 +) -> Iterable[list[Vec3]]: + """Profile interpolation by cubic B-spline interpolation. + + Args: + profiles: list of profiles + subdivide: count of interpolated profiles + 1, e.g. 4 creates 3 + sub-profiles between two main profiles (4 face loops) + + Returns: yields profiles as list of vertices + + """ + + if len(set(len(p) for p in profiles)) != 1: + raise ValueError("All profiles have to have the same vertex count") + + vertex_count = len(profiles[0]) + edges = [] # interpolated spline vertices, where profile vertices are fit points + for index in range(vertex_count): + edge_vertices = [p[index] for p in profiles] + edges.append(spline_interpolation(edge_vertices, subdivide=subdivide)) + + profile_count = len(edges[0]) + for profile_index in range(profile_count): + yield [edge[profile_index] for edge in edges] + + +def from_profiles_spline( + profiles: Sequence[Sequence[Vec3]], + subdivide: int = 4, + *, + close=True, + quads=True, + caps=False, +) -> MeshTransformer: + """Returns a :class:`~ezdxf.render.MeshTransformer` instance by spline + interpolation between given `profiles`. + Requires at least 4 profiles. A `subdivide` value of 4, means, create 4 face + loops between two profiles, without interpolation two profiles create one + face loop. + + Args: + profiles: list of profiles + subdivide: count of face loops + close: close profile polygon if ``True`` + quads: use quadrilaterals as connection faces if ``True`` else triangles + caps: close hull with top- and bottom faces (ngons) + + """ + if len(profiles) > 3: + profiles = list(spline_interpolated_profiles(profiles, subdivide)) + else: + raise ValueError("Spline interpolation requires at least 4 profiles") + return from_profiles_linear( + profiles, + close=close, + quads=quads, + caps=caps, + ) + + +def cone( + count: int = 16, + radius: float = 1.0, + apex: UVec = (0, 0, 1), + *, + caps=True, +) -> MeshTransformer: + """Create a `cone `_ as + :class:`~ezdxf.render.MeshTransformer` object, the base center is fixed in + the origin (0, 0, 0). + + Args: + count: edge count of basis_vector + radius: radius of basis_vector + apex: tip of the cone + caps: add a bottom face as ngon if ``True`` + + """ + mesh = MeshVertexMerger() + base_circle = list(circle(count, radius, close=True)) + for p1, p2 in zip(base_circle, base_circle[1:]): + mesh.add_face([p1, p2, apex]) + if caps: + # reversed for correct outside pointing normals + mesh.add_face(reversed(base_circle)) + return MeshTransformer.from_builder(mesh) + + +def cone_2p( + count: int = 16, + radius: float = 1.0, + base_center: UVec = (0, 0, 0), + apex: UVec = (0, 0, 1), + *, + caps=True, +) -> MeshTransformer: + """Create a `cone `_ as + :class:`~ezdxf.render.MeshTransformer` object from two points, `base_center` + is the center of the base circle and `apex` as the tip of the cone. + + Args: + count: edge count of basis_vector + radius: radius of basis_vector + base_center: center point of base circle + apex: tip of the cone + caps: add a bottom face as ngon if ``True`` + + Raises: + ValueError: the cone orientation cannot be detected (base center == apex) + + """ + origin = Vec3(base_center) + heading = Vec3(apex) - origin + if heading.is_null: + raise ValueError( + "the cone orientation cannot be detected (base center == apex)" + ) + + mesh = cone(count, radius, apex=(0, 0, heading.magnitude), caps=caps) + try: + ucs = UCS(origin=origin, uy=Z_AXIS.cross(heading), uz=heading) + except ZeroDivisionError: + # heading vector is parallel to the z-axis + ucs = UCS(origin=origin, ux=X_AXIS, uz=heading) + mesh.transform(ucs.matrix) + return mesh + + +def rotation_form( + count: int, + profile: Iterable[UVec], + angle: float = math.tau, + axis: UVec = (1, 0, 0), + *, + caps=False, +) -> MeshTransformer: + """Returns a :class:`~ezdxf.render.MeshTransformer` instance created by + rotating a `profile` around an `axis`. + + Args: + count: count of rotated profiles + profile: profile to rotate as list of vertices + angle: rotation angle in radians + axis: rotation axis + caps: close hull with start- and end faces (ngons) + + """ + if count < 3: + raise ValueError("count >= 2") + delta = float(angle) / count + m = Matrix44.axis_rotate(Vec3(axis), delta) + profile = [Vec3(p) for p in profile] + profiles = [profile] + for _ in range(int(count)): + profile = list(m.transform_vertices(profile)) + profiles.append(profile) + mesh = from_profiles_linear( + profiles, + close=False, + quads=True, + caps=caps, + ) + return mesh + + +def sphere( + count: int = 16, stacks: int = 8, radius: float = 1, *, quads=True +) -> MeshTransformer: + """Create a `sphere `_ as + :class:`~ezdxf.render.MeshTransformer` object, the center of the sphere is + always at (0, 0, 0). + + Args: + count: longitudinal slices + stacks: latitude slices + radius: radius of sphere + quads: use quadrilaterals as faces if ``True`` else triangles + + """ + radius = float(radius) + slices = int(count) + stacks_2 = int(stacks) // 2 # stacks from -stack/2 to +stack/2 + delta_theta = math.tau / float(slices) + delta_phi = math.pi / float(stacks) + mesh = MeshVertexMerger() + + def radius_of_stack(stack: float) -> float: + return radius * math.cos(delta_phi * stack) + + def vertex(slice_: float, r: float, z: float) -> Vec3: + actual_theta = delta_theta * slice_ + return Vec3(math.cos(actual_theta) * r, math.sin(actual_theta) * r, z) + + def cap_triangles(stack, top=False): + z = math.sin(stack * delta_phi) * radius + cap_vertex = Vec3(0, 0, radius) if top else Vec3(0, 0, -radius) + r1 = radius_of_stack(stack) + for slice_ in range(slices): + v1 = vertex(slice_, r1, z) + v2 = vertex(slice_ + 1, r1, z) + if top: + mesh.add_face((v1, v2, cap_vertex)) + else: + mesh.add_face((cap_vertex, v2, v1)) + + # bottom triangle faces + cap_triangles(-stacks_2 + 1, top=False) + + # add body faces + for actual_stack in range(-stacks_2 + 1, stacks_2 - 1): + next_stack = actual_stack + 1 + r1 = radius_of_stack(actual_stack) + r2 = radius_of_stack(next_stack) + z1 = math.sin(delta_phi * actual_stack) * radius + z2 = math.sin(delta_phi * next_stack) * radius + for i in range(slices): + v1 = vertex(i, r1, z1) + v2 = vertex(i + 1, r1, z1) + v3 = vertex(i + 1, r2, z2) + v4 = vertex(i, r2, z2) + if quads: + mesh.add_face([v1, v2, v3, v4]) + else: + center = vertex( + i + 0.5, + radius_of_stack(actual_stack + 0.5), + math.sin(delta_phi * (actual_stack + 0.5)) * radius, + ) + mesh.add_face([v1, v2, center]) + mesh.add_face([v2, v3, center]) + mesh.add_face([v3, v4, center]) + mesh.add_face([v4, v1, center]) + + # top triangle faces + cap_triangles(stacks_2 - 1, top=True) + + return MeshTransformer.from_builder(mesh) + + +def torus( + major_count: int = 16, + minor_count: int = 8, + major_radius=1.0, + minor_radius=0.1, + start_angle: float = 0.0, + end_angle: float = math.tau, + *, + caps=True, +) -> MeshTransformer: + """Create a `torus `_ as + :class:`~ezdxf.render.MeshTransformer` object, the center of the torus is + always at (0, 0, 0). The `major_radius` has to be bigger than the + `minor_radius`. + + Args: + major_count: count of circles + minor_count: count of circle vertices + major_radius: radius of the circle center + minor_radius: radius of circle + start_angle: start angle of torus in radians + end_angle: end angle of torus in radians + caps: close hull with start- and end faces (ngons) if the torus is open + + """ + if major_count < 1: + raise ValueError(f"major_count < 1") + if minor_count < 3: + raise ValueError(f"minor_count < 3") + major_radius = math.fabs(float(major_radius)) + minor_radius = math.fabs(float(minor_radius)) + if major_radius < 1e-9: + raise ValueError("major_radius is 0") + if minor_radius < 1e-9: + raise ValueError("minor_radius is 0") + if minor_radius >= major_radius: + raise ValueError("minor_radius >= major_radius") + start_angle = float(start_angle) % math.tau + if end_angle != math.tau: + end_angle = float(end_angle) % math.tau + angle_span = arc_angle_span_rad(start_angle, end_angle) + closed_torus = math.isclose(angle_span, math.tau) + step_angle = angle_span / major_count + circle_profile = [ + Vec3(v.x, 0, v.y) + for v in translate( + circle(minor_count, minor_radius, close=True), + Vec3(major_radius, 0, 0), + ) + ] + # required for outwards pointing normals: + circle_profile.reverse() + if start_angle > 1e-9: + circle_profile = [v.rotate(start_angle) for v in circle_profile] + mesh = MeshVertexMerger() + start_profile = circle_profile + end_profile = [v.rotate(step_angle) for v in circle_profile] + + if not closed_torus and caps: # add start cap + mesh.add_face(reversed(start_profile)) + + for _ in range(major_count): + for face in _quad_connection_faces(start_profile, end_profile): + mesh.add_face(face) + start_profile = end_profile + end_profile = [v.rotate(step_angle) for v in end_profile] + + if not closed_torus and caps: # add end cap + # end_profile is rotated to the next profile! + mesh.add_face(start_profile) + + return MeshTransformer.from_builder(mesh) + + +def connection_faces( + start_profile: list[Vec3], end_profile: list[Vec3], quad: bool +) -> Iterator[Sequence[Vec3]]: + assert len(start_profile) == len(end_profile), "profiles differ in vertex count" + if quad: + yield from _quad_connection_faces(start_profile, end_profile) + else: + yield from _tri_connection_faces(start_profile, end_profile) + + +def _quad_connection_faces( + start_profile: Sequence[Vec3], end_profile: Sequence[Vec3] +) -> Iterator[Sequence[Vec3]]: + v0_prev = start_profile[0] + v1_prev = end_profile[0] + for v0, v1 in zip(start_profile[1:], end_profile[1:]): + yield v0_prev, v0, v1, v1_prev + v0_prev = v0 + v1_prev = v1 + + +def _tri_connection_faces( + start_profile: Sequence[Vec3], end_profile: Sequence[Vec3] +) -> Iterator[Sequence[Vec3]]: + v0_prev = start_profile[0] + v1_prev = end_profile[0] + for v0, v1 in zip(start_profile[1:], end_profile[1:]): + yield v1, v1_prev, v0_prev, + yield v0_prev, v0, v1 + v0_prev = v0 + v1_prev = v1 + + +def reference_frame_z(heading: Vec3, origin: Vec3 = NULLVEC) -> UCS: + """Returns a reference frame as UCS from the given heading and the + WCS z-axis as reference "up" direction. + The z-axis of the reference frame is pointing in heading direction, the + x-axis is pointing right and the y-axis is pointing upwards. + + The reference frame is used to project vertices in xy-plane + (construction plane) onto the normal plane of the given heading. + + Use the :func:`reference_frame_ext` if heading is parallel to the WCS + Z_AXIS. + + Args: + heading: WCS direction of the reference frame z-axis + origin: new UCS origin + + Raises: + ZeroDivisionError: heading is parallel to WCS Z_AXIS + + """ + return UCS(uy=Z_AXIS.cross(heading), uz=heading, origin=origin) + + +def reference_frame_ext(frame: UCS, origin: Vec3 = NULLVEC) -> UCS: + """Reference frame calculation if heading vector is parallel to the WCS + Z_AXIS. + + Args: + frame: previous reference frame + origin: new UCS origin + + """ + try: # preserve x-axis + return UCS(uy=Z_AXIS.cross(frame.ux), uz=Z_AXIS, origin=origin) + except ZeroDivisionError: # preserve y-axis + return UCS(ux=frame.uy.cross(Z_AXIS), uz=Z_AXIS, origin=origin) + + +def _intersect_rays( + prev_rays: Sequence[Sequence[Vec3]], next_rays: Sequence[Sequence[Vec3]] +) -> Iterator[Vec3]: + for ray1, ray2 in zip(prev_rays, next_rays): + ip = intersection_ray_ray_3d(ray1, ray2) + count = len(ip) + if count == 1: # exact intersection + yield ip[0] + elif count == 2: # imprecise intersection + yield ip[0].lerp(ip[1]) + else: # parallel rays + yield ray1[-1].lerp(ray2[0]) + + +def _intersection_profiles( + start_profiles: Sequence[Sequence[Vec3]], + end_profiles: Sequence[Sequence[Vec3]], +) -> list[Sequence[Vec3]]: + profiles: list[Sequence[Vec3]] = [start_profiles[0]] + rays = [ + [(v0, v1) for v0, v1 in zip(p0, p1)] + for p0, p1 in zip(start_profiles, end_profiles) + ] + for prev_rays, next_rays in zip(rays, rays[1:]): + profiles.append(list(_intersect_rays(prev_rays, next_rays))) + profiles.append(end_profiles[-1]) + return profiles + + +def make_next_reference_frame(frame: UCS, heading: Vec3, origin: Vec3) -> UCS: + """Returns the following reference frame next to the current reference + `frame`. + + Args: + frame: the current reference frame + heading: z-axis direction of the following frame in WCS + origin: origin of the following reference frame + + """ + try: + next_frame = reference_frame_z(heading, origin) + # reverse y-axis if the next frame y-axis has opposite orientation to + # the previous frame y-axis: + if next_frame.uy.dot(frame.uy) < 0: + next_frame = UCS(origin=origin, uz=next_frame.uz, uy=-next_frame.uy) + return next_frame + except ZeroDivisionError: + # heading vector is parallel to the Z_AXIS + return reference_frame_ext(frame, origin) + + +def _make_sweep_start_and_end_profiles( + profile: Iterable[UVec], + sweeping_path: Iterable[UVec], + next_ref_frame: Callable[[UCS, Vec3, Vec3], UCS], +) -> tuple[list[list[Vec3]], list[list[Vec3]]]: + spath = Vec3.list(sweeping_path) + reference_profile = Vec3.list(profile) + start_profiles = [] + end_profiles = [] + ref_frame = UCS() + for origin, target in zip(spath, spath[1:]): + heading = target - origin + ref_frame = next_ref_frame(ref_frame, heading, origin) + start_profile = list(ref_frame.points_to_wcs(reference_profile)) + start_profiles.append(start_profile) + end_profiles.append([v + heading for v in start_profile]) + return start_profiles, end_profiles + + +def sweep_profile( + profile: Iterable[UVec], + sweeping_path: Iterable[UVec], +) -> list[Sequence[Vec3]]: + """Returns the intermediate profiles of sweeping a profile along a 3D path + where the sweeping path defines the final location in the `WCS`. + + The profile is defined in a reference system. The origin of this reference + system will be moved along the sweeping path where the z-axis of the + reference system is pointing into the moving direction. + + Returns the start-, end- and all intermediate profiles along the sweeping + path. + + """ + return _intersection_profiles( + *_make_sweep_start_and_end_profiles( + profile, sweeping_path, make_next_reference_frame + ) + ) + + +def debug_sweep_profiles( + profile: Iterable[UVec], + sweeping_path: Iterable[UVec], + close=True, +) -> list[Sequence[Vec3]]: + if close: + profile = close_polygon(profile) + profiles: list[Sequence[Vec3]] = [] + for sp, ep in zip( + *_make_sweep_start_and_end_profiles( + profile, sweeping_path, make_next_reference_frame + ) + ): + profiles.append(sp) + profiles.append(ep) + return profiles + + +def sweep( + profile: Iterable[UVec], + sweeping_path: Iterable[UVec], + *, + close=True, + quads=True, + caps=True, +) -> MeshTransformer: + """Returns the mesh from sweeping a profile along a 3D path, where the + sweeping path defines the final location in the `WCS`. + + The profile is defined in a reference system. The origin of this reference + system will be moved along the sweeping path where the z-axis of the + reference system is pointing into the moving direction. + + Returns the mesh as :class:`ezdxf.render.MeshTransformer` object. + + Args: + profile: sweeping profile defined in the reference system as + iterable of (x, y, z) coordinates in counter-clockwise order + sweeping_path: the sweeping path defined in the WCS as iterable of + (x, y, z) coordinates + close: close sweeping profile if ``True`` + quads: use quadrilaterals as connection faces if ``True`` else triangles + caps: close hull with top- and bottom faces (ngons) + + """ + profiles = sweep_profile(profile, sweeping_path) + return from_profiles_linear( + profiles, + close=close, + quads=quads, + caps=caps, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/hatching.py b/.venv/lib/python3.12/site-packages/ezdxf/render/hatching.py new file mode 100644 index 0000000..733c96f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/hatching.py @@ -0,0 +1,700 @@ +# Copyright (c) 2022-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterator, + Sequence, + TYPE_CHECKING, + Callable, + Any, + Union, + Optional, + Tuple, +) +from typing_extensions import TypeAlias +from collections import defaultdict +import enum +import math +import dataclasses +import random +from ezdxf.math import ( + Vec2, + Vec3, + Bezier3P, + Bezier4P, + intersection_ray_cubic_bezier_2d, + quadratic_to_cubic_bezier, +) +from ezdxf import const +from ezdxf.path import Path, LineTo, MoveTo, Curve3To, Curve4To + +if TYPE_CHECKING: + from ezdxf.entities.polygon import DXFPolygon + +MIN_HATCH_LINE_DISTANCE = 1e-4 # ??? what's a good choice +NONE_VEC2 = Vec2(math.nan, math.nan) +KEY_NDIGITS = 4 +SORT_NDIGITS = 10 + + +class IntersectionType(enum.IntEnum): + NONE = 0 + REGULAR = 1 + START = 2 + END = 3 + COLLINEAR = 4 + + +class HatchingError(Exception): + """Base exception class of the :mod:`hatching` module.""" + + pass + + +class HatchLineDirectionError(HatchingError): + """Hatching direction is undefined or a (0, 0) vector.""" + + pass + + +class DenseHatchingLinesError(HatchingError): + """Very small hatching distance which creates too many hatching lines.""" + + pass + + +@dataclasses.dataclass(frozen=True) +class Line: + start: Vec2 + end: Vec2 + distance: float # normal distance to the hatch baseline + + +@dataclasses.dataclass(frozen=True) +class Intersection: + """Represents an intersection.""" + + type: IntersectionType = IntersectionType.NONE + p0: Vec2 = NONE_VEC2 + p1: Vec2 = NONE_VEC2 + + +def side_of_line(distance: float, abs_tol=1e-12) -> int: + if abs(distance) < abs_tol: + return 0 + if distance > 0.0: + return +1 + return -1 + + +@dataclasses.dataclass(frozen=True) +class HatchLine: + """Represents a single hatch line. + + Args: + origin: the origin of the hatch line as :class:`~ezdxf.math.Vec2` instance + direction: the hatch line direction as :class:`~ezdxf.math.Vec2` instance, must not (0, 0) + distance: the normal distance to the base hatch line as float + + """ + + origin: Vec2 + direction: Vec2 + distance: float + + def intersect_line( + self, + a: Vec2, + b: Vec2, + dist_a: float, + dist_b: float, + ) -> Intersection: + """Returns the :class:`Intersection` of this hatch line and the line + defined by the points `a` and `b`. + The arguments `dist_a` and `dist_b` are the signed normal distances of + the points `a` and `b` from the hatch baseline. + The normal distances from the baseline are easy to calculate by the + :meth:`HatchBaseLine.signed_distance` method and allow a fast + intersection calculation by a simple point interpolation. + + Args: + a: start point of the line as :class:`~ezdxf.math.Vec2` instance + b: end point of the line as :class:`~ezdxf.math.Vec2` instance + dist_a: normal distance of point `a` to the hatch baseline as float + dist_b: normal distance of point `b` to the hatch baseline as float + + """ + # all distances are normal distances to the hatch baseline + line_distance = self.distance + side_a = side_of_line(dist_a - line_distance) + side_b = side_of_line(dist_b - line_distance) + if side_a == 0: + if side_b == 0: + return Intersection(IntersectionType.COLLINEAR, a, b) + else: + return Intersection(IntersectionType.START, a) + elif side_b == 0: + return Intersection(IntersectionType.END, b) + elif side_a != side_b: + factor = abs((dist_a - line_distance) / (dist_a - dist_b)) + return Intersection(IntersectionType.REGULAR, a.lerp(b, factor)) + return Intersection() # no intersection + + def intersect_cubic_bezier_curve(self, curve: Bezier4P) -> Sequence[Intersection]: + """Returns 0 to 3 :class:`Intersection` points of this hatch line with + a cubic Bèzier curve. + + Args: + curve: the cubic Bèzier curve as :class:`ezdxf.math.Bezier4P` instance + + """ + return [ + Intersection(IntersectionType.REGULAR, p, NONE_VEC2) + for p in intersection_ray_cubic_bezier_2d( + self.origin, self.origin + self.direction, curve + ) + ] + + +class PatternRenderer: + """ + The hatch pattern of a DXF entity has one or more :class:`HatchBaseLine` + instances with an origin, direction, offset and line pattern. + The :class:`PatternRenderer` for a certain distance from the + baseline has to be acquired from the :class:`HatchBaseLine` by the + :meth:`~HatchBaseLine.pattern_renderer` method. + + The origin of the hatch line is the starting point of the line + pattern. The offset defines the origin of the adjacent + hatch line and doesn't have to be orthogonal to the hatch line direction. + + **Line Pattern** + + The line pattern is a sequence of floats, where a value > 0.0 is a dash, a + value < 0.0 is a gap and value of 0.0 is a point. + + Args: + hatch_line: :class:`HatchLine` + pattern: the line pattern as sequence of float values + + """ + + def __init__(self, hatch_line: HatchLine, pattern: Sequence[float]): + self.origin = hatch_line.origin + self.direction = hatch_line.direction + self.pattern = pattern + self.pattern_length = math.fsum([abs(e) for e in pattern]) + + def sequence_origin(self, index: float) -> Vec2: + return self.origin + self.direction * (self.pattern_length * index) + + def render(self, start: Vec2, end: Vec2) -> Iterator[tuple[Vec2, Vec2]]: + """Yields the pattern lines as pairs of :class:`~ezdxf.math.Vec2` + instances from the start- to the end point on the hatch line. + For points the start- and end point are the same :class:`~ezdxf.math.Vec2` + instance and can be tested by the ``is`` operator. + + The start- and end points should be located collinear at the hatch line + of this instance, otherwise the points a projected onto this hatch line. + + """ + if start.isclose(end): + return + length = self.pattern_length + if length < 1e-9: + yield start, end + return + + direction = self.direction + if direction.dot(end - start) < 0.0: + # Line direction is reversed to the pattern line direction! + start, end = end, start + origin = self.origin + s_dist = direction.dot(start - origin) + e_dist = direction.dot(end - origin) + s_index, s_offset = divmod(s_dist, length) + e_index, e_offset = divmod(e_dist, length) + + if s_index == e_index: + yield from self.render_offset_to_offset(s_index, s_offset, e_offset) + return + # line crosses pattern border + if s_offset > 0.0: + yield from self.render_offset_to_offset( + s_index, + s_offset, + length, + ) + s_index += 1 + + while s_index < e_index: + yield from self.render_full_pattern(s_index) + s_index += 1 + + if e_offset > 0.0: + yield from self.render_offset_to_offset( + s_index, + 0.0, + e_offset, + ) + + def render_full_pattern(self, index: float) -> Iterator[tuple[Vec2, Vec2]]: + # fast pattern rendering + direction = self.direction + start_point = self.sequence_origin(index) + for dash in self.pattern: + if dash == 0.0: + yield start_point, start_point + else: + end_point = start_point + direction * abs(dash) + if dash > 0.0: + yield start_point, end_point + start_point = end_point + + def render_offset_to_offset( + self, index: float, s_offset: float, e_offset: float + ) -> Iterator[tuple[Vec2, Vec2]]: + direction = self.direction + origin = self.sequence_origin(index) + start_point = origin + direction * s_offset + distance = 0.0 + for dash in self.pattern: + distance += abs(dash) + if distance < s_offset: + continue + if dash == 0.0: + yield start_point, start_point + else: + end_point = origin + direction * min(distance, e_offset) + if dash > 0.0: + yield start_point, end_point + if distance >= e_offset: + return + start_point = end_point + + +class HatchBaseLine: + """A hatch baseline defines the source line for hatching a geometry. + A complete hatch pattern of a DXF entity can consist of one or more hatch + baselines. + + Args: + origin: the origin of the hatch line as :class:`~ezdxf.math.Vec2` instance + direction: the hatch line direction as :class:`~ezdxf.math.Vec2` instance, must not (0, 0) + offset: the offset of the hatch line origin to the next or to the previous hatch line + line_pattern: line pattern as sequence of floats, see also :class:`PatternRenderer` + min_hatch_line_distance: minimum hatch line distance to render, raises an + :class:`DenseHatchingLinesError` exception if the distance between hatch + lines is smaller than this value + + Raises: + HatchLineDirectionError: hatch baseline has no direction, (0, 0) vector + DenseHatchingLinesError: hatching lines are too narrow + + """ + + def __init__( + self, + origin: Vec2, + direction: Vec2, + offset: Vec2, + line_pattern: Optional[list[float]] = None, + min_hatch_line_distance=MIN_HATCH_LINE_DISTANCE, + ): + self.origin = origin + try: + self.direction = direction.normalize() + except ZeroDivisionError: + raise HatchLineDirectionError("hatch baseline has no direction") + self.offset = offset + self.normal_distance: float = (-offset).det(self.direction - offset) + if abs(self.normal_distance) < min_hatch_line_distance: + raise DenseHatchingLinesError("hatching lines are too narrow") + self._end = self.origin + self.direction + self.line_pattern: list[float] = line_pattern if line_pattern else [] + + def __repr__(self): + return ( + f"{self.__class__.__name__}(origin={self.origin!r}, " + f"direction={self.direction!r}, offset={self.offset!r})" + ) + + def hatch_line(self, distance: float) -> HatchLine: + """Returns the :class:`HatchLine` at the given signed `distance`.""" + factor = distance / self.normal_distance + return HatchLine(self.origin + self.offset * factor, self.direction, distance) + + def signed_distance(self, point: Vec2) -> float: + """Returns the signed normal distance of the given `point` from this + hatch baseline. + """ + # denominator (_end - origin).magnitude is 1.0 !!! + return (self.origin - point).det(self._end - point) + + def pattern_renderer(self, distance: float) -> PatternRenderer: + """Returns the :class:`PatternRenderer` for the given signed `distance`.""" + return PatternRenderer(self.hatch_line(distance), self.line_pattern) + + +def hatch_line_distances( + point_distances: Sequence[float], normal_distance: float +) -> list[float]: + """Returns all hatch line distances in the range of the given point + distances. + """ + assert normal_distance != 0.0 + normal_factors = [d / normal_distance for d in point_distances] + max_line_number = int(math.ceil(max(normal_factors))) + min_line_number = int(math.ceil(min(normal_factors))) + return [normal_distance * num for num in range(min_line_number, max_line_number)] + + +def intersect_polygon( + baseline: HatchBaseLine, polygon: Sequence[Vec2] +) -> Iterator[tuple[Intersection, float]]: + """Yields all intersection points of the hatch defined by the `baseline` and + the given `polygon`. + + Returns the intersection point and the normal-distance from the baseline, + intersection points with the same normal-distance lay on the same hatch + line. + + """ + count = len(polygon) + if count < 3: + return + if polygon[0].isclose(polygon[-1]): + count -= 1 + if count < 3: + return + + prev_point = polygon[count - 1] # last point + dist_prev = baseline.signed_distance(prev_point) + for index in range(count): + point = polygon[index] + dist_point = baseline.signed_distance(point) + for hatch_line_distance in hatch_line_distances( + (dist_prev, dist_point), baseline.normal_distance + ): + hatch_line = baseline.hatch_line(hatch_line_distance) + ip = hatch_line.intersect_line( + prev_point, + point, + dist_prev, + dist_point, + ) + if ( + ip.type != IntersectionType.NONE + and ip.type != IntersectionType.COLLINEAR + ): + yield ip, hatch_line_distance + + prev_point = point + dist_prev = dist_point + + +def hatch_polygons( + baseline: HatchBaseLine, + polygons: Sequence[Sequence[Vec2]], + terminate: Optional[Callable[[], bool]] = None, +) -> Iterator[Line]: + """Yields all pattern lines for all hatch lines generated by the given + :class:`HatchBaseLine`, intersecting the given 2D polygons as :class:`Line` + instances. + The `polygons` should represent a single entity with or without holes, the + order of the polygons and their winding orientation (cw or ccw) is not + important. Entities which do not intersect or overlap should be handled + separately! + + Each polygon is a sequence of :class:`~ezdxf.math.Vec2` instances, they are + treated as closed polygons even if the last vertex is not equal to the + first vertex. + + The hole detection is done by a simple inside/outside counting algorithm and + far from perfect, but is able to handle ordinary polygons well. + + The terminate function WILL BE CALLED PERIODICALLY AND should return + ``True`` to terminate execution. This can be used to implement a timeout, + which can be required if using a very small hatching distance, especially + if you get the data from untrusted sources. + + Args: + baseline: :class:`HatchBaseLine` + polygons: multiple sequences of :class:`~ezdxf.path.Vec2` instances of + a single entity, the order of exterior- and hole paths and the + winding orientation (cw or ccw) of paths is not important + terminate: callback function which is called periodically and should + return ``True`` to terminate the hatching function + + """ + yield from _hatch_geometry(baseline, polygons, intersect_polygon, terminate) + + +def intersect_path( + baseline: HatchBaseLine, path: Path +) -> Iterator[tuple[Intersection, float]]: + """Yields all intersection points of the hatch defined by the `baseline` and + the given single `path`. + + Returns the intersection point and the normal-distance from the baseline, + intersection points with the same normal-distance lay on the same hatch + line. + + """ + for path_element in _path_elements(path): + if isinstance(path_element, Bezier4P): + distances = [ + baseline.signed_distance(p) for p in path_element.control_points + ] + for hatch_line_distance in hatch_line_distances( + distances, baseline.normal_distance + ): + hatch_line = baseline.hatch_line(hatch_line_distance) + for ip in hatch_line.intersect_cubic_bezier_curve(path_element): + yield ip, hatch_line_distance + else: # line + a, b = Vec2.generate(path_element) + dist_a = baseline.signed_distance(a) + dist_b = baseline.signed_distance(b) + for hatch_line_distance in hatch_line_distances( + (dist_a, dist_b), baseline.normal_distance + ): + hatch_line = baseline.hatch_line(hatch_line_distance) + ip = hatch_line.intersect_line(a, b, dist_a, dist_b) + if ( + ip.type != IntersectionType.NONE + and ip.type != IntersectionType.COLLINEAR + ): + yield ip, hatch_line_distance + + +def _path_elements(path: Path) -> Union[Bezier4P, tuple[Vec2, Vec2]]: + if len(path) == 0: + return + start = path.start + path_start = start + for command in path.commands(): + end = command.end + if isinstance(command, MoveTo): + if not path_start.isclose(start): + yield start, path_start # close sub-path + path_start = end + elif isinstance(command, LineTo) and not start.isclose(end): + yield start, end + elif isinstance(command, Curve4To): + yield Bezier4P((start, command.ctrl1, command.ctrl2, end)) + elif isinstance(command, Curve3To): + curve3 = Bezier3P((start, command.ctrl, end)) + yield quadratic_to_cubic_bezier(curve3) + start = end + + if not path_start.isclose(start): # close path + yield start, path_start + + +def hatch_paths( + baseline: HatchBaseLine, + paths: Sequence[Path], + terminate: Optional[Callable[[], bool]] = None, +) -> Iterator[Line]: + """Yields all pattern lines for all hatch lines generated by the given + :class:`HatchBaseLine`, intersecting the given 2D :class:`~ezdxf.path.Path` + instances as :class:`Line` instances. The paths are handled as projected + into the xy-plane the z-axis of path vertices will be ignored if present. + + Same as the :func:`hatch_polygons` function, but for :class:`~ezdxf.path.Path` + instances instead of polygons build of vertices. This function **does not + flatten** the paths into vertices, instead the real intersections of the + Bézier curves and the hatch lines are calculated. + + For more information see the docs of the :func:`hatch_polygons` function. + + Args: + baseline: :class:`HatchBaseLine` + paths: sequence of :class:`~ezdxf.path.Path` instances of a single + entity, the order of exterior- and hole paths and the winding + orientation (cw or ccw) of the paths is not important + terminate: callback function which is called periodically and should + return ``True`` to terminate the hatching function + + """ + yield from _hatch_geometry(baseline, paths, intersect_path, terminate) + + +IFuncType: TypeAlias = Callable[ + [HatchBaseLine, Any], Iterator[Tuple[Intersection, float]] +] + + +def _hatch_geometry( + baseline: HatchBaseLine, + geometries: Sequence[Any], + intersection_func: IFuncType, + terminate: Optional[Callable[[], bool]] = None, +) -> Iterator[Line]: + """Returns all pattern lines intersecting the given geometries. + + The intersection_func() should yield all intersection points between a + HatchBaseLine() and as given geometry. + + The terminate function should return ``True`` to terminate execution + otherwise ``False``. Can be used to implement a timeout. + + """ + points: dict[float, list[Intersection]] = defaultdict(list) + for geometry in geometries: + if terminate and terminate(): + return + for ip, distance in intersection_func(baseline, geometry): + assert ip.type != IntersectionType.NONE + points[round(distance, KEY_NDIGITS)].append(ip) + + for distance, vertices in points.items(): + if terminate and terminate(): + return + start = NONE_VEC2 + end = NONE_VEC2 + for line in _line_segments(vertices, distance): + if start is NONE_VEC2: + start = line.start + end = line.end + continue + if line.start.isclose(end): + end = line.end + else: + yield Line(start, end, distance) + start = line.start + end = line.end + + if start is not NONE_VEC2: + yield Line(start, end, distance) + + +def _line_segments(vertices: list[Intersection], distance: float) -> Iterator[Line]: + if len(vertices) < 2: + return + vertices.sort(key=lambda p: p.p0.round(SORT_NDIGITS)) + inside = False + prev_point = NONE_VEC2 + for ip in vertices: + if ip.type == IntersectionType.NONE or ip.type == IntersectionType.COLLINEAR: + continue + # REGULAR, START, END + point = ip.p0 + if prev_point is NONE_VEC2: + inside = True + prev_point = point + continue + if inside: + yield Line(prev_point, point, distance) + + inside = not inside + prev_point = point + + +def hatch_entity( + polygon: DXFPolygon, + filter_text_boxes=True, + jiggle_origin: bool = True, +) -> Iterator[tuple[Vec3, Vec3]]: + """Yields the hatch pattern of the given HATCH or MPOLYGON entity as 3D lines. + Each line is a pair of :class:`~ezdxf.math.Vec3` instances as start- and end + vertex, points are represented as lines of zero length, which means the + start vertex is equal to the end vertex. + + The function yields nothing if `polygon` has a solid- or gradient filling + or does not have a usable pattern assigned. + + Args: + polygon: :class:`~ezdxf.entities.Hatch` or :class:`~ezdxf.entities.MPolygon` + entity + filter_text_boxes: ignore text boxes if ``True`` + jiggle_origin: move pattern line origins a small amount to avoid intersections + in corner points which causes errors in patterns + + """ + if polygon.pattern is None or polygon.dxf.solid_fill: + return + if len(polygon.pattern.lines) == 0: + return + ocs = polygon.ocs() + elevation = polygon.dxf.elevation.z + paths = hatch_boundary_paths(polygon, filter_text_boxes) + # todo: MPOLYGON offset + # All paths in OCS! + for baseline in pattern_baselines(polygon, jiggle_origin=jiggle_origin): + for line in hatch_paths(baseline, paths): + line_pattern = baseline.pattern_renderer(line.distance) + for s, e in line_pattern.render(line.start, line.end): + if ocs.transform: + yield ocs.to_wcs((s.x, s.y, elevation)), ocs.to_wcs( + (e.x, e.y, elevation) + ) + yield Vec3(s), Vec3(e) + + +def hatch_boundary_paths(polygon: DXFPolygon, filter_text_boxes=True) -> list[Path]: + """Returns the hatch boundary paths as :class:`ezdxf.path.Path` instances + of HATCH and MPOLYGON entities. Ignores text boxes if argument + `filter_text_boxes` is ``True``. + """ + from ezdxf.path import from_hatch_boundary_path + + loops = [] + for boundary in polygon.paths.rendering_paths(polygon.dxf.hatch_style): + if filter_text_boxes and boundary.path_type_flags & const.BOUNDARY_PATH_TEXTBOX: + continue + path = from_hatch_boundary_path(boundary) + for sub_path in path.sub_paths(): + if len(sub_path): + sub_path.close() + loops.append(sub_path) + return loops + + +def _jiggle_factor(): + # range 0.0003 .. 0.0010 + return random.random() * 0.0007 + 0.0003 + + +def pattern_baselines( + polygon: DXFPolygon, + min_hatch_line_distance: float = MIN_HATCH_LINE_DISTANCE, + *, + jiggle_origin: bool = False, +) -> Iterator[HatchBaseLine]: + """Yields the hatch pattern baselines of HATCH and MPOLYGON entities as + :class:`HatchBaseLine` instances. Set `jiggle_origin` to ``True`` to move pattern + line origins a small amount to avoid intersections in corner points which causes + errors in patterns. + + """ + pattern = polygon.pattern + if not pattern: + return + # The hatch pattern parameters are already scaled and rotated for direct + # usage! + # The stored scale and angle is just for reconstructing the base pattern + # when applying a new scaling or rotation. + + jiggle_offset = Vec2() + if jiggle_origin: + # move origin of base pattern lines a small amount to avoid intersections with + # boundary corner points + offsets: list[float] = [line.offset.magnitude for line in pattern.lines] + if len(offsets): + # calculate the same random jiggle offset for all pattern base lines + mean = sum(offsets) / len(offsets) + x = _jiggle_factor() * mean + y = _jiggle_factor() * mean + jiggle_offset = Vec2(x, y) + + for line in pattern.lines: + direction = Vec2.from_deg_angle(line.angle) + yield HatchBaseLine( + origin=line.base_point + jiggle_offset, + direction=direction, + offset=line.offset, + line_pattern=line.dash_length_items, + min_hatch_line_distance=min_hatch_line_distance, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/leader.py b/.venv/lib/python3.12/site-packages/ezdxf/render/leader.py new file mode 100644 index 0000000..0bc9a9a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/leader.py @@ -0,0 +1,126 @@ +# Copyright (c) 2020-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, cast + +from ezdxf import ARROWS +from ezdxf.entities import factory +from ezdxf.lldxf.const import BYBLOCK +from ezdxf.math import Vec3, fit_points_to_cad_cv + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic, Leader, Insert, Spline, Dimension, Line + + +def virtual_entities(leader: Leader) -> Iterator[DXFGraphic]: + # Source: https://atlight.github.io/formats/dxf-leader.html + # GDAL: DXF LEADER implementation: + # https://github.com/OSGeo/gdal/blob/master/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_leader.cpp + # LEADER DXF Reference: + # http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-396B2369-F89F-47D7-8223-8B7FB794F9F3 + assert leader.dxftype() == "LEADER" + + vertices = Vec3.list(leader.vertices) # WCS + if len(vertices) < 2: + # This LEADER entities should be removed by the auditor if loaded or + # ignored at exporting, if created by an ezdxf-user (log). + raise ValueError("More than 1 vertex required.") + dxf = leader.dxf + doc = leader.doc + + # Some default values depend on the measurement system + # 0/1 = imperial/metric + if doc: + measurement = doc.header.get("$MEASUREMENT", 0) + else: + measurement = 0 + + # Set default styling attributes values: + dimtad = 1 + dimgap = 0.625 if measurement else 0.0625 + dimscale = 1.0 + dimclrd = dxf.color + dimltype = dxf.linetype + dimlwd = dxf.lineweight + override = None + + if doc: + # get styling attributes from associated DIMSTYLE and/or XDATA override + override = leader.override() + dimtad = override.get("dimtad", dimtad) + dimgap = override.get("dimgap", dimgap) + dimscale = override.get("dimscale", dimscale) + if dimscale == 0.0: # special but unknown meaning + dimscale = 1.0 + dimclrd = override.get("dimclrd", dimclrd) + dimltype = override.get("dimltype", dimltype) + dimlwd = override.get("dimlwd", dimlwd) + + text_width = dxf.text_width + hook_line_vector = Vec3(dxf.horizontal_direction) + has_text_annotation = dxf.annotation_type == 0 + + if has_text_annotation and dxf.has_hookline: + if dxf.hookline_direction == 1: + hook_line_vector = -hook_line_vector + if dimtad != 0 and text_width > 0: + hook_line = hook_line_vector * (dimgap * dimscale + text_width) + vertices.append(vertices[-1] + hook_line) + + dxfattribs = leader.graphic_properties() + dxfattribs["color"] = dimclrd + dxfattribs["linetype"] = dimltype + dxfattribs["lineweight"] = dimlwd + + if dxfattribs.get("color") == BYBLOCK: + dxfattribs["color"] = dxf.block_color + + if dxf.path_type == 1: # Spline + start_tangent = vertices[1] - vertices[0] + end_tangent = vertices[-1] - vertices[-2] + bspline = fit_points_to_cad_cv(vertices, tangents=[start_tangent, end_tangent]) + spline = cast("Spline", factory.new("SPLINE", doc=doc)) + spline.apply_construction_tool(bspline) + yield spline + else: + attribs = dict(dxfattribs) + prev = vertices[0] + for vertex in vertices[1:]: + attribs["start"] = prev + attribs["end"] = vertex + yield cast( + "Line", + factory.new(dxftype="LINE", dxfattribs=attribs, doc=doc), + ) + prev = vertex + + if dxf.has_arrowhead and override: + arrow_name = override.get("dimldrblk", "") + if arrow_name is None: + return + size = override.get("dimasz", 2.5 if measurement else 0.1875) * dimscale + rotation = (vertices[0] - vertices[1]).angle_deg + if doc and arrow_name in doc.blocks: + dxfattribs.update( + { + "name": arrow_name, + "insert": vertices[0], + "rotation": rotation, + "xscale": size, + "yscale": size, + "zscale": size, + } + ) + # create a virtual block reference + insert = cast( + "Insert", factory.new("INSERT", dxfattribs=dxfattribs, doc=doc) + ) + yield from insert.virtual_entities() + else: # render standard arrows + yield from ARROWS.virtual_entities( + name=arrow_name, + insert=vertices[0], + size=size, + rotation=rotation, + dxfattribs=dxfattribs, + ) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/linetypes.py b/.venv/lib/python3.12/site-packages/ezdxf/render/linetypes.py new file mode 100644 index 0000000..de6a80a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/linetypes.py @@ -0,0 +1,21 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from typing import Iterable, Iterator +import ezdxf +from ezdxf.math import UVec +from ._linetypes import _LineTypeRenderer, LineSegment + +if ezdxf.options.use_c_ext: + try: + from ezdxf.acc.linetypes import _LineTypeRenderer # type: ignore + except ImportError: + pass + + +class LineTypeRenderer(_LineTypeRenderer): + def line_segments(self, vertices: Iterable[UVec]) -> Iterator[LineSegment]: + last = None + for vertex in vertices: + if last is not None: + yield from self.line_segment(last, vertex) + last = vertex diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/mesh.py b/.venv/lib/python3.12/site-packages/ezdxf/render/mesh.py new file mode 100644 index 0000000..282eea2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/mesh.py @@ -0,0 +1,1803 @@ +# Copyright (c) 2018-2022 Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Dict, + Iterable, + Iterator, + NamedTuple, + Optional, + Sequence, + TYPE_CHECKING, + Tuple, + Type, + TypeVar, + Union, +) +from typing_extensions import TypeAlias +from ezdxf.math import ( + BoundingBox, + Matrix44, + NULLVEC, + OCS, + UCS, + UVec, + Vec3, + area, + is_planar_face, + normal_vector_3p, + safe_normal_vector, + subdivide_face, + subdivide_ngons, +) + +if TYPE_CHECKING: + from ezdxf.entities import Polyface, Polymesh, Mesh, Solid3d + from ezdxf.eztypes import GenericLayoutType + +T = TypeVar("T") + + +class EdgeStat(NamedTuple): + """Named tuple of edge statistics.""" + + count: int # type: ignore + balance: int + + +Face: TypeAlias = Sequence[int] +Edge: TypeAlias = Tuple[int, int] +EdgeStats: TypeAlias = Dict[Edge, EdgeStat] + + +class MeshBuilderError(Exception): + pass + + +class NodeMergingError(MeshBuilderError): + pass + + +class MultipleMeshesError(MeshBuilderError): + pass + + +class DegeneratedPathError(MeshBuilderError): + pass + + +class NonManifoldMeshError(MeshBuilderError): + pass + + +def open_faces(faces: Iterable[Face]) -> Iterator[Face]: + """Yields all faces with more than two vertices as open faces + (first vertex index != last vertex index). + """ + for face in faces: + if len(face) < 3: + continue + if face[0] == face[-1]: + yield face[:-1] + else: + yield face + + +def normalize_faces( + faces: list[Sequence[int]], + *, + close=False, +) -> Iterator[Sequence[int]]: + """Removes duplicated vertices and returns closed or open faces according + the `close` argument. Returns only faces with at least 3 edges. + """ + for face in open_faces(faces): + new_face = [face[0]] + for index in face[1:]: + if new_face[-1] != index: + new_face.append(index) + if len(new_face) < 3: + continue + if close: + new_face.append(new_face[0]) + yield tuple(new_face) + + +def all_edges(faces: Iterable[Face]) -> Iterator[Edge]: + """Yields all face edges as int tuples.""" + for face in open_faces(faces): + yield from face_edges(face) + + +def face_edges(face: Face) -> Iterable[Edge]: + """Yields all edges of a single open face as int tuples.""" + size = len(face) + for index in range(size): + yield face[index], face[(index + 1) % size] + + +def get_edge_stats(faces: Iterable[Face]) -> EdgeStats: + """Returns the edge statistics. + + The Edge statistic contains for each edge `(a, b)` the :class:`EdgeStat` as + tuple `(count, balance)` where the vertex index `a` is always smaller than + the vertex index `b`. + + The edge count is how often this edge is used in faces as `(a, b)` or + `(b, a)` and the balance is the count of edge `(a, b)` minus the count of + edge `(b, a)` and should be 0 in "healthy" closed surfaces. + A balance not 0 indicates an error which may be double coincident faces or + mixed face vertex orders. + + """ + new_edge = EdgeStat(0, 0) + stats: EdgeStats = {} + for a, b in all_edges(faces): + edge = a, b + orientation = +1 + if a > b: + edge = b, a + orientation = -1 + # for all edges: count should be 2 and balance should be 0 + count, balance = stats.get(edge, new_edge) + stats[edge] = EdgeStat(count + 1, balance + orientation) + return stats + + +def estimate_face_normals_direction( + vertices: Sequence[Vec3], faces: Sequence[Face] +) -> float: + """Returns the estimated face-normals direction as ``float`` value + in the range [-1.0, 1.0] for a closed surface. + + This heuristic works well for simple convex hulls but struggles with + more complex structures like a torus (doughnut). + + A counter-clockwise (ccw) vertex arrangement is assumed but a + clockwise (cw) arrangement works too but the values are reversed. + + The closer the value to 1.0 (-1.0 for cw) the more likely all normals + pointing outwards from the surface. + + The closer the value to -1.0 (1.0 for cw) the more likely all normals + pointing inwards from the surface. + + """ + n_vertices = len(vertices) + if n_vertices == 0: + return 0.0 + + mesh_centroid = Vec3.sum(vertices) / n_vertices + count = 0 + direction_sum = 0.0 + for face in faces: + if len(face) < 3: + continue + try: + face_vertices = tuple(vertices[i] for i in face) + except IndexError: + continue + face_centroid = Vec3.sum(face_vertices) / len(face) + try: + face_normal = normal_vector_3p( + face_vertices[0], face_vertices[1], face_vertices[2] + ) + except ZeroDivisionError: + continue + try: + outward_vec = (face_centroid - mesh_centroid).normalize() + except ZeroDivisionError: + continue + direction_sum += face_normal.dot(outward_vec) + count += 1 + if count > 0: + return direction_sum / count + return 0.0 + + +def flip_face_normals( + faces: Sequence[Sequence[int]], +) -> Iterator[Sequence[int]]: + for face in faces: + yield tuple(reversed(face)) + + +def volume6(a: Vec3, b: Vec3, c: Vec3) -> float: + """ + Returns six times the volume of the tetrahedron determined by abc + and the origin (0, 0, 0). + The volume is positive if the origin is on the negative side of abc, + where the positive side is determined by the right-hand--rule. + So the volume is positive if the ccw normal to abc points outside the + tetrahedron. + + This code is taken from chull.c; see "Computational Geometry in C." + """ + return ( + a.z * (b.x * c.y - b.y * c.x) + + a.y * (b.z * c.x - b.x * c.z) + + a.x * (b.y * c.z - b.z * c.y) + ) + + +def area_3d(polygon: Sequence[Vec3]) -> float: + try: + ocs = OCS(safe_normal_vector(polygon)) + except ZeroDivisionError: + return 0.0 + return area(ocs.points_from_wcs(polygon)) + + +# Mesh Topology Analysis using the Euler Characteristic +# https://max-limper.de/publications/Euler/index.html + + +class MeshDiagnose: + def __init__(self, mesh: MeshBuilder): + self._mesh = mesh + self._edge_stats: EdgeStats = {} + self._bbox = BoundingBox() + self._face_normals: list[Vec3] = [] + + @property + def vertices(self) -> Sequence[Vec3]: + """Sequence of mesh vertices as :class:`~ezdxf.math.Vec3` instances""" + return self._mesh.vertices + + @property + def faces(self) -> Sequence[Face]: + """Sequence of faces as ``Sequence[int]``""" + return self._mesh.faces + + @property + def face_normals(self) -> Sequence[Vec3]: + """Returns all face normal vectors as sequence. The ``NULLVEC`` + instance is used as normal vector for degenerated faces. (cached data) + + """ + if len(self._face_normals) == 0: + self._face_normals = list(self._mesh.face_normals()) + return self._face_normals + + @property + def bbox(self) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` of the mesh. (cached data)""" + if not self._bbox.has_data: + self._bbox = self._mesh.bbox() + return self._bbox + + @property + def n_vertices(self) -> int: + """Returns the vertex count.""" + return len(self.vertices) + + @property + def n_faces(self) -> int: + """Returns the face count.""" + return len(self.faces) + + @property + def n_edges(self) -> int: + """Returns the unique edge count. (cached data)""" + return len(self.edge_stats) + + @property + def edge_stats(self) -> EdgeStats: + """Returns the edge statistics as a ``dict``. The dict-key is the edge + as tuple of two vertex indices `(a, b)` where `a` is always smaller than + `b`. The dict-value is an :class:`EdgeStat` tuple of edge count and edge + balance, see :class:`EdgeStat` for the definition of edge count and + edge balance. (cached data) + """ + if len(self._edge_stats) == 0: + self._edge_stats = get_edge_stats(self.faces) + return self._edge_stats + + @property + def euler_characteristic(self) -> int: + """Returns the Euler characteristic: + https://en.wikipedia.org/wiki/Euler_characteristic + + This number is always 2 for convex polyhedra. + """ + return self.n_vertices - self.n_edges + self.n_faces + + @property + def is_edge_balance_broken(self) -> bool: + """Returns ``True`` if the edge balance is broken, this indicates a + topology error for closed surfaces. A non-broken edge balance reflects + that each edge connects two faces, where the edge is clockwise oriented + in the first face and counter-clockwise oriented in the second face. + A broken edge balance indicates possible topology errors like mixed + face vertex orientations or a non-manifold mesh where an edge connects + more than two faces. (cached data) + + """ + return any(e.balance != 0 for e in self.edge_stats.values()) + + @property + def is_manifold(self) -> bool: + """Returns ``True`` if all edges have an edge count < 3. (cached data) + + A non-manifold mesh has edges with 3 or more connected faces. + + """ + return all(edge.count < 3 for edge in self.edge_stats.values()) + + @property + def is_closed_surface(self) -> bool: + """Returns ``True`` if the mesh has a closed surface. + This method does not require a unified face orientation. + If multiple separated meshes are present the state is only ``True`` if + **all** meshes have a closed surface. (cached data) + + Returns ``False`` for non-manifold meshes. + + """ + return all(edge.count == 2 for edge in self.edge_stats.values()) + + def total_edge_count(self) -> int: + """Returns the total edge count of all faces, shared edges are counted + separately for each face. In closed surfaces this count should be 2x + the unique edge count :attr:`n_edges`. (cached data) + """ + return sum(e.count for e in self.edge_stats.values()) + + def unique_edges(self) -> Iterable[Edge]: + """Yields the unique edges of the mesh as int 2-tuples. (cached data)""" + return self.edge_stats.keys() + + def estimate_face_normals_direction(self) -> float: + """Returns the estimated face-normals direction as ``float`` value + in the range [-1.0, 1.0] for a closed surface. + + This heuristic works well for simple convex hulls but struggles with + more complex structures like a torus (doughnut). + + A counter-clockwise (ccw) vertex arrangement for outward pointing faces + is assumed but a clockwise (cw) arrangement works too but the return + values are reversed. + + The closer the value to 1.0 (-1.0 for cw) the more likely all normals + pointing outwards from the surface. + + The closer the value to -1.0 (1.0 for cw) the more likely all normals + pointing inwards from the surface. + + There are no exact confidence values if all faces pointing outwards, + here some examples for surfaces created by :mod:`ezdxf.render.forms` + functions: + + - :func:`~ezdxf.render.forms.cube` returns 1.0 + - :func:`~ezdxf.render.forms.cylinder` returns 0.9992 + - :func:`~ezdxf.render.forms.sphere` returns 0.9994 + - :func:`~ezdxf.render.forms.cone` returns 0.9162 + - :func:`~ezdxf.render.forms.cylinder` with all hull faces pointing + outwards but caps pointing inwards returns 0.7785 but the + property :attr:`is_edge_balance_broken` returns ``True`` which + indicates the mixed vertex orientation + - and the estimation of 0.0469 for a :func:`~ezdxf.render.forms.torus` + is barely usable + + """ + return estimate_face_normals_direction(self.vertices, self.faces) + + def has_non_planar_faces(self) -> bool: + """Returns ``True`` if any face is non-planar.""" + return not all(is_planar_face(face) for face in self._mesh.faces_as_vertices()) + + def volume(self) -> float: + """Returns the volume of a closed surface or 0 otherwise. + + .. warning:: + + The face vertices have to be in counter-clockwise order, this + requirement is not checked by this method. + + The result is not correct for multiple separated meshes in a single + MeshBuilder object!!! + + """ + if self.is_closed_surface: + volume = 0.0 + for face in self._mesh.tessellation(3): + volume += volume6(face[0], face[1], face[2]) + return volume / 6.0 + return 0.0 + + def surface_area(self) -> float: + """Returns the surface area.""" + v = self.vertices + surface_area = 0.0 + for face in self._mesh.open_faces(): + polygon = [v[i] for i in face] + surface_area += area_3d(polygon) + return surface_area + + def centroid(self) -> Vec3: + """Returns the centroid of all vertices. (center of mass)""" + if self.n_vertices > 0: + return Vec3.sum(self.vertices) / self.n_vertices + return NULLVEC + + +class MeshBuilder: + """A simple Mesh builder. Stores a list of vertices and a faces list where + each face is a list of indices into the vertices list. + + The :meth:`render_mesh` method, renders the mesh into a DXF MESH entity. + The MESH entity supports ngons in AutoCAD, ngons are polygons with more + than 4 vertices. + + Can only create new meshes. + + """ + + def __init__(self) -> None: + self.vertices: list[Vec3] = [] + # face storage, each face is a tuple of vertex indices (v0, v1, v2, v3, ....) + self.faces: list[Sequence[int]] = [] + + def bbox(self) -> BoundingBox: + """Returns the :class:`~ezdxf.math.BoundingBox` of the mesh.""" + return BoundingBox(self.vertices) + + def copy(self): + """Returns a copy of mesh.""" + return self.from_builder(self) + + def diagnose(self) -> MeshDiagnose: + """Returns the :class:`MeshDiagnose` object for this mesh.""" + return MeshDiagnose(self) + + def get_face_vertices(self, index: int) -> Sequence[Vec3]: + """Returns the face `index` as sequence of :class:`~ezdxf.math.Vec3` + objects. + """ + vertices = self.vertices + return tuple(vertices[vi] for vi in self.faces[index]) + + def get_face_normal(self, index: int) -> Vec3: + """Returns the normal vector of the face `index` as :class:`~ezdxf.math.Vec3`, + returns the ``NULLVEC`` instance for degenerated faces. + """ + face = self.get_face_vertices(index) + try: + return safe_normal_vector(face) + except (ValueError, ZeroDivisionError): + return NULLVEC + + def face_normals(self) -> Iterator[Vec3]: + """Yields all face normals, yields the ``NULLVEC`` instance for degenerated + faces. + """ + for face in self.faces_as_vertices(): + try: + yield safe_normal_vector(face) + except (ValueError, ZeroDivisionError): + yield NULLVEC + + def faces_as_vertices(self) -> Iterator[list[Vec3]]: + """Yields all faces as list of vertices.""" + v = self.vertices + for face in self.faces: + yield [v[index] for index in face] + + def open_faces(self) -> Iterator[Face]: + """Yields all faces as sequence of integers where the first vertex + is not coincident with the last vertex. + """ + yield from open_faces(self.faces) + + def add_face(self, vertices: Iterable[UVec]) -> None: + """Add a face as vertices list to the mesh. A face requires at least 3 + vertices, each vertex is a ``(x, y, z)`` tuple or + :class:`~ezdxf.math.Vec3` object. The new vertex indices are stored as + face in the :attr:`faces` list. + + Args: + vertices: list of at least 3 vertices ``[(x1, y1, z1), (x2, y2, z2), + (x3, y3, y3), ...]`` + + """ + self.faces.append(self.add_vertices(vertices)) + + def add_vertices(self, vertices: Iterable[UVec]) -> Face: + """Add new vertices to the mesh, each vertex is a ``(x, y, z)`` tuple + or a :class:`~ezdxf.math.Vec3` object, returns the indices of the + `vertices` added to the :attr:`vertices` list. + + e.g. adding 4 vertices to an empty mesh, returns the indices + ``(0, 1, 2, 3)``, adding additional 4 vertices returns the indices + ``(4, 5, 6, 7)``. + + Args: + vertices: list of vertices, vertex as ``(x, y, z)`` tuple or + :class:`~ezdxf.math.Vec3` objects + + Returns: + tuple: indices of the `vertices` added to the :attr:`vertices` list + + """ + start_index = len(self.vertices) + self.vertices.extend(Vec3.generate(vertices)) + return tuple(range(start_index, len(self.vertices))) + + def add_mesh( + self, + vertices: Optional[list[Vec3]] = None, + faces: Optional[list[Face]] = None, + mesh=None, + ) -> None: + """Add another mesh to this mesh. + + A `mesh` can be a :class:`MeshBuilder`, :class:`MeshVertexMerger` or + :class:`~ezdxf.entities.Mesh` object or requires the attributes + :attr:`vertices` and :attr:`faces`. + + Args: + vertices: list of vertices, a vertex is a ``(x, y, z)`` tuple or + :class:`~ezdxf.math.Vec3` object + faces: list of faces, a face is a list of vertex indices + mesh: another mesh entity + + """ + if mesh is not None: + vertices = Vec3.list(mesh.vertices) + faces = mesh.faces + + if vertices is None: + raise ValueError("Requires vertices or another mesh.") + faces = faces or [] + indices = self.add_vertices(vertices) + + for face_vertices in open_faces(faces): + self.faces.append(tuple(indices[vi] for vi in face_vertices)) + + def render_mesh( + self, + layout: GenericLayoutType, + dxfattribs=None, + matrix: Optional[Matrix44] = None, + ucs: Optional[UCS] = None, + ): + """Render mesh as :class:`~ezdxf.entities.Mesh` entity into `layout`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + dxfattribs: dict of DXF attributes e.g. ``{'layer': 'mesh', 'color': 7}`` + matrix: transformation matrix of type :class:`~ezdxf.math.Matrix44` + ucs: transform vertices by :class:`~ezdxf.math.UCS` to :ref:`WCS` + + """ + dxfattribs = dict(dxfattribs) if dxfattribs else {} + vertices = self.vertices + if matrix is not None: + vertices = matrix.transform_vertices(vertices) + if ucs is not None: + vertices = ucs.points_to_wcs(vertices) # type: ignore + mesh = layout.add_mesh(dxfattribs=dxfattribs) + with mesh.edit_data() as data: + # data will be copied at setting in edit_data() + # ignore edges and creases! + data.vertices = list(vertices) + data.faces = list(self.faces) + return mesh + + def render_normals( + self, + layout: GenericLayoutType, + length: float = 1, + relative=True, + dxfattribs=None, + ): + """Render face normals as :class:`~ezdxf.entities.Line` entities into + `layout`, useful to check orientation of mesh faces. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + length: visual length of normal, use length < 0 to point normals in + opposite direction + relative: scale length relative to face size if ``True`` + dxfattribs: dict of DXF attributes e.g. ``{'layer': 'normals', 'color': 6}`` + + """ + dxfattribs = dict(dxfattribs) if dxfattribs else {} + for face in self.faces_as_vertices(): + count = len(face) + if count < 3: + continue + center = Vec3.sum(face) / count + try: + n = safe_normal_vector(face) + except ZeroDivisionError: + continue + if relative: + _length = (face[0] - center).magnitude * length + else: + _length = length + layout.add_line(center, center + n * _length, dxfattribs=dxfattribs) + + @classmethod + def from_mesh(cls: Type[T], other: Union[MeshBuilder, Mesh]) -> T: + """Create new mesh from other mesh as class method. + + Args: + other: `mesh` of type :class:`MeshBuilder` and inherited or DXF + :class:`~ezdxf.entities.Mesh` entity or any object providing + attributes :attr:`vertices`, :attr:`edges` and :attr:`faces`. + + """ + # just copy properties + mesh = cls() + assert isinstance(mesh, MeshBuilder) + mesh.add_mesh(mesh=other) + return mesh # type: ignore + + @classmethod + def from_polyface(cls: Type[T], other: Union[Polymesh, Polyface]) -> T: + """Create new mesh from a :class:`~ezdxf.entities.Polyface` or + :class:`~ezdxf.entities.Polymesh` object. + + """ + if other.dxftype() != "POLYLINE": + raise TypeError(f"Unsupported DXF type: {other.dxftype()}") + + mesh = cls() + assert isinstance(mesh, MeshBuilder) + if other.is_poly_face_mesh: + _, faces = other.indexed_faces() # type: ignore + for face in faces: + mesh.add_face(face.points()) + elif other.is_polygon_mesh: + vertices = other.get_mesh_vertex_cache() # type: ignore + for m in range(other.dxf.m_count - 1): + for n in range(other.dxf.n_count - 1): + mesh.add_face( + ( + vertices[m, n], + vertices[m, n + 1], + vertices[m + 1, n + 1], + vertices[m + 1, n], + ) + ) + else: + raise TypeError("Not a polymesh or polyface.") + return mesh # type: ignore + + def render_polyface( + self, + layout: GenericLayoutType, + dxfattribs=None, + matrix: Optional[Matrix44] = None, + ucs: Optional[UCS] = None, + ): + """Render mesh as :class:`~ezdxf.entities.Polyface` entity into + `layout`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + dxfattribs: dict of DXF attributes e.g. ``{'layer': 'mesh', 'color': 7}`` + matrix: transformation matrix of type :class:`~ezdxf.math.Matrix44` + ucs: transform vertices by :class:`~ezdxf.math.UCS` to :ref:`WCS` + + """ + dxfattribs = dict(dxfattribs) if dxfattribs else {} + polyface = layout.add_polyface(dxfattribs=dxfattribs) + t = MeshTransformer.from_builder(self) + if matrix is not None: + t.transform(matrix) + if ucs is not None: + t.transform(ucs.matrix) + polyface.append_faces( + t.tessellation(max_vertex_count=4), + dxfattribs=dxfattribs, + ) + return polyface + + def render_3dsolid(self, layout: GenericLayoutType, dxfattribs=None) -> Solid3d: + """Render mesh as :class:`~ezdxf.entities.Solid3d` entity into `layout`. + + This is an **experimental** feature to create simple 3DSOLID entities from + polyhedrons. + + The method supports closed and open shells. A 3DSOLID entity can contain + multiple shells. Separate the meshes beforehand by the method + :meth:`separate_meshes` if required. The normals vectors of all faces should + point outwards. Faces can have more than 3 vertices (ngons) but non-planar + faces and concave faces will cause problems in some CAD applications. The + method :meth:`mesh_tesselation` can help to break down the faces into triangles. + + Requires a valid DXF document for `layout` and DXF version R2000 or newer. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + dxfattribs: dict of DXF attributes e.g. ``{'layer': 'mesh', 'color': 7}`` + + Raises: + DXFValueError: valid DXF document required, if :attr:`layout.doc` is ``None`` + DXFVersionError: invalid DXF version + + .. versionadded:: 1.2.0 + + """ + from ezdxf.acis import api as acis + + dxfattribs = dict(dxfattribs) if dxfattribs else {} + solid3d = layout.add_3dsolid(dxfattribs=dxfattribs) + body = acis.body_from_mesh(self) + acis.export_dxf(solid3d, [body]) + return solid3d + + def render_3dfaces( + self, + layout: GenericLayoutType, + dxfattribs=None, + matrix: Optional[Matrix44] = None, + ucs: Optional[UCS] = None, + ): + """Render mesh as :class:`~ezdxf.entities.Face3d` entities into + `layout`. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + dxfattribs: dict of DXF attributes e.g. ``{'layer': 'mesh', 'color': 7}`` + matrix: transformation matrix of type :class:`~ezdxf.math.Matrix44` + ucs: transform vertices by :class:`~ezdxf.math.UCS` to :ref:`WCS` + + """ + dxfattribs = dict(dxfattribs) if dxfattribs else {} + t = MeshTransformer.from_builder(self) + if matrix is not None: + t.transform(matrix) + if ucs is not None: + t.transform(ucs.matrix) + for face in t.tessellation(max_vertex_count=4): + layout.add_3dface(face, dxfattribs=dxfattribs) + + @classmethod + def from_builder(cls: Type[T], other: MeshBuilder) -> T: + """Create new mesh from other mesh builder, faster than + :meth:`from_mesh` but supports only :class:`MeshBuilder` and inherited + classes. + + """ + # just copy properties + mesh = cls() + assert isinstance(mesh, MeshBuilder) + + # DO NOT COPY CACHES! + mesh.vertices = list(other.vertices) + mesh.faces = list(other.faces) + return mesh # type: ignore + + def merge_coplanar_faces(self, passes: int = 1) -> MeshTransformer: + """Returns a new :class:`MeshBuilder` object with merged adjacent + coplanar faces. + + The faces have to share at least two vertices and have to have the + same clockwise or counter-clockwise vertex order. + + The current implementation is not very capable! + + """ + mesh = self + for _ in range(passes): + mesh = _merge_adjacent_coplanar_faces(mesh.vertices, mesh.faces) + return MeshTransformer.from_builder(mesh) + + def subdivide(self, level: int = 1, quads=True) -> MeshTransformer: + """Returns a new :class:`MeshTransformer` object with all faces subdivided. + + Args: + level: subdivide levels from 1 to max of 5 + quads: create quad faces if ``True`` else create triangles + """ + mesh = self + level = min(int(level), 5) + while level > 0: + mesh = _subdivide(mesh, quads) + level -= 1 + return MeshTransformer.from_builder(mesh) + + def optimize_vertices(self, precision: int = 6) -> MeshTransformer: + """Returns a new mesh with optimized vertices. Coincident vertices are + merged together and all faces are open faces (first vertex != last + vertex). Uses internally the :class:`MeshVertexMerger` class to merge + vertices. + """ + mesh = MeshVertexMerger(precision=precision) + mesh.add_mesh(mesh=self) + return MeshTransformer.from_builder(mesh) + + def subdivide_ngons(self, max_vertex_count=4) -> Iterator[Sequence[Vec3]]: + """Yields all faces as sequence of :class:`~ezdxf.math.Vec3` instances, + where all ngons which have more than `max_vertex_count` vertices gets + subdivided. + In contrast to the :meth:`tessellation` method, creates this method a + new vertex in the centroid of the face. This can create a more regular + tessellation but only works reliable for convex faces! + """ + yield from subdivide_ngons(self.faces_as_vertices(), max_vertex_count) + + def tessellation(self, max_vertex_count: int = 4) -> Iterator[Sequence[Vec3]]: + """Yields all faces as sequence of :class:`~ezdxf.math.Vec3` instances, + each face has no more vertices than the given `max_vertex_count`. This + method uses the "ear clipping" algorithm which works with concave faces + too and does not create any additional vertices. + """ + from ezdxf.math.triangulation import mapbox_earcut_3d + + for face in self.faces_as_vertices(): + if len(face) <= max_vertex_count: + yield face + else: + yield from mapbox_earcut_3d(face) + + def mesh_tessellation(self, max_vertex_count: int = 4) -> MeshTransformer: + """Returns a new :class:`MeshTransformer` instance, where each face has + no more vertices than the given `max_vertex_count`. + + The `fast` mode uses a shortcut for faces with less than 6 vertices + which may not work for concave faces! + """ + mesh = MeshVertexMerger() + for face in self.tessellation(max_vertex_count=max_vertex_count): + mesh.add_face(face) + return MeshTransformer.from_builder(mesh) + + def flip_normals(self) -> None: + """Flips the normals of all faces by reversing the vertex order inplace.""" + self.faces = list(flip_face_normals(self.faces)) + + def separate_meshes(self) -> list[MeshTransformer]: + """A single :class:`MeshBuilder` instance can store multiple separated + meshes. This function returns this separated meshes as multiple + :class:`MeshTransformer` instances. + """ + return list(separate_meshes(self)) + + def normalize_faces(self) -> None: + """Removes duplicated vertex indices from faces and stores all faces as + open faces, where the last vertex is not coincident with the first + vertex. + """ + self.faces = list(normalize_faces(self.faces, close=False)) + + def face_orientation_detector(self, reference: int = 0) -> FaceOrientationDetector: + """Returns a :class:`FaceOrientationDetector` or short `fod` instance. + The forward orientation is defined by the `reference` face which is + 0 by default. + + The `fod` can check if all faces are reachable from the reference face + and if all faces have the same orientation. The `fod` can be reused to + unify the face orientation of the mesh. + + """ + return FaceOrientationDetector(self, reference=reference) + + def unify_face_normals( + self, *, fod: Optional[FaceOrientationDetector] = None + ) -> MeshTransformer: + """Returns a new :class:`MeshTransformer` object with unified + face normal vectors of all faces. + The forward direction (not necessarily outwards) is defined by the + face-normals of the majority of the faces. + This function can not process non-manifold meshes (more than two faces + are connected by a single edge) or multiple disconnected meshes in a + single :class:`MeshBuilder` object. + + It is possible to pass in an existing :class:`FaceOrientationDetector` + instance as argument `fod`. + + Raises: + NonManifoldError: non-manifold mesh + MultipleMeshesError: the :class:`MeshBuilder` object contains multiple disconnected meshes + + """ + return unify_face_normals_by_majority(self, fod=fod) + + def unify_face_normals_by_reference( + self, + reference: int = 0, + *, + force_outwards=False, + fod: Optional[FaceOrientationDetector] = None, + ) -> MeshTransformer: + """Returns a new :class:`MeshTransformer` object with unified + face normal vectors of all faces. + The forward direction (not necessarily outwards) is defined by the + reference face, which is the first face of the `mesh` by default. + This function can not process non-manifold + meshes (more than two faces are connected by a single edge) or multiple + disconnected meshes in a single :class:`MeshBuilder` object. + + The outward direction of all face normals can be forced by stetting + the argument `force_outwards` to ``True`` but this works only for closed + surfaces, and it's time-consuming! + + It is not possible to check for a closed surface as long the face normal + vectors are not unified. But it can be done afterward by the attribute + :meth:`MeshDiagnose.is_closed_surface` to see if the result is + trustworthy. + + It is possible to pass in an existing :class:`FaceOrientationDetector` + instance as argument `fod`. + + Args: + reference: index of the reference face + force_outwards: forces face-normals to point outwards, this works + only for closed surfaces, and it's time-consuming! + fod: :class:`FaceOrientationDetector` instance + + Raises: + ValueError: non-manifold mesh or the :class:`MeshBuilder` object + contains multiple disconnected meshes + + """ + mesh = unify_face_normals_by_reference(self, reference=reference, fod=fod) + if force_outwards: + _force_face_normals_pointing_outwards(mesh, reference) + return mesh + + +class MeshTransformer(MeshBuilder): + """A mesh builder with inplace transformation support.""" + + def transform(self, matrix: Matrix44): + """Transform mesh inplace by applying the transformation `matrix`. + + Args: + matrix: 4x4 transformation matrix as :class:`~ezdxf.math.Matrix44` + object + + """ + self.vertices = list(matrix.transform_vertices(self.vertices)) + return self + + def translate(self, dx: Union[float, UVec] = 0, dy: float = 0, dz: float = 0): + """Translate mesh inplace. + + Args: + dx: translation in x-axis or translation vector + dy: translation in y-axis + dz: translation in z-axis + + """ + if isinstance(dx, (float, int)): + t = Vec3(dx, dy, dz) + else: + t = Vec3(dx) + self.vertices = [t + v for v in self.vertices] + return self + + def scale(self, sx: float = 1, sy: float = 1, sz: float = 1): + """Scale mesh inplace. + + Args: + sx: scale factor for x-axis + sy: scale factor for y-axis + sz: scale factor for z-axis + + """ + self.vertices = [Vec3(x * sx, y * sy, z * sz) for x, y, z in self.vertices] + return self + + def scale_uniform(self, s: float): + """Scale mesh uniform inplace. + + Args: + s: scale factor for x-, y- and z-axis + + """ + self.vertices = [v * s for v in self.vertices] + return self + + def rotate_x(self, angle: float): + """Rotate mesh around x-axis about `angle` inplace. + + Args: + angle: rotation angle in radians + + """ + self.vertices = list(Matrix44.x_rotate(angle).transform_vertices(self.vertices)) + return self + + def rotate_y(self, angle: float): + """Rotate mesh around y-axis about `angle` inplace. + + Args: + angle: rotation angle in radians + + """ + self.vertices = list(Matrix44.y_rotate(angle).transform_vertices(self.vertices)) + return self + + def rotate_z(self, angle: float): + """Rotate mesh around z-axis about `angle` inplace. + + Args: + angle: rotation angle in radians + + """ + self.vertices = list(Matrix44.z_rotate(angle).transform_vertices(self.vertices)) + return self + + def rotate_axis(self, axis: UVec, angle: float): + """Rotate mesh around an arbitrary axis located in the origin (0, 0, 0) + about `angle`. + + Args: + axis: rotation axis as Vec3 + angle: rotation angle in radians + + """ + self.vertices = list( + Matrix44.axis_rotate(axis, angle).transform_vertices(self.vertices) + ) + return self + + +def _subdivide(mesh, quads=True) -> MeshVertexMerger: + """Returns a new :class:`MeshVertexMerger` object with subdivided faces + and edges. + + Args: + quads: create quad faces if ``True`` else create triangles + + """ + new_mesh = MeshVertexMerger() + for vertices in mesh.faces_as_vertices(): + if len(vertices) < 3: + continue + for face in subdivide_face(vertices, quads): + new_mesh.add_face(face) + return new_mesh + + +class MeshVertexMerger(MeshBuilder): + """Subclass of :class:`MeshBuilder` + + Mesh with unique vertices and no doublets, but needs extra memory for + bookkeeping. + + :class:`MeshVertexMerger` creates a key for every vertex by rounding its + components by the Python :func:`round` function and a given `precision` + value. Each vertex with the same key gets the same vertex index, which is + the index of first vertex with this key, so all vertices with the same key + will be located at the location of this first vertex. If you want an average + location of all vertices with the same key use the + :class:`MeshAverageVertexMerger` class. + + Args: + precision: floating point precision for vertex rounding + + """ + + # can not support vertex transformation + def __init__(self, precision: int = 6): + """ + Args: + precision: floating point precision for vertex rounding + + """ + super().__init__() + self.ledger: dict[Vec3, int] = {} + self.precision: int = precision + + def add_vertices(self, vertices: Iterable[UVec]) -> Face: + """Add new `vertices` only, if no vertex with identical (x, y, z) + coordinates already exist, else the index of the existing vertex is + returned as index of the added vertices. + + Args: + vertices: list of vertices, vertex as (x, y, z) tuple or + :class:`~ezdxf.math.Vec3` objects + + Returns: + indices of the added `vertices` + + """ + indices = [] + precision = self.precision + for vertex in Vec3.generate(vertices): + key = vertex.round(precision) + try: + indices.append(self.ledger[key]) + except KeyError: + index = len(self.vertices) + self.vertices.append(vertex) + self.ledger[key] = index + indices.append(index) + return tuple(indices) + + def index(self, vertex: UVec) -> int: + """Get index of `vertex`, raises :class:`IndexError` if not found. + + Args: + vertex: ``(x, y, z)`` tuple or :class:`~ezdxf.math.Vec3` object + + (internal API) + """ + try: + return self.ledger[Vec3(vertex).round(self.precision)] + except KeyError: + raise IndexError(f"Vertex {str(vertex)} not found.") + + @classmethod + def from_builder(cls, other: MeshBuilder) -> MeshVertexMerger: + """Create new mesh from other mesh builder.""" + # rebuild from scratch to create a valid ledger + return cls.from_mesh(other) + + +class MeshAverageVertexMerger(MeshBuilder): + """Subclass of :class:`MeshBuilder` + + Mesh with unique vertices and no doublets, but needs extra memory for + bookkeeping and runtime for calculation of average vertex location. + + :class:`MeshAverageVertexMerger` creates a key for every vertex by rounding + its components by the Python :func:`round` function and a given `precision` + value. Each vertex with the same key gets the same vertex index, which is the + index of first vertex with this key, the difference to the + :class:`MeshVertexMerger` class is the calculation of the average location + for all vertices with the same key, this needs extra memory to keep track of + the count of vertices for each key and extra runtime for updating the vertex + location each time a vertex with an existing key is added. + + Args: + precision: floating point precision for vertex rounding + + """ + + # can not support vertex transformation + def __init__(self, precision: int = 6): + super().__init__() + self.ledger: dict[ + Vec3, tuple[int, int] + ] = {} # each key points to a tuple (vertex index, vertex count) + self.precision: int = precision + + def add_vertices(self, vertices: Iterable[UVec]) -> Face: + """Add new `vertices` only, if no vertex with identical ``(x, y, z)`` + coordinates already exist, else the index of the existing vertex is + returned as index of the added vertices. + + Args: + vertices: list of vertices, vertex as ``(x, y, z)`` tuple or + :class:`~ezdxf.math.Vec3` objects + + Returns: + tuple: indices of the `vertices` added to the + :attr:`~MeshBuilder.vertices` list + + """ + indices = [] + precision = self.precision + for vertex in Vec3.generate(vertices): + key = vertex.round(precision) + try: + index, count = self.ledger[key] + except KeyError: # new key + index = len(self.vertices) + self.vertices.append(vertex) + self.ledger[key] = (index, 1) + else: # update key entry + # calculate new average location + average = (self.vertices[index] * count) + vertex + count += 1 + # update vertex location + self.vertices[index] = average / count + # update ledger + self.ledger[key] = (index, count) + indices.append(index) + return tuple(indices) + + def index(self, vertex: UVec) -> int: + """Get index of `vertex`, raises :class:`IndexError` if not found. + + Args: + vertex: ``(x, y, z)`` tuple or :class:`~ezdxf.math.Vec3` object + + (internal API) + """ + try: + return self.ledger[Vec3(vertex).round(self.precision)][0] + except KeyError: + raise IndexError(f"Vertex {str(vertex)} not found.") + + @classmethod + def from_builder(cls, other: MeshBuilder) -> MeshAverageVertexMerger: + """Create new mesh from other mesh builder.""" + # rebuild from scratch to create a valid ledger + return cls.from_mesh(other) + + +class _XFace: + __slots__ = ("fingerprint", "indices", "_orientation") + + def __init__(self, indices: Face): + self.fingerprint: int = hash(indices) + self.indices: Face = indices + self._orientation: Vec3 = VEC3_SENTINEL + + def orientation(self, vertices: Sequence[Vec3], precision: int = 4) -> Vec3: + if self._orientation is VEC3_SENTINEL: + orientation = NULLVEC + v0, v1, *v = [vertices[i] for i in self.indices] + for v2 in v: + try: + orientation = normal_vector_3p(v0, v1, v2).round(precision) + break + except ZeroDivisionError: + continue + self._orientation = orientation + return self._orientation + + +def _merge_adjacent_coplanar_faces( + vertices: list[Vec3], faces: list[Face], precision: int = 4 +) -> MeshVertexMerger: + oriented_faces: dict[Vec3, list[_XFace]] = {} + extended_faces: list[_XFace] = [] + for face in faces: + if len(face) < 3: + raise ValueError("found invalid face count < 3") + xface = _XFace(face) + extended_faces.append(xface) + oriented_faces.setdefault(xface.orientation(vertices, precision), []).append( + xface + ) + + mesh = MeshVertexMerger() + done = set() + for xface in extended_faces: + if xface.fingerprint in done: + continue + done.add(xface.fingerprint) + face = xface.indices + orientation = xface.orientation(vertices, precision) + parallel_faces = oriented_faces[orientation] + face_set = set(face) + for parallel_face in parallel_faces: + if parallel_face.fingerprint in done: + continue + common_vertices = face_set.intersection(set(parallel_face.indices)) + # connection by at least 2 vertices required: + if len(common_vertices) > 1: + if len(common_vertices) == len(parallel_face.indices): + face = merge_full_patch(face, parallel_face.indices) + else: + try: + face = merge_connected_paths(face, parallel_face.indices) + except (NodeMergingError, DegeneratedPathError): + continue + done.add(parallel_face.fingerprint) + face_set = set(face) + v0 = list(remove_colinear_face_vertices([vertices[i] for i in face])) + mesh.add_face(v0) + return mesh + + +VEC3_SENTINEL = Vec3(0, 0, 0) + + +def remove_colinear_face_vertices(vertices: Sequence[Vec3]) -> Iterator[Vec3]: + def get_direction(v1: Vec3, v2: Vec3): + return (v2 - v1).normalize() + + if len(vertices) < 3: + yield from vertices + return + + # remove duplicated vertices + _vertices: list[Vec3] = [vertices[0]] + for v in vertices[1:]: + if not v.isclose(_vertices[-1]): + _vertices.append(v) + + if len(_vertices) < 3: + if len(_vertices) == 1: + _vertices.append(_vertices[0]) + yield from _vertices + return + + start = _vertices[0] + prev_vertex = VEC3_SENTINEL + current_direction = VEC3_SENTINEL + start_index = 0 + + # find start direction + yield start + while current_direction is VEC3_SENTINEL: + start_index += 1 + try: + prev_vertex = vertices[start_index] + except IndexError: + yield prev_vertex + return + current_direction = get_direction(start, prev_vertex) + + yielded_anything = False + _vertices.append(start) + for vertex in _vertices[start_index:]: + try: + if get_direction(start, vertex).isclose(current_direction): + prev_vertex = vertex + continue + except ZeroDivisionError: + continue + yield prev_vertex + yielded_anything = True + start = prev_vertex + current_direction = get_direction(start, vertex) + prev_vertex = vertex + + if not yielded_anything: + yield _vertices[-2] # last vertex + + +def merge_connected_paths(p1: Sequence[int], p2: Sequence[int]) -> Sequence[int]: + def build_nodes(p: Sequence[int]): + nodes = {e1: e2 for e1, e2 in zip(p, p[1:])} + nodes[p[-1]] = p[0] + return nodes + + current_path = build_nodes(p1) + other_path = build_nodes(p2) + current_node = p1[0] + finish = p1[0] + connected_path = [current_node] + while True: + try: + next_node = current_path[current_node] + except KeyError: + raise NodeMergingError + if next_node in other_path: + current_path, other_path = other_path, current_path + if next_node == finish: + break + current_node = next_node + if current_node in connected_path: + # node duplication is an error, e.g. two path are only connected + # by one node: + raise NodeMergingError + connected_path.append(current_node) + + if len(connected_path) < 3: + raise DegeneratedPathError + return connected_path + + +def merge_full_patch(path: Sequence[int], patch: Sequence[int]): + count = len(path) + new_path = [] + for pos, node in enumerate(path): + prev = path[pos - 1] + succ = path[(pos + 1) % count] + if prev in patch and succ in patch: + continue + new_path.append(node) + return new_path + + +class Lump: + def __init__(self, face: Face): + self.edges: set[Edge] = set() + self.faces: list[Face] = [face] + for a, b in face_edges(face): + # sort vertex indices to guarantee: edge a,b == edge b,a + self.edges.add((a, b) if a <= b else (b, a)) + + def is_connected(self, other: Lump) -> bool: + return not self.edges.isdisjoint(other.edges) + + def merge(self, other: Lump): + self.faces.extend(other.faces) + self.edges.update(other.edges) + + +def merge_lumps(lumps: Iterable[Lump]) -> list[Lump]: + merged_lumps = _merge_lumps(lumps) + prior_len = 0 + while 1 < len(merged_lumps) != prior_len: + prior_len = len(merged_lumps) + merged_lumps = _merge_lumps(merged_lumps) + return merged_lumps + + +def _merge_lumps(lumps: Iterable[Lump]) -> list[Lump]: + merged_lumps: list[Lump] = [] + for lump in lumps: + for base in merged_lumps: + if lump.is_connected(base): + base.merge(lump) + break + else: + merged_lumps.append(lump) + return merged_lumps + + +def separate_meshes(m: MeshBuilder) -> Iterator[MeshTransformer]: + """Returns the separated meshes in a single :class:`MeshBuilder` instance + as multiple :class:`MeshTransformer` instances. + """ + # At the beginning each face is a separated lump and all connected faces + # should be merged: + disconnected_lumps = list(merge_lumps(Lump(face) for face in open_faces(m.faces))) + if len(disconnected_lumps) > 1: + vertices = m.vertices + # create new separated meshes: + for lump in disconnected_lumps: + mesh = MeshVertexMerger() + for face in lump.faces: + mesh.add_face(vertices[i] for i in face) + yield MeshTransformer.from_builder(mesh) + else: + yield MeshTransformer.from_builder(m) + + +def have_away_pointing_normals(f0: Sequence[Vec3], f1: Sequence[Vec3]) -> bool: + """Returns ``True`` if the normals of the two faces are pointing + away from the center of the two faces. + + .. warning:: + + This does not work for any arbitrary face pair! + + """ + c0 = Vec3.sum(f0) / len(f0) + c1 = Vec3.sum(f1) / len(f1) + n0 = normal_vector_3p(f0[0], f0[1], f0[2]) * 0.5 + n1 = normal_vector_3p(f1[0], f1[1], f1[2]) * 0.5 + e0 = c0 + n0 + e1 = c1 + n1 + # distance of centroids + d0 = c0.distance(c1) + # distance of normal end points + d1 = e0.distance(e1) + return d1 > d0 + + +def face_normals_after_transformation(m: Matrix44) -> bool: + """Returns the state of face-normals of the unit-cube after the + transformation `m` was applied. + + - ``True``: face-normals pointing outwards + - ``False``: face-normals pointing inwards + + The state before the transformation is outward-pointing face-normals. + + """ + from .forms import cube + + unit_cube = cube(True).transform(m) + bottom, _, _, _, _, top = unit_cube.faces_as_vertices() + # it is not necessary to check all 3 axis! + return have_away_pointing_normals(bottom, top) + + +def _make_edge_mapping(faces: Iterable[Face]) -> dict[Edge, list[Face]]: + mapping: dict[Edge, list[Face]] = {} + for face in faces: + for edge in face_edges(face): + mapping.setdefault(edge, []).append(face) + return mapping + + +class FaceOrientationDetector: + """ + Helper class for face orientation and face normal vector detection. Use the + method :meth:`MeshBuilder.face_orientation_detector` to create an instance. + + The face orientation detector classifies the faces of a mesh by their + forward or backward orientation. + The forward orientation is defined by a reference face, which is the first + face of the mesh by default and this orientation is not necessarily outwards. + + This class has some overlapping features with :class:`MeshDiagnose` but it + has a longer setup time and needs more memory than :class:`MeshDiagnose`. + + Args: + mesh: source mesh as :class:`MeshBuilder` object + reference: index of the reference face + + """ + + def __init__(self, mesh: MeshBuilder, reference: int = 0): + self._mesh = mesh + self.edge_mapping: dict[Edge, list[Face]] = _make_edge_mapping(mesh.faces) + self.reference = reference + self.is_manifold = True # 2-manifold is meant + self.forward: dict[int, Face] = dict() + self.backward: dict[int, Face] = dict() + self.classify_faces(reference) + + @property + def has_uniform_face_normals(self) -> bool: + """Returns ``True`` if all reachable faces are forward oriented + according to the reference face. + """ + return len(self.backward) == 0 + + @property + def all_reachable(self) -> bool: + """Returns ``True`` if all faces are reachable from the reference face + same as property :attr:`is_single_mesh`. + """ + return len(self._mesh.faces) == sum(self.count) + + @property + def is_single_mesh(self) -> bool: + """Returns ``True`` if only a single mesh is present same as property + :attr:`all_reachable`. + """ + return self.all_reachable + + @property + def count(self) -> tuple[int, int]: + """Returns the count of forward and backward oriented faces.""" + return len(self.forward), len(self.backward) + + @property + def forward_faces(self) -> Iterator[Face]: + """Yields all forward oriented faces.""" + return iter(self.forward.values()) + + @property + def backward_faces(self) -> Iterator[Face]: + """Yields all backward oriented faces.""" + return iter(self.backward.values()) + + def classify_faces(self, reference: int = 0) -> None: + """Detect the forward and backward oriented faces. + + The forward and backward orientation has to be defined by a `reference` + face. + """ + + def add_forward(f: Face): + forward[id(f)] = f + + def add_backward(f: Face): + backward[id(f)] = f + + def add_face_to_process(f: Face, orientation: bool): + key = id(f) + if key not in forward and key not in backward: # unprocessed face! + process_faces.append((f, orientation)) + + def add_adjacent_faces_to_process_queue(f: Face, orientation: bool): + for edge in face_edges(f): + # find adjacent faces at this edge with same edge orientation: + linked_faces = edge_mapping[edge] + if len(linked_faces) > 1: + # these faces are backward oriented faces: + for linked_face in linked_faces: + if linked_face is f: # skip legit current face + continue + add_face_to_process(linked_face, not orientation) + + # find all adjacent faces at this edge with reversed edges: + try: + linked_faces = edge_mapping[edge[1], edge[0]] + except KeyError: + # open surface or backward oriented faces present + continue + if len(linked_faces) == 1: + add_face_to_process(linked_faces[0], orientation) + else: # non-manifold mesh + # none of the linked face is processed! + self.is_manifold = False + + self.reference = int(reference) + self.is_manifold = True + edge_mapping = self.edge_mapping + forward: dict[int, Face] = dict() + backward: dict[int, Face] = dict() + # the reference face defines the forward orientation + process_faces: list[tuple[Face, bool]] = [(self._mesh.faces[reference], True)] + while len(process_faces): + # current face and orientation, True = forward, False = backward + face, face_orientation = process_faces.pop(0) + if face_orientation: + add_forward(face) + else: + add_backward(face) + add_adjacent_faces_to_process_queue(face, face_orientation) + + self.forward = forward + self.backward = backward + + @property + def is_closed_surface(self) -> bool: + """Returns ``True`` if the mesh has a closed surface. + This method does not require a unified face orientation. + If multiple separated meshes are present the state is only ``True`` if + **all** meshes have a closed surface. + + Returns ``False`` for non-manifold meshes. + + """ + if not self.is_manifold: + return False + empty: list[Face] = [] + edge_mapping = self.edge_mapping + # For a closed surface all edges have to connect exact 2 faces. + for edge in edge_mapping.keys(): + forward_connected_faces = edge_mapping.get(edge, empty) + reversed_edge = edge[1], edge[0] + backward_connected_faces = edge_mapping.get(reversed_edge, empty) + if len(forward_connected_faces) + len(backward_connected_faces) != 2: + return False + return True + + def is_reference_face_pointing_outwards(self) -> bool: + """Returns ``True`` if the normal vector of the reference face is + pointing outwards. This works only for meshes with unified faces which + represent a closed surfaces, and it's a time-consuming calculation! + + """ + from ezdxf.math import is_face_normal_pointing_outwards + + faces = list(self._mesh.faces_as_vertices()) + reference_face = faces[self.reference] + return is_face_normal_pointing_outwards(faces, reference_face) + + +def unify_face_normals_by_reference( + mesh: MeshBuilder, + *, + fod: Optional[FaceOrientationDetector] = None, + reference: int = 0, +) -> MeshTransformer: + """Unifies the orientation of all faces of a :class:`MeshBuilder` object. + The forward orientation is defined by a reference face, which is the first + face of the `mesh` by default. This function can not process non-manifold + meshes (more than two faces are connected by a single edge) or multiple + disconnected meshes in a single :class:`MeshBuilder` object. + Returns always a copy of the source `mesh` as :class:`MeshTransformer` + object. + + Args: + mesh: source :class:`MeshBuilder` object + fod: an already created :class:`FaceOrientationDetector` + instance or ``None`` to create one internally. + reference: index of the reference face for the internally created + :class:`FaceOrientationDetector` instance + + Raises: + NonManifoldError: non-manifold mesh + MultipleMeshesError: :class:`MeshBuilder` object contains multiple + disconnected meshes + + """ + if fod is None: + fod = FaceOrientationDetector(mesh, reference) + + def backward_selector(detector: FaceOrientationDetector): + return detector.backward + + return _unify_face_normals(mesh, fod, backward_selector) + + +def unify_face_normals_by_majority( + mesh: MeshBuilder, + *, + fod: Optional[FaceOrientationDetector] = None, +) -> MeshTransformer: + """Unifies the orientation of all faces of a :class:`MeshBuilder` object. + The forward orientation is defined by the orientation of the majority of + the faces. + This function can not process non-manifold meshes (more than two faces are + connected by a single edge) or multiple disconnected meshes in a single + :class:`MeshBuilder` object. + Returns always a copy of the source `mesh` as :class:`MeshTransformer` + object. + + Args: + mesh: source :class:`MeshBuilder` object + fod: an already created :class:`FaceOrientationDetector` + instance or ``None`` to create one internally. + + Raises: + NonManifoldError: non-manifold mesh + MultipleMeshesError: :class:`MeshBuilder` object contains multiple + disconnected meshes + + """ + if fod is None: + fod = FaceOrientationDetector(mesh) + + def backward_selector(detector: FaceOrientationDetector): + count0, count1 = detector.count + return detector.backward if count0 >= count1 else detector.forward + + return _unify_face_normals(mesh, fod, backward_selector) + + +def _unify_face_normals( + mesh: MeshBuilder, + fod: FaceOrientationDetector, + backward_selector, +) -> MeshTransformer: + """Unifies all faces of a MeshBuilder. The backward_selector() function + returns the face ledger which represents the backward oriented faces. + """ + if not fod.is_manifold: + raise NonManifoldMeshError("non-manifold mesh") + if not fod.all_reachable: + raise MultipleMeshesError( + f"not all faces are reachable from reference face #{fod.reference}" + ) + + new_mesh = MeshTransformer() + new_mesh.vertices = list(mesh.vertices) + if not fod.has_uniform_face_normals: + backward = backward_selector(fod) + faces = [] + for face in mesh.faces: + if id(face) in backward: + faces.append(tuple(reversed(face))) + else: + faces.append(tuple(face)) + new_mesh.faces = faces # type: ignore + else: + new_mesh.faces = list(mesh.faces) + return new_mesh + + +def _force_face_normals_pointing_outwards( + mesh: MeshBuilder, reference: int = 0 +) -> None: + """Detect the orientation of the reference face and flip all face normals + if required. + + Requirements: all face normals have to be unified and the mesh has a closed + surface + + """ + from ezdxf.math import is_face_normal_pointing_outwards + + faces = list(mesh.faces_as_vertices()) + reference_face = faces[reference] + if not is_face_normal_pointing_outwards(faces, reference_face): + mesh.flip_normals() + + +def normalize_mesh(mesh: MeshBuilder) -> MeshTransformer: + """Returns a new mesh with these properties: + + - one mesh: removes all meshes except the first mesh starting at the + first face + - optimized vertices: merges shared vertices + - normalized faces: removes duplicated face vertices and faces with less + than 3 vertices + - open faces: all faces are open faces where first vertex != last vertex + - unified face-orientation: all faces have the same orientation (ccw or cw) + - ccw face-orientation: all face-normals are pointing outwards if the + mesh has a closed surface + + Raises: + NonManifoldMeshError: non-manifold mesh + + """ + new_mesh = mesh.optimize_vertices() + new_mesh.normalize_faces() + fod = new_mesh.face_orientation_detector(reference=0) + + if not fod.is_manifold: + raise NonManifoldMeshError("non-manifold mesh") + + if not fod.all_reachable: # extract first mesh + new_mesh = list(separate_meshes(new_mesh))[0] + fod = new_mesh.face_orientation_detector(reference=0) + + if not fod.has_uniform_face_normals: + new_mesh = unify_face_normals_by_reference(new_mesh, fod=fod) + fod = new_mesh.face_orientation_detector() + + if fod.is_closed_surface and not fod.is_reference_face_pointing_outwards(): + new_mesh.flip_normals() + return new_mesh diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/mleader.py b/.venv/lib/python3.12/site-packages/ezdxf/render/mleader.py new file mode 100644 index 0000000..93b73cd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/mleader.py @@ -0,0 +1,1637 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Any, + Iterable, + Iterator, + Optional, + TYPE_CHECKING, + Union, + cast, +) +import abc +import math +import logging +import enum +from collections import defaultdict +from dataclasses import dataclass + +from ezdxf import colors +from ezdxf.math import ( + BoundingBox, + Matrix44, + NULLVEC, + OCS, + UCS, + UVec, + Vec2, + Vec3, + X_AXIS, + Z_AXIS, + fit_points_to_cad_cv, + is_point_left_of_line, +) +from ezdxf.entities import factory +from ezdxf.lldxf import const +from ezdxf.proxygraphic import ProxyGraphic +from ezdxf.render.arrows import ARROWS, arrow_length +from ezdxf.tools import text_size, text as text_tools +from ezdxf.entities.mleader import ( + AttribData, + BlockData, + LeaderData, + LeaderLine, + MLeaderContext, + MLeaderStyle, + MTextData, + MultiLeader, + acdb_mleader_style, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.layouts import BlockLayout + from ezdxf.entities import ( + DXFGraphic, + Insert, + MText, + Spline, + Textstyle, + ) + +__all__ = [ + "virtual_entities", + "MultiLeaderBuilder", + "MultiLeaderMTextBuilder", + "MultiLeaderBlockBuilder", + "ConnectionSide", + "HorizontalConnection", + "VerticalConnection", + "LeaderType", + "TextAlignment", + "BlockAlignment", +] + +logger = logging.getLogger("ezdxf") + +# How to render MLEADER: https://atlight.github.io/formats/dxf-leader.html +# DXF reference: +# http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-72D20B8C-0F5E-4993-BEB7-0FCF94F32BE0 + +# AutoCAD and BricsCAD always (?) use values stored in the MULTILEADER +# entity, even if the override flag isn't set! +IGNORE_OVERRIDE_FLAGS = True + +# Distance between baseline and underline as factor of cap-height +# Just guessing but the descender height is too much! +UNDERLINE_DISTANCE_FACTOR = 0.20 + + +class ConnectionTypeError(const.DXFError): + pass + + +OVERRIDE_FLAG = { + "leader_type": 1 << 0, + "leader_line_color": 1 << 1, + "leader_linetype_handle": 1 << 2, + "leader_lineweight": 1 << 3, + "has_landing": 1 << 4, + "landing_gap": 1 << 5, # ??? not in MultiLeader + "has_dogleg": 1 << 6, + "dogleg_length": 1 << 7, + "arrow_head_handle": 1 << 8, + "arrow_head_size": 1 << 9, + "content_type": 1 << 10, + "text_style_handle": 1 << 11, + "text_left_attachment_type": 1 << 12, + "text_angle_type": 1 << 13, + "text_alignment_type": 1 << 14, + "text_color": 1 << 15, + "char_height": 1 << 16, # stored in MultiLeader.context.char_height + "has_text_frame": 1 << 17, + # 1 << 18 # use default content stored in MultiLeader.mtext.default_content + "block_record_handle": 1 << 19, + "block_color": 1 << 20, + "block_scale_vector": 1 << 21, # 3 values in MLeaderStyle + "block_rotation": 1 << 22, + "block_connection_type": 1 << 23, + "scale": 1 << 24, + "text_right_attachment_type": 1 << 25, + "text_switch_alignment": 1 << 26, # ??? not in MultiLeader/MLeaderStyle + "text_attachment_direction": 1 << 27, # this flag is not set by BricsCAD + "text_top_attachment_type": 1 << 28, + "text_bottom_attachment_type": 1 << 29, +} + + +class MLeaderStyleOverride: + def __init__(self, style: MLeaderStyle, mleader: MultiLeader): + self._style_dxf = style.dxf + self._mleader_dxf = mleader.dxf + self._context = mleader.context + self._property_override_flags = mleader.dxf.get( + "property_override_flags", 0 + ) + self._block_scale_vector = Vec3( + ( + style.dxf.get("block_scale_x", 1.0), + style.dxf.get("block_scale_y", 1.0), + style.dxf.get("block_scale_z", 1.0), + ) + ) + self.use_mtext_default_content = bool( + self._property_override_flags & (1 << 18) + ) # if False, what MTEXT content is used? + + def get(self, attrib_name: str) -> Any: + # Set MLEADERSTYLE value as default value: + if attrib_name == "block_scale_vector": + value = self._block_scale_vector + else: + value = self._style_dxf.get_default(attrib_name) + if IGNORE_OVERRIDE_FLAGS or self.is_overridden(attrib_name): + # Get overridden value from MULTILEADER: + if attrib_name == "char_height": + value = self._context.char_height + else: + value = self._mleader_dxf.get(attrib_name, value) + return value + + def is_overridden(self, attrib_name: str) -> bool: + flag = OVERRIDE_FLAG.get(attrib_name, 0) + return bool(flag & self._property_override_flags) + + +def virtual_entities( + mleader: MultiLeader, proxy_graphic=False +) -> Iterator[DXFGraphic]: + doc = mleader.doc + assert doc is not None, "valid DXF document required" + if proxy_graphic and mleader.proxy_graphic is not None: + return ProxyGraphic(mleader.proxy_graphic, doc).virtual_entities() + else: + return iter(RenderEngine(mleader, doc).run()) + + +def get_style(mleader: MultiLeader, doc: Drawing) -> MLeaderStyleOverride: + handle = mleader.dxf.style_handle + style = doc.entitydb.get(handle) + if style is None: + logger.warning( + f"referenced MLEADERSTYLE(#{handle}) does not exist, " + f"replaced by 'Standard'" + ) + style = doc.mleader_styles.get("Standard") + assert style is not None, "mandatory MLEADERSTYLE 'Standard' does not exist" + return MLeaderStyleOverride(cast(MLeaderStyle, style), mleader) + + +def get_text_style(handle: str, doc: Drawing) -> Textstyle: + text_style = doc.entitydb.get(handle) + if text_style is None: + logger.warning( + f"referenced STYLE(#{handle}) does not exist, " + f"replaced by 'Standard'" + ) + text_style = doc.styles.get("Standard") + assert text_style is not None, "mandatory STYLE 'Standard' does not exist" + return text_style # type: ignore + + +def get_arrow_direction(vertices: list[Vec3]) -> Vec3: + if len(vertices) < 2: + return X_AXIS + direction = vertices[1] - vertices[0] + return direction.normalize() + + +ACI_COLOR_TYPES = { + colors.COLOR_TYPE_BY_BLOCK, + colors.COLOR_TYPE_BY_LAYER, + colors.COLOR_TYPE_ACI, +} + + +def decode_raw_color(raw_color: int) -> tuple[int, Optional[int]]: + aci_color = colors.BYBLOCK + true_color: Optional[int] = None + color_type, color = colors.decode_raw_color_int(raw_color) + if color_type in ACI_COLOR_TYPES: + aci_color = color + elif color_type == colors.COLOR_TYPE_RGB: + true_color = color + # COLOR_TYPE_WINDOW_BG: not supported as entity color + return aci_color, true_color + + +def copy_mtext_data(mtext: MText, mtext_data: MTextData, scale: float) -> None: + # MLEADERSTYLE has a flag "use_mtext_default_content", what else should be + # used as content if this flag is false? + mtext.text = mtext_data.default_content + dxf = mtext.dxf + aci_color, true_color = decode_raw_color(mtext_data.color) + dxf.color = aci_color + if true_color is not None: + dxf.true_color = true_color + dxf.insert = mtext_data.insert + assert mtext.doc is not None + mtext.dxf.style = get_text_style( + mtext_data.style_handle, mtext.doc + ).dxf.name + if not mtext_data.extrusion.isclose(Z_AXIS): + dxf.extrusion = mtext_data.extrusion + dxf.text_direction = mtext_data.text_direction + # ignore rotation! + dxf.width = mtext_data.width * scale + dxf.line_spacing_factor = mtext_data.line_spacing_factor + dxf.line_spacing_style = mtext_data.line_spacing_style + dxf.flow_direction = mtext_data.flow_direction + # alignment=attachment_point: 1=top left, 2=top center, 3=top right + dxf.attachment_point = mtext_data.alignment + + +def make_mtext(mleader: MultiLeader) -> MText: + mtext = cast("MText", factory.new("MTEXT", doc=mleader.doc)) + mtext.dxf.layer = mleader.dxf.layer + context = mleader.context + mtext_data = context.mtext + if mtext_data is None: + raise TypeError(f"MULTILEADER has no MTEXT content") + scale = context.scale + # !char_height is the final already scaled value! + mtext.dxf.char_height = context.char_height + if mtext_data is not None: + copy_mtext_data(mtext, mtext_data, scale) + if mtext_data.has_bg_fill: + set_mtext_bg_fill(mtext, mtext_data) + set_mtext_columns(mtext, mtext_data, scale) + return mtext + + +def set_mtext_bg_fill(mtext: MText, mtext_data: MTextData) -> None: + # Note: the "text frame" flag (16) in "bg_fill" is never set by BricsCAD! + # Set required DXF attributes: + mtext.dxf.box_fill_scale = mtext_data.bg_scale_factor + mtext.dxf.bg_fill = 1 + mtext.dxf.bg_fill_color = colors.BYBLOCK + mtext.dxf.bg_fill_transparency = mtext_data.bg_transparency + color_type, color = colors.decode_raw_color_int(mtext_data.bg_color) + if color_type in ACI_COLOR_TYPES: + mtext.dxf.bg_fill_color = color + elif color_type == colors.COLOR_TYPE_RGB: + mtext.dxf.bg_fill_true_color = color + + if ( + mtext_data.use_window_bg_color + or color_type == colors.COLOR_TYPE_WINDOW_BG + ): + # override fill mode, but keep stored colors + mtext.dxf.bg_fill = 3 + + +def set_mtext_columns( + mtext: MText, mtext_data: MTextData, scale: float +) -> None: + # BricsCAD does not support columns for MTEXT content, so exploring + # MLEADER with columns was not possible! + pass + + +def _get_insert(entity: MultiLeader) -> Vec3: + context = entity.context + if context.mtext is not None: + return context.mtext.insert + elif context.block is not None: + return context.block.insert + return context.plane_origin + + +def _get_extrusion(entity: MultiLeader) -> Vec3: + context = entity.context + if context.mtext is not None: + return context.mtext.extrusion + elif context.block is not None: + return context.block.extrusion + return context.plane_z_axis + + +def _get_dogleg_vector(leader: LeaderData, default: Vec3 = X_AXIS) -> Vec3: + # All leader vertices and directions in WCS! + try: + if leader.has_dogleg_vector: # what else? + return leader.dogleg_vector.normalize(leader.dogleg_length) + except ZeroDivisionError: # dogleg_vector is NULL + pass + return default.normalize(leader.dogleg_length) + + +def _get_block_name(handle: str, doc: Drawing) -> Optional[str]: + block_record = doc.entitydb.get(handle) + if block_record is None: + logger.error(f"required BLOCK_RECORD entity #{handle} does not exist") + return None + return block_record.dxf.get("name") # has no default value + + +class RenderEngine: + def __init__(self, mleader: MultiLeader, doc: Drawing): + self.entities: list[DXFGraphic] = [] # result container + self.mleader = mleader + self.doc = doc + self.style: MLeaderStyleOverride = get_style(mleader, doc) + self.context = mleader.context + self.insert = _get_insert(mleader) + self.extrusion: Vec3 = _get_extrusion(mleader) + self.ocs: Optional[OCS] = None + if not self.extrusion.isclose(Z_AXIS): + self.ocs = OCS(self.extrusion) + self.elevation: float = self.insert.z + + # Gather final parameters from various places: + # This is the actual entity scaling, ignore scale in MLEADERSTYLE! + self.scale: float = self.context.scale + self.layer = mleader.dxf.layer + self.linetype = self.linetype_name() + self.lineweight = self.style.get("leader_lineweight") + aci_color, true_color = decode_raw_color( + self.style.get("leader_line_color") + ) + self.leader_aci_color: int = aci_color + self.leader_true_color: Optional[int] = true_color + self.leader_type: int = self.style.get("leader_type") + self.has_text_frame = False + self.has_dogleg: bool = bool(self.style.get("has_dogleg")) + self.arrow_heads: dict[int, str] = { + head.index: head.handle for head in mleader.arrow_heads + } + self.arrow_head_handle = self.style.get("arrow_head_handle") + self.dxf_mtext_entity: Optional["MText"] = None + self._dxf_mtext_extents: Optional[tuple[float, float]] = None + self.has_horizontal_attachment = bool( + self.style.get("text_attachment_direction") + ) + self.left_attachment_type = self.style.get("text_left_attachment_type") + self.right_attachment_type = self.style.get( + "text_right_attachment_type" + ) + self.top_attachment_type = self.style.get("text_top_attachment_type") + self.bottom_attachment_type = self.style.get( + "text_bottom_attachment_type" + ) + + @property + def has_extrusion(self) -> bool: + return self.ocs is not None + + @property + def has_text_content(self) -> bool: + return self.context.mtext is not None + + @property + def has_block_content(self) -> bool: + return self.context.block is not None + + @property + def mtext_extents(self) -> tuple[float, float]: + """Calculate MTEXT width on demand.""" + + if self._dxf_mtext_extents is not None: + return self._dxf_mtext_extents + if self.dxf_mtext_entity is not None: + # TODO: this is very inaccurate if using inline codes, better + # solution is required like a text layout engine with column width + # calculation from the MTEXT content. + width, height = text_size.estimate_mtext_extents( + self.dxf_mtext_entity + ) + else: + width, height = 0.0, 0.0 + self._dxf_mtext_extents = (width, height) + return self._dxf_mtext_extents + + def run(self) -> list[DXFGraphic]: + """Entry point to render MLEADER entities.""" + self.entities.clear() + if abs(self.scale) > 1e-9: + self.add_content() + self.add_leaders() + # otherwise it vanishes by scaling down to almost "nothing" + return self.entities + + def linetype_name(self) -> str: + handle = self.style.get("leader_linetype_handle") + ltype = self.doc.entitydb.get(handle) + if ltype is not None: + return ltype.dxf.name + logger.warning(f"invalid linetype handle #{handle} in {self.mleader}") + return "Continuous" + + def arrow_block_name(self, index: int) -> str: + closed_filled = "_CLOSED_FILLED" + handle = self.arrow_heads.get(index, self.arrow_head_handle) + if handle is None or handle == "0": + return closed_filled + block_record = self.doc.entitydb.get(handle) + if block_record is None: + logger.warning( + f"arrow block #{handle} in {self.mleader} does not exist, " + f"replaced by closed filled arrow" + ) + return closed_filled + return block_record.dxf.name + + def leader_line_attribs(self, raw_color: Optional[int] = None) -> dict: + aci_color = self.leader_aci_color + true_color = self.leader_true_color + + # Ignore color override value BYBLOCK! + if raw_color and raw_color is not colors.BY_BLOCK_RAW_VALUE: + aci_color, true_color = decode_raw_color(raw_color) + + attribs = { + "layer": self.layer, + "color": aci_color, + "linetype": self.linetype, + "lineweight": self.lineweight, + } + if true_color is not None: + attribs["true_color"] = true_color + return attribs + + def add_content(self) -> None: + # also check self.style.get("content_type") ? + if self.has_text_content: + self.add_mtext_content() + elif self.has_block_content: + self.add_block_content() + + def add_mtext_content(self) -> None: + mtext = make_mtext(self.mleader) + self.entities.append(mtext) + self.dxf_mtext_entity = mtext + if self.has_text_frame: + self.add_text_frame() + + def add_text_frame(self) -> None: + # not supported - yet? + # 1. This requires a full MTEXT height calculation. + # 2. Only the default rectangle and the rounded rectangle are + # acceptable every other text frame is just ugly, especially + # when the MTEXT gets more complex. + pass + + def add_block_content(self) -> None: + block = self.context.block + assert block is not None + block_name = _get_block_name(block.block_record_handle, self.doc) # type: ignore + if block_name is None: + return + location = block.insert # in WCS, really funny for an OCS entity! + rotation = math.degrees(block.rotation) + if self.ocs is not None: + location = self.ocs.from_wcs(location) + aci_color, true_color = decode_raw_color(block.color) + scale = block.scale + + attribs = { + "name": block_name, + "insert": location, + "rotation": rotation, + "color": aci_color, + "extrusion": block.extrusion, + "xscale": scale.x, + "yscale": scale.y, + "zscale": scale.z, + } + if true_color is not None: + attribs["true_color"] = true_color + insert = cast( + "Insert", factory.new("INSERT", dxfattribs=attribs, doc=self.doc) + ) + self.entities.append(insert) + if self.mleader.block_attribs: + self.add_block_attributes(insert) + + def add_block_attributes(self, insert: Insert): + entitydb = self.doc.entitydb + values: dict[str, str] = dict() + for attrib in self.mleader.block_attribs: + attdef = entitydb.get(attrib.handle) + if attdef is None: + logger.error( + f"required ATTDEF entity #{attrib.handle} does not exist" + ) + continue + tag = attdef.dxf.tag + values[tag] = attrib.text + if values: + insert.add_auto_attribs(values) + + def add_leaders(self) -> None: + if self.leader_type == 0: + return + + for leader in self.context.leaders: + for line in leader.lines: + self.add_leader_line(leader, line) + + if self.has_text_content: + if leader.has_horizontal_attachment: + # add text underlines for these horizontal attachment styles: + # 5 = bottom of bottom text line & underline bottom text line + # 6 = bottom of top text line & underline top text line + self.add_text_underline(leader) + else: + # text with vertical attachment may have an extra "overline" + # across the text + self.add_overline(leader) + + def add_text_underline(self, leader: LeaderData): + mtext = self.context.mtext + if mtext is None: + return + has_left_underline = self.left_attachment_type in (5, 6, 8) + has_right_underline = self.right_attachment_type in (5, 6, 8) + if not (has_left_underline or has_right_underline): + return + connection_point = leader.last_leader_point + _get_dogleg_vector(leader) + width, height = self.mtext_extents + length = width + self.context.landing_gap_size + if length < 1e-9: + return + # The connection point is on the "left" or "right" side of the + # detection line, which is a "vertical" line through the text + # insertion point. + start = mtext.insert + if self.ocs is None: # text plane is parallel to the xy-plane + start2d = start.vec2 + up2d = mtext.text_direction.vec2.orthogonal() + cp2d = connection_point.vec2 + else: # project points into the text plane + from_wcs = self.ocs.from_wcs + start2d = Vec2(from_wcs(start)) + up2d = Vec2(from_wcs(mtext.text_direction)).orthogonal() + cp2d = Vec2(from_wcs(connection_point)) + is_left = is_point_left_of_line(cp2d, start2d, start2d + up2d) + is_right = not is_left + line = mtext.text_direction.normalize(length if is_left else -length) + if (is_left and has_left_underline) or ( + is_right and has_right_underline + ): + self.add_dxf_line(connection_point, connection_point + line) + + def add_overline(self, leader: LeaderData): + mtext = self.context.mtext + if mtext is None: + return + has_bottom_line = self.bottom_attachment_type == 10 + has_top_line = self.top_attachment_type == 10 + if not (has_bottom_line or has_top_line): + return + length, height = self.mtext_extents + if length < 1e-9: + return + + # The end of the leader is the center of the "overline". + # The leader is on the bottom of the text if the insertion + # point of the text is left of "overline" (start -> end). + center = leader.last_leader_point + insert = mtext.insert + line2 = mtext.text_direction.normalize(length / 2) + start = center - line2 + end = center + line2 + + if self.ocs is None: # z-axis is ignored + bottom = is_point_left_of_line(insert, start, end) + else: # project points into the text plane, z-axis is ignored + from_wcs = self.ocs.from_wcs + bottom = is_point_left_of_line( + from_wcs(insert), from_wcs(start), from_wcs(end) + ) + top = not bottom + if (bottom and has_bottom_line) or (top and has_top_line): + self.add_dxf_line(start, end) + + def leader_vertices( + self, leader: LeaderData, line_vertices: list[Vec3], has_dogleg=False + ) -> list[Vec3]: + # All leader vertices and directions in WCS! + vertices = list(line_vertices) + end_point = leader.last_leader_point + if leader.has_horizontal_attachment: + if has_dogleg: + vertices.append(end_point) + vertices.append(end_point + _get_dogleg_vector(leader)) + else: + vertices.append(end_point) + return vertices + + def add_leader_line(self, leader: LeaderData, line: LeaderLine): + # All leader vertices and directions in WCS! + leader_type: int = self.leader_type + if leader_type == 0: # invisible leader lines + return + has_dogleg: bool = self.has_dogleg + if leader_type == 2: # splines do not have a dogleg! + has_dogleg = False + vertices: list[Vec3] = self.leader_vertices( + leader, line.vertices, has_dogleg + ) + if len(vertices) < 2: # at least 2 vertices required + return + + arrow_direction: Vec3 = get_arrow_direction(vertices) + raw_color: int = line.color + index: int = line.index + block_name: str = self.create_arrow_block(self.arrow_block_name(index)) + arrow_size: float = self.context.arrow_head_size + self.add_arrow( + name=block_name, + location=vertices[0], + direction=arrow_direction, + scale=arrow_size, + color=raw_color, + ) + arrow_offset: Vec3 = arrow_direction * arrow_length( + block_name, arrow_size + ) + vertices[0] += arrow_offset + if leader_type == 1: # add straight lines + for s, e in zip(vertices, vertices[1:]): + self.add_dxf_line(s, e, raw_color) + elif leader_type == 2: # add spline + if leader.has_horizontal_attachment: + end_tangent = _get_dogleg_vector(leader) + else: + end_tangent = vertices[-1] - vertices[-2] + self.add_dxf_spline( + vertices, + # tangent normalization is not required + tangents=[arrow_direction, end_tangent], + color=raw_color, + ) + + def create_arrow_block(self, name: str) -> str: + if name not in self.doc.blocks: + # create predefined arrows + arrow_name = ARROWS.arrow_name(name) + if arrow_name not in ARROWS: + arrow_name = ARROWS.closed_filled + name = ARROWS.create_block(self.doc.blocks, arrow_name) + return name + + def add_dxf_spline( + self, + fit_points: list[Vec3], + tangents: Optional[Iterable[UVec]] = None, + color: Optional[int] = None, + ): + attribs = self.leader_line_attribs(color) + spline = cast( + "Spline", + factory.new("SPLINE", dxfattribs=attribs, doc=self.doc), + ) + spline.apply_construction_tool( + fit_points_to_cad_cv(fit_points, tangents=tangents) + ) + self.entities.append(spline) + + def add_dxf_line(self, start: Vec3, end: Vec3, color: Optional[int] = None): + attribs = self.leader_line_attribs(color) + attribs["start"] = start + attribs["end"] = end + self.entities.append( + factory.new("LINE", dxfattribs=attribs, doc=self.doc) # type: ignore + ) + + def add_arrow( + self, + name: str, + location: Vec3, + direction: Vec3, + scale: float, + color: int, + ): + attribs = self.leader_line_attribs(color) + attribs["name"] = name + if self.ocs is not None: + location = self.ocs.from_wcs(location) + direction = self.ocs.from_wcs(direction) + attribs["extrusion"] = self.extrusion + + attribs["insert"] = location + attribs["rotation"] = direction.angle_deg + 180.0 + attribs["xscale"] = scale + attribs["yscale"] = scale + attribs["zscale"] = scale + self.entities.append( + factory.new("INSERT", dxfattribs=attribs, doc=self.doc) # type: ignore + ) + + +class LeaderType(enum.IntEnum): + """The leader type.""" + + none = 0 + straight_lines = 1 + splines = 2 + + +# noinspection PyArgumentList +class ConnectionSide(enum.Enum): + """ + The leader connection side. + + Vertical (top, bottom) and horizontal attachment sides (left, right) + can not be mixed in a single entity - this is a limitation of the + MULTILEADER entity. + """ + + left = enum.auto() + right = enum.auto() + top = enum.auto() + bottom = enum.auto() + + +DOGLEG_DIRECTIONS = { + ConnectionSide.left: X_AXIS, + ConnectionSide.right: -X_AXIS, + ConnectionSide.top: -X_AXIS, # ??? + ConnectionSide.bottom: X_AXIS, # ??? +} + + +class HorizontalConnection(enum.IntEnum): + """The horizontal leader connection type.""" + + by_style = -1 + top_of_top_line = 0 + middle_of_top_line = 1 + middle_of_text = 2 + middle_of_bottom_line = 3 + bottom_of_bottom_line = 4 + bottom_of_bottom_line_underline = 5 + bottom_of_top_line_underline = 6 + bottom_of_top_line = 7 + bottom_of_top_line_underline_all = 8 + + +class VerticalConnection(enum.IntEnum): + """The vertical leader connection type.""" + + by_style = 0 + center = 9 + center_overline = 10 + + +class TextAlignment(enum.IntEnum): + """The :class:`MText` alignment type.""" + + left = 1 + center = 2 + right = 3 + + +class BlockAlignment(enum.IntEnum): + """The :class:`Block` alignment type.""" + + center_extents = 0 + insertion_point = 1 + + +@dataclass +class ConnectionBox: + """Contains the connection points for all 4 sides of the content, the + landing gap is included. + """ + + left: Vec2 + right: Vec2 + top: Vec2 + bottom: Vec2 + + def get(self, side: ConnectionSide) -> Vec2: + if side == ConnectionSide.left: + return self.left + elif side == ConnectionSide.right: + return self.right + elif side == ConnectionSide.top: + return self.top + return self.bottom + + +def ocs_rotation(ucs: UCS) -> float: + """Returns the ocs rotation angle of the UCS""" + if not Z_AXIS.isclose(ucs.uz): + ocs = OCS(ucs.uz) + x_axis_in_ocs = Vec2(ocs.from_wcs(ucs.ux)) + return x_axis_in_ocs.angle # in radians! + return 0.0 + + +class MultiLeaderBuilder(abc.ABC): + def __init__(self, multileader: MultiLeader): + doc = multileader.doc + assert doc is not None, "valid DXF document required" + handle = multileader.dxf.style_handle + style: MLeaderStyle = doc.entitydb.get(handle) # type: ignore + if style is None: + raise ValueError(f"invalid MLEADERSTYLE handle #{handle}") + self._doc: "Drawing" = doc + self._mleader_style: MLeaderStyle = style + self._multileader = multileader + self._leaders: dict[ConnectionSide, list[list[Vec2]]] = defaultdict( + list + ) + self.set_mleader_style(style) + self._multileader.context.landing_gap_size = ( + self._mleader_style.dxf.landing_gap_size + ) + + @abc.abstractmethod + def _init_content(self): + ... + + def _reset_cache(self): + pass + + @abc.abstractmethod + def _build_connection_box(self) -> ConnectionBox: + """Returns the connection box with the connection points on all 4 sides + in build UCS coordinates. The origin of the build ucs is the insertion + or attachment point of the content. + """ + ... + + @abc.abstractmethod + def _transform_content_to_render_ucs( + self, insert: Vec2, rotation: float + ) -> None: + ... + + @abc.abstractmethod + def _apply_conversion_factor(self, conversion_factor: float) -> None: + ... + + @abc.abstractmethod + def _set_base_point(self, left: Vec3, bottom: Vec3): + ... + + @property + def multileader(self) -> MultiLeader: + """Returns the :class:`~ezdxf.entities.MultiLeader` entity.""" + return self._multileader + + @property + def context(self) -> MLeaderContext: + """Returns the context entity :class:`~ezdxf.entities.MLeaderContext`.""" + return self._multileader.context + + @property + def _landing_gap_size(self) -> float: + return self._multileader.context.landing_gap_size + + def set_mleader_style(self, style: MLeaderStyle): + """Reset base properties by :class:`~ezdxf.entities.MLeaderStyle` + properties. This also resets the content! + """ + + def copy_style_to_context(): + self.context.char_height = style_dxf.char_height + self.context.landing_gap_size = style_dxf.landing_gap_size + + self._mleader_style = style + multileader_dxf = self._multileader.dxf + style_dxf = style.dxf + keys = list(acdb_mleader_style.attribs.keys()) + for key in keys: + if multileader_dxf.is_supported(key): + multileader_dxf.set(key, style_dxf.get_default(key)) + copy_style_to_context() + multileader_dxf.block_scale_vector = Vec3( + style_dxf.block_scale_x, + style_dxf.block_scale_y, + style_dxf.block_scale_z, + ) + # MLEADERSTYLE contains unscaled values + self.context.set_scale(multileader_dxf.scale) + self._init_content() + + def set_connection_properties( + self, + landing_gap: float = 0.0, # unscaled value! + dogleg_length: float = 0.0, # unscaled value! + ): + """Set the properties how to connect the leader line to the content. + + The landing gap is the space between the content and the start of the + leader line. The "dogleg" is the first line segment of the leader + in the "horizontal" direction of the content. + + """ + multileader = self.multileader + scale = multileader.dxf.scale + if dogleg_length: + multileader.dxf.has_dogleg = 1 + multileader.dxf.dogleg_length = dogleg_length * scale + else: + multileader.dxf.has_dogleg = 0 + multileader.context.landing_gap_size * landing_gap * scale + + def set_connection_types( + self, + left=HorizontalConnection.by_style, + right=HorizontalConnection.by_style, + top=VerticalConnection.by_style, + bottom=VerticalConnection.by_style, + ): + """Set the connection type for each connection side.""" + context = self.context + style = self._mleader_style + if left == HorizontalConnection.by_style: + context.left_attachment = style.dxf.text_left_attachment_type + else: + context.left_attachment = int(left) + + if right == HorizontalConnection.by_style: + context.right_attachment = style.dxf.text_right_attachment_type + else: + context.right_attachment = int(right) + + if top == VerticalConnection.by_style: + context.top_attachment = style.dxf.text_top_attachment_type + else: + context.top_attachment = int(top) + + if bottom == VerticalConnection.by_style: + context.bottom_attachment = style.dxf.text_bottom_attachment_type + else: + context.bottom_attachment = int(bottom) + + dxf = self._multileader.dxf + dxf.text_left_attachment_type = context.left_attachment + dxf.text_right_attachment_type = context.right_attachment + dxf.text_top_attachment_type = context.top_attachment + dxf.text_bottom_attachment_type = context.bottom_attachment + + def set_overall_scaling(self, scale: float): + """Set the overall scaling factor for the whole entity, + except for the leader line vertices! + + Args: + scale: scaling factor > 0.0 + + """ + new_scale = float(scale) + if new_scale <= 0.0: + raise ValueError(f"invalid scaling factor: {scale}") + context = self.context + multileader = self.multileader + old_scale = multileader.dxf.scale + try: + # convert from existing scaling to new scale factor + conversion_factor = new_scale / old_scale + except ZeroDivisionError: + conversion_factor = new_scale + + multileader.dxf.scale = new_scale + multileader.dxf.dogleg_length *= conversion_factor + context.set_scale(new_scale) + self._apply_conversion_factor(conversion_factor) + + def set_leader_properties( + self, + color: Union[int, colors.RGB] = colors.BYBLOCK, + linetype: str = "BYBLOCK", + lineweight: int = const.LINEWEIGHT_BYBLOCK, + leader_type=LeaderType.straight_lines, + ): + """Set leader line properties. + + Args: + color: line color as :ref:`ACI` or RGB tuple + linetype: as name string, e.g. "BYLAYER" + lineweight: as integer value, see: :ref:`lineweights` + leader_type: straight lines of spline type + + """ + mleader = self._multileader + mleader.dxf.leader_line_color = colors.encode_raw_color(color) + linetype_ = self._doc.linetypes.get(linetype) + if linetype_ is None: + raise ValueError(f"invalid linetype name '{linetype}'") + mleader.dxf.leader_linetype_handle = linetype_.dxf.handle + mleader.dxf.leader_lineweight = lineweight + mleader.dxf.leader_type = int(leader_type) + + def set_arrow_properties( + self, + name: str = "", + size: float = 0.0, # 0=by style + ): + """Set leader arrow properties all leader lines have the same arrow + type. + + The MULTILEADER entity is able to support multiple arrows, but this + seems to be unsupported by CAD applications and is therefore also not + supported by the builder classes. + + """ + if size == 0.0: + size = self._mleader_style.dxf.arrow_head_size + self._multileader.dxf.arrow_head_size = size + self.context.arrow_head_size = size + if name: + self._multileader.dxf.arrow_head_handle = ARROWS.arrow_handle( + self._doc.blocks, name + ) + else: + # empty string is the default "closed filled" arrow, + # no handle needed + del self._multileader.dxf.arrow_head_handle + + def add_leader_line( + self, side: ConnectionSide, vertices: Iterable[Vec2] + ) -> None: + """Add leader as iterable of vertices in render UCS coordinates + (:ref:`WCS` by default). + + .. note:: + + Vertical (top, bottom) and horizontal attachment sides (left, right) + can not be mixed in a single entity - this is a limitation of the + MULTILEADER entity. + + Args: + side: connection side where to attach the leader line + vertices: leader vertices + + """ + self._leaders[side].append(list(vertices)) + + def build( + self, insert: Vec2, rotation: float = 0.0, ucs: Optional[UCS] = None + ) -> None: + """Compute the required geometry data. The construction plane is + the xy-plane of the given render :class:`~ezdxf.math.UCS`. + + Args: + insert: insert location for the content in render UCS coordinates + rotation: content rotation angle around the render UCS z-axis in degrees + ucs: the render :class:`~ezdxf.math.UCS`, default is the :ref:`WCS` + + """ + assert isinstance(insert, Vec2), "insert has to be a Vec2() object" + rotation = math.radians(rotation) + # transformation matrix from build ucs to render ucs + m = Matrix44.z_rotate(rotation) + connection_box = self._build_connection_box() + m.set_row(3, (insert.x, insert.y)) # fast translation + + self._set_required_multileader_attributes() + self._transform_content_to_render_ucs(insert, rotation) + self._set_attachment_direction() + self._set_base_point( # MTEXT requires "text_attachment_direction" + left=m.transform(connection_box.left.vec3), + bottom=m.transform(connection_box.bottom.vec3), + ) + self.context.leaders.clear() + + for side, leader_lines in self._leaders.items(): + self._build_leader(leader_lines, side, connection_box.get(side), m) + if ucs is not None: + self._transform_to_wcs(ucs) + self.multileader.update_proxy_graphic() + + def _set_attachment_direction(self): + leaders = self._leaders + if leaders: + horizontal = (ConnectionSide.left in leaders) or ( + ConnectionSide.right in leaders + ) + vertical = (ConnectionSide.top in leaders) or ( + ConnectionSide.bottom in leaders + ) + if horizontal and vertical: + raise ConnectionTypeError( + "invalid mix of horizontal and vertical connection types" + ) + self._multileader.dxf.text_attachment_direction = ( + 0 if horizontal else 1 + ) + if vertical: + self._multileader.dxf.has_dogleg = False + # else MULTILEADER without any leader lines! + + def _transform_to_wcs(self, ucs: UCS) -> None: + # transformation from render UCS into WCS + self.multileader.transform(ucs.matrix) + + def _set_required_multileader_attributes(self): + dxf = self.multileader.dxf + doc = self._doc + handle = dxf.get("leader_linetype_handle") + if handle is None or handle not in doc.entitydb: + linetype = doc.linetypes.get("BYLAYER") + if linetype is None: + raise ValueError(f"required linetype 'BYLAYER' does not exist") + dxf.leader_linetype_handle = linetype.dxf.handle + dxf.property_override_flags = 0x7FFFFFFF + + def _build_leader( + self, + leader_lines: list[list[Vec2]], + side: ConnectionSide, + connection_point: Vec2, + m: Matrix44, + ): + # The content is always aligned to the x- and y-axis of the build UCS! + + # The dogleg vector points to the content: + dogleg_direction = DOGLEG_DIRECTIONS[side] + leader = LeaderData() + leader.index = len(self.context.leaders) + + # dogleg_length is the already scaled length! + leader.dogleg_length = float(self._multileader.dxf.dogleg_length) + leader.has_dogleg_vector = 1 # ignored by AutoCAD/BricsCAD + leader.has_last_leader_line = ( + 1 # leader is invisible in AutoCAD if 0 ... + ) + # flag is ignored by BricsCAD + leader.dogleg_vector = dogleg_direction + if side == ConnectionSide.left or side == ConnectionSide.right: + leader.attachment_direction = 0 + else: + leader.attachment_direction = 1 + + # setting last leader point: + # landing gap is already included in connection box + if self.multileader.dxf.has_dogleg: + leader.last_leader_point = connection_point.vec3 + ( + dogleg_direction * -leader.dogleg_length + ) + else: + leader.last_leader_point = connection_point.vec3 + + # transform leader from build ucs to user UCS + leader.last_leader_point = m.transform(leader.last_leader_point) + leader.dogleg_vector = m.transform_direction(leader.dogleg_vector) + + # leader line vertices in user UCS coordinates! + self._append_leader_lines(leader, leader_lines) + self.context.leaders.append(leader) + + @staticmethod + def _append_leader_lines( + leader: LeaderData, leader_lines: list[list[Vec2]] + ) -> None: + for index, vertices in enumerate(leader_lines): + line = LeaderLine() + line.index = index + line.vertices = Vec3.list(vertices) + leader.lines.append(line) + + +# TODO: MultiLeaderBuilder & MText horizontal connection type 6 issue in BricsCAD +# 6 = "underline the bottom of the top line" +# This connection is not rendered correct in BricsCAD, the rendering in AutoCAD +# is OK, also the rendering by the ezdxf multileader RenderEngine. +# Maybe an error in BricsCAD. +# BricsCAD can create correct MULTILEADER entities with this connection type but +# I couldn't find the difference in the DXF tags which causes this issue. + + +class MultiLeaderMTextBuilder(MultiLeaderBuilder): + def _init_content(self): + self._reset_cache() + context = self.context + style = self._mleader_style + mleader = self._multileader + + # reset content type + mleader.dxf.content_type = 2 + context.block = None + + # create default mtext content + mtext = MTextData() + context.mtext = mtext + + mtext.default_content = style.dxf.default_text_content + mtext.style_handle = mleader.dxf.text_style_handle + mtext.color = mleader.dxf.text_color + mtext.alignment = mleader.dxf.text_attachment_point + + # The char height is stored in MLeader Context()! + # The content dimensions (width, height) are not calculated yet, + # therefore scaling is not necessary! + + def set_content( + self, + content: str, + color: Optional[ + Union[int, colors.RGB] + ] = None, # None = uses MLEADERSTYLE value + char_height: float = 0.0, # unscaled char height, 0.0 is by style + alignment: TextAlignment = TextAlignment.left, + style: str = "", + ): + """Set MTEXT content. + + Args: + content: MTEXT content as string + color: block color as :ref:`ACI` or RGB tuple + char_height: initial char height in drawing units + alignment: :class:`TextAlignment` - left, center, right + style: name of :class:`~ezdxf.entities.Textstyle` as string + + """ + mleader = self._multileader + context = self.context + # update MULTILEADER DXF namespace + if color is not None: + mleader.dxf.text_color = colors.encode_raw_color(color) + mleader.dxf.text_attachment_point = int(alignment) + self._init_content() + # following attributes are not stored in the MULTILEADER DXF namespace + assert context.mtext is not None + context.mtext.default_content = text_tools.escape_dxf_line_endings( + content + ) + if char_height: + context.char_height = char_height * self.multileader.dxf.scale + if style: + self._set_mtext_style(style) + + def _set_mtext_style(self, name: str): + style = self._doc.styles.get(name) + if style is not None: + self._multileader.dxf.text_style_handle = style.dxf.handle + assert self.context.mtext is not None + self.context.mtext.style_handle = style.dxf.handle + else: + raise ValueError(f"text style '{name}' does not exist") + + def _build_connection_box(self) -> ConnectionBox: + """Returns the connection box with the connection points on all 4 sides + in build UCS coordinates. The origin of the build ucs is the attachment + point of the MTEXT content. + """ + + def get_left_x() -> float: + assert mtext is not None # shut-up mypy!!!! + # relative to the attachment point + x = -gap # left + if mtext.alignment == 2: # center + x = -width * 0.5 - gap + elif mtext.alignment == 3: # right + x = -width - gap + return x + + def vertical_connection_height( + connection: HorizontalConnection, + ) -> float: + underline_distance = char_height * UNDERLINE_DISTANCE_FACTOR + if connection == HorizontalConnection.middle_of_top_line: + return -char_height * 0.5 + elif connection == HorizontalConnection.middle_of_text: + return -height * 0.5 + elif connection == HorizontalConnection.middle_of_bottom_line: + return -height + char_height * 0.5 + elif connection in ( + HorizontalConnection.bottom_of_bottom_line, + HorizontalConnection.bottom_of_bottom_line_underline, + ): + return -height - underline_distance + elif connection in ( + HorizontalConnection.bottom_of_top_line, + HorizontalConnection.bottom_of_top_line_underline, + HorizontalConnection.bottom_of_top_line_underline_all, + ): + return -char_height - underline_distance + return 0.0 + + context = self.context + mtext = context.mtext + assert isinstance(mtext, MTextData), "undefined MTEXT content" + left_attachment = HorizontalConnection(context.left_attachment) + right_attachment = HorizontalConnection(context.right_attachment) + char_height = context.char_height # scaled value! + gap = context.landing_gap_size # scaled value! + + width: float + height: float + # required data: context.scale, context.char_height + entity = make_mtext(self._multileader) + if text_tools.has_inline_formatting_codes(entity.text): + size = text_size.mtext_size(entity) + width = size.total_width + height = size.total_height + else: + width, height = text_size.estimate_mtext_extents(entity) + + left_x = get_left_x() + right_x = left_x + width + 2.0 * gap + center_x = (left_x + right_x) * 0.5 + + # Connection box in build UCS coordinates: + return ConnectionBox( + left=Vec2(left_x, vertical_connection_height(left_attachment)), + right=Vec2(right_x, vertical_connection_height(right_attachment)), + top=Vec2(center_x, gap), + bottom=Vec2(center_x, -height - gap), + ) + + def _transform_content_to_render_ucs( + self, insert: Vec2, rotation: float + ) -> None: + mtext = self.context.mtext + assert mtext is not None + mtext.extrusion = Z_AXIS + mtext.insert = Vec3(insert) + mtext.text_direction = X_AXIS.rotate(rotation) + # todo: text_angle_type? + mtext.rotation = rotation + + def _apply_conversion_factor(self, conversion_factor: float) -> None: + mtext = self.context.mtext + assert mtext is not None + mtext.apply_conversion_factor(conversion_factor) + + def quick_leader( + self, + content: str, + target: Vec2, + segment1: Vec2, + segment2: Optional[Vec2] = None, + connection_type: Union[ + HorizontalConnection, VerticalConnection + ] = HorizontalConnection.middle_of_top_line, + ucs: Optional[UCS] = None, + ) -> None: + """Creates a quick MTEXT leader. The `target` point defines where the + leader points to. + The `segment1` is the first segment of the leader line relative to the + `target` point, `segment2` is an optional second line segment relative + to the first line segment. + The `connection_type` defines the type of connection (horizontal or + vertical) and the MTEXT alignment (left, center or right). + Horizontal connections are always left or right aligned, vertical + connections are always center aligned. + + Args: + content: MTEXT content string + target: leader target point as :class:`Vec2` + segment1: first leader line segment as relative distance to `insert` + segment2: optional second leader line segment as relative distance to + first line segment + connection_type: one of :class:`HorizontalConnection` or + :class:`VerticalConnection` + ucs: the rendering :class:`~ezdxf.math.UCS`, default is the :ref:`WCS` + + """ + offset = segment1 + if segment2 is not None: + offset += segment2 + if isinstance(connection_type, VerticalConnection): + alignment = TextAlignment.center + else: + alignment = ( + TextAlignment.right if offset.x <= 0.0 else TextAlignment.left + ) + # Use text color and char height defined by the associated MLEADERSTYLE. + self.set_content(content, alignment=alignment) + + # Build a connection box to compute the required MTEXT movement. + move_text_x: float # relative x-movement of MTEXT from insert location + move_text_y: float # relative y-movement of MTEXT from insert location + side: ConnectionSide # left, right, top, bottom + has_dogleg = bool(self.multileader.dxf.has_dogleg) + connection_box = self._build_connection_box() + if isinstance(connection_type, HorizontalConnection): + move_text_x = 0.0 # MTEXT is aligned to the insert location + if offset.x <= 0.0: + side = ConnectionSide.right + move_text_y = -connection_box.right.y # opposite direction + else: + side = ConnectionSide.left + move_text_y = -connection_box.left.y # opposite direction + self.set_connection_types( + left=connection_type, + right=connection_type, + ) + elif isinstance(connection_type, VerticalConnection): + # vertical connection never have doglegs! + has_dogleg = False + move_text_x = 0.0 # MTEXT is centered to the insert location + if offset.y >= 0.0: + side = ConnectionSide.bottom + move_text_y = -connection_box.bottom.y # opposite direction + else: + side = ConnectionSide.top + move_text_y = -connection_box.top.y # opposite direction + self.set_connection_types( + top=connection_type, + bottom=connection_type, + ) + else: + raise ValueError("invalid connection type") + + # Build the leader lines. + points = [target] + if segment2 is not None: + points.append(target + segment1) + self.add_leader_line(side, points) + + # The dogleg_length and gap are already scaled! + dogleg_length = float(self._multileader.dxf.dogleg_length) + gap = self._landing_gap_size + last_leader_point = target + offset + dogleg_direction = DOGLEG_DIRECTIONS[side] + if has_dogleg: + last_segment = dogleg_direction * (dogleg_length + gap) + else: + last_segment = Vec2() + insert = ( + last_leader_point + last_segment + Vec2(move_text_x, move_text_y) + ) + self.build(insert, ucs=ucs) + + def _set_base_point(self, left: Vec3, bottom: Vec3): + if self._multileader.dxf.text_attachment_direction == 0: # horizontal + self.context.base_point = left + else: # vertical + self.context.base_point = bottom + + +class MultiLeaderBlockBuilder(MultiLeaderBuilder): + def __init__(self, multileader: MultiLeader): + super().__init__(multileader) + self._block_layout: Optional["BlockLayout"] = None # cache + self._extents = BoundingBox() # cache + + def _init_content(self): + self._reset_cache() + + context = self.context + multileader = self._multileader + + # set content type + multileader.dxf.content_type = 1 + context.mtext = None + + # create default block content + block = BlockData() + context.block = block + + block.block_record_handle = multileader.dxf.block_record_handle + # final scaling factors for the INSERT entity: + block.scale = multileader.dxf.block_scale_vector * context.scale + block.rotation = multileader.dxf.block_rotation + block.color = multileader.dxf.block_color + + def _reset_cache(self): + super()._reset_cache() + self._block_layout = None + self._extents = BoundingBox() + + @property + def block_layout(self) -> "BlockLayout": + """Returns the block layout.""" + if self._block_layout is not None: + return self._block_layout + + block = self.context.block + assert isinstance(block, BlockData), "undefined BLOCK content" + + handle = block.block_record_handle + block_record = self._doc.entitydb.get(handle) # type: ignore + if block_record is None: + raise ValueError(f"invalid BLOCK_RECORD handle #{handle}") + name = block_record.dxf.name + block_layout = self._doc.blocks.get(name) + if block_layout is None: + raise ValueError( + f"BLOCK '{name}' defined by {str(block_record)} not found" + ) + self._block_layout = block_layout + return block_layout + + @property + def extents(self) -> BoundingBox: + """Returns the bounding box of the block.""" + if not self._extents.has_data: + from ezdxf import bbox + + block_layout = self.block_layout + extents = bbox.extents( + e for e in block_layout if e.dxftype() != "ATTDEF" + ) + if not extents.has_data: + extents.extend([NULLVEC]) + self._extents = extents + return self._extents + + def _build_connection_box(self) -> ConnectionBox: + """Returns the connection box with the connection points on all 4 sides + in build UCS coordinates. The origin of the build ucs is the insertion + point of the BLOCK content. + """ + # ignore the landing gap for BLOCK content + block = self.context.block + assert isinstance(block, BlockData), "undefined BLOCK content" + + block_connection_type = self._multileader.dxf.block_connection_type + block_layout = self.block_layout + extents = self.extents + sx = block.scale.x + sy = block.scale.y + width2 = extents.size.x * 0.5 * sx + height2 = extents.size.y * 0.5 * sx + base_x = block_layout.base_point.x * sx + base_y = block_layout.base_point.y * sy + center_x = extents.center.x * sx - base_x + center_y = extents.center.y * sy - base_y + + if block_connection_type == BlockAlignment.center_extents: + # adjustment of the insert point is required! + block.insert = Vec3(-center_x, -center_y, 0) + center_x = 0.0 + center_y = 0.0 + return ConnectionBox( + left=Vec2(center_x - width2, center_y), + right=Vec2(center_x + width2, center_y), + top=Vec2(center_x, center_y + height2), + bottom=Vec2(center_x, center_y - height2), + ) + + def _transform_content_to_render_ucs(self, insert: Vec2, rotation: float): + block = self.context.block + assert isinstance(block, BlockData), "undefined BLOCK content" + block.extrusion = Z_AXIS + block.insert = block.insert.rotate(rotation) + Vec3(insert) + block.rotation = rotation + + def _apply_conversion_factor(self, conversion_factor: float) -> None: + block = self.context.block + assert isinstance(block, BlockData), "undefined BLOCK content" + block.apply_conversion_factor(conversion_factor) + + def set_content( + self, + name: str, # block name + color: Union[int, colors.RGB] = colors.BYBLOCK, + scale: float = 1.0, + alignment=BlockAlignment.center_extents, + ): + """Set BLOCK content. + + Args: + name: the block name as string + color: block color as :ref:`ACI` or RGB tuple + scale: the block scaling, not to be confused with overall scaling + alignment: the block insertion point or the center of extents + + """ + mleader = self._multileader + # update MULTILEADER DXF namespace + block = self._doc.blocks.get(name) + if block is None: + raise ValueError(f"undefined BLOCK '{name}'") + # All angles in MultiLeader are radians! + mleader.dxf.block_record_handle = block.block_record_handle + mleader.dxf.block_color = colors.encode_raw_color(color) + mleader.dxf.block_scale_vector = Vec3(scale, scale, scale) + mleader.dxf.block_connection_type = int(alignment) + self._init_content() + + def set_attribute(self, tag: str, text: str, width: float = 1.0): + """Add BLOCK attributes based on an ATTDEF entity in the block + definition. All properties of the new created ATTRIB entity are + defined by the template ATTDEF entity including the location. + + Args: + tag: attribute tag name + text: attribute content string + width: width factor + + """ + block_layout = self.block_layout + block_attribs = self._multileader.block_attribs + for index, attdef in enumerate(block_layout.attdefs()): + if tag == attdef.dxf.tag: + block_attribs.append( + AttribData( + handle=attdef.dxf.handle, + index=index, + width=float(width), # width factor, do not scale! + text=str(text), + ) + ) + break + + def _set_base_point(self, left: Vec3, bottom: Vec3): + # BricsCAD does not support vertical attached leaders + self.context.base_point = left diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/mline.py b/.venv/lib/python3.12/site-packages/ezdxf/render/mline.py new file mode 100644 index 0000000..01f9123 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/mline.py @@ -0,0 +1,233 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, cast, Sequence, Any +from itertools import chain +from ezdxf.entities import factory, MLineStyle +from ezdxf.math import Vec3, OCS +import logging + +if TYPE_CHECKING: + from ezdxf.entities import MLine, DXFGraphic, Hatch, Line, Arc + +__all__ = ["virtual_entities"] +logger = logging.getLogger("ezdxf") + + +# The MLINE geometry stored in vertices, is the final geometry, +# scaling factor, justification and MLineStyle settings are already +# applied. + + +def _dxfattribs(mline) -> dict[str, Any]: + attribs = mline.graphic_properties() + # True color value of MLINE is ignored by CAD applications: + if "true_color" in attribs: + del attribs["true_color"] + return attribs + + +def virtual_entities(mline: MLine) -> list[DXFGraphic]: + """Yields 'virtual' parts of MLINE as LINE, ARC and HATCH entities. + + These entities are located at the original positions, but are not stored + in the entity database, have no handle and are not assigned to any + layout. + """ + + def filling() -> Hatch: + attribs = _dxfattribs(mline) + attribs["color"] = style.dxf.fill_color + attribs["elevation"] = Vec3(ocs.from_wcs(bottom_border[0])).replace( + x=0.0, y=0.0 + ) + attribs["extrusion"] = mline.dxf.extrusion + hatch = cast("Hatch", factory.new("HATCH", dxfattribs=attribs, doc=doc)) + bulges: list[float] = [0.0] * (len(bottom_border) * 2) + points = chain( + Vec3.generate(ocs.points_from_wcs(bottom_border)), + Vec3.generate(ocs.points_from_wcs(reversed(top_border))), + ) + if not closed: + if style.get_flag_state(style.END_ROUND): + bulges[len(bottom_border) - 1] = 1.0 + if style.get_flag_state(style.START_ROUND): + bulges[-1] = 1.0 + lwpoints = ((v.x, v.y, bulge) for v, bulge in zip(points, bulges)) + hatch.paths.add_polyline_path(lwpoints, is_closed=True) + return hatch + + def start_cap() -> list[DXFGraphic]: + entities: list[DXFGraphic] = [] + if style.get_flag_state(style.START_SQUARE): + entities.extend(create_miter(miter_points[0])) + if style.get_flag_state(style.START_ROUND): + entities.extend(round_caps(0, top_index, bottom_index)) + if ( + style.get_flag_state(style.START_INNER_ARC) + and len(style.elements) > 3 + ): + start_index = ordered_indices[-2] + end_index = ordered_indices[1] + entities.extend(round_caps(0, start_index, end_index)) + return entities + + def end_cap() -> list[DXFGraphic]: + entities: list[DXFGraphic] = [] + if style.get_flag_state(style.END_SQUARE): + entities.extend(create_miter(miter_points[-1])) + if style.get_flag_state(style.END_ROUND): + entities.extend(round_caps(-1, bottom_index, top_index)) + if ( + style.get_flag_state(style.END_INNER_ARC) + and len(style.elements) > 3 + ): + start_index = ordered_indices[1] + end_index = ordered_indices[-2] + entities.extend(round_caps(-1, start_index, end_index)) + return entities + + def round_caps(miter_index: int, start_index: int, end_index: int): + color1 = style.elements[start_index].color + color2 = style.elements[end_index].color + start = ocs.from_wcs(miter_points[miter_index][start_index]) + end = ocs.from_wcs(miter_points[miter_index][end_index]) + return _arc_caps(start, end, color1, color2) + + def _arc_caps( + start: Vec3, end: Vec3, color1: int, color2: int + ) -> Sequence[Arc]: + attribs = _dxfattribs(mline) + center = start.lerp(end) + radius = (end - start).magnitude / 2.0 + angle = (start - center).angle_deg + attribs["center"] = center + attribs["radius"] = radius + attribs["color"] = color1 + attribs["start_angle"] = angle + attribs["end_angle"] = angle + (180 if color1 == color2 else 90) + arc1 = cast("Arc", factory.new("ARC", dxfattribs=attribs, doc=doc)) + if color1 == color2: + return (arc1,) + attribs["start_angle"] = angle + 90 + attribs["end_angle"] = angle + 180 + attribs["color"] = color2 + arc2 = cast("Arc", factory.new("ARC", dxfattribs=attribs, doc=doc)) + return arc1, arc2 + + def lines() -> list[Line]: + prev = None + _lines: list[Line] = [] + attribs = _dxfattribs(mline) + + for miter in miter_points: + if prev is not None: + for index, element in enumerate(style.elements): + attribs["start"] = prev[index] + attribs["end"] = miter[index] + attribs["color"] = element.color + attribs["linetype"] = element.linetype + _lines.append( + cast( + "Line", + factory.new("LINE", dxfattribs=attribs, doc=doc), + ) + ) + prev = miter + return _lines + + def display_miter(): + _lines = [] + skip = set() + skip.add(len(miter_points) - 1) + if not closed: + skip.add(0) + for index, miter in enumerate(miter_points): + if index not in skip: + _lines.extend(create_miter(miter)) + return _lines + + def create_miter(miter) -> list[Line]: + _lines: list[Line] = [] + attribs = _dxfattribs(mline) + top = miter[top_index] + bottom = miter[bottom_index] + zero = bottom.lerp(top) + element = style.elements[top_index] + attribs["start"] = top + attribs["end"] = zero + attribs["color"] = element.color + attribs["linetype"] = element.linetype + _lines.append( + cast("Line", factory.new("LINE", dxfattribs=attribs, doc=doc)) + ) + element = style.elements[bottom_index] + attribs["start"] = bottom + attribs["end"] = zero + attribs["color"] = element.color + attribs["linetype"] = element.linetype + _lines.append( + cast("Line", factory.new("LINE", dxfattribs=attribs, doc=doc)) + ) + return _lines + + entities: list[DXFGraphic] = [] + if not mline.is_alive or mline.doc is None or len(mline.vertices) < 2: + return entities + + style: MLineStyle = mline.style # type: ignore + if style is None: + return entities + + doc = mline.doc + ocs = OCS(mline.dxf.extrusion) + element_count = len(style.elements) + closed = mline.is_closed + ordered_indices = style.ordered_indices() + bottom_index = ordered_indices[0] + top_index = ordered_indices[-1] + bottom_border: list[Vec3] = [] + top_border: list[Vec3] = [] + miter_points: list[list[Vec3]] = [] + + for vertex in mline.vertices: + offsets = vertex.line_params + if len(offsets) != element_count: + logger.debug( + f"Invalid line parametrization for vertex {len(miter_points)} " + f"in {str(mline)}." + ) + return entities + location = vertex.location + miter_direction = vertex.miter_direction + miter = [] + for offset in offsets: + try: + length = offset[0] + except IndexError: # DXFStructureError? + length = 0 + miter.append(location + miter_direction * length) + miter_points.append(miter) + top_border.append(miter[top_index]) + bottom_border.append(miter[bottom_index]) + + if closed: + miter_points.append(miter_points[0]) + top_border.append(top_border[0]) + bottom_border.append(bottom_border[0]) + + if not closed: + entities.extend(start_cap()) + + entities.extend(lines()) + + if style.get_flag_state(style.MITER): + entities.extend(display_miter()) + + if not closed: + entities.extend(end_cap()) + + if style.get_flag_state(style.FILL): + entities.insert(0, filling()) + + return entities diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/point.py b/.venv/lib/python3.12/site-packages/ezdxf/render/point.py new file mode 100644 index 0000000..7895bc9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/point.py @@ -0,0 +1,88 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import cast +import math +from ezdxf.entities import factory, Point, DXFGraphic +from ezdxf.math import Vec3, UCS, NULLVEC + + +def virtual_entities( + point: Point, pdsize: float = 1, pdmode: int = 0 +) -> list[DXFGraphic]: + """Yields point graphic as DXF primitives LINE and CIRCLE entities. + The dimensionless point is rendered as zero-length line! + + Check for this condition:: + + e.dxftype() == 'LINE' and e.dxf.start.isclose(e.dxf.end) + + if the rendering engine can't handle zero-length lines. + + + Args: + point: DXF POINT entity + pdsize: point size in drawing units + pdmode: point styling mode, see :class:`~ezdxf.entities.Point` class + + """ + + def add_line_symmetrical(offset: Vec3): + dxfattribs["start"] = ucs.to_wcs(-offset) + dxfattribs["end"] = ucs.to_wcs(offset) + entities.append(cast(DXFGraphic, factory.new("LINE", dxfattribs))) + + def add_line(s: Vec3, e: Vec3): + dxfattribs["start"] = ucs.to_wcs(s) + dxfattribs["end"] = ucs.to_wcs(e) + entities.append(cast(DXFGraphic, factory.new("LINE", dxfattribs))) + + center = point.dxf.location + # This is not a real OCS! Defines just the point orientation, + # location is in WCS! + ocs = point.ocs() + ucs = UCS(origin=center, ux=ocs.ux, uz=ocs.uz) + + # The point angle is clockwise oriented: + ucs = ucs.rotate_local_z(math.radians(-point.dxf.angle)) + + entities: list[DXFGraphic] = [] + gfx = point.graphic_properties() + + radius = pdsize * 0.5 + has_circle = bool(pdmode & 32) + has_square = bool(pdmode & 64) + style = pdmode & 7 + + dxfattribs = dict(gfx) + if style == 0: # . dimensionless point as zero-length line + add_line_symmetrical(NULLVEC) + # style == 1: no point symbol + elif style == 2: # + cross + add_line_symmetrical(Vec3(pdsize, 0)) + add_line_symmetrical(Vec3(0, pdsize)) + elif style == 3: # x cross + add_line_symmetrical(Vec3(pdsize, pdsize)) + add_line_symmetrical(Vec3(pdsize, -pdsize)) + elif style == 4: # ' tick + add_line(NULLVEC, Vec3(0, radius)) + if has_square: + x1 = -radius + x2 = radius + y1 = -radius + y2 = radius + add_line(Vec3(x1, y1), Vec3(x2, y1)) + add_line(Vec3(x2, y1), Vec3(x2, y2)) + add_line(Vec3(x2, y2), Vec3(x1, y2)) + add_line(Vec3(x1, y2), Vec3(x1, y1)) + if has_circle: + dxfattribs = dict(gfx) + if point.dxf.hasattr("extrusion"): + dxfattribs["extrusion"] = ocs.uz + dxfattribs["center"] = ocs.from_wcs(center) + else: + dxfattribs["center"] = center + dxfattribs["radius"] = radius + entities.append(cast(DXFGraphic, factory.new("CIRCLE", dxfattribs))) + + return entities diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/polyline.py b/.venv/lib/python3.12/site-packages/ezdxf/render/polyline.py new file mode 100644 index 0000000..6f77f97 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/polyline.py @@ -0,0 +1,248 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Union +import logging +import math + +from ezdxf.entities import factory +from ezdxf.lldxf.const import VERTEXNAMES +from ezdxf.math import Vec3, bulge_to_arc, OCS + +if TYPE_CHECKING: + from ezdxf.entities import LWPolyline, Polyline, Line, Arc, Face3d, Polymesh + +logger = logging.getLogger("ezdxf") + + +def virtual_lwpolyline_entities( + lwpolyline: LWPolyline, +) -> Iterable[Union[Line, Arc]]: + """Yields 'virtual' entities of LWPOLYLINE as LINE or ARC objects. + + These entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + assert lwpolyline.dxftype() == "LWPOLYLINE" + + points = lwpolyline.get_points("xyb") + if len(points) < 2: + return + + if lwpolyline.closed: + points.append(points[0]) + + yield from _virtual_polyline_entities( + points=points, + elevation=lwpolyline.dxf.elevation, + extrusion=lwpolyline.dxf.get("extrusion", None), + dxfattribs=lwpolyline.graphic_properties(), + doc=lwpolyline.doc, + ) + + +def virtual_polyline_entities( + polyline: Polyline, +) -> Iterable[Union[Line, Arc, Face3d]]: + """Yields 'virtual' entities of POLYLINE as LINE, ARC or 3DFACE objects. + + These entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + assert polyline.dxftype() == "POLYLINE" + if polyline.is_2d_polyline: + return virtual_polyline2d_entities(polyline) + elif polyline.is_3d_polyline: + return virtual_polyline3d_entities(polyline) + elif polyline.is_polygon_mesh: + return virtual_polymesh_entities(polyline) + elif polyline.is_poly_face_mesh: + return virtual_polyface_entities(polyline) + return [] + + +def virtual_polyline2d_entities( + polyline: Polyline, +) -> Iterable[Union[Line, Arc]]: + """Yields 'virtual' entities of 2D POLYLINE as LINE or ARC objects. + + These entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + assert polyline.dxftype() == "POLYLINE" + assert polyline.is_2d_polyline + if len(polyline.vertices) < 2: + return + + points = [ + (v.dxf.location.x, v.dxf.location.y, v.dxf.bulge) + for v in polyline.vertices + ] + if polyline.is_closed: + points.append(points[0]) + + yield from _virtual_polyline_entities( + points=points, + elevation=Vec3(polyline.dxf.get("elevation", (0, 0, 0))).z, + extrusion=polyline.dxf.get("extrusion", None), + dxfattribs=polyline.graphic_properties(), + doc=polyline.doc, + ) + + +def _virtual_polyline_entities( + points, elevation: float, extrusion: Vec3, dxfattribs: dict, doc +) -> Iterable[Union[Line, Arc]]: + ocs = OCS(extrusion) if extrusion else OCS() + prev_point = None + prev_bulge = None + + for x, y, bulge in points: + point = Vec3(x, y, elevation) + if prev_point is None: + prev_point = point + prev_bulge = bulge + continue + + attribs = dict(dxfattribs) + if prev_bulge != 0: + center, start_angle, end_angle, radius = bulge_to_arc( + prev_point, point, prev_bulge + ) + if radius > 0: + attribs["center"] = Vec3(center.x, center.y, elevation) + attribs["radius"] = radius + attribs["start_angle"] = math.degrees(start_angle) + attribs["end_angle"] = math.degrees(end_angle) + if extrusion: + attribs["extrusion"] = extrusion + yield factory.new(dxftype="ARC", dxfattribs=attribs, doc=doc) + else: + attribs["start"] = ocs.to_wcs(prev_point) + attribs["end"] = ocs.to_wcs(point) + yield factory.new(dxftype="LINE", dxfattribs=attribs, doc=doc) + prev_point = point + prev_bulge = bulge + + +def virtual_polyline3d_entities(polyline: Polyline) -> Iterable[Line]: + """Yields 'virtual' entities of 3D POLYLINE as LINE objects. + + This entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + assert polyline.dxftype() == "POLYLINE" + assert polyline.is_3d_polyline + if len(polyline.vertices) < 2: + return + doc = polyline.doc + vertices = polyline.vertices + dxfattribs = polyline.graphic_properties() + start = -1 if polyline.is_closed else 0 + for index in range(start, len(vertices) - 1): + dxfattribs["start"] = vertices[index].dxf.location + dxfattribs["end"] = vertices[index + 1].dxf.location + yield factory.new(dxftype="LINE", dxfattribs=dxfattribs, doc=doc) # type: ignore + + +def virtual_polymesh_entities(polyline: Polyline) -> Iterable[Face3d]: + """Yields 'virtual' entities of POLYMESH as 3DFACE objects. + + This entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + polymesh: "Polymesh" = polyline # type: ignore + assert polymesh.dxftype() == "POLYLINE" + assert polymesh.is_polygon_mesh + + doc = polymesh.doc + mesh = polymesh.get_mesh_vertex_cache() + dxfattribs = polymesh.graphic_properties() + m_count = polymesh.dxf.m_count + n_count = polymesh.dxf.n_count + m_range = m_count - int(not polymesh.is_m_closed) + n_range = n_count - int(not polymesh.is_n_closed) + + for m in range(m_range): + for n in range(n_range): + next_m = (m + 1) % m_count + next_n = (n + 1) % n_count + + dxfattribs["vtx0"] = mesh[m, n] + dxfattribs["vtx1"] = mesh[next_m, n] + dxfattribs["vtx2"] = mesh[next_m, next_n] + dxfattribs["vtx3"] = mesh[m, next_n] + yield factory.new(dxftype="3DFACE", dxfattribs=dxfattribs, doc=doc) # type: ignore + + +def virtual_polyface_entities(polyline: Polyline) -> Iterable[Face3d]: + """Yields 'virtual' entities of POLYFACE as 3DFACE objects. + + This entities are located at the original positions, but are not stored in + the entity database, have no handle and are not assigned to any layout. + + (internal API) + + """ + assert polyline.dxftype() == "POLYLINE" + assert polyline.is_poly_face_mesh + + doc = polyline.doc + vertices = polyline.vertices + base_attribs = polyline.graphic_properties() + + face_records = (v for v in vertices if v.is_face_record) + for face in face_records: + # check if vtx0, vtx1 and vtx2 exist + for name in VERTEXNAMES[:-1]: + if not face.dxf.hasattr(name): + logger.info( + f"skipped face {str(face)} with less than 3 vertices" + f"in PolyFaceMesh(#{str(polyline.dxf.handle)})" + ) + continue + # Alternate solutions: return a face with less than 3 vertices + # as LINE (breaks the method signature) or as degenerated 3DFACE + # (vtx0, vtx1, vtx1, vtx1) + + face3d_attribs = dict(base_attribs) + face3d_attribs.update(face.graphic_properties()) + invisible = 0 + pos = 1 + indices = ( + (face.dxf.get(name), name) + for name in VERTEXNAMES + if face.dxf.hasattr(name) + ) + for index, name in indices: + # vertex indices are 1-based, negative indices indicate invisible edges + if index < 0: + index = abs(index) + invisible += pos + # python list `vertices` is 0-based + face3d_attribs[name] = vertices[index - 1].dxf.location + # vertex index bit encoded: 1=0b0001, 2=0b0010, 3=0b0100, 4=0b1000 + pos <<= 1 + + if "vtx3" not in face3d_attribs: + # A triangle face ends with two identical vertices vtx2 and vtx3. + # This is a requirement defined by AutoCAD. + face3d_attribs["vtx3"] = face3d_attribs["vtx2"] + + face3d_attribs["invisible"] = invisible + yield factory.new(dxftype="3DFACE", dxfattribs=face3d_attribs, doc=doc) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/r12spline.py b/.venv/lib/python3.12/site-packages/ezdxf/render/r12spline.py new file mode 100644 index 0000000..2ba6ca1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/r12spline.py @@ -0,0 +1,236 @@ +# Copyright (c) 2018-2022 Manfred Moitzi +# License: MIT License +""" +DXF R12 Splines +=============== + +DXF R12 supports 2d B-splines, but Autodesk do not document the usage in the +DXF Reference. The base entity for splines in DXF R12 is the POLYLINE entity. + +Transformed Into 3D Space +------------------------- + +The spline itself is always in a plane, but as any 2D entity, the spline can be +transformed into the 3D object by elevation, extrusion and thickness/width. + +Open Quadratic Spline with Fit Vertices +------------------------------------- + +Example: 2D_SPLINE_QUADRATIC.dxf +expected knot vector: open uniform +degree: 2 +order: 3 + +POLYLINE: +flags (70): 4 = SPLINE_FIT_VERTICES_ADDED +smooth type (75): 5 = QUADRATIC_BSPLINE + +Sequence of VERTEX +flags (70): SPLINE_VERTEX_CREATED = 8 # Spline vertex created by spline-fitting + +This vertices are the curve vertices of the spline (fitted). + +Frame control vertices appear after the curve vertices. + +Sequence of VERTEX +flags (70): SPLINE_FRAME_CONTROL_POINT = 16 + +No control point at the starting point, but a control point at the end point, +last control point == last fit vertex + +Closed Quadratic Spline with Fit Vertices +----------------------------------------- + +Example: 2D_SPLINE_QUADRATIC_CLOSED.dxf +expected knot vector: closed uniform +degree: 2 +order: 3 + +POLYLINE: +flags (70): 5 = CLOSED | SPLINE_FIT_VERTICES_ADDED +smooth type (75): 5 = QUADRATIC_BSPLINE + +Sequence of VERTEX +flags (70): SPLINE_VERTEX_CREATED = 8 # Spline vertex created by spline-fitting + +Frame control vertices appear after the curve vertices. + +Sequence of VERTEX +flags (70): SPLINE_FRAME_CONTROL_POINT = 16 + + +Open Cubic Spline with Fit Vertices +----------------------------------- + +Example: 2D_SPLINE_CUBIC.dxf +expected knot vector: open uniform +degree: 3 +order: 4 + +POLYLINE: +flags (70): 4 = SPLINE_FIT_VERTICES_ADDED +smooth type (75): 6 = CUBIC_BSPLINE + +Sequence of VERTEX +flags (70): SPLINE_VERTEX_CREATED = 8 # Spline vertex created by spline-fitting + +This vertices are the curve vertices of the spline (fitted). + +Frame control vertices appear after the curve vertices. + +Sequence of VERTEX +flags (70): SPLINE_FRAME_CONTROL_POINT = 16 + +No control point at the starting point, but a control point at the end point, +last control point == last fit vertex + +Closed Curve With Extra Vertices Created +---------------------------------------- + +Example: 2D_FIT_CURVE_CLOSED.dxf + +POLYLINE: +flags (70): 3 = CLOSED | CURVE_FIT_VERTICES_ADDED + +Vertices with bulge values: + +flags (70): 1 = EXTRA_VERTEX_CREATED +Vertex 70=0, Vertex 70=1, Vertex 70=0, Vertex 70=1 + +""" +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional +from ezdxf.lldxf import const +from ezdxf.math import BSpline, closed_uniform_bspline, Vec3, UCS, UVec + +if TYPE_CHECKING: + from ezdxf.layouts import BaseLayout + from ezdxf.entities import Polyline + + +class R12Spline: + """DXF R12 supports 2D B-splines, but Autodesk do not document the usage + in the DXF Reference. The base entity for splines in DXF R12 is the POLYLINE + entity. The spline itself is always in a plane, but as any 2D entity, the + spline can be transformed into the 3D object by elevation and extrusion + (:ref:`OCS`, :ref:`UCS`). + + This way it was possible to store the spline parameters in the DXF R12 file, + to allow CAD applications to modify the spline parameters and rerender the + B-spline afterward again as polyline approximation. Therefore, the result is + not better than an approximation by the :class:`Spline` class, it is also + just a POLYLINE entity, but maybe someone need exact this tool in the + future. + + """ + + def __init__( + self, + control_points: Iterable[UVec], + degree: int = 2, + closed: bool = True, + ): + """ + Args: + control_points: B-spline control frame vertices + degree: degree of B-spline, only 2 and 3 is supported + closed: ``True`` for closed curve + + """ + self.control_points = Vec3.list(control_points) + self.degree = degree + self.closed = closed + + def approximate( + self, segments: int = 40, ucs: Optional[UCS] = None + ) -> list[UVec]: + """Approximate the B-spline by a polyline with `segments` line segments. + If `ucs` is not ``None``, ucs defines an :class:`~ezdxf.math.UCS`, to + transform the curve into :ref:`OCS`. The control points are placed + xy-plane of the UCS, don't use z-axis coordinates, if so make sure all + control points are in a plane parallel to the OCS base plane + (UCS xy-plane), else the result is unpredictable and depends on the CAD + application used to open the DXF file - it may crash. + + Args: + segments: count of line segments for approximation, vertex count is + `segments` + 1 + ucs: :class:`~ezdxf.math.UCS` definition, control points in ucs + coordinates + + Returns: + list of vertices in :class:`~ezdxf.math.OCS` as + :class:`~ezdxf.math.Vec3` objects + + """ + if self.closed: + spline = closed_uniform_bspline( + self.control_points, order=self.degree + 1 + ) + else: + spline = BSpline(self.control_points, order=self.degree + 1) + vertices = spline.approximate(segments) + if ucs is not None: + vertices = (ucs.to_ocs(vertex) for vertex in vertices) + return list(vertices) + + def render( + self, + layout: BaseLayout, + segments: int = 40, + ucs: Optional[UCS] = None, + dxfattribs=None, + ) -> Polyline: + """Renders the B-spline into `layout` as 2D :class:`~ezdxf.entities.Polyline` + entity. Use an :class:`~ezdxf.math.UCS` to place the 2D spline in the + 3D space, see :meth:`approximate` for more information. + + Args: + layout: :class:`~ezdxf.layouts.BaseLayout` object + segments: count of line segments for approximation, vertex count is + `segments` + 1 + ucs: :class:`~ezdxf.math.UCS` definition, control points in ucs + coordinates. + dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` + + """ + polyline = layout.add_polyline2d(points=[], dxfattribs=dxfattribs) + flags = polyline.SPLINE_FIT_VERTICES_ADDED + if self.closed: + flags |= polyline.CLOSED + polyline.dxf.flags = flags + + if self.degree == 2: + smooth_type = polyline.QUADRATIC_BSPLINE + elif self.degree == 3: + smooth_type = polyline.CUBIC_BSPLINE + else: + raise ValueError("invalid degree of spline") + polyline.dxf.smooth_type = smooth_type + + # set OCS extrusion vector + if ucs is not None: + polyline.dxf.extrusion = ucs.uz + + # add fit points in OCS + polyline.append_vertices( + self.approximate(segments, ucs), + dxfattribs={ + "layer": polyline.dxf.layer, + "flags": const.VTX_SPLINE_VERTEX_CREATED, + }, + ) + + # add control frame points in OCS + control_points = self.control_points + if ucs is not None: + control_points = list(ucs.points_to_ocs(control_points)) + polyline.dxf.elevation = (0, 0, control_points[0].z) + polyline.append_vertices( + control_points, + dxfattribs={ + "layer": polyline.dxf.layer, + "flags": const.VTX_SPLINE_FRAME_CONTROL_POINT, + }, + ) + return polyline diff --git a/.venv/lib/python3.12/site-packages/ezdxf/render/trace.py b/.venv/lib/python3.12/site-packages/ezdxf/render/trace.py new file mode 100644 index 0000000..d9d1047 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/render/trace.py @@ -0,0 +1,608 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Tuple, + Union, + cast, + Sequence, + Optional, +) +from typing_extensions import TypeAlias +from abc import abstractmethod +from collections import namedtuple +import math +import numpy as np + +from ezdxf.math import ( + Vec2, + Vec3, + UVec, + BSpline, + ConstructionRay, + OCS, + ParallelRaysError, + bulge_to_arc, + ConstructionArc, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFGraphic, Solid, Trace, Face3d, LWPolyline, Polyline + +__all__ = ["TraceBuilder", "LinearTrace", "CurvedTrace"] + +LinearStation = namedtuple("LinearStation", ("vertex", "start_width", "end_width")) +# start_width of the next (following) segment +# end_width of the next (following) segment + +CurveStation = namedtuple("CurveStation", ("vertex0", "vertex1")) + +Face: TypeAlias = Tuple[Vec2, Vec2, Vec2, Vec2] +Polygon: TypeAlias = Sequence[Vec2] +Quadrilateral: TypeAlias = Union["Solid", "Trace", "Face3d"] + + +class AbstractTrace: + @abstractmethod + def faces(self) -> Iterable[Face]: + # vertex order: up1, down1, down2, up2 + # faces connections: + # up2 -> next up1 + # down2 -> next down1 + pass + + def polygon(self) -> Polygon: + def merge(vertices: Polygon) -> Iterable[UVec]: + if not len(vertices): + return + + _vertices = iter(vertices) + prev = next(_vertices) + yield prev + for vertex in _vertices: + if not prev.isclose(vertex): + yield vertex + prev = vertex + + forward_contour: list[Vec2] = [] + backward_contour: list[Vec2] = [] + for up1, down1, down2, up2 in self.faces(): + forward_contour.extend((down1, down2)) + backward_contour.extend((up1, up2)) + + contour = list(merge(forward_contour)) + contour.extend(reversed(list(merge(backward_contour)))) + return contour + + def virtual_entities( + self, dxftype="TRACE", dxfattribs=None, doc: Optional[Drawing] = None + ) -> Iterable[Quadrilateral]: + """ + Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes + given in `dxfattribs`. + + If a document is given, the doc attribute of the new entities will be + set and the new entities will be automatically added to the entity + database of that document. + + Args: + dxftype: DXF type as string, "SOLID", "TRACE" or "3DFACE" + dxfattribs: DXF attributes for SOLID, TRACE or 3DFACE entities + doc: associated document + + """ + from ezdxf.entities.factory import new + + if dxftype not in {"SOLID", "TRACE", "3DFACE"}: + raise TypeError(f"Invalid dxftype {dxftype}.") + dxfattribs = dict(dxfattribs or {}) + for face in self.faces(): + for i in range(4): + dxfattribs[f"vtx{i}"] = face[i] + + if dxftype != "3DFACE": + # weird vertex order for SOLID and TRACE + dxfattribs["vtx2"] = face[3] + dxfattribs["vtx3"] = face[2] + entity = new(dxftype, dxfattribs, doc) + if doc: + doc.entitydb.add(entity) + yield entity # type: ignore + + +class LinearTrace(AbstractTrace): + """Linear 2D banded lines like polylines with start- and end width. + + Accepts 3D input, but z-axis is ignored. + + """ + + def __init__(self) -> None: + self._stations: list[LinearStation] = [] + self.abs_tol = 1e-12 + + def __len__(self): + return len(self._stations) + + def __getitem__(self, item): + return self._stations[item] + + @property + def is_started(self) -> bool: + """`True` if at least one station exist.""" + return bool(self._stations) + + def add_station( + self, point: UVec, start_width: float, end_width: Optional[float] = None + ) -> None: + """Add a trace station (like a vertex) at location `point`, + `start_width` is the width of the next segment starting at this station, + `end_width` is the end width of the next segment. + + Adding the last location again, replaces the actual last location e.g. + adding lines (a, b), (b, c), creates only 3 stations (a, b, c), this is + very important to connect to/from splines. + + Args: + point: 2D location (vertex), z-axis of 3D vertices is ignored. + start_width: start width of next segment + end_width: end width of next segment + + """ + if end_width is None: + end_width = start_width + point = Vec2(point) + stations = self._stations + + if bool(stations) and stations[-1].vertex.isclose(point, abs_tol=self.abs_tol): + # replace last station + stations.pop() + stations.append(LinearStation(point, float(start_width), float(end_width))) + + def faces(self) -> Iterable[Face]: + """Yields all faces as 4-tuples of :class:`~ezdxf.math.Vec2` objects. + + First and last miter is 90 degrees if the path is not closed, otherwise + the intersection of first and last segment is taken into account, + a closed path has to have explicit the same last and first vertex. + + """ + stations = self._stations + count = len(stations) + if count < 2: # Two or more stations required to create faces + return + + def offset_rays( + segment: int, + ) -> tuple[ConstructionRay, ConstructionRay]: + """Create offset rays from segment offset vertices.""" + + def ray(v1, v2): + if v1.isclose(v2): + # vertices too close to define a ray, offset ray is parallel to segment: + angle = ( + stations[segment].vertex - stations[segment + 1].vertex + ).angle + return ConstructionRay(v1, angle) + else: + return ConstructionRay(v1, v2) + + left1, left2, right1, right2 = segments[segment] + return ray(left1, left2), ray(right1, right2) + + def intersect( + ray1: ConstructionRay, ray2: ConstructionRay, default: Vec2 + ) -> Vec2: + """Intersect two rays but take parallel rays into account.""" + # check for nearly parallel rays pi/100 ~1.8 degrees + angle = abs(ray1.direction.angle_between(ray2.direction)) + if angle < 0.031415 or abs(math.pi - angle) < 0.031415: + return default + try: + return ray1.intersect(ray2) + except ParallelRaysError: + return default + + # Path has to be explicit closed by vertices: + is_closed = stations[0].vertex.isclose(stations[-1].vertex) + + segments = [] + # Each segment has 4 offset vertices normal to the line from start- to + # end vertex + # 1st vertex left of line at the start, distance = start_width/2 + # 2nd vertex left of line at the end, distance = end_width/2 + # 3rd vertex right of line at the start, distance = start_width/2 + # 4th vertex right of line at the end, distance = end_width/2 + for station in range(count - 1): + start_vertex, start_width, end_width = stations[station] + end_vertex = stations[station + 1].vertex + # Start- and end vertex are never to close together, close stations + # will be merged in method LinearTrace.add_station(). + segments.append( + _normal_offset_points(start_vertex, end_vertex, start_width, end_width) + ) + + # offset rays: + # 1 is the upper or left of line + # 2 is the lower or right of line + offset_ray1, offset_ray2 = offset_rays(0) + prev_offset_ray1 = None + prev_offset_ray2 = None + + # Store last vertices explicit, they get modified for closed paths. + last_up1, last_up2, last_down1, last_down2 = segments[-1] + + for i in range(len(segments)): + up1, up2, down1, down2 = segments[i] + if i == 0: + # Set first vertices of the first face. + if is_closed: + # Compute first two vertices as intersection of first and + # last segment + last_offset_ray1, last_offset_ray2 = offset_rays(len(segments) - 1) + vtx0 = intersect(last_offset_ray1, offset_ray1, up1) + vtx1 = intersect(last_offset_ray2, offset_ray2, down1) + + # Store last vertices for the closing face. + last_up2 = vtx0 + last_down2 = vtx1 + else: + # Set first two vertices of the first face for an open path. + vtx0 = up1 + vtx1 = down1 + prev_offset_ray1 = offset_ray1 + prev_offset_ray2 = offset_ray2 + else: + # Compute first two vertices for the actual face. + vtx0 = intersect(prev_offset_ray1, offset_ray1, up1) # type: ignore + vtx1 = intersect(prev_offset_ray2, offset_ray2, down1) # type: ignore + + if i < len(segments) - 1: + # Compute last two vertices for the actual face. + next_offset_ray1, next_offset_ray2 = offset_rays(i + 1) + vtx2 = intersect(next_offset_ray2, offset_ray2, down2) + vtx3 = intersect(next_offset_ray1, offset_ray1, up2) + prev_offset_ray1 = offset_ray1 + prev_offset_ray2 = offset_ray2 + offset_ray1 = next_offset_ray1 + offset_ray2 = next_offset_ray2 + else: + # Pickup last two vertices for the last face. + vtx2 = last_down2 + vtx3 = last_up2 + yield vtx0, vtx1, vtx2, vtx3 + + +def _normal_offset_points( + start: Vec2, end: Vec2, start_width: float, end_width: float +) -> Face: + dir_vector = (end - start).normalize() + ortho = dir_vector.orthogonal(True) + offset_start = ortho.normalize(start_width / 2) + offset_end = ortho.normalize(end_width / 2) + return ( + start + offset_start, + end + offset_end, + start - offset_start, + end - offset_end, + ) + + +_NULLVEC2 = Vec2((0, 0)) + + +class CurvedTrace(AbstractTrace): + """2D banded curves like arcs or splines with start- and end width. + + Represents always only one curved entity and all miter of curve segments + are perpendicular to curve tangents. + + Accepts 3D input, but z-axis is ignored. + + """ + + def __init__(self) -> None: + self._stations: list[CurveStation] = [] + + def __len__(self): + return len(self._stations) + + def __getitem__(self, item): + return self._stations[item] + + @classmethod + def from_spline( + cls, + spline: BSpline, + start_width: float, + end_width: float, + segments: int, + ) -> CurvedTrace: + """ + Create curved trace from a B-spline. + + Args: + spline: :class:`~ezdxf.math.BSpline` object + start_width: start width + end_width: end width + segments: count of segments for approximation + + """ + curve_trace = cls() + count = segments + 1 + t = np.linspace(0, spline.max_t, count) + for (point, derivative), width in zip( + spline.derivatives(t, n=1), np.linspace(start_width, end_width, count) + ): + normal = Vec2(derivative).orthogonal(True) + curve_trace._append(Vec2(point), normal, width) + return curve_trace + + @classmethod + def from_arc( + cls, + arc: ConstructionArc, + start_width: float, + end_width: float, + segments: int = 64, + ) -> CurvedTrace: + """ + Create curved trace from an arc. + + Args: + arc: :class:`~ezdxf.math.ConstructionArc` object + start_width: start width + end_width: end width + segments: count of segments for full circle (360 degree) + approximation, partial arcs have proportional less segments, + but at least 3 + + Raises: + ValueError: if arc.radius <= 0 + + """ + if arc.radius <= 0: + raise ValueError(f"Invalid radius: {arc.radius}.") + curve_trace = cls() + count = max(math.ceil(arc.angle_span / 360.0 * segments), 3) + 1 + center = Vec2(arc.center) + for point, width in zip( + arc.vertices(arc.angles(count)), + np.linspace(start_width, end_width, count), + ): + curve_trace._append(point, point - center, width) + return curve_trace + + def _append(self, point: Vec2, normal: Vec2, width: float) -> None: + """ + Add a curve trace station (like a vertex) at location `point`. + + Args: + point: 2D curve location (vertex), z-axis of 3D vertices is ignored. + normal: curve normal + width: width of station + + """ + if _NULLVEC2.isclose(normal): + normal = _NULLVEC2 + else: + normal = normal.normalize(width / 2) + self._stations.append(CurveStation(point + normal, point - normal)) + + def faces(self) -> Iterable[Face]: + """Yields all faces as 4-tuples of :class:`~ezdxf.math.Vec2` objects.""" + count = len(self._stations) + if count < 2: # Two or more stations required to create faces + return + + vtx0 = None + vtx1 = None + for vtx2, vtx3 in self._stations: + if vtx0 is None: + vtx0 = vtx3 + vtx1 = vtx2 + continue + yield vtx0, vtx1, vtx2, vtx3 + vtx0 = vtx3 + vtx1 = vtx2 + + +class TraceBuilder(Sequence): + """Sequence of 2D banded lines like polylines with start- and end width or + curves with start- and end width. + + + .. note:: + + Accepts 3D input, but z-axis is ignored. The :class:`TraceBuilder` is a + 2D only object and uses only the :ref:`OCS` coordinates! + + """ + + def __init__(self) -> None: + self._traces: list[AbstractTrace] = [] + self.abs_tol = 1e-12 + + def __len__(self): + return len(self._traces) + + def __getitem__(self, item): + return self._traces[item] + + def append(self, trace: AbstractTrace) -> None: + """Append a new trace.""" + self._traces.append(trace) + + def faces(self) -> Iterable[Face]: + """Yields all faces as 4-tuples of :class:`~ezdxf.math.Vec2` objects + in :ref:`OCS`. + """ + for trace in self._traces: + yield from trace.faces() + + def faces_wcs(self, ocs: OCS, elevation: float) -> Iterable[Sequence[Vec3]]: + """Yields all faces as 4-tuples of :class:`~ezdxf.math.Vec3` objects + in :ref:`WCS`. + """ + for face in self.faces(): + yield tuple(ocs.points_to_wcs(Vec3(v.x, v.y, elevation) for v in face)) + + def polygons(self) -> Iterable[Polygon]: + """Yields for each sub-trace a single polygon as sequence of + :class:`~ezdxf.math.Vec2` objects in :ref:`OCS`. + """ + for trace in self._traces: + yield trace.polygon() + + def polygons_wcs(self, ocs: OCS, elevation: float) -> Iterable[Sequence[Vec3]]: + """Yields for each sub-trace a single polygon as sequence of + :class:`~ezdxf.math.Vec3` objects in :ref:`WCS`. + """ + for trace in self._traces: + yield tuple( + ocs.points_to_wcs(Vec3(v.x, v.y, elevation) for v in trace.polygon()) + ) + + def virtual_entities( + self, dxftype="TRACE", dxfattribs=None, doc: Optional[Drawing] = None + ) -> Iterable[Quadrilateral]: + """Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes + given in `dxfattribs`. + + If a document is given, the doc attribute of the new entities will be + set and the new entities will be automatically added to the entity + database of that document. + + .. note:: + + The :class:`TraceBuilder` is a 2D only object and uses only the + :ref:`OCS` coordinates! + + Args: + dxftype: DXF type as string, "SOLID", "TRACE" or "3DFACE" + dxfattribs: DXF attributes for SOLID, TRACE or 3DFACE entities + doc: associated document + + """ + for trace in self._traces: + yield from trace.virtual_entities(dxftype, dxfattribs, doc) + + def close(self): + """Close multi traces by merging first and last trace, if linear traces.""" + traces = self._traces + if len(traces) < 2: + return + if isinstance(traces[0], LinearTrace) and isinstance(traces[-1], LinearTrace): + first = cast(LinearTrace, traces.pop(0)) + last = cast(LinearTrace, traces[-1]) + for point, start_width, end_width in first: + last.add_station(point, start_width, end_width) + + @classmethod + def from_polyline(cls, polyline: DXFGraphic, segments: int = 64) -> TraceBuilder: + """ + Create a complete trace from a LWPOLYLINE or a 2D POLYLINE entity, the + trace consist of multiple sub-traces if :term:`bulge` values are + present. Uses only the :ref:`OCS` coordinates! + + Args: + polyline: :class:`~ezdxf.entities.LWPolyline` or 2D + :class:`~ezdxf.entities.Polyline` + segments: count of segments for bulge approximation, given count is + for a full circle, partial arcs have proportional less segments, + but at least 3 + + """ + dxftype = polyline.dxftype() + if dxftype == "LWPOLYLINE": + polyline = cast("LWPolyline", polyline) + const_width = polyline.dxf.const_width + points = [] + for x, y, start_width, end_width, bulge in polyline.lwpoints: + location = Vec2(x, y) + if const_width: + # This is AutoCAD behavior, BricsCAD uses const width + # only for missing width values. + start_width = const_width + end_width = const_width + points.append((location, start_width, end_width, bulge)) + closed = polyline.closed + elif dxftype == "POLYLINE": + polyline = cast("Polyline", polyline) + if not polyline.is_2d_polyline: + raise TypeError("2D POLYLINE required") + closed = polyline.is_closed + default_start_width = polyline.dxf.default_start_width + default_end_width = polyline.dxf.default_end_width + points = [] + for vertex in polyline.vertices: + location = Vec2(vertex.dxf.location) + if vertex.dxf.hasattr("start_width"): + start_width = vertex.dxf.start_width + else: + start_width = default_start_width + if vertex.dxf.hasattr("end_width"): + end_width = vertex.dxf.end_width + else: + end_width = default_end_width + bulge = vertex.dxf.bulge + points.append((location, start_width, end_width, bulge)) + else: + raise TypeError(f"Invalid DXF type {dxftype}") + + if closed and not points[0][0].isclose(points[-1][0]): + # close polyline explicit + points.append(points[0]) + + trace = cls() + store_bulge = None + store_start_width = None + store_end_width = None + store_point = None + + linear_trace = LinearTrace() + for point, start_width, end_width, bulge in points: + if store_bulge: + center, start_angle, end_angle, radius = bulge_to_arc( + store_point, point, store_bulge + ) + if radius > 0: + arc = ConstructionArc( + center, + radius, + math.degrees(start_angle), + math.degrees(end_angle), + is_counter_clockwise=True, + ) + if arc.start_point.isclose(point): + sw = store_end_width + ew = store_start_width + else: + ew = store_end_width + sw = store_start_width + trace.append(CurvedTrace.from_arc(arc, sw, ew, segments)) + store_bulge = None + + if bulge != 0: # arc from prev_point to point + if linear_trace.is_started: + linear_trace.add_station(point, start_width, end_width) + trace.append(linear_trace) + linear_trace = LinearTrace() + store_bulge = bulge + store_start_width = start_width + store_end_width = end_width + store_point = point + continue + + linear_trace.add_station(point, start_width, end_width) + if linear_trace.is_started: + trace.append(linear_trace) + + if closed and len(trace) > 1: + # This is required for traces with multiple paths to create the correct + # miter at the closing point. (only linear to linear trace). + trace.close() + return trace diff --git a/.venv/lib/python3.12/site-packages/ezdxf/reorder.py b/.venv/lib/python3.12/site-packages/ezdxf/reorder.py new file mode 100644 index 0000000..c01d1a3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/reorder.py @@ -0,0 +1,100 @@ +# Copyright (c) 2020-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Union, Mapping, Optional +import heapq + +if TYPE_CHECKING: + from ezdxf.entities import DXFGraphic + +__all__ = ["ascending", "descending"] + + +def ascending( + entities: Iterable[DXFGraphic], + mapping: Optional[Union[dict, Iterable[tuple[str, str]]]] = None, +) -> Iterable[DXFGraphic]: + """Yields entities in ascending handle order. + + The sort-handle doesn't have to be the entity handle, every entity handle + in `mapping` will be replaced by the given sort-handle, `mapping` is an + iterable of 2-tuples (entity_handle, sort_handle) or a + dict (entity_handle, sort_handle). Entities with equal sort-handles show + up in source entities order. + + Args: + entities: iterable of :class:`DXFGraphic` objects + mapping: iterable of 2-tuples (entity_handle, sort_handle) or a + handle mapping as dict. + + """ + mapping = dict(mapping) if mapping else {} + heap = _build(entities, mapping, +1) + return _sorted(heap) + + +def descending( + entities: Iterable[DXFGraphic], + mapping: Optional[Union[dict, Iterable[tuple[str, str]]]] = None, +) -> Iterable[DXFGraphic]: + """Yields entities in descending handle order. + + The sort-handle doesn't have to be the entity handle, every entity handle + in `mapping` will be replaced by the given sort-handle, `mapping` is an + iterable of 2-tuples (entity_handle, sort_handle) or a + dict (entity_handle, sort_handle). Entities with equal sort-handles show + up in reversed source entities order. + + Args: + entities: iterable of :class:`DXFGraphic` objects + mapping: iterable of 2-tuples (entity_handle, sort_handle) or a + handle mapping as dict. + + """ + mapping = dict(mapping) if mapping else {} + heap = _build(entities, mapping, -1) + return _sorted(heap) + + +def _sorted(heap) -> Iterable[DXFGraphic]: + """Yields heap content in order.""" + while heap: + yield heapq.heappop(heap)[-1] + + +def _build( + entities: Iterable[DXFGraphic], mapping: Mapping, order: int +) -> list[tuple[int, int, DXFGraphic]]: + """Returns a heap structure. + + Args: + entities: DXF entities to order + mapping: handle remapping + order: +1 for ascending, -1 for descending + + """ + + def sort_handle(entity: DXFGraphic) -> int: + handle = entity.dxf.handle + sort_handle_ = int(mapping.get(handle, handle), 16) + # Special handling of sort-handle "0": this behavior is defined by + # AutoCAD but not documented in the DXF reference. + # max handle value: ODA DWG Specs: 2.13. Handle References + # COUNTER is 4 bits, which allows handles up to 16 * 1 byte = 128-bit + # Example for 128-bit handles: "CADKitSamples\AEC Plan Elev Sample.dxf" + return sort_handle_ if sort_handle_ else 0xFFFFFFFFFFFFFFFF + + heap: list[tuple[int, int, DXFGraphic]] = [] + for index, entity in enumerate(entities): + # DXFGraphic is not sortable, using the index as second value avoids + # a key function and preserves explicit the source order for + # equal sort-handles. + heapq.heappush( + heap, + ( + sort_handle(entity) * order, + index * order, + entity, + ), + ) + return heap diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/16x16.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/16x16.png new file mode 100644 index 0000000..0a6305f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/16x16.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/24x24.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/24x24.png new file mode 100644 index 0000000..3fe2560 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/24x24.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/256x256.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/256x256.png new file mode 100644 index 0000000..74eb6a9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/256x256.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/32x32.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/32x32.png new file mode 100644 index 0000000..8ec21d1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/32x32.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/48x48.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/48x48.png new file mode 100644 index 0000000..c825bfe Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/48x48.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/64x64.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/64x64.png new file mode 100644 index 0000000..082a902 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/64x64.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-copy-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-copy-64px.png new file mode 100644 index 0000000..61be6e1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-copy-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-find-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-find-64px.png new file mode 100644 index 0000000..59c25d8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-find-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-bookmark-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-bookmark-64px.png new file mode 100644 index 0000000..96038b1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-bookmark-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-handle-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-handle-64px.png new file mode 100644 index 0000000..c8b14cd Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-handle-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-line-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-line-64px.png new file mode 100644 index 0000000..3358b86 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-goto-line-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-left-arrow-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-left-arrow-64px.png new file mode 100644 index 0000000..a16af6b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-left-arrow-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-next-entity-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-next-entity-64px.png new file mode 100644 index 0000000..10d8587 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-next-entity-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-prev-entity-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-prev-entity-64px.png new file mode 100644 index 0000000..0da0b45 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-prev-entity-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-right-arrow-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-right-arrow-64px.png new file mode 100644 index 0000000..2003cfc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-right-arrow-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-show-in-tree-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-show-in-tree-64px.png new file mode 100644 index 0000000..456246e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-show-in-tree-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-store-bookmark-64px.png b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-store-bookmark-64px.png new file mode 100644 index 0000000..2e85bc6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/resources/icon-store-bookmark-64px.png differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/revcloud.py b/.venv/lib/python3.12/site-packages/ezdxf/revcloud.py new file mode 100644 index 0000000..64f48bb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/revcloud.py @@ -0,0 +1,115 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, TYPE_CHECKING, Iterable, Any +import math +from ezdxf.math import UVec, Vec2, has_clockwise_orientation +from ezdxf.entities import LWPolyline, DXFEntity + +if TYPE_CHECKING: + from ezdxf.layouts import BaseLayout + + +REVCLOUD_PROPS = "RevcloudProps" +REQUIRED_BULGE = 0.520567050552 + + +def points( + vertices: Iterable[UVec], + segment_length: float, + *, + bulge: float = REQUIRED_BULGE, # required to be recognized as REVCLOUD + start_width: float = 0.0, + end_width: float = 0.0, +) -> list[Sequence[float]]: + """Returns the points for a :class:`~ezdxf.entities.LWPolyline` entity to render a + revision cloud, similar to the REVCLOUD command in CAD applications. + + Args: + vertices: corner points of a polygon + segment_length: approximate segment length + bulge: LWPOLYLINE bulge value + start_width: start width of the segment arc + end_width: end width of the segment arc, CAD applications use 0.1 * segment_length + for a calligraphy effect + + """ + if segment_length < 1e-6: + raise ValueError("segment length too small.") + _vertices = _to_vec2_list(vertices) + lw_points: list[Sequence[float]] = [] + + for s, e in zip(_vertices, _vertices[1:]): + lw_points.append((s.x, s.y, start_width, end_width, bulge)) + diff = e - s + length = diff.magnitude + if length <= segment_length: + continue + + count = math.ceil(length / segment_length) + _segment_length = length / count + offset = diff.normalize(_segment_length) + for _ in range(count - 1): + s += offset + lw_points.append((s.x, s.y, start_width, end_width, bulge)) + return lw_points + + +def add_entity( + layout: BaseLayout, + vertices: Iterable[UVec], + segment_length: float, + *, + calligraphy=True, + dxfattribs: Any = None, +) -> LWPolyline: + """Adds a revision cloud as :class:`~ezdxf.entities.LWPolyline` entity to `layout`, + similar to the REVCLOUD command in CAD applications. + + Args: + layout: target layout + vertices: corner points of a polygon + segment_length: approximate segment length + calligraphy: ``True`` for a calligraphy effect + dxfattribs: additional DXF attributes + + """ + _vertices = _to_vec2_list(vertices) + bulge = REQUIRED_BULGE + if has_clockwise_orientation(_vertices): + bulge = -bulge + + end_width = segment_length * 0.1 if calligraphy else 0.0 + lw_points = points(_vertices, segment_length, bulge=bulge, end_width=end_width) + lwp = layout.add_lwpolyline(lw_points, close=True, dxfattribs=dxfattribs) + lwp.set_xdata(REVCLOUD_PROPS, [(1070, 0), (1040, segment_length)]) + doc = layout.doc + if doc is not None and not doc.appids.has_entry(REVCLOUD_PROPS): + doc.appids.add(REVCLOUD_PROPS) + return lwp + + +def is_revcloud(entity: DXFEntity) -> bool: + """Returns ``True`` when the given entity represents a revision cloud.""" + if not isinstance(entity, LWPolyline): + return False + lwpolyline: LWPolyline = entity + if not lwpolyline.is_closed: + return False + if not lwpolyline.has_xdata(REVCLOUD_PROPS): + return False + return all( + abs(REQUIRED_BULGE - abs(p[0])) < 0.02 + for p in lwpolyline.get_points(format="b") + ) + + +def _to_vec2_list(vertices: Iterable[UVec]) -> list[Vec2]: + _vertices: list[Vec2] = Vec2.list(vertices) + if len(_vertices) < 3: + raise ValueError("3 or more points required.") + if not _vertices[0].isclose(_vertices[-1]): + _vertices.append(_vertices[0]) + if len(_vertices) < 4: + raise ValueError("3 or more points required.") + return _vertices diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/__init__.py new file mode 100644 index 0000000..53e5aee --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..83738da Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/acdsdata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/acdsdata.cpython-312.pyc new file mode 100644 index 0000000..f89a753 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/acdsdata.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/blocks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/blocks.cpython-312.pyc new file mode 100644 index 0000000..2f76b7c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/blocks.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/classes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/classes.cpython-312.pyc new file mode 100644 index 0000000..4a5c830 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/classes.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/entities.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/entities.cpython-312.pyc new file mode 100644 index 0000000..b2eeb91 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/entities.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/header.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/header.cpython-312.pyc new file mode 100644 index 0000000..9d54b9a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/header.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/headervars.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/headervars.cpython-312.pyc new file mode 100644 index 0000000..0746fea Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/headervars.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/objects.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/objects.cpython-312.pyc new file mode 100644 index 0000000..fc9367e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/objects.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/table.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/table.cpython-312.pyc new file mode 100644 index 0000000..df0586e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/table.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/tables.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/tables.cpython-312.pyc new file mode 100644 index 0000000..69d414f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/sections/__pycache__/tables.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/acdsdata.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/acdsdata.py new file mode 100644 index 0000000..6a65439 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/acdsdata.py @@ -0,0 +1,518 @@ +# Purpose: acdsdata section manager +# Copyright (c) 2014-2022, Manfred Moitzi +# License: MIT License +""" +ACDSDATA entities have NO handles, therefore they can not be stored in the +drawing entity database. + +section structure (work in progress): +0 SECTION +2 ACDSDATA +70 2 # flag? +71 6 # count of following ACDSSCHEMA entities ??? no, just another flag + +0 ACDSSCHEMA # dxftype: schema definition +90 0 # schema number 0, 1, 2, 3 ... +1 AcDb3DSolid_ASM_Data # schema name + +2 AcDbDs::ID # subsection name +280 10 # subsection type 10 = ??? +91 8 # data ??? + +2 ASM_Data # subsection name +280 15 # subsection type +91 0 # data ??? +101 ACDSRECORD # data +95 0 +90 2 +... + +0 ACDSSCHEMA +90 1 +1 AcDb_Thumbnail_Schema +... + +0 ACDSSCHEMA +90 2 +1 AcDbDs::TreatedAsObjectDataSchema +... + +0 ACDSSCHEMA +90 3 +1 AcDbDs::LegacySchema +2 AcDbDs::Legacy +280 1 +91 0 + +0 ACDSSCHEMA +90 4 +1 AcDbDs::IndexedPropertySchema +2 AcDs:Indexable +280 1 +91 0 + +0 ACDSSCHEMA +90 5 +1 AcDbDs::HandleAttributeSchema +2 AcDbDs::HandleAttribute +280 7 +91 1 +284 1 + +0 ACDSRECORD # dxftype: data record +90 0 # ??? flag +2 AcDbDs::ID # subsection name +280 10 # subsection type 10 = handle to owner entity, 3DSOLID/REGION +320 339 # handle +2 ASM_Data # subsection name +280 15 # subsection type 15 = binary data +94 1088 # size of data +310 # data +310 # data +... + +0 ENDSEC +""" +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Iterable, Any, Optional +import abc +from itertools import islice + +from ezdxf.lldxf.tags import group_tags, Tags +from ezdxf.lldxf.types import dxftag +from ezdxf.lldxf.const import DXFKeyError, DXFStructureError + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + + +class AcDsEntity(abc.ABC): + @abc.abstractmethod + def export_dxf(self, tagwriter: AbstractTagWriter): + ... + + @abc.abstractmethod + def dxftype(self) -> str: + ... + + +class AcDsDataSection: + name = "ACDSDATA" + + def __init__(self, doc: Drawing, entities: Optional[Iterable[Tags]] = None): + self.doc = doc + self.entities: list[AcDsEntity] = [] + self.section_info = Tags() + if entities is not None: + self.load_tags(iter(entities)) + + @property + def is_valid(self) -> bool: + return len(self.section_info) > 0 + + @property + def has_records(self) -> bool: + return any( + isinstance(entity, AcDsRecord) for entity in self.entities + ) + + def load_tags(self, entities: Iterator[Tags]) -> None: + section_head = next(entities) + if section_head[0] != (0, "SECTION") or section_head[1] != ( + 2, + "ACDSDATA", + ): + raise DXFStructureError( + "Critical structure error in ACDSDATA section." + ) + + self.section_info = section_head + for entity in entities: + self.append(AcDsData(entity)) # tags have no subclasses + + def append(self, entity: AcDsData) -> None: + cls = ACDSDATA_TYPES.get(entity.dxftype(), AcDsData) + data = cls(entity.tags) + self.entities.append(data) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + if not self.is_valid or not self.has_records: + # Empty ACDSDATA section is not required! + return + tagwriter.write_tags(self.section_info) + for entity in self.entities: + entity.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + + @property + def acdsrecords(self) -> Iterator[AcDsRecord]: + return ( + entity for entity in self.entities if isinstance(entity, AcDsRecord) + ) + + def get_acis_data(self, handle: str) -> bytes: + asm_record = self.find_acis_record(handle) + if asm_record is not None: + return b"".join(get_acis_data(asm_record)) + return b"" + + def set_acis_data(self, handle: str, sab_data: bytes) -> None: + asm_record = self.find_acis_record(handle) + if asm_record is not None: + set_acis_data(asm_record, sab_data) + else: + self.new_acis_data(handle, sab_data) + + def new_acis_data(self, handle: str, sab_data: bytes) -> None: + self.entities.append(new_acis_record(handle, sab_data)) + + def del_acis_data(self, handle) -> None: + asm_record = self.find_acis_record(handle) + if asm_record is not None: + self.entities.remove(asm_record) + + def find_acis_record(self, handle: str) -> Optional[AcDsRecord]: + for record in self.acdsrecords: + if is_acis_data(record) and acis_entity_handle(record) == handle: + return record + return None + + +class AcDsData(AcDsEntity): + def __init__(self, tags: Tags): + self.tags = tags + + def export_dxf(self, tagwriter: AbstractTagWriter): + tagwriter.write_tags(self.tags) + + def dxftype(self) -> str: + return self.tags[0].value + + +class Section(Tags): + @property + def name(self) -> str: + return self[0].value + + @property + def type(self) -> str: + return self[1].value + + @property + def data(self) -> Tags: + return Tags(self[2:]) + + +class AcDsRecord(AcDsEntity): + def __init__(self, tags: Tags): + self._dxftype = tags[0] + self.flags = tags[1] + self.sections = [ + Section(group) + for group in group_tags(islice(tags, 2, None), splitcode=2) + ] + + def dxftype(self) -> str: + return "ACDSRECORD" + + def has_section(self, name: str) -> bool: + return self.get_section(name, default=None) is not None + + def get_section(self, name: str, default: Any = DXFKeyError) -> Section: + for section in self.sections: + if section.name == name: + return section + if default is DXFKeyError: + raise DXFKeyError(name) + else: + return default + + def index(self, name: str) -> int: + for i, section in enumerate(self.sections): + if section.name == name: + return i + return -1 + + def replace(self, section: Section) -> None: + index = self.index(section.name) + if index == -1: + self.sections.append(section) + else: + self.sections[index] = section + + def append(self, section: Section): + self.sections.append(section) + + def __len__(self): + return len(self.sections) + + def __getitem__(self, item) -> Section: + return self.sections[item] + + def _write_header(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_tags(Tags([self._dxftype, self.flags])) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + self._write_header(tagwriter) + for section in self.sections: + tagwriter.write_tags(section) + + +def get_acis_data(record: AcDsRecord) -> list[bytes]: + try: + asm_data = record.get_section("ASM_Data") + except DXFKeyError: # no data stored + return [] + else: + return [tag.value for tag in asm_data if tag.code == 310] + + +def is_acis_data(record: AcDsRecord) -> bool: + return record.has_section("ASM_Data") + + +def acis_entity_handle(record: AcDsRecord) -> str: + try: + section = record.get_section("AcDbDs::ID") + except DXFKeyError: # not present + return "" + return section.get_first_value(320, "") + + +def set_acis_data(record: AcDsRecord, data: bytes) -> None: + chunk_size = 127 + size = len(data) + tags = Tags( + [ + dxftag(2, "ASM_Data"), + dxftag(280, 15), + dxftag(94, size), + ] + ) + index = 0 + while index < size: + tags.append(dxftag(310, data[index : index + chunk_size])) + index += chunk_size + record.replace(Section(tags)) + + +def new_acis_record(handle: str, sab_data: bytes) -> AcDsRecord: + tags = Tags( + [ + dxftag(0, "ACDSRECORD"), + dxftag(90, 1), + dxftag(2, "AcDbDs::ID"), + dxftag(280, 10), + dxftag(320, handle), + ] + ) + record = AcDsRecord(tags) + set_acis_data(record, sab_data) + return record + + +ACDSDATA_TYPES = { + "ACDSRECORD": AcDsRecord, +} + + +DEFAULT_SETUP = """0 +SECTION +2 +ACDSDATA +70 +2 +71 +2 +0 +ACDSSCHEMA +90 +0 +1 +AcDb_Thumbnail_Schema +2 +AcDbDs::ID +280 +10 +91 +8 +2 +Thumbnail_Data +280 +15 +91 +0 +101 +ACDSRECORD +95 +0 +90 +2 +2 +AcDbDs::TreatedAsObjectData +280 +1 +291 +1 +101 +ACDSRECORD +95 +0 +90 +3 +2 +AcDbDs::Legacy +280 +1 +291 +1 +101 +ACDSRECORD +1 +AcDbDs::ID +90 +4 +2 +AcDs:Indexable +280 +1 +291 +1 +101 +ACDSRECORD +1 +AcDbDs::ID +90 +5 +2 +AcDbDs::HandleAttribute +280 +7 +282 +1 +0 +ACDSSCHEMA +90 +1 +1 +AcDb3DSolid_ASM_Data +2 +AcDbDs::ID +280 +10 +91 +8 +2 +ASM_Data +280 +15 +91 +0 +101 +ACDSRECORD +95 +1 +90 +2 +2 +AcDbDs::TreatedAsObjectData +280 +1 +291 +1 +101 +ACDSRECORD +95 +1 +90 +3 +2 +AcDbDs::Legacy +280 +1 +291 +1 +101 +ACDSRECORD +1 +AcDbDs::ID +90 +4 +2 +AcDs:Indexable +280 +1 +291 +1 +101 +ACDSRECORD +1 +AcDbDs::ID +90 +5 +2 +AcDbDs::HandleAttribute +280 +7 +282 +1 +0 +ACDSSCHEMA +90 +2 +1 +AcDbDs::TreatedAsObjectDataSchema +2 +AcDbDs::TreatedAsObjectData +280 +1 +91 +0 +0 +ACDSSCHEMA +90 +3 +1 +AcDbDs::LegacySchema +2 +AcDbDs::Legacy +280 +1 +91 +0 +0 +ACDSSCHEMA +90 +4 +1 +AcDbDs::IndexedPropertySchema +2 +AcDs:Indexable +280 +1 +91 +0 +0 +ACDSSCHEMA +90 +5 +1 +AcDbDs::HandleAttributeSchema +2 +AcDbDs::HandleAttribute +280 +7 +91 +1 +284 +1 +""" +# (0, ENDSEC) must be omitted! + + +def new_acds_data_section(doc: Drawing) -> AcDsDataSection: + if doc.dxfversion >= "AC1027": + return AcDsDataSection(doc, group_tags(Tags.from_text(DEFAULT_SETUP))) + else: + return AcDsDataSection(doc) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/blocks.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/blocks.py new file mode 100644 index 0000000..91b63fc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/blocks.py @@ -0,0 +1,499 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + Union, + cast, + Optional, +) +import logging + +from ezdxf.audit import Auditor, AuditError +from ezdxf.layouts.blocklayout import BlockLayout +from ezdxf.lldxf import const, validator +from ezdxf.lldxf.const import ( + DXFBlockInUseError, + DXFKeyError, + DXFStructureError, + DXFTableEntryError, + DXFTypeError, +) +from ezdxf.entities import ( + Attrib, + Block, + BlockRecord, + EndBlk, + entity_linker, + factory, + is_graphic_entity, +) +from ezdxf.math import UVec, NULLVEC, Vec3 +from ezdxf.render.arrows import ARROWS + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity, DXFTagStorage + from ezdxf.entitydb import EntityDB + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.sections.table import Table + +logger = logging.getLogger("ezdxf") + + +def is_special_block(name: str) -> bool: + name = name.upper() + # Anonymous dimension, groups and table blocks do not have explicit + # references by an INSERT entity: + if is_anonymous_block(name): + return True + + # Arrow blocks maybe used in DIMENSION or LEADER override without an + # INSERT reference: + if ARROWS.is_ezdxf_arrow(name): + return True + if name.startswith("_"): + if ARROWS.is_acad_arrow(ARROWS.arrow_name(name)): + return True + + return False + + +def is_anonymous_block(name: str) -> bool: + # *U### = anonymous BLOCK, require an explicit INSERT to be in use + # *E### = anonymous non-uniformly scaled BLOCK, requires INSERT? + # *X### = anonymous HATCH graphic, requires INSERT? + # *D### = anonymous DIMENSION graphic, has no explicit INSERT + # *A### = anonymous GROUP, requires INSERT? + # *T### = anonymous block for ACAD_TABLE, has no explicit INSERT + return len(name) > 1 and name[0] == "*" and name[1] in "UEXDAT" + + +def recover_block_name(block: Block) -> str: + name = block.dxf.get("name", "") + if name: + return name + owner = block.dxf.get("owner", "") + if not owner: + return "" + doc = block.doc + # The owner of BLOCK is BLOCK_RECORD which also stores the block name + # as group code 2; DXF attribute name is "name" + if doc is not None and doc.entitydb is not None: + block_record = doc.entitydb.get(owner) + if isinstance(block_record, BlockRecord): + return block_record.dxf.get("name", "") + return "" + + +_MISSING_BLOCK_ = Block() + + +class BlocksSection: + """ + Manages BLOCK definitions in a dict(), block names are case insensitive + e.g. 'Test' == 'TEST'. + + """ + + def __init__( + self, + doc: Optional[Drawing] = None, + entities: Optional[list[DXFEntity]] = None, + ): + self.doc = doc + if entities is not None: + self.load(entities) + self._reconstruct_orphaned_block_records() + self._anonymous_block_counter = 0 + + def __len__(self): + return len(self.block_records) + + @staticmethod + def key(entity: Union[str, BlockLayout]) -> str: + if not isinstance(entity, str): + entity = entity.name + return entity.lower() # block key is lower case + + @property + def block_records(self) -> Table: + return self.doc.block_records # type: ignore + + @property + def entitydb(self) -> EntityDB: + return self.doc.entitydb # type: ignore + + def load(self, entities: list[DXFEntity]) -> None: + """ + Load DXF entities into BlockLayouts. `entities` is a list of + entity tags, separated by BLOCK and ENDBLK entities. + + """ + + def load_block_record( + block: Block, + endblk: EndBlk, + block_entities: list[DXFEntity], + ) -> BlockRecord | None: + try: + block_record = cast("BlockRecord", block_records.get(block.dxf.name)) + # Special case DXF R12 - has no BLOCK_RECORD table + except DXFTableEntryError: + block_record = cast( + "BlockRecord", + block_records.new(block.dxf.name, dxfattribs={"scale": 0}), + ) + except DXFTypeError: + raise DXFStructureError( + f"Invalid or missing name of BLOCK #{block.dxf.handle}" + ) + # The BLOCK_RECORD is the central object which stores all the + # information about a BLOCK and also owns all the entities of + # this block definition. + block_record.set_block(block, endblk) + for entity in block_entities: + block_record.add_entity(entity) # type: ignore + return block_record + + def link_entities() -> Iterable["DXFEntity"]: + linked = entity_linker() + for entity in entities: + # Do not store linked entities (VERTEX, ATTRIB, SEQEND) in + # the block layout, linked entities ares stored in their + # parent entity e.g. VERTEX -> POLYLINE: + if not linked(entity): + yield entity + + block_records = self.block_records + section_head = cast("DXFTagStorage", entities[0]) + if section_head.dxftype() != "SECTION" or section_head.base_class[1] != ( + 2, + "BLOCKS", + ): + raise DXFStructureError("Critical structure error in BLOCKS section.") + # Remove SECTION entity + del entities[0] + content: list[DXFEntity] = [] + block: Block = _MISSING_BLOCK_ + for entity in link_entities(): + if isinstance(entity, Block): + if block is not _MISSING_BLOCK_: + logger.warning("Missing required ENDBLK, ignoring content.") + block = entity + content.clear() + elif isinstance(entity, EndBlk): + if block is _MISSING_BLOCK_: + logger.warning( + "Found ENDBLK without a preceding BLOCK, ignoring content." + ) + else: + block_name = block.dxf.get("name", "") + handle = block.dxf.get("handle", "") + if not block_name: + block_name = recover_block_name(block) + if block_name: + logger.info( + f'Recovered block name "{block_name}" for block #{handle}.' + ) + block.dxf.name = block_name + if block_name: + block_record = load_block_record(block, entity, content) + if isinstance(block_record, BlockRecord): + self.add(block_record) + else: + logger.warning( + f"Ignoring invalid BLOCK definition #{handle}." + ) + else: + logger.warning(f"Ignoring BLOCK without name #{handle}.") + block = _MISSING_BLOCK_ + content.clear() + else: + # No check for valid entities here: + # Use the audit or the recover module to fix invalid DXF files! + content.append(entity) + + def _reconstruct_orphaned_block_records(self): + """Find BLOCK_RECORD entries without block definition in the blocks + section and create block definitions for this orphaned block records. + + """ + for block_record in self.block_records: + if block_record.block is None: + block = factory.create_db_entry( + "BLOCK", + dxfattribs={ + "name": block_record.dxf.name, + "base_point": (0, 0, 0), + }, + doc=self.doc, + ) + endblk = factory.create_db_entry( + "ENDBLK", + dxfattribs={}, + doc=self.doc, + ) + block_record.set_block(block, endblk) + self.add(block_record) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_str(" 0\nSECTION\n 2\nBLOCKS\n") + for block_record in self.block_records: + assert isinstance(block_record, BlockRecord) + block_record.export_block_definition(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + + def add(self, block_record: BlockRecord) -> BlockLayout: + """Add or replace a block layout object defined by its block record. + (internal API) + """ + block_layout = BlockLayout(block_record) + block_record.block_layout = block_layout + assert self.block_records.has_entry(block_record.dxf.name) + return block_layout + + def __iter__(self) -> Iterator[BlockLayout]: + """Iterable of all :class:`~ezdxf.layouts.BlockLayout` objects.""" + return (block_record.block_layout for block_record in self.block_records) + + def __contains__(self, name: str) -> bool: + """Returns ``True`` if :class:`~ezdxf.layouts.BlockLayout` `name` + exist. + """ + return self.block_records.has_entry(name) + + def __getitem__(self, name: str) -> BlockLayout: + """Returns :class:`~ezdxf.layouts.BlockLayout` `name`, + raises :class:`DXFKeyError` if `name` not exist. + """ + try: + block_record = cast("BlockRecord", self.block_records.get(name)) + return block_record.block_layout # type: ignore + except DXFTableEntryError: + raise DXFKeyError(name) + + def __delitem__(self, name: str) -> None: + """Deletes :class:`~ezdxf.layouts.BlockLayout` `name` and all of + its content, raises :class:`DXFKeyError` if `name` not exist. + """ + if name in self: + self.block_records.remove(name) + else: + raise DXFKeyError(name) + + def block_names(self) -> list[str]: + """Returns a list of all block names.""" + return list(self.doc.block_records.entries.keys()) # type: ignore + + def get(self, name: str, default=None) -> BlockLayout: + """Returns :class:`~ezdxf.layouts.BlockLayout` `name`, returns + `default` if `name` not exist. + """ + try: + return self.__getitem__(name) + except DXFKeyError: + return default + + def get_block_layout_by_handle(self, block_record_handle: str) -> BlockLayout: + """Returns a block layout by block record handle. (internal API)""" + return self.doc.entitydb[block_record_handle].block_layout # type: ignore + + def new( + self, + name: str, + base_point: UVec = NULLVEC, + dxfattribs=None, + ) -> BlockLayout: + """Create and add a new :class:`~ezdxf.layouts.BlockLayout`, `name` + is the BLOCK name, `base_point` is the insertion point of the BLOCK. + """ + assert self.doc is not None + block_record = cast(BlockRecord, self.doc.block_records.new(name)) + + dxfattribs = dxfattribs or {} + dxfattribs["owner"] = block_record.dxf.handle + dxfattribs["name"] = name + dxfattribs["base_point"] = Vec3(base_point) + head = factory.create_db_entry("BLOCK", dxfattribs, self.doc) + tail = factory.create_db_entry( + "ENDBLK", {"owner": block_record.dxf.handle}, doc=self.doc + ) + block_record.set_block(head, tail) # type: ignore + return self.add(block_record) + + def new_anonymous_block( + self, type_char: str = "U", base_point: UVec = NULLVEC + ) -> BlockLayout: + """Create and add a new anonymous :class:`~ezdxf.layouts.BlockLayout`, + `type_char` is the BLOCK type, `base_point` is the insertion point of + the BLOCK. + + ========= ========== + type_char Anonymous Block Type + ========= ========== + ``'U'`` ``'*U###'`` anonymous BLOCK + ``'E'`` ``'*E###'`` anonymous non-uniformly scaled BLOCK + ``'X'`` ``'*X###'`` anonymous HATCH graphic + ``'D'`` ``'*D###'`` anonymous DIMENSION graphic + ``'A'`` ``'*A###'`` anonymous GROUP + ``'T'`` ``'*T###'`` anonymous block for ACAD_TABLE content + ========= ========== + + """ + block_name = self.anonymous_block_name(type_char) + block = self.new(block_name, base_point, {"flags": const.BLK_ANONYMOUS}) + return block + + def anonymous_block_name(self, type_char: str) -> str: + """Create name for an anonymous block. (internal API) + + Args: + type_char: letter + + U = *U### anonymous blocks + E = *E### anonymous non-uniformly scaled blocks + X = *X### anonymous hatches + D = *D### anonymous dimensions + A = *A### anonymous groups + T = *T### anonymous ACAD_TABLE content + + """ + while True: + self._anonymous_block_counter += 1 + block_name = f"*{type_char}{self._anonymous_block_counter}" + if not self.block_records.has_entry(block_name): + return block_name + + def rename_block(self, old_name: str, new_name: str) -> None: + """Rename :class:`~ezdxf.layouts.BlockLayout` `old_name` to `new_name` + + .. warning:: + + This is a low-level tool and does not rename the block references, + so all block references to `old_name` are pointing to a non-existing + block definition! + + """ + block_record = cast(BlockRecord, self.block_records.get(old_name)) + block_record.rename(new_name) + self.block_records.replace(old_name, block_record) + self.add(block_record) + + def delete_block(self, name: str, safe: bool = True) -> None: + """ + Delete block. Checks if the block is still referenced if `safe` is ``True``. + + Args: + name: block name (case insensitive) + safe: check if the block is still referenced or a special block without + explicit references + + Raises: + DXFKeyError: if block not exists + DXFBlockInUseError: if block is still referenced, and safe is ``True`` + + """ + if safe: + if is_special_block(name): + raise DXFBlockInUseError( + f'Special block "{name}" maybe used without explicit INSERT entity.' + ) + assert self.doc is not None + block_refs = self.doc.query(f"INSERT[name=='{name}']i") # ignore case + if len(block_refs): + raise DXFBlockInUseError(f'Block "{name}" is still in use.') + self.__delitem__(name) + + def delete_all_blocks(self) -> None: + """Delete all blocks without references except modelspace- or + paperspace layout blocks, special arrow- and anonymous blocks + (DIMENSION, ACAD_TABLE). + + .. warning:: + + There could exist references to blocks which are not documented in the DXF + reference, hidden in extended data sections or application defined data, + which could invalidate a DXF document if these blocks will be deleted. + + """ + assert self.doc is not None + active_references = set( + validator.make_table_key(entity.dxf.name) + for entity in self.doc.query("INSERT") + ) + + def is_safe(name: str) -> bool: + if is_special_block(name): + return False + return name not in active_references + + trash = set() + for block in self: + name = validator.make_table_key(block.name) + if not block.is_any_layout and is_safe(name): + trash.add(name) + + for name in trash: + self.__delitem__(name) + + def audit(self, auditor: Auditor) -> None: + """Audit and repair BLOCKS section. + + .. important:: + + Do not delete entities during the auditing process as this will alter + the entity database while iterating it, instead use:: + + auditor.trash(entity) + + to delete invalid entities after auditing automatically. + + """ + assert self.doc is auditor.doc, "Auditor for different DXF document." + + for block_record in self.block_records: + assert isinstance(block_record, BlockRecord) + + block_record_handle: str = block_record.dxf.handle + unlink_entities: list[DXFEntity] = [] + es = block_record.entity_space + for entity in es: + if not is_graphic_entity(entity): + auditor.fixed_error( + code=AuditError.REMOVED_INVALID_GRAPHIC_ENTITY, + message=f"Removed invalid DXF entity {str(entity)} from" + f" BLOCK '{block_record.dxf.name}'.", + ) + auditor.trash(entity) + elif isinstance(entity, Attrib): + # ATTRIB can only exist as an attached entity of the INSERT + # entity! + auditor.fixed_error( + code=AuditError.REMOVED_STANDALONE_ATTRIB_ENTITY, + message=f"Removed standalone {str(entity)} entity from" + f" BLOCK '{block_record.dxf.name}'.", + ) + auditor.trash(entity) + + if not entity.is_alive: + continue + + if entity.dxf.owner != block_record_handle: + auditor.fixed_error( + code=AuditError.REMOVED_ENTITY_WITH_INVALID_OWNER_HANDLE, + message=f"Removed DXF entity {str(entity)} with invalid owner " + f"handle (#{entity.dxf.owner} != #{block_record_handle}) " + f"from BLOCK '{block_record.dxf.name}'.", + ) + # do not destroy the entity, it's maybe owned to another block + unlink_entities.append(entity) + + for entity in unlink_entities: + if entity.is_alive: + try: + es.remove(entity) + except ValueError: + pass diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/classes.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/classes.py new file mode 100644 index 0000000..8169c52 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/classes.py @@ -0,0 +1,324 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Iterable, Union, cast, Optional +from collections import Counter, OrderedDict +import logging + +from ezdxf.lldxf.const import DXFStructureError, DXF2004, DXF2000, DXFKeyError +from ezdxf.entities.dxfclass import DXFClass +from ezdxf.entities.dxfentity import DXFEntity, DXFTagStorage + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +logger = logging.getLogger("ezdxf") + +# name: cpp_class_name (2), app_name (3), flags(90), was_a_proxy (280), +# is_an_entity (281) +# Multiple entries for 'name' are possible and supported, ClassSection stores +# entries with key: (name, cpp_class_name). +# 0 CLASS +# 1 MPOLYGON +# 2 AcDbMPolygon +# 3 "AcMPolygonObj15|Version(1.0.0.0) Product Desc: Object enabler for the AcDbMPolyg ... odesk.com" +# 90 3071, b101111111111 +# 280 0 +# 281 1 +CLASS_DEFINITIONS = { + "ACDBDICTIONARYWDFLT": [ + "AcDbDictionaryWithDefault", + "ObjectDBX Classes", + 0, + 0, + 0, + ], + "SUN": ["AcDbSun", "SCENEOE", 1153, 0, 0], + "DICTIONARYVAR": ["AcDbDictionaryVar", "ObjectDBX Classes", 0, 0, 0], + "TABLESTYLE": ["AcDbTableStyle", "ObjectDBX Classes", 4095, 0, 0], + "MATERIAL": ["AcDbMaterial", "ObjectDBX Classes", 1153, 0, 0], + "VISUALSTYLE": ["AcDbVisualStyle", "ObjectDBX Classes", 4095, 0, 0], + "SCALE": ["AcDbScale", "ObjectDBX Classes", 1153, 0, 0], + "MLEADERSTYLE": ["AcDbMLeaderStyle", "ACDB_MLEADERSTYLE_CLASS", 4095, 0, 0], + "MLEADER": ["AcDbMLeader", "ACDB_MLEADER_CLASS", 3071, 0, 1], + "MPOLYGON": ["AcDbMPolygon", "AcMPolygonObj15", 1025, 0, 1], + "CELLSTYLEMAP": ["AcDbCellStyleMap", "ObjectDBX Classes", 1152, 0, 0], + "EXACXREFPANELOBJECT": ["ExAcXREFPanelObject", "EXAC_ESW", 1025, 0, 0], + "NPOCOLLECTION": [ + "AcDbImpNonPersistentObjectsCollection", + "ObjectDBX Classes", + 1153, + 0, + 0, + ], + "LAYER_INDEX": ["AcDbLayerIndex", "ObjectDBX Classes", 0, 0, 0], + "SPATIAL_INDEX": ["AcDbSpatialIndex", "ObjectDBX Classes", 0, 0, 0], + "IDBUFFER": ["AcDbIdBuffer", "ObjectDBX Classes", 0, 0, 0], + "DIMASSOC": ["AcDbDimAssoc", "AcDbDimAssoc", 0, 0, 0], + "ACDBSECTIONVIEWSTYLE": [ + "AcDbSectionViewStyle", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "ACDBDETAILVIEWSTYLE": [ + "AcDbDetailViewStyle", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "IMAGEDEF": ["AcDbRasterImageDef", "ISM", 0, 0, 0], + "RASTERVARIABLES": ["AcDbRasterVariables", "ISM", 0, 0, 0], + "IMAGEDEF_REACTOR": ["AcDbRasterImageDefReactor", "ISM", 1, 0, 0], + "IMAGE": ["AcDbRasterImage", "ISM", 2175, 0, 1], + "PDFDEFINITION": ["AcDbPdfDefinition", "ObjectDBX Classes", 1153, 0, 0], + "PDFUNDERLAY": ["AcDbPdfReference", "ObjectDBX Classes", 4095, 0, 1], + "DWFDEFINITION": ["AcDbDwfDefinition", "ObjectDBX Classes", 1153, 0, 0], + "DWFUNDERLAY": ["AcDbDwfReference", "ObjectDBX Classes", 1153, 0, 1], + "DGNDEFINITION": ["AcDbDgnDefinition", "ObjectDBX Classes", 1153, 0, 0], + "DGNUNDERLAY": ["AcDbDgnReference", "ObjectDBX Classes", 1153, 0, 1], + "MENTALRAYRENDERSETTINGS": [ + "AcDbMentalRayRenderSettings", + "SCENEOE", + 1024, + 0, + 0, + ], + "ACDBPLACEHOLDER": ["AcDbPlaceHolder", "ObjectDBX Classes", 0, 0, 0], + "LAYOUT": ["AcDbLayout", "ObjectDBX Classes", 0, 0, 0], + "SURFACE": ["AcDbSurface", "ObjectDBX Classes", 4095, 0, 1], + "EXTRUDEDSURFACE": ["AcDbExtrudedSurface", "ObjectDBX Classes", 4095, 0, 1], + "LOFTEDSURFACE": ["AcDbLoftedSurface", "ObjectDBX Classes", 0, 0, 1], + "REVOLVEDSURFACE": ["AcDbRevolvedSurface", "ObjectDBX Classes", 0, 0, 1], + "SWEPTSURFACE": ["AcDbSweptSurface", "ObjectDBX Classes", 0, 0, 1], + "PLANESURFACE": ["AcDbPlaneSurface", "ObjectDBX Classes", 4095, 0, 1], + "NURBSSURFACE": ["AcDbNurbSurface", "ObjectDBX Classes", 4095, 0, 1], + "ACDBASSOCEXTRUDEDSURFACEACTIONBODY": [ + "AcDbAssocExtrudedSurfaceActionBody", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "ACDBASSOCLOFTEDSURFACEACTIONBODY": [ + "AcDbAssocLoftedSurfaceActionBody", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "ACDBASSOCREVOLVEDSURFACEACTIONBODY": [ + "AcDbAssocRevolvedSurfaceActionBody", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "ACDBASSOCSWEPTSURFACEACTIONBODY": [ + "AcDbAssocSweptSurfaceActionBody", + "ObjectDBX Classes", + 1025, + 0, + 0, + ], + "HELIX": ["AcDbHelix", "ObjectDBX Classes", 4095, 0, 1], + "WIPEOUT": ["AcDbWipeout", "WipeOut", 127, 0, 1], + "WIPEOUTVARIABLES": ["AcDbWipeoutVariables", "WipeOut", 0, 0, 0], + "FIELDLIST": ["AcDbFieldList", "ObjectDBX Classes", 1152, 0, 0], + "GEODATA": ["AcDbGeoData", "ObjectDBX Classes", 4095, 0, 0], + "SORTENTSTABLE": ["AcDbSortentsTable", "ObjectDBX Classes", 0, 0, 0], + "ACAD_TABLE": ["AcDbTable", "ObjectDBX Classes", 1025, 0, 1], + "ARC_DIMENSION": ["AcDbArcDimension", "ObjectDBX Classes", 1025, 0, 1], + "LARGE_RADIAL_DIMENSION": [ + "AcDbRadialDimensionLarge", + "ObjectDBX Classes", + 1025, + 0, + 1, + ], +} + +REQ_R2000 = [ + "ACDBDICTIONARYWDFLT", + "SUN", + "VISUALSTYLE", + "MATERIAL", + "SCALE", + "TABLESTYLE", + "MLEADERSTYLE", + "DICTIONARYVAR", + "CELLSTYLEMAP", + "MENTALRAYRENDERSETTINGS", + "ACDBDETAILVIEWSTYLE", + "ACDBSECTIONVIEWSTYLE", + "RASTERVARIABLES", + "ACDBPLACEHOLDER", + "LAYOUT", +] + +REQ_R2004 = [ + "ACDBDICTIONARYWDFLT", + "SUN", + "VISUALSTYLE", + "MATERIAL", + "SCALE", + "TABLESTYLE", + "MLEADERSTYLE", + "DICTIONARYVAR", + "CELLSTYLEMAP", + "MENTALRAYRENDERSETTINGS", + "ACDBDETAILVIEWSTYLE", + "ACDBSECTIONVIEWSTYLE", + "RASTERVARIABLES", +] + +REQUIRED_CLASSES = { + DXF2000: REQ_R2000, + DXF2004: REQ_R2004, +} + + +class ClassesSection: + def __init__( + self, + doc: Optional[Drawing] = None, + entities: Optional[Iterable[DXFEntity]] = None, + ): + # Multiple entries for 'name' possible -> key is (name, cpp_class_name) + # DXFClasses are not stored in the entities database, because CLASS has + # no handle. + self.classes: dict[tuple[str, str], DXFClass] = OrderedDict() + self.doc = doc + if entities is not None: + self.load(iter(entities)) + + def __iter__(self) -> Iterator[DXFClass]: + return (cls for cls in self.classes.values()) + + def load(self, entities: Iterator[DXFEntity]) -> None: + section_head = cast(DXFTagStorage, next(entities)) + + if section_head.dxftype() != "SECTION" or section_head.base_class[1] != ( + 2, + "CLASSES", + ): + raise DXFStructureError("Critical structure error in CLASSES section.") + + for cls_entity in entities: + if isinstance(cls_entity, DXFClass): + self.register(cls_entity) + else: + logger.warning( + f"Ignored invalid DXF entity type '{cls_entity.dxftype()}'" + f" in section CLASSES." + ) + + def register( + self, classes: Optional[Union[DXFClass, Iterable[DXFClass]]] = None + ) -> None: + if classes is None: + return + + if isinstance(classes, DXFClass): + classes = (classes,) + + for dxfclass in classes: + key = dxfclass.key + if key not in self.classes: + self.classes[key] = dxfclass + + def add_class(self, name: str): + """Register a known class by `name`.""" + if name not in CLASS_DEFINITIONS: + return + cls_data = CLASS_DEFINITIONS[name] + cls = DXFClass.new(doc=self.doc) + cpp, app, flags, proxy, entity = cls_data + cls.update_dxf_attribs( + { + "name": name, + "cpp_class_name": cpp, + "app_name": app, + "flags": flags, + "was_a_proxy": proxy, + "is_an_entity": entity, + } + ) + self.register(cls) + + def get(self, name: str) -> DXFClass: + """Returns the first class matching `name`. + + Storage key is the ``(name, cpp_class_name)`` tuple, because there are + some classes with the same :attr:`name` but different + :attr:`cpp_class_names`. + + """ + for cls in self.classes.values(): + if cls.dxf.name == name: + return cls + raise DXFKeyError(name) + + def add_required_classes(self, dxfversion: str) -> None: + """Add all required CLASS definitions for the specified DXF version.""" + names = REQUIRED_CLASSES.get(dxfversion, REQ_R2004) + for name in names: + self.add_class(name) + + if self.doc is None: # testing environment SUT + return + + dxf_types_in_use = self.doc.entitydb.dxf_types_in_use() + if "IMAGE" in dxf_types_in_use: + self.add_class("IMAGE") + self.add_class("IMAGEDEF") + self.add_class("IMAGEDEF_REACTOR") + if "PDFUNDERLAY" in dxf_types_in_use: + self.add_class("PDFDEFINITION") + self.add_class("PDFUNDERLAY") + if "DWFUNDERLAY" in dxf_types_in_use: + self.add_class("DWFDEFINITION") + self.add_class("DWFUNDERLAY") + if "DGNUNDERLAY" in dxf_types_in_use: + self.add_class("DGNDEFINITION") + self.add_class("DGNUNDERLAY") + if "EXTRUDEDSURFACE" in dxf_types_in_use: + self.add_class("EXTRUDEDSURFACE") + self.add_class("ACDBASSOCEXTRUDEDSURFACEACTIONBODY") + if "LOFTEDSURFACE" in dxf_types_in_use: + self.add_class("LOFTEDSURFACE") + self.add_class("ACDBASSOCLOFTEDSURFACEACTIONBODY") + if "REVOLVEDSURFACE" in dxf_types_in_use: + self.add_class("REVOLVEDSURFACE") + self.add_class("ACDBASSOCREVOLVEDSURFACEACTIONBODY") + if "SWEPTSURFACE" in dxf_types_in_use: + self.add_class("SWEPTSURFACE") + self.add_class("ACDBASSOCSWEPTSURFACEACTIONBODY") + + for dxftype in dxf_types_in_use: + self.add_class(dxftype) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF tags. (internal API)""" + tagwriter.write_str(" 0\nSECTION\n 2\nCLASSES\n") + for dxfclass in self.classes.values(): + dxfclass.export_dxf(tagwriter) + tagwriter.write_str(" 0\nENDSEC\n") + + def update_instance_counters(self) -> None: + """Update CLASS instance counter for all registered classes, requires + DXF R2004+. + """ + assert self.doc is not None + if self.doc.dxfversion < DXF2004: + return # instance counter not supported + counter: dict[str, int] = Counter() + # count all entities in the entity database + for entity in self.doc.entitydb.values(): + counter[entity.dxftype()] += 1 + + for dxfclass in self.classes.values(): + dxfclass.dxf.instance_count = counter[dxfclass.dxf.name] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/entities.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/entities.py new file mode 100644 index 0000000..ea3a417 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/entities.py @@ -0,0 +1,113 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Iterator, cast, Optional +from itertools import chain +import logging + +from ezdxf.lldxf import const +from ezdxf.entities import entity_linker + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity, DXFTagStorage, BlockRecord, DXFGraphic + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.lldxf.tags import Tags + + +logger = logging.getLogger("ezdxf") + + +class StoredSection: + def __init__(self, entities: list[Tags]): + self.entities = entities + + def export_dxf(self, tagwriter: AbstractTagWriter): + # (0, SECTION) (2, NAME) is stored in entities + for entity in self.entities: + tagwriter.write_tags(entity) + # ENDSEC not stored in entities !!! + tagwriter.write_str(" 0\nENDSEC\n") + + +class EntitySection: + """:class:`EntitiesSection` is just a proxy for :class:`Modelspace` and + active :class:`Paperspace` linked together. + """ + + def __init__( + self, + doc: Optional[Drawing] = None, + entities: Optional[Iterable[DXFEntity]] = None, + ): + self.doc = doc + if entities is not None: + self._build(iter(entities)) + + def __iter__(self) -> Iterator[DXFEntity]: + """Returns an iterator for all entities of the modelspace and the active + paperspace. + """ + assert self.doc is not None + layouts = self.doc.layouts + for entity in chain(layouts.modelspace(), layouts.active_layout()): + yield entity + + def __len__(self) -> int: + """Returns the count of all entities in the modelspace and the active paperspace. + """ + assert self.doc is not None + layouts = self.doc.layouts + return len(layouts.modelspace()) + len(layouts.active_layout()) + + # none public interface + + def _build(self, entities: Iterator[DXFEntity]) -> None: + assert self.doc is not None + section_head = cast("DXFTagStorage", next(entities)) + if section_head.dxftype() != "SECTION" or section_head.base_class[ + 1 + ] != (2, "ENTITIES"): + raise const.DXFStructureError( + "Critical structure error in ENTITIES section." + ) + + def add(entity: DXFGraphic): + handle = entity.dxf.owner + # higher priority for owner handle + paperspace = 0 + if handle == msp_layout_key: + paperspace = 0 + elif handle == psp_layout_key: + paperspace = 1 + elif entity.dxf.hasattr( + "paperspace" + ): # paperspace flag as fallback + paperspace = entity.dxf.paperspace + + if paperspace: + psp.add_entity(entity) + else: + msp.add_entity(entity) + + msp = cast("BlockRecord", self.doc.block_records.get("*Model_Space")) + psp = cast("BlockRecord", self.doc.block_records.get("*Paper_Space")) + msp_layout_key: str = msp.dxf.handle + psp_layout_key: str = psp.dxf.handle + linked_entities = entity_linker() + # Don't store linked entities (VERTEX, ATTRIB, SEQEND) in entity space + for entity in entities: + # No check for valid entities here: + # Use the audit- or the recover module to fix invalid DXF files! + if not linked_entities(entity): + add(entity) # type: ignore + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + assert self.doc is not None + layouts = self.doc.layouts + tagwriter.write_str(" 0\nSECTION\n 2\nENTITIES\n") + # Just write *Model_Space and the active *Paper_Space into the + # ENTITIES section. + layouts.modelspace().entity_space.export_dxf(tagwriter) + layouts.active_layout().entity_space.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/header.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/header.py new file mode 100644 index 0000000..9880915 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/header.py @@ -0,0 +1,371 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Any, + Iterable, + Iterator, + KeysView, + Optional, + Sequence, + TYPE_CHECKING, + Union, +) +import logging +from collections import OrderedDict + +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import group_tags, Tags, DXFTag +from ezdxf.lldxf.types import strtag +from ezdxf.lldxf.validator import header_validator +from ezdxf.sections.headervars import ( + HEADER_VAR_MAP, + version_specific_group_code, +) + +if TYPE_CHECKING: + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +logger = logging.getLogger("ezdxf") + +MIN_HEADER_TEXT = """ 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1009 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$HANDSEED + 5 +FF +""" + +# Additional variables may be stored as DICTIONARYVAR in the OBJECTS +# section in the DICTIONARY "AcDbVariableDictionary" of the root dict. +# - CANNOSCALE +# - CENTEREXE +# - CENTERLTYPEFILE +# - CETRANSPARENCY +# - CMLEADERSTYLE +# - CTABLESTYLE +# - CVIEWDETAILSTYLE +# - CVIEWSECTIONSTYLE +# - LAYEREVAL +# - LAYERNOTIFY +# - LIGHTINGUNITS +# - MSLTSCALE + + +class CustomVars: + """The :class:`CustomVars` class stores custom properties in the DXF header as + $CUSTOMPROPERTYTAG and $CUSTOMPROPERTY values. Custom properties require DXF R2004 + or later, `ezdxf` can create custom properties for older DXF versions as well, but + AutoCAD will not show that properties. + + """ + + def __init__(self) -> None: + self.properties: list[tuple[str, str]] = list() + + def __len__(self) -> int: + """Count of custom properties.""" + return len(self.properties) + + def __iter__(self) -> Iterator[tuple[str, str]]: + """Iterate over all custom properties as ``(tag, value)`` tuples.""" + return iter(self.properties) + + def clear(self) -> None: + """Remove all custom properties.""" + self.properties.clear() + + def append(self, tag: str, value: str) -> None: + """Add custom property as ``(tag, value)`` tuple.""" + # custom properties always stored as strings + self.properties.append((tag, str(value))) + + def get(self, tag: str, default: Optional[str] = None): + """Returns the value of the first custom property `tag`.""" + for key, value in self.properties: + if key == tag: + return value + else: + return default + + def has_tag(self, tag: str) -> bool: + """Returns ``True`` if custom property `tag` exist.""" + return self.get(tag) is not None + + def remove(self, tag: str, all: bool = False) -> None: + """Removes the first occurrence of custom property `tag`, removes all + occurrences if `all` is ``True``. + + Raises `:class:`DXFValueError` if `tag` does not exist. + + """ + found_tag = False + for item in self.properties: + if item[0] == tag: + self.properties.remove(item) + found_tag = True + if not all: + return + if not found_tag: + raise const.DXFValueError(f"Tag '{tag}' does not exist") + + def replace(self, tag: str, value: str) -> None: + """Replaces the value of the first custom property `tag` by a new + `value`. + + Raises :class:`DXFValueError` if `tag` does not exist. + + """ + properties = self.properties + for index in range(len(properties)): + name = properties[index][0] + if name == tag: + properties[index] = (name, value) + return + + raise const.DXFValueError(f"Tag '{tag}' does not exist") + + def write(self, tagwriter: AbstractTagWriter) -> None: + """Export custom properties as DXF tags. (internal API)""" + for tag, value in self.properties: + s = f" 9\n$CUSTOMPROPERTYTAG\n 1\n{tag}\n 9\n$CUSTOMPROPERTY\n 1\n{value}\n" + tagwriter.write_str(s) + + +def default_vars() -> OrderedDict: + vars = OrderedDict() + for vardef in HEADER_VAR_MAP.values(): + vars[vardef.name] = HeaderVar(DXFTag(vardef.code, vardef.default)) + return vars + + +class HeaderSection: + MIN_HEADER_TAGS = Tags.from_text(MIN_HEADER_TEXT) + name = "HEADER" + + def __init__(self) -> None: + self.hdrvars: dict[str, HeaderVar] = OrderedDict() + self.custom_vars = CustomVars() + + @classmethod + def load(cls, tags: Optional[Iterable[DXFTag]] = None) -> HeaderSection: + """Constructor to generate header variables loaded from DXF files + (untrusted environment). + + Args: + tags: DXF tags as Tags() or ExtendedTags() + + (internal API) + """ + if tags is None: # create default header + # files without a header have the default version: R12 + return cls.new(dxfversion=const.DXF12) + section = cls() + section.load_tags(iter(tags)) + return section + + @classmethod + def new(cls, dxfversion=const.LATEST_DXF_VERSION) -> HeaderSection: + section = HeaderSection() + section.hdrvars = default_vars() + section["$ACADVER"] = dxfversion + return section + + def load_tags(self, tags: Iterable[DXFTag]) -> None: + """Constructor to generate header variables loaded from DXF files + (untrusted environment). + + Args: + tags: DXF tags as Tags() or ExtendedTags() + + """ + _tags = iter(tags) or iter(self.MIN_HEADER_TAGS) + section_tag = next(_tags) + name_tag = next(_tags) + + if section_tag != (0, "SECTION") or name_tag != (2, "HEADER"): + raise const.DXFStructureError("Critical structure error in HEADER section.") + + groups = group_tags(header_validator(_tags), splitcode=9) + custom_property_stack = [] # collect $CUSTOMPROPERTY/TAG + for group in groups: + name = group[0].value + value = group[1] + if name in ("$CUSTOMPROPERTYTAG", "$CUSTOMPROPERTY"): + custom_property_stack.append(value.value) + else: + self.hdrvars[name] = HeaderVar(value) + + custom_property_stack.reverse() + while len(custom_property_stack): + try: + self.custom_vars.append( + tag=custom_property_stack.pop(), + value=custom_property_stack.pop(), + ) + except IndexError: # internal exception + break + + @classmethod + def from_text(cls, text: str) -> HeaderSection: + """Load constructor from text for testing""" + return cls.load(Tags.from_text(text)) + + def _headervar_factory(self, key: str, value: Any) -> DXFTag: + if key in HEADER_VAR_MAP: + factory = HEADER_VAR_MAP[key].factory + return factory(value) + else: + raise const.DXFKeyError(f"Invalid header variable {key}.") + + def __len__(self) -> int: + """Returns count of header variables.""" + return len(self.hdrvars) + + def __contains__(self, key) -> bool: + """Returns ``True`` if header variable `key` exist.""" + return key in self.hdrvars + + def varnames(self) -> KeysView: + """Returns an iterable of all header variable names.""" + return self.hdrvars.keys() + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Exports header section as DXF tags. (internal API)""" + + def _write(name: str, value: Any) -> None: + if value.value is None: + logger.info(f"did not write header var {name}, value is None.") + return + tagwriter.write_tag2(9, name) + group_code = version_specific_group_code(name, dxfversion) + # fix invalid group codes + if group_code != value.code: + value = HeaderVar((group_code, value.value)) + tagwriter.write_str(str(value)) + + dxfversion: str = tagwriter.dxfversion + write_handles = tagwriter.write_handles + + tagwriter.write_str(" 0\nSECTION\n 2\nHEADER\n") + save = self["$ACADVER"] + self["$ACADVER"] = dxfversion + for name, value in header_vars_by_priority(self.hdrvars, dxfversion): + if not write_handles and name == "$HANDSEED": + continue # skip $HANDSEED + _write(name, value) + if name == "$LASTSAVEDBY": # ugly hack, but necessary for AutoCAD + self.custom_vars.write(tagwriter) + self["$ACADVER"] = save + tagwriter.write_str(" 0\nENDSEC\n") + + def get(self, key: str, default: Any = None) -> Any: + """Returns value of header variable `key` if exist, else the `default` + value. + + """ + if key in self.hdrvars: + return self.__getitem__(key) + else: + return default + + def __getitem__(self, key: str) -> Any: + """Get header variable `key` by index operator like: + :code:`drawing.header['$ACADVER']` + + """ + try: + return self.hdrvars[key].value + except KeyError: # map exception + raise const.DXFKeyError(str(key)) + + def __setitem__(self, key: str, value: Any) -> None: + """Set header variable `key` to `value` by index operator like: + :code:`drawing.header['$ANGDIR'] = 1` + + """ + try: + tags = self._headervar_factory(key, value) + except (IndexError, ValueError): + raise const.DXFValueError(str(value)) + self.hdrvars[key] = HeaderVar(tags) + + def __delitem__(self, key: str) -> None: + """Delete header variable `key` by index operator like: + :code:`del drawing.header['$ANGDIR']` + + """ + try: + del self.hdrvars[key] + except KeyError: # map exception + raise const.DXFKeyError(str(key)) + + def reset_wcs(self): + """Reset the current UCS settings to the :ref:`WCS`.""" + self["$UCSBASE"] = "" + self["$UCSNAME"] = "" + self["$UCSORG"] = (0, 0, 0) + self["$UCSXDIR"] = (1, 0, 0) + self["$UCSYDIR"] = (0, 1, 0) + self["$UCSORTHOREF"] = "" + self["$UCSORTHOVIEW"] = 0 + self["$UCSORGTOP"] = (0, 0, 0) + self["$UCSORGBOTTOM"] = (0, 0, 0) + self["$UCSORGLEFT"] = (0, 0, 0) + self["$UCSORGRIGHT"] = (0, 0, 0) + self["$UCSORGFRONT"] = (0, 0, 0) + self["$UCSORGBACK"] = (0, 0, 0) + + +def header_vars_by_priority( + header_vars: dict[str, HeaderVar], dxfversion: str +) -> Iterable[tuple]: + order = [] + for name, value in header_vars.items(): + vardef = HEADER_VAR_MAP.get(name, None) + if vardef is None: + logger.info(f"Header variable {name} ignored, dxfversion={dxfversion}.") + continue + if vardef.mindxf <= dxfversion <= vardef.maxdxf: + order.append((vardef.priority, (name, value))) + order.sort() + for priority, tag in order: + yield tag + + +class HeaderVar: + def __init__(self, tag: Union[DXFTag, Sequence]): + self.tag = tag + + @property + def code(self) -> int: + return self.tag[0] + + @property + def value(self) -> Any: + return self.tag[1] + + @property + def ispoint(self) -> bool: + return self.code == 10 + + def __str__(self) -> str: + if self.ispoint: + code, value = self.tag + s = [] + for coord in value: + s.append(strtag((code, coord))) + code += 10 + return "".join(s) + else: + return strtag(self.tag) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/headervars.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/headervars.py new file mode 100644 index 0000000..0cdfc44 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/headervars.py @@ -0,0 +1,2390 @@ +# Copyright (c) 2019-2021, Manfred Moitzi +# License: MIT License +from functools import partial +from ezdxf.lldxf.hdrvars import SingleValue, Point2D, Point3D, HeaderVarDef +from ezdxf.lldxf.const import ( + DXF12, + DXF2000, + DXF2004, + DXF2007, + DXF2010, + DXF2013, + DXF2018, +) + +CONST_GUID = "{00000000-0000-0000-0000-000000000000}" + +HEADER_VAR_MAP = { + "$ACADVER": HeaderVarDef( + name="$ACADVER", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=0, + default="AC1032", + ), + "$ACADMAINTVER": HeaderVarDef( + name="$ACADMAINTVER", + # group code changed to 90 in DXF R2018+, this fact is handled in: + # ezdxf.sections.header.HeaderSection.export_dxf() + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=100, + default=4, + ), + "$DWGCODEPAGE": HeaderVarDef( + name="$DWGCODEPAGE", + code=3, + factory=partial(SingleValue, code=3), + mindxf=DXF12, + maxdxf=DXF2018, + priority=200, + default="ANSI_1252", + ), + "$LASTSAVEDBY": HeaderVarDef( + name="$LASTSAVEDBY", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=300, + default="ezdxf", + ), + "$REQUIREDVERSIONS": HeaderVarDef( + name="$REQUIREDVERSIONS", + code=160, + factory=partial(SingleValue, code=160), + mindxf=DXF2013, + maxdxf=DXF2018, + priority=400, + default=0, + ), + "$INSBASE": HeaderVarDef( + name="$INSBASE", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=500, + default=(0.0, 0.0, 0.0), + ), + "$EXTMIN": HeaderVarDef( + name="$EXTMIN", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=600, + default=(1e20, 1e20, 1e20), + ), + "$EXTMAX": HeaderVarDef( + name="$EXTMAX", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=700, + default=(-1e20, -1e20, -1e20), + ), + "$LIMMIN": HeaderVarDef( + name="$LIMMIN", + code=10, + factory=Point2D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=800, + default=(0.0, 0.0), + ), + "$LIMMAX": HeaderVarDef( + name="$LIMMAX", + code=10, + factory=Point2D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=900, + default=(420.0, 297.0), + ), + "$ORTHOMODE": HeaderVarDef( + name="$ORTHOMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1000, + default=0, + ), + "$REGENMODE": HeaderVarDef( + name="$REGENMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1100, + default=1, + ), + "$FILLMODE": HeaderVarDef( + name="$FILLMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1200, + default=1, + ), + "$DRAGMODE": HeaderVarDef( + name="$DRAGMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=1250, + default=2, + ), + "$QTEXTMODE": HeaderVarDef( + name="$QTEXTMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1300, + default=0, + ), + "$MIRRTEXT": HeaderVarDef( + name="$MIRRTEXT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1400, + default=1, + ), + "$OSMODE": HeaderVarDef( + name="$OSMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=1400, + default=20583, + ), + "$LTSCALE": HeaderVarDef( + name="$LTSCALE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1500, + default=1.0, + ), + "$ATTMODE": HeaderVarDef( + name="$ATTMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1600, + default=1, + ), + "$TEXTSIZE": HeaderVarDef( + name="$TEXTSIZE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1700, + default=2.5, + ), + "$TRACEWID": HeaderVarDef( + name="$TRACEWID", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1800, + default=1.0, + ), + "$TEXTSTYLE": HeaderVarDef( + name="$TEXTSTYLE", + code=7, + factory=partial(SingleValue, code=7), + mindxf=DXF12, + maxdxf=DXF2018, + priority=1900, + default="Standard", + ), + "$CLAYER": HeaderVarDef( + name="$CLAYER", + code=8, + factory=partial(SingleValue, code=8), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2000, + default="0", + ), + "$CELTYPE": HeaderVarDef( + name="$CELTYPE", + code=6, + factory=partial(SingleValue, code=6), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2100, + default="ByLayer", + ), + "$CECOLOR": HeaderVarDef( + name="$CECOLOR", + code=62, + factory=partial(SingleValue, code=62), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2200, + default=256, + ), + "$CELTSCALE": HeaderVarDef( + name="$CELTSCALE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=2300, + default=1.0, + ), + "$DISPSILH": HeaderVarDef( + name="$DISPSILH", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=2400, + default=0, + ), + "$DIMSCALE": HeaderVarDef( + name="$DIMSCALE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2500, + default=1.0, + ), + "$DIMASZ": HeaderVarDef( + name="$DIMASZ", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2600, + default=2.5, + ), + "$DIMEXO": HeaderVarDef( + name="$DIMEXO", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2700, + default=0.625, + ), + "$DIMDLI": HeaderVarDef( + name="$DIMDLI", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2800, + default=3.75, + ), + "$DIMRND": HeaderVarDef( + name="$DIMRND", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=2900, + default=0.0, + ), + "$DIMDLE": HeaderVarDef( + name="$DIMDLE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3000, + default=0.0, + ), + "$DIMEXE": HeaderVarDef( + name="$DIMEXE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3100, + default=1.25, + ), + "$DIMTP": HeaderVarDef( + name="$DIMTP", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3200, + default=0.0, + ), + "$DIMTM": HeaderVarDef( + name="$DIMTM", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3300, + default=0.0, + ), + "$DIMTXT": HeaderVarDef( + name="$DIMTXT", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3400, + default=2.5, + ), + "$DIMCEN": HeaderVarDef( + name="$DIMCEN", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3500, + default=2.5, + ), + "$DIMTSZ": HeaderVarDef( + name="$DIMTSZ", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3600, + default=0.0, + ), + "$DIMTOL": HeaderVarDef( + name="$DIMTOL", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3700, + default=0, + ), + "$DIMLIM": HeaderVarDef( + name="$DIMLIM", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3800, + default=0, + ), + "$DIMTIH": HeaderVarDef( + name="$DIMTIH", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=3900, + default=0, + ), + "$DIMTOH": HeaderVarDef( + name="$DIMTOH", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4000, + default=0, + ), + "$DIMSE1": HeaderVarDef( + name="$DIMSE1", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4100, + default=0, + ), + "$DIMSE2": HeaderVarDef( + name="$DIMSE2", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4200, + default=0, + ), + "$DIMTAD": HeaderVarDef( + name="$DIMTAD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4300, + default=1, + ), + "$DIMZIN": HeaderVarDef( + name="$DIMZIN", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4400, + default=8, + ), + "$DIMBLK": HeaderVarDef( + name="$DIMBLK", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4500, + default="", + ), + "$DIMASO": HeaderVarDef( + name="$DIMASO", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4600, + default=1, + ), + "$DIMSHO": HeaderVarDef( + name="$DIMSHO", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4700, + default=1, + ), + "$DIMPOST": HeaderVarDef( + name="$DIMPOST", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4800, + default="", + ), + "$DIMAPOST": HeaderVarDef( + name="$DIMAPOST", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=4900, + default="", + ), + "$DIMALT": HeaderVarDef( + name="$DIMALT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5000, + default=0, + ), + "$DIMALTD": HeaderVarDef( + name="$DIMALTD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5100, + default=3, + ), + "$DIMALTF": HeaderVarDef( + name="$DIMALTF", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5200, + default=0.03937007874, + ), + "$DIMLFAC": HeaderVarDef( + name="$DIMLFAC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5300, + default=1.0, + ), + "$DIMTOFL": HeaderVarDef( + name="$DIMTOFL", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5400, + default=1, + ), + "$DIMTVP": HeaderVarDef( + name="$DIMTVP", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5500, + default=0.0, + ), + "$DIMTIX": HeaderVarDef( + name="$DIMTIX", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5600, + default=0, + ), + "$DIMSOXD": HeaderVarDef( + name="$DIMSOXD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5700, + default=0, + ), + "$DIMSAH": HeaderVarDef( + name="$DIMSAH", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5800, + default=0, + ), + "$DIMBLK1": HeaderVarDef( + name="$DIMBLK1", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=5900, + default="", + ), + "$DIMBLK2": HeaderVarDef( + name="$DIMBLK2", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6000, + default="", + ), + "$DIMSTYLE": HeaderVarDef( + name="$DIMSTYLE", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6100, + default="ISO-25", + ), + "$DIMCLRD": HeaderVarDef( + name="$DIMCLRD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6200, + default=0, + ), + "$DIMCLRE": HeaderVarDef( + name="$DIMCLRE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6300, + default=0, + ), + "$DIMCLRT": HeaderVarDef( + name="$DIMCLRT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6400, + default=0, + ), + "$DIMTFAC": HeaderVarDef( + name="$DIMTFAC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6500, + default=1.0, + ), + "$DIMGAP": HeaderVarDef( + name="$DIMGAP", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=6600, + default=0.625, + ), + "$DIMJUST": HeaderVarDef( + name="$DIMJUST", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=6700, + default=0, + ), + "$DIMSD1": HeaderVarDef( + name="$DIMSD1", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=6800, + default=0, + ), + "$DIMSD2": HeaderVarDef( + name="$DIMSD2", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=6900, + default=0, + ), + "$DIMTOLJ": HeaderVarDef( + name="$DIMTOLJ", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7000, + default=0, + ), + "$DIMTZIN": HeaderVarDef( + name="$DIMTZIN", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7100, + default=8, + ), + "$DIMALTZ": HeaderVarDef( + name="$DIMALTZ", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7200, + default=0, + ), + "$DIMALTTZ": HeaderVarDef( + name="$DIMALTTZ", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7300, + default=0, + ), + "$DIMUPT": HeaderVarDef( + name="$DIMUPT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7400, + default=0, + ), + "$DIMDEC": HeaderVarDef( + name="$DIMDEC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7500, + default=2, + ), + "$DIMTDEC": HeaderVarDef( + name="$DIMTDEC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7600, + default=2, + ), + "$DIMALTU": HeaderVarDef( + name="$DIMALTU", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7700, + default=2, + ), + "$DIMALTTD": HeaderVarDef( + name="$DIMALTTD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7800, + default=3, + ), + "$DIMTXSTY": HeaderVarDef( + name="$DIMTXSTY", + code=7, + factory=partial(SingleValue, code=7), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=7900, + default="Standard", + ), + "$DIMAUNIT": HeaderVarDef( + name="$DIMAUNIT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8000, + default=0, + ), + "$DIMADEC": HeaderVarDef( + name="$DIMADEC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8100, + default=0, + ), + "$DIMALTRND": HeaderVarDef( + name="$DIMALTRND", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8200, + default=0.0, + ), + "$DIMAZIN": HeaderVarDef( + name="$DIMAZIN", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8300, + default=0, + ), + "$DIMDSEP": HeaderVarDef( + name="$DIMDSEP", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8400, + default=44, + ), + "$DIMATFIT": HeaderVarDef( + name="$DIMATFIT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8500, + default=3, + ), + "$DIMFRAC": HeaderVarDef( + name="$DIMFRAC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8600, + default=0, + ), + "$DIMLDRBLK": HeaderVarDef( + name="$DIMLDRBLK", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8700, + default="", + ), + "$DIMLUNIT": HeaderVarDef( + name="$DIMLUNIT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8800, + default=2, + ), + "$COORDS": HeaderVarDef( + name="$COORDS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=8800, + default=1, + ), + "$DIMLWD": HeaderVarDef( + name="$DIMLWD", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=8900, + default=-2, + ), + "$DIMLWE": HeaderVarDef( + name="$DIMLWE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=9000, + default=-2, + ), + "$DIMTMOVE": HeaderVarDef( + name="$DIMTMOVE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=9100, + default=0, + ), + "$DIMFXL": HeaderVarDef( + name="$DIMFXL", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9200, + default=1.0, + ), + "$ATTDIA": HeaderVarDef( + name="$ATTDIA", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=9200, + default=0, + ), + "$DIMFXLON": HeaderVarDef( + name="$DIMFXLON", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9300, + default=0, + ), + "$ATTREQ": HeaderVarDef( + name="$ATTREQ", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=9300, + default=1, + ), + "$DIMJOGANG": HeaderVarDef( + name="$DIMJOGANG", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9400, + default=0.785398163397, + ), + "$DIMTFILL": HeaderVarDef( + name="$DIMTFILL", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9500, + default=0, + ), + "$DIMTFILLCLR": HeaderVarDef( + name="$DIMTFILLCLR", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9600, + default=0, + ), + "$DIMARCSYM": HeaderVarDef( + name="$DIMARCSYM", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9700, + default=0, + ), + "$DIMLTYPE": HeaderVarDef( + name="$DIMLTYPE", + code=6, + factory=partial(SingleValue, code=6), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9800, + default="", + ), + "$DIMLTEX1": HeaderVarDef( + name="$DIMLTEX1", + code=6, + factory=partial(SingleValue, code=6), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=9900, + default="", + ), + "$DIMLTEX2": HeaderVarDef( + name="$DIMLTEX2", + code=6, + factory=partial(SingleValue, code=6), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=10000, + default="", + ), + "$DIMTXTDIRECTION": HeaderVarDef( + name="$DIMTXTDIRECTION", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2010, + maxdxf=DXF2018, + priority=10100, + default=0, + ), + "$LUNITS": HeaderVarDef( + name="$LUNITS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10200, + default=2, + ), + "$LUPREC": HeaderVarDef( + name="$LUPREC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10300, + default=4, + ), + "$SKETCHINC": HeaderVarDef( + name="$SKETCHINC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10400, + default=1.0, + ), + "$FILLETRAD": HeaderVarDef( + name="$FILLETRAD", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10500, + default=10.0, + ), + "$AUNITS": HeaderVarDef( + name="$AUNITS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10600, + default=0, + ), + "$AUPREC": HeaderVarDef( + name="$AUPREC", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10700, + default=2, + ), + "$MENU": HeaderVarDef( + name="$MENU", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10800, + default=".", + ), + "$ELEVATION": HeaderVarDef( + name="$ELEVATION", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=10900, + default=0.0, + ), + "$PELEVATION": HeaderVarDef( + name="$PELEVATION", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11000, + default=0.0, + ), + "$THICKNESS": HeaderVarDef( + name="$THICKNESS", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11100, + default=0.0, + ), + "$LIMCHECK": HeaderVarDef( + name="$LIMCHECK", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11200, + default=0, + ), + "$CHAMFERA": HeaderVarDef( + name="$CHAMFERA", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11300, + default=0.0, + ), + "$CHAMFERB": HeaderVarDef( + name="$CHAMFERB", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11400, + default=0.0, + ), + "$CHAMFERC": HeaderVarDef( + name="$CHAMFERC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=11500, + default=0.0, + ), + "$CHAMFERD": HeaderVarDef( + name="$CHAMFERD", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=11600, + default=0.0, + ), + "$SKPOLY": HeaderVarDef( + name="$SKPOLY", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11700, + default=0, + ), + "$TDCREATE": HeaderVarDef( + name="$TDCREATE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=11800, + default=2458532.195663565, + ), + "$TDUCREATE": HeaderVarDef( + name="$TDUCREATE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=11900, + default=2458532.153996898, + ), + "$TDUPDATE": HeaderVarDef( + name="$TDUPDATE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12000, + default=2458532.196097766, + ), + "$TDUUPDATE": HeaderVarDef( + name="$TDUUPDATE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=12100, + default=2458532.1544311, + ), + "$TDINDWG": HeaderVarDef( + name="$TDINDWG", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12200, + default=0.0, + ), + "$TDUSRTIMER": HeaderVarDef( + name="$TDUSRTIMER", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12300, + default=0.0, + ), + "$USRTIMER": HeaderVarDef( + name="$USRTIMER", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12400, + default=1, + ), + "$ANGBASE": HeaderVarDef( + name="$ANGBASE", + code=50, + factory=partial(SingleValue, code=50), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12500, + default=0.0, + ), + "$ANGDIR": HeaderVarDef( + name="$ANGDIR", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12600, + default=0, + ), + "$PDMODE": HeaderVarDef( + name="$PDMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12700, + default=0, + ), + "$PDSIZE": HeaderVarDef( + name="$PDSIZE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12800, + default=0.0, + ), + "$PLINEWID": HeaderVarDef( + name="$PLINEWID", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=12900, + default=0.0, + ), + "$SPLFRAME": HeaderVarDef( + name="$SPLFRAME", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13000, + default=0, + ), + "$SPLINETYPE": HeaderVarDef( + name="$SPLINETYPE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13100, + default=6, + ), + "$SPLINESEGS": HeaderVarDef( + name="$SPLINESEGS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13200, + default=8, + ), + "$HANDLING": HeaderVarDef( + name="$HANDLING", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF12, + priority=9400, + default=1, + ), + "$HANDSEED": HeaderVarDef( + name="$HANDSEED", + code=5, + factory=partial(SingleValue, code=5), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13300, + default="100", + ), + "$SURFTAB1": HeaderVarDef( + name="$SURFTAB1", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13400, + default=6, + ), + "$SURFTAB2": HeaderVarDef( + name="$SURFTAB2", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13500, + default=6, + ), + "$SURFTYPE": HeaderVarDef( + name="$SURFTYPE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13600, + default=6, + ), + "$SURFU": HeaderVarDef( + name="$SURFU", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13700, + default=6, + ), + "$SURFV": HeaderVarDef( + name="$SURFV", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=13800, + default=6, + ), + "$UCSBASE": HeaderVarDef( + name="$UCSBASE", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=13900, + default="", + ), + "$UCSNAME": HeaderVarDef( + name="$UCSNAME", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF12, + maxdxf=DXF2018, + priority=14000, + default="", + ), + "$UCSORG": HeaderVarDef( + name="$UCSORG", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=14100, + default=(0.0, 0.0, 0.0), + ), + "$UCSXDIR": HeaderVarDef( + name="$UCSXDIR", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=14200, + default=(1.0, 0.0, 0.0), + ), + "$UCSYDIR": HeaderVarDef( + name="$UCSYDIR", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=14300, + default=(0.0, 1.0, 0.0), + ), + "$UCSORTHOREF": HeaderVarDef( + name="$UCSORTHOREF", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14400, + default="", + ), + "$UCSORTHOVIEW": HeaderVarDef( + name="$UCSORTHOVIEW", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14500, + default=0, + ), + "$UCSORGTOP": HeaderVarDef( + name="$UCSORGTOP", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14600, + default=(0.0, 0.0, 0.0), + ), + "$UCSORGBOTTOM": HeaderVarDef( + name="$UCSORGBOTTOM", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14700, + default=(0.0, 0.0, 0.0), + ), + "$UCSORGLEFT": HeaderVarDef( + name="$UCSORGLEFT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14800, + default=(0.0, 0.0, 0.0), + ), + "$UCSORGRIGHT": HeaderVarDef( + name="$UCSORGRIGHT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=14900, + default=(0.0, 0.0, 0.0), + ), + "$UCSORGFRONT": HeaderVarDef( + name="$UCSORGFRONT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15000, + default=(0.0, 0.0, 0.0), + ), + "$UCSORGBACK": HeaderVarDef( + name="$UCSORGBACK", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15100, + default=(0.0, 0.0, 0.0), + ), + "$PUCSBASE": HeaderVarDef( + name="$PUCSBASE", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15200, + default="", + ), + "$PUCSNAME": HeaderVarDef( + name="$PUCSNAME", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF12, + maxdxf=DXF2018, + priority=15300, + default="", + ), + "$PUCSORG": HeaderVarDef( + name="$PUCSORG", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=15400, + default=(0.0, 0.0, 0.0), + ), + "$PUCSXDIR": HeaderVarDef( + name="$PUCSXDIR", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=15500, + default=(1.0, 0.0, 0.0), + ), + "$PUCSYDIR": HeaderVarDef( + name="$PUCSYDIR", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=15600, + default=(0.0, 1.0, 0.0), + ), + "$PUCSORTHOREF": HeaderVarDef( + name="$PUCSORTHOREF", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15700, + default="", + ), + "$PUCSORTHOVIEW": HeaderVarDef( + name="$PUCSORTHOVIEW", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15800, + default=0, + ), + "$PUCSORGTOP": HeaderVarDef( + name="$PUCSORGTOP", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=15900, + default=(0.0, 0.0, 0.0), + ), + "$PUCSORGBOTTOM": HeaderVarDef( + name="$PUCSORGBOTTOM", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=16000, + default=(0.0, 0.0, 0.0), + ), + "$PUCSORGLEFT": HeaderVarDef( + name="$PUCSORGLEFT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=16100, + default=(0.0, 0.0, 0.0), + ), + "$PUCSORGRIGHT": HeaderVarDef( + name="$PUCSORGRIGHT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=16200, + default=(0.0, 0.0, 0.0), + ), + "$PUCSORGFRONT": HeaderVarDef( + name="$PUCSORGFRONT", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=16300, + default=(0.0, 0.0, 0.0), + ), + "$PUCSORGBACK": HeaderVarDef( + name="$PUCSORGBACK", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=16400, + default=(0.0, 0.0, 0.0), + ), + "$USERI1": HeaderVarDef( + name="$USERI1", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=16500, + default=0, + ), + "$USERI2": HeaderVarDef( + name="$USERI2", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=16600, + default=0, + ), + "$USERI3": HeaderVarDef( + name="$USERI3", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=16700, + default=0, + ), + "$USERI4": HeaderVarDef( + name="$USERI4", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=16800, + default=0, + ), + "$USERI5": HeaderVarDef( + name="$USERI5", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=16900, + default=0, + ), + "$USERR1": HeaderVarDef( + name="$USERR1", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17000, + default=0.0, + ), + "$USERR2": HeaderVarDef( + name="$USERR2", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17100, + default=0.0, + ), + "$USERR3": HeaderVarDef( + name="$USERR3", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17200, + default=0.0, + ), + "$USERR4": HeaderVarDef( + name="$USERR4", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17300, + default=0.0, + ), + "$USERR5": HeaderVarDef( + name="$USERR5", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17400, + default=0.0, + ), + "$WORLDVIEW": HeaderVarDef( + name="$WORLDVIEW", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17500, + default=1, + ), + "$SHADEDGE": HeaderVarDef( + name="$SHADEDGE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17600, + default=3, + ), + "$SHADEDIF": HeaderVarDef( + name="$SHADEDIF", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17700, + default=70, + ), + "$TILEMODE": HeaderVarDef( + name="$TILEMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17800, + default=1, + ), + "$MAXACTVP": HeaderVarDef( + name="$MAXACTVP", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=17900, + default=64, + ), + "$PINSBASE": HeaderVarDef( + name="$PINSBASE", + code=10, + factory=Point3D, + mindxf=DXF2000, + maxdxf=DXF2018, + priority=18000, + default=(0.0, 0.0, 0.0), + ), + "$PLIMCHECK": HeaderVarDef( + name="$PLIMCHECK", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=18100, + default=0, + ), + "$PEXTMIN": HeaderVarDef( + name="$PEXTMIN", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=18200, + default=(1e20, 1e20, 1e20), + ), + "$PEXTMAX": HeaderVarDef( + name="$PEXTMAX", + code=10, + factory=Point3D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=18300, + default=(-1e20, -1e20, -1e20), + ), + "$PLIMMIN": HeaderVarDef( + name="$PLIMMIN", + code=10, + factory=Point2D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=18400, + default=(0.0, 0.0), + ), + "$PLIMMAX": HeaderVarDef( + name="$PLIMMAX", + code=10, + factory=Point2D, + mindxf=DXF12, + maxdxf=DXF2018, + priority=18500, + default=(420.0, 297.0), + ), + "$UNITMODE": HeaderVarDef( + name="$UNITMODE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=18600, + default=0, + ), + "$VISRETAIN": HeaderVarDef( + name="$VISRETAIN", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=18700, + default=1, + ), + "$PLINEGEN": HeaderVarDef( + name="$PLINEGEN", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=18800, + default=0, + ), + "$PSLTSCALE": HeaderVarDef( + name="$PSLTSCALE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF12, + maxdxf=DXF2018, + priority=18900, + default=1, + ), + "$TREEDEPTH": HeaderVarDef( + name="$TREEDEPTH", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19000, + default=3020, + ), + "$CMLSTYLE": HeaderVarDef( + name="$CMLSTYLE", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19100, + default="Standard", + ), + "$CMLJUST": HeaderVarDef( + name="$CMLJUST", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19200, + default=0, + ), + "$CMLSCALE": HeaderVarDef( + name="$CMLSCALE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19300, + default=20.0, + ), + "$PROXYGRAPHICS": HeaderVarDef( + name="$PROXYGRAPHICS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19400, + default=1, + ), + "$MEASUREMENT": HeaderVarDef( + name="$MEASUREMENT", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19500, + default=1, + ), + "$CELWEIGHT": HeaderVarDef( + name="$CELWEIGHT", + code=370, + factory=partial(SingleValue, code=370), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19600, + default=-1, + ), + "$ENDCAPS": HeaderVarDef( + name="$ENDCAPS", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19700, + default=0, + ), + "$JOINSTYLE": HeaderVarDef( + name="$JOINSTYLE", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19800, + default=0, + ), + "$LWDISPLAY": HeaderVarDef( + name="$LWDISPLAY", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=19900, + default=0, + ), + "$INSUNITS": HeaderVarDef( + name="$INSUNITS", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20000, + default=6, + ), + "$HYPERLINKBASE": HeaderVarDef( + name="$HYPERLINKBASE", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20100, + default="", + ), + "$STYLESHEET": HeaderVarDef( + name="$STYLESHEET", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20200, + default="", + ), + "$XEDIT": HeaderVarDef( + name="$XEDIT", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20300, + default=1, + ), + "$CEPSNTYPE": HeaderVarDef( + name="$CEPSNTYPE", + code=380, + factory=partial(SingleValue, code=380), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20400, + default=0, + ), + "$PSTYLEMODE": HeaderVarDef( + name="$PSTYLEMODE", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20500, + default=1, + ), + "$FINGERPRINTGUID": HeaderVarDef( + name="$FINGERPRINTGUID", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20600, + default=CONST_GUID, + ), + "$VERSIONGUID": HeaderVarDef( + name="$VERSIONGUID", + code=2, + factory=partial(SingleValue, code=2), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20700, + default=CONST_GUID, + ), + "$EXTNAMES": HeaderVarDef( + name="$EXTNAMES", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20800, + default=1, + ), + "$PSVPSCALE": HeaderVarDef( + name="$PSVPSCALE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=20900, + default=0.0, + ), + "$OLESTARTUP": HeaderVarDef( + name="$OLESTARTUP", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2000, + maxdxf=DXF2018, + priority=21000, + default=0, + ), + # 0 = Disables SORTENTS + # 1 = Sorts for object selection + # 2 = Sorts for object snap + # 4 = Sorts for redraws; obsolete + # 8 = Sorts for MSLIDE command slide creation; obsolete + # 16 = Sorts for REGEN commands + # 32 = Sorts for plotting + # 64 = Sorts for PostScript output; obsolete + "$SORTENTS": HeaderVarDef( + name="$SORTENTS", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21100, + default=127, + ), + "$INDEXCTL": HeaderVarDef( + name="$INDEXCTL", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21200, + default=0, + ), + "$HIDETEXT": HeaderVarDef( + name="$HIDETEXT", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21300, + default=1, + ), + "$XCLIPFRAME": HeaderVarDef( + name="$XCLIPFRAME", + code=280, # 2004 & 2007 = 290 + factory=partial(SingleValue, code=280), # 2004 & 2007 = 290 + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21400, + # 0 = Clipping boundary is not visible + # 1 = Clipping boundary is visible + # default for 2004 & 2007 is 0; R2010+ is 2? + default=1, # changed 2014-03-16 issue #1049 - from 2 to 1 + ), + "$HALOGAP": HeaderVarDef( + name="$HALOGAP", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21500, + default=0, + ), + "$OBSCOLOR": HeaderVarDef( + name="$OBSCOLOR", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21600, + default=257, + ), + "$OBSLTYPE": HeaderVarDef( + name="$OBSLTYPE", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21700, + default=0, + ), + "$INTERSECTIONDISPLAY": HeaderVarDef( + name="$INTERSECTIONDISPLAY", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21800, + default=0, + ), + "$INTERSECTIONCOLOR": HeaderVarDef( + name="$INTERSECTIONCOLOR", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=21900, + default=257, + ), + "$DIMASSOC": HeaderVarDef( + name="$DIMASSOC", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=22000, + default=2, + ), + "$PROJECTNAME": HeaderVarDef( + name="$PROJECTNAME", + code=1, + factory=partial(SingleValue, code=1), + mindxf=DXF2004, + maxdxf=DXF2018, + priority=22100, + default="", + ), + "$CAMERADISPLAY": HeaderVarDef( + name="$CAMERADISPLAY", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22200, + default=0, + ), + "$LENSLENGTH": HeaderVarDef( + name="$LENSLENGTH", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22300, + default=50.0, + ), + "$CAMERAHEIGHT": HeaderVarDef( + name="$CAMERAHEIGHT", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22400, + default=0.0, + ), + "$STEPSPERSEC": HeaderVarDef( + name="$STEPSPERSEC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22500, + default=24.0, + ), + "$STEPSIZE": HeaderVarDef( + name="$STEPSIZE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22600, + default=100.0, + ), + "$3DDWFPREC": HeaderVarDef( + name="$3DDWFPREC", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22700, + default=2.0, + ), + "$PSOLWIDTH": HeaderVarDef( + name="$PSOLWIDTH", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22800, + default=0.005, + ), + "$PSOLHEIGHT": HeaderVarDef( + name="$PSOLHEIGHT", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=22900, + default=0.08, + ), + "$LOFTANG1": HeaderVarDef( + name="$LOFTANG1", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23000, + default=1.570796326795, + ), + "$LOFTANG2": HeaderVarDef( + name="$LOFTANG2", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23100, + default=1.570796326795, + ), + "$LOFTMAG1": HeaderVarDef( + name="$LOFTMAG1", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23200, + default=0.0, + ), + "$LOFTMAG2": HeaderVarDef( + name="$LOFTMAG2", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23300, + default=0.0, + ), + "$LOFTPARAM": HeaderVarDef( + name="$LOFTPARAM", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23400, + default=7, + ), + "$LOFTNORMALS": HeaderVarDef( + name="$LOFTNORMALS", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23500, + default=1, + ), + "$LATITUDE": HeaderVarDef( + name="$LATITUDE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23600, + default=37.795, + ), + "$LONGITUDE": HeaderVarDef( + name="$LONGITUDE", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23700, + default=-122.394, + ), + "$NORTHDIRECTION": HeaderVarDef( + name="$NORTHDIRECTION", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23800, + default=0.0, + ), + "$TIMEZONE": HeaderVarDef( + name="$TIMEZONE", + code=70, + factory=partial(SingleValue, code=70), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=23900, + default=-8000, + ), + "$LIGHTGLYPHDISPLAY": HeaderVarDef( + name="$LIGHTGLYPHDISPLAY", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24000, + default=1, + ), + "$TILEMODELIGHTSYNCH": HeaderVarDef( + name="$TILEMODELIGHTSYNCH", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24100, + default=1, + ), + "$CMATERIAL": HeaderVarDef( + name="$CMATERIAL", + code=347, + factory=partial(SingleValue, code=347), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24200, + default="45", + ), # default value '0' crashes BricsCAD + "$SOLIDHIST": HeaderVarDef( + name="$SOLIDHIST", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24300, + default=0, + ), + "$SHOWHIST": HeaderVarDef( + name="$SHOWHIST", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24400, + default=1, + ), + "$DWFFRAME": HeaderVarDef( + name="$DWFFRAME", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24500, + default=2, + ), + "$DGNFRAME": HeaderVarDef( + name="$DGNFRAME", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24600, + default=2, + ), + "$REALWORLDSCALE": HeaderVarDef( + name="$REALWORLDSCALE", + code=290, + factory=partial(SingleValue, code=290), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24700, + default=1, + ), + "$INTERFERECOLOR": HeaderVarDef( + name="$INTERFERECOLOR", + code=62, + factory=partial(SingleValue, code=62), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24800, + default=256, + ), + "$INTERFEREOBJVS": HeaderVarDef( + # Handle to a VisualStyle, if pointing to an invalid or non-existing VS, + # copy to clipboard in AutoCAD can fail. + name="$INTERFEREOBJVS", + code=345, + factory=partial(SingleValue, code=345), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24810, + default=None, + ), # will not be written, if not set + "$INTERFEREVPVS": HeaderVarDef( + # Handle to a VisualStyle, if pointing to an invalid or non-existing VS, + # copy to clipboard in AutoCAD can fail. + name="$INTERFEREVPVS", + code=346, + factory=partial(SingleValue, code=346), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24820, + default=None, + ), # will not be written, if not set + "$CSHADOW": HeaderVarDef( + name="$CSHADOW", + code=280, + factory=partial(SingleValue, code=280), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=24900, + default=0, + ), + "$SHADOWPLANELOCATION": HeaderVarDef( + name="$SHADOWPLANELOCATION", + code=40, + factory=partial(SingleValue, code=40), + mindxf=DXF2007, + maxdxf=DXF2018, + priority=25000, + default=0.0, + ), +} + + +def version_specific_group_code(name: str, dxfversion: str) -> int: + group_code = HEADER_VAR_MAP[name].code + # The HEADER_VAR_MAP contains the group codes for the latest DXF version. + # This section adjust changed group codes for older DXF versions: + if name == "$ACADMAINTVER": + group_code = 70 if dxfversion < DXF2018 else 90 + elif name == "$XCLIPFRAME": + group_code = 290 if dxfversion < DXF2010 else 280 + return group_code + + +VERSION_SPECIFIC_HEADER_VARS = """ +DXF Version R2004 +Name | BC GCode | BC Value | EZ GCode | EZ Value +---------------------------------------------------------------- +$XCLIPFRAME | 290 | 0 | 280 | 1 + +DXF Version R2007 +Name | BC GCode | BC Value | EZ GCode | EZ Value +---------------------------------------------------------------- +$XCLIPFRAME | 290 | 0 | 280 | 1 +""" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/objects.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/objects.py new file mode 100644 index 0000000..aed8c0f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/objects.py @@ -0,0 +1,717 @@ +# Copyright (c) 2011-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + Optional, + TYPE_CHECKING, + Union, + cast, +) +import logging + +from ezdxf.entities.dictionary import Dictionary +from ezdxf.entities import factory, is_dxf_object +from ezdxf.lldxf import const, validator +from ezdxf.entitydb import EntitySpace, EntityDB +from ezdxf.query import EntityQuery +from ezdxf.tools.handle import UnderlayKeyGenerator +from ezdxf.audit import Auditor, AuditError + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entities import ( + GeoData, + DictionaryVar, + DXFTagStorage, + DXFObject, + ImageDef, + UnderlayDefinition, + DictionaryWithDefault, + XRecord, + Placeholder, + ) + from ezdxf.entities.image import ImageDefReactor + +logger = logging.getLogger("ezdxf") + + +class ObjectsSection: + def __init__(self, doc: Drawing, entities: Optional[Iterable[DXFObject]] = None): + self.doc = doc + self.underlay_key_generator = UnderlayKeyGenerator() + self._entity_space = EntitySpace() + if entities is not None: + self._build(iter(entities)) + + @property + def entitydb(self) -> EntityDB: + """Returns drawing entity database. (internal API)""" + return self.doc.entitydb + + def get_entity_space(self) -> EntitySpace: + """Returns entity space. (internal API)""" + return self._entity_space + + def next_underlay_key(self, checkfunc=lambda k: True) -> str: + while True: + key = self.underlay_key_generator.next() + if checkfunc(key): + return key + + def _build(self, entities: Iterator[DXFObject]) -> None: + section_head = cast("DXFTagStorage", next(entities)) + + if section_head.dxftype() != "SECTION" or section_head.base_class[1] != ( + 2, + "OBJECTS", + ): + raise const.DXFStructureError( + "Critical structure error in the OBJECTS section." + ) + + for entity in entities: + # No check for valid entities here: + # Use the audit or the recover module to fix invalid DXF files! + self._entity_space.add(entity) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF entity by `tagwriter`. (internal API)""" + tagwriter.write_str(" 0\nSECTION\n 2\nOBJECTS\n") + self._entity_space.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + + def new_entity(self, _type: str, dxfattribs: dict) -> DXFObject: + """Create new DXF object, add it to the entity database and to the + entity space. + + Args: + _type: DXF type like `DICTIONARY` + dxfattribs: DXF attributes as dict + + (internal API) + """ + dxf_entity = factory.create_db_entry(_type, dxfattribs, self.doc) + self._entity_space.add(dxf_entity) + return dxf_entity # type: ignore + + def delete_entity(self, entity: DXFObject) -> None: + """Remove `entity` from entity space and destroy object. (internal API)""" + self._entity_space.remove(entity) + self.entitydb.delete_entity(entity) + + def delete_all_entities(self) -> None: + """Delete all DXF objects. (internal API)""" + db = self.entitydb + for entity in self._entity_space: + db.delete_entity(entity) + self._entity_space.clear() + + def setup_rootdict(self) -> Dictionary: + """Create a root dictionary. Has to be the first object in the objects + section. (internal API)""" + if len(self): + raise const.DXFStructureError( + "Can not create root dictionary in none empty objects section." + ) + logger.debug("Creating ROOT dictionary.") + # root directory has no owner + return self.add_dictionary(owner="0", hard_owned=False) + + def setup_object_management_tables(self, rootdict: Dictionary) -> None: + """Setup required management tables. (internal API)""" + + def setup_plot_style_name_table(): + plot_style_name_dict = self.add_dictionary_with_default( + owner=rootdict.dxf.handle, + hard_owned=False, + ) + placeholder = self.add_placeholder(owner=plot_style_name_dict.dxf.handle) + plot_style_name_dict.set_default(placeholder) + plot_style_name_dict["Normal"] = placeholder + rootdict["ACAD_PLOTSTYLENAME"] = plot_style_name_dict + + def restore_table_handle(table_name: str, handle: str) -> None: + # The original object table does not exist, but the handle is maybe + # used by some DXF entities. Try to restore the original table + # handle. + new_table = rootdict.get(table_name) + if isinstance(new_table, Dictionary) and self.doc.entitydb.reset_handle( + new_table, handle + ): + logger.debug(f"reset handle of table {table_name} to #{handle}") + + # check required object tables: + for name in _OBJECT_TABLE_NAMES: + table: Union[Dictionary, str, None] = rootdict.get(name) # type: ignore + # Dictionary: existing table object + # str: handle of not existing table object + # None: no entry in the rootdict for "name" + if isinstance(table, Dictionary): + continue # skip existing tables + + logger.info(f"creating {name} dictionary") + if name == "ACAD_PLOTSTYLENAME": + setup_plot_style_name_table() + else: + rootdict.add_new_dict(name, hard_owned=False) + + if isinstance(table, str) and validator.is_handle(table): + restore_table_handle(name, handle=table) + + def add_object(self, entity: DXFObject) -> None: + """Add `entity` to OBJECTS section. (internal API)""" + if is_dxf_object(entity): + self._entity_space.add(entity) + else: + raise const.DXFTypeError( + f"invalid DXF type {entity.dxftype()} for OBJECTS section" + ) + + def add_dxf_object_with_reactor(self, dxftype: str, dxfattribs) -> DXFObject: + """Add DXF object with reactor. (internal API)""" + dxfobject = self.new_entity(dxftype, dxfattribs) + dxfobject.set_reactors([dxfattribs["owner"]]) + return dxfobject + + def purge(self): + self._entity_space.purge() + + # start of public interface + + @property + def rootdict(self) -> Dictionary: + """Returns the root DICTIONARY, or as AutoCAD calls it: + the named DICTIONARY. + """ + if len(self): + return self._entity_space[0] # type: ignore + else: + return self.setup_rootdict() + + def __len__(self) -> int: + """Returns the count of all DXF objects in the OBJECTS section.""" + return len(self._entity_space) + + def __iter__(self) -> Iterator[DXFObject]: + """Returns an iterator of all DXF objects in the OBJECTS section.""" + return iter(self._entity_space) # type: ignore + + def __getitem__(self, index) -> DXFObject: + """Get entity at `index`. + + The underlying data structure for storing DXF objects is organized like + a standard Python list, therefore `index` can be any valid list indexing + or slicing term, like a single index ``objects[-1]`` to get the last + entity, or an index slice ``objects[:10]`` to get the first 10 or fewer + objects as ``list[DXFObject]``. + + """ + return self._entity_space[index] # type: ignore + + def __contains__(self, entity): + """Returns ``True`` if `entity` stored in OBJECTS section. + + Args: + entity: :class:`DXFObject` or handle as hex string + + """ + if isinstance(entity, str): + try: + entity = self.entitydb[entity] + except KeyError: + return False + return entity in self._entity_space + + def query(self, query: str = "*") -> EntityQuery: + """Get all DXF objects matching the :ref:`entity query string`.""" + return EntityQuery(iter(self), query) + + def audit(self, auditor: Auditor) -> None: + """Audit and repair OBJECTS section. + + .. important:: + + Do not delete entities while auditing process, because this + would alter the entity database while iterating, instead use:: + + auditor.trash(entity) + + to delete invalid entities after auditing automatically. + + """ + assert self.doc is auditor.doc, "Auditor for different DXF document." + for entity in self._entity_space: + if not is_dxf_object(entity): + auditor.fixed_error( + code=AuditError.REMOVED_INVALID_DXF_OBJECT, + message=f"Removed invalid DXF entity {str(entity)} " + f"from OBJECTS section.", + ) + auditor.trash(entity) + self.reorg(auditor) + self._entity_space.audit(auditor) + + def add_dictionary(self, owner: str = "0", hard_owned: bool = True) -> Dictionary: + """Add new :class:`~ezdxf.entities.Dictionary` object. + + Args: + owner: handle to owner as hex string. + hard_owned: ``True`` to treat entries as hard owned. + + """ + entity = self.new_entity( + "DICTIONARY", + dxfattribs={ + "owner": owner, + "hard_owned": hard_owned, + }, + ) + return cast(Dictionary, entity) + + def add_dictionary_with_default( + self, owner="0", default="0", hard_owned: bool = True + ) -> DictionaryWithDefault: + """Add new :class:`~ezdxf.entities.DictionaryWithDefault` object. + + Args: + owner: handle to owner as hex string. + default: handle to default entry. + hard_owned: ``True`` to treat entries as hard owned. + + """ + entity = self.new_entity( + "ACDBDICTIONARYWDFLT", + dxfattribs={ + "owner": owner, + "default": default, + "hard_owned": hard_owned, + }, + ) + return cast("DictionaryWithDefault", entity) + + def add_dictionary_var(self, owner: str = "0", value: str = "") -> DictionaryVar: + """Add a new :class:`~ezdxf.entities.DictionaryVar` object. + + Args: + owner: handle to owner as hex string. + value: value as string + + """ + return self.new_entity( # type: ignore + "DICTIONARYVAR", dxfattribs={"owner": owner, "value": value} + ) + + def add_xrecord(self, owner: str = "0") -> XRecord: + """Add a new :class:`~ezdxf.entities.XRecord` object. + + Args: + owner: handle to owner as hex string. + + """ + return self.new_entity("XRECORD", dxfattribs={"owner": owner}) # type: ignore + + def add_placeholder(self, owner: str = "0") -> Placeholder: + """Add a new :class:`~ezdxf.entities.Placeholder` object. + + Args: + owner: handle to owner as hex string. + + """ + return self.new_entity( # type: ignore + "ACDBPLACEHOLDER", dxfattribs={"owner": owner} + ) + + # end of public interface + + def set_raster_variables( + self, frame: int = 0, quality: int = 1, units: str = "m" + ) -> None: + """Set raster variables. + + Args: + frame: ``0`` = do not show image frame; ``1`` = show image frame + quality: ``0`` = draft; ``1`` = high + units: units for inserting images. This defines the real world unit for one + drawing unit for the purpose of inserting and scaling images with an + associated resolution. + + ===== =========================== + mm Millimeter + cm Centimeter + m Meter (ezdxf default) + km Kilometer + in Inch + ft Foot + yd Yard + mi Mile + none None + ===== =========================== + + (internal API), public interface :meth:`~ezdxf.drawing.Drawing.set_raster_variables` + + """ + units_: int = const.RASTER_UNITS.get(units, 0) + try: + raster_vars = self.rootdict["ACAD_IMAGE_VARS"] + except const.DXFKeyError: + raster_vars = self.add_dxf_object_with_reactor( + "RASTERVARIABLES", + dxfattribs={ + "owner": self.rootdict.dxf.handle, + "frame": frame, + "quality": quality, + "units": units_, + }, + ) + self.rootdict["ACAD_IMAGE_VARS"] = raster_vars + else: + raster_vars.dxf.frame = frame + raster_vars.dxf.quality = quality + raster_vars.dxf.units = units_ + + def get_raster_variables(self) -> tuple[int, int, str]: + try: + raster_vars = self.rootdict["ACAD_IMAGE_VARS"] + except const.DXFKeyError: + return 0, 1, "none" + return ( + raster_vars.dxf.frame, + raster_vars.dxf.quality, + const.REVERSE_RASTER_UNITS.get(raster_vars.dxf.units, "none"), + ) + + def set_wipeout_variables(self, frame: int = 0) -> None: + """Set wipeout variables. + + Args: + frame: ``0`` = do not show image frame; ``1`` = show image frame + + (internal API) + """ + try: + wipeout_vars = self.rootdict["ACAD_WIPEOUT_VARS"] + except const.DXFKeyError: + wipeout_vars = self.add_dxf_object_with_reactor( + "WIPEOUTVARIABLES", + dxfattribs={ + "owner": self.rootdict.dxf.handle, + "frame": int(frame), + }, + ) + self.rootdict["ACAD_WIPEOUT_VARS"] = wipeout_vars + else: + wipeout_vars.dxf.frame = int(frame) + + def get_wipeout_frame_setting(self) -> int: + try: + wipeout_vars = self.rootdict["ACAD_WIPEOUT_VARS"] + except const.DXFKeyError: + return 0 + return wipeout_vars.dxf.frame + + def add_image_def( + self, + filename: str, + size_in_pixel: tuple[int, int], + name: Optional[str] = None, + ) -> ImageDef: + """Add an image definition to the objects section. + + Add an :class:`~ezdxf.entities.image.ImageDef` entity to the drawing + (objects section). `filename` is the image file name as relative or + absolute path and `size_in_pixel` is the image size in pixel as (x, y) + tuple. To avoid dependencies to external packages, `ezdxf` can not + determine the image size by itself. Returns a :class:`~ezdxf.entities.image.ImageDef` + entity which is needed to create an image reference. `name` is the + internal image name, if set to ``None``, name is auto-generated. + + Absolute image paths works best for AutoCAD but not really good, you + have to update external references manually in AutoCAD, which is not + possible in TrueView. If the drawing units differ from 1 meter, you also + have to use: :meth:`set_raster_variables`. + + Args: + filename: image file name (absolute path works best for AutoCAD) + size_in_pixel: image size in pixel as (x, y) tuple + name: image name for internal use, None for using filename as name + (best for AutoCAD) + + """ + if name is None: + name = filename + image_dict = self.rootdict.get_required_dict("ACAD_IMAGE_DICT") + image_def = self.add_dxf_object_with_reactor( + "IMAGEDEF", + dxfattribs={ + "owner": image_dict.dxf.handle, + "filename": filename, + "image_size": size_in_pixel, + }, + ) + image_dict[name] = image_def + return cast("ImageDef", image_def) + + def add_image_def_reactor(self, image_handle: str) -> ImageDefReactor: + """Add required IMAGEDEF_REACTOR object for IMAGEDEF object. + + (internal API) + """ + image_def_reactor = self.new_entity( + "IMAGEDEF_REACTOR", + dxfattribs={ + "owner": image_handle, + "image_handle": image_handle, + }, + ) + return cast("ImageDefReactor", image_def_reactor) + + def add_underlay_def( + self, filename: str, fmt: str = "pdf", name: Optional[str] = None + ) -> UnderlayDefinition: + """Add an :class:`~ezdxf.entities.underlay.UnderlayDefinition` entity + to the drawing (OBJECTS section). `filename` is the underlay file name + as relative or absolute path and `fmt` as string (pdf, dwf, dgn). + The underlay definition is required to create an underlay reference. + + Args: + filename: underlay file name + fmt: file format as string ``'pdf'|'dwf'|'dgn'`` + name: pdf format = page number to display; dgn format = ``'default'``; dwf: ???? + + """ + fmt = fmt.upper() + if fmt in ("PDF", "DWF", "DGN"): + underlay_dict_name = f"ACAD_{fmt}DEFINITIONS" + underlay_def_entity = f"{fmt}DEFINITION" + else: + raise const.DXFValueError(f"Unsupported file format: '{fmt}'") + + if name is None: + if fmt == "PDF": + name = "1" # Display first page by default + elif fmt == "DGN": + name = "default" + else: + name = "Model" # Display model space for DWF ??? + + underlay_dict = self.rootdict.get_required_dict(underlay_dict_name) + underlay_def = self.new_entity( + underlay_def_entity, + dxfattribs={ + "owner": underlay_dict.dxf.handle, + "filename": filename, + "name": name, + }, + ) + + # auto-generated underlay key + key = self.next_underlay_key(lambda k: k not in underlay_dict) + underlay_dict[key] = underlay_def + return cast("UnderlayDefinition", underlay_def) + + def add_geodata(self, owner: str = "0", dxfattribs=None) -> GeoData: + """Creates a new :class:`GeoData` entity and replaces existing ones. + The GEODATA entity resides in the OBJECTS section and NOT in the layout + entity space, and it is linked to the layout by an extension dictionary + located in BLOCK_RECORD of the layout. + + The GEODATA entity requires DXF version R2010+. The DXF Reference does + not document if other layouts than model space supports geo referencing, + so getting/setting geo data may only make sense for the model space + layout, but it is also available in paper space layouts. + + Args: + owner: handle to owner as hex string + dxfattribs: DXF attributes for :class:`~ezdxf.entities.GeoData` entity + + """ + if dxfattribs is None: + dxfattribs = {} + dxfattribs["owner"] = owner + return cast("GeoData", self.add_dxf_object_with_reactor("GEODATA", dxfattribs)) + + def reorg(self, auditor: Optional[Auditor] = None) -> Auditor: + """Validate and recreate the integrity of the OBJECTS section.""" + if auditor is None: + assert self.doc is not None, "valid document required" + auditor = Auditor(self.doc) + sanitizer = _Sanitizer(auditor, self) + sanitizer.execute() + return auditor + + +_OBJECT_TABLE_NAMES = [ + "ACAD_COLOR", + "ACAD_GROUP", + "ACAD_LAYOUT", + "ACAD_MATERIAL", + "ACAD_MLEADERSTYLE", + "ACAD_MLINESTYLE", + "ACAD_PLOTSETTINGS", + "ACAD_PLOTSTYLENAME", + "ACAD_SCALELIST", + "ACAD_TABLESTYLE", + "ACAD_VISUALSTYLE", +] + +KNOWN_DICT_CONTENT: dict[str, str] = { + "ACAD_COLOR": "DBCOLOR", + "ACAD_GROUP": "GROUP", + "ACAD_IMAGE_DICT": "IMAGEDEF", + "ACAD_DETAILVIEWSTYLE": "ACDBDETAILVIEWSTYLE", + "ACAD_LAYOUT": "LAYOUT", + "ACAD_MATERIAL": "MATERIAL", + "ACAD_MLEADERSTYLE": "MLEADERSTYLE", + "ACAD_MLINESTYLE": "MLINESTYLE", + "ACAD_PLOTSETTINGS": "PLOTSETTINGS", + "ACAD_RENDER_ACTIVE_SETTINGS": "MENTALRAYRENDERSETTINGS", + "ACAD_SCALELIST": "SCALE", + "ACAD_SECTIONVIEWSTYLE": "ACDBSECTIONVIEWSTYLE", + "ACAD_TABLESTYLE": "TABLESTYLE", + "ACAD_PDFDEFINITIONS": "PDFDEFINITION", + "ACAD_DWFDEFINITIONS": "DWFDEFINITION", + "ACAD_DGNDEFINITIONS": "DGNDEFINITION", + "ACAD_VISUALSTYLE": "VISUALSTYLE", + "AcDbVariableDictionary": "DICTIONARYVAR", +} + + +class _Sanitizer: + def __init__(self, auditor: Auditor, objects: ObjectsSection) -> None: + self.objects = objects + self.auditor = auditor + self.rootdict = objects.rootdict + self.removed_entity = True + + def dictionaries(self) -> Iterator[Dictionary]: + for d in self.objects: + if isinstance(d, Dictionary): + yield d + + def execute(self, max_loops=100) -> None: + self.restore_owner_handles_of_dictionary_entries() + self.validate_known_dictionaries() + loops = 0 + self.removed_entity = True + while self.removed_entity and loops < max_loops: + loops += 1 + self.removed_entity = False + self.remove_orphaned_dictionaries() + # Run audit on all entities of the OBJECTS section to take the removed + # dictionaries into account. + self.audit_objects() + self.create_required_structures() + + def restore_owner_handles_of_dictionary_entries(self) -> None: + def reclaim_entity() -> None: + entity.dxf.owner = dict_handle + self.auditor.fixed_error( + AuditError.INVALID_OWNER_HANDLE, + f"Fixed invalid owner handle of {entity}.", + ) + + def purge_key(): + purge.append(key) + self.auditor.fixed_error( + AuditError.INVALID_OWNER_HANDLE, + f"Removed invalid key {key} in {str(dictionary)}.", + ) + + entitydb = self.auditor.entitydb + for dictionary in self.dictionaries(): + purge: list[str] = [] # list of keys to discard + dict_handle = dictionary.dxf.handle + for key, entity in dictionary.items(): + if isinstance(entity, str): + # handle is not resolved -> entity does not exist + purge_key() + continue + owner_handle = entity.dxf.get("owner") + if owner_handle == dict_handle: + continue + parent_dict = entitydb.get(owner_handle) + if isinstance(parent_dict, Dictionary) and parent_dict.find_key(entity): + # entity belongs to parent_dict, discard key + purge_key() + else: + reclaim_entity() + for key in purge: + dictionary.discard(key) + + def remove_orphaned_dictionaries(self) -> None: + def kill_dictionary(): + entitydb.discard(dictionary) + dictionary._silent_kill() + + entitydb = self.auditor.entitydb + rootdict = self.rootdict + for dictionary in self.dictionaries(): + if dictionary is rootdict: + continue + owner = entitydb.get(dictionary.dxf.get("owner")) + if owner is None: + # owner does not exist: + # A DICTIONARY without an owner has no purpose and the owner can not be + # determined, except for searching all dictionaries for an entry that + # references this DICTIONARY, this is done in the method + # restore_owner_handles_of_dictionary_entries(). + kill_dictionary() + continue + if not isinstance(owner, Dictionary): + continue + key = owner.find_key(dictionary) + if not key: # owner dictionary has no entry for this dict + kill_dictionary() + + def validate_known_dictionaries(self) -> None: + from ezdxf.entities import DXFEntity + + auditor = self.auditor + for dict_name, expected_type in KNOWN_DICT_CONTENT.items(): + object_dict = self.rootdict.get(dict_name) + if not isinstance(object_dict, Dictionary): + continue + purge_keys: list[str] = [] + for key, entry in object_dict.items(): + if isinstance(entry, DXFEntity) and entry.dxftype() != expected_type: + auditor.fixed_error( + AuditError.REMOVED_INVALID_DXF_OBJECT, + f"Removed invalid type {entry} from {object_dict}<{dict_name}>, " + f"expected type {expected_type}", + ) + purge_keys.append(key) + auditor.trash(entry) + for key in purge_keys: + object_dict.discard(key) + + def create_required_structures(self): + self.objects.setup_object_management_tables(self.rootdict) + doc = self.objects.doc + # update ObjectCollections: + doc.materials.update_object_dict() + doc.materials.create_required_entries() + doc.mline_styles.update_object_dict() + doc.mline_styles.create_required_entries() + doc.mleader_styles.update_object_dict() + doc.mleader_styles.create_required_entries() + doc.groups.update_object_dict() + + def cleanup_entitydb(self): + self.auditor.empty_trashcan() + self.auditor.entitydb.purge() + + def audit_objects(self): + self.cleanup_entitydb() + auditor = self.auditor + current_db_size = len(auditor.entitydb) + + for entity in self.objects: + auditor.check_owner_exist(entity) + entity.audit(auditor) + + auditor.empty_trashcan() + if current_db_size != len(auditor.entitydb): + self.removed_entity = True diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/table.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/table.py new file mode 100644 index 0000000..54f9efa --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/table.py @@ -0,0 +1,779 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Generic, + Iterator, + List, + Optional, + TYPE_CHECKING, + TypeVar, + Union, + cast, + Sequence, +) +from collections import OrderedDict +import logging + +from ezdxf.audit import Auditor, AuditError +from ezdxf.lldxf import const, validator +from ezdxf.entities.table import TableHead +from ezdxf.entities import ( + factory, + DXFEntity, + Layer, + Linetype, + Textstyle, + VPort, + View, + AppID, + UCSTableEntry, + BlockRecord, + DimStyle, + is_graphic_entity, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.lldxf.tagwriter import AbstractTagWriter + from ezdxf.entitydb import EntityDB + + +logger = logging.getLogger("ezdxf") + +T = TypeVar("T", bound="DXFEntity") + + +class Table(Generic[T]): + TABLE_TYPE = "UNKNOWN" + + def __init__(self) -> None: + self.doc: Optional[Drawing] = None + self.entries: dict[str, T] = OrderedDict() + self._head = TableHead() + + def load(self, doc: Drawing, entities: Iterator[DXFEntity]) -> None: + """Loading interface. (internal API)""" + self.doc = doc + table_head = next(entities) + if isinstance(table_head, TableHead): + self._head = table_head + else: + raise const.DXFStructureError("Critical structure error in TABLES section.") + expected_entry_dxftype = self.TABLE_TYPE + for table_entry in entities: + if table_entry.dxftype() == expected_entry_dxftype: + self._append(cast(T, table_entry)) + else: + logger.warning( + f"Ignored invalid DXF entity type '{table_entry.dxftype()}'" + f" in {self.TABLE_TYPE} table." + ) + + def reset(self, doc: Drawing, handle: str) -> None: + """Reset table. (internal API)""" + self.doc = doc + self._set_head(self.TABLE_TYPE, handle) + self.entries.clear() + + def _set_head(self, name: str, handle: Optional[str] = None) -> None: + self._head = TableHead.new( + handle, owner="0", dxfattribs={"name": name}, doc=self.doc + ) + + @property + def head(self): + """Returns table head entry.""" + return self._head + + @property + def name(self) -> str: + return self.TABLE_TYPE + + @staticmethod + def key(name: str) -> str: + """Unified table entry key.""" + return validator.make_table_key(name) + + def has_entry(self, name: str) -> bool: + """Returns ``True`` if a table entry `name` exist.""" + return self.key(name) in self.entries + + __contains__ = has_entry + + def __len__(self) -> int: + """Count of table entries.""" + return len(self.entries) + + def __iter__(self) -> Iterator[T]: + """Iterable of all table entries.""" + for e in self.entries.values(): + if e.is_alive: + yield e + + def new(self, name: str, dxfattribs=None) -> T: + """Create a new table entry `name`. + + Args: + name: name of table entry + dxfattribs: additional DXF attributes for table entry + + """ + if self.has_entry(name): + raise const.DXFTableEntryError( + f"{self.TABLE_TYPE} '{name}' already exists!" + ) + dxfattribs = dxfattribs or {} + dxfattribs["name"] = name + dxfattribs["owner"] = self._head.dxf.handle + return self.new_entry(dxfattribs) + + def get(self, name: str) -> T: + """Returns table entry `name`. + + Args: + name: name of table entry, case-insensitive + + Raises: + DXFTableEntryError: table entry does not exist + + """ + entry = self.entries.get(self.key(name)) + if entry: + return entry + else: + raise const.DXFTableEntryError(name) + + def get_entry_by_handle(self, handle: str) -> Optional[T]: + """Returns table entry by handle or ``None`` if entry does not exist. + + (internal API) + """ + entry = self.doc.entitydb.get(handle) # type: ignore + if entry and entry.dxftype() == self.TABLE_TYPE: + return entry # type: ignore + return None + + def get_handle_of_entry(self, name: str) -> str: + """Returns the handle of table entry by `name`, returns an empty string if no + entry for the given name exist. + + Args: + name: name of table entry, case-insensitive + + (internal API) + """ + entry = self.entries.get(self.key(name)) + if entry is not None: + return entry.dxf.handle + return "" + + def remove(self, name: str) -> None: + """Removes table entry `name`. + + Args: + name: name of table entry, case-insensitive + + Raises: + DXFTableEntryError: table entry does not exist + + """ + key = self.key(name) + entry = self.get(name) + self.entitydb.delete_entity(entry) + self.discard(key) + + def duplicate_entry(self, name: str, new_name: str) -> T: + """Returns a new table entry `new_name` as copy of `name`, + replaces entry `new_name` if already exist. + + Args: + name: name of table entry, case-insensitive + new_name: name of duplicated table entry + + Raises: + DXFTableEntryError: table entry does not exist + + """ + entry = self.get(name) + entitydb = self.entitydb + if entitydb: + new_entry = entitydb.duplicate_entity(entry) + else: # only for testing! + new_entry = entry.copy() + new_entry.dxf.name = new_name + entry = cast(T, new_entry) + self._append(entry) + return entry + + def discard(self, name: str) -> None: + """Remove table entry without destroying object. + + Args: + name: name of table entry, case-insensitive + + (internal API) + """ + del self.entries[self.key(name)] + + def replace(self, name: str, entry: T) -> None: + """Replace table entry `name` by new `entry`. (internal API)""" + self.discard(name) + self._append(entry) + + @property + def entitydb(self) -> EntityDB: + return self.doc.entitydb # type: ignore + + def new_entry(self, dxfattribs) -> T: + """Create and add new table-entry of type 'self.entry_dxftype'. + + Does not check if an entry dxfattribs['name'] already exists! + Duplicate entries are possible for Viewports. + """ + assert self.doc is not None, "valid DXF document required" + entry = cast(T, factory.create_db_entry(self.TABLE_TYPE, dxfattribs, self.doc)) + + self._append(entry) + return entry + + def _append(self, entry: T) -> None: + """Add a table entry, replaces existing entries with same name. + (internal API). + """ + assert entry.dxftype() == self.TABLE_TYPE + self.entries[self.key(entry.dxf.name)] = entry + + def add_entry(self, entry: T) -> None: + """Add a table `entry`, created by other object than this table. + (internal API) + """ + if entry.dxftype() != self.TABLE_TYPE: + raise const.DXFTypeError( + f"Invalid table entry type {entry.dxftype()} " + f"for table {self.TABLE_TYPE}" + ) + name = entry.dxf.name + if self.has_entry(name): + raise const.DXFTableEntryError( + f"{self._head.dxf.name} {name} already exists!" + ) + if self.doc: + factory.bind(entry, self.doc) + entry.dxf.owner = self._head.dxf.handle + self._append(entry) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + """Export DXF representation. (internal API)""" + + self.update_owner_handles() + # The table head itself has no owner and is therefore always '0': + self._head.dxf.owner = "0" + self._head.dxf.count = len(self) + self._head.export_dxf(tagwriter) + self.export_table_entries(tagwriter) + tagwriter.write_tag2(0, "ENDTAB") + + def export_table_entries(self, tagwriter: AbstractTagWriter) -> None: + for entry in self.entries.values(): + entry.export_dxf(tagwriter) + + def update_owner_handles(self) -> None: + owner_handle = self._head.dxf.handle + for entry in self.entries.values(): + entry.dxf.owner = owner_handle + + def set_handle(self, handle: str): + """Set new `handle` for table, updates also :attr:`owner` tag of table + entries. (internal API) + """ + if self._head.dxf.handle is None: + self._head.dxf.handle = handle + self.update_owner_handles() + + def audit(self, auditor: Auditor): + # The table entries are stored in the entity database and are already + # audited! + self._fix_table_head(auditor) + self._fix_entry_handles(auditor) + + def _fix_entry_handles(self, auditor: Auditor): + # Why: see duplicate handle issue #604 + entitydb = self.entitydb + for entry in self: + entity = entitydb.get(entry.dxf.handle) + if entity is not entry: # duplicate handle usage + # This can break entities referring to this entity, but at + # least the DXF readable + entry.dxf.handle = entitydb.next_handle() + self.entitydb.add(entry) + auditor.fixed_error( + code=AuditError.INVALID_TABLE_HANDLE, + message=f"Fixed invalid table entry handle in {entry}", + ) + + def _fix_table_head(self, auditor: Auditor): + def fix_head(): + head.dxf.handle = entitydb.next_handle() + entitydb.add(head) + if log: + auditor.fixed_error( + code=AuditError.INVALID_TABLE_HANDLE, + message=f"Fixed invalid table head handle in table {self.name}", + ) + + # fix silently for older DXF versions + log = auditor.doc.dxfversion > const.DXF12 + + head = self.head + # Another exception for an invalid owner tag, but this usage is + # covered in Auditor.check_owner_exist(): + head.dxf.owner = "0" + handle = head.dxf.handle + entitydb = self.entitydb + if handle is None or handle == "0": + # Entity database does not assign new handle: + fix_head() + else: + # Why: see duplicate handle issue #604 + entry = self.entitydb.get(handle) + if entry is not head: # another entity has the same handle! + fix_head() + # Just to be sure owner handle is valid in every circumstance: + self.update_owner_handles() + + +class LayerTable(Table[Layer]): + TABLE_TYPE = "LAYER" + + def new_entry(self, dxfattribs) -> Layer: + layer = cast(Layer, super().new_entry(dxfattribs)) + if self.doc: + layer.set_required_attributes() + return layer + + def add( + self, + name: str, + *, + color: int = const.BYLAYER, + true_color: Optional[int] = None, + linetype: str = "Continuous", + lineweight: int = const.LINEWEIGHT_BYLAYER, + plot: bool = True, + transparency: Optional[float] = None, + dxfattribs=None, + ) -> Layer: + """Add a new :class:`~ezdxf.entities.Layer`. + + Args: + name (str): layer name + color (int): :ref:`ACI` value, default is BYLAYER + true_color (int): true color value, use :func:`ezdxf.rgb2int` to + create ``int`` values from RGB values + linetype (str): line type name, default is "Continuous" + lineweight (int): line weight, default is BYLAYER + plot (bool): plot layer as bool, default is ``True`` + transparency: transparency value in the range [0, 1], where 1 is + 100% transparent and 0 is opaque + dxfattribs (dict): additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + if validator.is_valid_aci_color(color): + dxfattribs["color"] = color + else: + raise const.DXFValueError(f"invalid color: {color}") + dxfattribs["linetype"] = linetype + if validator.is_valid_lineweight(lineweight): + dxfattribs["lineweight"] = lineweight + else: + raise const.DXFValueError(f"invalid lineweight: {lineweight}") + if true_color is not None: + dxfattribs["true_color"] = int(true_color) + dxfattribs["plot"] = int(plot) + layer = cast("Layer", self.new(name, dxfattribs)) + if transparency is not None: + layer.transparency = transparency + return layer + + def create_referenced_layers(self) -> None: + """Create for all referenced layers table entries if not exist.""" + if self.doc is None: + return + for e in self.doc.entitydb.values(): + if not is_graphic_entity(e): + continue + layer_name = e.dxf.get("layer", "") + if layer_name and not self.has_entry(layer_name): + # create layer table entry with default settings + self.add(layer_name) + + +class LinetypeTable(Table[Linetype]): + TABLE_TYPE = "LTYPE" + + def new_entry(self, dxfattribs) -> Linetype: + pattern = dxfattribs.pop("pattern", [0.0]) + length = dxfattribs.pop("length", 0) # required for complex types + ltype = cast(Linetype, super().new_entry(dxfattribs)) + ltype.setup_pattern(pattern, length) + return ltype + + def add( + self, + name: str, + pattern: Union[Sequence[float], str], + *, + description: str = "", + length: float = 0.0, + dxfattribs=None, + ) -> Linetype: + """Add a new line type entry. The simple line type pattern is a list of + floats :code:`[total_pattern_length, elem1, elem2, ...]` + where an element > 0 is a line, an element < 0 is a gap and an + element == 0.0 is a dot. The definition for complex line types are + strings, like: ``'A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25'`` + similar to the line type definitions stored in the line definition + `.lin` files, for more information see the tutorial about complex line + types. Be aware that not many CAD applications and DXF viewers support + complex linetypes. + + .. seealso:: + + - `Tutorial for simple line types `_ + - `Tutorial for complex line types `_ + + Args: + name (str): line type name + pattern: line type pattern as list of floats or as a string + description (str): line type description, optional + length (float): total pattern length, only for complex line types required + dxfattribs (dict): additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs.update( + { + "name": name, + "description": str(description), + "pattern": pattern, + "length": float(length), + } + ) + return self.new_entry(dxfattribs) + + +class TextstyleTable(Table[Textstyle]): + TABLE_TYPE = "STYLE" + + def __init__(self) -> None: + super().__init__() + self.shx_files: dict[str, Textstyle] = dict() + + def export_table_entries(self, tagwriter: AbstractTagWriter) -> None: + super().export_table_entries(tagwriter) + for shx_file in self.shx_files.values(): + shx_file.export_dxf(tagwriter) + + def _append(self, entry: Textstyle) -> None: + """Add a table entry, replaces existing entries with same name. + (internal API). + """ + if entry.dxf.name == "" and (entry.dxf.flags & 1): # shx shape file + self.shx_files[self.key(entry.dxf.font)] = entry + else: + self.entries[self.key(entry.dxf.name)] = entry + + def update_owner_handles(self) -> None: + super().update_owner_handles() + owner_handle = self._head.dxf.handle + for entry in self.shx_files.values(): + entry.dxf.owner = owner_handle + + def add(self, name: str, *, font: str, dxfattribs=None) -> Textstyle: + """Add a new text style entry for TTF fonts. The entry must not yet + exist, otherwise an :class:`DXFTableEntryError` exception will be + raised. + + Finding the TTF font files is the task of the DXF viewer and each + viewer is different (hint: support files). + + Args: + name (str): text style name + font (str): TTF font file name like "Arial.ttf", the real font file + name from the file system is required and only the Windows filesystem + is case-insensitive. + dxfattribs (dict): additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs.update( + { + "name": name, + "font": str(font), + "last_height": 2.5, # maybe required by AutoCAD + } + ) + return self.new_entry(dxfattribs) + + def add_shx(self, shx_file_name: str, *, dxfattribs=None) -> Textstyle: + """Add a new shape font (SHX file) entry. These are special text style + entries and have no name. The entry must not yet exist, otherwise an + :class:`DXFTableEntryError` exception will be raised. + + Locating the SHX files in the filesystem is the task of the DXF viewer and each + viewer is different (hint: support files). + + Args: + shx_file_name (str): shape file name like "gdt.shx" + dxfattribs (dict): additional DXF attributes + + """ + if self.find_shx(shx_file_name) is not None: + raise const.DXFTableEntryError( + f"{self._head.dxf.name} shape file entry for " + f"'{shx_file_name}' already exists!" + ) + + dxfattribs = dict(dxfattribs or {}) + dxfattribs.update( + { + "name": "", # shape file entry has no name + "flags": 1, # shape file flag + "font": shx_file_name, + "last_height": 2.5, # maybe required by AutoCAD + } + ) + return self.new_entry(dxfattribs) + + def get_shx(self, shx_file_name: str) -> Textstyle: + """Get existing entry for a shape file (SHX file), or create a new + entry. + + Locating the SHX files in the filesystem is the task of the DXF viewer and each + viewer is different (hint: support files). + + Args: + shx_file_name (str): shape file name like "gdt.shx" + + """ + shape_file = self.find_shx(shx_file_name) + if shape_file is None: + return self.add_shx(shx_file_name) + return shape_file + + def find_shx(self, shx_file_name: str) -> Optional[Textstyle]: + """Find the shape file (SHX file) text style table entry, by a + case-insensitive search. + + A shape file table entry has no name, so you have to search by the + font attribute. + + Args: + shx_file_name (str): shape file name like "gdt.shx" + + """ + return self.shx_files.get(self.key(shx_file_name)) + + def discard_shx(self, shx_file_name: str) -> None: + """Discard the shape file (SHX file) text style table entry. Does not raise an + exception if the entry does not exist. + + Args: + shx_file_name (str): shape file name like "gdt.shx" + + """ + try: + del self.shx_files[self.key(shx_file_name)] + except KeyError: + pass + + +class ViewportTable(Table[VPort]): + TABLE_TYPE = "VPORT" + # Viewport-Table can have multiple entries with same name + # each table entry is a list of VPORT entries + + def export_table_entries(self, tagwriter: AbstractTagWriter) -> None: + for entry in self.entries.values(): + assert isinstance(entry, list) + for e in entry: + e.export_dxf(tagwriter) + + def new(self, name: str, dxfattribs=None) -> VPort: + """Create a new table entry.""" + dxfattribs = dxfattribs or {} + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + def add(self, name: str, *, dxfattribs=None) -> VPort: + """Add a new modelspace viewport entry. A modelspace viewport + configuration can consist of multiple viewport entries with the same + name. + + Args: + name (str): viewport name, multiple entries possible + dxfattribs (dict): additional DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + def remove(self, name: str) -> None: + """Remove table-entry from table and entitydb by name.""" + key = self.key(name) + entries = cast(List[DXFEntity], self.get(name)) + for entry in entries: + self.entitydb.delete_entity(entry) + del self.entries[key] + + def __iter__(self) -> Iterator[VPort]: + for entries in self.entries.values(): + yield from iter(entries) # type: ignore + + def _flatten(self) -> Iterator[VPort]: + for entries in self.entries.values(): + yield from iter(entries) # type: ignore + + def __len__(self) -> int: + # calling __iter__() invokes recursion! + return len(list(self._flatten())) + + def new_entry(self, dxfattribs) -> VPort: + """Create and add new table-entry of type 'self.entry_dxftype'. + + Does not check if an entry dxfattribs['name'] already exists! + Duplicate entries are possible for Viewports. + """ + assert self.doc is not None, "valid DXF document expected" + entry = cast( + VPort, + factory.create_db_entry(self.TABLE_TYPE, dxfattribs, self.doc), + ) + self._append(entry) + return entry + + def duplicate_entry(self, name: str, new_name: str) -> VPort: + raise NotImplementedError() + + def _append(self, entry: T) -> None: + key = self.key(entry.dxf.name) + if key in self.entries: + self.entries[key].append(entry) # type: ignore + else: + self.entries[key] = [entry] # type: ignore # store list of VPORT + + def replace(self, name: str, entry: T) -> None: + self.discard(name) + config: list[T] + if isinstance(entry, list): + config = entry + else: + config = [entry] + if not config: + return + key = self.key(config[0].dxf.name) + self.entries[key] = config # type: ignore + + def update_owner_handles(self) -> None: + owner_handle = self._head.dxf.handle + for entries in self.entries.values(): + for entry in entries: # type: ignore + entry.dxf.owner = owner_handle + + def get_config(self, name: str) -> list[VPort]: + """Returns a list of :class:`~ezdxf.entities.VPort` objects, for + the multi-viewport configuration `name`. + """ + try: + return self.entries[self.key(name)] # type: ignore + except KeyError: + raise const.DXFTableEntryError(name) + + def delete_config(self, name: str) -> None: + """Delete all :class:`~ezdxf.entities.VPort` objects of the + multi-viewport configuration `name`. + """ + self.remove(name) + + +class AppIDTable(Table[AppID]): + TABLE_TYPE = "APPID" + + def add(self, name: str, *, dxfattribs=None) -> AppID: + """Add a new appid table entry. + + Args: + name (str): appid name + dxfattribs (dict): DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + +class ViewTable(Table[View]): + TABLE_TYPE = "VIEW" + + def add(self, name: str, *, dxfattribs=None) -> View: + """Add a new view table entry. + + Args: + name (str): view name + dxfattribs (dict): DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + +class BlockRecordTable(Table[BlockRecord]): + TABLE_TYPE = "BLOCK_RECORD" + + def add(self, name: str, *, dxfattribs=None) -> BlockRecord: + """Add a new block record table entry. + + Args: + name (str): block record name + dxfattribs (dict): DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + +class DimStyleTable(Table[DimStyle]): + TABLE_TYPE = "DIMSTYLE" + + def add(self, name: str, *, dxfattribs=None) -> DimStyle: + """Add a new dimension style table entry. + + Args: + name (str): dimension style name + dxfattribs (dict): DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) + + +class UCSTable(Table[UCSTableEntry]): + TABLE_TYPE = "UCS" + + def add(self, name: str, *, dxfattribs=None) -> UCSTableEntry: + """Add a new UCS table entry. + + Args: + name (str): UCS name + dxfattribs (dict): DXF attributes + + """ + dxfattribs = dict(dxfattribs or {}) + dxfattribs["name"] = name + return self.new_entry(dxfattribs) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/sections/tables.py b/.venv/lib/python3.12/site-packages/ezdxf/sections/tables.py new file mode 100644 index 0000000..6b1e96b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/sections/tables.py @@ -0,0 +1,152 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Sequence, Optional +import logging +from ezdxf.lldxf.const import DXFStructureError, DXF12 +from .table import ( + Table, + ViewportTable, + TextstyleTable, + LayerTable, + LinetypeTable, + AppIDTable, + ViewTable, + BlockRecordTable, + DimStyleTable, + UCSTable, +) + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DXFEntity, DXFTagStorage + from ezdxf.lldxf.tagwriter import AbstractTagWriter + +logger = logging.getLogger("ezdxf") + +TABLENAMES = { + "LAYER": "layers", + "LTYPE": "linetypes", + "APPID": "appids", + "DIMSTYLE": "dimstyles", + "STYLE": "styles", + "UCS": "ucs", + "VIEW": "views", + "VPORT": "viewports", + "BLOCK_RECORD": "block_records", +} + + +class TablesSection: + def __init__(self, doc: Drawing, entities: Optional[list[DXFEntity]] = None): + assert doc is not None + self.doc = doc + # not loaded tables: table.doc is None + self.layers = LayerTable() + self.linetypes = LinetypeTable() + self.appids = AppIDTable() + self.dimstyles = DimStyleTable() + self.styles = TextstyleTable() + self.ucs = UCSTable() + self.views = ViewTable() + self.viewports = ViewportTable() + self.block_records = BlockRecordTable() + + if entities is not None: + self._load(entities) + self._reset_not_loaded_tables() + + def tables(self) -> Sequence[Table]: + return ( + self.layers, + self.linetypes, + self.appids, + self.dimstyles, + self.styles, + self.ucs, + self.views, + self.viewports, + self.block_records, + ) + + def _load(self, entities: list[DXFEntity]) -> None: + section_head: "DXFTagStorage" = entities[0] # type: ignore + if section_head.dxftype() != "SECTION" or section_head.base_class[ + 1 + ] != (2, "TABLES"): + raise DXFStructureError( + "Critical structure error in TABLES section." + ) + del entities[0] # delete first entity (0, SECTION) + + table_records: list[DXFEntity] = [] + table_name = None + for entity in entities: + if entity.dxftype() == "TABLE": + if len(table_records): + # TABLE entity without preceding ENDTAB entity, should we care? + logger.debug( + f'Ignore missing ENDTAB entity in table "{table_name}".' + ) + self._load_table(table_name, table_records) # type: ignore + table_name = entity.dxf.name + table_records = [entity] # collect table head + elif entity.dxftype() == "ENDTAB": # do not collect (0, 'ENDTAB') + self._load_table(table_name, table_records) # type: ignore + table_records = ( + [] + ) # collect entities outside of tables, but ignore it + else: # collect table entries + table_records.append(entity) + + if len(table_records): + # last ENDTAB entity is missing, should we care? + logger.debug( + 'Ignore missing ENDTAB entity in table "{}".'.format(table_name) + ) + self._load_table(table_name, table_records) # type: ignore + + def _load_table( + self, name: str, table_entities: Iterable[DXFEntity] + ) -> None: + """ + Load table from tags. + + Args: + name: table name e.g. VPORT + table_entities: iterable of table records + + """ + table = getattr(self, TABLENAMES[name]) + if isinstance(table, Table): + table.load(self.doc, iter(table_entities)) + + def _reset_not_loaded_tables(self) -> None: + entitydb = self.doc.entitydb + for table in self.tables(): + if table.doc is None: + handle = entitydb.next_handle() + table.reset(self.doc, handle) + entitydb.add(table.head) + + def export_dxf(self, tagwriter: AbstractTagWriter) -> None: + tagwriter.write_str(" 0\nSECTION\n 2\nTABLES\n") + version = tagwriter.dxfversion + self.viewports.export_dxf(tagwriter) + self.linetypes.export_dxf(tagwriter) + self.layers.export_dxf(tagwriter) + self.styles.export_dxf(tagwriter) + self.views.export_dxf(tagwriter) + self.ucs.export_dxf(tagwriter) + self.appids.export_dxf(tagwriter) + self.dimstyles.export_dxf(tagwriter) + if version > DXF12: + self.block_records.export_dxf(tagwriter) + tagwriter.write_tag2(0, "ENDSEC") + + def create_table_handles(self): + # DXF R12: TABLE does not require a handle and owner tag + # DXF R2000+: TABLE requires a handle and an owner tag + for table in self.tables(): + handle = self.doc.entitydb.next_handle() + table.set_handle(handle) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/select.py b/.venv/lib/python3.12/site-packages/ezdxf/select.py new file mode 100644 index 0000000..91b47e7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/select.py @@ -0,0 +1,450 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Callable, Sequence +from typing_extensions import override +import abc + +from ezdxf import bbox +from ezdxf.entities import DXFEntity +from ezdxf.math import UVec, Vec2, Vec3, BoundingBox2d, is_point_in_polygon_2d +from ezdxf.math.clipping import CohenSutherlandLineClipping2d +from ezdxf.math import rtree, BoundingBox +from ezdxf.query import EntityQuery + + +__all__ = [ + "bbox_chained", + "bbox_crosses_fence", + "bbox_inside", + "bbox_outside", + "bbox_overlap", + "Circle", + "PlanarSearchIndex", + "point_in_bbox", + "Polygon", + "Window", +] + + +class SelectionShape(abc.ABC): + """AbstractBaseClass for selection shapes. + + It is guaranteed that all methods get an entity_bbox which has data! + """ + + @abc.abstractmethod + def is_inside_bbox(self, entity_bbox: BoundingBox2d) -> bool: ... + + @abc.abstractmethod + def is_outside_bbox(self, entity_bbox: BoundingBox2d) -> bool: ... + + @abc.abstractmethod + def is_overlapping_bbox(self, entity_bbox: BoundingBox2d) -> bool: ... + + +class Window(SelectionShape): + """This selection shape tests entities against a rectangular and axis-aligned 2D + window. All entities are projected on the xy-plane. + + Args: + p1: first corner of the window + p2: second corner of the window + """ + + def __init__(self, p1: UVec, p2: UVec): + self._bbox = BoundingBox2d((p1, p2)) + + @override + def is_inside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return self._bbox.contains(entity_bbox) + + @override + def is_outside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return not self._bbox.has_overlap(entity_bbox) + + @override + def is_overlapping_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return self._bbox.has_overlap(entity_bbox) + + +class Circle(SelectionShape): + """This selection shape tests entities against a circle. All entities are + projected on the xy-plane. + + Args: + center: center of the circle + radius: radius of the circle + """ + + def __init__(self, center: UVec, radius: float): + self._center = Vec2(center) + self._radius = float(radius) + r_vec = Vec2(self._radius, self._radius) + self._bbox = BoundingBox2d((self._center - r_vec, self._center + r_vec)) + + def _is_vertex_inside(self, v: Vec2) -> bool: + return self._center.distance(v) <= self._radius + + @override + def is_inside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return all(self._is_vertex_inside(v) for v in entity_bbox.rect_vertices()) + + @override + def is_outside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return not self.is_overlapping_bbox(entity_bbox) + + @override + def is_overlapping_bbox(self, entity_bbox: BoundingBox2d) -> bool: + if not self._bbox.has_overlap(entity_bbox): + return False + if any(self._is_vertex_inside(v) for v in entity_bbox.rect_vertices()): + return True + return self._is_vertex_inside(entity_bbox.center) + + +class Polygon(SelectionShape): + """This selection shape tests entities against an arbitrary closed polygon. + All entities are projected on the xy-plane. Complex **concave** polygons may not + work as expected. + """ + + def __init__(self, vertices: Iterable[UVec]): + v = Vec2.list(vertices) + if len(v) < 3: + raise ValueError("3 or more vertices required") + if v[0].isclose(v[-1]): + v.pop() # open polygon + if len(v) < 3: + raise ValueError("3 or more vertices required") + self._vertices: list[Vec2] = v + self._bbox = BoundingBox2d(self._vertices) + + def _has_intersection(self, extmin: Vec2, extmax: Vec2) -> bool: + cs = CohenSutherlandLineClipping2d(extmin, extmax) + vertices = self._vertices + for index, end in enumerate(vertices): + if cs.clip_line(vertices[index - 1], end): + return True + return False + + @override + def is_inside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + if not self._bbox.has_overlap(entity_bbox): + return False + if any( + is_point_in_polygon_2d(v, self._vertices) < 0 # outside + for v in entity_bbox.rect_vertices() + ): + return False + + # Additional test for concave polygons. This may not cover all concave polygons. + # Is any point of the polygon (strict) inside the entity bbox? + min_x, min_y = entity_bbox.extmin + max_x, max_y = entity_bbox.extmax + # strict inside test: points on the boundary line do not count as inside + return not any( + (min_x < v.x < max_x) and (min_y < v.y < max_y) for v in self._vertices + ) + + @override + def is_outside_bbox(self, entity_bbox: BoundingBox2d) -> bool: + return not self.is_overlapping_bbox(entity_bbox) + + @override + def is_overlapping_bbox(self, entity_bbox: BoundingBox2d) -> bool: + if not self._bbox.has_overlap(entity_bbox): + return False + if any( + is_point_in_polygon_2d(v, self._vertices) >= 0 # inside or on boundary + for v in entity_bbox.rect_vertices() + ): + return True + # special case: all bbox corners are outside the polygon but bbox edges may + # intersect the polygon + return self._has_intersection(entity_bbox.extmin, entity_bbox.extmax) + + +def bbox_inside( + shape: SelectionShape, + entities: Iterable[DXFEntity], + *, + cache: bbox.Cache | None = None, +) -> EntityQuery: + """Selects entities whose bounding box lies withing the selection shape. + + Args: + shape: seclection shape + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + return select_by_bbox(entities, shape.is_inside_bbox, cache) + + +def bbox_outside( + shape: SelectionShape, + entities: Iterable[DXFEntity], + *, + cache: bbox.Cache | None = None, +) -> EntityQuery: + """Selects entities whose bounding box is completely outside the selection shape. + + Args: + shape: seclection shape + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + return select_by_bbox(entities, shape.is_outside_bbox, cache) + + +def bbox_overlap( + shape: SelectionShape, + entities: Iterable[DXFEntity], + *, + cache: bbox.Cache | None = None, +) -> EntityQuery: + """Selects entities whose bounding box overlaps the selection shape. + + Args: + shape: seclection shape + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + return select_by_bbox(entities, shape.is_overlapping_bbox, cache) + + +def select_by_bbox( + entities: Iterable[DXFEntity], + test_func: Callable[[BoundingBox2d], bool], + cache: bbox.Cache | None = None, +) -> EntityQuery: + """Calculates the bounding box for each entity and returns all entities for that the + test function returns ``True``. + + Args: + entities: iterable of DXFEntities + func: test function which takes the bounding box of the entity as input and + returns ``True`` if the entity is part of the selection. + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + selection: list[DXFEntity] = [] + + for entity in entities: + extents = bbox.extents((entity,), fast=True, cache=cache) + if not extents.has_data: + continue + if test_func(BoundingBox2d(extents)): + selection.append(entity) + return EntityQuery(selection) + + +def bbox_crosses_fence( + vertices: Iterable[UVec], + entities: Iterable[DXFEntity], + *, + cache: bbox.Cache | None = None, +) -> EntityQuery: + """Selects entities whose bounding box intersects an open polyline. + + All entities are projected on the xy-plane. + + A single point can not be selected by a fence polyline by definition. + + Args: + vertices: vertices of the selection polyline + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + + def is_crossing(entity_bbox: BoundingBox2d) -> bool: + if not _bbox.has_overlap(entity_bbox): + return False + if any(entity_bbox.inside(v) for v in _vertices): + return True + # All fence vertices are outside the entity bbox, but fence edges may + # intersect the entity bbox. + extmin = entity_bbox.extmin + extmax = entity_bbox.extmax + if extmin.isclose(extmax): # is point + return False # by definition + cs = CohenSutherlandLineClipping2d(extmin, extmax) + return any( + cs.clip_line(start, end) for start, end in zip(_vertices, _vertices[1:]) + ) + + _vertices = Vec2.list(vertices) + if len(_vertices) < 2: + raise ValueError("2 or more vertices required") + _bbox = BoundingBox2d(_vertices) + + return select_by_bbox(entities, is_crossing, cache) + + +def point_in_bbox( + location: UVec, entities: Iterable[DXFEntity], *, cache: bbox.Cache | None = None +) -> EntityQuery: + """Selects entities where the selection point lies within the bounding box. + All entities are projected on the xy-plane. + + Args: + point: selection point + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + + def is_crossing(entity_bbox: BoundingBox2d) -> bool: + return entity_bbox.inside(point) + + point = Vec2(location) + return select_by_bbox(entities, is_crossing, cache) + + +def bbox_chained( + start: DXFEntity, entities: Iterable[DXFEntity], *, cache: bbox.Cache | None = None +) -> EntityQuery: + """Selects elements that are directly or indirectly connected to each other by + overlapping bounding boxes. The selection begins at the specified starting element. + + Warning: the current implementation has a complexity of O(n²). + + Args: + start: first entity of selection + entities: iterable of DXFEntities + cache: optional :class:`ezdxf.bbox.Cache` instance + + """ + + def get_bbox_2d(entity: DXFEntity) -> BoundingBox2d: + return BoundingBox2d(bbox.extents((entity,), fast=True, cache=cache)) + + if cache is None: + cache = bbox.Cache() + selected: dict[DXFEntity, BoundingBox2d] = {start: get_bbox_2d(start)} + + entities = list(entities) + restart = True + while restart: + restart = False + for entity in entities: + if entity in selected: + continue + entity_bbox = get_bbox_2d(entity) + for selected_bbox in selected.values(): + if entity_bbox.has_overlap(selected_bbox): + selected[entity] = entity_bbox + restart = True + break + + return EntityQuery(selected.keys()) + + +class PlanarSearchIndex: + """**Spatial Search Index for DXF Entities** + + This class implements a spatial search index for DXF entities based on their + bounding boxes except for POINT and LINE. + It operates strictly within the two-dimensional (2D) space of the xy-plane. + The index is built once and cannot be extended afterward. + + The index can be used to pre-select DXF entities from a certain area to reduce the + search space for other selection tools of this module. + + **Functionality** + + - The index relies on the bounding boxes of DXF entities, and only the corner + vertices of these bounding boxes are indexed except for POINT and LINE. + - It can only find DXF entities that have at least one bounding box vertex located + within the search area. Entities whose bounding boxes overlap the search area but + have no vertices inside it will not be found (e.g., a circle whose center point + is inside the search area but none of its bounding box vertices will not be + included). + - The detection behavior can be customized by overriding the :meth:`detection_points` + method. + + **Recommendations** + + Since this index is intended to be used in conjunction with other selection tools + within this module, it's recommended to maintain a bounding box cache to avoid + the computational cost of recalculating them frequently. This class creates a new + bounding box cache if none is specified. This cache can be accessed through the + public attribute :attr:`cache`. + + """ + + def __init__( + self, + entities: Iterable[DXFEntity], + cache: bbox.Cache | None = None, + max_node_size=5, # Change only if you know what you do! + ): + class RTreeVtx(Vec2): # super() doesn't work, so no __init__() + __slots__ = ("uid",) + + def detection_vertex(location: Vec2, uid: int) -> RTreeVtx: + vertex = RTreeVtx(location) + vertex.uid = uid + return vertex + + self.cache = cache or bbox.Cache() + self._entities: dict[int, DXFEntity] = {} + detection_vertices: list[RTreeVtx] = [] + for entity in entities: + detection_points = self.detection_points(entity) + if not detection_points: + continue + + uid = id(entity) + self._entities[uid] = entity + detection_vertices.extend( + detection_vertex(pnt, uid) for pnt in detection_points + ) + self._search_tree = rtree.RTree( + detection_vertices, max_node_size=max(5, int(max_node_size)) + ) + + def detection_points(self, entity: DXFEntity) -> Sequence[Vec2]: + """Returns the detection points for a given DXF entity. + + The detection points must be 2D points projected onto the xy-plane (ignore z-axis). + This implementation returns the corner vertices of the entity bounding box. + + Override this method to return more sophisticated detection points + (e.g., the vertices of LWPOLYLINE and POLYLINE or equally spaced raster points + for block references). + """ + dxftype = entity.dxftype() + if dxftype == "POINT": + return (Vec2(entity.dxf.location),) + if dxftype == "LINE": + return (Vec2(entity.dxf.start), Vec2(entity.dxf.end)) + + box2d = BoundingBox2d(bbox.extents((entity,), fast=True, cache=self.cache)) + if box2d.has_data: + return box2d.rect_vertices() + return tuple() + + def detection_point_in_circle( + self, center: UVec, radius: float + ) -> Sequence[DXFEntity]: + """Returns all DXF entities that have at least one detection point located + around `center` with a max. distance of `radius`. + """ + detection_vertices = self._search_tree.points_in_sphere(Vec2(center), radius) + entities = self._entities + return [entities[uid] for uid in set(v.uid for v in detection_vertices)] + + def detection_point_in_rect(self, p1: UVec, p2: UVec) -> Sequence[DXFEntity]: + """Returns all DXF entities that have at least one detection point located + inside or at the border of the rectangle defined by the two given corner points. + """ + detection_vertices = self._search_tree.points_in_bbox( + BoundingBox([Vec2(p1), Vec2(p2)]) + ) + entities = self._entities + return [entities[uid] for uid in set(v.uid for v in detection_vertices)] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__init__.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/__init__.py new file mode 100644 index 0000000..1148e7e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/__init__.py @@ -0,0 +1,161 @@ +# Copyright (c) 2015-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, TypeVar, Iterator, Any +from uuid import uuid4 +import functools +import html +from .juliandate import juliandate, calendardate +from .binarydata import hex_strings_to_bytes, bytes_to_hexstr + +escape = functools.partial(html.escape, quote=True) + + +def float2transparency(value: float) -> int: + """ + Returns DXF transparency value as integer in the range from ``0`` to ``255``, where + ``0`` is 100% transparent and ``255`` is opaque. + + Args: + value: transparency value as float in the range from ``0`` to ``1``, where ``0`` + is opaque and ``1`` is 100% transparency. + + """ + return int((1.0 - float(value)) * 255) | 0x02000000 + + +def transparency2float(value: int) -> float: + """ + Returns transparency value as float from ``0`` to ``1``, ``0`` for no transparency + (opaque) and ``1`` for 100% transparency. + + Args: + value: DXF integer transparency value, ``0`` for 100% transparency and ``255`` + for opaque + + """ + # 255 -> 0. + # 0 -> 1. + return 1.0 - float(int(value) & 0xFF) / 255.0 + + +def set_flag_state(flags: int, flag: int, state: bool = True) -> int: + """Set/clear binary `flag` in data `flags`. + + Args: + flags: data value + flag: flag to set/clear + state: ``True`` for setting, ``False`` for clearing + + """ + if state: + flags = flags | flag + else: + flags = flags & ~flag + return flags + + +def guid() -> str: + """Returns a general unique ID, based on :func:`uuid.uuid4`. + + This function creates a GUID for the header variables $VERSIONGUID and + $FINGERPRINTGUID, which matches the AutoCAD pattern + ``{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}``. + + """ + return "{" + str(uuid4()).upper() + "}" + + +T = TypeVar("T") + + +def take2(iterable: Iterable[T]) -> Iterator[tuple[T, T]]: + """Iterate `iterable` as non-overlapping pairs. + + :code:`take2('ABCDEFGH') -> AB CD EF GH` + + """ + sentinel = object() + store: Any = sentinel + for item in iterable: + if store is sentinel: + store = item + else: + yield store, item + store = sentinel + + +def pairwise(iterable: Iterable[T], close=False) -> Iterator[tuple[T, T]]: + """Iterate `iterable` as consecutive overlapping pairs. + This is similar to ``itertools.pairwise()`` in Python 3.10 but with `close` option. + + :code:`polygon_segments('ABCDEFG') -> AB BC CD DE EF FG` + :code:`polygon_segments('ABCDEFG', True) -> AB BC CD DE EF FG GA` + + """ + sentinel = object() + first: Any = sentinel + store: Any = sentinel + item: Any = sentinel + for item in iterable: + if store is sentinel: + store = item + first = item + else: + yield store, item + store = item + if close and first is not sentinel and item is not first: + yield item, first + + +def suppress_zeros(s: str, leading: bool = False, trailing: bool = True): + """Suppress trailing and/or leading ``0`` of string `s`. + + Args: + s: data string + leading: suppress leading ``0`` + trailing: suppress trailing ``0`` + + """ + # is anything to do? + if (not leading) and (not trailing): + return s + + # if `s` represents zero + if float(s) == 0.0: + return "0" + + # preserve sign + if s[0] in "-+": + sign = s[0] + s = s[1:] + else: + sign = "" + + # strip zeros + if leading: + s = s.lstrip("0") + if trailing and "." in s: + s = s.rstrip("0") + + # remove comma if no decimals follow + if s[-1] in ".,": + s = s[:-1] + + return sign + s + + +def normalize_text_angle(angle: float, fix_upside_down=True) -> float: + """ + Normalizes text `angle` to the range from 0 to 360 degrees and fixes upside down text angles. + + Args: + angle: text angle in degrees + fix_upside_down: rotate upside down text angle about 180 degree + + """ + angle = angle % 360.0 # normalize angle (0 .. 360) + if fix_upside_down and (90 < angle <= 270): # flip text orientation + angle -= 180 + angle = angle % 360.0 # normalize again + return angle diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..5c366ed Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/_iso_pattern.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/_iso_pattern.cpython-312.pyc new file mode 100644 index 0000000..49668c1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/_iso_pattern.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/analyze.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/analyze.cpython-312.pyc new file mode 100644 index 0000000..d47a976 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/analyze.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/binarydata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/binarydata.cpython-312.pyc new file mode 100644 index 0000000..8621c0f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/binarydata.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/clipping_portal.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/clipping_portal.cpython-312.pyc new file mode 100644 index 0000000..f398d8c Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/clipping_portal.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/codepage.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/codepage.cpython-312.pyc new file mode 100644 index 0000000..5b7fee2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/codepage.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/complex_ltype.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/complex_ltype.cpython-312.pyc new file mode 100644 index 0000000..92de89a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/complex_ltype.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/crypt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/crypt.cpython-312.pyc new file mode 100644 index 0000000..d7aec99 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/crypt.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/debug.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/debug.cpython-312.pyc new file mode 100644 index 0000000..987ce4d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/debug.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/difftags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/difftags.cpython-312.pyc new file mode 100644 index 0000000..4f9369b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/difftags.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/handle.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/handle.cpython-312.pyc new file mode 100644 index 0000000..5a8e270 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/handle.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/indexing.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/indexing.cpython-312.pyc new file mode 100644 index 0000000..1808d8d Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/indexing.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/juliandate.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/juliandate.cpython-312.pyc new file mode 100644 index 0000000..acc2428 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/juliandate.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/pattern.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/pattern.cpython-312.pyc new file mode 100644 index 0000000..89de9b2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/pattern.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/rawloader.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/rawloader.cpython-312.pyc new file mode 100644 index 0000000..eaa64ec Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/rawloader.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/standards.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/standards.cpython-312.pyc new file mode 100644 index 0000000..658b983 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/standards.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/strip.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/strip.cpython-312.pyc new file mode 100644 index 0000000..e947b33 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/strip.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/test.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/test.cpython-312.pyc new file mode 100644 index 0000000..d781016 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/test.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text.cpython-312.pyc new file mode 100644 index 0000000..4d77884 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_layout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_layout.cpython-312.pyc new file mode 100644 index 0000000..630b883 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_layout.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_size.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_size.cpython-312.pyc new file mode 100644 index 0000000..fd7a7c1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/text_size.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/zipmanager.cpython-312.pyc b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/zipmanager.cpython-312.pyc new file mode 100644 index 0000000..bb6e798 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/ezdxf/tools/__pycache__/zipmanager.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/_iso_pattern.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/_iso_pattern.py new file mode 100644 index 0000000..e0b45c3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/_iso_pattern.py @@ -0,0 +1,4400 @@ +# Copyright (c) 2020, Manfred Moitzi +# License: MIT License +# Scaled for $MEASUREMENT=1 (m, cm, mm, ...) +# Collected, extracted and scaled from various DXF files ... +# format: [angle, origin, offset, line_pattern] +# line_pattern: [element, element, ...] where: +# element > 0 is dash +# element == 0 is a point +# element < 0 is a gap + +ISO_PATTERN = { + "ACAD_ISO02W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0]]], + "ACAD_ISO03W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -18.0]]], + "ACAD_ISO04W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0]]], + "ACAD_ISO05W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0, 0.5, -3.0]] + ], + "ACAD_ISO06W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-34.0, 0.5, -3.0]], + ], + "ACAD_ISO07W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [0.5, -3.0]]], + "ACAD_ISO08W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 6.0, -3.0]]], + "ACAD_ISO09W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 6.0, -3.0, 6.0, -3.0]] + ], + "ACAD_ISO10W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0]]], + "ACAD_ISO11W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -3.0]] + ], + "ACAD_ISO12W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0, 0.5, -3.0]] + ], + "ACAD_ISO13W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-33.5, 0.5, -3.0]], + ], + "ACAD_ISO14W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-22.0, 0.5, -3.0]], + ], + "ACAD_ISO15W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -10.0]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-33.5, 0.5, -3.0, 0.5, -3.0]], + ], + "ANCHORLOCK": [ + [ + 18.435, + (-7.5301714395, -2.5100646395), + (50.2011354351, 25.1006237677), + [15.875, -63.5], + ], + [ + 333.435, + (-17.5703851665, -22.590536607), + (25.1005788571, 2.25052e-05), + [11.2253201325, -44.9012805935], + ], + [ + 63.435, + (-2.5100869915, 32.6307503975), + (-2.23917e-05, 25.1005789423), + [11.2253201325, -44.9012805935], + ], + [ + 108.435, + (2.5100198085, 17.5704075185), + (-2.24201e-05, 25.1005789276), + [15.875, -63.5], + ], + ], + "ANGLE": [ + [0.0, (0.0, 0.0), (0.0, 13.97), [10.16, -3.81]], + [90.0, (0.0, 0.0), (-13.97, 0.0), [10.16, -3.81]], + ], + "ANSI31": [[45.0, (0.0, 0.0), (-2.2450640303, 2.2450640303), []]], + "ANSI32": [ + [45.0, (0.0, 0.0), (-6.7351920908, 6.7351920908), []], + [45.0, (4.490128053, 0.0), (-6.7351920908, 6.7351920908), []], + ], + "ANSI33": [ + [45.0, (0.0, 0.0), (-4.4901280605, 4.4901280605), []], + [45.0, (4.490128053, 0.0), (-4.4901280605, 4.4901280605), [3.175, -1.5875]], + ], + "ANSI34": [ + [45.0, (0.0, 0.0), (-13.4703841816, 13.4703841816), []], + [45.0, (4.490128053, 0.0), (-13.4703841816, 13.4703841816), []], + [45.0, (8.9802561314, 0.0), (-13.4703841816, 13.4703841816), []], + [45.0, (13.4703841844, 0.0), (-13.4703841816, 13.4703841816), []], + ], + "ANSI35": [ + [45.0, (0.0, 0.0), (-4.4901280605, 4.4901280605), []], + [ + 45.0, + (4.490128053, 0.0), + (-4.4901280605, 4.4901280605), + [7.9375, -1.5875, 0.0, -1.5875], + ], + ], + "ANSI36": [ + [ + 45.0, + (0.0, 0.0), + (1.6837980227, 6.1739260832), + [7.9375, -1.5875, 0.0, -1.5875], + ] + ], + "ANSI37": [ + [45.0, (0.0, 0.0), (-2.2450640303, 2.2450640303), []], + [135.0, (0.0, 0.0), (-2.2450640303, -2.2450640303), []], + ], + "ANSI38": [ + [45.0, (0.0, 0.0), (-2.2450640303, 2.2450640303), []], + [135.0, (0.0, 0.0), (-6.7351920908, 2.2450640303), [7.9375, -4.7625]], + ], + "AR-B816": [ + [0.0, (0.0, 0.0), (0.0, 203.2), []], + [90.0, (0.0, 0.0), (-203.2, 203.2), [203.2, -203.2]], + ], + "AR-B816C": [ + [0.0, (0.0, 0.0), (203.2, 203.2), [396.875, -9.525]], + [0.0, (-203.2, 9.525), (203.2, 203.2), [396.875, -9.525]], + [90.0, (0.0, 0.0), (-203.2, 203.2), [-212.725, 193.675]], + [90.0, (-9.525, 0.0), (-203.2, 203.2), [-212.725, 193.675]], + ], + "AR-B88": [ + [0.0, (0.0, 0.0), (0.0, 203.2), []], + [90.0, (0.0, 0.0), (-101.6, 203.2), [203.2, -203.2]], + ], + "AR-BRELM": [ + [0.0, (0.0, 0.0), (0.0, 135.484), [193.675, -9.525]], + [0.0, (0.0, 57.15), (0.0, 135.484), [193.675, -9.525]], + [0.0, (50.8, 67.7418), (0.0, 135.484), [92.075, -9.525]], + [0.0, (50.8, 124.892), (0.0, 135.484), [92.075, -9.525]], + [90.0, (0.0, 0.0), (-203.2, 0.0), [57.15, -78.334]], + [90.0, (-9.525, 0.0), (-203.2, 0.0), [57.15, -78.334]], + [90.0, (50.8, 67.7418), (-101.6, 0.0), [57.15, -78.334]], + [90.0, (41.275, 67.7418), (-101.6, 0.0), [57.15, -78.334]], + ], + "AR-BRSTD": [ + [0.0, (0.0, 0.0), (0.0, 67.7418), []], + [90.0, (0.0, 0.0), (-101.6, 67.7418), [67.7418, -67.7418]], + ], + "AR-CONC": [ + [50.0, (0.0, 0.0), (182.184668996, -15.9390855389), [19.05, -209.55]], + [355.0, (0.0, 0.0), (-35.243421425, 191.056845239), [15.24, -167.64058417]], + [ + 100.4514447, + (15.182007, -1.3282535), + (146.9412470904, 175.1177519122), + [16.1900088, -178.0902446], + ], + [46.1842, (0.0, 50.8), (271.0790408921, -42.0423279327), [28.575, -314.325]], + [ + 96.63555761, + (22.5899, 47.2965), + (237.4041340515, 247.4261245977), + [24.28502314, -267.13560816], + ], + [ + 351.18415117, + (0.0, 50.8), + (237.404134065, 247.4261245855), + [22.85996707, -251.45973192], + ], + [21.0, (25.4, 38.1), (151.6143912691, -102.2651981871), [19.05, -209.55]], + [326.0, (25.4, 38.1), (61.8020283476, 184.1879661223), [15.24, -167.64]], + [ + 71.451445, + (38.0345326, 29.5779001), + (213.4164192787, 81.9227688859), + [16.1900088, -178.0899376], + ], + [ + 37.5, + (0.0, 0.0), + (3.0886032506, 84.5550388732), + [0.0, -165.608, 0.0, -170.18, 0.0, -168.275], + ], + [ + 7.5, + (0.0, 0.0), + (66.8196625103, 100.1805748181), + [0.0, -97.028, 0.0, -161.798, 0.0, -64.135], + ], + [ + -32.5, + (-56.642, 0.0), + (135.5905951669, -5.7287439927), + [0.0, -63.5, 0.0, -198.12, 0.0, -262.89], + ], + [ + -42.5, + (-82.042, 0.0), + (148.129181386, 25.4264910333), + [0.0, -82.55, 0.0, -131.572, 0.0, -186.69], + ], + ], + "AR-HBONE": [ + [45.0, (0.0, 0.0), (0.0, 143.6840979371), [304.8, -101.6]], + [135.0, (71.842, 71.842), (0.0, 143.6840979371), [304.8, -101.6]], + ], + "AR-PARQ1": [ + [90.0, (0.0, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (50.8, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (101.6, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (152.4, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (203.2, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (254.0, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [90.0, (304.8, 0.0), (-304.8, 304.8), [304.8, -304.8]], + [0.0, (0.0, 304.8), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 355.6), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 406.4), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 457.2), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 508.0), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 558.8), (304.8, -304.8), [304.8, -304.8]], + [0.0, (0.0, 609.6), (304.8, -304.8), [304.8, -304.8]], + ], + "AR-RROOF": [ + [0.0, (0.0, 0.0), (55.88, 25.4), [381.0, -50.8, 127.0, -25.4]], + [0.0, (33.782, 12.7), (-25.4, 33.782), [76.2, -8.382, 152.4, -19.05]], + [0.0, (12.7, 21.59), (132.08, 17.018), [203.2, -35.56, 101.6, -25.4]], + ], + "AR-RSHKE": [ + [0.0, (0.0, 0.0), (647.7, 304.8), [152.4, -127.0, 177.8, -76.2, 228.6, -101.6]], + [0.0, (152.4, 12.7), (647.7, 304.8), [127.0, -482.6, 101.6, -152.4]], + [0.0, (457.2, -19.05), (647.7, 304.8), [76.2, -787.4]], + [90.0, (0.0, 0.0), (-215.9, 304.8), [292.1, -927.1]], + [90.0, (152.4, 0.0), (-215.9, 304.8), [285.75, -933.45]], + [90.0, (279.4, 0.0), (-215.9, 304.8), [266.7, -952.5]], + [90.0, (457.2, -19.05), (-215.9, 304.8), [292.1, -927.1]], + [90.0, (533.4, -19.05), (-215.9, 304.8), [292.1, -927.1]], + [90.0, (762.0, 0.0), (-215.9, 304.8), [279.4, -939.8]], + ], + "AR-SAND": [ + [ + 37.5, + (0.0, 0.0), + (-1.600031296, 48.9413237329), + [0.0, -38.608, 0.0, -43.18, 0.0, -41.275], + ], + [ + 7.5, + (0.0, 0.0), + (44.9523283138, 71.6825100568), + [0.0, -20.828, 0.0, -34.798, 0.0, -13.335], + ], + [ + -32.5, + (-31.242, 0.0), + (79.0992370241, 0.1437184679), + [0.0, -12.7, 0.0, -45.72, 0.0, -59.69], + ], + [ + -42.5, + (-31.242, 0.0), + (76.3556452472, 22.2929323257), + [0.0, -6.35, 0.0, -29.972, 0.0, -34.29], + ], + ], + "ASPHALT": [ + [0.0, (11.8968774, 4.6476158), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-11.464417, 8.075549), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-11.5913916, -4.5570648), (0.0, 25.4), [0.0, -25.4]], + [0.0, (3.1998666, -5.128387), (0.0, 25.4), [0.0, -25.4]], + [0.0, (8.7227918, -5.3188108), (0.0, 25.4), [0.0, -25.4]], + [0.0, (1.1684508, 11.1860838), (0.0, 25.4), [0.0, -25.4]], + [0.0, (10.5002838, 11.8208806), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-2.5134824, 5.4728618), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-0.5455412, 0.3944112), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-5.1162458, -1.827403), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-7.46506, 1.3466318), (0.0, 25.4), [0.0, -25.4]], + [0.0, (7.9610204, 0.9657334), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-0.2281428, 7.8850998), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-5.1797204, 11.4400076), (0.0, 25.4), [0.0, -25.4]], + [0.0, (6.3739776, 7.5677014), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-9.6234504, 4.9650142), (0.0, 25.4), [0.0, -25.4]], + [0.0, (0.2797048, -1.6369538), (0.0, 25.4), [0.0, -25.4]], + [0.0, (6.5644268, -11.2225074), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-9.306052, -10.9050836), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-2.7039316, -8.429371), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-7.972933, -7.984998), (0.0, 25.4), [0.0, -25.4]], + [0.0, (-12.7, 12.7), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, 9.525), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, 6.35), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, 3.175), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, 0.0), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, -3.175), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, -6.35), (0.0, 25.4), [25.4, 0.0]], + [0.0, (-12.7, -9.525), (0.0, 25.4), [25.4, 0.0]], + ], + "BLOCKS": [ + [0.0, (0.0, 0.0), (0.0, 203.2), []], + [90.0, (0.0, 0.0), (-203.2, 203.2), [203.2, -203.2]], + ], + "BOARD": [ + [0.0, (0.0, 1.016), (0.0, 2.54), []], + [90.0, (0.0, 1.016), (-10.16, 10.16), [2.54, -35.56]], + [90.0, (15.24, 6.096), (-10.16, 10.16), [2.54, -35.56]], + ], + "BOX": [ + [90.0, (0.0, 0.0), (-25.4, 0.0), []], + [90.0, (6.35, 0.0), (-25.4, 0.0), []], + [0.0, (0.0, 0.0), (0.0, 25.4), [-6.35, 6.35]], + [0.0, (0.0, 6.35), (0.0, 25.4), [-6.35, 6.35]], + [0.0, (0.0, 12.7), (0.0, 25.4), [6.35, -6.35]], + [0.0, (0.0, 19.05), (0.0, 25.4), [6.35, -6.35]], + [90.0, (12.7, 0.0), (-25.4, 0.0), [6.35, -6.35]], + [90.0, (19.05, 0.0), (-25.4, 0.0), [6.35, -6.35]], + ], + "BRASS": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [0.0, (0.0, 3.175), (0.0, 6.35), [3.175, -1.5875]], + ], + "BRICK": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [90.0, (0.0, 0.0), (-12.7, 0.0), [6.35, -6.35]], + [90.0, (6.35, 0.0), (-12.7, 0.0), [-6.35, 6.35]], + ], + "BRICK_DEMOLITION": [ + [45.0, (0.0, 0.0), (-5.3881536726, 5.3881536726), [2.54, -2.54]], + [45.0, (1.796034, 0.0), (-5.3881536726, 5.3881536726), [2.54, -2.54]], + ], + "BRICK_EXISTING": [ + [45.0, (0.0, 0.0), (-7.1842048969, 7.1842048969), []], + [45.0, (3.5920934, 0.0), (-7.1842048969, 7.1842048969), []], + ], + "BRICK_FLBOND": [ + [0.0, (0.0, 0.0), (38.1, 16.9333333291), [48.41875, -27.78125]], + [0.0, (50.8, 0.0), (38.1, 16.9333333291), [23.01875, -53.18125]], + [0.0, (0.0, 14.5520833291), (38.1, 16.9333333291), [48.41875, -27.78125]], + [0.0, (50.8, 14.5520833291), (38.1, 16.9333333291), [23.01875, -53.18125]], + [90.0, (0.0, 0.0), (-38.1, 16.9333333291), [14.5520833291, -19.3145833291]], + [ + 90.0, + (48.41875, 0.0), + (-38.1, 16.9333333291), + [14.5520833291, -19.3145833291], + ], + [90.0, (50.8, 0.0), (-38.1, 16.9333333291), [14.5520833291, -19.3145833291]], + [ + 90.0, + (73.81875, 0.0), + (-38.1, 16.9333333291), + [14.5520833291, -19.3145833291], + ], + ], + "BRICK_INSULATING": [ + [45.0, (0.0, 0.0), (-6.2861792847, 6.2861792847), []], + [0.0, (0.0, 0.0), (0.0, 2.54), [0.0, -2.54]], + ], + "BRICK_LWEIGHT": [ + [45.0, (0.0, 0.0), (-6.2861792847, 6.2861792847), []], + [0.0, (0.0, 0.0), (0.79375, 1.5875), [0.0, -1.5875]], + ], + "BRICK_PAIRS": [ + [ + 0.0, + (0.0, 0.0), + (50.8, 50.8), + [48.41875, -2.38125, 23.01875, -2.38125, 23.01875, -2.38125], + ], + [0.0, (0.0, 23.01875), (50.8, 50.8), [48.41875, -53.18125]], + [0.0, (0.0, 25.4), (50.8, 50.8), [48.41875, -53.18125]], + [ + 0.0, + (0.0, 48.41875), + (50.8, 50.8), + [48.41875, -2.38125, 23.01875, -2.38125, 23.01875, -2.38125], + ], + [ + 90.0, + (0.0, 0.0), + (-50.8, 50.8), + [23.01875, -2.38125, 23.01875, -2.38125, 48.41875, -2.38125], + ], + [90.0, (23.01875, 50.8), (-50.8, 50.8), [48.41875, -53.18125]], + [90.0, (25.4, 50.8), (-50.8, 50.8), [48.41875, -53.18125]], + [ + 90.0, + (48.41875, 0.0), + (-50.8, 50.8), + [23.01875, -2.38125, 23.01875, -2.38125, 48.41875, -2.38125], + ], + ], + "BRICK_STBOND": [ + [0.0, (0.0, 0.0), (0.0, 25.4), []], + [90.0, (0.0, 0.0), (-50.8, 0.0), []], + ], + "BRICK_STRBOND": [ + [0.0, (0.0, 0.0), (0.0, 50.8), []], + [90.0, (0.0, 0.0), (-101.6, 50.8), [50.8, -50.8]], + ], + "BRSTONE": [ + [0.0, (0.0, 0.0), (0.0, 8.382), []], + [90.0, (22.86, 0.0), (-12.7, 8.382), [8.382, -8.382]], + [90.0, (20.32, 0.0), (-12.7, 8.382), [8.382, -8.382]], + [0.0, (22.86, 1.397), (12.7, 8.382), [-22.86, 2.54]], + [0.0, (22.86, 2.794), (12.7, 8.382), [-22.86, 2.54]], + [0.0, (22.86, 4.191), (12.7, 8.382), [-22.86, 2.54]], + [0.0, (22.86, 5.588), (12.7, 8.382), [-22.86, 2.54]], + [0.0, (22.86, 6.985), (12.7, 8.382), [-22.86, 2.54]], + ], + "BUTTERFLY": [ + [0.0, (-6.35, 0.0), (19.05, 19.05), [12.7, -25.4]], + [0.0, (12.7, 6.35), (19.05, 19.05), [12.7, -25.4]], + [90.0, (0.0, 0.0), (-19.05, 19.05), [25.4, -12.7]], + [ + 45.0, + (6.35, 0.0), + (-19.0500000129, 19.0500000129), + [8.980256106, -17.960512212], + ], + [ + 135.0, + (-6.35, 0.0), + (-19.0500000129, -19.0500000129), + [8.980256106, -17.960512212], + ], + ], + "CHECKER": [ + [0.0, (0.0, 0.0), (12.7, 12.7), [12.7, -12.7]], + [90.0, (6.35, 6.35), (-12.7, 12.7), [12.7, -12.7]], + ], + "CLAY": [ + [0.0, (0.0, 0.0), (0.0, 4.7625), []], + [0.0, (0.0, 0.79375), (0.0, 4.7625), []], + [0.0, (0.0, 1.5875), (0.0, 4.7625), []], + [0.0, (0.0, 3.175), (0.0, 4.7625), [4.7625, -3.175]], + ], + "CONCRETE1": [ + [0.0, (0.0, 0.0), (20.32, 20.32), [2.54, -17.78]], + [90.0, (0.0, 0.0), (-20.32, 20.32), [2.54, -17.78]], + [135.0, (2.54, 0.0), (-20.3199999659, 0.0), [3.592102544, -25.144717808]], + [0.0, (2.54, 11.43), (20.32, 20.32), [2.54, -17.78]], + [45.0, (3.81, 10.16), (0.0, 20.3199999659), [1.796050256, -26.940768064]], + [135.0, (3.81, 10.16), (-20.3199999659, 0.0), [1.796050256, -26.940768064]], + [0.0, (10.16, 16.51), (20.32, 20.32), [3.592102544, -16.727897456]], + [45.0, (10.16, 16.51), (0.0, 20.3199999659), [2.54, -26.196820352]], + [135.0, (13.752102544, 16.51), (-20.3199999659, 0.0), [2.54, -26.196820352]], + [90.0, (13.97, 5.08), (-20.32, 20.32), [2.54, -17.78]], + [45.0, (13.97, 5.08), (0.0, 20.3199999659), [1.796050256, -26.940768064]], + [135.0, (15.24, 6.35), (-20.3199999659, 0.0), [1.796050256, -26.940768064]], + [0.0, (2.54, 5.08), (20.32, 20.32), [1.27, -17.018]], + [0.0, (17.78, 10.16), (20.32, 20.32), [1.27, -17.018]], + [90.0, (11.43, 12.7), (-20.32, 20.32), [1.27, -17.018]], + [135.0, (13.97, 1.27), (-20.3199999659, 0.0), [1.796050256, -26.940768064]], + [135.0, (5.08, 15.24), (-20.3199999659, 0.0), [1.796050256, -26.940768064]], + [45.0, (9.525, 6.6675), (0.0, 20.3199999659), [1.796050256, -26.940768064]], + [90.0, (6.985, 2.54), (-20.32, 20.32), [0.3175, -20.0025]], + [90.0, (7.9375, 11.1125), (-20.32, 20.32), [0.3175, -20.0025]], + [90.0, (17.4625, 14.605), (-20.32, 20.32), [0.3175, -20.0025]], + [90.0, (17.78, 3.81), (-20.32, 20.32), [0.3175, -20.0025]], + ], + "CONCRETE2": [ + [50.0, (0.0, 0.0), (14.5747269104, -1.2751233828), [1.524, -16.764]], + [355.0, (0.0, 0.0), (-2.819427099, 15.2845441568), [1.2192, -13.4112]], + [ + 100.4514, + (1.2145605376, -0.1062601888), + (11.7553106364, 14.0094114947), + [1.2952006608, -14.2472077158], + ], + [46.1842, (0.0, 4.064), (21.6863381081, -3.3633463712), [2.286, -25.146]], + [ + 96.6356, + (1.8071946584, 3.7837200018), + (18.9923461767, 19.7940751367), + [1.9428010522, -21.37080816], + ], + [351.1842, (0.0, 4.064), (18.9923307251, 19.7940899708), [1.8288, -20.1168]], + [21.0, (2.032, 3.048), (12.129151299, -8.1812158583), [1.524, -16.764]], + [326.0, (2.032, 3.048), (4.9441675446, 14.7350489154), [1.2192, -13.4112]], + [ + 71.4514, + (3.0427621746, 2.3662313661), + (17.0733238128, 6.5538196931), + [1.2952006608, -14.2472077158], + ], + [ + 37.5, + (0.0, 0.0), + (0.24708826, 6.7644031099), + [0.0, -13.24864, 0.0, -13.6144, 0.0, -13.462], + ], + [ + 7.5, + (0.0, 0.0), + (5.3455730008, 8.0144459854), + [0.0, -7.76224, 0.0, -12.94384, 0.0, -5.1308], + ], + [ + -32.5, + (-4.53136, 0.0), + (10.847271903, -0.4583149936), + [0.0, -5.08, 0.0, -15.8496, 0.0, -21.0312], + ], + [ + -42.5, + (-6.56336, 0.0), + (11.850342961, 2.034133241), + [0.0, -6.604, 0.0, -10.52576, 0.0, -14.9352], + ], + ], + "CONCRETE3": [ + [ + 82.88, + (97.10721498, 59.2083144), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 97.13, + (97.10660538, 59.2448904), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 116.57, + (97.09453022, 59.29154258), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 135.0, + (97.06356, 59.33695778), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 172.88, + (97.01943258, 59.3792564), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 172.88, + (96.9621632, 59.3875368), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 187.13, + (96.92463978, 59.38655382), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 225.0, + (96.8702152, 59.3801708), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 243.44, + (96.82142942, 59.3422232), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 262.88, + (96.79022298, 59.29440262), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 262.88, + (96.78295858, 59.2425536), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 277.13, + (96.78366978, 59.20499462), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 296.57, + (96.79555698, 59.1593432), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 315.0, + (96.8265272, 59.11391022), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 352.88, + (96.87065462, 59.07162938), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 7.13, + (96.96544742, 59.0642964), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 45.0, + (97.0198212, 59.07066418), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 63.44, + (97.06865778, 59.1086448), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 82.88, + (97.09986422, 59.15646538), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 82.88, + (87.67045458, 53.3422352), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 97.13, + (87.66984498, 53.37879342), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 116.57, + (87.65776982, 53.4254456), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 135.0, + (87.6267996, 53.47087858), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 172.88, + (87.58267218, 53.51315942), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 172.88, + (87.5254028, 53.52143982), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 187.13, + (87.48787938, 53.52045938), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 225.0, + (87.4334548, 53.51407382), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 243.44, + (87.38466902, 53.47612622), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 262.88, + (87.35346258, 53.42830818), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 262.88, + (87.34619818, 53.37645662), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 277.13, + (87.34690938, 53.33890018), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 296.57, + (87.35879658, 53.29324622), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 315.0, + (87.3897668, 53.24781578), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 352.88, + (87.43389422, 53.2055324), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 7.13, + (87.52868702, 53.19819942), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 45.0, + (87.5830608, 53.2045672), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 63.44, + (87.63189738, 53.24254782), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 82.88, + (87.66310382, 53.29038618), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 82.88, + (93.68222818, 52.93331298), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 63.44, + (93.6510192, 52.8854924), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 45.0, + (93.60218262, 52.847494), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 7.13, + (93.54781138, 52.84112622), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 352.88, + (93.45301858, 52.84847698), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 315.0, + (93.40888862, 52.89075782), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 296.57, + (93.3779184, 52.93617302), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 277.13, + (93.3660312, 52.98182698), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 262.88, + (93.36532, 53.01938342), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 262.88, + (93.3725844, 53.07125022), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 243.44, + (93.40379338, 53.1190708), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 225.0, + (93.45257662, 53.15700062), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 187.13, + (93.5070012, 53.16340142), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 172.88, + (93.54452462, 53.16436662), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 172.88, + (93.601794, 53.15608622), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 135.0, + (93.64592142, 53.11380538), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 116.57, + (93.67689418, 53.0683724), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 97.13, + (93.6889668, 53.02172022), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 82.88, + (93.6895764, 52.985162), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 82.88, + (89.09138138, 65.02255982), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 63.44, + (89.06015462, 64.97474178), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 45.0, + (89.01132058, 64.93675862), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 7.13, + (88.95696458, 64.93039338), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 352.88, + (88.862154, 64.93772382), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 315.0, + (88.81802658, 64.9800072), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 296.57, + (88.78705382, 65.0254224), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 277.13, + (88.7751844, 65.07107382), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 262.88, + (88.77445542, 65.10865058), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 262.88, + (88.78171982, 65.1604996), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 243.44, + (88.81294658, 65.20832018), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 225.0, + (88.86171458, 65.24626778), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 187.13, + (88.9161544, 65.2526508), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 172.88, + (88.95366258, 65.253616), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 172.88, + (89.0109472, 65.2453356), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 135.0, + (89.05507462, 65.20305222), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 116.57, + (89.08604738, 65.15763702), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 97.13, + (89.09810222, 65.11098738), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 82.88, + (89.0987296, 65.07441138), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 82.88, + (88.11877982, 63.97348902), + (-0.0008534187, 16.9336313627), + [0.15551658, -136.3660976], + ], + [ + 97.13, + (88.11622458, 64.12612778), + (-16.9431028479, 118.5322702695), + [0.20597622, -136.31563542], + ], + [ + 116.57, + (88.06583098, 64.32089498), + (-16.9342802744, 16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 135.0, + (87.93656022, 64.51053138), + (-16.9331709419, 0.0), + [0.24807418, -23.69904582], + ], + [ + 172.88, + (87.75230862, 64.6870436), + (-118.5352255934, 16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 172.88, + (87.51319302, 64.72162062), + (-118.5352255934, 16.9224148061), + [0.16085058, -136.3607636], + ], + [ + 187.13, + (87.35657662, 64.71755662), + (-118.5322702695, -16.9431028479), + [0.21959062, -136.30202102], + ], + [ + 225.0, + (87.12934822, 64.69088662), + (-0.0, -16.9331709419), + [0.25350978, -23.69361022], + ], + [ + 243.44, + (86.92572658, 64.53249222), + (0.0014916558, -16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 262.88, + (86.79542458, 64.33284822), + (0.0008534187, -16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 262.88, + (86.76506142, 64.11637418), + (0.0008534187, -16.9336313627), + [0.16085058, -136.3607636], + ], + [ + 277.13, + (86.7680764, 63.95955458), + (16.9431028479, -118.5322702695), + [0.20170902, -136.31990262], + ], + [ + 296.57, + (86.81769022, 63.768986), + (16.9342802744, -16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 315.0, + (86.94696098, 63.5793496), + (16.9331709419, -0.0), + [0.24807418, -23.69904582], + ], + [ + 352.88, + (87.13121258, 63.4028196), + (118.5352255934, -16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 7.13, + (87.52695982, 63.37220498), + (118.5322702695, 16.9431028479), + [0.21760942, -136.30400222], + ], + [ + 45.0, + (87.75393422, 63.39877338), + (0.0, 16.9331709419), + [0.2538476, -23.6932724], + ], + [ + 63.44, + (87.95779462, 63.55737098), + (-0.0014916558, 16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 82.88, + (88.0881144, 63.75701498), + (-0.0008534187, 16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 82.88, + (87.3229648, 65.74639378), + (-0.0008534187, 16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 63.44, + (87.1926628, 65.54674978), + (-0.0014916558, 16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 45.0, + (86.98878462, 65.38815218), + (0.0, 16.9331709419), + [0.2538476, -23.6932724], + ], + [ + 7.13, + (86.76181022, 65.361566), + (118.5322702695, 16.9431028479), + [0.21760942, -136.30400222], + ], + [ + 352.88, + (86.36606298, 65.3921984), + (118.5352255934, -16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 315.0, + (86.18182662, 65.56871062), + (16.9331709419, -0.0), + [0.24807418, -23.69904582], + ], + [ + 296.57, + (86.05254062, 65.75834702), + (16.9342802744, -16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 277.13, + (86.00294458, 65.94893338), + (16.9431028479, -118.5322702695), + [0.20170902, -136.31990262], + ], + [ + 262.88, + (85.9999296, 66.1057352), + (0.0008534187, -16.9336313627), + [0.16085058, -136.3607636], + ], + [ + 262.88, + (86.03027498, 66.32222702), + (0.0008534187, -16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 243.44, + (86.16057698, 66.52187102), + (0.0014916558, -16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 225.0, + (86.36419862, 66.68025018), + (-0.0, -16.9331709419), + [0.25350978, -23.69361022], + ], + [ + 187.13, + (86.5914448, 66.70692018), + (-118.5322702695, -16.9431028479), + [0.21959062, -136.30202102], + ], + [ + 172.88, + (86.7480612, 66.71099942), + (-118.5352255934, 16.9224148061), + [0.16085058, -136.3607636], + ], + [ + 172.88, + (86.9871768, 66.6764224), + (-118.5352255934, 16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 135.0, + (87.17141062, 66.4998924), + (-16.9331709419, 0.0), + [0.24807418, -23.69904582], + ], + [ + 116.57, + (87.30069662, 66.310256), + (-16.9342802744, 16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 97.13, + (87.35107498, 66.1154888), + (-16.9431028479, 118.5322702695), + [0.20597622, -136.31563542], + ], + [ + 82.88, + (87.353648, 65.96285258), + (-0.0008534187, 16.9336313627), + [0.15551658, -136.3660976], + ], + [ + 82.88, + (94.74125578, 62.99714858), + (-0.0008534187, 16.9336313627), + [0.52391818, -135.997696], + ], + [ + 63.44, + (94.43093382, 62.52167582), + (-0.0014916558, 16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 45.0, + (93.94542298, 62.14397782), + (0.0, 16.9331709419), + [0.60453778, -23.34258222], + ], + [ + 7.13, + (93.40487542, 62.08068102), + (118.5322702695, 16.9431028479), + [0.51824382, -136.00336782], + ], + [ + 352.88, + (92.46236778, 62.15361458), + (118.5352255934, -16.9224148061), + [0.578866, -135.94274818], + ], + [ + 315.0, + (92.0235904, 62.5740176), + (16.9331709419, -0.0), + [0.59077098, -23.35634902], + ], + [ + 296.57, + (91.71570938, 63.0256296), + (16.9342802744, -16.9313563251), + [0.559816, -37.30480982], + ], + [ + 277.13, + (91.5975816, 63.47950982), + (16.9431028479, -118.5322702695), + [0.4803648, -136.04124938], + ], + [ + 262.88, + (91.59040102, 63.85294062), + (0.0008534187, -16.9336313627), + [0.38306502, -136.13854662], + ], + [ + 262.88, + (91.66267418, 64.36850982), + (0.0008534187, -16.9336313627), + [0.52391818, -135.997696], + ], + [ + 243.44, + (91.97301138, 64.84398258), + (0.0014916558, -16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 225.0, + (92.4579304, 65.22117258), + (-0.0, -16.9331709419), + [0.603758, -23.343362], + ], + [ + 187.13, + (92.99912058, 65.28468782), + (-118.5322702695, -16.9431028479), + [0.52296822, -135.99864342], + ], + [ + 172.88, + (93.37209418, 65.29439062), + (-118.5352255934, 16.9224148061), + [0.38306502, -136.13854662], + ], + [ + 172.88, + (93.94156218, 65.21204382), + (-118.5352255934, 16.9224148061), + [0.578866, -135.94274818], + ], + [ + 135.0, + (94.38033702, 64.7916408), + (-16.9331709419, 0.0), + [0.59077098, -23.35634902], + ], + [ + 116.57, + (94.68822058, 64.3400288), + (-16.9342802744, 16.9313563251), + [0.559816, -37.30480982], + ], + [ + 97.13, + (94.80822542, 63.876174), + (-16.9431028479, 118.5322702695), + [0.49054258, -136.0310716], + ], + [ + 82.88, + (94.81432142, 63.51266698), + (-0.0008534187, 16.9336313627), + [0.37036502, -136.15124662], + ], + [ + 82.88, + (99.5581956, 54.0248856), + (-0.0008534187, 16.9336313627), + [0.37036502, -136.15124662], + ], + [ + 97.13, + (99.5520996, 54.3884104), + (-16.9431028479, 118.5322702695), + [0.49054258, -136.0310716], + ], + [ + 116.57, + (99.43211, 54.8522652), + (-16.9342802744, 16.9313563251), + [0.559816, -37.30480982], + ], + [ + 135.0, + (99.12422898, 55.3038772), + (-16.9331709419, 0.0), + [0.59077098, -23.35634902], + ], + [ + 172.88, + (98.6854516, 55.72428022), + (-118.5352255934, 16.9224148061), + [0.578866, -135.94274818], + ], + [ + 172.88, + (98.1159836, 55.80661178), + (-118.5352255934, 16.9224148061), + [0.38306502, -136.13854662], + ], + [ + 187.13, + (97.74301, 55.79692422), + (-118.5322702695, -16.9431028479), + [0.52296822, -135.99864342], + ], + [ + 225.0, + (97.20181982, 55.73340898), + (-0.0, -16.9331709419), + [0.603758, -23.343362], + ], + [ + 243.44, + (96.7169008, 55.3562012), + (0.0014916558, -16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 262.88, + (96.4065636, 54.88073098), + (0.0008534187, -16.9336313627), + [0.52391818, -135.997696], + ], + [ + 262.88, + (96.33429298, 54.36517702), + (0.0008534187, -16.9336313627), + [0.38306502, -136.13854662], + ], + [ + 277.13, + (96.34147102, 53.99174622), + (16.9431028479, -118.5322702695), + [0.4803648, -136.04124938], + ], + [ + 296.57, + (96.4595988, 53.53784822), + (16.9342802744, -16.9313563251), + [0.559816, -37.30480982], + ], + [ + 315.0, + (96.76747982, 53.08623622), + (16.9331709419, -0.0), + [0.59077098, -23.35634902], + ], + [ + 352.88, + (97.2062572, 52.6658332), + (118.5352255934, -16.9224148061), + [0.578866, -135.94274818], + ], + [ + 7.13, + (98.1487496, 52.59291742), + (118.5322702695, 16.9431028479), + [0.51824382, -136.00336782], + ], + [ + 45.0, + (98.68929462, 52.65619898), + (0.0, 16.9331709419), + [0.60453778, -23.34258222], + ], + [ + 63.44, + (99.174808, 53.03391222), + (-0.0014916558, 16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 82.88, + (99.4851452, 53.50938498), + (-0.0008534187, 16.9336313627), + [0.52391818, -135.997696], + ], + [ + 82.88, + (100.58544018, 60.18634902), + (-0.0008534187, 16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 63.44, + (100.4551204, 59.98670502), + (-0.0014916558, 16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 45.0, + (100.25126, 59.82810742), + (0.0, 16.9331709419), + [0.2538476, -23.6932724], + ], + [ + 7.13, + (100.0242856, 59.80153902), + (118.5322702695, 16.9431028479), + [0.21760942, -136.30400222], + ], + [ + 352.88, + (99.62853582, 59.83215618), + (118.5352255934, -16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 315.0, + (99.444302, 60.00868618), + (16.9331709419, -0.0), + [0.24807418, -23.69904582], + ], + [ + 296.57, + (99.315016, 60.1983048), + (16.9342802744, -16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 277.13, + (99.26541742, 60.38888862), + (16.9431028479, -118.5322702695), + [0.20170902, -136.31990262], + ], + [ + 262.88, + (99.26240498, 60.54570822), + (0.0008534187, -16.9336313627), + [0.16085058, -136.3607636], + ], + [ + 262.88, + (99.29274782, 60.7621848), + (0.0008534187, -16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 243.44, + (99.42304982, 60.9618288), + (0.0014916558, -16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 225.0, + (99.626674, 61.1202232), + (-0.0, -16.9331709419), + [0.25350978, -23.69361022], + ], + [ + 187.13, + (99.85392018, 61.1468932), + (-118.5322702695, -16.9431028479), + [0.21959062, -136.30202102], + ], + [ + 172.88, + (100.01053658, 61.1509572), + (-118.5352255934, 16.9224148061), + [0.16085058, -136.3607636], + ], + [ + 172.88, + (100.24965218, 61.11638018), + (-118.5352255934, 16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 135.0, + (100.433886, 60.93986542), + (-16.9331709419, 0.0), + [0.24807418, -23.69904582], + ], + [ + 116.57, + (100.563172, 60.75022902), + (-16.9342802744, 16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 97.13, + (100.61354782, 60.55544658), + (-16.9431028479, 118.5322702695), + [0.20597622, -136.31563542], + ], + [ + 82.88, + (100.6161056, 60.40280782), + (-0.0008534187, 16.9336313627), + [0.15551658, -136.3660976], + ], + [ + 82.88, + (97.50794062, 65.78770942), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 63.44, + (97.47673418, 65.73989138), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 45.0, + (97.4278976, 65.70189298), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 7.13, + (97.37352382, 65.6955252), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 352.88, + (97.27873102, 65.70285818), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 315.0, + (97.2346036, 65.7451568), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 296.57, + (97.20363338, 65.790572), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 277.13, + (97.19174618, 65.83622342), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 262.88, + (97.19103498, 65.8737824), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 262.88, + (97.19829938, 65.9256492), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 243.44, + (97.22950582, 65.97346978), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 225.0, + (97.2782916, 66.0113996), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 187.13, + (97.33271618, 66.01778262), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 172.88, + (97.3702396, 66.0187656), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 172.88, + (97.42750898, 66.0104852), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 135.0, + (97.4716364, 65.96820182), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 116.57, + (97.50260662, 65.92277138), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 97.13, + (97.51468178, 65.8761192), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 82.88, + (97.51529138, 65.83956098), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 82.88, + (98.2182948, 64.2727696), + (-0.0008534187, 16.9336313627), + [0.15922498, -136.3623892], + ], + [ + 63.44, + (98.12399222, 64.12827662), + (-0.0014916558, 16.9328188651), + [0.16943578, -37.69519258], + ], + [ + 45.0, + (97.97641822, 64.01346862), + (0.0, 16.9331709419), + [0.18372582, -23.76339418], + ], + [ + 7.13, + (97.8121488, 63.99425098), + (118.5322702695, 16.9431028479), + [0.15749778, -136.3641164], + ], + [ + 352.88, + (97.52570538, 64.01639978), + (118.5352255934, -16.9224148061), + [0.17593818, -136.345676], + ], + [ + 315.0, + (97.3923376, 64.14417702), + (16.9331709419, -0.0), + [0.17954498, -23.76757502], + ], + [ + 296.57, + (97.298764, 64.28142338), + (16.9342802744, -16.9313563251), + [0.17014698, -37.69448138], + ], + [ + 277.13, + (97.26286618, 64.4193784), + (16.9431028479, -118.5322702695), + [0.1459992, -136.37561498], + ], + [ + 262.88, + (97.26069702, 64.5328656), + (0.0008534187, -16.9336313627), + [0.11641582, -136.40519582], + ], + [ + 262.88, + (97.2826604, 64.68956582), + (0.0008534187, -16.9336313627), + [0.15922498, -136.3623892], + ], + [ + 243.44, + (97.37697822, 64.8340588), + (0.0014916558, -16.9328188651), + [0.16943578, -37.69519258], + ], + [ + 225.0, + (97.52434902, 64.94869662), + (-0.0, -16.9331709419), + [0.1834896, -23.7636304], + ], + [ + 187.13, + (97.68882418, 64.96800062), + (-118.5322702695, -16.9431028479), + [0.15893542, -136.36267622], + ], + [ + 172.88, + (97.80217422, 64.9709648), + (-118.5352255934, 16.9224148061), + [0.11641582, -136.40519582], + ], + [ + 172.88, + (97.97524982, 64.94593818), + (-118.5352255934, 16.9224148061), + [0.17593818, -136.345676], + ], + [ + 135.0, + (98.1086176, 64.8181584), + (-16.9331709419, 0.0), + [0.17954498, -23.76757502], + ], + [ + 116.57, + (98.2021912, 64.68091458), + (-16.9342802744, 16.9313563251), + [0.17014698, -37.69448138], + ], + [ + 97.13, + (98.23864782, 64.5399268), + (-16.9431028479, 118.5322702695), + [0.14908022, -136.37253142], + ], + [ + 82.88, + (98.24051218, 64.42945458), + (-0.0008534187, 16.9336313627), + [0.11255502, -136.40905662], + ], + [ + 82.88, + (94.03588, 58.51547098), + (-0.0008534187, 16.9336313627), + [0.15551658, -136.3660976], + ], + [ + 97.13, + (94.03332222, 58.6681072), + (-16.9431028479, 118.5322702695), + [0.20597622, -136.31563542], + ], + [ + 116.57, + (93.9829464, 58.8628744), + (-16.9342802744, 16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 135.0, + (93.8536604, 59.0525108), + (-16.9331709419, 0.0), + [0.24807418, -23.69904582], + ], + [ + 172.88, + (93.66942658, 59.2290408), + (-118.5352255934, 16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 172.88, + (93.4302932, 59.26360258), + (-118.5352255934, 16.9224148061), + [0.16085058, -136.3607636], + ], + [ + 187.13, + (93.27369458, 59.25953858), + (-118.5322702695, -16.9431028479), + [0.21959062, -136.30202102], + ], + [ + 225.0, + (93.0464484, 59.23286858), + (-0.0, -16.9331709419), + [0.25350978, -23.69361022], + ], + [ + 243.44, + (92.84282422, 59.07447418), + (0.0014916558, -16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 262.88, + (92.71252222, 58.87483018), + (0.0008534187, -16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 262.88, + (92.68217938, 58.6583536), + (0.0008534187, -16.9336313627), + [0.16085058, -136.3607636], + ], + [ + 277.13, + (92.68519182, 58.50155178), + (16.9431028479, -118.5322702695), + [0.20170902, -136.31990262], + ], + [ + 296.57, + (92.7347904, 58.31096542), + (16.9342802744, -16.9313563251), + [0.23506938, -37.62955898], + ], + [ + 315.0, + (92.86405862, 58.12132902), + (16.9331709419, -0.0), + [0.24807418, -23.69904582], + ], + [ + 352.88, + (93.04831022, 57.94479902), + (118.5352255934, -16.9224148061), + [0.24306022, -136.27855142], + ], + [ + 7.13, + (93.44406, 57.9141844), + (118.5322702695, 16.9431028479), + [0.21760942, -136.30400222], + ], + [ + 45.0, + (93.6710344, 57.9407528), + (0.0, 16.9331709419), + [0.2538476, -23.6932724], + ], + [ + 63.44, + (93.8748948, 58.0993504), + (-0.0014916558, 16.9328188651), + [0.23410418, -37.63052418], + ], + [ + 82.88, + (94.00521458, 58.29901218), + (-0.0008534187, 16.9336313627), + [0.21999702, -136.30161462], + ], + [ + 82.88, + (90.7421096, 59.22648302), + (-0.0008534187, 16.9336313627), + [0.11255502, -136.40905662], + ], + [ + 97.13, + (90.74024778, 59.33695778), + (-16.9431028479, 118.5322702695), + [0.14908022, -136.37253142], + ], + [ + 116.57, + (90.70378862, 59.47794302), + (-16.9342802744, 16.9313563251), + [0.17014698, -37.69448138], + ], + [ + 135.0, + (90.61021502, 59.61518938), + (-16.9331709419, 0.0), + [0.17954498, -23.76757502], + ], + [ + 172.88, + (90.47686502, 59.74296662), + (-118.5352255934, 16.9224148061), + [0.17593818, -136.345676], + ], + [ + 172.88, + (90.30378942, 59.767978), + (-118.5352255934, 16.9224148061), + [0.11641582, -136.40519582], + ], + [ + 187.13, + (90.1904216, 59.7650316), + (-118.5322702695, -16.9431028479), + [0.15893542, -136.36267622], + ], + [ + 225.0, + (90.02594898, 59.7457276), + (-0.0, -16.9331709419), + [0.1834896, -23.7636304], + ], + [ + 243.44, + (89.87857818, 59.63108978), + (0.0014916558, -16.9328188651), + [0.16943578, -37.69519258], + ], + [ + 262.88, + (89.78425782, 59.4865968), + (0.0008534187, -16.9336313627), + [0.15922498, -136.3623892], + ], + [ + 262.88, + (89.76229698, 59.32989658), + (0.0008534187, -16.9336313627), + [0.11641582, -136.40519582], + ], + [ + 277.13, + (89.7644636, 59.21640938), + (16.9431028479, -118.5322702695), + [0.1459992, -136.37561498], + ], + [ + 296.57, + (89.8003792, 59.07845182), + (16.9342802744, -16.9313563251), + [0.17014698, -37.69448138], + ], + [ + 315.0, + (89.8939528, 58.941208), + (16.9331709419, -0.0), + [0.17954498, -23.76757502], + ], + [ + 352.88, + (90.0273028, 58.81342822), + (118.5352255934, -16.9224148061), + [0.17593818, -136.345676], + ], + [ + 7.13, + (90.31374622, 58.79126418), + (118.5322702695, 16.9431028479), + [0.15749778, -136.3641164], + ], + [ + 45.0, + (90.47803342, 58.8104996), + (0.0, 16.9331709419), + [0.18372582, -23.76339418], + ], + [ + 63.44, + (90.62559218, 58.9253076), + (-0.0014916558, 16.9328188651), + [0.16943578, -37.69519258], + ], + [ + 82.88, + (90.71991, 59.06980058), + (-0.0008534187, 16.9336313627), + [0.15922498, -136.3623892], + ], + [ + 82.88, + (88.04749218, 58.09938342), + (-0.0008534187, 16.9336313627), + [0.21413978, -136.3074744], + ], + [ + 97.13, + (88.0439692, 58.30954302), + (-16.9431028479, 118.5322702695), + [0.28359862, -136.23801302], + ], + [ + 116.57, + (87.97459418, 58.57771622), + (-16.9342802744, 16.9313563251), + [0.32366458, -37.54096378], + ], + [ + 135.0, + (87.79659098, 58.83882822), + (-16.9331709419, 0.0), + [0.34156142, -23.60555858], + ], + [ + 172.88, + (87.54291102, 59.0818732), + (-118.5352255934, 16.9224148061), + [0.3346704, -136.18694378], + ], + [ + 172.88, + (87.21367622, 59.12949058), + (-118.5352255934, 16.9224148061), + [0.22147022, -136.30014142], + ], + [ + 187.13, + (86.998048, 59.1238848), + (-118.5322702695, -16.9431028479), + [0.3023616, -136.21925258], + ], + [ + 225.0, + (86.68515302, 59.0871564), + (-0.0, -16.9331709419), + [0.34906458, -23.59805542], + ], + [ + 243.44, + (86.40478782, 58.869072), + (0.0014916558, -16.9328188651), + [0.322326, -37.54229982], + ], + [ + 262.88, + (86.22538, 58.59417542), + (0.0008534187, -16.9336313627), + [0.30290262, -136.21870902], + ], + [ + 262.88, + (86.18358938, 58.29611658), + (0.0008534187, -16.9336313627), + [0.22147022, -136.30014142], + ], + [ + 277.13, + (86.1877372, 58.08021658), + (16.9431028479, -118.5322702695), + [0.2777236, -136.24389058], + ], + [ + 296.57, + (86.25603018, 57.81779902), + (16.9342802744, -16.9313563251), + [0.32366458, -37.54096378], + ], + [ + 315.0, + (86.43403338, 57.5567048), + (16.9331709419, -0.0), + [0.34156142, -23.60555858], + ], + [ + 352.88, + (86.6877108, 57.31364458), + (118.5352255934, -16.9224148061), + [0.3346704, -136.18694378], + ], + [ + 7.13, + (87.23262462, 57.27148058), + (118.5322702695, 16.9431028479), + [0.2996184, -136.22199578], + ], + [ + 45.0, + (87.54514622, 57.30807182), + (0.0, 16.9331709419), + [0.349504, -23.597616], + ], + [ + 63.44, + (87.825834, 57.52644578), + (-0.0014916558, 16.9328188651), + [0.322326, -37.54229982], + ], + [ + 82.88, + (88.0052596, 57.80133982), + (-0.0008534187, 16.9336313627), + [0.30290262, -136.21870902], + ], + [ + 82.88, + (90.0168888, 60.63658942), + (-0.0008534187, 16.9336313627), + [0.03725418, -136.48436], + ], + [ + 97.13, + (90.0162792, 60.67315018), + (-16.9431028479, 118.5322702695), + [0.04934458, -136.4722696], + ], + [ + 116.57, + (90.00420658, 60.71979982), + (-16.9342802744, 16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 135.0, + (89.9732516, 60.7652328), + (-16.9331709419, 0.0), + [0.05941822, -23.88770178], + ], + [ + 172.88, + (89.9291064, 60.80751618), + (-118.5352255934, 16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 172.88, + (89.87183702, 60.81579658), + (-118.5352255934, 16.9224148061), + [0.03852418, -136.48309], + ], + [ + 187.13, + (89.8343136, 60.8148136), + (-118.5322702695, -16.9431028479), + [0.05259578, -136.4690184], + ], + [ + 225.0, + (89.77988902, 60.80843058), + (-0.0, -16.9331709419), + [0.06072378, -23.88639622], + ], + [ + 243.44, + (89.73110578, 60.77049822), + (0.0014916558, -16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 262.88, + (89.6998968, 60.7226624), + (0.0008534187, -16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 262.88, + (89.6926324, 60.67081338), + (0.0008534187, -16.9336313627), + [0.03852418, -136.48309], + ], + [ + 277.13, + (89.6933436, 60.6332544), + (16.9431028479, -118.5322702695), + [0.0483108, -136.47330338], + ], + [ + 296.57, + (89.7052308, 60.58760298), + (16.9342802744, -16.9313563251), + [0.05630418, -37.80832418], + ], + [ + 315.0, + (89.73620102, 60.54218778), + (16.9331709419, -0.0), + [0.05941822, -23.88770178], + ], + [ + 352.88, + (89.78033098, 60.49988662), + (118.5352255934, -16.9224148061), + [0.0582168, -136.46339738], + ], + [ + 7.13, + (89.87512378, 60.49255618), + (118.5322702695, 16.9431028479), + [0.0521208, -136.46949338], + ], + [ + 45.0, + (89.92949502, 60.49892142), + (0.0, 16.9331709419), + [0.0608076, -23.8863124], + ], + [ + 63.44, + (89.9783316, 60.53691982), + (-0.0014916558, 16.9328188651), + [0.0560832, -37.80854262], + ], + [ + 82.88, + (90.00954058, 60.5847404), + (-0.0008534187, 16.9336313627), + [0.05269738, -136.4689168], + ], + [ + 82.88, + (91.272614, 55.4477428), + (-0.0008534187, 16.9336313627), + [0.52391818, -135.997696], + ], + [ + 63.44, + (90.9622768, 54.97227258), + (-0.0014916558, 16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 45.0, + (90.47676342, 54.5945568), + (0.0, 16.9331709419), + [0.60453778, -23.34258222], + ], + [ + 7.13, + (89.9362184, 54.53127778), + (118.5322702695, 16.9431028479), + [0.51824382, -136.00336782], + ], + [ + 352.88, + (88.993726, 54.6042088), + (118.5352255934, -16.9224148061), + [0.578866, -135.94274818], + ], + [ + 315.0, + (88.55494862, 55.02461182), + (16.9331709419, -0.0), + [0.59077098, -23.35634902], + ], + [ + 296.57, + (88.2470676, 55.47622382), + (16.9342802744, -16.9313563251), + [0.559816, -37.30480982], + ], + [ + 277.13, + (88.12893982, 55.93010658), + (16.9431028479, -118.5322702695), + [0.4803648, -136.04124938], + ], + [ + 262.88, + (88.12176178, 56.30353738), + (0.0008534187, -16.9336313627), + [0.38306502, -136.13854662], + ], + [ + 262.88, + (88.1940324, 56.8190888), + (0.0008534187, -16.9336313627), + [0.52391818, -135.997696], + ], + [ + 243.44, + (88.5043696, 57.2945768), + (0.0014916558, -16.9328188651), + [0.55751222, -37.3071136], + ], + [ + 225.0, + (88.98928862, 57.6717668), + (-0.0, -16.9331709419), + [0.603758, -23.343362], + ], + [ + 187.13, + (89.5304788, 57.73528458), + (-118.5322702695, -16.9431028479), + [0.52296822, -135.99864342], + ], + [ + 172.88, + (89.9034524, 57.74498738), + (-118.5352255934, 16.9224148061), + [0.38306502, -136.13854662], + ], + [ + 172.88, + (90.4729204, 57.66264058), + (-118.5352255934, 16.9224148061), + [0.578866, -135.94274818], + ], + [ + 135.0, + (90.91169778, 57.24223502), + (-16.9331709419, 0.0), + [0.59077098, -23.35634902], + ], + [ + 116.57, + (91.2195788, 56.79062302), + (-16.9342802744, 16.9313563251), + [0.559816, -37.30480982], + ], + [ + 97.13, + (91.3395684, 56.32676822), + (-16.9431028479, 118.5322702695), + [0.49054258, -136.0310716], + ], + [ + 82.88, + (91.3456644, 55.96324342), + (-0.0008534187, 16.9336313627), + [0.37036502, -136.15124662], + ], + ], + "CONC_DEMOLITION": [ + [45.0, (0.0, 0.0), (-5.3881536726, 5.3881536726), [2.54, -2.54]], + [45.0, (1.796034, 0.0), (-5.3881536726, 5.3881536726), [2.54, -2.54]], + [-45.0, (0.0, 0.0), (5.3881536726, 5.3881536726), [2.54, -2.54]], + [-45.0, (1.796034, 0.0), (5.3881536726, 5.3881536726), [2.54, -2.54]], + ], + "CONC_EXISTING": [ + [45.0, (0.0, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (1.7960467, 0.0), (-5.3881536726, 5.3881536726), []], + [-45.0, (0.0, 0.0), (5.3881536726, 5.3881536726), []], + [-45.0, (1.7960467, 0.0), (5.3881536726, 5.3881536726), []], + ], + "CONC_PRECAST": [ + [45.0, (0.0, 0.0), (-2.6940768363, 2.6940768363), []], + [-45.0, (0.0, 0.0), (5.3881536726, 5.3881536726), []], + ], + "CORK": [ + [0.0, (0.0, 0.0), (0.0, 3.81), []], + [ + 135.0, + (1.905, -1.905), + (-7.6199999872, -7.6199999872), + [5.3881536941, -5.3881536941], + ], + [ + 135.0, + (2.8575, -1.905), + (-7.6199999872, -7.6199999872), + [5.3881536941, -5.3881536941], + ], + [ + 135.0, + (3.81, -1.905), + (-7.6199999872, -7.6199999872), + [5.3881536941, -5.3881536941], + ], + ], + "CROSS": [ + [0.0, (0.0, 0.0), (6.35, 6.35), [3.175, -9.525]], + [90.0, (1.5875, -1.5875), (-6.35, 6.35), [3.175, -9.525]], + ], + "CROSSES": [ + [45.0, (-4.48945, 0.0), (-8.9802561211, 8.9802561211), [6.35, -6.35]], + [135.0, (0.0, 0.0), (-8.9802561211, -8.9802561211), [6.35, -6.35]], + ], + "DASH": [[0.0, (0.0, 0.0), (3.175, 3.175), [3.175, -3.175]]], + "DIAMONDS": [ + [60.0, (0.0, 0.0), (-5.499261314, 3.175), []], + [120.0, (0.0, 0.0), (-5.499261314, -3.175), []], + ], + "DOLMIT": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [ + 45.0, + (0.0, 0.0), + (-12.6999913435, 12.6999913435), + [8.9802561211, -17.9605122421], + ], + ], + "DOTGRID": [[0.0, (0.0, 0.0), (0.0, 25.4), [0.0, -25.4]]], + "DOTS": [[0.0, (0.0, 0.0), (0.79375, 1.5875), [0.0, -1.5875]]], + "DOTS1": [[0.0, (0.0, 0.0), (0.79375, 1.5875), [0.0, -1.5875]]], + "DOTS2": [ + [0.0, (1.016, 0.508), (0.0, 25.4), [0.0, -25.4]], + [0.0, (9.144, 1.016), (0.0, 25.4), [0.0, -25.4]], + [0.0, (4.572, 6.604), (0.0, 25.4), [0.0, -25.4]], + [0.0, (10.16, 10.668), (0.0, 25.4), [0.0, -25.4]], + [0.0, (3.556, 12.192), (0.0, 25.4), [0.0, -25.4]], + [0.0, (5.588, 18.288), (0.0, 25.4), [0.0, -25.4]], + [0.0, (2.032, 22.86), (0.0, 25.4), [0.0, -25.4]], + [0.0, (10.16, 22.352), (0.0, 25.4), [0.0, -25.4]], + [0.0, (16.256, 23.368), (0.0, 25.4), [0.0, -25.4]], + [0.0, (19.304, 17.272), (0.0, 25.4), [0.0, -25.4]], + [0.0, (24.384, 16.764), (0.0, 25.4), [0.0, -25.4]], + [0.0, (24.384, 7.62), (0.0, 25.4), [0.0, -25.4]], + [0.0, (19.812, 4.572), (0.0, 25.4), [0.0, -25.4]], + [0.0, (12.7, 6.096), (0.0, 25.4), [0.0, -25.4]], + [0.0, (17.272, 10.668), (0.0, 25.4), [0.0, -25.4]], + [0.0, (12.7, 15.24), (0.0, 25.4), [0.0, -25.4]], + [0.0, (23.368, 1.016), (0.0, 25.4), [0.0, -25.4]], + ], + "EARTH": [ + [0.0, (0.0, 0.0), (6.35, 6.35), [6.35, -6.35]], + [0.0, (0.0, 2.38125), (6.35, 6.35), [6.35, -6.35]], + [0.0, (0.0, 4.7625), (6.35, 6.35), [6.35, -6.35]], + [90.0, (0.79375, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + [90.0, (3.175, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + [90.0, (5.55625, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + ], + "EARTH1": [ + [0.0, (0.0, 0.0), (6.35, 6.35), [6.35, -6.35]], + [0.0, (0.0, 2.38125), (6.35, 6.35), [6.35, -6.35]], + [0.0, (0.0, 4.7625), (6.35, 6.35), [6.35, -6.35]], + [90.0, (0.79375, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + [90.0, (3.175, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + [90.0, (5.55625, 5.55625), (-6.35, 6.35), [6.35, -6.35]], + ], + "EARTH2": [ + [45.0, (0.0, 0.0), (0.0, 13.4703841816), [9.525, -9.525]], + [45.0, (-1.3470384159, 1.3470384159), (0.0, 13.4703841816), [9.525, -9.525]], + [45.0, (-2.6940768128, 2.6940768128), (0.0, 13.4703841816), [9.525, -9.525]], + [45.0, (-4.0411152668, 4.0411152668), (0.0, 13.4703841816), [9.525, -9.525]], + [45.0, (-5.388153435, 5.388153435), (0.0, 13.4703841816), [9.525, -9.525]], + [45.0, (-6.73519227, 6.73519227), (0.0, 13.4703841816), [9.525, -9.525]], + [135.0, (0.0, 0.0), (-13.4703841816, 0.0), [9.525, -9.525]], + [135.0, (-1.3470384159, -1.3470384159), (-13.4703841816, 0.0), [9.525, -9.525]], + [135.0, (-2.6940768128, -2.6940768128), (-13.4703841816, 0.0), [9.525, -9.525]], + [135.0, (-4.0411152668, -4.0411152668), (-13.4703841816, 0.0), [9.525, -9.525]], + [135.0, (-5.388153435, -5.388153435), (-13.4703841816, 0.0), [9.525, -9.525]], + [135.0, (-6.73519227, -6.73519227), (-13.4703841816, 0.0), [9.525, -9.525]], + ], + "EGYPTIAN": [ + [0.0, (0.0, 0.0), (0.0, 31.75), [6.35, -6.35, 19.05]], + [0.0, (0.0, 6.35), (0.0, 31.75), [-19.05, 12.7]], + [0.0, (0.0, 12.7), (0.0, 31.75), [-19.05, 6.35, -6.35]], + [0.0, (0.0, 19.05), (0.0, 31.75), [-12.7, 12.7, -6.35]], + [0.0, (0.0, 25.4), (0.0, 31.75), [-6.35, 25.4]], + [90.0, (6.35, 0.0), (-31.75, 0.0), [25.4, -6.35]], + [90.0, (12.7, 0.0), (-31.75, 0.0), [19.05, -12.7]], + [90.0, (19.05, 0.0), (-31.75, 0.0), [-6.35, 6.35, -19.05]], + [90.0, (25.4, 0.0), (-31.75, 0.0), [-12.7, 6.35, -12.7]], + [90.0, (31.75, 0.0), (-31.75, 0.0), [-6.35, 19.05, -6.35]], + ], + "ESCHER": [ + [60.0, (0.0, 0.0), (-30.4799999881, -6.9e-09), [27.94, -2.54]], + [180.0, (0.0, 0.0), (15.24, -26.3964542936), [27.94, -2.54]], + [300.0, (0.0, 0.0), (30.4799999881, -6.9e-09), [27.94, -2.54]], + [60.0, (2.54, 0.0), (-30.4799999881, -6.9e-09), [5.08, -25.4]], + [300.0, (2.54, 0.0), (30.4799999881, -6.9e-09), [5.08, -25.4]], + [60.0, (-1.27, 2.199704516), (-30.4799999881, -6.9e-09), [5.08, -25.4]], + [180.0, (-1.27, 2.199704516), (15.24, -26.3964542936), [5.08, -25.4]], + [300.0, (-1.27, -2.199704516), (30.4799999881, -6.9e-09), [5.08, -25.4]], + [180.0, (-1.27, -2.199704516), (15.24, -26.3964542936), [5.08, -25.4]], + [60.0, (-10.16, 0.0), (-30.4799999881, -6.9e-09), [5.08, -25.4]], + [300.0, (-10.16, 0.0), (30.4799999881, -6.9e-09), [5.08, -25.4]], + [60.0, (5.08, -8.7988180894), (-30.4799999881, -6.9e-09), [5.08, -25.4]], + [180.0, (5.08, -8.7988180894), (15.24, -26.3964542936), [5.08, -25.4]], + [300.0, (5.08, 8.7988180894), (30.4799999881, -6.9e-09), [5.08, -25.4]], + [180.0, (5.08, 8.7988180894), (15.24, -26.3964542936), [5.08, -25.4]], + [0.0, (5.08, 4.3994090574), (-15.24, 26.3964542936), [17.78, -12.7]], + [0.0, (5.08, -4.3994090574), (-15.24, 26.3964542936), [17.78, -12.7]], + [120.0, (1.27, 6.5991135734), (-30.4799999881, 6.9e-09), [17.78, -12.7]], + [120.0, (-6.35, 2.199704516), (-30.4799999881, 6.9e-09), [17.78, -12.7]], + [240.0, (-6.35, -2.199704516), (15.2399999881, -26.3964543005), [17.78, -12.7]], + [240.0, (1.27, -6.5991135734), (15.2399999881, -26.3964543005), [17.78, -12.7]], + ], + "FLEX": [ + [0.0, (0.0, 0.0), (0.0, 6.35), [6.35, -6.35]], + [ + 45.0, + (6.35, 0.0), + (0.0, 6.3499999893), + [1.5875, -5.8052561314, 1.5875, -8.9802561314], + ], + ], + "FLEXIBLE": [ + [0.0, (0.0, 0.0), (0.0, 7.62), [7.62, -7.62]], + [ + 45.0, + (7.62, 0.0), + (0.0, 7.6199999872), + [1.905, -6.9663073577, 1.905, -10.7763073577], + ], + ], + "GLASS": [ + [ + 236.3099, + (12.192, 14.224), + (-20.3200271172, -40.6399910139), + [7.3264776, -65.93831872], + ], + [ + 236.3099, + (12.5984, 13.0048), + (-20.3200271172, -40.6399910139), + [4.39588656, -68.86890976], + ], + [ + 236.3099, + (10.16, 13.0048), + (-20.3200271172, -40.6399910139), + [4.39588656, -68.86890976], + ], + ], + "GOST_GLASS": [ + [45.0, (0.0, 0.0), (8.4852813742, 0.0), [5.0, -7.0]], + [45.0, (2.12132, 0.0), (8.4852813742, 0.0), [2.0, -10.0]], + [45.0, (0.0, 2.12132), (8.4852813742, 0.0), [2.0, -10.0]], + ], + "GOST_GROUND": [ + [45.0, (0.0, 0.0), (14.1421356237, 0.0), [20.0]], + [45.0, (3.0, 0.0), (14.1421356237, 0.0), [20.0]], + [45.0, (6.0, 0.0), (14.1421356237, 0.0), [20.0]], + ], + "GOST_WOOD": [ + [90.0, (0.0, 0.0), (6.0, 0.0), [10.0, -2.0]], + [90.0, (2.0, -2.0), (6.0, 0.0), [6.0, -1.5, 3.0, -1.5]], + [90.0, (4.0, -5.0), (6.0, 0.0), [10.0, -2.0]], + ], + "GRASS": [ + [90.0, (0.0, 0.0), (-17.96051224, 17.96051224), [4.7625, -31.15852448]], + [45.0, (0.0, 0.0), (-17.9605122421, 17.9605122421), [4.7625, -20.6375]], + [135.0, (0.0, 0.0), (-17.9605122421, -17.9605122421), [4.7625, -20.6375]], + ], + "GRASS1": [ + [90.0, (0.0, 0.0), (-14.3684097899, 14.3684097899), [3.81, -24.9268196002]], + [45.0, (0.0, 0.0), (-14.3684097937, 14.3684097937), [3.81, -16.51]], + [135.0, (0.0, 0.0), (-14.3684097937, -14.3684097937), [3.81, -16.51]], + ], + "GRASS2": [ + [0.0, (0.0, 0.0), (10.16, 17.597636189), [2.54, -17.78]], + [90.0, (1.27, 0.0), (-10.16, 17.597636189), [1.27, -33.9252723779]], + [90.0, (1.5875, 0.0), (-10.16, 17.597636189), [1.016, -34.1792723779]], + [90.0, (0.9525, 0.0), (-10.16, 17.597636189), [1.016, -34.1792723779]], + [60.0, (1.905, 0.0), (-10.1599999862, 17.5976361969), [0.8128, -19.5072]], + [120.0, (0.635, 0.0), (-20.3199999862, 8e-09), [0.8128, -19.5072]], + ], + "GRATE": [ + [0.0, (0.0, 0.0), (0.0, 0.79375), []], + [90.0, (0.0, 0.0), (-3.175, 0.0), []], + ], + "GRAVEL": [ + [ + 228.0127875, + (18.288, 25.4), + (-203.200000016, -228.5999999858), + [3.4172144, -338.3048363956], + ], + [ + 184.969741, + (16.002, 22.86), + (304.7999998794, 25.400001447), + [5.8640472, -580.5404889352], + ], + [ + 132.5104471, + (10.16, 22.352), + (254.0000001073, -279.3999999025), + [4.1348152, -409.347227941], + ], + [ + 267.273689, + (0.254, 16.002), + (25.4000000532, 507.9999999973), + [5.3400452, -528.6643742574], + ], + [ + 292.83365418, + (0.0, 10.668), + (-127.0000000106, 304.7999999956), + [5.236337, -518.3980774534], + ], + [ + 357.273689, + (2.032, 5.842), + (-507.9999999973, 25.4000000532), + [5.3400452, -528.6643742574], + ], + [ + 37.69424047, + (7.366, 5.588), + (-330.1999999854, -254.000000019), + [7.0619366, -699.1311531425], + ], + [ + 72.25532837, + (12.954, 9.906), + (177.8000000478, 558.7999999848), + [6.6671952, -660.0525660191], + ], + [ + 121.42956562, + (14.986, 16.256), + (-203.2000000288, 330.1999999823), + [5.35813, -530.4554569871], + ], + [ + 175.2363583, + (12.192, 20.828), + (279.399999996, -25.4000000439), + [6.1171328, -299.7393695], + ], + [ + 222.3974378, + (6.096, 21.336), + (-304.7999999902, -279.4000000106), + [7.9107792, -783.1677251218], + ], + [ + 138.81407483, + (25.4, 15.748), + (-177.7999999893, 152.4000000124), + [2.7000454, -267.3056582434], + ], + [ + 171.4692344, + (23.368, 17.526), + (330.2000000089, -50.7999999424), + [5.1368198, -508.5463899704], + ], + [225.0, (18.288, 18.288), (-0.0, -25.4), [3.5920934, -32.3289310843]], + [ + 203.19859051, + (16.51, 21.336), + (127.0000000035, 50.7999999911), + [1.9344132, -191.5062236889], + ], + [ + 291.80140949, + (14.732, 20.574), + (-25.4000000053, 76.1999999982), + [2.7356562, -134.0475299], + ], + [ + 30.96375653, + (15.748, 18.034), + (76.2000000019, 50.7999999972), + [4.4431966, -143.6629815291], + ], + [ + 161.56505118, + (19.558, 20.32), + (50.8000000013, -25.3999999973), + [3.2128714, -77.1089811683], + ], + [16.389540334, (0.0, 20.574), (254.0, 76.2), [4.50088, -445.5882667254]], + [ + 70.34617594, + (4.318, 21.844), + (-101.6000000093, -279.3999999967), + [3.7759894, -373.822156782], + ], + [ + 293.19859051, + (19.558, 25.4), + (-50.7999999911, 127.0000000036), + [3.868801, -189.5718358889], + ], + [ + 343.61045967, + (21.082, 21.844), + (-254.0000000053, 76.1999999822), + [4.50088, -445.5882667254], + ], + [339.44395478, (0.0, 4.826), (-127.0, 50.8), [4.340352, -212.6773431311]], + [ + 294.7751406, + (4.064, 3.302), + (-127.0000001512, 279.3999999313), + [3.6367212, -360.0359338072], + ], + [ + 66.80140949, + (19.812, 0.0), + (50.799999992, 127.0000000032), + [3.868801, -189.5718358889], + ], + [ + 17.35402464, + (21.336, 3.556), + (-330.1999999934, -101.6000000213), + [4.2578274, -421.523759802], + ], + [ + 69.44395478, + (7.366, 0.0), + (-50.8000000009, -126.9999999996), + [2.170176, -214.8475191311], + ], + [101.309932474, (18.288, 0.0), (-25.4, 101.6), [1.295146, -128.2199496453]], + [165.963756532, (18.034, 1.27), (76.2, -25.4), [5.236337, -99.4905458907]], + [ + 186.00900596, + (12.954, 2.54), + (253.9999999987, 25.4000000133), + [4.85267, -480.4136486334], + ], + [ + 303.69006753, + (15.748, 15.748), + (-25.4000000035, 50.7999999982), + [3.6632388, -87.9177635968], + ], + [ + 353.15722659, + (17.78, 12.7), + (431.8000000027, -50.7999999774), + [6.3955676, -633.1600906503], + ], + [ + 60.9453959, + (24.13, 11.938), + (-101.6000000028, -177.7999999984), + [2.6150824, -258.8939231811], + ], + [90.0, (25.4, 14.224), (-25.4, 25.4), [1.524, -23.876]], + [ + 120.25643716, + (12.446, 3.302), + (101.5999999876, -177.8000000071), + [3.5286696, -349.339407732], + ], + [ + 48.0127875, + (10.668, 6.35), + (203.2000000168, 228.5999999851), + [6.8344288, -334.8876219957], + ], + [0.0, (15.24, 11.43), (25.4, 25.4), [6.604, -18.796]], + [ + 325.3048465, + (21.844, 11.43), + (254.0000000962, -177.7999998625), + [4.0160956, -397.5931672414], + ], + [ + 254.0546041, + (25.146, 9.144), + (-25.3999999982, -101.6000000004), + [3.6982908, -181.2165003877], + ], + [ + 207.64597536, + (24.13, 5.588), + (-482.6000000177, -253.9999999663), + [6.021451, -596.1246442294], + ], + [175.42607874, (18.796, 2.794), (-330.2, 25.4), [6.3702946, -630.6584645624]], + ], + "GRAVEL1": [ + [ + 228.0128, + (12.9600000032, 17.9999999816), + (-143.9999681763, -162.000024158), + [2.4216479939, -239.7435839968], + ], + [ + 184.9697, + (11.3399999971, 16.2000000155), + (216.0000189102, 17.9998435066), + [4.1556239824, -411.4066499867], + ], + [ + 132.5104, + (7.2000000018, 15.840000004), + (179.9998329469, -198.0001561228), + [2.9301840101, -290.0885759914], + ], + [ + 267.2737, + (0.1800000058, 11.3399999971), + (17.9999283207, 360.0000052976), + [3.7842839935, -374.6440439896], + ], + [ + 292.8337, + (0.0, 7.5600000133), + (-90.0001782992, 215.999935404), + [3.7107900079, -367.3687139784], + ], + [ + 357.2737, + (1.4400000004, 4.1399999953), + (-360.0000052976, 17.9999283207), + [3.7842839935, -374.6440439896], + ], + [ + 37.6942, + (5.2199999842, 3.9599999896), + (-234.0001322119, -179.9998272812), + [5.0045219899, -495.4472817984], + ], + [ + 72.2553, + (9.1800000194, 7.019999996), + (126.0001937207, 395.9999321528), + [4.724783987, -467.7537780288], + ], + [ + 121.4296, + (10.6200000198, 11.5200000029), + (-144.0001482242, 233.9999106564), + [3.7970999953, -375.9133139885], + ], + [ + 175.2364, + (8.6400000022, 14.7600000151), + (198.0000170247, -17.9998475922), + [4.3349759986, -212.4137339982], + ], + [ + 222.3974, + (4.3200000011, 15.1199999809), + (-216.0001323074, -197.9998574727), + [5.6060640076, -555.0007501944], + ], + [ + 138.8141, + (17.9999999816, 11.1599999914), + (-126.0000530418, 107.9999516683), + [1.9134179816, -189.4291919867], + ], + [ + 171.4692, + (16.5599999813, 12.419999986), + (233.9999691401, -36.0001423904), + [3.6402659935, -360.3871980151], + ], + [ + 225.0, + (12.9600000032, 12.9600000032), + (-0.0, -18.000005591), + [2.5455779975, -22.9102560184], + ], + [ + 203.1986, + (11.7000000086, 15.1199999809), + (89.9999951667, 36.0000238407), + [1.3708440198, -135.7130699906], + ], + [ + 291.8014, + (10.440000014, 14.5800000094), + (-17.9999983704, 54.0000049026), + [1.9386540043, -94.9943160054], + ], + [ + 30.9638, + (11.1599999914, 12.7799999975), + (53.9999644169, 36.0000446951), + [3.1487219982, -101.8084140155], + ], + [ + 161.5651, + (13.8599999863, 14.4000000036), + (36.0000078261, -17.9999712785), + [2.2768379863, -54.644165987], + ], + [ + 16.3895, + (0.0, 14.5800000094), + (180.0000395482, 53.999868792), + [3.1896000216, -315.7712100108], + ], + [ + 70.3462, + (3.0600000065, 15.4799999924), + (-71.9999144577, -198.0000384368), + [2.6758980112, -264.913343995], + ], + [ + 293.1986, + (13.8599999863, 17.9999999816), + (-36.0000238407, 89.9999951667), + [2.7416699802, -134.3422439845], + ], + [ + 343.6105, + (14.9400000209, 15.4799999924), + (-180.0000395482, 53.999868792), + [3.1896000216, -315.7712100108], + ], + [ + 339.444, + (0.0, 3.420000018), + (-90.000033183, 35.9999279355), + [3.0758400205, -150.7162320086], + ], + [ + 294.7751, + (2.8800000007, 2.3399999834), + (-89.9998594132, 198.0000615975), + [2.5772039845, -255.1435739892], + ], + [ + 66.8014, + (14.0399999921, 0.0), + (36.0000238407, 89.9999951667), + [2.7416699802, -134.3422439845], + ], + [ + 17.354, + (15.1199999809, 2.5199999892), + (-234.0000363497, -71.9999010651), + [3.017358014, -298.7176319971], + ], + [ + 69.444, + (5.2199999842, 0.0), + (-35.9999279355, -90.000033183), + [1.5379199874, -152.254151996], + ], + [ + 101.3099, + (12.9600000032, 0.0), + (-17.9999573944, 72.0000135294), + [0.9178199932, -90.8645219942], + ], + [ + 165.9638, + (12.7799999975, 0.8999999831), + (54.0000098409, -17.9999650276), + [3.7107900079, -70.5050999903], + ], + [ + 186.009, + (9.1800000194, 1.8000000119), + (179.9999954963, 17.9999876948), + [3.4388999802, -340.4506140022], + ], + [ + 303.6901, + (11.1599999914, 11.1599999914), + (-18.0000240412, 35.9999920382), + [2.5959960018, -62.3039220112], + ], + [ + 353.1572, + (12.5999999917, 9.0000000137), + (305.9999885795, -36.0001439522), + [4.5322919971, -448.6961339953], + ], + [ + 60.9454, + (17.0999999986, 8.4599999964), + (-72.0000005012, -126.0000069224), + [1.8532079878, -183.4681320216], + ], + [ + 90.0, + (17.9999999816, 10.0800000025), + (-17.9999999816, 17.9999999816), + [1.0799999888, -16.9199999928], + ], + [ + 120.2564, + (8.8200000079, 2.3399999834), + (71.9999079614, -126.0000441964), + [2.5006319914, -247.5633600209], + ], + [ + 48.0128, + (7.5600000133, 4.5000000068), + (143.9999681763, 162.000024158), + [4.8432959878, -237.3219360029], + ], + [ + 0.0, + (10.7999999798, 8.0999999849), + (17.9999999816, 17.9999999816), + [4.6800000126, -13.3200000148], + ], + [ + 325.3048, + (15.4799999924, 8.0999999849), + (-179.9998966718, 126.0001549797), + [2.8460519863, -281.7589319903], + ], + [ + 254.0546, + (17.8200000216, 6.4799999788), + (-17.9999980057, -72.0000022974), + [2.6208359978, -128.4211439852], + ], + [ + 207.646, + (17.0999999986, 3.9599999896), + (-341.999924501, -180.0001388421), + [4.2671699924, -422.4505320137], + ], + [ + 175.4261, + (13.320007142, 1.980001628), + (-233.9997863523, 17.9999001623), + [4.51438391, -446.9228933], + ], + ], + "GRID": [[0.0, (0.0, 0.0), (0.0, 25.4), []], [90.0, (0.0, 0.0), (-25.4, 0.0), []]], + "GROUT": [ + [0.0, (5.08, 2.54), (1.27, 10.16), [1.27, -8.89]], + [0.0, (6.35, 6.35), (0.0, 10.16), [0.0, -10.16]], + [0.0, (2.54, 2.54), (3.81, 10.16), [0.0, -10.16]], + [0.0, (2.54, 10.16), (10.16, 10.16), [2.54, -17.78]], + [0.0, (10.16, 3.81), (0.0, 10.16), [0.0, -10.16]], + [0.0, (7.62, 2.54), (2.54, 10.16), [0.0, -10.16]], + [0.0, (8.89, 3.81), (0.0, 10.16), [0.0, -10.16]], + [0.0, (3.81, 10.16), (0.0, 10.16), [0.0, -10.16]], + ], + "HERRING_45": [ + [0.0, (0.0, 0.0), (25.4, 25.4), [76.2, -25.4]], + [90.0, (25.4, 0.0), (-25.4, -25.4), [76.2, -25.4]], + ], + "HERRING_H": [ + [0.0, (0.0, 0.0), (0.0, 20.32), []], + [315.0, (0.0, 0.0), (20.3199999946, -0.0), [28.7368196002, -28.7368196002]], + [45.0, (0.0, 0.0), (20.3199999946, 0.0), [28.7368196002, -28.7368196002]], + ], + "HERRING_UNI": [ + [ + 18.435, + (0.0, 0.0), + (25.1005565075, 25.1006013476), + [7.9375, -63.5, 15.875, -71.4375], + ], + [ + 18.435, + (17.5703865, -2.510028), + (25.1005565075, 25.1006013476), + [15.875, -63.5, 7.9375, -71.4375], + ], + [ + 108.435, + (2.510028, -7.5301475), + (25.1005565075, 25.1006013476), + [15.875, -63.5, 15.875, -63.5], + ], + [ + 108.435, + (2.510028, 17.5703865), + (25.1005565075, 25.1006013476), + [15.875, -63.5, 15.875, -63.5], + ], + [108.435, (25.100534, 0.0), (25.1005565075, 25.1006013476), [7.9375, -71.4375]], + [ + 108.435, + (-22.5905695, 17.5703865), + (25.1005565075, 25.1006013476), + [7.9375, -71.4375], + ], + [ + 333.435, + (7.5301729, 2.5100661), + (25.1005713744, 25.1005878164), + [11.2253395, -101.02788405, 11.2253395, -101.02788405], + ], + [ + 333.435, + (-42.6710094, 27.6106001), + (25.1005713744, 25.1005878164), + [11.22532045, -213.2810822], + ], + [ + 333.435, + (32.630745, 2.51008515), + (25.1005713744, 25.1005878164), + [11.2253395, -44.93962818, 11.2253395, -157.15447995], + ], + [ + 333.435, + (-17.57043095, 27.61061915), + (25.1005713744, 25.1005878164), + [11.22532045, -213.2810822], + ], + [ + 333.435, + (57.7313425, 2.5100915), + (25.1005713744, 25.1005878164), + [11.2253395, -101.02788405, 11.2253395, -101.02788405], + ], + [ + 333.435, + (107.9325121, -22.59042345), + (25.1005713744, 25.1005878164), + [11.22532045, -213.2810822], + ], + [ + 63.435, + (-2.510155, 7.530465), + (-25.1007417629, -25.1005026224), + [11.22553, -44.90085, 11.22553, -101.0285, 11.22553, -44.90085], + ], + ], + "HERRING_V": [ + [45.0, (0.0, 0.0), (0.0, 35.9210244843), [76.2, -25.4]], + [135.0, (17.9605122437, 17.9605122437), (0.0, 35.9210244843), [76.2, -25.4]], + ], + "HEX": [ + [0.0, (0.0, 0.0), (0.0, 5.4992613154), [3.175, -6.35]], + [120.0, (0.0, 0.0), (-4.7625000012, -2.7496306577), [3.175, -6.35]], + [60.0, (3.175, 0.0), (-4.7625000012, 2.7496306577), [3.175, -6.35]], + ], + "HEXAGONS": [ + [0.0, (0.0, 0.0), (0.0, 6.5991135785), [3.81, -7.62]], + [120.0, (0.0, 0.0), (-5.7150000014, -3.2995567892), [3.81, -7.62]], + [60.0, (3.81, 0.0), (-5.7150000014, 3.2995567892), [3.81, -7.62]], + ], + "HONEY": [ + [0.0, (0.0, 0.0), (4.7625, 2.749630645), [3.175, -6.35]], + [120.0, (0.0, 0.0), (-4.7624999896, 2.749630663), [3.175, -6.35]], + [60.0, (0.0, 0.0), (1.04e-08, 5.499261308), [-6.35, 3.175]], + ], + "HONEYCOMB": [ + [0.0, (0.0, 0.0), (5.715, 3.299556774), [3.81, -7.62]], + [120.0, (0.0, 0.0), (-5.7149999875, 3.2995567956), [3.81, -7.62]], + [60.0, (0.0, 0.0), (1.25e-08, 6.5991135696), [-7.62, 3.81]], + ], + "HOUND": [ + [0.0, (0.0, 0.0), (6.35, 1.5875), [25.4, -12.7]], + [90.0, (0.0, 0.0), (-1.5875, -6.35), [25.4, -12.7]], + ], + "INSUL": [ + [0.0, (0.0, 0.0), (0.0, 9.525), []], + [0.0, (0.0, 3.175), (0.0, 9.525), [3.175, -3.175]], + [0.0, (0.0, 6.35), (0.0, 9.525), [3.175, -3.175]], + ], + "INSULATION": [ + [45.0, (0.0, 0.0), (-2.5144717139, 2.5144717139), []], + [135.0, (0.0, 0.0), (-2.5144717139, -2.5144717139), []], + ], + "ISO02W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0]]], + "ISO03W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -18.0]]], + "ISO04W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0]]], + "ISO05W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0, 0.5, -3.0]]], + "ISO06W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 0.5, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-34.0, 0.5, -3.0]], + ], + "ISO07W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [0.5, -3.0]]], + "ISO08W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 6.0, -3.0]]], + "ISO09W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [24.0, -3.0, 6.0, -3.0, 6.0, -3.0]]], + "ISO10W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0]]], + "ISO11W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -3.0]]], + "ISO12W100": [[0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0, 0.5, -3.0]]], + "ISO13W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-33.5, 0.5, -3.0]], + ], + "ISO14W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 0.5, -3.0, 0.5, -6.5]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-22.0, 0.5, -3.0]], + ], + "ISO15W100": [ + [0.0, (0.0, 0.0), (0.0, 5.0), [12.0, -3.0, 12.0, -3.0, 0.5, -10.0]], + [0.0, (0.0, 0.0), (0.0, 5.0), [-33.5, 0.5, -3.0, 0.5, -3.0]], + ], + "JIS_LC_20": [ + [45.0, (0.0, 0.0), (-14.1421356237, 14.1421356237), []], + [45.0, (0.4, 0.0), (-14.1421356237, 14.1421356237), []], + ], + "JIS_LC_20A": [ + [45.0, (0.0, 0.0), (-14.1421356237, 14.1421356237), []], + [45.0, (1.0, 0.0), (-14.1421356237, 14.1421356237), []], + ], + "JIS_LC_8": [ + [45.0, (0.0, 0.0), (-5.5154328933, 5.5154328933), []], + [45.0, (0.4, 0.0), (-5.5154328933, 5.5154328933), []], + ], + "JIS_LC_8A": [ + [45.0, (0.0, 0.0), (-5.5154328933, 5.5154328933), []], + [45.0, (1.0, 0.0), (-5.5154328933, 5.5154328933), []], + ], + "JIS_RC_10": [ + [45.0, (0.0, 0.0), (-7.0710678119, 7.0710678119), []], + [45.0, (0.725, 0.0), (-7.0710678119, 7.0710678119), []], + [45.0, (1.45, 0.0), (-7.0710678119, 7.0710678119), []], + ], + "JIS_RC_15": [ + [45.0, (0.0, 0.0), (-10.6066017178, 10.6066017178), []], + [45.0, (0.725, 0.0), (-10.6066017178, 10.6066017178), []], + [45.0, (1.45, 0.0), (-10.6066017178, 10.6066017178), []], + ], + "JIS_RC_18": [ + [45.0, (0.0, 0.0), (-12.7279220614, 12.7279220614), []], + [45.0, (1.0, 0.0), (-12.7279220614, 12.7279220614), []], + [45.0, (2.0, 0.0), (-12.7279220614, 12.7279220614), []], + ], + "JIS_RC_30": [ + [45.0, (0.0, 0.0), (-21.2132034356, 21.2132034356), []], + [45.0, (1.0, 0.0), (-21.2132034356, 21.2132034356), []], + [45.0, (2.0, 0.0), (-21.2132034356, 21.2132034356), []], + ], + "JIS_STN_1E": [ + [45.0, (0.0, 0.0), (-0.7071067812, 0.7071067812), []], + [45.0, (0.705, 0.0), (-0.7071067812, 0.7071067812), [1.0, -0.5]], + ], + "JIS_STN_2.5": [ + [45.0, (0.0, 0.0), (-1.767766953, 1.767766953), []], + [45.0, (1.765, 0.0), (-1.767766953, 1.767766953), [1.2, -0.5]], + ], + "JIS_WOOD": [[45.0, (0.0, 0.0), (-0.4999999992, 0.4999999992), []]], + "LINE": [[0.0, (0.0, 0.0), (0.0, 3.175), []]], + "LINES": [[0.0, (0.0, 0.0), (0.0, 2.54), []]], + "MUDST": [[0.0, (0.0, 0.0), (12.7, 6.35), [6.35, -6.35, 0.0, -6.35, 0.0, -6.35]]], + "NATURAL": [ + [45.0, (0.0, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (3.5920934, 0.0), (-5.3881536726, 5.3881536726), [1.27, -1.27]], + [45.0, (7.1841868, 0.0), (-5.3881536726, 5.3881536726), [1.27, -1.27]], + ], + "NET": [[0.0, (0.0, 0.0), (0.0, 3.175), []], [90.0, (0.0, 0.0), (-3.175, 0.0), []]], + "NET3": [ + [0.0, (0.0, 0.0), (0.0, 3.175), []], + [60.0, (0.0, 0.0), (-2.749630657, 1.5875), []], + [120.0, (0.0, 0.0), (-2.749630657, -1.5875), []], + ], + "OCTAGONS": [ + [315.0, (0.0, 8.8392), (30.480009432, -0.0), [12.50051856, -30.60472416]], + [0.0, (8.8392, 0.0), (30.48, 30.48), [12.8016, -17.6784]], + [45.0, (21.6408, 0.0), (0.0, 30.480009432), [12.50051856, -30.60472416]], + [135.0, (30.48, 21.6408), (-30.480009432, 0.0), [12.50051856, -30.60472416]], + [225.0, (8.8392, 30.48), (-0.0, -30.480009432), [12.50051856, -30.60472416]], + [270.0, (0.0, 21.6408), (30.48, -30.48), [12.8016, -17.6784]], + ], + "PLAST": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [0.0, (0.0, 0.79375), (0.0, 6.35), []], + [0.0, (0.0, 1.5875), (0.0, 6.35), []], + ], + "PLASTI": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [0.0, (0.0, 0.79375), (0.0, 6.35), []], + [0.0, (0.0, 1.5875), (0.0, 6.35), []], + [0.0, (0.0, 3.96875), (0.0, 6.35), []], + ], + "PLUSSES": [ + [0.0, (0.0, 0.0), (7.62, 7.62), [3.81, -11.43]], + [90.0, (1.905, -1.905), (-7.62, 7.62), [3.81, -11.43]], + ], + "ROCK": [ + [0.0, (0.0, 0.0), (0.0, 5.08), []], + [ + 45.0, + (0.0, 0.0), + (-10.159999983, 10.159999983), + [7.1842048848, -14.3684280576], + ], + ], + "SACNCR": [ + [45.0, (0.0, 0.0), (-1.6837980227, 1.6837980227), []], + [45.0, (1.6838, 0.0), (-1.6837980227, 1.6837980227), [0.0, -2.38125]], + ], + "SAND": [ + [45.0, (0.0, 0.0), (-4.0411152545, 4.0411152545), [-1.905, 1.905, -1.905]], + [45.0, (4.0386, 0.0), (-4.0411152545, 4.0411152545), [-1.905, 1.905, -1.905]], + [135.0, (0.0, 0.0), (-4.0411152545, -4.0411152545), [0.9525, -3.81, 0.9525]], + [135.0, (4.0386, 0.0), (-4.0411152545, -4.0411152545), [0.9525, -3.81, 0.9525]], + ], + "SCREED": [ + [0.0, (0.0, 0.0), (50.8, 12.7), [-6.35, 0.0, -19.05, 0.0]], + [ + 0.0, + (0.0, 0.635), + (50.8, 12.7), + [-2.54, 0.0, -8.89, 0.0, -4.572, 0.0, -19.05, 0.0], + ], + [ + 0.0, + (0.0, 1.27), + (50.8, 12.7), + [-1.27, 0.0, -6.35, 0.0, -6.35, 0.0, -13.97, 0.0, -4.572, 0.0], + ], + [0.0, (0.0, 1.905), (50.8, 12.7), [-4.572, 0.0, -20.32, 0.0]], + [0.0, (0.0, 2.54), (50.8, 12.7), [-15.24, 0.0, -15.24, 0.0]], + [0.0, (0.0, 3.175), (50.8, 12.7), [-21.59, 0.0]], + [0.0, (0.0, 3.81), (50.8, 12.7), [-6.35, 0.0, -27.94, 0.0]], + [0.0, (0.0, 4.445), (50.8, 12.7), [-8.89, 0.0, -5.08, 0.0]], + [0.0, (0.0, 5.08), (50.8, 12.7), [-12.7, 0.0]], + [0.0, (0.0, 6.35), (50.8, 12.7), [-1.778, 0.0, -19.05, 0.0, -11.43, 0.0]], + [0.0, (0.0, 6.985), (50.8, 12.7), [-2.54, 0.0, -0.254, 0.0, -6.35, 0.0]], + [0.0, (0.0, 7.62), (50.8, 12.7), [-1.27, 0.0, -16.51, 0.0, -19.05, 0.0]], + [0.0, (0.0, 8.255), (50.8, 12.7), [-12.7, 0.0]], + [0.0, (0.0, 8.89), (50.8, 12.7), [-6.35, 0.0, -26.67, 0.0]], + [0.0, (0.0, 10.16), (50.8, 12.7), [-30.48, 0.0]], + [0.0, (0.0, 10.795), (50.8, 12.7), [-6.35, 0.0, -0.508, 0.0, -8.89, 0.0]], + [ + 0.0, + (0.0, 11.43), + (50.8, 12.7), + [-1.778, 0.0, -12.7, 0.0, -5.08, 0.0, -8.89, 0.0, -10.16, 0.0], + ], + [ + 0.0, + (0.0, 12.065), + (50.8, 12.7), + [-3.81, 0.0, -5.08, 0.0, -12.7, 0.0, -0.508, 0.0, -6.35, 0.0], + ], + [0.0, (0.0, 12.7), (50.8, 12.7), [-12.7, 0.0]], + ], + "SHAKES": [ + [0.0, (0.0, 3.048), (101.6, 101.6), [10.16, -91.44]], + [0.0, (10.16, 0.0), (101.6, 101.6), [30.48, -71.12]], + [0.0, (40.64, 2.032), (101.6, 101.6), [15.24, -86.36]], + [0.0, (55.88, 0.0), (101.6, 101.6), [30.48, -71.12]], + [0.0, (86.36, 3.048), (101.6, 101.6), [15.24, -86.36]], + [0.0, (15.24, 33.528), (101.6, 101.6), [30.48, -71.12]], + [0.0, (0.0, 35.56), (101.6, 101.6), [15.24, -86.36]], + [0.0, (45.72, 36.576), (101.6, 101.6), [20.32, -81.28]], + [0.0, (66.04, 33.528), (101.6, 101.6), [35.56, -66.04]], + [0.0, (0.0, 68.072), (101.6, 101.6), [34.544, -67.056]], + [0.0, (34.544, 70.104), (101.6, 101.6), [24.384, -77.216]], + [0.0, (58.928, 67.056), (101.6, 101.6), [18.288, -83.312]], + [0.0, (77.216, 71.12), (101.6, 101.6), [17.272, -84.328]], + [180.0, (101.6, 68.072), (-101.6, -101.6), [7.112, -94.488]], + [90.0, (10.16, 0.0), (-101.6, 101.6), [35.56, -66.04]], + [90.0, (40.64, 0.0), (-101.6, 101.6), [33.528, -68.072]], + [90.0, (55.88, 0.0), (-101.6, 101.6), [36.576, -65.024]], + [90.0, (86.36, 0.0), (-101.6, 101.6), [33.528, -68.072]], + [90.0, (45.72, 33.528), (-101.6, 101.6), [36.576, -65.024]], + [90.0, (34.544, 68.072), (-101.6, 101.6), [33.528, -68.072]], + [90.0, (58.928, 67.056), (-101.6, 101.6), [34.544, -67.056]], + [270.0, (0.0, 68.072), (101.6, -101.6), [34.544, -67.056]], + [270.0, (15.24, 68.072), (101.6, -101.6), [34.544, -67.056]], + [270.0, (66.04, 67.056), (101.6, -101.6), [33.528, -68.072]], + [90.0, (94.488, 68.072), (-101.6, 101.6), [33.528, -68.072]], + [90.0, (77.216, 67.056), (-101.6, 101.6), [34.544, -67.056]], + [270.0, (94.488, 3.048), (101.6, -101.6), [3.048, -98.552]], + ], + "SOLID": [[45.0, (0.0, 0.0), (-0.0883883476, 0.0883883476), []]], + "SPANISH": [ + [ + 274.9697, + (28.0416, 30.48), + (-30.4797350376, 365.7600320503), + [28.14742656, -675.53802408], + ], + [180.0, (30.48, 2.4384), (-30.48, -30.48), [2.4384, -28.0416]], + [0.0, (0.0, 0.0), (30.48, 30.48), [8.5344, -21.9456]], + [90.0, (8.5344, 0.0), (-30.48, 30.48), [3.048, -27.432]], + [270.0, (28.0416, 3.048), (30.48, -30.48), [3.048, -27.432]], + [0.0, (28.0416, 0.0), (30.48, 30.48), [2.4384, -28.0416]], + [0.0, (0.0, 2.4384), (30.48, 30.48), [6.096, -24.384]], + [ + 85.0303, + (6.096, 2.4384), + (30.4797350376, 365.7600320503), + [28.14742656, -675.53802408], + ], + [ + 52.6961, + (6.096, 3.9624), + (-396.2395699236, -518.1603274067), + [8.04696384, -796.64814], + ], + [ + 18.4349, + (10.9728, 10.3632), + (60.9600132464, 30.4799513302), + [7.71089136, -88.6753116], + ], + [ + 341.5651, + (18.288, 12.8016), + (-60.9600132464, 30.4799513302), + [7.71089136, -88.6753116], + ], + [ + 307.3039, + (25.6032, 10.3632), + (396.2395699236, -518.1603274067), + [8.04696384, -796.64814], + ], + [ + 20.2249, + (12.4968, 8.2296), + (-335.2799166169, -121.920254069), + [6.1717428, -611.00122656], + ], + [ + 339.7751, + (18.288, 10.3632), + (335.2799166169, -121.920254069), + [6.1717428, -611.00122656], + ], + [ + 307.4054, + (24.0792, 8.2296), + (304.8003033557, -396.2397703326), + [6.52299432, -645.777474], + ], + [ + 52.5946, + (8.5344, 3.048), + (-304.8003033557, -396.2397703326), + [6.52299432, -645.777474], + ], + ], + "SQUARE": [ + [0.0, (0.0, 0.0), (0.0, 3.175), [3.175, -3.175]], + [90.0, (0.0, 0.0), (-3.175, 0.0), [3.175, -3.175]], + ], + "SQUARES": [ + [0.0, (0.0, 0.0), (0.0, 3.81), [3.81, -3.81]], + [90.0, (0.0, 0.0), (-3.81, 0.0), [3.81, -3.81]], + ], + "STARS": [ + [0.0, (0.0, 0.0), (0.0, 5.4992613154), [3.175, -3.175]], + [60.0, (0.0, 0.0), (-4.7625000012, 2.7496306577), [3.175, -3.175]], + [ + 120.0, + (1.5875, 2.7496306704), + (-4.7625000012, -2.7496306577), + [3.175, -3.175], + ], + ], + "STEEL": [ + [45.0, (0.0, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (4.318, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (4.572, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (4.826, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (5.08, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (5.334, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (5.588, 0.0), (-5.3881536726, 5.3881536726), []], + [45.0, (5.842, 0.0), (-5.3881536726, 5.3881536726), []], + ], + "SWAMP": [ + [0.0, (0.0, 0.0), (12.7, 21.9970452362), [3.175, -22.225]], + [90.0, (1.5875, 0.0), (-12.7, 21.9970452362), [1.5875, -42.4065904724]], + [90.0, (1.984375, 0.0), (-12.7, 21.9970452362), [1.27, -42.7240904724]], + [90.0, (1.190625, 0.0), (-12.7, 21.9970452362), [1.27, -42.7240904724]], + [60.0, (2.38125, 0.0), (-12.6999999827, 21.9970452462), [1.016, -24.384]], + [120.0, (0.79375, 0.0), (-25.3999999827, 1e-08), [1.016, -24.384]], + ], + "TILEPAT1": [ + [0.0, (5.7473088, 0.0), (24.384, 24.384), [37.2731792, -11.4948208]], + [90.0, (0.0, 5.7473088), (-24.384, 24.384), [37.2731792, -11.4948208]], + [ + 45.0, + (18.6366912, 24.384), + (-24.3840535245, 24.3840535245), + [8.128, -26.3562592], + ], + [ + 315.0, + (18.6366912, 24.384), + (24.3840535245, 24.3840535245), + [8.128, -26.3562592], + ], + [ + 45.0, + (24.384, 18.6366912), + (-24.3840535245, 24.3840535245), + [8.128, -26.3562592], + ], + [ + 315.0, + (24.384, 30.1313088), + (24.3840535245, 24.3840535245), + [8.128, -26.3562592], + ], + ], + "TRANS": [ + [0.0, (0.0, 0.0), (0.0, 6.35), []], + [0.0, (0.0, 3.175), (0.0, 6.35), [3.175, -3.175]], + ], + "TRIANG": [ + [60.0, (0.0, 0.0), (-4.7624999908, 8.2488919657), [4.7625, -4.7625]], + [120.0, (0.0, 0.0), (-9.5249999908, 5.3e-09), [4.7625, -4.7625]], + [0.0, (-2.38125, 4.1244459802), (4.7625, 8.2488919604), [4.7625, -4.7625]], + ], + "TRIANGLES": [ + [60.0, (0.0, 0.0), (-5.7149999889, 9.8986703589), [5.715, -5.715]], + [120.0, (0.0, 0.0), (-11.4299999889, 6.4e-09), [5.715, -5.715]], + [0.0, (-2.8575, 4.9493351762), (5.715, 9.8986703525), [5.715, -5.715]], + ], + "TRIHEX": [ + [30.0, (0.0, 0.0), (6.9e-09, 30.4799999881), [10.16, -20.32]], + [30.0, (-8.7988181148, 15.24), (6.9e-09, 30.4799999881), [10.16, -20.32]], + [90.0, (0.0, 20.32), (-26.3964542936, 15.24), [10.16, -20.32]], + [90.0, (17.5976362296, 20.32), (-26.3964542936, 15.24), [10.16, -20.32]], + [150.0, (0.0, 0.0), (-26.3964543005, -15.2399999881), [10.16, -20.32]], + [ + 150.0, + (-8.7988181148, 15.24), + (-26.3964543005, -15.2399999881), + [10.16, -20.32], + ], + ], + "V_BATTEN_FLOOR": [[0.0, (0.0, 0.0), (0.0, 15.0), []]], + "V_MASONRY200x100": [ + [0.0, (0.0, 0.0), (0.0, 10.0), []], + [90.0, (0.0, 0.0), (-10.0, 10.0), [10.0, -10.0]], + ], + "V_MASONRY200x60": [ + [0.0, (0.0, 0.0), (0.0, 6.0), []], + [90.0, (0.0, 0.0), (-10.0, 6.0), [6.0, -6.0]], + ], + "V_MASONRY200x75": [ + [0.0, (0.0, 0.0), (0.0, 7.5), []], + [90.0, (0.0, 0.0), (-10.0, 7.5), [7.5, -7.5]], + ], + "V_MASONRY220x80": [ + [0.0, (0.0, 0.0), (0.0, 8.0), []], + [90.0, (0.0, 0.0), (-11.0, 8.0), [8.0, -8.0]], + ], + "V_MASONRY300x100": [ + [0.0, (0.0, 0.0), (0.0, 10.0), []], + [90.0, (0.0, 0.0), (-15.0, 10.0), [10.0, -10.0]], + ], + "V_MASONRY300x150": [ + [0.0, (0.0, 0.0), (0.0, 15.0), []], + [90.0, (0.0, 0.0), (-15.0, 15.0), [15.0, -15.0]], + ], + "V_MASONRY300x200": [ + [0.0, (0.0, 0.0), (0.0, 20.0), []], + [90.0, (0.0, 0.0), (-15.0, 20.0), [20.0, -20.0]], + ], + "V_MASONRY300x75": [ + [0.0, (0.0, 0.0), (0.0, 7.5), []], + [90.0, (0.0, 0.0), (-15.0, 7.5), [7.5, -7.5]], + ], + "V_MASONRY400x100": [ + [0.0, (0.0, 0.0), (0.0, 10.0), []], + [90.0, (0.0, 0.0), (-20.0, 10.0), [10.0, -10.0]], + ], + "V_MASONRY400x200": [ + [0.0, (0.0, 0.0), (0.0, 20.0), []], + [90.0, (0.0, 0.0), (-20.0, 20.0), [20.0, -20.0]], + ], + "V_PARQUET": [[0.0, (0.0, 0.0), (0.0, 15.0), []]], + "V_STANDING_SEAM": [ + [90.0, (0.0, 0.0), (-55.0, 0.0), []], + [90.0, (2.0, 0.0), (-55.0, 0.0), []], + ], + "V_ZINC": [ + [90.0, (0.0, 0.0), (-40.0, 0.0), []], + [90.0, (0.0, 2.0), (-40.0, 0.0), []], + ], + "WAFFLE": [ + [0.0, (8.89, 6.35), (0.0, 15.24), [12.7, -2.54]], + [0.0, (8.89, 8.89), (0.0, 15.24), [12.7, -2.54]], + [90.0, (6.35, 8.89), (-15.24, 0.0), [12.7, -2.54]], + [90.0, (8.89, 8.89), (-15.24, 0.0), [12.7, -2.54]], + ], + "WATER": [ + [0.0, (0.0, 0.0), (0.0, 20.32), [4.064, -16.256]], + [45.0, (8.128, 2.032), (0.0, 20.3200000004), [5.747363918, -22.989455672]], + [135.0, (16.256, 2.032), (-20.3200000004, 0.0), [5.747363918, -22.989455672]], + [ + 26.5650512, + (4.064, 0.0), + (20.3199999955, 1.72e-08), + [4.543552, -40.8933492926], + ], + [ + 333.4349488, + (16.256, 2.032), + (20.3199999955, -1.72e-08), + [4.543552, -40.8933492926], + ], + ], + "WOOD1": [ + [216.8699, (8.128, 20.32), (60.9599983302, 40.6400025047), [10.16, -91.44]], + [ + 206.5651, + (20.32, 14.224), + (-20.3199828894, -20.3200266069), + [22.71845088, -22.71845088], + ], + [ + 198.4349, + (20.32, 4.064), + (-40.6400088309, -20.3199675535), + [12.85150592, -51.40598304], + ], + ], + "WOOD2": [ + [ + 108.4349, + (5.2832, 0.0), + (-20.3199675535, 40.6400088309), + [7.71089136, -56.54657728], + ], + [ + 139.3987, + (2.8448, 7.3152), + (-121.9199800489, 101.6000085595), + [3.74682512, -183.59432928], + ], + [ + 136.8476, + (20.32, 9.7536), + (-304.7999499622, 284.4800575845), + [8.91304288, -436.73934496], + ], + [ + 109.9831, + (13.8176, 15.8496), + (-60.9599889052, 162.5600133871), + [4.75679008, -233.08271392], + ], + [90.0, (12.192, 0.0), (-20.32, 20.32), [4.064, -16.256]], + [ + 118.4429, + (12.192, 4.064), + (142.2398748065, -264.1600765238), + [11.09256608, -543.53549408], + ], + [ + 84.2894, + (6.9088, 13.8176), + (-20.320026714, -182.8799882854), + [4.08427936, -200.12920096], + ], + [ + 129.8056, + (7.3152, 17.8816), + (81.2800494301, -101.5999606056), + [3.1740856, -155.5301944], + ], + ], + "WOOD3": [ + [ + 355.2364, + (0.0, 9.4996), + (-614.6800528803, 55.8795268451), + [6.72884608, -666.15548252], + ], + [ + 11.3099, + (6.7056, 8.9408), + (223.5200420347, 55.8798676852), + [8.54801948, -276.38521812], + ], + [45.0, (15.0876, 10.6172), (0.0, 55.880017292), [6.32209556, -72.70412688]], + [ + 46.8476, + (19.558, 15.0876), + (782.3201583573, 838.199862396), + [12.25543396, -1213.2886326], + ], + [ + 12.9946, + (27.94, 24.0284), + (-502.9200429018, -111.7598646351), + [7.45534196, -738.07684236], + ], + [0.0, (35.2044, 25.7048), (55.88, 55.88), [13.97, -41.91]], + [ + 350.5377, + (49.1744, 25.7048), + (-279.4000432341, 55.8798960186), + [6.7980814, -333.10665916], + ], + [ + 354.2894, + (0.0, 24.5872), + (-502.9199677849, 55.8800734636), + [5.61588412, -555.97118676], + ], + [0.0, (5.588, 24.0284), (55.88, 55.88), [8.382, -47.498]], + [ + 28.3008, + (13.97, 24.0284), + (614.6797272924, 335.2804958908), + [8.25057024, -816.807739], + ], + [ + 52.125, + (21.2344, 27.94), + (-223.5201042102, -279.3999496738), + [12.7425958, -624.38741772], + ], + [ + 39.2894, + (29.0576, 37.9984), + (335.2800357399, 279.3999794311), + [7.94205676, -786.26199872], + ], + [ + 6.3402, + (35.2044, 43.0276), + (447.0399666176, 55.8800882323), + [10.12031504, -495.89459876], + ], + [ + 348.1113, + (45.2628, 44.1452), + (-782.3198491826, 167.6405887097), + [10.8499402, -1074.14340924], + ], + [ + 353.2902, + (0.0, 41.91), + (502.9200557543, -55.8796580839), + [9.56509136, -946.9463916], + ], + [ + 3.3665, + (9.4996, 40.7924), + (894.0799621116, 55.8806126322), + [9.51602872, -942.08611684], + ], + [ + 33.6901, + (18.9992, 41.3512), + (-111.7599752883, -55.8800745723), + [10.07393464, -191.40431112], + ], + [ + 47.4896, + (27.3812, 46.9392), + (558.7994813412, 614.6804846959), + [9.09659344, -900.56386816], + ], + [ + 14.9314, + (33.528, 53.6448), + (614.6800298916, 167.6398297883), + [8.67492296, -858.81597604], + ], + [0.0, (41.91, 55.88), (55.88, 55.88), [6.7056, -49.1744]], + [ + 347.0054, + (48.6156, 55.88), + (502.9200429018, -111.7598646351), + [7.45534196, -738.07684236], + ], + [0.0, (17.3228, 0.0), (55.88, 55.88), [0.0, -55.88]], + [ + 223.1524, + (25.146, 8.382), + (838.199862396, 782.3201583573), + [12.25543396, -1213.2886326], + ], + [ + 206.5651, + (16.2052, 55.88), + (-55.8799529457, -55.8800731691), + [4.99807484, -119.953405], + ], + [ + 188.1301, + (11.7348, 53.6448), + (-335.2799875086, -55.879964003), + [7.90260548, -387.22861848], + ], + [ + 156.8014, + (3.9116, 52.5272), + (-279.3999849497, 111.7600740558), + [4.25570904, -421.3136862], + ], + [ + 26.5651, + (25.146, 8.382), + (55.8799529457, 55.8800731691), + [6.24755164, -118.7039282], + ], + [ + 6.7098, + (30.734, 11.176), + (-502.9200557543, -55.8796580839), + [9.56509136, -946.9463916], + ], + [ + 349.8753, + (40.2336, 12.2936), + (949.9599323656, -167.6404799319), + [15.89389252, -1573.49675648], + ], + [ + 349.6952, + (0.0, 3.3528), + (335.2800536922, -55.879713645), + [6.24755164, -618.50979168], + ], + [ + 15.5241, + (6.1468, 2.2352), + (-614.6800572563, -167.6398758126), + [10.4392222, -1033.48528888], + ], + [ + 42.8789, + (16.2052, 5.0292), + (-726.4400443095, -670.5599862115), + [10.675874, -1056.91001724], + ], + [ + 34.6952, + (24.0284, 12.2936), + (558.7996791922, 391.1604811041), + [8.83541032, -874.70495112], + ], + [ + 9.4623, + (31.2928, 17.3228), + (279.4000432341, 55.8798960186), + [10.19715004, -329.7076464], + ], + [ + 353.4181, + (41.3512, 18.9992), + (-949.9600803515, 111.7592568165), + [14.625193, -1447.8943864], + ], + [ + 351.8699, + (0.0, 17.3228), + (-335.2799875086, 55.879964003), + [7.90260548, -387.22861848], + ], + [ + 11.3099, + (7.8232, 16.2052), + (223.5200420347, 55.8798676852), + [8.54801948, -276.38521812], + ], + [ + 42.5104, + (16.2052, 17.8816), + (-614.6804846959, -558.7994813412), + [9.09659344, -900.56386816], + ], + [45.0, (22.9108, 24.0284), (0.0, 55.880017292), [10.27342624, -68.75285208]], + [ + 17.354, + (30.1752, 31.2928), + (-726.4401128271, -223.5196927862), + [9.36722028, -927.35229312], + ], + [ + 356.6335, + (39.116, 34.0868), + (-894.0799621116, 55.8806126322), + [9.51602872, -942.08611684], + ], + [ + 342.8973, + (48.6156, 33.528), + (558.8000967259, -167.6397481729), + [7.6005182, -752.44968128], + ], + [ + 351.2538, + (0.0, 31.2928), + (391.1599629156, -55.8802345316), + [7.34984052, -727.63678196], + ], + [ + 14.9314, + (7.2644, 30.1752), + (614.6800298916, 167.6398297883), + [8.67492296, -858.81597604], + ], + [ + 32.0054, + (15.6464, 32.4104), + (-279.3999410347, -167.6400617685), + [10.5434384, -516.62747576], + ], + [ + 49.8991, + (24.5872, 37.9984), + (-614.6798915808, -726.440107823), + [13.8803126, -1374.1501092], + ], + [ + 15.9454, + (33.528, 48.6156), + (-223.5200070773, -55.8799938139), + [8.13623976, -398.67630704], + ], + [ + 353.991, + (41.3512, 50.8508), + (558.7999860806, -55.8799618609), + [10.675874, -1056.91001724], + ], + [ + 336.8014, + (51.9684, 49.7332), + (279.3999849497, -111.7600740558), + [4.25570904, -421.3136862], + ], + [ + 350.5377, + (0.0, 48.0568), + (-279.4000432341, 55.8798960186), + [6.7980814, -333.10665916], + ], + [ + 10.008, + (6.7056, 46.9392), + (614.6799751096, 111.7601940241), + [9.64639676, -954.991994], + ], + [ + 37.4054, + (16.2052, 48.6156), + (726.4395789431, 558.8005561521), + [11.95882292, -1183.925369], + ], + [ + 29.0546, + (25.7048, 0.0), + (391.1600214898, 223.5200015199), + [5.75318128, -569.56662312], + ], + [ + 10.7843, + (30.734, 2.794), + (-894.0799722664, -167.6400307161), + [11.94580288, -1182.63219404], + ], + [ + 352.875, + (42.4688, 5.0292), + (-391.1600212258, 55.8799039922), + [13.51558384, -437.0033932], + ], + ], + "WOOD4": [ + [ + 349.6952, + (17.3228, 43.0276), + (335.2800536922, -55.879713645), + [6.24755164, -618.50979168], + ], + [0.0, (23.4696, 41.91), (55.88, 55.88), [6.1468, -49.7332]], + [ + 18.4349, + (29.6164, 41.91), + (111.7600242851, 55.8799107721), + [5.30122384, -171.40681492], + ], + [ + 172.875, + (34.6456, 43.5864), + (391.1600212258, -55.8799039922), + [4.50521324, -446.0137638], + ], + [ + 174.8056, + (30.1752, 44.1452), + (558.8000374421, -55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 194.0362, + (24.0284, 44.704), + (-167.6400305099, -55.8798914453), + [6.91196484, -223.48714256], + ], + [ + 9.4623, + (21.7932, 43.0276), + (279.4000432341, 55.8798960186), + [3.39906864, -336.5057278], + ], + [ + 353.6598, + (25.146, 43.5864), + (-447.0399666176, 55.8800882323), + [5.06015752, -500.95475628], + ], + [ + 185.7106, + (30.1752, 43.0276), + (-502.9199677849, -55.8800734636), + [5.61588412, -555.97118676], + ], + [ + 168.6901, + (24.5872, 42.4688), + (223.5200420347, -55.8798676852), + [2.8493212, -282.08386052], + ], + [ + 354.8056, + (12.2936, 42.4688), + (-558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 348.6901, + (18.4404, 41.91), + (-223.5200420347, 55.8798676852), + [5.6986424, -279.23453932], + ], + [0.0, (24.0284, 40.7924), (55.88, 55.88), [6.7056, -49.1744]], + [ + 20.556, + (30.734, 40.7924), + (279.400103073, 111.75977628), + [4.7743872, -472.66455632], + ], + [ + 3.8141, + (35.2044, 42.4688), + (782.3199632, 55.8803422077), + [8.40060804, -831.65997244], + ], + [ + 354.8056, + (43.5864, 43.0276), + (-558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [0.0, (49.7332, 42.4688), (55.88, 55.88), [6.1468, -49.7332]], + [ + 5.1944, + (0.0, 42.4688), + (558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 354.8056, + (6.1468, 43.0276), + (-558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [0.0, (0.0, 43.5864), (55.88, 55.88), [3.3528, -52.5272]], + [ + 5.1944, + (3.3528, 43.5864), + (558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [0.0, (9.4996, 44.1452), (55.88, 55.88), [5.588, -50.292]], + [ + 10.3048, + (15.0876, 44.1452), + (-335.2800536922, -55.879713645), + [6.24755164, -618.50979168], + ], + [ + 5.1944, + (21.2344, 45.2628), + (558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 354.8056, + (27.3812, 45.8216), + (-558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 354.8056, + (33.528, 45.2628), + (-558.8000374421, 55.8797331562), + [6.17216952, -611.04260316], + ], + [ + 351.8699, + (39.6748, 44.704), + (-335.2799875086, 55.879964003), + [7.90260548, -387.22861848], + ], + [0.0, (47.498, 43.5864), (55.88, 55.88), [8.382, -47.498]], + [ + 347.4712, + (45.2628, 10.0584), + (279.4000179045, -55.8799778181), + [5.1518566, -510.03626212], + ], + [ + 354.2894, + (50.292, 8.9408), + (-502.9199677849, 55.8800734636), + [5.61588412, -555.97118676], + ], + [ + 8.1301, + (45.2628, 10.0584), + (335.2799875086, 55.879964003), + [3.95133068, -391.17994916], + ], + [ + 9.4623, + (49.1744, 10.6172), + (279.4000432341, 55.8798960186), + [6.7980814, -333.10665916], + ], + [0.0, (0.0, 11.7348), (55.88, 55.88), [6.7056, -49.1744]], + [ + 350.5377, + (6.7056, 11.7348), + (-279.4000432341, 55.8798960186), + [3.39906864, -336.5057278], + ], + [ + 201.8014, + (10.0584, 11.176), + (167.6400152558, 55.8799949988), + [3.00924976, -297.91377044], + ], + [ + 192.9946, + (7.2644, 10.0584), + (502.9200429018, 111.7598646351), + [7.45534196, -738.07684236], + ], + [ + 352.875, + (51.4096, 10.0584), + (-391.1600212258, 55.8799039922), + [4.50521324, -446.0137638], + ], + [ + 7.125, + (51.4096, 10.0584), + (391.1600212258, 55.8799039922), + [4.50521324, -446.0137638], + ], + [0.0, (0.0, 10.6172), (55.88, 55.88), [4.4704, -51.4096]], + [ + 194.0362, + (4.4704, 10.6172), + (-167.6400305099, -55.8798914453), + [4.60797656, -225.79118672], + ], + [ + 356.6335, + (12.2936, 12.2936), + (-894.0799621116, 55.8806126322), + [9.51602872, -942.08611684], + ], + [ + 357.7094, + (21.7932, 11.7348), + (-1341.1200072183, 55.8797626847), + [13.981176, -1384.13597696], + ], + [ + 3.1798, + (35.7632, 11.176), + (949.9600280908, 55.8794994452), + [10.07393464, -997.31712652], + ], + [ + 9.4623, + (45.8216, 11.7348), + (279.4000432341, 55.8798960186), + [10.19715004, -329.7076464], + ], + [ + 10.3048, + (0.0, 6.7056), + (-335.2800536922, -55.879713645), + [6.24755164, -618.50979168], + ], + [ + 15.9454, + (6.1468, 7.8232), + (-223.5200070773, -55.8799938139), + [8.13623976, -398.67630704], + ], + [0.0, (13.97, 10.0584), (55.88, 55.88), [7.2644, -48.6156]], + [ + 351.8699, + (21.2344, 10.0584), + (-335.2799875086, 55.879964003), + [7.90260548, -387.22861848], + ], + [ + 3.5763, + (29.0576, 8.9408), + (838.2000365642, 55.8794812845), + [8.95823456, -886.86628316], + ], + [ + 351.2538, + (37.9984, 9.4996), + (391.1599629156, -55.8802345316), + [7.34984052, -727.63678196], + ], + [ + 345.9638, + (45.2628, 8.382), + (-167.6400305099, 55.8798914453), + [6.91196484, -223.48714256], + ], + [0.0, (51.9684, 6.7056), (55.88, 55.88), [3.9116, -51.9684]], + [ + 174.8056, + (12.2936, 12.2936), + (558.8000374421, -55.8797331562), + [12.34428316, -604.87048952], + ], + [ + 355.2364, + (0.0, 15.6464), + (-614.6800528803, 55.8795268451), + [13.45769216, -659.42663644], + ], + [0.0, (13.4112, 14.5288), (55.88, 55.88), [12.8524, -43.0276]], + [ + 4.0856, + (26.2636, 14.5288), + (726.4400083269, 55.879783876), + [15.68624244, -768.6268854], + ], + [0.0, (41.91, 15.6464), (55.88, 55.88), [13.97, -41.91]], + [ + 7.125, + (0.0, 3.9116), + (391.1600212258, 55.8799039922), + [13.51558384, -437.0033932], + ], + [ + 6.3402, + (13.4112, 5.588), + (447.0399666176, 55.8800882323), + [10.12031504, -495.89459876], + ], + [ + 357.5104, + (23.4696, 6.7056), + (-1229.3599709259, 55.8809983113), + [12.86452596, -1273.58969056], + ], + [ + 353.4802, + (36.322, 6.1468), + (-1452.879988314, 167.6399734706), + [19.68529464, -1948.84584576], + ], + [ + 3.0128, + (0.0, 40.2336), + (1005.8400006536, 55.8802293806), + [10.63189644, -1052.5576358], + ], + [ + 351.8699, + (10.6172, 40.7924), + (-335.2799875086, 55.879964003), + [11.85393616, -383.27734368], + ], + [ + 357.6141, + (22.352, 39.116), + (-1285.2400292741, 55.8790372189), + [13.42282304, -1328.86082208], + ], + [ + 10.6197, + (35.7632, 38.5572), + (-614.6799108501, -111.7604516847), + [9.09659344, -900.56386816], + ], + [0.0, (44.704, 40.2336), (55.88, 55.88), [11.176, -44.704]], + [ + 356.8202, + (0.0, 46.9392), + (-949.9600280908, 55.8794994452), + [10.07393464, -997.31712652], + ], + [ + 6.009, + (10.0584, 46.3804), + (-558.7999860806, -55.8799618609), + [10.675874, -1056.91001724], + ], + [ + 6.7098, + (20.6756, 47.498), + (-502.9200557543, -55.8796580839), + [9.56509136, -946.9463916], + ], + [ + 354.2894, + (30.1752, 48.6156), + (-502.9199677849, 55.8800734636), + [11.23176824, -550.35530264], + ], + [ + 347.9052, + (41.3512, 47.498), + (-502.9199218582, 111.7603762673), + [8.00078664, -792.07905084], + ], + [ + 9.4623, + (49.1744, 45.8216), + (279.4000432341, 55.8798960186), + [6.7980814, -333.10665916], + ], + [ + 3.8141, + (0.0, 36.322), + (782.3199632, 55.8803422077), + [8.40060804, -831.65997244], + ], + [ + 347.1957, + (8.382, 36.8808), + (-726.4398796839, 167.6404128232), + [12.6070868, -1248.10315784], + ], + [0.0, (20.6756, 34.0868), (55.88, 55.88), [13.97, -41.91]], + [ + 5.4403, + (34.6456, 34.0868), + (-614.6800174462, -55.879629585), + [11.787886, -1167.00199924], + ], + [ + 6.7098, + (46.3804, 35.2044), + (-502.9200557543, -55.8796580839), + [9.56509136, -946.9463916], + ], + [0.0, (0.0, 50.8508), (55.88, 55.88), [9.4996, -46.3804]], + [ + 8.1301, + (9.4996, 50.8508), + (335.2799875086, 55.879964003), + [15.80526684, -379.326013], + ], + [ + 357.6141, + (25.146, 53.086), + (-1285.2400292741, 55.8790372189), + [13.42282304, -1328.86082208], + ], + [ + 354.4725, + (38.5572, 52.5272), + (1173.4800960801, -111.7591830157), + [17.40371424, -1722.968995], + ], + [ + 6.8428, + (0.0, 0.0), + (-949.9599645429, -111.760446924), + [14.07024872, -1392.95222044], + ], + [0.0, (13.97, 1.6764), (55.88, 55.88), [15.6464, -40.2336]], + [ + 356.3478, + (29.6164, 1.6764), + (-1732.280052651, 111.7592902418), + [26.31702128, -2605.38773308], + ], + [0.0, (0.0, 19.558), (55.88, 55.88), [13.4112, -42.4688]], + [ + 4.7636, + (13.4112, 19.558), + (614.6800528803, 55.8795268451), + [13.45769216, -659.42663644], + ], + [ + 358.1524, + (26.8224, 20.6756), + (-1676.4000259456, 55.8796837064), + [17.33179668, -1715.84926832], + ], + [ + 357.2737, + (44.1452, 20.1168), + (-1117.6000164831, 55.8797774706), + [11.74809944, -1163.06162104], + ], + [ + 354.8056, + (0.0, 28.4988), + (-558.8000374421, 55.8797331562), + [12.34428316, -604.87048952], + ], + [0.0, (12.2936, 27.3812), (55.88, 55.88), [17.8816, -37.9984]], + [ + 1.9092, + (30.1752, 27.3812), + (1620.5199458846, 55.8813545915), + [16.77333196, -1660.5577406], + ], + [ + 3.5763, + (46.9392, 27.94), + (838.2000365642, 55.8794812845), + [8.95823456, -886.86628316], + ], + ], + "ZIGZAG": [ + [0.0, (0.0, 0.0), (6.35, 6.35), [6.35, -6.35]], + [90.0, (6.35, 0.0), (-6.35, 6.35), [6.35, -6.35]], + ], +} diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/analyze.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/analyze.py new file mode 100644 index 0000000..e7842b2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/analyze.py @@ -0,0 +1,576 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +# Debugging tools to analyze DXF entities. +from __future__ import annotations +from typing import Iterable, Sequence, Optional +import textwrap + +import ezdxf +from ezdxf import colors +from ezdxf.math import Vec2 +from ezdxf.lldxf import const +from ezdxf.enums import TextEntityAlignment +from ezdxf.tools.debug import print_bitmask +from ezdxf.render.mleader import MLeaderStyleOverride, OVERRIDE_FLAG +from ezdxf.entities import ( + EdgePath, + PolylinePath, + LineEdge, + ArcEdge, + EllipseEdge, + SplineEdge, + mleader, +) +from ezdxf.entities.polygon import DXFPolygon + +EDGE_START_MARKER = "EDGE_START_MARKER" +EDGE_END_MARKER = "EDGE_END_MARKER" +HATCH_LAYER = "HATCH" +POLYLINE_LAYER = "POLYLINE_MARKER" +LINE_LAYER = "LINE_MARKER" +ARC_LAYER = "ARC_MARKER" +ELLIPSE_LAYER = "ELLIPSE_MARKER" +SPLINE_LAYER = "SPLINE_MARKER" + + +class HatchAnalyzer: + def __init__( + self, + *, + marker_size: float = 1.0, + angle: float = 45, + ): + self.marker_size = marker_size + self.angle = angle + self.doc = ezdxf.new() + self.msp = self.doc.modelspace() + self.init_layers() + self.init_markers() + + def init_layers(self): + self.doc.layers.add(POLYLINE_LAYER, color=colors.YELLOW) + self.doc.layers.add(LINE_LAYER, color=colors.RED) + self.doc.layers.add(ARC_LAYER, color=colors.GREEN) + self.doc.layers.add(ELLIPSE_LAYER, color=colors.MAGENTA) + self.doc.layers.add(SPLINE_LAYER, color=colors.CYAN) + self.doc.layers.add(HATCH_LAYER) + + def init_markers(self): + blk = self.doc.blocks.new(EDGE_START_MARKER) + attribs = {"layer": "0"} # from INSERT + radius = self.marker_size / 2.0 + height = radius + + # start marker: 0-- name + blk.add_circle( + center=(0, 0), + radius=radius, + dxfattribs=attribs, + ) + text_start = radius * 4 + blk.add_line( + start=(radius, 0), + end=(text_start - radius / 2.0, 0), + dxfattribs=attribs, + ) + text = blk.add_attdef( + tag="NAME", + dxfattribs=attribs, + ) + text.dxf.height = height + text.set_placement( + (text_start, 0), align=TextEntityAlignment.MIDDLE_LEFT + ) + + # end marker: name --X + blk = self.doc.blocks.new(EDGE_END_MARKER) + attribs = {"layer": "0"} # from INSERT + blk.add_line( + start=(-radius, -radius), + end=(radius, radius), + dxfattribs=attribs, + ) + blk.add_line( + start=(-radius, radius), + end=(radius, -radius), + dxfattribs=attribs, + ) + text_start = -radius * 4 + blk.add_line( + start=(-radius, 0), + end=(text_start + radius / 2.0, 0), + dxfattribs=attribs, + ) + text = blk.add_attdef( + tag="NAME", + dxfattribs=attribs, + ) + text.dxf.height = height + text.set_placement( + (text_start, 0), align=TextEntityAlignment.MIDDLE_RIGHT + ) + + def export(self, name: str) -> None: + self.doc.saveas(name) + + def add_hatch(self, hatch: DXFPolygon) -> None: + hatch.dxf.discard("extrusion") + hatch.dxf.layer = HATCH_LAYER + self.msp.add_foreign_entity(hatch) + + def add_boundary_markers(self, hatch: DXFPolygon) -> None: + hatch.dxf.discard("extrusion") + path_num: int = 0 + + for p in hatch.paths: + path_num += 1 + if isinstance(p, PolylinePath): + self.add_polyline_markers(p, path_num) + elif isinstance(p, EdgePath): + self.add_edge_markers(p, path_num) + else: + raise TypeError(f"unknown boundary path type: {type(p)}") + + def add_start_marker(self, location: Vec2, name: str, layer: str) -> None: + self.add_marker(EDGE_START_MARKER, location, name, layer) + + def add_end_marker(self, location: Vec2, name: str, layer: str) -> None: + self.add_marker(EDGE_END_MARKER, location, name, layer) + + def add_marker( + self, blk_name: str, location: Vec2, name: str, layer: str + ) -> None: + blkref = self.msp.add_blockref( + name=blk_name, + insert=location, + dxfattribs={ + "layer": layer, + "rotation": self.angle, + }, + ) + blkref.add_auto_attribs({"NAME": name}) + + def add_polyline_markers(self, p: PolylinePath, num: int) -> None: + self.add_start_marker( + Vec2(p.vertices[0]), f"Poly-S({num})", POLYLINE_LAYER + ) + self.add_end_marker( + Vec2(p.vertices[0]), f"Poly-E({num})", POLYLINE_LAYER + ) + + def add_edge_markers(self, p: EdgePath, num: int) -> None: + edge_num: int = 0 + for edge in p.edges: + edge_num += 1 + name = f"({num}.{edge_num})" + if isinstance( + edge, + LineEdge, + ): + self.add_line_edge_markers(edge, name) + elif isinstance(edge, ArcEdge): + self.add_arc_edge_markers(edge, name) + elif isinstance(edge, EllipseEdge): + self.add_ellipse_edge_markers(edge, name) + elif isinstance(edge, SplineEdge): + self.add_spline_edge_markers(edge, name) + else: + raise TypeError(f"unknown edge type: {type(edge)}") + + def add_line_edge_markers(self, line: LineEdge, name: str) -> None: + self.add_start_marker(line.start, "Line-S" + name, LINE_LAYER) + self.add_end_marker(line.end, "Line-E" + name, LINE_LAYER) + + def add_arc_edge_markers(self, arc: ArcEdge, name: str) -> None: + self.add_start_marker(arc.start_point, "Arc-S" + name, ARC_LAYER) + self.add_end_marker(arc.end_point, "Arc-E" + name, ARC_LAYER) + + def add_ellipse_edge_markers(self, ellipse: EllipseEdge, name: str) -> None: + self.add_start_marker( + ellipse.start_point, "Ellipse-S" + name, ELLIPSE_LAYER + ) + self.add_end_marker( + ellipse.end_point, "Ellipse-E" + name, ELLIPSE_LAYER + ) + + def add_spline_edge_markers(self, spline: SplineEdge, name: str) -> None: + if len(spline.control_points): + # Assuming a clamped B-spline, because this is the only practical + # usable B-spline for edges. + self.add_start_marker( + spline.start_point, "SplineS" + name, SPLINE_LAYER + ) + self.add_end_marker( + spline.end_point, "SplineE" + name, SPLINE_LAYER + ) + + @staticmethod + def report(hatch: DXFPolygon) -> list[str]: + return hatch_report(hatch) + + @staticmethod + def print_report(hatch: DXFPolygon) -> None: + print("\n".join(hatch_report(hatch))) + + +def hatch_report(hatch: DXFPolygon) -> list[str]: + dxf = hatch.dxf + style = const.ISLAND_DETECTION[dxf.hatch_style] + pattern_type = const.HATCH_PATTERN_TYPE[dxf.pattern_type] + text = [ + f"{str(hatch)}", + f" solid fill: {bool(dxf.solid_fill)}", + f" pattern type: {pattern_type}", + f" pattern name: {dxf.pattern_name}", + f" associative: {bool(dxf.associative)}", + f" island detection: {style}", + f" has pattern data: {hatch.pattern is not None}", + f" has gradient data: {hatch.gradient is not None}", + f" seed value count: {len(hatch.seeds)}", + f" boundary path count: {len(hatch.paths)}", + ] + num = 0 + for path in hatch.paths: + num += 1 + if isinstance(path, PolylinePath): + text.extend(polyline_path_report(path, num)) + elif isinstance(path, EdgePath): + text.extend(edge_path_report(path, num)) + return text + + +def polyline_path_report(p: PolylinePath, num: int) -> list[str]: + path_type = ", ".join(const.boundary_path_flag_names(p.path_type_flags)) + return [ + f"{num}. Polyline Path, vertex count: {len(p.vertices)}", + f" path type: {path_type}", + ] + + +def edge_path_report(p: EdgePath, num: int) -> list[str]: + closed = False + connected = False + path_type = ", ".join(const.boundary_path_flag_names(p.path_type_flags)) + edges = p.edges + if len(edges): + closed = edges[0].start_point.isclose(edges[-1].end_point) + connected = all( + e1.end_point.isclose(e2.start_point) + for e1, e2 in zip(edges, edges[1:]) + ) + + return [ + f"{num}. Edge Path, edge count: {len(p.edges)}", + f" path type: {path_type}", + f" continuously connected edges: {connected}", + f" closed edge loop: {closed}", + ] + + +MULTILEADER = "MULTILEADER_MARKER" +POINT_MARKER = "POINT_MARKER" + + +class MultileaderAnalyzer: + """Multileader can not be added as foreign entity to a new document. + Annotations have to be added to the source document. + + """ + + def __init__( + self, + multileader: mleader.MultiLeader, + *, + marker_size: float = 1.0, + report_width: int = 79, + ): + self.marker_size = marker_size + self.report_width = report_width + self.multileader = multileader + assert self.multileader.doc is not None, "valid DXF document required" + self.doc = self.multileader.doc + self.msp = self.doc.modelspace() + self.init_layers() + self.init_markers() + + def init_layers(self): + if self.doc.layers.has_entry(MULTILEADER): + return + self.doc.layers.add(MULTILEADER, color=colors.RED) + + def init_markers(self): + if POINT_MARKER not in self.doc.blocks: + blk = self.doc.blocks.new(POINT_MARKER) + attribs = {"layer": "0"} # from INSERT + size = self.marker_size + size_2 = size / 2.0 + radius = size / 4.0 + blk.add_circle( + center=(0, 0), + radius=radius, + dxfattribs=attribs, + ) + blk.add_line((-size_2, 0), (size_2, 0), dxfattribs=attribs) + blk.add_line((0, -size_2), (0, size_2), dxfattribs=attribs) + + @property + def context(self) -> mleader.MLeaderContext: + return self.multileader.context + + @property + def mleaderstyle(self) -> Optional[mleader.MLeaderStyle]: + handle = self.multileader.dxf.get("style_handle") + return self.doc.entitydb.get(handle) # type: ignore + + def divider_line(self, symbol="-") -> str: + return symbol * self.report_width + + def shorten_lines(self, lines: Iterable[str]) -> list[str]: + return [ + textwrap.shorten(line, width=self.report_width) for line in lines + ] + + def report(self) -> list[str]: + report = [ + str(self.multileader), + self.divider_line(), + "Existing DXF attributes:", + self.divider_line(), + ] + report.extend(self.multileader_attributes()) + report.extend(self.context_attributes()) + if self.context.mtext is not None: + report.extend(self.mtext_attributes()) + if self.context.block is not None: + report.extend(self.block_attributes()) + if self.multileader.block_attribs: + report.extend(self.block_reference_attribs()) + if self.multileader.context.leaders: + report.extend(self.leader_attributes()) + if self.multileader.arrow_heads: + report.extend(self.arrow_heads()) + return self.shorten_lines(report) + + def print_report(self) -> None: + width = self.report_width + print() + print("=" * width) + print("\n".join(self.report())) + print("=" * width) + + def print_overridden_properties(self): + print("\n".join(self.overridden_attributes())) + + def overridden_attributes(self) -> list[str]: + multileader = self.multileader + style = self.mleaderstyle + if style is not None: + report = [ + self.divider_line(), + f"Override attributes of {str(style)}: '{style.dxf.name}'", + self.divider_line(), + ] + + override = MLeaderStyleOverride(style, multileader) + for name in OVERRIDE_FLAG.keys(): + if override.is_overridden(name): + report.append(f"{name}: {override.get(name)}") + if override.use_mtext_default_content: + report.append("use_mtext_default_content: 1") + else: + handle = self.multileader.dxf.get("style_handle") + report = [ + self.divider_line(), + f"MLEADERSTYLE(#{handle}) not found", + ] + return report + + def multileader_attributes(self) -> list[str]: + attribs = self.multileader.dxf.all_existing_dxf_attribs() + keys = sorted(attribs.keys()) + return [f"{key}: {attribs[key]}" for key in keys] + + def print_override_state(self): + flags = self.multileader.dxf.property_override_flags + print(f"\nproperty_override_flags:") + print(f"dec: {flags}") + print(f"hex: {hex(flags)}") + print_bitmask(flags) + + def print_context_attributes(self): + print("\n".join(self.context_attributes())) + + def context_attributes(self) -> list[str]: + context = self.context + if context is None: + return [] + report = [ + self.divider_line(), + "CONTEXT object attributes:", + self.divider_line(), + f"has MTEXT content: {yes_or_no(context.mtext)}", + f"has BLOCK content: {yes_or_no(context.block)}", + self.divider_line(), + ] + keys = [ + key + for key in context.__dict__.keys() + if key not in ("mtext", "block", "leaders") + ] + attributes = [f"{name}: {getattr(context, name)}" for name in keys] + attributes.sort() + report.extend(attributes) + return self.shorten_lines(report) + + def print_mtext_attributes(self): + print("\n".join(self.mtext_attributes())) + + def mtext_attributes(self) -> list[str]: + report = [ + self.divider_line(), + "MTEXT content attributes:", + self.divider_line(), + ] + mtext = self.context.mtext + if mtext is not None: + report.extend(_content_attributes(mtext)) + return self.shorten_lines(report) + + def print_block_attributes(self): + print("\n".join(self.block_attributes())) + + def block_attributes(self) -> list[str]: + report = [ + self.divider_line(), + "BLOCK content attributes:", + self.divider_line(), + ] + block = self.context.block + if block is not None: + report.extend(_content_attributes(block)) + return self.shorten_lines(report) + + def print_leader_attributes(self): + print("\n".join(self.leader_attributes())) + + def leader_attributes(self) -> list[str]: + report = [] + leaders = self.context.leaders + if leaders is not None: + for index, leader in enumerate(leaders): + report.extend(self._leader_attributes(index, leader)) + return self.shorten_lines(report) + + def _leader_attributes( + self, index: int, leader: mleader.LeaderData + ) -> list[str]: + report = [ + self.divider_line(), + f"{index+1}. LEADER attributes:", + self.divider_line(), + ] + report.extend(_content_attributes(leader, exclude=("lines", "breaks"))) + s = ", ".join(map(str, leader.breaks)) + report.append(f"breaks: [{s}]") + if leader.lines: + report.extend(self._leader_lines(leader.lines)) + return report + + def _leader_lines(self, lines) -> list[str]: + report = [] + for num, line in enumerate(lines): + report.extend( + [ + self.divider_line(), + f"{num + 1}. LEADER LINE attributes:", + self.divider_line(), + ] + ) + for name, value in line.__dict__.items(): + if name in ("vertices", "breaks"): + vstr = "" + if value is not None: + vstr = ", ".join(map(str, value)) + vstr = f"[{vstr}]" + else: + vstr = str(value) + report.append(f"{name}: {vstr}") + return report + + def print_block_attribs(self): + print("\n".join(self.block_reference_attribs())) + + def block_reference_attribs(self) -> list[str]: + report = [ + self.divider_line(), + f"BLOCK reference attributes:", + self.divider_line(), + ] + for index, attr in enumerate(self.multileader.block_attribs): + report.extend( + [ + f"{index+1}. Attributes", + self.divider_line(), + ] + ) + report.append(f"handle: {attr.handle}") + report.append(f"index: {attr.index}") + report.append(f"width: {attr.width}") + report.append(f"text: {attr.text}") + return report + + def arrow_heads(self) -> list[str]: + report = [ + self.divider_line(), + f"ARROW HEAD attributes:", + self.divider_line(), + ] + for index, attr in enumerate(self.multileader.arrow_heads): + report.extend( + [ + f"{index+1}. Arrow Head", + self.divider_line(), + ] + ) + report.append(f"handle: {attr.handle}") + report.append(f"index: {attr.index}") + return report + + def print_mleaderstyle(self): + print("\n".join(self.mleaderstyle_attributes())) + + def mleaderstyle_attributes(self) -> list[str]: + report = [] + style = self.mleaderstyle + if style is not None: + report.extend( + [ + self.divider_line("="), + str(style), + self.divider_line("="), + ] + ) + attribs = style.dxf.all_existing_dxf_attribs() + keys = sorted(attribs.keys()) + report.extend([f"{name}: {attribs[name]}" for name in keys]) + else: + handle = self.multileader.dxf.get("style_handle") + report.append(f"MLEADERSTYLE(#{handle}) not found") + return self.shorten_lines(report) + + +def _content_attributes( + entity, exclude: Optional[Sequence[str]] = None +) -> list[str]: + exclude = exclude or [] + if entity is not None: + return [ + f"{name}: {value}" + for name, value in entity.__dict__.items() + if name not in exclude + ] + return [] + + +def yes_or_no(data) -> str: + return "yes" if data else "no" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/binarydata.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/binarydata.py new file mode 100644 index 0000000..3b8ac91 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/binarydata.py @@ -0,0 +1,606 @@ +# Copyright (c) 2014-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Any, Sequence, Union, overload, Optional +from array import array +import struct +from binascii import unhexlify, hexlify +from codecs import decode + +Bytes = Union[bytes, bytearray, memoryview] + + +def hex_strings_to_bytes(data: Iterable[str]) -> bytes: + """Returns multiple hex strings `data` as bytes.""" + byte_array = array("B") + for hexstr in data: + byte_array.extend(unhexlify(hexstr)) + return byte_array.tobytes() + + +def bytes_to_hexstr(data: bytes) -> str: + """Returns `data` bytes as plain hex string.""" + return hexlify(data).upper().decode() + + +NULL_NULL = b"\x00\x00" + + +class EndOfBufferError(EOFError): + pass + + +class ByteStream: + """Process little endian binary data organized as bytes, data is padded to + 4 byte boundaries by default. + """ + + # Created for Proxy Entity Graphic decoding + def __init__(self, buffer: Bytes, align: int = 4): + self.buffer = memoryview(buffer) + self.index: int = 0 + self._align: int = align + + @property + def has_data(self) -> bool: + return self.index < len(self.buffer) + + def align(self, index: int) -> int: + modulo = index % self._align + return index + self._align - modulo if modulo else index + + def read_struct(self, fmt: str) -> Any: + """Read data defined by a struct format string. Insert little endian + format character '<' as first character, if machine has native big + endian byte order. + """ + if not self.has_data: + raise EndOfBufferError("Unexpected end of buffer.") + + result = struct.unpack_from(fmt, self.buffer, offset=self.index) + self.index = self.align(self.index + struct.calcsize(fmt)) + return result + + def read_float(self) -> float: + return self.read_struct(" int: + return self.read_struct(" int: + return self.read_struct(" Sequence[float]: + return self.read_struct("<3d") + + def read_padded_string(self, encoding: str = "utf_8") -> str: + """PS: Padded String. This is a string, terminated with a zero byte. + The file’s text encoding (code page) is used to encode/decode the bytes + into a string. + """ + buffer = self.buffer + for end_index in range(self.index, len(buffer)): + if buffer[end_index] == 0: + start_index = self.index + self.index = self.align(end_index + 1) + # noinspection PyTypeChecker + return decode(buffer[start_index:end_index], encoding=encoding) + raise EndOfBufferError( + "Unexpected end of buffer, did not detect terminating zero byte." + ) + + def read_padded_unicode_string(self) -> str: + """PUS: Padded Unicode String. The bytes are encoded using Unicode + encoding. The bytes consist of byte pairs and the string is terminated + by 2 zero bytes. + """ + buffer = self.buffer + for end_index in range(self.index, len(buffer), 2): + if buffer[end_index : end_index + 2] == NULL_NULL: + start_index = self.index + self.index = self.align(end_index + 2) + # noinspection PyTypeChecker + return decode( + buffer[start_index:end_index], encoding="utf_16_le" + ) + raise EndOfBufferError( + "Unexpected end of buffer, did not detect terminating zero bytes." + ) + + +class BitStream: + """Process little endian binary data organized as bit stream.""" + + # Created for Proxy Entity Graphic decoding and DWG bit stream decoding + def __init__( + self, + buffer: Bytes, + dxfversion: str = "AC1015", + encoding: str = "cp1252", + ): + self.buffer = memoryview(buffer) + self.bit_index: int = 0 + self.dxfversion = dxfversion + self.encoding = encoding + + @property + def has_data(self) -> bool: + return self.bit_index >> 3 < len(self.buffer) + + def align(self, count: int) -> None: + """Align to byte border.""" + byte_index = (self.bit_index >> 3) + bool(self.bit_index & 7) + modulo = byte_index % count + if modulo: + byte_index += count - modulo + self.bit_index = byte_index << 3 + + def skip(self, count: int) -> None: + """Skip `count` bits.""" + self.bit_index += count + + def read_bit(self) -> int: + """Read one bit from buffer.""" + index = self.bit_index + self.bit_index += 1 + try: + return 1 if self.buffer[index >> 3] & (0x80 >> (index & 7)) else 0 + except IndexError: + raise EndOfBufferError("Unexpected end of buffer.") + + def read_bits(self, count) -> int: + """Read `count` bits from buffer.""" + index = self.bit_index + buffer = self.buffer + # index of next bit after reading `count` bits + next_bit_index = index + count + + if (next_bit_index - 1) >> 3 > len(buffer): + # not enough data to read all bits + raise EndOfBufferError("Unexpected end of buffer.") + self.bit_index = next_bit_index + + test_bit = 0x80 >> (index & 7) + test_byte_index = index >> 3 + value = 0 + test_byte = buffer[test_byte_index] + while count > 0: + value <<= 1 + if test_byte & test_bit: + value |= 1 + count -= 1 + test_bit >>= 1 + if not test_bit and count: + test_bit = 0x80 + test_byte_index += 1 + test_byte = buffer[test_byte_index] + return value + + def read_unsigned_byte(self) -> int: + """Read an unsigned byte (8 bit) from buffer.""" + return self.read_bits(8) + + def read_signed_byte(self) -> int: + """Read a signed byte (8 bit) from buffer.""" + value = self.read_bits(8) + if value & 0x80: + # 2er complement + return -((~value & 0xFF) + 1) + else: + return value + + def read_aligned_bytes(self, count: int) -> Sequence[int]: + buffer = self.buffer + start_index = self.bit_index >> 3 + end_index = start_index + count + if end_index <= len(buffer): + self.bit_index += count << 3 + return buffer[start_index:end_index] + else: + raise EndOfBufferError("Unexpected end of buffer.") + + def read_unsigned_short(self) -> int: + """Read an unsigned short (16 bit) from buffer.""" + if self.bit_index & 7: + s1 = self.read_bits(8) + s2 = self.read_bits(8) + else: # aligned data + s1, s2 = self.read_aligned_bytes(2) + return (s2 << 8) + s1 + + def read_signed_short(self) -> int: + """Read a signed short (16 bit) from buffer.""" + value = self.read_unsigned_short() + if value & 0x8000: + # 2er complement + return -((~value & 0xFFFF) + 1) + else: + return value + + def read_unsigned_long(self) -> int: + """Read an unsigned long (32 bit) from buffer.""" + if self.bit_index & 7: + read_bits = self.read_bits + l1 = read_bits(8) + l2 = read_bits(8) + l3 = read_bits(8) + l4 = read_bits(8) + else: # aligned data + l1, l2, l3, l4 = self.read_aligned_bytes(4) + return (l4 << 24) + (l3 << 16) + (l2 << 8) + l1 + + def read_signed_long(self) -> int: + """Read a signed long (32 bit) from buffer.""" + value = self.read_unsigned_long() + if value & 0x80000000: + # 2er complement + return -((~value & 0xFFFFFFFF) + 1) + else: + return value + + def read_float(self) -> float: + if self.bit_index & 7: + read_bits = self.read_bits + data = bytes(read_bits(8) for _ in range(8)) + else: # aligned data + data = bytes(self.read_aligned_bytes(8)) + return struct.unpack(" int: + bit = self.read_bit() + if bit: # 1 + bit = self.read_bit() + if bit: # 11 + bit = self.read_bit() + if bit: + return 7 # 111 + else: + return 6 # 110 + return 2 # 10 + else: + return 0 # 0 + + @overload + def read_bit_short(self) -> int: + ... + + @overload + def read_bit_short(self, count: int) -> Sequence[int]: + ... + + def read_bit_short(self, count: int = 1) -> Union[int, Sequence[int]]: + def _read(): + bits = self.read_bits(2) + if bits == 0: + return self.read_signed_short() + elif bits == 1: + return self.read_unsigned_byte() + elif bits == 2: + return 0 + else: + return 256 + + if count == 1: + return _read() + else: + return tuple(_read() for _ in range(count)) + + @overload + def read_bit_long(self) -> int: + ... + + @overload + def read_bit_long(self, count: int) -> Sequence[int]: + ... + + def read_bit_long(self, count: int = 1) -> Union[int, Sequence[int]]: + def _read(): + bits = self.read_bits(2) + if bits == 0: + return self.read_signed_long() + elif bits == 1: + return self.read_unsigned_byte() + elif bits == 2: + return 0 + else: # not used! + return 256 # ??? + + if count == 1: + return _read() + else: + return tuple(_read() for _ in range(count)) + + # LibreDWG: https://github.com/LibreDWG/libredwg/blob/master/src/bits.c + # Read 1 bitlonglong (compacted uint64_t) for REQUIREDVERSIONS, preview_size. + # ODA doc bug. ODA say 1-3 bits until the first 0 bit. See 3BLL. + # The first 3 bits indicate the length l (see paragraph 2.1). Then + # l bytes follow, which represent the number (the least significant + # byte is first). + def read_bit_long_long(self) -> int: + value = 0 + shifting = 0 + length = self.read_bits(3) # or read_3_bits() ? + while length > 0: + value += self.read_unsigned_byte() << shifting + length -= 1 + shifting += 8 + return value + + @overload + def read_raw_double(self) -> float: + ... + + @overload + def read_raw_double(self, count: int) -> Sequence[float]: + ... + + def read_raw_double(self, count: int = 1) -> Union[float, Sequence[float]]: + if count == 1: + return self.read_float() + else: + return tuple(self.read_float() for _ in range(count)) + + @overload + def read_bit_double(self) -> float: + ... + + @overload + def read_bit_double(self, count: int) -> Sequence[float]: + ... + + def read_bit_double(self, count: int = 1) -> Union[float, Sequence[float]]: + def _read(): + bits = self.read_bits(2) + if bits == 0: + return self.read_float() + elif bits == 1: + return 1.0 + elif bits == 2: + return 0.0 + else: # not used! + return 0.0 + + if count == 1: + return _read() + else: + return tuple(_read() for _ in range(count)) + + @overload + def read_bit_double_default(self) -> float: + ... + + @overload + def read_bit_double_default(self, count: int) -> Sequence[float]: + ... + + @overload + def read_bit_double_default( + self, count: int, default: float + ) -> Sequence[float]: + ... + + def read_bit_double_default( + self, count: int = 1, default: float = 0.0 + ) -> Union[float, Sequence[float]]: + data = struct.pack(" int: + """Modular characters are a method of storing compressed integer + values. They consist of a stream of bytes, terminating when the high + bit (8) of the byte is 0 else another byte follows. Negative numbers + are indicated by bit 7 set in the last byte. + + """ + shifting = 0 + value = 0 + while True: + char = self.read_unsigned_byte() + if char & 0x80: + # bit 8 set = another char follows + value |= (char & 0x7F) << shifting + shifting += 7 + else: + # bit 8 clear = end of modular char + # bit 7 set = negative number + value |= (char & 0x3F) << shifting + return -value if char & 0x40 else value + + def read_unsigned_modular_chars(self) -> int: + """Modular characters are a method of storing compressed integer + values. They consist of a stream of bytes, terminating when the high + bit (8) of the byte is 0 else another byte follows. + + """ + shifting = 0 + value = 0 + while True: + char = self.read_unsigned_byte() + value |= (char & 0x7F) << shifting + shifting += 7 + # bit 8 set = another char follows + if not (char & 0x80): + return value + + def read_modular_shorts(self) -> int: + """Modular shorts are a method of storing compressed unsigned integer + values. Only 1 or 2 shorts in practical usage (1GB), if the high + bit (16) of the first short is set another short follows. + + """ + short = self.read_unsigned_short() + if short & 0x8000: + return (self.read_unsigned_short() << 15) | (short & 0x7FFF) + else: + return short + + def read_bit_extrusion(self) -> Sequence[float]: + if self.read_bit(): + return 0.0, 0.0, 1.0 + else: + return self.read_bit_double(3) + + def read_bit_thickness(self, dxfversion="AC1015") -> float: + if dxfversion >= "AC1015": + if self.read_bit(): + return 0.0 + return self.read_bit_double() + + def read_cm_color(self) -> int: + return self.read_bit_short() + + def read_text(self) -> str: + length = self.read_bit_short() + data = bytes(self.read_unsigned_byte() for _ in range(length)) + return data.decode(encoding=self.encoding) + + def read_text_unicode(self) -> str: + # Unicode text is read from the "string stream" within the object data, + # see the main Object description section for details. + length = self.read_bit_short() + data = bytes(self.read_unsigned_byte() for _ in range(length * 2)) + return data.decode(encoding="utf16") + + def read_text_variable(self) -> str: + if self.dxfversion < "AC1018": # R2004 + return self.read_text() + else: + return self.read_text_unicode() + + def read_cm_color_cms(self) -> tuple[int, str, str]: + """Returns tuple (rgb, color_name, book_name).""" + _ = self.read_bit_short() # index always 0 + color_name = "" + book_name = "" + rgb = self.read_bit_long() + rc = self.read_unsigned_byte() + if rc & 1: + color_name = self.read_text_variable() + if rc & 2: + book_name = self.read_text_variable() + return rgb, color_name, book_name + + def read_cm_color_enc(self) -> Union[int, Sequence[Optional[int]]]: + """Returns color index as int or tuple (rgb, color_handle, + transparency_type, transparency). + """ + flags_and_index = self.read_bit_short() + flags = flags_and_index >> 8 + index = flags_and_index & 0xFF + if flags: + rgb = None + color_handle = None + transparency_type = None + transparency = None + if flags & 0x80: + rgb = self.read_bit_short() & 0x00FFFFFF + if flags & 0x40: + color_handle = self.read_handle() + if flags & 0x20: + data = self.read_bit_long() + transparency_type = data >> 24 + transparency = data & 0xFF + return rgb, color_handle, transparency_type, transparency + else: + return index + + def read_object_type(self) -> int: + bits = self.read_bits(2) + if bits == 0: + return self.read_unsigned_byte() + elif bits == 1: + return self.read_unsigned_byte() + 0x1F0 + else: + return self.read_unsigned_short() + + def read_handle(self, reference: int = 0) -> int: + """Returns handle as integer value.""" + code = self.read_bits(4) + length = self.read_bits(4) + if code == 6: + return reference + 1 + if code == 8: + return reference - 1 + + data = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00") + for index in range(length): + data[index] = self.read_unsigned_byte() + offset = struct.unpack(" str: + """Returns handle as hex string.""" + return "%X" % self.read_handle(reference) + + def read_code(self, code: str): + """Read data from bit stream by data codes defined in the + ODA reference. + + """ + if code == "B": + return self.read_bit() + elif code == "RC": + return self.read_unsigned_byte() + elif code == "RS": + return self.read_signed_short() + elif code == "BS": + return self.read_bit_short() + elif code == "RL": + return self.read_signed_long() + elif code == "BL": + return self.read_bit_long() + elif code == "RD": + return self.read_raw_double() + elif code == "2RD": + return self.read_raw_double(2) + elif code == "BD": + return self.read_bit_double() + elif code == "2BD": + return self.read_bit_double(2) + elif code == "3BD": + return self.read_bit_double(3) + elif code == "T": + return self.read_text() + elif code == "TV": + return self.read_text_variable() + elif code == "H": + return self.read_hex_handle() + elif code == "BLL": + return self.read_bit_long_long() + elif code == "CMC": + return self.read_cm_color() + raise ValueError(f"Unknown code: {code}") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/clipping_portal.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/clipping_portal.py new file mode 100644 index 0000000..0988aad --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/clipping_portal.py @@ -0,0 +1,470 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Optional, + Iterable, + Iterator, + Sequence, + NamedTuple, + Callable, + TYPE_CHECKING, +) +import abc + +from ezdxf.math import ( + Matrix44, + Vec2, + BoundingBox2d, + UVec, + is_convex_polygon_2d, + is_axes_aligned_rectangle_2d, +) +from ezdxf.npshapes import NumpyPath2d, NumpyPoints2d + +if TYPE_CHECKING: + from ezdxf.math.clipping import Clipping + +__all__ = [ + "ClippingShape", + "ClippingPortal", + "ClippingRect", + "ConvexClippingPolygon", + "InvertedClippingPolygon", + "MultiClip", + "find_best_clipping_shape", + "make_inverted_clipping_shape", +] + + +class ClippingShape(abc.ABC): + """The ClippingShape defines a single clipping path and executes the clipping on + basic geometries: + + - point: a single point + - line: a line between two vertices + - polyline: open polyline with one or more straight line segments + - polygon: closed shape with straight line as edges + - path: open shape with straight lines and Bezier-curves as segments + - filled-path: closed shape with straight lines and Bezier-curves as edges + + Difference between open and closed shapes: + + - an open shape is treated as a linear shape without a filling + - clipping an open shape returns one or more open shapes + - a closed shape is treated as a filled shape, where the first vertex is + coincident to the last vertex. + - clipping a closed shape returns one or more closed shapes + + Notes: + + An arbitrary clipping polygon can split any basic geometry (except point) into + multiple parts. + + All current implemented clipping algorithms flatten Bezier-curves into polylines. + + """ + + @abc.abstractmethod + def bbox(self) -> BoundingBox2d: ... + + @abc.abstractmethod + def is_completely_inside(self, other: BoundingBox2d) -> bool: ... + + # returning False means: I don't know! + + @abc.abstractmethod + def is_completely_outside(self, other: BoundingBox2d) -> bool: ... + + @abc.abstractmethod + def clip_point(self, point: Vec2) -> Optional[Vec2]: ... + + @abc.abstractmethod + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: ... + + @abc.abstractmethod + def clip_polyline(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: ... + + @abc.abstractmethod + def clip_polygon(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: ... + + @abc.abstractmethod + def clip_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: ... + + @abc.abstractmethod + def clip_filled_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: ... + + +class ClippingStage(NamedTuple): + portal: ClippingShape + transform: Matrix44 | None + + +class ClippingPortal: + """The ClippingPortal manages a clipping path stack.""" + + def __init__(self) -> None: + self._stages: list[ClippingStage] = [] + + @property + def is_active(self) -> bool: + return bool(self._stages) + + def push(self, portal: ClippingShape, transform: Matrix44 | None) -> None: + self._stages.append(ClippingStage(portal, transform)) + + def pop(self) -> None: + if self._stages: + self._stages.pop() + + def foreach_stage(self, command: Callable[[ClippingStage], bool]) -> None: + for stage in self._stages[::-1]: + if not command(stage): + return + + def clip_point(self, point: Vec2) -> Optional[Vec2]: + result: Vec2 | None = point + + def do(stage: ClippingStage) -> bool: + nonlocal result + assert result is not None + if stage.transform: + result = Vec2(stage.transform.transform(result)) + result = stage.portal.clip_point(result) + return result is not None + + self.foreach_stage(do) + return result + + def clip_line(self, start: Vec2, end: Vec2) -> list[tuple[Vec2, Vec2]]: + def do(stage: ClippingStage) -> bool: + lines = list(result) + result.clear() + for s, e in lines: + if stage.transform: + s, e = stage.transform.fast_2d_transform((s, e)) + result.extend(stage.portal.clip_line(s, e)) + return bool(result) + + result = [(start, end)] + self.foreach_stage(do) + return result + + def clip_polyline(self, points: NumpyPoints2d) -> list[NumpyPoints2d]: + def do(stage: ClippingStage) -> bool: + polylines = list(result) + result.clear() + for polyline in polylines: + if stage.transform: + polyline.transform_inplace(stage.transform) + result.extend(stage.portal.clip_polyline(polyline)) + return bool(result) + + result = [points] + self.foreach_stage(do) + return result + + def clip_polygon(self, points: NumpyPoints2d) -> list[NumpyPoints2d]: + def do(stage: ClippingStage) -> bool: + polygons = list(result) + result.clear() + for polygon in polygons: + if stage.transform: + polygon.transform_inplace(stage.transform) + result.extend(stage.portal.clip_polygon(polygon)) + return bool(result) + + result = [points] + self.foreach_stage(do) + return result + + def clip_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> list[NumpyPath2d]: + def do(stage: ClippingStage) -> bool: + paths = list(result) + result.clear() + for path in paths: + if stage.transform: + path.transform_inplace(stage.transform) + result.extend(stage.portal.clip_paths(paths, max_sagitta)) + return bool(result) + + result = list(paths) + self.foreach_stage(do) + return result + + def clip_filled_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> list[NumpyPath2d]: + def do(stage: ClippingStage) -> bool: + paths = list(result) + result.clear() + for path in paths: + if stage.transform: + path.transform_inplace(stage.transform) + result.extend(stage.portal.clip_filled_paths(paths, max_sagitta)) + return bool(result) + + result = list(paths) + self.foreach_stage(do) + return result + + def transform_matrix(self, m: Matrix44) -> Matrix44: + for _, transform in self._stages[::-1]: + if transform is not None: + m @= transform + return m + + +class ClippingPolygon(ClippingShape): + """Represents an arbitrary polygon as clipping shape. Removes the geometry + outside the clipping polygon. + + """ + + def __init__(self, bbox: BoundingBox2d, clipper: Clipping) -> None: + if not bbox.has_data: + raise ValueError("clipping box not detectable") + self._bbox = bbox + self.clipper = clipper + + def bbox(self) -> BoundingBox2d: + return self._bbox + + def clip_point(self, point: Vec2) -> Optional[Vec2]: + is_inside = self.clipper.is_inside(Vec2(point)) + if not is_inside: + return None + return point + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + return self.clipper.clip_line(start, end) + + def clip_polyline(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: + clipper = self.clipper + if len(points) == 0: + return tuple() + polyline_bbox = BoundingBox2d(points.extents()) + if self.is_completely_outside(polyline_bbox): + return tuple() + if self.is_completely_inside(polyline_bbox): + return (points,) + return [ + NumpyPoints2d(part) + for part in clipper.clip_polyline(points.vertices()) + if len(part) > 0 + ] + + def clip_polygon(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: + clipper = self.clipper + if len(points) < 2: + return tuple() + polygon_bbox = BoundingBox2d(points.extents()) + if self.is_completely_outside(polygon_bbox): + return tuple() + if self.is_completely_inside(polygon_bbox): + return (points,) + return [ + NumpyPoints2d(part) + for part in clipper.clip_polygon(points.vertices()) + if len(part) > 0 + ] + + def clip_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: + clipper = self.clipper + for path in paths: + for sub_path in path.sub_paths(): + path_bbox = BoundingBox2d(sub_path.control_vertices()) + if not path_bbox.has_data: + continue + if self.is_completely_inside(path_bbox): + yield sub_path + continue + if self.is_completely_outside(path_bbox): + continue + polyline = Vec2.list(sub_path.flattening(max_sagitta, segments=4)) + for part in clipper.clip_polyline(polyline): + if len(part) > 0: + yield NumpyPath2d.from_vertices(part, close=False) + + def clip_filled_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: + clipper = self.clipper + for path in paths: + for sub_path in path.sub_paths(): + if len(sub_path) < 2: + continue + path_bbox = BoundingBox2d(sub_path.control_vertices()) + if self.is_completely_inside(path_bbox): + yield sub_path + continue + if self.is_completely_outside(path_bbox): + continue + for part in clipper.clip_polygon( + Vec2.list(sub_path.flattening(max_sagitta, segments=4)) + ): + if len(part) > 0: + yield NumpyPath2d.from_vertices(part, close=True) + + +class ClippingRect(ClippingPolygon): + """Represents a rectangle as clipping shape where the edges are parallel to + the x- and y-axis of the coordinate system. Removes the geometry outside the + clipping rectangle. + + """ + + def __init__(self, vertices: Iterable[UVec]) -> None: + from ezdxf.math.clipping import ClippingRect2d + + polygon = Vec2.list(vertices) + bbox = BoundingBox2d(polygon) + if not bbox.has_data: + raise ValueError("clipping box not detectable") + size: Vec2 = bbox.size + self.remove_all = size.x * size.y < 1e-9 + + super().__init__(bbox, ClippingRect2d(bbox.extmin, bbox.extmax)) + + def is_completely_inside(self, other: BoundingBox2d) -> bool: + return self._bbox.contains(other) + + def is_completely_outside(self, other: BoundingBox2d) -> bool: + return not self._bbox.has_intersection(other) + + def clip_point(self, point: Vec2) -> Optional[Vec2]: + if self.remove_all: + return None + return super().clip_point(point) + + def clip_line(self, start: Vec2, end: Vec2) -> Sequence[tuple[Vec2, Vec2]]: + if self.remove_all: + return tuple() + return self.clipper.clip_line(start, end) + + def clip_polyline(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: + if self.remove_all: + return (NumpyPoints2d(tuple()),) + return super().clip_polyline(points) + + def clip_polygon(self, points: NumpyPoints2d) -> Sequence[NumpyPoints2d]: + if self.remove_all: + return (NumpyPoints2d(tuple()),) + return super().clip_polygon(points) + + def clip_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: + if self.remove_all: + return iter(tuple()) + return super().clip_paths(paths, max_sagitta) + + def clip_filled_paths( + self, paths: Iterable[NumpyPath2d], max_sagitta: float + ) -> Iterator[NumpyPath2d]: + if self.remove_all: + return iter(tuple()) + return super().clip_filled_paths(paths, max_sagitta) + + +class ConvexClippingPolygon(ClippingPolygon): + """Represents an arbitrary convex polygon as clipping shape. Removes the geometry + outside the clipping polygon. + + """ + + def __init__(self, vertices: Iterable[UVec]) -> None: + from ezdxf.math.clipping import ConvexClippingPolygon2d + + polygon = Vec2.list(vertices) + super().__init__(BoundingBox2d(polygon), ConvexClippingPolygon2d(polygon)) + + def is_completely_inside(self, other: BoundingBox2d) -> bool: + return False # I don't know! + + def is_completely_outside(self, other: BoundingBox2d) -> bool: + return not self._bbox.has_intersection(other) + + +class ConcaveClippingPolygon(ClippingPolygon): + """Represents an arbitrary concave polygon as clipping shape. Removes the geometry + outside the clipping polygon. + + """ + + def __init__(self, vertices: Iterable[UVec]) -> None: + from ezdxf.math.clipping import ConcaveClippingPolygon2d + + polygon = Vec2.list(vertices) + super().__init__(BoundingBox2d(polygon), ConcaveClippingPolygon2d(polygon)) + + def is_completely_inside(self, other: BoundingBox2d) -> bool: + return False # I don't know! + + def is_completely_outside(self, other: BoundingBox2d) -> bool: + return not self._bbox.has_intersection(other) + + +class InvertedClippingPolygon(ClippingPolygon): + """Represents an arbitrary inverted clipping polygon. Removes the geometry + inside the clipping polygon. + + .. Important:: + + The `outer_bounds` must be larger than the content to clip to work correctly. + + """ + + def __init__(self, vertices: Iterable[UVec], outer_bounds: BoundingBox2d) -> None: + from ezdxf.math.clipping import InvertedClippingPolygon2d + + polygon = Vec2.list(vertices) + super().__init__(outer_bounds, InvertedClippingPolygon2d(polygon, outer_bounds)) + + def is_completely_inside(self, other: BoundingBox2d) -> bool: + # returning False means: I don't know! + return False # not easy to detect + + def is_completely_outside(self, other: BoundingBox2d) -> bool: + return not self._bbox.has_intersection(other) + + +def find_best_clipping_shape(polygon: Iterable[UVec]) -> ClippingShape: + """Returns the best clipping shape for the given clipping polygon. + + The function analyses the given polygon (rectangular, convex or concave polygon, ...) + and returns the optimized (fastest) clipping shape. + + Args: + polygon: clipping polygon as iterable vertices + + """ + points = Vec2.list(polygon) + if is_axes_aligned_rectangle_2d(points): + return ClippingRect(points) + elif is_convex_polygon_2d(points, strict=False): + return ConvexClippingPolygon(points) + return ConcaveClippingPolygon(points) + + +def make_inverted_clipping_shape( + polygon: Iterable[UVec], outer_bounds: BoundingBox2d +) -> ClippingShape: + """Returns an inverted clipping shape that removes the geometry inside the clipping + polygon and beyond the outer bounds. + + Args: + polygon: clipping polygon as iterable vertices + outer_bounds: outer bounds of the clipping shape + + """ + + return InvertedClippingPolygon(polygon, outer_bounds) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/codepage.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/codepage.py new file mode 100644 index 0000000..5048831 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/codepage.py @@ -0,0 +1,91 @@ +# Purpose: constant values +# Created: 10.03.2011 +# Copyright (c) 2011-2018, Manfred Moitzi +# License: MIT License + +# --- For Unix --- +# 0: undefined Rises an error. +# 1: ascii $20-$7F,%%c,%%d,%%p Only +# 2: iso8859_1 Western Europe(Unix) $20-$FF,%%c,%%d,%%p +# 3: iso8859_2 Central Europe(Unix) +# 4: iso8859_3 Eastern Europe(Unix) +# 5: iso8859_4 Baltic(Unix) +# 6: iso8859_5 Cyrillic(Unix) +# 7: iso8859_6 Arabic(Unix) +# 8: iso8859_7 Greek(Unix) +# 9: iso8859_8 Hebrew(Unix) +# 10: iso8859_9 Turkish(Unix) +# +# --- For DOS/Mac --- +# 11: dos437 DOS USA +# 12: dos850 DOS Western Europe +# 13: dos852 DOS Eastern Europe +# 14: dos855 IBM Russian +# 15: dos857 IBM Turkish +# 16: dos860 DOS Portuguese +# 17: dos861 DOS Icelandic +# 18: dos863 DOS Canadian French +# 19: dos864 DOS Arabic +# 20: dos865 DOS Norwegian +# 21: dos869 DOS Greek +# 22: dos932 DOS Japanese +# 23: mac-roman Mac +# 24: big5 DOS Traditional Chinese +# 25: ksc5601 Korean Wansung +# 26: johab Korean Johab +# 27: dos866 DOS Russian +# 31: gb2312 DOS Simplified Chinese +# +# --- For Windows --- +# 28: ansi_1250 Win Eastern Europe +# 29: ansi_1251 Win Russian +# 30: ansi_1252 Win Western Europe(ANSI) +# 32: ansi_1253 Win Greek +# 33: ansi_1254 Win Turkish +# 34: ansi_1255 Win Hebrew +# 35: ansi_1256 Win Arabic +# 36: ansi_1257 Win Baltic +# 37: ansi_874 Win Thai +# 38: ansi_932 Win Japanese +# 39: ansi_936 Win Simplified Chinese GB +# 40: ansi_949 Win Korean Wansung +# 41: ansi_950 Win Traditional Chinese big5 +# 42: ansi_1361 Win Korean Johab +# 43: ansi_1200 Unicode (reserved) +# --: ansi_1258 Win Vietnamese (reserved) + +codepage_to_encoding = { + "874": "cp874", # Thai, + "932": "cp932", # Japanese + "936": "gbk", # UnifiedChinese + "949": "cp949", # Korean + "950": "cp950", # TradChinese + "1250": "cp1250", # CentralEurope + "1251": "cp1251", # Cyrillic + "1252": "cp1252", # WesternEurope + "1253": "cp1253", # Greek + "1254": "cp1254", # Turkish + "1255": "cp1255", # Hebrew + "1256": "cp1256", # Arabic + "1257": "cp1257", # Baltic + "1258": "cp1258", # Vietnam +} + +encoding_to_codepage = { + codec: ansi for ansi, codec in codepage_to_encoding.items() +} + + +def is_supported_encoding(encoding: str = "cp1252") -> bool: + return encoding in encoding_to_codepage + + +def toencoding(dxfcodepage: str) -> str: + for codepage, encoding in codepage_to_encoding.items(): + if dxfcodepage.endswith(codepage): + return encoding + return "cp1252" + + +def tocodepage(encoding: str) -> str: + return "ANSI_" + encoding_to_codepage.get(encoding, "1252") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/complex_ltype.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/complex_ltype.py new file mode 100644 index 0000000..9b81272 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/complex_ltype.py @@ -0,0 +1,214 @@ +# Purpose: compiler for line type definitions +# Copyright (c) 2018-2021, Manfred Moitzi +# License: MIT License + +# Auszug acadlt.lin +# +# *RAND,Rand __ __ . __ __ . __ __ . __ __ . __ __ . +# A,.5,-.25,.5,-.25,0,-.25 +# *RAND2,Rand (.5x) __.__.__.__.__.__.__.__.__.__.__. +# A,.25,-.125,.25,-.125,0,-.125 +# *RANDX2,Rand (2x) ____ ____ . ____ ____ . ___ +# A,1.0,-.5,1.0,-.5,0,-.5 +# +# *MITTE,Mitte ____ _ ____ _ ____ _ ____ _ ____ _ ____ +# A,1.25,-.25,.25,-.25 +# *CENTER2,Mitte (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ +# A,.75,-.125,.125,-.125 +# *MITTEX2,Mitte (2x) ________ __ ________ __ _____ +# A,2.5,-.5,.5,-.5 +# +# ;; Komplexe Linientypen +# ;; +# ;; Dieser Datei sind komplexe Linientypen hinzugefügt worden. +# ;; Diese Linientypen wurden in LTYPESHP.LIN in +# ;; Release 13 definiert und wurden in ACAD.LIN in +# ;; Release 14 aufgenommen. +# ;; +# ;; Diese Linientypdefinitionen verwenden LTYPESHP.SHX. +# ;; +# *GRENZE1,Grenze rund ----0-----0----0-----0----0-----0-- +# A,.25,-.1,[CIRC1,ltypeshp.shx,x=-.1,s=.1],-.1,1 +# *GRENZE2,Grenze eckig ----[]-----[]----[]-----[]----[]--- +# A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1 +# *EISENBAHN,Eisenbahn -|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|- +# A,.15,[TRACK1,ltypeshp.shx,s=.25],.15 +# *ISOLATION,Isolation SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS +# A,.0001,-.1,[BAT,ltypeshp.shx,x=-.1,s=.1],-.2,[BAT,ltypeshp.shx,r=180,x=.1,s=.1],-.1 +# *HEISSWASSERLEITUNG,Heißwasserleitung ---- HW ---- HW ---- HW ---- +# A,.5,-.2,["HW",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.2 +# *GASLEITUNG,Gasleitung ----GAS----GAS----GAS----GAS----GAS----GAS-- +# A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25 +# *ZICKZACK,Zickzack /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +# A,.0001,-.2,[ZIG,ltypeshp.shx,x=-.2,s=.2],-.4,[ZIG,ltypeshp.shx,r=180,x=.2,s=.2],-.2 +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Sequence, Union, Any +from ezdxf.lldxf.const import DXFValueError, DXFTableEntryError +from ezdxf.lldxf.tags import DXFTag, Tags + +if TYPE_CHECKING: # import forward references + from ezdxf.document import Drawing + +Token = Union[str, float, list] + + +def lin_compiler(definition: str) -> Sequence[DXFTag]: + """ + Compiles line type definitions like 'A,.5,-.25,.5,-.25,0,-.25' or + 'A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25' into DXFTags(). + + Args: + definition: definition string + + Returns: + list of DXFTag() + """ + # 'A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25' + # ['A', .5, -.2, ['TEXT', 'GAS', 'STANDARD', 's', .1, 'u', 0.0, 'x', -.1, 'y', -.05], -.25] + tags = [] + for token in lin_parser(definition): + if token == "A": + continue + elif isinstance(token, float): + tags.append( + DXFTag(49, token) + ) # Dash, dot or space length (one entry per element) + elif isinstance(token, list): # yield from + tags.append(compile_complex_definition(token)) # type: ignore + return tags + + +class ComplexLineTypePart: + def __init__(self, type_: str, value, font: str = "STANDARD"): + self.type = type_ + self.value = value + self.font = font + self.tags = Tags() + + def complex_ltype_tags(self, doc: "Drawing") -> Sequence[DXFTag]: + def get_font_handle() -> str: + if self.type == "SHAPE": + # Create new shx or returns existing entry: + font = doc.styles.get_shx(self.font) + else: + try: + # Case insensitive search for text style: + font = doc.styles.get(self.font) + except DXFTableEntryError: + font = doc.styles.new(self.font) + return font.dxf.handle + + # Note: AutoCAD/BricsCAD do NOT report an error or even crash, if the + # text style handle is invalid! + if doc is not None: + handle = get_font_handle() + else: + handle = "0" + tags = [] + if self.type == "TEXT": + tags.append(DXFTag(74, 2)) + tags.append(DXFTag(75, 0)) + else: # SHAPE + tags.append(DXFTag(74, 4)) + tags.append(DXFTag(75, self.value)) + tags.append(DXFTag(340, handle)) + tags.extend(self.tags) + if self.type == "TEXT": + tags.append(DXFTag(9, self.value)) + return tags + + +CMD_CODES = { + "s": 46, # scaling factor + "r": 50, # rotation angle, r == u + "u": 50, # rotation angle + "x": 44, # shift x units = parallel to line direction + "y": 45, # shift y units = normal to line direction +} + + +def compile_complex_definition(tokens: Sequence) -> ComplexLineTypePart: + part = ComplexLineTypePart(tokens[0], tokens[1], tokens[2]) + commands = list(reversed(tokens[3:])) + params = {} + while len(commands): + cmd = commands.pop() + value = commands.pop() + code = CMD_CODES.get(cmd, 0) + params[code] = DXFTag(code, value) + + for code in (46, 50, 44, 45): + tag = params.get(code, DXFTag(code, 0.0)) + part.tags.append(tag) + return part + + +def lin_parser(definition: str) -> Sequence[Token]: + bag: list[Any] = [] + sublist = None + first = True + for token in lin_tokenizer(definition): + if token == "A" and first: + bag.append(token) + first = False + continue + + try: + value = float(token) # only outside of TEXT or SHAPE definition + bag.append(value) + continue + except ValueError: + pass + + if token.startswith("["): + if sublist is not None: + raise DXFValueError( + "Complex line type error. {}".format(definition) + ) + sublist = [] + if token.startswith('["'): + sublist.append("TEXT") + sublist.append( + token[2:-1] + ) # text without surrounding '["' and '"' + else: + sublist.append("SHAPE") + try: + sublist.append(int(token[1:])) # type: ignore # shape index! required + except ValueError: + raise DXFValueError( + "Complex line type with shapes requires shape index not shape name!" + ) + else: + _token = token.rstrip("]") + subtokens = _token.split("=") + if len(subtokens) == 2: + sublist.append(subtokens[0].lower()) + sublist.append(float(subtokens[1])) # type: ignore + else: + sublist.append(_token) + if token.endswith("]"): + if sublist is None: + raise DXFValueError( + "Complex line type error. {}".format(definition) + ) + bag.append(sublist) + sublist = None # type: ignore + return bag + + +def lin_tokenizer(definition: str) -> Iterable[str]: + token = "" + escape = False + for char in definition: + if char == "," and not escape: + yield token.strip() + token = "" + continue + token += char + if char == '"': + escape = not escape + if escape: + raise DXFValueError("Line type parsing error: '{}'".format(definition)) + if token: + yield token.strip() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/crypt.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/crypt.py new file mode 100644 index 0000000..931c57f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/crypt.py @@ -0,0 +1,58 @@ +# Purpose: decode/encode DXF proprietary data +# Created: 01.05.2014 +# Copyright (c) 2014-2018, Manfred Moitzi +# License: MIT License +from typing import Iterable + +_decode_table = { + 0x20: ' ', + 0x40: '_', + 0x5F: '@', +} +for c in range(0x41, 0x5F): + _decode_table[c] = chr(0x41 + (0x5E - c)) # 0x5E -> 'A', 0x5D->'B', ... + + +def decode(text_lines: Iterable[str]) -> Iterable[str]: + """ Decode the Standard :term:`ACIS` Text (SAT) format "encrypted" by AutoCAD. """ + def _decode(text): + dectab = _decode_table # fast local var + s = [] + text = bytes(text, 'ascii') + skip = False + for c in text: + if skip: + skip = False + continue + if c in dectab: + s += dectab[c] + skip = (c == 0x5E) # skip space after 'A' + else: + s += chr(c ^ 0x5F) + return ''.join(s) + return (_decode(line) for line in text_lines) + + +_encode_table = { + ' ': ' ', # 0x20 + '_': '@', # 0x40 + '@': '_', # 0x5F +} +for c in range(0x41, 0x5F): + _encode_table[chr(c)] = chr(0x5E - (c - 0x41)) # 0x5E->'A', 'B'->0x5D, ... + + +def encode(text_lines: Iterable[str]) -> Iterable[str]: + """ Encode the Standard :term:`ACIS` Text (SAT) format by AutoCAD "encryption" algorithm. """ + def _encode(text): + s = [] + enctab = _encode_table # fast local var + for c in text: + if c in enctab: + s += enctab[c] + if c == 'A': + s += ' ' # append a space for an 'A' -> cryptography + else: + s += chr(ord(c) ^ 0x5F) + return ''.join(s) + return (_encode(line) for line in text_lines) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/debug.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/debug.py new file mode 100644 index 0000000..8b9fc1a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/debug.py @@ -0,0 +1,54 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +from typing import Sequence + + +def group_chars(s: str, n: int = 4, sep="-") -> str: + chars = [] + for index, char in enumerate(reversed(s)): + if index % n == 0: + chars.append(sep) + chars.append(char) + if chars: + chars.reverse() + chars.pop() + return "".join(chars) + return "" + + +def bitmask_strings( + value: int, base: int = 10, sep: str = "-" +) -> Sequence[str]: + if base == 10: + top, bottom = ( + "3322-2222-2222-1111-1111-1100-0000-0000", + "1098-7654-3210-9876-5432-1098-7654-3210", + ) + elif base == 16: + top, bottom = ( + "1111-1111-1111-1111-0000-0000-0000-0000", + "FEDC-BA98-7654-3210-FEDC-BA98-7654-3210", + ) + else: + raise ValueError(f"invalid base {base}, valid bases: 10, 16") + top = top.replace("-", sep) + bottom = bottom.replace("-", sep) + l0 = len(top) + bin_str = group_chars(bin(value)[2:], n=4, sep=sep) + l1 = len(bin_str) + return [ + top[l0 - l1 :], + bottom[l0 - l1 :], + bin_str, + ] + + +def print_bitmask(value: int, *, base=10, sep="-"): + lines = bitmask_strings(value, base, sep) + assert len(lines) > 2 + divider_line = "=" * (max(map(len, lines)) + 4) + print(divider_line) + print("x0 :" + lines[0]) + print("0x :" + lines[1]) + print(divider_line) + print("bin:" + lines[2]) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/difftags.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/difftags.py new file mode 100644 index 0000000..1bcf589 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/difftags.py @@ -0,0 +1,80 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterator, NamedTuple, Iterable, Optional +from difflib import SequenceMatcher +import enum + +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import DXFVertex, DXFTag + +__all__ = ["diff_tags", "print_diff", "OpCode"] + +# https://docs.python.org/3/library/difflib.html + + +class OpCode(enum.Enum): + replace = enum.auto() + delete = enum.auto() + insert = enum.auto() + equal = enum.auto() + + +class Operation(NamedTuple): + opcode: OpCode + i1: int + i2: int + j1: int + j2: int + + +CONVERT = { + "replace": OpCode.replace, + "delete": OpCode.delete, + "insert": OpCode.insert, + "equal": OpCode.equal, +} + + +def convert_opcodes(opcodes) -> Iterator[Operation]: + for tag, i1, i2, j1, j2 in opcodes: + yield Operation(CONVERT[tag], i1, i2, j1, j2) + + +def round_tags(tags: Tags, ndigits: int) -> Iterator[DXFTag]: + for tag in tags: + if isinstance(tag, DXFVertex): + yield DXFVertex(tag.code, (round(d, ndigits) for d in tag.value)) + elif isinstance(tag.value, float): + yield DXFTag(tag.code, round(tag.value, ndigits)) + else: + yield tag + + +def diff_tags( + a: Tags, b: Tags, ndigits: Optional[int] = None +) -> Iterator[Operation]: + if ndigits is not None: + a = Tags(round_tags(a, ndigits)) + b = Tags(round_tags(b, ndigits)) + + sequencer = SequenceMatcher(a=a, b=b) + return convert_opcodes(sequencer.get_opcodes()) + + +def print_diff(a: Tags, b: Tags, operations: Iterable[Operation]): + t1: DXFTag + t2: DXFTag + print() + for op in operations: + if op.opcode == OpCode.insert: + for t1 in b[op.j1 : op.j2]: + print(f"insert a[{op.i1}:{op.i2}]: {t1}") + elif op.opcode == OpCode.replace: + for index, t1 in enumerate(a[op.i1 : op.i2], op.i1): + print(f"replace a[{index}]: {t1}") + for index, t2 in enumerate(b[op.j1 : op.j2], op.j1): + print(f" by b[{index}]: {t2}") + elif op.opcode == OpCode.delete: + for index, t1 in enumerate(a[op.i1 : op.i2], op.i1): + print(f"delete a[{index}]: {t1}") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/handle.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/handle.py new file mode 100644 index 0000000..a045281 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/handle.py @@ -0,0 +1,48 @@ +# Copyright (c) 2011-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Optional +from ezdxf.lldxf.types import is_valid_handle + +if TYPE_CHECKING: + from ezdxf.document import Drawing + +START_HANDLE = "1" + + +class HandleGenerator: + def __init__(self, start_value: str = START_HANDLE): + self._handle: int = max(1, int(start_value, 16)) + + reset = __init__ + + def __str__(self): + return "%X" % self._handle + + def next(self) -> str: + next_handle = self.__str__() + self._handle += 1 + return next_handle + + __next__ = next + + def copy(self) -> HandleGenerator: + return HandleGenerator(str(self)) + + +class UnderlayKeyGenerator(HandleGenerator): + def __str__(self): + return "Underlay%05d" % self._handle + + +def safe_handle(handle: Optional[str], doc: Optional["Drawing"] = None) -> str: + if handle is None: + return "0" + assert isinstance(handle, str), "invalid type" + if doc is not None: + if handle not in doc.entitydb: + return "0" + return handle + if not is_valid_handle(handle): + return "0" + return handle.upper() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/indexing.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/indexing.py new file mode 100644 index 0000000..76d36f0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/indexing.py @@ -0,0 +1,29 @@ +# created: 23.04.2018 +# Copyright (c) 2018 Manfred Moitzi +# License: MIT License + +from typing import Iterable + + +class Index: + def __init__(self, item): + try: + self.length = len(item) + except TypeError: + self.length = int(item) + + def index(self, item: int, error=None) -> int: + if item < 0: + result = self.length + int(item) + else: + result = int(item) + if error and not (0 <= result < self.length): + raise error('index out of range') + return result + + def slicing(self, *args) -> Iterable[int]: + if isinstance(args[0], slice): + s = args[0] + else: + s = slice(*args) + return range(*s.indices(self.length)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/juliandate.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/juliandate.py new file mode 100644 index 0000000..628b04a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/juliandate.py @@ -0,0 +1,71 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from math import floor +from datetime import datetime + + +def frac(number: float) -> float: + return number - floor(number) + + +class JulianDate: + def __init__(self, date: datetime): + self.date = date + self.result: float = self.julian_date() + self.fractional_day() + + def fractional_day(self) -> float: + seconds = ( + self.date.hour * 3600.0 + self.date.minute * 60.0 + self.date.second + ) + return seconds / 86400.0 + + def julian_date(self) -> float: + y = self.date.year + (float(self.date.month) - 2.85) / 12.0 + A = floor(367.0 * y) - 1.75 * floor(y) + self.date.day + B = floor(A) - 0.75 * floor(y / 100.0) + return floor(B) + 1721115.0 + + +class CalendarDate: + def __init__(self, juliandate: float): + self.jdate = juliandate + year, month, day = self.get_date() + hour, minute, second = frac2time(self.jdate) + self.result = datetime(year, month, day, hour, minute, second) + + def get_date(self) -> tuple[int, int, int]: + Z = floor(self.jdate) + + if Z < 2299161: + A = Z # julian calendar + else: + g = floor((Z - 1867216.25) / 36524.25) # gregorian calendar + A = Z + 1 + g - floor(g / 4.0) + + B = A + 1524. + C = floor((B - 122.1) / 365.25) + D = floor(365.25 * C) + E = floor((B - D) / 30.6001) + + day = B - D - floor(30.6001 * E) + month = E - 1 if E < 14 else E - 13 + year = C - 4716 if month > 2 else C - 4715 + return int(year), int(month), int(day) + + +def frac2time(jdate) -> tuple[int, int, int]: + seconds = int(frac(jdate) * 86400.0) + hour = int(seconds / 3600) + seconds = seconds % 3600 + minute = int(seconds / 60) + second = seconds % 60 + return hour, minute, second + + +def juliandate(date: datetime) -> float: + return JulianDate(date).result + + +def calendardate(juliandate: float) -> datetime: + return CalendarDate(juliandate).result diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/pattern.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/pattern.py new file mode 100644 index 0000000..38c2d4e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/pattern.py @@ -0,0 +1,190 @@ +# Copyright (c) 2015-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Tuple, Optional +from typing_extensions import TypeAlias +from ezdxf.math import Vec2 +from ._iso_pattern import ISO_PATTERN + +# Predefined hatch pattern prior to ezdxf v0.11 were scaled for imperial units, +# and were too small for ISO units by a factor of 1/25.4, to replicate this +# pattern scaling use load(measurement=0). + +__all__ = [ + "load", + "scale_pattern", + "scale_all", + "parse", + "ISO_PATTERN", + "IMPERIAL_PATTERN", + "HatchPatternLineType", + "HatchPatternType", + "PatternAnalyser", +] +IMPERIAL_SCALE_FACTOR = 1.0 / 25.4 +HatchPatternLineType: TypeAlias = Tuple[ + float, Sequence[float], Sequence[float], Sequence[float] +] +HatchPatternType: TypeAlias = Sequence[HatchPatternLineType] + + +def load(measurement: int = 1, factor: Optional[float] = None): + """Load hatch pattern definition, default scaling is like the iso.pat of + BricsCAD, set `measurement` to 0 to use the imperial (US) scaled pattern, + which has a scaling factor of 1/25.4 = ~0.03937. + + Args: + measurement: like the $MEASUREMENT header variable, 0 to user imperial + scaled pattern, 1 to use ISO scaled pattern. + factor: hatch pattern scaling factor, overrides `measurement` + + Returns: hatch pattern dict of scaled pattern + + """ + if factor is None: + factor = 1.0 if measurement == 1 else IMPERIAL_SCALE_FACTOR + pattern = ISO_PATTERN + if factor != 1.0: + pattern = scale_all(pattern, factor=factor) + return pattern + + +def scale_pattern( + pattern: HatchPatternType, factor: float = 1, angle: float = 0 +) -> HatchPatternType: + ndigits = 10 + + def _scale(iterable) -> Sequence[float]: + return [round(i * factor, ndigits) for i in iterable] + + def _scale_line(line) -> HatchPatternLineType: + angle0, base_point, offset, dash_length_items = line + if angle: + base_point = Vec2(base_point).rotate_deg(angle) + offset = Vec2(offset).rotate_deg(angle) + angle0 = (angle0 + angle) % 360.0 + + # noinspection PyTypeChecker + return [ # type: ignore + round(angle0, ndigits), + tuple(_scale(base_point)), + tuple(_scale(offset)), + _scale(dash_length_items), + ] + + return [_scale_line(line) for line in pattern] + + +def scale_all(pattern: dict, factor: float = 1, angle: float = 0): + return {name: scale_pattern(p, factor, angle) for name, p in pattern.items()} + + +def parse(pattern: str) -> dict: + try: + comp = PatternFileCompiler(pattern) + return comp.compile_pattern() + except Exception: + raise ValueError("Incompatible pattern definition.") + + +def _tokenize_pattern_line(line: str) -> list: + return line.split(",", maxsplit=1 if line.startswith("*") else -1) + + +class PatternFileCompiler: + def __init__(self, content: str): + self._lines = [ + _tokenize_pattern_line(line) + for line in (line.strip() for line in content.split("\n")) + if line and line[0] != ";" + ] + + def _parse_pattern(self): + pattern = [] + for line in self._lines: + if line[0].startswith("*"): + if pattern: + yield pattern + pattern = [[line[0][1:], line[1]]] # name, description + else: + pattern.append([float(e) for e in line]) # list[floats] + + if pattern: + yield pattern + + def compile_pattern(self, ndigits: int = 10) -> dict: + pattern = dict() + for p in self._parse_pattern(): + pat = [] + for line in p[1:]: + # offset before rounding: + offset = Vec2(line[3], line[4]) + + # round all values: + line = [round(e, ndigits) for e in line] + pat_line = [] + + angle = line[0] + pat_line.append(angle) + + # base point: + pat_line.append((line[1], line[2])) + + # rotate offset: + offset = offset.rotate_deg(angle) + pat_line.append((round(offset.x, ndigits), round(offset.y, ndigits))) + + # line dash pattern + pat_line.append(line[5:]) + pat.append(pat_line) + pattern[p[0][0]] = pat + return pattern + + +IMPERIAL_PATTERN = load(measurement=0) + + +def is_solid(pattern: Sequence[float]) -> bool: + return not bool(len(pattern)) + + +def round_angle_15_deg(angle: float) -> int: + return round((angle % 180) / 15) * 15 + + +class PatternAnalyser: + def __init__(self, pattern: HatchPatternType): + # List of 2-tuples: (angle, is solid line pattern) + # angle is rounded to a multiple of 15° in the range [0, 180) + self._lines: list[tuple[int, bool]] = [ + (round_angle_15_deg(angle), is_solid(line_pattern)) + for angle, _, _, line_pattern in pattern + ] + + def has_angle(self, angle: int) -> bool: + return any(angle_ == angle for angle_, _ in self._lines) + + def all_angles(self, angle: int) -> bool: + return all(angle_ == angle for angle_, _ in self._lines) + + def has_line(self, angle: int, solid: bool) -> bool: + return any( + angle_ == angle and solid_ == solid for angle_, solid_ in self._lines + ) + + def all_lines(self, angle: int, solid: bool) -> bool: + return all( + angle_ == angle and solid_ == solid for angle_, solid_ in self._lines + ) + + def has_solid_line(self) -> bool: + return any(solid for _, solid in self._lines) + + def has_dashed_line(self) -> bool: + return any(not solid for _, solid in self._lines) + + def all_solid_lines(self) -> bool: + return all(solid for _, solid in self._lines) + + def all_dashed_lines(self) -> bool: + return all(not solid for _, solid in self._lines) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/rawloader.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/rawloader.py new file mode 100644 index 0000000..ace9dad --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/rawloader.py @@ -0,0 +1,36 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Union, Iterable, TYPE_CHECKING +from pathlib import Path + +from ezdxf.lldxf import loader +from ezdxf.lldxf.types import DXFTag +from ezdxf.lldxf.tagger import ascii_tags_loader +from ezdxf.lldxf.validator import is_dxf_file +from ezdxf.filemanagement import dxf_file_info + +if TYPE_CHECKING: + from ezdxf.eztypes import SectionDict + + +def raw_structure_loader(filename: Union[str, Path]) -> SectionDict: + """Load content of ASCII DXF file `filename` as SectionDict, all tags are in + raw format with the group code as integer and the value as string: (int, str). + + """ + tagger = get_tag_loader(filename) + return loader.load_dxf_structure(tagger) + + +def get_tag_loader( + filename: Union[str, Path], errors: str = "ignore" +) -> Iterable[DXFTag]: + + filename = str(filename) + if not is_dxf_file(filename): + raise IOError(f"File '{filename}' is not an ASCII DXF file.") + + info = dxf_file_info(filename) + with open(filename, mode="rt", encoding=info.encoding, errors=errors) as fp: + return list(ascii_tags_loader(fp, skip_comments=True)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/standards.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/standards.py new file mode 100644 index 0000000..692e71b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/standards.py @@ -0,0 +1,4002 @@ +# Copyright (c) 2016-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import TYPE_CHECKING, Tuple, Sequence, Union, cast, Optional +from typing_extensions import TypeAlias +from ezdxf import const +from ezdxf._options import options +from ezdxf.render.arrows import ARROWS +from ezdxf.lldxf.types import DXFTag +from ezdxf.lldxf.tags import Tags + +import logging + +if TYPE_CHECKING: + from ezdxf.document import Drawing + from ezdxf.entities import DimStyle + +logger = logging.getLogger("ezdxf") +LTypeDef: TypeAlias = Tuple[str, str, Sequence[float]] + + +def setup_drawing(doc: Drawing, topics: Union[str, bool, Sequence] = "all"): + """ + Setup default linetypes, text styles or dimension styles. + + Args: + doc: DXF document + topics: "all" or True to setup everything + Tuple of strings to specify setup: + - "linetypes": setup linetypes + - "styles": setup text styles + - "dimstyles[:all|metric|us]": setup dimension styles (us not implemented) + - "visualstyles": setup 25 standard visual styles + + """ + if not topics: # topics is None, False or "" + return + + def get_token(name: str) -> list[str]: + for t in topics: # type: ignore + token = t.split(":") + if token[0] == name: + return token + return [] + + if topics in ("all", True): + setup_all = True + topics = [] + else: + setup_all = False + if isinstance(topics, str): + topics = [topics.lower()] + else: + topics = list(t.lower() for t in topics) # type: ignore + + if setup_all or "linetypes" in topics: + setup_linetypes(doc) + + if setup_all or "styles" in topics: + setup_styles(doc) + + if setup_all or "visualstyles" in topics: + setup_visual_styles(doc) + + dimstyles = get_token("dimstyles") + if setup_all or len(dimstyles): + if len(dimstyles) == 2: + domain = dimstyles[1] + else: + domain = "all" + setup_dimstyles(doc, domain=domain) + + +def setup_linetypes(doc: Drawing) -> None: + measurement = 1 + if doc: + measurement = doc.header.get("$MEASUREMENT", measurement) + factor = ISO_LTYPE_FACTOR if measurement else 1.0 + for name, desc, pattern in linetypes(scale=factor): + if name in doc.linetypes: + continue + doc.linetypes.new( + name, + dxfattribs={ + "description": desc, + "pattern": pattern, + }, + ) + + +def setup_styles(doc: Drawing) -> None: + doc.header["$TEXTSTYLE"] = "OpenSans" + for name, font in styles(): + if name in doc.styles: + continue + doc.styles.new( + name, + dxfattribs={ + "font": font, + }, + ) + + +def setup_dimstyles(doc: Drawing, domain: str = "all") -> None: + setup_styles(doc) + ezdxf_dimstyle = setup_dimstyle( + doc, + name="EZDXF", + fmt="EZ_M_100_H25_CM", + style=options.default_dimension_text_style, + blk=ARROWS.architectural_tick, + ) + ezdxf_dimstyle.dxf.dimasz *= 0.7 # smaller arch ticks + doc.header["$DIMSTYLE"] = "EZDXF" + ezdxf_dimstyle.copy_to_header(doc) + + if domain in ("metric", "all"): + setup_dimstyle( + doc, + fmt="EZ_M_100_H25_CM", + style=options.default_dimension_text_style, + ) + setup_dimstyle( + doc, + fmt="EZ_M_50_H25_CM", + style=options.default_dimension_text_style, + ) + setup_dimstyle( + doc, + fmt="EZ_M_25_H25_CM", + style=options.default_dimension_text_style, + ) + setup_dimstyle( + doc, + fmt="EZ_M_20_H25_CM", + style=options.default_dimension_text_style, + ) + setup_dimstyle( + doc, + fmt="EZ_M_10_H25_CM", + style=options.default_dimension_text_style, + ) + setup_dimstyle( + doc, fmt="EZ_M_5_H25_CM", style=options.default_dimension_text_style + ) + setup_dimstyle( + doc, fmt="EZ_M_1_H25_CM", style=options.default_dimension_text_style + ) + elif domain in ("us", "all"): + pass + if domain in ("radius", "all"): + ez_radius = cast( + "DimStyle", doc.dimstyles.duplicate_entry("EZDXF", "EZ_RADIUS") + ) + ez_radius.set_arrows(blk=ARROWS.closed_blank) + ez_radius.dxf.dimasz = 0.25 # set arrow size + ez_radius.dxf.dimtofl = 0 # force dimension line if text outside + ez_radius.dxf.dimcen = ( + 0 # size of center mark, 0=disable, >0=draw mark, <0=draw lines + ) + # dimtmove: use leader, is the best setting for text outside to preserves + # appearance of DIMENSION entity, if editing DIMENSION afterwards in + # BricsCAD (AutoCAD) + ez_radius.dxf.dimtmove = 1 + + ez_radius_inside = doc.dimstyles.duplicate_entry( + "EZ_RADIUS", "EZ_RADIUS_INSIDE" + ) + # dimtmove: keep dim line with text, is the best setting for text inside + # to preserves appearance of DIMENSION entity, if editing DIMENSION + # afterwards in BricsCAD (AutoCAD) + ez_radius_inside.dxf.dimtmove = 0 + ez_radius_inside.dxf.dimtix = 1 # force text inside + ez_radius_inside.dxf.dimatfit = ( + 0 # required by BricsCAD (AutoCAD) to force text inside + ) + ez_radius_inside.dxf.dimtad = 0 # center text vertical + if domain in ("angular", "curved", "arc", "all"): + # curved dimension lines for angular and arc dimensions + ez_angular = cast( + "DimStyle", doc.dimstyles.duplicate_entry("EZDXF", "EZ_CURVED") + ) + ez_angular.set_arrows(blk=ARROWS.closed_filled) + ez_angular.dxf.dimasz = 0.25 # set arrow size + ez_angular.dxf.dimtad = 1 # above + ez_angular.dxf.dimaunit = 0 # 0=decimal deg 1=DMS 2=Grad 3=Radians + ez_angular.dxf.dimazin = 2 # suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) + ez_angular.dxf.dimarcsym = 2 # disable arc symbol + + +class DimStyleFmt: + DIMASZ = 2.5 # in mm in paper space + DIMTSZ = 1.25 # x2 in mm in paper space + UNIT_FACTOR = { + "m": 1, # 1 drawing unit == 1 meter + "dm": 10, # 1 drawing unit == 1 decimeter + "cm": 100, # 1 drawing unit == 1 centimeter + "mm": 1000, # 1 drawing unit == 1 millimeter + } + + def __init__(self, fmt: str): + tokens = fmt.lower().split("_") + self.name = fmt + self.drawing_unit = tokens[1] # EZ__100_H25_CM + self.scale = float(tokens[2]) # EZ_M_<100>_H25_CM + self.height = float(tokens[3][1:]) / 10.0 # EZ_M_100_H<25>_CM # in mm + self.measurement_unit = tokens[4] # EZ_M_100_H25_ + + @property + def unit_factor(self): + return self.UNIT_FACTOR[self.drawing_unit] + + @property + def measurement_factor(self): + return self.UNIT_FACTOR[self.measurement_unit] + + @property + def text_factor(self): + return self.unit_factor / self.UNIT_FACTOR["mm"] * self.scale + + @property + def dimlfac(self): + return self.measurement_factor / self.unit_factor + + @property + def dimasz(self): + return self.DIMASZ * self.text_factor + + @property + def dimtsz(self): + return self.DIMTSZ * self.text_factor + + @property + def dimtxt(self): + return self.height * self.text_factor + + @property + def dimexe(self): + return self.dimtxt * 1.5 + + @property + def dimexo(self): + return self.dimtxt / 2 + + @property + def dimdle(self): + return 0.25 * self.unit_factor + + +def setup_dimstyle( + doc: Drawing, + fmt: str, + style: Optional[str] = None, + blk: Optional[str] = None, + name: str = "", +) -> DimStyle: + """Easy DimStyle setup, the `fmt` string defines four essential dimension + parameters separated by the `_` character. Tested and works with the metric + system, I don't touch the 'english unit' system. + + Example: `fmt` = 'EZ_M_100_H25_CM' + + 1. '_M_100_H25_CM': arbitrary prefix + 2. 'EZ__100_H25_CM': defines the drawing unit, valid values are 'M', 'DM', 'CM', 'MM' + 3. 'EZ_M_<100>_H25_CM': defines the scale of the drawing, '100' is for 1:100 + 4. 'EZ_M_100__CM': defines the text height in mm in paper space times 10, 'H25' is 2.5mm + 5. 'EZ_M_100_H25_': defines the units for the measurement text, valid values are 'M', 'DM', 'CM', 'MM' + + Args: + doc: DXF drawing + fmt: format string + style: text style for measurement + blk: block name of arrow head, ``None`` for oblique stroke + name: dimension style name, if name is '', `fmt` string is used as name + + """ + style = style or options.default_dimension_text_style + dim_style_fmt = DimStyleFmt(fmt) + name = name or dim_style_fmt.name + if doc.dimstyles.has_entry(name): + logging.debug(f'DimStyle "{name}" already exists.') + return cast("DimStyle", doc.dimstyles.get(name)) + + dimstyle = cast("DimStyle", doc.dimstyles.new(name)) + dimstyle.dxf.dimtxt = dim_style_fmt.dimtxt + dimstyle.dxf.dimlfac = ( + dim_style_fmt.dimlfac + ) # factor for measurement; dwg in m : measurement in cm -> dimlfac=100 + dimstyle.dxf.dimgap = ( + dim_style_fmt.dimtxt * 0.4 + ) # gap between text and dimension line + dimstyle.dxf.dimtad = 1 # text above dimline + dimstyle.dxf.dimexe = dim_style_fmt.dimexe + dimstyle.dxf.dimexo = dim_style_fmt.dimexo + dimstyle.dxf.dimdle = 0 # dimension extension beyond extension lines + dimstyle.dxf.dimtix = 0 # Draws dimension text between the extension lines even if it would ordinarily be placed outside those lines + dimstyle.dxf.dimtih = 0 # Align text inside extension lines with dimension line; 1 = Draws text horizontally + dimstyle.dxf.dimtoh = 0 # Align text outside of extension lines with dimension line; 1 = Draws text horizontally + dimstyle.dxf.dimzin = 12 # Suppresses leading trailing zeros in linear dimensions + dimstyle.dxf.dimazin = ( + 3 # Suppresses leading + trailing zeros in angular dimensions + ) + dimstyle.dxf.dimdec = 2 # decimals places for linear measurements + dimstyle.dxf.dimadec = 2 # decimals places for angle measurements + dimstyle.dxf.dimsah = 0 + dimstyle.dxf.dimtmove = 2 # move freely without leader + dimstyle.dxf.dimtxsty = style # text style + dimstyle.dxf.dimtfac = 0.5 # tolerance text factor + dimstyle.dxf.dimtdec = 2 # tolerance decimal places + + # user location override, controls both the text position and the + # dimension line location, same as DXF12 + dimstyle.dxf.dimupt = 1 + dimstyle.dxf.dimdsep = ord(".") + + if blk is None: # oblique stroke + dimstyle.dxf.dimtsz = dim_style_fmt.dimtsz # tick size + dimstyle.dxf.dimasz = dim_style_fmt.dimasz # arrow size + else: # arrow or block + dimstyle.set_arrows(blk=blk) + dimstyle.dxf.dimasz = dim_style_fmt.dimasz + return dimstyle + + +ISO_LTYPE_FACTOR = 2.54 +# DXF linetype definition for $MEASUREMENT=0 (imperial) +# name, description, elements: +# elements = [total_pattern_length, elem1, elem2, ...] +# total_pattern_length = sum(abs(elem)) +# elem > 0 is line, < 0 is gap, 0.0 = dot; +ANSI_LINE_TYPES = [ + ("CONTINUOUS", "Solid", [0.0]), + ( + "CENTER", + "Center ____ _ ____ _ ____ _ ____ _ ____ _ ____", + [2.0, 1.25, -0.25, 0.25, -0.25], + ), + ( + "CENTERX2", + "Center (2x) ________ __ ________ __ ________", + [3.5, 2.5, -0.25, 0.5, -0.25], + ), + ( + "CENTER2", + "Center (.5x) ____ _ ____ _ ____ _ ____ _ ____", + [1.0, 0.625, -0.125, 0.125, -0.125], + ), + ( + "DASHED", + "Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _", + [0.6, 0.5, -0.1], + ), + ( + "DASHEDX2", + "Dashed (2x) ____ ____ ____ ____ ____ ____", + [1.2, 1.0, -0.2], + ), + ("DASHED2", "Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _", [0.3, 0.25, -0.05]), + ( + "PHANTOM", + "Phantom ______ __ __ ______ __ __ ______", + [2.5, 1.25, -0.25, 0.25, -0.25, 0.25, -0.25], + ), + ( + "PHANTOMX2", + "Phantom (2x)____________ ____ ____ ____________", + [4.25, 2.5, -0.25, 0.5, -0.25, 0.5, -0.25], + ), + ( + "PHANTOM2", + "Phantom (.5x) ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___", + [1.25, 0.625, -0.125, 0.125, -0.125, 0.125, -0.125], + ), + ( + "DASHDOT", + "Dash dot __ . __ . __ . __ . __ . __ . __ . __", + [1.4, 1.0, -0.2, 0.0, -0.2], + ), + ( + "DASHDOTX2", + "Dash dot (2x) ____ . ____ . ____ . ____", + [2.4, 2.0, -0.2, 0.0, -0.2], + ), + ( + "DASHDOT2", + "Dash dot (.5x) _ . _ . _ . _ . _ . _ . _ . _", + [0.7, 0.5, -0.1, 0.0, -0.1], + ), + ( + "DOT", + "Dot . . . . . . . . . . . . . . . .", + [0.2, 0.0, -0.2], + ), + ( + "DOTX2", + "Dot (2x) . . . . . . . . ", + [0.4, 0.0, -0.4], + ), + ( + "DOT2", + "Dot (.5) . . . . . . . . . . . . . . . . . . . ", + [0.1, 0.0, -0.1], + ), + ( + "DIVIDE", + "Divide __ . . __ . . __ . . __ . . __ . . __", + [1.6, 1.0, -0.2, 0.0, -0.2, 0.0, -0.2], + ), + ( + "DIVIDEX2", + "Divide (2x) ____ . . ____ . . ____ . . ____", + [2.6, 2.0, -0.2, 0.0, -0.2, 0.0, -0.2], + ), + ( + "DIVIDE2", + "Divide(.5x) _ . _ . _ . _ . _ . _ . _ . _", + [0.8, 0.5, -0.1, 0.0, -0.1, 0.0, -0.1], + ), +] + + +def linetypes(scale: float = 1.0) -> list[LTypeDef]: + """Creates a list of standard line types. + Imperial units (in, ft, yd, ...) have a scale factor of 1.0, ISO units (m, + cm, mm, ...) have a scale factor of 2.54, available as constant + :attr:`ezdxf.tools.standards.ISO_LTYPE_FACTOR`. + + """ + return [scale_linetype(ltype, scale) for ltype in ANSI_LINE_TYPES] + + +def scale_linetype(ltype: LTypeDef, scale: float) -> LTypeDef: + name, pattern_str, pattern = ltype + return name, pattern_str, [round(e * scale, 3) for e in pattern] + + +def styles(): + """Creates a list of standard styles.""" + return [ + ("STANDARD", "txt"), + ("OpenSans-Light", "OpenSans-Light.ttf"), + ("OpenSans-Light-Italic", "OpenSans-LightItalic.ttf"), + ("OpenSans", "OpenSans-Regular.ttf"), + ("OpenSans-Italic", "OpenSans-Italic.ttf"), + ("OpenSans-SemiBold", "OpenSans-SemiBold.ttf"), + ("OpenSans-SemiBoldItalic", "OpenSans-SemiBoldItalic.ttf"), + ("OpenSans-Bold", "OpenSans-Bold.ttf"), + ("OpenSans-BoldItalic", "OpenSans-BoldItalic.ttf"), + ("OpenSans-ExtraBold", "OpenSans-ExtraBold.ttf"), + ("OpenSans-ExtraBoldItalic", "OpenSans-ExtraBoldItalic.ttf"), + ("OpenSansCondensed-Bold", "OpenSansCondensed-Bold.ttf"), + ("OpenSansCondensed-Light", "OpenSansCondensed-Light.ttf"), + ("OpenSansCondensed-Italic", "OpenSansCondensed-LightItalic.ttf"), + ("LiberationSans", "LiberationSans-Regular.ttf"), + ("LiberationSans-Bold", "LiberationSans-Bold.ttf"), + ("LiberationSans-BoldItalic", "LiberationSans-BoldItalic.ttf"), + ("LiberationSans-Italic", "LiberationSans-Italic.ttf"), + ("LiberationSerif", "LiberationSerif-Regular.ttf"), + ("LiberationSerif-Bold", "LiberationSerif-Bold.ttf"), + ("LiberationSerif-BoldItalic", "LiberationSerif-BoldItalic.ttf"), + ("LiberationSerif-Italic", "LiberationSerif-Italic.ttf"), + ("LiberationMono", "LiberationMono-Regular.ttf"), + ("LiberationMono-Bold", "LiberationMono-Bold.ttf"), + ("LiberationMono-BoldItalic", "LiberationMono-BoldItalic.ttf"), + ("LiberationMono-Italic", "LiberationMono-Italic.ttf"), + ] + + +def setup_visual_styles(doc: Drawing): + if doc.dxfversion < const.DXF2013: + setup_visual_styles_r2000(doc) + else: + setup_visual_styles_r2013(doc) + + +def setup_visual_styles_r2000(doc: Drawing): + objects = doc.objects + vstyle_dict = doc.rootdict.get_required_dict("ACAD_VISUALSTYLE") + vstyle_dict_handle = vstyle_dict.dxf.handle + for vstyle in VISUAL_STYLES_R2000: + vstyle["owner"] = vstyle_dict_handle + vstyle_object = objects.add_dxf_object_with_reactor( + "VISUALSTYLE", dxfattribs=vstyle + ) + vstyle_dict[vstyle_object.dxf.description] = vstyle_object + + +def setup_visual_styles_r2013(doc: Drawing): + objects = doc.objects + vstyle_dict = doc.rootdict.get_required_dict("ACAD_VISUALSTYLE") + vstyle_dict_handle = vstyle_dict.dxf.handle + for desc, vstyle in VISUAL_STYLES_R2013.items(): + vstyle["owner"] = vstyle_dict_handle + attribs = dict(vstyle) + del attribs["xdata"] + vstyle_object = objects.add_dxf_object_with_reactor( + "VISUALSTYLE", dxfattribs=attribs + ) + vstyle_object.acad_xdata = vstyle["xdata"] # type: ignore + vstyle_dict[desc] = vstyle_object + + +VISUAL_STYLES_R2000 = [ + { + "description": "2dWireframe", + "style_type": 4, + "internal_use_only_flag": 0, + "face_modifiers": 0, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Basic", + "style_type": 7, + "internal_use_only_flag": 1, + "face_modifiers": 1, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Brighten", + "style_type": 12, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "ColorChange", + "style_type": 16, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 8, + "edge_hide_precision": 0, + }, + { + "description": "Conceptual", + "style_type": 9, + "internal_use_only_flag": 0, + "face_modifiers": 3, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Dim", + "style_type": 11, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "EdgeColorOff", + "style_type": 22, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Facepattern", + "style_type": 15, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Flat", + "style_type": 0, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "FlatWithEdges", + "style_type": 1, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Gouraud", + "style_type": 2, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "GouraudWithEdges", + "style_type": 3, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Hidden", + "style_type": 6, + "internal_use_only_flag": 0, + "face_modifiers": 1, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "JitterOff", + "style_type": 20, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Linepattern", + "style_type": 14, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Modeling", + "style_type": 10, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "OverhangOff", + "style_type": 21, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Realistic", + "style_type": 8, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Shaded", + "style_type": 27, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Shaded with edges", + "style_type": 26, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Shades of Gray", + "style_type": 23, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Sketchy", + "style_type": 24, + "internal_use_only_flag": 0, + "face_modifiers": 1, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Thicken", + "style_type": 13, + "internal_use_only_flag": 1, + "face_modifiers": 2, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "Wireframe", + "style_type": 5, + "internal_use_only_flag": 0, + "face_modifiers": 0, + "face_opacity_level": 0.6, + "color1": 7, + "edge_hide_precision": 0, + }, + { + "description": "X-Ray", + "style_type": 25, + "internal_use_only_flag": 0, + "face_modifiers": 2, + "face_opacity_level": 0.5, + "color1": 7, + "edge_hide_precision": 0, + }, +] + +VISUAL_STYLES_R2013 = { + "2dWireframe": { + "description": "2dWireframe", + "style_type": 4, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Basic": { + "description": "Basic", + "style_type": 7, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Brighten": { + "description": "Brighten", + "style_type": 12, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "ColorChange": { + "description": "ColorChange", + "style_type": 16, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Conceptual": { + "description": "Conceptual", + "style_type": 9, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Dim": { + "description": "Dim", + "style_type": 11, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "EdgeColorOff": { + "description": "EdgeColorOff", + "style_type": 22, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Facepattern": { + "description": "Facepattern", + "style_type": 15, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Flat": { + "description": "Flat", + "style_type": 0, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "FlatWithEdges": { + "description": "FlatWithEdges", + "style_type": 1, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Gouraud": { + "description": "Gouraud", + "style_type": 2, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "GouraudWithEdges": { + "description": "GouraudWithEdges", + "style_type": 3, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Hidden": { + "description": "Hidden", + "style_type": 6, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "JitterOff": { + "description": "JitterOff", + "style_type": 20, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Linepattern": { + "description": "Linepattern", + "style_type": 14, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Modeling": { + "description": "Modeling", + "style_type": 10, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "OverhangOff": { + "description": "OverhangOff", + "style_type": 21, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Realistic": { + "description": "Realistic", + "style_type": 8, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Shaded": { + "description": "Shaded", + "style_type": 27, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Shaded with edges": { + "description": "Shaded with edges", + "style_type": 26, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Shades of Gray": { + "description": "Shades of Gray", + "style_type": 23, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Sketchy": { + "description": "Sketchy", + "style_type": 24, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Thicken": { + "description": "Thicken", + "style_type": 13, + "unknown1": 3, + "internal_use_only_flag": 1, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "Wireframe": { + "description": "Wireframe", + "style_type": 5, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(40, 0.6), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, + "X-Ray": { + "description": "X-Ray", + "style_type": 25, + "unknown1": 3, + "internal_use_only_flag": 0, + "xdata": Tags( + [ + DXFTag(70, 58), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(40, 0.5), + DXFTag(176, 1), + DXFTag(40, 30.0), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(420, 16777215), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 4), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(62, 257), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 8), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(90, 6), + DXFTag(176, 1), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(62, 7), + DXFTag(176, 1), + DXFTag(90, 5), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 1), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 1), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(40, 0.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(90, 0), + DXFTag(176, 1), + DXFTag(62, 18), + DXFTag(420, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 3), + DXFTag(176, 1), + DXFTag(62, 5), + DXFTag(420, 255), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(90, 50), + DXFTag(176, 1), + DXFTag(62, 256), + DXFTag(176, 0), + DXFTag(40, 1.0), + DXFTag(176, 0), + DXFTag(90, 2), + DXFTag(176, 1), + DXFTag(1, "strokes_ogs.tif"), + DXFTag(176, 1), + DXFTag(290, 0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + DXFTag(40, 1.0), + DXFTag(176, 1), + ] + ), + }, +} + +# all page sizes in landscape orientation +PAGE_SIZES = { + "ISO A0": ("mm", 1189, 841), + "ISO A1": ("mm", 841, 594), + "ISO A2": ("mm", 594, 420), + "ISO A3": ("mm", 420, 297), + "ISO A4": ("mm", 297, 210), + "ANSI A": ("inch", 11, 8.5), + "ANSI B": ("inch", 17, 11), + "ANSI C": ("inch", 22, 17), + "ANSI D": ("inch", 34, 22), + "ANSI E": ("inch", 44, 34), + "ARCH C": ("inch", 24, 18), + "ARCH D": ("inch", 36, 24), + "ARCH E": ("inch", 48, 36), + "ARCH E1": ("inch", 42, 30), + "Letter": ("inch", 11, 8.5), + "Legal": ("inch", 14, 8.5), +} diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/strip.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/strip.py new file mode 100644 index 0000000..19f1b3f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/strip.py @@ -0,0 +1,192 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import BinaryIO, Optional, Sequence +from ezdxf.lldxf.validator import is_dxf_file, DXFStructureError +from pathlib import Path + + +class TagWriter: + def __init__(self, fp: BinaryIO): + self.fp = fp + + def write(self, raw_code_str: bytes, raw_value_str: bytes): + self.fp.write(raw_code_str) + self.fp.write(raw_value_str) + + +class ThumbnailRemover(TagWriter): + def __init__(self, fp: BinaryIO): + super().__init__(fp) + self._start_section = False + self._skip_tags = False + self._section_code: Optional[bytes] = None + self._section_value: Optional[bytes] = None + self.removed_thumbnail_image = False + + def write(self, raw_code_str: bytes, raw_value_str: bytes): + code = raw_code_str.strip() + value = raw_value_str.strip() + if self._start_section: + self._start_section = False + if code == b"2" and value == b"THUMBNAILIMAGE": + self._skip_tags = True + self.removed_thumbnail_image = True + else: + # write buffered section tag: + super().write(self._section_code, self._section_value) # type: ignore + + if code == b"0": + if value == b"SECTION": + self._start_section = True + self._skip_tags = False + # buffer section tag: + self._section_code = raw_code_str + self._section_value = raw_value_str + return + elif value == b"ENDSEC": + skip = self._skip_tags + self._skip_tags = False + if skip: # don't write ENDSEC + return + + if not self._skip_tags: + super().write(raw_code_str, raw_value_str) + + +def strip_tags( + infile: BinaryIO, + tagwriter: TagWriter, + codes: Sequence[int], + verbose=False, +) -> int: + search_codes = set(codes) + line_number: int = 1 + removed_tags: int = 0 + while True: + try: + raw_code_str = infile.readline() + except EOFError: + raw_code_str = b"" + if raw_code_str == b"": # regular end of file + return removed_tags + try: + code = int(raw_code_str) + except ValueError: + code_str = raw_code_str.strip().decode(encoding="utf8", errors="ignore") + raise DXFStructureError( + f'CANCELED: "{infile.name}" - found invalid ' + f'group code "{code_str}" at line {line_number}' + ) + + try: + raw_value_str = infile.readline() + except EOFError: + raw_value_str = b"" + + if raw_value_str == b"": + raise DXFStructureError( + f'CANCELED: "{infile.name}" - premature end of file' + ) + line_number += 2 + if code not in search_codes: + tagwriter.write(raw_code_str, raw_value_str) + else: + if verbose: + value = raw_value_str.strip() + _value = value.decode(encoding="utf8", errors="ignore") + print(f'removing tag: ({code}, "{_value}")') + removed_tags += 1 + + +def safe_rename(source: Path, target: Path, backup=True, verbose=False) -> bool: + backup_file = target.with_suffix(".bak") + backup_file.unlink(missing_ok=True) + _target = Path(target) + if _target.exists(): + if verbose: + print(f'renaming "{_target.name}" to "{backup_file.name}"') + try: + _target.rename(backup_file) + except IOError as e: + print(f"IOError: {str(e)}") + return False + + if verbose: + print(f'renaming "{source.name}" to "{target.name}"') + try: + source.rename(target) + except IOError as e: + print(f"IOError: {str(e)}") + return False + + if not backup: + if verbose: + print(f'deleting backup file "{backup_file.name}"') + backup_file.unlink(missing_ok=True) + return True + + +DEFAULT_CODES = (999,) + + +def strip( + filename: str, + backup=False, + thumbnail=False, + verbose=False, + codes: Sequence[int] = DEFAULT_CODES, +): + def remove_tmp_file(): + if tmp_file.exists(): + if verbose: + print(f'deleting temp file: "{tmp_file.name}"') + tmp_file.unlink(missing_ok=True) + + if verbose: + print(f'\nProcessing file: "{filename}"') + try: + if not is_dxf_file(filename): + print( + f'CANCELED: "{filename}" is not a DXF file, binary DXF files ' + f"are not supported" + ) + return + except IOError as e: + print(f"IOError: {str(e)}") + return + source_file = Path(filename) + tmp_file = source_file.with_suffix(".ezdxf.tmp") + error = False + tagwriter: TagWriter + if verbose: + print(f'make a temporary copy: "{tmp_file.name}"') + with open(tmp_file, "wb") as fp, open(source_file, "rb") as infile: + if thumbnail: + tagwriter = ThumbnailRemover(fp) + else: + tagwriter = TagWriter(fp) + try: + removed_tags = strip_tags(infile, tagwriter, codes=codes, verbose=verbose) + except IOError as e: + print(f"IOError: {str(e)}") + error = True + except DXFStructureError as e: + print(str(e)) + error = True + + if not error: + rename = False + if thumbnail and tagwriter.removed_thumbnail_image: # type: ignore + print(f'"{source_file.name}" - removed THUMBNAILIMAGE section') + rename = True + + if removed_tags > 0: + tags = "tag" if removed_tags == 1 else "tags" + print(f'"{source_file.name}" - {removed_tags} {tags} removed') + rename = True + + if rename: + safe_rename(tmp_file, source_file, backup, verbose) + + remove_tmp_file() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/test.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/test.py new file mode 100644 index 0000000..9e7aebf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/test.py @@ -0,0 +1,50 @@ +# Copyright (c) 2011-2022, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, TYPE_CHECKING, Iterable +from ezdxf.lldxf.tagger import internal_tag_compiler + +if TYPE_CHECKING: + from ezdxf.lldxf.types import DXFTag + from ezdxf.lldxf.extendedtags import ExtendedTags + + +def compile_tags_without_handles(text: str) -> Iterable[DXFTag]: + return ( + tag for tag in internal_tag_compiler(text) if tag.code not in (5, 105) + ) + + +def normlines(text: str) -> Sequence[str]: + lines = text.split("\n") + return [line.strip() for line in lines] + + +def load_section(text: str, name: str) -> list[ExtendedTags]: + from ezdxf.lldxf.loader import load_dxf_structure + + dxf = load_dxf_structure( + internal_tag_compiler(text), ignore_missing_eof=True + ) + return dxf[name] # type: ignore + + +def load_entities(text: str, name: str): + from ezdxf.lldxf.loader import load_dxf_structure, load_dxf_entities + + dxf = load_dxf_structure( + internal_tag_compiler(text), ignore_missing_eof=True + ) + return load_dxf_entities(dxf[name]) # type: ignore + + +def parse_hex_dump(txt: str) -> bytes: + b = bytearray() + lines = txt.split("\n") + for line in lines: + if line == "": + continue + data = [int(v, 16) for v in line.strip().split(" ")] + assert data[0] == len(b) + b.extend(data[1:]) + return b diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/text.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/text.py new file mode 100644 index 0000000..4502b55 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/text.py @@ -0,0 +1,1871 @@ +# Copyright (c) 2021-2024, Manfred Moitzi +# License: MIT License +# pylint: disable=consider-using-in +""" +Tools in this module should be as independent of DXF entities as possible! +""" +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + TYPE_CHECKING, + Union, + Optional, + Callable, + NamedTuple, + Any, +) +import enum +import re +import math + +from ezdxf.lldxf import validator, const +from ezdxf.enums import ( + TextEntityAlignment, + TextHAlign, + MTextParagraphAlignment, + MTextLineAlignment, + MTextStroke, + MAP_MTEXT_ALIGN_TO_FLAGS, +) +from ezdxf.lldxf.const import ( + LEFT, + CENTER, + RIGHT, + BASELINE, + MIDDLE, + TOP, + MAX_STR_LEN, +) +from ezdxf.math import Vec3, Vec2, UVec +from ezdxf.colors import rgb2int, RGB, int2rgb + + +if TYPE_CHECKING: + from ezdxf.entities import Text, MText, DXFEntity + from ezdxf.lldxf.tags import Tags + from ezdxf.fonts import fonts + +X_MIDDLE = 4 # special case for overall alignment "MIDDLE" + + +class TextLine: + """Helper class which represents a single line text entity + (e.g. :class:`~ezdxf.entities.Text`). + + Args: + text: content string + font: ezdxf font definition like :class:`~ezdxf.fonts.fonts.MonospaceFont` + or :class:`~ezdxf.fonts.fonts.TrueTypeFont` + + """ + + def __init__(self, text: str, font: fonts.AbstractFont): + self._font = font + self._text_width: float = font.text_width(text) + self._stretch_x: float = 1.0 + self._stretch_y: float = 1.0 + + def stretch(self, alignment: TextEntityAlignment, p1: Vec3, p2: Vec3) -> None: + """Set stretch factors for FIT and ALIGNED alignments to fit the + text between `p1` and `p2`, only the distance between these points is + important. Other given `alignment` values are ignore. + + """ + assert isinstance(alignment, TextEntityAlignment) + sx: float = 1.0 + sy: float = 1.0 + if alignment in (TextEntityAlignment.FIT, TextEntityAlignment.ALIGNED): + defined_length: float = (p2 - p1).magnitude + if self._text_width > 1e-9: + sx = defined_length / self._text_width + if alignment == TextEntityAlignment.ALIGNED: + sy = sx + self._stretch_x = sx + self._stretch_y = sy + + @property + def width(self) -> float: + """Returns the final (stretched) text width.""" + return self._text_width * self._stretch_x + + @property + def height(self) -> float: + """Returns the final (stretched) text height.""" + return self._font.measurements.total_height * self._stretch_y + + def font_measurements(self) -> fonts.FontMeasurements: + """Returns the scaled font measurements.""" + return self._font.measurements.scale(self._stretch_y) + + def baseline_vertices( + self, + insert: UVec, + halign: int = 0, + valign: int = 0, + angle: float = 0, + scale: tuple[float, float] = (1, 1), + ) -> list[Vec3]: + """Returns the left and the right baseline vertex of the text line. + + Args: + insert: insertion location + halign: horizontal alignment left=0, center=1, right=2 + valign: vertical alignment baseline=0, bottom=1, middle=2, top=3 + angle: text rotation in radians + scale: scale in x- and y-axis as 2-tuple of float + + """ + fm = self.font_measurements() + vertices = [ + Vec2(0, fm.baseline), + Vec2(self.width, fm.baseline), + ] + shift = self._shift_vector(halign, valign, fm) + # Oblique angle is deliberately not supported, the baseline should be + # (near) the y-coordinate=0. + return TextLine.transform_2d(vertices, insert, shift, angle, scale) + + def corner_vertices( + self, + insert: UVec, + halign: int = 0, + valign: int = 0, + angle: float = 0, + scale: tuple[float, float] = (1, 1), + oblique: float = 0, + ) -> list[Vec3]: + """Returns the corner vertices of the text line in the order + bottom left, bottom right, top right, top left. + + Args: + insert: insertion location + halign: horizontal alignment left=0, center=1, right=2 + valign: vertical alignment baseline=0, bottom=1, middle=2, top=3 + angle: text rotation in radians + scale: scale in x- and y-axis as 2-tuple of float + oblique: shear angle (slanting) in x-direction in radians + + """ + fm = self.font_measurements() + vertices = [ + Vec2(0, fm.bottom), + Vec2(self.width, fm.bottom), + Vec2(self.width, fm.cap_top), + Vec2(0, fm.cap_top), + ] + shift = self._shift_vector(halign, valign, fm) + return TextLine.transform_2d(vertices, insert, shift, angle, scale, oblique) + + def _shift_vector( + self, halign: int, valign: int, fm: fonts.FontMeasurements + ) -> tuple[float, float]: + return _shift_x(self.width, halign), _shift_y(fm, valign) + + @staticmethod + def transform_2d( + vertices: Iterable[UVec], + insert: UVec = Vec3(0, 0, 0), + shift: tuple[float, float] = (0, 0), + rotation: float = 0, + scale: tuple[float, float] = (1, 1), + oblique: float = 0, + ) -> list[Vec3]: + """Transform any vertices from the text line located at the base + location at (0, 0) and alignment LEFT. + + Args: + vertices: iterable of vertices + insert: insertion location + shift: (shift-x, shift-y) as 2-tuple of float + rotation: text rotation in radians + scale: (scale-x, scale-y) as 2-tuple of float + oblique: shear angle (slanting) in x-direction in radians + + """ + # Building a transformation matrix vs. applying transformations in + # individual steps: + # Most text is horizontal, because people like to read horizontal text! + # Operating in 2D is faster than building a full 3D transformation + # matrix and a pure 2D transformation matrix is not implemented! + # This function doesn't transform many vertices at the same time, + # mostly only 4 vertices, therefore the matrix multiplication overhead + # does not pay off. + # The most expensive rotation transformation is the least frequently + # used transformation. + # IMPORTANT: these assumptions are not verified by profiling! + + # Use 2D vectors: + vertices_: Iterable[Vec2] = Vec2.generate(vertices) + + # 1. slanting at the original location (very rare): + if oblique: + slant_x = math.tan(oblique) + vertices_ = (Vec2(v.x + v.y * slant_x, v.y) for v in vertices_) + + # 2. apply alignment shifting (frequently): + shift_vector = Vec2(shift) + if shift_vector: + vertices_ = (v + shift_vector for v in vertices_) + + # 3. scale (and mirror) at the aligned location (more often): + scale_x, scale_y = scale + if scale_x != 1 or scale_y != 1: + vertices_ = (Vec2(v.x * scale_x, v.y * scale_y) for v in vertices_) + + # 4. apply rotation (rare): + if rotation: + vertices_ = (v.rotate(rotation) for v in vertices_) + + # 5. move to insert location in OCS/3D! (every time) + insert = Vec3(insert) + return [insert + v for v in vertices_] + + +def _shift_x(total_width: float, halign: int) -> float: + if halign == CENTER: + return -total_width / 2.0 + if halign == RIGHT: + return -total_width + return 0.0 # LEFT + + +def _shift_y(fm: fonts.FontMeasurements, valign: int) -> float: + if valign == BASELINE: + return fm.baseline + if valign == MIDDLE: + return -fm.cap_top + fm.cap_height / 2 + if valign == X_MIDDLE: + return -fm.cap_top + fm.total_height / 2 + if valign == TOP: + return -fm.cap_top + return -fm.bottom + + +def unified_alignment(entity: Union[Text, MText]) -> tuple[int, int]: + """Return unified horizontal and vertical alignment. + + horizontal alignment: left=0, center=1, right=2 + + vertical alignment: baseline=0, bottom=1, middle=2, top=3 + + Returns: + tuple(halign, valign) + + """ + dxftype = entity.dxftype() + if dxftype in ("TEXT", "ATTRIB", "ATTDEF"): + halign = entity.dxf.halign + valign = entity.dxf.valign + if halign in (TextHAlign.ALIGNED, TextHAlign.FIT): + # For the alignments ALIGNED and FIT the text stretching has to be + # handles separately. + halign = CENTER + valign = BASELINE + elif halign == TextHAlign.MIDDLE: # MIDDLE is different to MIDDLE/CENTER + halign = CENTER + valign = X_MIDDLE + return halign, valign + if dxftype == "MTEXT": + return MAP_MTEXT_ALIGN_TO_FLAGS.get(entity.dxf.attachment_point, (LEFT, TOP)) + raise TypeError(f"invalid DXF {dxftype}") + + +def plain_text(text: str) -> str: + """Returns the plain text for :class:`~ezdxf.entities.Text`, + :class:`~ezdxf.entities.Attrib` and :class:`~ezdxf.entities.Attdef` content. + """ + # TEXT, ATTRIB and ATTDEF are short strings <= 255 in R12. + # R2000 allows 2049 chars, but this limit is not often used in real world + # applications. + result = "" + scanner = TextScanner(validator.fix_one_line_text(caret_decode(text))) + while scanner.has_data: + char = scanner.peek() + if char == "%": # special characters + if scanner.peek(1) == "%": + code = scanner.peek(2).lower() + letter = const.SPECIAL_CHAR_ENCODING.get(code) + if letter: + scanner.consume(3) # %%? + result += letter + continue + if code in "kou": + # formatting codes (%%k, %%o, %%u) will be ignored in + # TEXT, ATTRIB and ATTDEF: + scanner.consume(3) + continue + scanner.consume(1) + # slightly faster then "".join(chars) + result += char + return result + + +ONE_CHAR_COMMANDS = "PNLlOoKkX" + + +################################################## +# MTEXT inline codes +# \L Start underline +# \l Stop underline +# \O Start overline +# \o Stop overline +# \K Start strike-through +# \k Stop strike-through +# \P New paragraph (new line) +# \N New column +# \~ None breaking space +# ^I Tabulator +# \ Escape character - e.g. \\ = "\", \{ = "{" +# +# \p start paragraph properties until next ";" +# \pi#,l#,r#; paragraph indent +# i# indent first line left, relative to (l)! +# l# indent paragraph left +# r# indent paragraph right +# q? alignments: +# ql align text in paragraph: left +# qr align text in paragraph: right +# qc align text in paragraph: center +# qj align text in paragraph: justified +# qd align text in paragraph: distributed +# x unknown meaning +# t#[,c#,r#...] define absolute tabulator stops 1,c2,r3... +# without prefix is a left adjusted tab stop +# prefix 'c' for center adjusted tab stop +# prefix 'r' for right adjusted tab stop +# ?* reset command to default value +# +# Examples: +# \pi1,t[5,20,...]; define tab stops as comma separated list +# \pxt4,c8,r12,16,c20,r24; left, centered and right adjusted tab stops +# \pi*,l*,r*,q*,t; reset to default values +# \pi2,l0; = first line 2 & paragraph left 0 +# \pi-2,l2; = first line -2 & paragraph left 2 +# \pi0,l2; = first line 0 & paragraph left 2 +# +# \X Paragraph wrap on the dimension line (only in dimensions) +# \Q Slanting (oblique) text by angle - e.g. \Q30; +# \H Text height relative - e.g. \H3x; +# \H Text height absolute - e.g. \H3; +# \W Text width factor relative e.g. \W0.8x; +# \W Text width factor absolute e.g. \W0.8; +# \F Font selection +# \f Font selection +# +# e.g. \Fgdt;o - GDT-tolerance +# e.g. \fArial|b0|i0|c238|p10; - font Arial, non-bold, non-italic, +# codepage 238, pitch 10 +# codepage 0 = no change +# pitch 0 = no change +# +# \S Stacking, fractions +# +# e.g. \SA^ B; +# A +# B +# e.g. \SX/ Y; +# X +# - +# Y +# e.g. \S1# 4; +# 1/4 +# +# \A Alignment relative to current line +# +# \A0; = bottom +# \A1; = center +# \A2; = top +# +# \C Color change +# +# \C1; = red +# \C2; = yellow +# \C3; = green +# \C4; = cyan +# \C5; = blue +# \C6; = magenta +# \C7; = white + +# \c255; = RED (255, 0, 0) +# \c65280; = GREEN (0, 255, 0) +# \c16711680; = BLUE (0, 0, 255) + +# RGB color = \c7528479; = 31,224,114 +# ezdxf.rgb2int((31,224,114)) = 2089074 (r,g,b) wrong! +# ezdxf.rgb2int((114,224,31)) = 7528479 (b,g,r) reversed order is correct! +# +# \T Tracking, char spacing factor as absolute value e.g. \T2; +# \T Tracking, char spacing factor as relative value e.g. \T2x; +# {} Braces - define the text area influenced by the code +# Multiple codes after the opening brace are valid until the closing +# brace. e.g. {\H0.4x;\A1;small centered text} +# +# Codes and braces can be nested up to 8 levels deep +# +# Column types in BricsCAD: +# - dynamic auto height: all columns have the same height +# - dynamic manual height: each column has an individual height +# - no columns +# - static: all columns have the same height, like dynamic auto height, +# difference is only important for user interaction in CAD applications +# +# - All columns have the same width and gutter. +# - Paragraphs do overflow into the next column if required. + + +# pylint: disable-next=too-many-branches +def fast_plain_mtext(text: str, split=False) -> Union[list[str], str]: + """Returns the plain MTEXT content as a single string or a list of + strings if `split` is ``True``. Replaces ``\\P`` by ``\\n`` and removes + other controls chars and inline codes. + + This function is more than 4x faster than :func:`plain_mtext`, but does not + remove single letter inline commands with arguments without a terminating + semicolon like this ``"\\C1red text"``. + + .. note:: + + Well behaved CAD applications and libraries always create inline codes + for commands with arguments with a terminating semicolon like this + ``"\\C1;red text"``! + + Args: + text: MTEXT content string + split: split content at line endings ``\\P`` + + """ + chars = [] + # split text into chars, in reversed order for efficient pop() + raw_chars = list(reversed(caret_decode(text))) + # pylint: disable=too-many-nested-blocks + while raw_chars: + char = raw_chars.pop() + if char == "\\": # is a formatting command + try: + char = raw_chars.pop() + except IndexError: + break # premature end of text - just ignore + + if char in "\\{}": + chars.append(char) + elif char in ONE_CHAR_COMMANDS: + if char == "P": # new line + chars.append("\n") + elif char == "N": # new column + # until columns are supported, better to at least remove the + # escape character + chars.append(" ") + # else: discard other commands + else: # multiple character commands are terminated by ';' + stacking = char == "S" # stacking command surrounds user data + first_char = char + search_chars = raw_chars.copy() + try: + while char != ";": # end of format marker + char = search_chars.pop() + if stacking and char != ";": + # append user data of stacking command + chars.append(char) + raw_chars = search_chars + except IndexError: + # premature end of text - just ignore + chars.append("\\") + chars.append(first_char) + elif char in "{}": # grouping + pass # discard group markers + elif char == "%": # special characters + if raw_chars and raw_chars[-1] == "%": + raw_chars.pop() # discard next '%' + if raw_chars: + code = raw_chars.pop() + letter = const.SPECIAL_CHAR_ENCODING.get(code.lower()) + if letter: + chars.append(letter) + else: + chars.extend(("%", "%", code)) + else: # char is just a single '%' + chars.append(char) + else: # char is what it is, a character + chars.append(char) + + result = "".join(chars) + return result.split("\n") if split else result + + +def caret_decode(text: str) -> str: + """DXF stores some special characters using caret notation. This function + decodes this notation to normalize the representation of special characters + in the string. + + see: https://en.wikipedia.org/wiki/Caret_notation + + """ + + def replace_match(match: re.Match) -> str: + c = ord(match.group(1)) + return chr((c - 64) % 126) + + return re.sub(r"\^(.)", replace_match, text) + + +def split_mtext_string(s: str, size: int = 250) -> list[str]: + """Split the MTEXT content string into chunks of max `size`.""" + chunks = [] + pos = 0 + while True: + chunk = s[pos : pos + size] + if len(chunk): + if len(chunk) < size: + chunks.append(chunk) + return chunks + pos += size + # do not split chunks at '^' + if chunk[-1] == "^": + chunk = chunk[:-1] + pos -= 1 + chunks.append(chunk) + else: + return chunks + + +def plain_mtext( + text: str, + split=False, + tabsize: int = 4, +) -> Union[list[str], str]: + """Returns the plain MTEXT content as a single string or a list of + strings if `split` is ``True``. Replaces ``\\P`` by ``\\n`` and removes + other controls chars and inline codes. + + This function is much slower than :func:`fast_plain_mtext`, but removes all + inline codes. + + Args: + text: MTEXT content string + split: split content at line endings ``\\P`` + tabsize: count of replacement spaces for tabulators ``^I`` + + """ + content: list[str] = [] + paragraph: list[str] = [] + + # localize enum to speed up inner loop + ( + _, + word, + stack, + space, + nbsp, + tabulator, + new_paragraph, + new_column, + *_, + ) = iter(TokenType) + tab_replacement = " " * tabsize + + # pylint: disable=consider-using-in + for token in MTextParser(text): + t = token.type + if t == word: + paragraph.append(token.data) + elif t == space or t == nbsp: + paragraph.append(" ") + elif t == new_paragraph or t == new_column: + content.append("".join(paragraph)) + paragraph.clear() + elif t == tabulator: + paragraph.append(tab_replacement) + elif t == stack: + upr, lwr, divider = token.data + paragraph.append(upr + divider + lwr) + + if paragraph: + content.append("".join(paragraph)) + if split: + return content + return "\n".join(content) + + +def escape_dxf_line_endings(text: str) -> str: + # replacing '\r\n' and '\n' by '\P' is required when exporting, else an + # invalid DXF file would be created. + return text.replace("\r", "").replace("\n", "\\P") + + +def replace_non_printable_characters(text: str, replacement: str = "▯") -> str: + return "".join(replacement if is_non_printable_char(c) else c for c in text) + + +def is_non_printable_char(char: str) -> bool: + return 0 <= ord(char) < 32 and char != "\t" + + +def text_wrap( + text: str, + box_width: Optional[float], + get_text_width: Callable[[str], float], +) -> list[str]: + """Wrap text at ``\\n`` and given `box_width`. This tool was developed for + usage with the MTEXT entity. This isn't the most straightforward word + wrapping algorithm, but it aims to match the behavior of AutoCAD. + + Args: + text: text to wrap, included ``\\n`` are handled as manual line breaks + box_width: wrapping length, ``None`` to just wrap at ``\\n`` + get_text_width: callable which returns the width of the given string + + """ + # Copyright (c) 2020-2021, Matthew Broadway + # License: MIT License + if not text or text.isspace(): + return [] + manual_lines = re.split(r"(\n)", text) # includes \n as its own token + tokens = [t for line in manual_lines for t in re.split(r"(\s+)", line) if t] + lines: list[str] = [] + current_line: str = "" + line_just_wrapped = False + + for t in tokens: + on_first_line = not lines + if t == "\n" and line_just_wrapped: + continue + line_just_wrapped = False + if t == "\n": + lines.append(current_line.rstrip()) + current_line = "" + elif t.isspace(): + if current_line or on_first_line: + current_line += t + else: + if box_width is not None and get_text_width(current_line + t) > box_width: + if not current_line: + current_line += t + else: + lines.append(current_line.rstrip()) + current_line = t + line_just_wrapped = True + else: + current_line += t + + if current_line and not current_line.isspace(): + lines.append(current_line.rstrip()) + return lines + + +def is_text_vertical_stacked(text: DXFEntity) -> bool: + """Returns ``True`` if the associated text :class:`~ezdxf.entities.Textstyle` + is vertical stacked. + """ + if not text.is_supported_dxf_attrib("style"): + raise TypeError(f"{text.dxftype()} does not support the style attribute.") + + if text.doc: + style = text.doc.styles.get(text.dxf.style) + if style: + return style.is_vertical_stacked + return False + + +_alignment_char = { + MTextParagraphAlignment.DEFAULT: "", + MTextParagraphAlignment.LEFT: "l", + MTextParagraphAlignment.RIGHT: "r", + MTextParagraphAlignment.CENTER: "c", + MTextParagraphAlignment.JUSTIFIED: "j", + MTextParagraphAlignment.DISTRIBUTED: "d", +} + +COMMA = "," +DIGITS = "01234567890" + + +def rstrip0(s: str) -> str: + if isinstance(s, (int, float)): + return f"{s:g}" + return s + + +class ParagraphProperties(NamedTuple): + """Stores all known MTEXT paragraph properties in a :class:`NamedTuple`. + Indentations and tab stops are multiples of the default text height + :attr:`MText.dxf.char_height`. E.g. :attr:`char_height` is 0.25 and + :attr:`indent` is 4, the real indentation is 4 x 0.25 = 1 drawing unit. + The default tabulator stops are 4, 8, 12, ... if no tabulator stops are + explicit defined. + + Args: + indent (float): left indentation of the first line, relative to :attr:`left`, + which means an :attr:`indent` of 0 has always the same indentation + as :attr:`left` + left (float): left indentation of the paragraph except for the first line + right (float): left indentation of the paragraph + align: :class:`~ezdxf.lldxf.const.MTextParagraphAlignment` enum + tab_stops: tuple of tabulator stops, as ``float`` or as ``str``, + ``float`` values are left aligned tab stops, strings with prefix + ``"c"`` are center aligned tab stops and strings with prefix ``"r"`` + are right aligned tab stops + + """ + + # Reset: \pi*,l*,r*,q*,t; + indent: float = 0 # relative to left! + left: float = 0 + right: float = 0 + align: MTextParagraphAlignment = MTextParagraphAlignment.DEFAULT + # tab stops without prefix or numbers are left adjusted + # tab stops, e.g 2 or '2' + # prefix 'c' defines a center adjusted tab stop e.g. 'c3.5' + # prefix 'r' defines a right adjusted tab stop e.g. 'r2.7' + # The tab stop in drawing units = n x char_height + tab_stops: tuple = tuple() + + def tostring(self) -> str: + """Returns the MTEXT paragraph properties as MTEXT inline code + e.g. ``"\\pxi-2,l2;"``. + + """ + args = [] + if self.indent: + args.append(f"i{self.indent:g}") + args.append(COMMA) + if self.left: + args.append(f"l{self.left:g}") + args.append(COMMA) + if self.right: + args.append(f"r{self.right:g}") + args.append(COMMA) + if self.align: + args.append(f"q{_alignment_char[self.align]}") + args.append(COMMA) + if self.tab_stops: + args.append(f"t{COMMA.join(map(rstrip0, self.tab_stops))}") + args.append(COMMA) + + if args: + if args[-1] == COMMA: + args.pop() + # exporting always "x" as second letter seems to be safe + return "\\px" + "".join(args) + ";" + return "" + + +# IMPORTANT for parsing MTEXT inline codes: "\\H0.1\\A1\\C1rot" +# Inline commands with a single argument, don't need a trailing ";"! + + +class MTextEditor: + """The :class:`MTextEditor` is a helper class to build MTEXT content + strings with support for inline codes to change color, font or + paragraph properties. The result is always accessible by the :attr:`text` + attribute or the magic :func:`__str__` function as + :code:`str(MTextEditor("text"))`. + + All text building methods return `self` to implement a floating interface:: + + e = MTextEditor("This example ").color("red").append("switches color to red.") + mtext = msp.add_mtext(str(e)) + + The initial text height, color, text style and so on is determined by the + DXF attributes of the :class:`~ezdxf.entities.MText` entity. + + .. warning:: + + The :class:`MTextEditor` assembles just the inline code, which has to be + parsed and rendered by the target CAD application, `ezdxf` has no influence + to that result. + + Keep inline formatting as simple as possible, don't test the limits of its + capabilities, this will not work across different CAD applications and keep + the formatting in a logic manner like, do not change paragraph properties + in the middle of a paragraph. + + **There is no official documentation for the inline codes!** + + Args: + text: init value of the MTEXT content string. + + """ + + def __init__(self, text: str = ""): + self.text = str(text) + + NEW_LINE = r"\P" + NEW_PARAGRAPH = r"\P" + NEW_COLUMN = r"\N" + UNDERLINE_START = r"\L" + UNDERLINE_STOP = r"\l" + OVERSTRIKE_START = r"\O" + OVERSTRIKE_STOP = r"\o" + STRIKE_START = r"\K" + STRIKE_STOP = r"\k" + GROUP_START = "{" + GROUP_END = "}" + ALIGN_BOTTOM = r"\A0;" + ALIGN_MIDDLE = r"\A1;" + ALIGN_TOP = r"\A2;" + NBSP = r"\~" # non-breaking space + TAB = "^I" + + def append(self, text: str) -> MTextEditor: + """Append `text`.""" + self.text += text + return self + + def __iadd__(self, text: str) -> MTextEditor: + r""" + Append `text`:: + + e = MTextEditor("First paragraph.\P") + e += "Second paragraph.\P") + + """ + self.text += text + return self + + def __str__(self) -> str: + """Returns the MTEXT content attribute :attr:`text`.""" + return self.text + + def clear(self): + """Reset the content to an empty string.""" + self.text = "" + + def font(self, name: str, bold: bool = False, italic: bool = False) -> MTextEditor: + """Set the text font by the font family name. Changing the font height + should be done by the :meth:`height` or the :meth:`scale_height` method. + The font family name is the name shown in font selection widgets in + desktop applications: "Arial", "Times New Roman", "Comic Sans MS". + Switching the codepage is not supported. + + Args: + name: font family name + bold: flag + italic: flag + + """ + # c0 = current codepage + # The current implementation of ezdxf writes everything in one + # encoding, defined by $DWGCODEPAGE < DXF R2007 or utf8 for DXF R2007+ + # Switching codepage makes no sense! + # p0 = current text size; + # Text size should be changed by \Hx; + return self.append(rf"\f{name}|b{int(bold)}|i{int(italic)};") + + def scale_height(self, factor: float) -> MTextEditor: + """Scale the text height by a `factor`. This scaling will accumulate, + which means starting at height 2.5 and scaling by 2 and again by 3 will + set the text height to 2.5 x 2 x 3 = 15. The current text height is not + stored in the :class:`MTextEditor`, you have to track the text height by + yourself! The initial text height is stored in the + :class:`~ezdxf.entities.MText` entity as DXF attribute + :class:`~ezdxf.entities.MText.dxf.char_height`. + + """ + return self.append(rf"\H{round(factor, 3)}x;") + + def height(self, height: float) -> MTextEditor: + """Set the absolute text height in drawing units.""" + return self.append(rf"\H{round(height, 3)};") + + def width_factor(self, factor: float) -> MTextEditor: + """Set the absolute text width factor.""" + return self.append(rf"\W{round(factor, 3)};") + + def char_tracking_factor(self, factor: float) -> MTextEditor: + """Set the absolute character tracking factor.""" + return self.append(rf"\T{round(factor, 3)};") + + def oblique(self, angle: int) -> MTextEditor: + """Set the text oblique angle in degrees, vertical is 0, a value of 15 + will lean the text 15 degree to the right. + + """ + return self.append(rf"\Q{int(angle)};") + + def color(self, name: str) -> MTextEditor: + """Set the text color by color name: "red", "yellow", "green", "cyan", + "blue", "magenta" or "white". + + """ + return self.aci(const.MTEXT_COLOR_INDEX[name.lower()]) + + def aci(self, aci: int) -> MTextEditor: + """Set the text color by :ref:`ACI` in range [0, 256].""" + if 0 <= aci <= 256: + return self.append(rf"\C{aci};") + raise ValueError("aci not in range [0, 256]") + + def rgb(self, rgb: RGB) -> MTextEditor: + """Set the text color as RGB value.""" + r, g, b = rgb + return self.append(rf"\c{rgb2int((b, g, r))};") + + def stack(self, upr: str, lwr: str, t: str = "^") -> MTextEditor: + r"""Append stacked text `upr` over `lwr`, argument `t` defines the + kind of stacking, the space " " after the "^" will be added + automatically to avoid caret decoding: + + .. code-block:: none + + "^": vertical stacked without divider line, e.g. \SA^ B: + A + B + + "/": vertical stacked with divider line, e.g. \SX/Y: + X + - + Y + + "#": diagonal stacked, with slanting divider line, e.g. \S1#4: + 1/4 + + """ + if t not in "^/#": + raise ValueError(f"invalid type symbol: {t}") + # space " " after "^" is required to avoid caret decoding + if t == "^": + t += " " + return self.append(rf"\S{upr}{t}{lwr};") + + def group(self, text: str) -> MTextEditor: + """Group `text`, all properties changed inside a group are reverted at + the end of the group. AutoCAD supports grouping up to 8 levels. + + """ + return self.append(f"{{{text}}}") + + def underline(self, text: str) -> MTextEditor: + """Append `text` with a line below the text.""" + return self.append(rf"\L{text}\l") + + def overline(self, text: str) -> MTextEditor: + """Append `text` with a line above the text.""" + return self.append(rf"\O{text}\o") + + def strike_through(self, text: str) -> MTextEditor: + """Append `text` with a line through the text.""" + return self.append(rf"\K{text}\k") + + def paragraph(self, props: ParagraphProperties) -> MTextEditor: + """Set paragraph properties by a :class:`ParagraphProperties` object.""" + return self.append(props.tostring()) + + def bullet_list( + self, indent: float, bullets: Iterable[str], content: Iterable[str] + ) -> MTextEditor: + """Build bulleted lists by utilizing paragraph indentation and a + tabulator stop. Any string can be used as bullet. Indentation is + a multiple of the initial MTEXT char height (see also docs about + :class:`ParagraphProperties`), which means indentation in + drawing units is :attr:`MText.dxf.char_height` x `indent`. + + Useful UTF bullets: + + - "bull" U+2022 = • (Alt Numpad 7) + - "circle" U+25CB = ○ (Alt Numpad 9) + + For numbered lists just use numbers as bullets:: + + MTextEditor.bullet_list( + indent=2, + bullets=["1.", "2."], + content=["first", "second"], + ) + + Args: + indent: content indentation as multiple of the initial MTEXT char height + bullets: iterable of bullet strings, e.g. :code:`["-"] * 3`, + for 3 dashes as bullet strings + content: iterable of list item strings, one string per list item, + list items should not contain new line or new paragraph commands. + + """ + items = MTextEditor().paragraph( + ParagraphProperties( + indent=-indent * 0.75, # like BricsCAD + left=indent, + tab_stops=(indent,), + ) + ) + items.append( + "".join( + b + self.TAB + c + self.NEW_PARAGRAPH for b, c in zip(bullets, content) + ) + ) + return self.group(str(items)) + + +class UnknownCommand(Exception): + pass + + +class MTextContext: + """Internal class to store the MTEXT context state.""" + + def __init__(self) -> None: + from ezdxf.fonts import fonts + + self._stroke: int = 0 + self.continue_stroke: bool = False + self._aci = 7 # used if rgb is None + self.rgb: Optional[RGB] = None # overrules aci + self.align = MTextLineAlignment.BOTTOM + self.font_face = fonts.FontFace() # is immutable + self.cap_height: float = 1.0 + self.width_factor: float = 1.0 + self.char_tracking_factor: float = 1.0 + self.oblique: float = 0.0 # in degrees, where 0 is vertical (TEXT entity) + self.paragraph = ParagraphProperties() + + def __copy__(self) -> MTextContext: + p = MTextContext() + p._stroke = self._stroke + p.continue_stroke = self.continue_stroke + p._aci = self._aci + p.rgb = self.rgb + p.align = self.align + p.font_face = self.font_face # is immutable + p.cap_height = self.cap_height + p.width_factor = self.width_factor + p.char_tracking_factor = self.char_tracking_factor + p.oblique = self.oblique + p.paragraph = self.paragraph # is immutable + return p + + copy = __copy__ + + def __hash__(self): + return hash( + ( + self._stroke, + self.continue_stroke, + self._aci, + self.rgb, + self.align, + self.font_face, + self.cap_height, + self.width_factor, + self.char_tracking_factor, + self.oblique, + self.paragraph, + ) + ) + + def __eq__(self, other) -> bool: + return hash(self) == hash(other) + + @property + def aci(self) -> int: + return self._aci + + @aci.setter + def aci(self, aci: int): + if 0 <= aci <= 256: + self._aci = aci + self.rgb = None # clear rgb + else: + raise ValueError("aci not in range[0,256]") + + def _set_stroke_state(self, stroke: MTextStroke, state: bool = True) -> None: + """Set/clear binary `stroke` flag in `self._stroke`. + + Args: + stroke: set/clear stroke flag + state: ``True`` for setting, ``False`` for clearing + + """ + if state: + self._stroke |= stroke + else: + self._stroke &= ~stroke + + @property + def underline(self) -> bool: + return bool(self._stroke & MTextStroke.UNDERLINE) + + @underline.setter + def underline(self, value: bool) -> None: + self._set_stroke_state(MTextStroke.UNDERLINE, value) + + @property + def strike_through(self) -> bool: + return bool(self._stroke & MTextStroke.STRIKE_THROUGH) + + @strike_through.setter + def strike_through(self, value: bool) -> None: + self._set_stroke_state(MTextStroke.STRIKE_THROUGH, value) + + @property + def overline(self) -> bool: + return bool(self._stroke & MTextStroke.OVERLINE) + + @overline.setter + def overline(self, value: bool) -> None: + self._set_stroke_state(MTextStroke.OVERLINE, value) + + @property + def has_any_stroke(self) -> bool: + return bool(self._stroke) + + +class TextScanner: + __slots__ = ("_text", "_text_len", "_index") + + def __init__(self, text: str): + self._text = str(text) + self._text_len = len(self._text) + self._index = 0 + + @property + def is_empty(self) -> bool: + return self._index >= self._text_len + + @property + def has_data(self) -> bool: + return self._index < self._text_len + + def get(self) -> str: + try: + char = self._text[self._index] + self._index += 1 + except IndexError: + return "" + return char + + def consume(self, count: int = 1) -> None: + if count < 1: + raise ValueError(count) + self._index += count + + def fast_consume(self, count: int = 1) -> None: + """consume() without safety check""" + self._index += count + + def peek(self, offset: int = 0) -> str: + if offset < 0: + raise ValueError(offset) + try: + return self._text[self._index + offset] + except IndexError: + return "" + + def fast_peek(self, offset: int = 0) -> str: + """peek() without safety check""" + try: + return self._text[self._index + offset] + except IndexError: + return "" + + def find(self, char: str, escape=False) -> int: + """Return the index of the next `char`. If `escape` is True, backslash + escaped `chars` will be ignored e.g. "\\;;" index of the next ";" is 1 + if `escape` is False and 2 if `escape` is True. Returns -1 if `char` + was not found. + + Args: + char: single letter as string + escape: ignore backslash escaped chars if True. + + """ + + scanner = self.__class__(self._text[self._index :]) + while scanner.has_data: + c = scanner.peek() + if escape and c == "\\" and scanner.peek(1) == char: + scanner.consume(2) + continue + if c == char: + return self._index + scanner._index # pylint: disable=w0212 + scanner.consume(1) + return -1 + + def substr(self, stop: int) -> str: + """Returns the substring from the current location until index < stop.""" + if stop < self._index: + raise IndexError(stop) + return self._text[self._index : stop] + + def tail(self) -> str: + """Returns the unprocessed part of the content.""" + return self._text[self._index :] + + def index(self) -> int: + return self._index + + def substr2(self, start: int, stop: int) -> str: + return self._text[start:stop] + + +class TokenType(enum.IntEnum): + NONE = 0 + WORD = 1 # data = str + STACK = 2 # data = tuple[upr: str, lwr:str, type:str] + SPACE = 3 # data = None + NBSP = 4 # data = None + TABULATOR = 5 # data = None + NEW_PARAGRAPH = 6 # data = None + NEW_COLUMN = 7 # data = None + WRAP_AT_DIMLINE = 8 # data = None + PROPERTIES_CHANGED = 9 # data = full command string e.g. "\H150;" + + +class MTextToken: + __slots__ = ("type", "ctx", "data") + + def __init__(self, t: TokenType, ctx: MTextContext, data=None): + self.type: TokenType = t + self.ctx: MTextContext = ctx + self.data = data + + +RE_FLOAT = re.compile(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?") +RE_FLOAT_X = re.compile(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?([x]?)") + +CHAR_TO_ALIGN = { + "l": MTextParagraphAlignment.LEFT, + "r": MTextParagraphAlignment.RIGHT, + "c": MTextParagraphAlignment.CENTER, + "j": MTextParagraphAlignment.JUSTIFIED, + "d": MTextParagraphAlignment.DISTRIBUTED, +} + + +class MTextParser: + """Parses the MText content string and yields the content as tokens and + the current MText properties as MTextContext object. The context object is + treated internally as immutable object and should be treated by the client + the same way. + + The parser works as iterator and yields MTextToken objects. + + Args: + content: MText content string + ctx: initial MText context + yield_property_commands: yield commands that change properties or context, + default is ``False`` + + """ + + def __init__( + self, + content: str, + ctx: Optional[MTextContext] = None, + yield_property_commands=False, + ): + if ctx is None: + ctx = MTextContext() + self.ctx = ctx + self.scanner = TextScanner(caret_decode(content)) + self._ctx_stack: list[MTextContext] = [] + self._continue_stroke = False + self._yield_property_commands = bool(yield_property_commands) + + def __iter__(self) -> Iterator[MTextToken]: + return self.parse() + + def push_ctx(self) -> None: + self._ctx_stack.append(self.ctx) + + def pop_ctx(self) -> None: + if self._ctx_stack: + self.ctx = self._ctx_stack.pop() + + def parse(self) -> Iterator[MTextToken]: + # pylint: disable=too-many-statements + # localize method calls + scanner = self.scanner + consume = scanner.fast_consume + peek = scanner.fast_peek + followup_token: Optional[TokenType] = None + space_token = TokenType.SPACE + word_token = TokenType.WORD + + def word_and_token(word, token): + nonlocal followup_token + consume() + if word: + followup_token = token + return word_token, word + return token, None + + def next_token() -> tuple[TokenType, Any]: + # pylint: disable=too-many-return-statements,too-many-branches,too-many-nested-blocks + word: str = "" + while scanner.has_data: + escape = False + letter = peek() + cmd_start_index = scanner.index() + if letter == "\\": + # known escape sequences: "\\", "\{", "\}" + if peek(1) in "\\{}": + escape = True + consume() # leading backslash + letter = peek() + else: + # A non escaped backslash is always the end of a word. + if word: + # Do not consume backslash! + return word_token, word + consume() # leading backslash + cmd = scanner.get() + if cmd == "~": + return TokenType.NBSP, None + if cmd == "P": + return TokenType.NEW_PARAGRAPH, None + if cmd == "N": + return TokenType.NEW_COLUMN, None + if cmd == "X": + return TokenType.WRAP_AT_DIMLINE, None + if cmd == "S": + return self.parse_stacking() + if cmd: + try: + self.parse_properties(cmd) + except UnknownCommand: + # print invalid escaped letters verbatim + word += letter + cmd + else: + if self._yield_property_commands: + return ( + TokenType.PROPERTIES_CHANGED, + scanner.substr2( + cmd_start_index, scanner.index() + ), + ) + continue + + # process control chars, caret decoding is already done! + if letter < " ": + if letter == "\t": + return word_and_token(word, TokenType.TABULATOR) + if letter == "\n": # LF + return word_and_token(word, TokenType.NEW_PARAGRAPH) + # replace other control chars by a space + letter = " " + elif letter == "%" and peek(1) == "%": + code = peek(2).lower() + special_char = const.SPECIAL_CHAR_ENCODING.get(code) + if special_char: + consume(2) # %% + letter = special_char + + if letter == " ": + return word_and_token(word, space_token) + + if not escape: + if letter == "{": + if word: + return word_token, word + else: + consume(1) + self.push_ctx() + continue + elif letter == "}": + if word: + return word_token, word + else: + consume(1) + self.pop_ctx() + continue + + # any unparsed unicode letter can be used in a word + consume() + if letter >= " ": + word += letter + + if word: + return word_token, word + else: + return TokenType.NONE, None + + while True: + type_, data = next_token() + if type_: + yield MTextToken(type_, self.ctx, data) + if followup_token: + yield MTextToken(followup_token, self.ctx, None) + followup_token = None + else: + break + + def parse_stacking(self) -> tuple[TokenType, Any]: + """Returns a tuple of strings: (numerator, denominator, type). + The numerator and denominator is always a single and can contain spaces, + which are not decoded as separate tokens. The type string is "^" for + a limit style fraction without a line, "/" for a horizontal fraction + and "#" for a diagonal fraction. If the expression does not contain + any stacking type char, the type and denominator string are empty "". + + """ + + def peek_char(): + c = stacking_scanner.peek() + if ord(c) < 32: # replace all control chars by space + c = " " + return c + + def get_next_char(): + escape = False + c = peek_char() + # escape sequences: remove backslash and return next char + if c == "\\": + escape = True + stacking_scanner.consume(1) + c = peek_char() + stacking_scanner.consume(1) + return c, escape + + def parse_numerator() -> tuple[str, str]: + word = "" + while stacking_scanner.has_data: + c, escape = get_next_char() + if not escape and c in "^/#": # scan until stacking type char + return word, c + word += c + return word, "" + + def parse_denominator() -> str: + word = "" + while stacking_scanner.has_data: + word += get_next_char()[0] + return word + + stacking_scanner = TextScanner(self.extract_expression(escape=True)) + numerator, stacking_type = parse_numerator() + denominator = parse_denominator() if stacking_type else "" + return TokenType.STACK, (numerator, denominator, stacking_type) + + def parse_properties(self, cmd: str) -> None: + # pylint: disable=too-many-branches + # Treat the existing context as immutable, create a new one: + new_ctx = self.ctx.copy() + if cmd == "L": + new_ctx.underline = True + self._continue_stroke = True + elif cmd == "l": + new_ctx.underline = False + if not new_ctx.has_any_stroke: + self._continue_stroke = False + elif cmd == "O": + new_ctx.overline = True + self._continue_stroke = True + elif cmd == "o": + new_ctx.overline = False + if not new_ctx.has_any_stroke: + self._continue_stroke = False + elif cmd == "K": + new_ctx.strike_through = True + self._continue_stroke = True + elif cmd == "k": + new_ctx.strike_through = False + if not new_ctx.has_any_stroke: + self._continue_stroke = False + elif cmd == "A": + self.parse_align(new_ctx) + elif cmd == "C": + self.parse_aci_color(new_ctx) + elif cmd == "c": + self.parse_rgb_color(new_ctx) + elif cmd == "H": + self.parse_height(new_ctx) + elif cmd == "W": + self.parse_width(new_ctx) + elif cmd == "Q": + self.parse_oblique(new_ctx) + elif cmd == "T": + self.parse_char_tracking(new_ctx) + elif cmd == "p": + self.parse_paragraph_properties(new_ctx) + elif cmd == "f" or cmd == "F": + self.parse_font_properties(new_ctx) + else: + raise UnknownCommand(f"unknown command: {cmd}") + new_ctx.continue_stroke = self._continue_stroke + self.ctx = new_ctx + + def parse_align(self, ctx: MTextContext): + char = self.scanner.get() # always consume next char + if char in "012": + ctx.align = MTextLineAlignment(int(char)) + else: + ctx.align = MTextLineAlignment.BOTTOM + self.consume_optional_terminator() + + def parse_height(self, ctx: MTextContext): + ctx.cap_height = self.parse_float_value_or_factor(ctx.cap_height) + self.consume_optional_terminator() + + def parse_width(self, ctx: MTextContext): + ctx.width_factor = self.parse_float_value_or_factor(ctx.width_factor) + self.consume_optional_terminator() + + def parse_char_tracking(self, ctx: MTextContext): + ctx.char_tracking_factor = self.parse_float_value_or_factor( + ctx.char_tracking_factor + ) + self.consume_optional_terminator() + + def parse_float_value_or_factor(self, value) -> float: + expr = self.extract_float_expression(relative=True) + if expr: + if expr.endswith("x"): + factor = float(expr[:-1]) + value *= abs(factor) + else: + value = abs(float(expr)) + return value + + def parse_oblique(self, ctx: MTextContext): + oblique_expr = self.extract_float_expression(relative=False) + if oblique_expr: + ctx.oblique = float(oblique_expr) + self.consume_optional_terminator() + + def parse_aci_color(self, ctx: MTextContext): + aci_expr = self.extract_int_expression() + if aci_expr: + aci = int(aci_expr) + if aci < 257: + ctx.aci = aci + ctx.rgb = None + self.consume_optional_terminator() + + def parse_rgb_color(self, ctx: MTextContext): + rgb_expr = self.extract_int_expression() + if rgb_expr: + # in reversed order! + b, g, r = int2rgb(int(rgb_expr) & 0xFFFFFF) + ctx.rgb = RGB(r, g, b) + self.consume_optional_terminator() + + def extract_float_expression(self, relative=False) -> str: + result = "" + tail = self.scanner.tail() + pattern = RE_FLOAT_X if relative else RE_FLOAT + match = re.match(pattern, tail) + if match: + start, end = match.span() + result = tail[start:end] + self.scanner.consume(end) + return result + + def extract_int_expression(self) -> str: + result = "" + tail = self.scanner.tail() + match = re.match(r"\d+", tail) + if match: + start, end = match.span() + result = tail[start:end] + self.scanner.consume(end) + return result + + def extract_expression(self, escape=False) -> str: + """Returns the next expression from the current location until + the terminating ";". The terminating semicolon is not included. + Skips escaped "\\;" semicolons if `escape` is True. + + """ + stop = self.scanner.find(";", escape=escape) + if stop < 0: # ";" not found + expr = self.scanner.tail() # scan until end of content + else: + expr = self.scanner.substr(stop) # exclude ";" + # skip the expression in the main scanner + self.scanner.consume(len(expr) + 1) # include ";" + return expr + + def parse_paragraph_properties(self, ctx: MTextContext): + def parse_float() -> float: + value = 0.0 + expr = parse_float_expr() + if expr: + value = float(expr) + return value + + def parse_float_expr() -> str: + expr = "" + tail = paragraph_scanner.tail() + match = re.match(RE_FLOAT, tail) + if match: + start, end = match.span() + expr = tail[start:end] + paragraph_scanner.consume(end) + skip_commas() + return expr + + def skip_commas(): + while paragraph_scanner.peek() == ",": + paragraph_scanner.consume(1) + + paragraph_scanner = TextScanner(self.extract_expression()) + indent, left, right, align, tab_stops = ctx.paragraph # NamedTuple + while paragraph_scanner.has_data: + cmd = paragraph_scanner.get() + if cmd == "i": + indent = parse_float() + elif cmd == "l": + left = parse_float() + elif cmd == "r": + right = parse_float() + elif cmd == "x": + pass # ignore + elif cmd == "q": + adjustment = paragraph_scanner.get() + align = CHAR_TO_ALIGN.get(adjustment, MTextParagraphAlignment.DEFAULT) + skip_commas() + elif cmd == "t": + tab_stops = [] # type: ignore + while paragraph_scanner.has_data: # parse to end + type_ = paragraph_scanner.peek() + if type_ == "r" or type_ == "c": + paragraph_scanner.consume() + tab_stops.append(type_ + parse_float_expr()) # type: ignore + else: + float_expr = parse_float_expr() + if float_expr: + tab_stops.append(float(float_expr)) # type: ignore + else: + # invalid float expression, consume invalid letter + # and try again: + paragraph_scanner.consume() + ctx.paragraph = ParagraphProperties( + indent, left, right, align, tuple(tab_stops) + ) + + def parse_font_properties(self, ctx: MTextContext): + from ezdxf.fonts import fonts + + parts = self.extract_expression().split("|") + # an empty font family name does not change the font properties + if parts and parts[0]: + name = parts[0] + style = "Regular" + weight = 400 + # ignore codepage and pitch - it seems not to be used in newer + # CAD applications. + for part in parts[1:]: + if part.startswith("b1"): + weight = 700 + elif part.startswith("i1"): + style = "Italic" + ctx.font_face = fonts.FontFace(family=name, style=style, weight=weight) + + def consume_optional_terminator(self): + if self.scanner.peek() == ";": + self.scanner.consume(1) + + +def load_mtext_content(tags: Tags) -> str: + tail = "" + content = "" + for code, value in tags: + if code == 1: + tail = value + elif code == 3: + content += value + return escape_dxf_line_endings(content + tail) + + +def has_inline_formatting_codes(text: str) -> bool: + """Returns `True` if `text` contains any MTEXT inline formatting codes.""" + # Each inline formatting code starts with a backslash "\". + # Remove all special chars starting with a "\" and test if any backslashes + # remain. Escaped backslashes "\\" may return false positive, + # but they are rare. + # Replacing multiple strings at once by "re" is much slower, + # see profiling/string_replace.py + return "\\" in text.replace( # line breaks + r"\P", "" + ).replace( # non breaking spaces + r"\~", "" + ) + + +def is_upside_down_text_angle(angle: float, tol: float = 3.0) -> bool: + """Returns ``True`` if the given text `angle` in degrees causes an upside + down text in the :ref:`WCS`. The strict flip range is 90° < `angle` < 270°, + the tolerance angle `tol` extends this range to: 90+tol < `angle` < 270-tol. + The angle is normalized to [0, 360). + + Args: + angle: text angle in degrees + tol: tolerance range in which text flipping will be avoided + + """ + angle %= 360.0 + return 90.0 + tol < angle < 270.0 - tol + + +def upright_text_angle(angle: float, tol: float = 3.0) -> float: + """Returns a readable (upright) text angle in the range `angle` <= 90+tol or + `angle` >= 270-tol. The angle is normalized to [0, 360). + + Args: + angle: text angle in degrees + tol: tolerance range in which text flipping will be avoided + + """ + if is_upside_down_text_angle(angle, tol): + angle += 180.0 + return angle % 360.0 + + +def leading(cap_height: float, line_spacing: float = 1.0) -> float: + """Returns the distance from baseline to baseline. + + Args: + cap_height: cap height of the line + line_spacing: line spacing factor as percentage of 3-on-5 spacing + + """ + # method "exact": 3-on-5 line spacing = 5/3 = 1.667 + # method "at least" is not supported + return cap_height * 1.667 * line_spacing + + +def estimate_mtext_extents(mtext: MText) -> tuple[float, float]: + """Estimate the width and height of a single column + :class:`~ezdxf.entities.MText` entity. + + This function is faster than the :func:`~ezdxf.tools.text_size.mtext_size` + function, but the result is very inaccurate if inline codes are used or + line wrapping at the column border is involved! + + Returns: + Tuple[width, height] + + """ + + def _make_font() -> fonts.AbstractFont: + from ezdxf.fonts import fonts + + cap_height: float = mtext.dxf.get_default("char_height") + doc = mtext.doc + if doc: + style = doc.styles.get(mtext.dxf.get_default("style")) + if style is not None: + return style.make_font(cap_height) + return fonts.make_font(const.DEFAULT_TTF, cap_height=cap_height) + + return estimate_mtext_content_extents( + content=mtext.text, + font=_make_font(), + column_width=mtext.dxf.get("width", 0.0), + line_spacing_factor=mtext.dxf.get_default("line_spacing_factor"), + ) + + +_SAFETY_FACTOR = 1.01 + + +def set_estimation_safety_factor(factor: float) -> None: + """Set the global safety factor for MTEXT size estimation.""" + global _SAFETY_FACTOR + _SAFETY_FACTOR = factor + + +def reset_estimation_safety_factor() -> None: + """Reset the global safety factor for MTEXT size estimation to the hard coded + default value. + """ + global _SAFETY_FACTOR + _SAFETY_FACTOR = 1.01 + + +def estimate_mtext_content_extents( + content: str, + font: fonts.AbstractFont, + column_width: float = 0.0, + line_spacing_factor: float = 1.0, +) -> tuple[float, float]: + """Estimate the width and height of the :class:`~ezdxf.entities.MText` + content string. The result is very inaccurate if inline codes are used or + line wrapping at the column border is involved! + Column breaks ``\\N`` will be ignored. + + Args: + content: the :class:`~ezdxf.entities.MText` content string + font: font abstraction based on :class:`ezdxf.tools.fonts.AbstractFont` + column_width: :attr:`MText.dxf.width` or 0.0 for an unrestricted column + width + line_spacing_factor: :attr:`MText.dxf.line_spacing_factor` + + Returns: + tuple[width, height] + + """ + max_width: float = 0.0 + height: float = 0.0 + cap_height: float = font.measurements.cap_height + has_column_width: bool = column_width > 0.0 + lines: list[str] = fast_plain_mtext(content, split=True) # type: ignore + + if any(lines): # has any non-empty lines + line_count: int = 0 + for line in lines: + line_width = font.text_width(line) + if line_width == 0 and line: + # line contains only white space and text_width() returns 0 + # - MatplotlibFont returns 0 as text width + # - MonospaceFont returns the correct width + line_width = len(line) * font.space_width() + if has_column_width: + # naive line wrapping, does not care about line content + line_count += math.ceil(line_width / column_width) + line_width = min(line_width, column_width) + else: + line_count += 1 + # Note: max_width can be smaller than the column_width, if all lines + # are shorter than column_width! + max_width = max(max_width, line_width) + + spacing = leading(cap_height, line_spacing_factor) - cap_height + height = cap_height * line_count + spacing * (line_count - 1) + + return max_width * _SAFETY_FACTOR, height + + +def safe_string(s: Optional[str], max_len: int = MAX_STR_LEN) -> str: + """Returns a string with line breaks ``\\n`` replaced by ``\\P`` and the + length limited to `max_len`. + """ + if isinstance(s, str): + return escape_dxf_line_endings(s)[:max_len] + return "" + + +VALID_HEIGHT_CHARS = set("0123456789.") + + +def scale_mtext_inline_commands(content: str, factor: float) -> str: + """Scale all inline commands which define an absolute value by a `factor`.""" + + def _scale_leading_number(substr: str, prefix: str) -> str: + index: int = 0 + try: + while substr[index] in VALID_HEIGHT_CHARS: + index += 1 + if substr[index] == "x": # relative factor + return f"{prefix}{substr}" + except IndexError: # end of string + pass + try: + new_size = float(substr[:index]) * factor + value = f"{new_size:.3g}" + except ValueError: + value = "" # return a valid construct + return rf"{prefix}{value}{substr[index:]}" + + # So far only the "\H;" command will be scaled. + # Fast check if scaling is required: + if r"\H" not in content: + return content + + factor = abs(factor) + old_parts = content.split(r"\H") + new_parts: list[str] = [old_parts[0]] + for part in old_parts[1:]: + new_parts.append(_scale_leading_number(part, r"\H")) + + return "".join(new_parts) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/text_layout.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/text_layout.py new file mode 100644 index 0000000..6c18d82 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/text_layout.py @@ -0,0 +1,1669 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Iterable, Optional, Tuple, NamedTuple +from typing_extensions import TypeAlias +import abc +import itertools +import enum + +from ezdxf.math import Matrix44, BoundingBox2d +from ezdxf.tools.text import leading + +""" + +Text Layout Engine +================== + +The main goal of this text layout engine is to layout words as boxes in +columns, paragraphs, and (bullet) lists. + +The starting point is a layout engine for MTEXT, which can be used for +different purposes like the drawing add-on or exploding MTEXT into DXF +primitives. But the engine is not bound to the MTEXT entity, the MTEXT +entity just defines the basic requirements. + +This engine works on given (text) boxes as input and does not render the glyphs +by itself nor does it have any knowledge about the glyphs, therefore individual +kerning between letters is not supported in anyway. As consequence the +"distributed" paragraph alignment of MTEXT can not be supported. + +Each input box can have an individual rendering object attached, derived from +the :class:`ContentRenderer` class, which requires two methods: + +1. method :meth:`render` to render the box content like the text or the + container background + +2. method :meth:`line` to render simple straight lines like under- and over + stroke lines or fraction dividers. + +Soft hyphens or auto word wrapping is not supported. + +Text direction is determined by the client by the given arrangement of the +input cells, but the vertical flow is always organized in lines from top to +bottom. + +The main work done by the layout engine is the placing of the given content +cells. The layout engine does not change the size of content cells and only +adjusts the width of glue cells e.g. "justified" paragraphs. + +Switching fonts or changing text size and -color has to be done by the client +at the process of dividing the input text into text- and glue cells and +assigning them appropriate rendering functions. + +The only text styling provided by the layout engine are strokes above, through +or below one or more words, which have to span across glue cells. + +Content organization +-------------------- + +The content is divided into containers (layout, column, paragraphs, ...) and +simple boxes for the actual content as cells like words and glue cells like +spaces or tabs. + +The basic content object is a text cell, which represents a single word. +Fractions of the MTEXT entity are supported by fraction cells. Content cells +have to be separated by mandatory glue cells. +Non breaking spaces have to be fed into the layout engine as special glue +element, because it is also a simple space, which should be adjustable in the +"justified" paragraph alignment. + +Containers +---------- + +All containers support margins. + +1. Layout + + Contains only columns. The size of the layout is determined by the + columns inside of the layout. Each column can have a different width. + +2. Column + + Contains only paragraphs. A Column has a fixed width, the height can be + fixed (MTEXT) or flexible. + +3. Paragraph + + A paragraph has a fixed width and the height is always flexible. + A paragraph can contain anything except the high level containers + Layout and Column. + + 3.1 FlowText, supports left, right, center and justified alignments; + indentation for the left side, the right side and the first line; + line spacing; no nested paragraphs or bullet lists; + The final content is distributed as lines (HCellGroup). + + 3.2 BulletList, the "bullet" can be any text cell, the flow text of each + list is an paragraph with left aligned text ... + +Simple Boxes +------------ + +Do not support margins. + +1. Glue cells + + The height of glue cells is always 0. + + 1.1 Space, flexible width but has a minimum width, possible line break + 1.2 Non breaking space, like a space but prevents line break between + adjacent text cells + 1.3 Tabulator, the current implementation treats tabulators like spaces. + +2. Content cells + + 2.1 Text cell - the height of a text cell is the cap height (height of + letter "X"), ascenders and descenders are ignored. + This is not a clipping box, the associated render object can still draw + outside of the box borders, this box is only used to determine the final + layout location. + + 2.2 Fraction cell ... (MTEXT!) + +3. AbstractLine + + A line contains only simple boxes and has a fixed width. + The height is determined by the tallest box of the group. + The content cells (words) are connected/separated by mandatory glue cells. + +""" + +LOREM_IPSUM = """Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed +diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed +diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet +clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +""" + + +class LayoutError(Exception): + pass + + +class Stacking(enum.IntEnum): + OVER = 0 + LINE = 1 + SLANTED = 2 + + +class LayoutAlignment(enum.IntEnum): + TOP_LEFT = 1 + TOP_CENTER = 2 + TOP_RIGHT = 3 + MIDDLE_LEFT = 4 + MIDDLE_CENTER = 5 + MIDDLE_RIGHT = 6 + BOTTOM_LEFT = 7 + BOTTOM_CENTER = 8 + BOTTOM_RIGHT = 9 + + +class CellAlignment(enum.IntEnum): + BOTTOM = 0 + CENTER = 1 + TOP = 2 + + +class ParagraphAlignment(enum.IntEnum): + LEFT = 1 + RIGHT = 2 + CENTER = 3 + JUSTIFIED = 4 + + +class TabStopType(enum.IntEnum): + LEFT = 0 + RIGHT = 1 + CENTER = 2 + + +class TabStop(NamedTuple): + pos: float = 0.0 + kind: TabStopType = TabStopType.LEFT + + +def lorem_ipsum(count=100): + return itertools.islice(itertools.cycle(LOREM_IPSUM.split()), count) + + +class ContentRenderer(abc.ABC): + @abc.abstractmethod + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ) -> None: + """Render content into the given borders (lower left and upper right + corners). + + Args: + left: x coordinate of the left border + bottom: y coordinate of the bottom border + right: x coordinate of the right border + top: y coordinate of the top border + m: transformation Matrix44 + + """ + + @abc.abstractmethod + def line( + self, x1: float, y1: float, x2: float, y2: float, m: Matrix44 = None + ) -> None: + """Draw a line from (x1, y1) to (x2, y2).""" + + +class DoNothingRenderer(ContentRenderer): + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Matrix44 = None, + ) -> None: + pass + + def line( + self, x1: float, y1: float, x2: float, y2: float, m: Matrix44 = None + ) -> None: + pass + + +Tuple4f: TypeAlias = Tuple[float, float, float, float] +Tuple2f: TypeAlias = Tuple[float, float] + + +def resolve_margins(margins: Optional[Sequence[float]]) -> Tuple4f: + """Returns the box margins in CSS like order: top, right, bottom, left.""" + if margins is None: + return 0, 0, 0, 0 + count = len(margins) + if count == 4: # CSS: top, right, bottom, left + return margins[0], margins[1], margins[2], margins[3] + if count == 3: # CSS: top, right, bottom, left=right + return margins[0], margins[1], margins[2], margins[1] + if count == 2: # CSS: top, right, bottom=top, left=right + return margins[0], margins[1], margins[0], margins[1] + if count == 1: # CSS: top, right=top, bottom=top, left=top + return margins[0], margins[0], margins[0], margins[0] + return 0, 0, 0, 0 + + +def insert_location(align: LayoutAlignment, width: float, height: float) -> Tuple2f: + """Returns the left top corner adjusted to the given alignment.""" + left: float = 0.0 + top: float = 0.0 + center = width / 2.0 + middle = height / 2.0 + if align == LayoutAlignment.TOP_LEFT: + pass + elif align == LayoutAlignment.TOP_CENTER: + left, top = (-center, 0) + elif align == LayoutAlignment.TOP_RIGHT: + left, top = (-width, 0) + elif align == LayoutAlignment.MIDDLE_LEFT: + left, top = (0, middle) + elif align == LayoutAlignment.MIDDLE_CENTER: + left, top = (-center, middle) + elif align == LayoutAlignment.MIDDLE_RIGHT: + left, top = (-width, middle) + elif align == LayoutAlignment.BOTTOM_LEFT: + left, top = (0, height) + elif align == LayoutAlignment.BOTTOM_CENTER: + left, top = (-center, height) + elif align == LayoutAlignment.BOTTOM_RIGHT: + left, top = (-width, height) + return left, top + + +class Box(abc.ABC): + @property + @abc.abstractmethod + def total_width(self) -> float: ... + + @property + @abc.abstractmethod + def total_height(self) -> float: ... + + @abc.abstractmethod + def place(self, x: float, y: float): + """(x, y) is the top/left corner""" + + @abc.abstractmethod + def final_location(self) -> tuple[float, float]: + """Returns the final location as the top/left corner""" + + @abc.abstractmethod + def render(self, m: Matrix44 = None) -> None: + """Render content at the final location.""" + + def bbox(self) -> BoundingBox2d: + """Returns the 2D bounding box of the container. If the cell is not placed the + top/left corner is (0, 0). + + """ + try: + x, y = self.final_location() + except (LayoutError, TypeError): + x, y = 0, 0 + return BoundingBox2d([(x, y), (x + self.total_width, y - self.total_height)]) + + +class Cell(Box): # ABC + is_visible = False + + def place(self, x: float, y: float): + # Base cells do not render anything, therefore placing the content is + # not necessary + pass + + def final_location(self) -> tuple[float, float]: + # Base cells do not render anything, therefore final location is not + # important + return 0, 0 + + def render(self, m: Matrix44 = None) -> None: + pass + + +class Glue(Cell): # ABC + EMPTY: tuple = tuple() + + def __init__( + self, + width: float, + min_width: Optional[float] = None, + max_width: Optional[float] = None, + ): + self._width: float = float(width) + self._min_width = float(min_width) if min_width else self._width + self._max_width: Optional[float] = max_width + + def resize(self, width: float): + max_width = self._max_width + if max_width is not None: + width = min(max_width, width) + self._width = max(width, self._min_width) + + @property + def can_shrink(self): + return self._min_width < self._width + + @property + def can_grow(self): + return self._max_width is None or self._width < self._max_width + + @property + def total_width(self) -> float: + return self._width + + @property + def total_height(self) -> float: + return 0 + + def to_space(self) -> Space: + return Space(self._width, self._min_width, self._max_width) + + +class Space(Glue): + pass + + +class NonBreakingSpace(Glue): + pass + + +class Tabulator(Glue): + pass + + +class ContentCell(Cell): # ABC + """Represents visible content like text or fractions. + + Supported vertical alignments (IntEnum): + + === ================= + int CellAlignment + === ================= + 0 BOTTOM + 1 CENTER + 2 TOP + === ================= + + """ + + is_visible = True + + def __init__( + self, + width: float, + height: float, + valign: CellAlignment = CellAlignment.BOTTOM, + renderer: Optional[ContentRenderer] = None, + ): + self._final_x: Optional[float] = None + self._final_y: Optional[float] = None + self._width = float(width) + self._height = float(height) + self.valign = CellAlignment(valign) # public attribute read/write + self.renderer = renderer + + def set_final_location(self, x: float, y: float): + self._final_x = x + self._final_y = y + + def final_location(self): + return self._final_x, self._final_y + + @property + def total_width(self) -> float: + return self._width + + @property + def total_height(self) -> float: + return self._height + + def place(self, x: float, y: float): + """(x, y) is the top/left corner""" + self._final_x = x + self._final_y = y + + +class Stroke: + # no enum because bit values can be combined: UNDERLINE + OVERLINE + NO_STROKE = 0 + UNDERLINE = 1 + STRIKE_THROUGH = 2 + OVERLINE = 4 + CONTINUE = 8 # continue stroke to following text cell + + +class Text(ContentCell): + """Represents visible text content. + + Supported strokes as bit values (flags), can be combined: + + === ================= + int Stroke + === ================= + 0 NO_STROKE + 1 UNDERLINE + 2 STRIKE THROUGH + 4 OVERLINE + 8 CONTINUE + === ================= + + The CONTINUE flag extends the stroke of the current text cell across the + glue cells to the following text cell. + + """ + + def __init__( + self, + width: float, + height: float, + valign: CellAlignment = CellAlignment.BOTTOM, + stroke: int = Stroke.NO_STROKE, + renderer: Optional[ContentRenderer] = None, + ): + super().__init__(width, height, valign, renderer) + self.stroke = int(stroke) # public attribute read/write + + def render(self, m: Optional[Matrix44] = None) -> None: + left, top = self.final_location() + height = self.total_height + bottom = top - height + right = left + self.total_width + self.renderer.render( # type: ignore + left=left, bottom=bottom, right=right, top=top, m=m + ) + + def render_stroke( + self, + extend_left: float = 0, + extend_right: float = 0, + m: Matrix44 = None, + ) -> None: + left, top = self.final_location() + left -= extend_left + height = self.total_height + bottom = top - height + right = left + self.total_width + extend_right + renderer = self.renderer + assert renderer is not None + + # render underline, strike through, overline + spacing = height / 5 # ??? + if self.stroke & Stroke.UNDERLINE: + y = bottom - spacing + renderer.line(left, y, right, y, m) + if self.stroke & Stroke.STRIKE_THROUGH: + y = (top + bottom) / 2 + renderer.line(left, y, right, y, m) + if self.stroke & Stroke.OVERLINE: + y = top + spacing + renderer.line(left, y, right, y, m) + + +def render_cells(cells: Iterable[Cell], m: Matrix44 = None) -> None: + for cell in cells: + if cell.is_visible: + cell.render(m) + + +def render_text_strokes(cells: list[Cell], m: Matrix44 = None) -> None: + """Render text cell strokes across glue cells.""" + + # Should be called for container with horizontal arranged text cells + # like HCellGroup to create underline, overline and strike through + # features. + # Can not render strokes across line breaks! + def stroke_extension(): + extend = 0 + i = index + 1 + count = len(cells) + while i < count: + cell = cells[i] + # extend stroke only across adjacent glue cells: + if isinstance(cell, Glue): + extend += cell.total_width + else: + break + i += 1 + return extend + + for index, cell in enumerate(cells): + if isinstance(cell, Text) and cell.stroke: + extend = stroke_extension() if cell.stroke & Stroke.CONTINUE else 0 + cell.render_stroke(extend_right=extend, m=m) + + +class Fraction(ContentCell): + """Represents visible fractions. + + Supported stacking A/B (IntEnum): + + === =========== ========= + int Stacking Description + === =========== ========= + 0 OVER A over B, without horizontal line + 1 LINE A over B, horizontal line between + 2 SLANTED A slanted line B + === =========== ========= + + """ + + HEIGHT_SCALE = 1.2 + + def __init__( + self, + top: ContentCell, + bottom: ContentCell, + stacking: Stacking = Stacking.OVER, + valign: CellAlignment = CellAlignment.BOTTOM, + renderer: Optional[ContentRenderer] = None, + ): + super().__init__(0, 0, valign, renderer) + self._stacking = stacking + self._top_content = top + self._bottom_content = bottom + self._update_size() + + def _update_size(self): + top = self._top_content + bottom = self._bottom_content + if self._stacking == Stacking.SLANTED: + self._height = top.total_height + bottom.total_height + self._width = top.total_width + bottom.total_width + else: + self._height = self.HEIGHT_SCALE * (top.total_height + bottom.total_height) + self._width = max(top.total_width, bottom.total_width) + + def place(self, x: float, y: float): + """(x, y) is the top/left corner""" + self._final_x = x + self._final_y = y + width = self.total_width + height = self.total_height + top_content = self._top_content + bottom_content = self._bottom_content + if top_content is None or bottom_content is None: + raise LayoutError("no content set") + + if self._stacking == Stacking.SLANTED: + top_content.place(x, y) # left/top + x += width - bottom_content.total_width + y -= height - bottom_content.total_height + bottom_content.place(x, y) # right/bottom + else: + center = x + width / 2 + x = center - top_content.total_width / 2 + top_content.place(x, y) # center/top + x = center - bottom_content.total_width / 2 + y -= height - bottom_content.total_height + bottom_content.place(x, y) # center/bottom + + def render(self, m: Matrix44 = None) -> None: + self._top_content.render(m) + self._bottom_content.render(m) + if self._stacking != Stacking.OVER: + self._render_line(m) + + def _render_line(self, m: Matrix44) -> None: + x, y = self.final_location() + tw = self.total_width + th = self.total_height + if self._stacking == Stacking.LINE: + x1 = x + x2 = x + tw + y1 = y2 = y - th / 2 + else: # SLANTED + delta = min(tw, th) / 2 + cx = x + self._top_content.total_width + cy = y - self._top_content.total_height + x1 = cx - delta + y1 = cy - delta + x2 = cx + delta + y2 = cy + delta + self.renderer.line(x1, y1, x2, y2, m) # type: ignore + + +_content = (Text, Fraction) +_glue = (Space, NonBreakingSpace, Tabulator) +_no_break = (Text, NonBreakingSpace) + + +def normalize_cells(cells: Iterable[Cell]) -> list[Cell]: + def replace_pending_nbsp_by_spaces(): + index = len(content) - 1 + while index >= 0: + cell = content[index] + if isinstance(cell, NonBreakingSpace): + content[index] = cell.to_space() + index -= 1 + else: + return + + def is_useless_nbsp(): + try: + peek = cells[index + 1] + except IndexError: + return True + if not isinstance(prev, _no_break) or not isinstance(peek, _no_break): + return True + return False + + content = [] + cells = list(cells) + prev = None + for index, cell in enumerate(cells): + if isinstance(cell, _content): + if isinstance(prev, _content): + raise LayoutError("no glue between content cells") + elif isinstance(cell, NonBreakingSpace) and is_useless_nbsp(): + cell = cell.to_space() + replace_pending_nbsp_by_spaces() + + prev = cell + content.append(cell) + + # remove pending glue: + while content and isinstance(content[-1], _glue): + content.pop() + + return content + + +class Container(Box): + def __init__( + self, + width: Optional[float], + height: Optional[float] = None, + margins: Optional[Sequence[float]] = None, + renderer: Optional[ContentRenderer] = None, + ): + self._final_x: Optional[float] = None + self._final_y: Optional[float] = None + + # _content_width is None for: defined by content + self._content_width: Optional[float] = width + + # _content_height is None for: defined by content + self._content_height: Optional[float] = height + + # margins are always defined + self._margins: Tuple4f = resolve_margins(margins) + + # content renderer is optional: + self.renderer: Optional[ContentRenderer] = renderer + + def place(self, x: float, y: float): + self._final_x = x + self._final_y = y + self.place_content() + + def final_location(self): + if not self.is_placed(): + raise LayoutError("Container is not placed.") + return self._final_x, self._final_y + + def is_placed(self) -> bool: + return self._final_x is not None and self._final_y is not None + + @abc.abstractmethod + def __iter__(self) -> Box: + pass + + @property + def top_margin(self) -> float: + return self._margins[0] + + @property + def right_margin(self) -> float: + return self._margins[1] + + @property + def bottom_margin(self) -> float: + return self._margins[2] + + @property + def left_margin(self) -> float: + return self._margins[3] + + @property + def content_width(self) -> float: + if self._content_width is None: + return 0 + else: + return self._content_width + + @property + def total_width(self) -> float: + return self.content_width + self.right_margin + self.left_margin + + @property + def content_height(self) -> float: + if self._content_height is None: + return 0 + else: + return self._content_height + + @property + def has_flex_height(self): + return self._content_height is None + + @property + def total_height(self) -> float: + return self.content_height + self.top_margin + self.bottom_margin + + def render(self, m: Matrix44 = None) -> None: + """Render container content. + + (x, y) is the top/left corner + """ + if not self.is_placed(): + raise LayoutError("Layout has to be placed before rendering") + if self.renderer: + self.render_background(m) + self.render_content(m) + + @abc.abstractmethod + def place_content(self): + """Place container content at the final location.""" + pass + + def render_content(self, m: Matrix44 = None) -> None: + """Render content at the final location.""" + for entity in self: # type: ignore + entity.render(m) + + def render_background(self, m: Matrix44) -> None: + """Render background at the final location.""" + # Render content background inclusive margins! + # (x, y) is the top/left corner + x, y = self.final_location() + if self.renderer: + self.renderer.render( + left=x, + bottom=y - self.total_height, + top=y, + right=x + self.total_width, + m=m, + ) + + +class EmptyParagraph(Cell): + """Spacer between two paragraphs, represents empty lines like in + "line1\n\nline2". + """ + + def __init__(self, cap_height: float, line_spacing: float = 1): + self._height: float = cap_height + self._width: float = 0 + self._last_line_spacing = leading(cap_height, line_spacing) - cap_height + + @property + def total_width(self) -> float: + return self._width + + @property + def total_height(self) -> float: + return self._height + + def set_total_width(self, width: float): + self._width = width + + def distribute_content(self, height: Optional[float] = None): + pass + + @property + def distance_to_next_paragraph(self) -> float: + return self._last_line_spacing + + +class Paragraph(Container): + def __init__( + self, + width: Optional[float] = None, # defined by parent container + align: ParagraphAlignment = ParagraphAlignment.LEFT, + indent: tuple[float, float, float] = (0, 0, 0), + line_spacing: float = 1, + margins: Optional[Sequence[float]] = None, + tab_stops: Optional[Sequence[TabStop]] = None, + renderer: Optional[ContentRenderer] = None, + ): + super().__init__(width, None, margins, renderer) + self._align = align + first, left, right = indent + self._indent_first = first + self._indent_left = left + self._indent_right = right + self._line_spacing = line_spacing + self._tab_stops = tab_stops or [] + + # contains the raw and not distributed content: + self._cells: list[Cell] = [] + + # contains the final distributed content: + self._lines: list[AbstractLine] = [] + + # space to next paragraph + self._last_line_spacing = 0.0 + + def __iter__(self): + return iter(self._lines) + + @property + def distance_to_next_paragraph(self): + return self._last_line_spacing + + def set_total_width(self, width: float): + self._content_width = width - self.left_margin - self.right_margin + if self._content_width < 1e-6: + raise LayoutError("invalid width, no usable space left") + + def append_content(self, content: Iterable[Cell]): + self._cells.extend(content) + + def line_width(self, first: bool) -> float: + indent = self._indent_right + indent += self._indent_first if first else self._indent_left + return self.content_width - indent + + def place_content(self): + x, y = self.final_location() + x += self.left_margin + y -= self.top_margin + first = True + lines = self._lines + for line in lines: + x_final = self._left_border(x, first) + line.place(x_final, y) + y -= leading(line.total_height, self._line_spacing) + first = False + + def _left_border(self, x: float, first: bool) -> float: + """Apply indentation and paragraph alignment""" + left_indent = self._indent_first if first else self._indent_left + return x + left_indent + + def _calculate_content_height(self) -> float: + """Returns the actual content height determined by the distributed + lines. + """ + lines = self._lines + line_spacing = self._line_spacing + height = 0.0 + if len(lines): + last_line = lines[-1] + height = sum( + leading(line.total_height, line_spacing) for line in lines[:-1] + ) + # do not add line spacing after last line! + last_line_height = last_line.total_height + self._last_line_spacing = ( + leading(last_line_height, line_spacing) - last_line_height + ) + height += last_line_height + return height + + def distribute_content(self, height: Optional[float] = None) -> Optional[Paragraph]: + """Distribute the raw content into lines. Returns the cells which do + not fit as a new paragraph. + + Args: + height: available total height (margins + content), ``None`` for + unrestricted paragraph height + + """ + + def new_line(width: float) -> AbstractLine: + if align in (ParagraphAlignment.LEFT, ParagraphAlignment.JUSTIFIED): + indent = self._indent_first if first else self._indent_left + tab_stops = shift_tab_stops(self._tab_stops, -indent, width) + return ( + LeftLine(width, tab_stops) + if align == ParagraphAlignment.LEFT + else JustifiedLine(width, tab_stops) + ) + elif align == ParagraphAlignment.RIGHT: + return RightLine(width) + elif align == ParagraphAlignment.CENTER: + return CenterLine(width) + else: + raise LayoutError(align) + + cells: list[Cell] = normalize_cells(self._cells) + cells = group_non_breakable_cells(cells) + # Delete raw content: + self._cells.clear() + + align: ParagraphAlignment = self._align + index: int = 0 # index of current cell + count: int = len(cells) + first: bool = True # is current line the first line? + + # current paragraph height: + paragraph_height: float = self.top_margin + self.bottom_margin + + # localize enums for core loop optimization: + # CPython 3.9 access is around 3x faster, no difference for PyPy 3.7! + FAIL, SUCCESS, FORCED = iter(AppendType) + while index < count: + # store index of first unprocessed cell to restore index, + # if not enough space in line + undo = index + line = new_line(self.line_width(first)) + has_tab_support = line.has_tab_support + while index < count: + # core loop of paragraph processing and the whole layout engine: + cell = cells[index] + if isinstance(cell, Tabulator) and has_tab_support: + append_state = line.append_with_tab( + # a tabulator cell has always a following cell, + # see normalize_cells()! + cells[index + 1], + cell, + ) + if append_state == SUCCESS: + index += 1 # consume tabulator + elif not line.has_content: + # The tabulator and the following word do no fit into a + # line -> ignore the tabulator + index += 1 + else: + append_state = line.append(cell) + # state check order by probability: + if append_state == SUCCESS: + index += 1 # consume current cell + elif append_state == FAIL: + break + elif append_state == FORCED: + index += 1 # consume current cell + break + + if line.has_content: + line.remove_line_breaking_space() + # remove line breaking space: + if index < count and isinstance(cells[index], Space): + index += 1 + + line_height = line.total_height + if ( + height is not None # restricted paragraph height + and paragraph_height + line_height > height + ): + # Not enough space for the new line: + index = undo + break + else: + first = False + self._lines.append(line) + paragraph_height += leading(line_height, self._line_spacing) + not_all_cells_processed = index < count + if align == ParagraphAlignment.JUSTIFIED: + # distribute justified text across the line width, + # except for the VERY last line: + end = len(self._lines) if not_all_cells_processed else -1 + for line in self._lines[:end]: + assert isinstance(line, JustifiedLine) + line.distribute() + + # Update content height: + self._content_height = self._calculate_content_height() + + # If not all cells could be processed, put them into a new paragraph + # and return it to the caller. + if not_all_cells_processed: + return self._new_paragraph(cells[index:], first) + else: + return None + + def _new_paragraph(self, cells: list[Cell], first: bool) -> Paragraph: + # First line of the paragraph included? + indent_first = self._indent_first if first else self._indent_left + indent = (indent_first, self._indent_left, self._indent_right) + paragraph = Paragraph( + self._content_width, + self._align, + indent, + self._line_spacing, + self._margins, + self._tab_stops, + self.renderer, + ) + paragraph.append_content(cells) + return paragraph + + +class Column(Container): + def __init__( + self, + width: float, + height: Optional[float] = None, + gutter: float = 0, + margins: Optional[Sequence[float]] = None, + renderer: Optional[ContentRenderer] = None, + ): + super().__init__(width, height, margins, renderer) + # spacing between columns + self._gutter = gutter + self._paragraphs: list[Paragraph] = [] + + def clone_empty(self) -> Column: + return self.__class__( + width=self.content_width, + height=self.content_height, + gutter=self.gutter, + margins=( + self.top_margin, + self.right_margin, + self.bottom_margin, + self.left_margin, + ), + renderer=self.renderer, + ) + + def __iter__(self): + return iter(self._paragraphs) + + def __len__(self): + return len(self._paragraphs) + + @property + def content_height(self) -> float: + """Returns the current content height for flexible columns and the + max. content height otherwise. + """ + max_height = self.max_content_height + if max_height is None: + return self.used_content_height() + else: + return max_height + + def used_content_height(self) -> float: + paragraphs = self._paragraphs + height = 0.0 + if paragraphs: + height = sum( + p.total_height + p.distance_to_next_paragraph for p in paragraphs[:-1] + ) + height += paragraphs[-1].total_height + return height + + @property + def gutter(self): + return self._gutter + + @property + def max_content_height(self) -> Optional[float]: + return self._content_height + + @property + def has_free_space(self) -> bool: + if self.max_content_height is None: # flexible height column + return True + return self.used_content_height() < self.max_content_height + + def place_content(self): + x, y = self.final_location() + x += self.left_margin + y -= self.top_margin + for p in self._paragraphs: + p.place(x, y) + y -= p.total_height + p.distance_to_next_paragraph + + def append_paragraphs(self, paragraphs: Iterable[Paragraph]) -> list[Paragraph]: + remainder: list[Paragraph] = [] + for paragraph in paragraphs: + if remainder: + remainder.append(paragraph) + continue + paragraph.set_total_width(self.content_width) + if self.has_flex_height: + height = None + else: + height = self.max_content_height - self.used_content_height() # type: ignore + rest = paragraph.distribute_content(height) + self._paragraphs.append(paragraph) + if rest is not None: + remainder.append(rest) + return remainder + + +class Layout(Container): + def __init__( + self, + width: float, + height: Optional[float] = None, + margins: Optional[Sequence[float]] = None, + renderer: Optional[ContentRenderer] = None, + ): + super().__init__(width, height, margins, renderer) + self._reference_column_width = width + self._current_column = 0 + self._columns: list[Column] = [] + + def __iter__(self): + return iter(self._columns) + + def __len__(self): + return len(self._columns) + + @property + def current_column_index(self): + return self._current_column + + @property + def content_width(self): + width = self._content_width + if self._columns: + width = self._calculate_content_width() + return width + + def _calculate_content_width(self) -> float: + width = sum(c.total_width + c.gutter for c in self._columns[:-1]) + if self._columns: + width += self._columns[-1].total_width + return width + + @property + def content_height(self): + height = self._content_height + if self._columns: + height = self._calculate_content_height() + elif height is None: + height = 0 + return height + + def _calculate_content_height(self) -> float: + return max(c.total_height for c in self._columns) + + def place( + self, + x: float = 0, + y: float = 0, + align: LayoutAlignment = LayoutAlignment.TOP_LEFT, + ): + """Place layout and all sub-entities at the final location, relative + to the insertion point (x, y) by the alignment defined by the argument + `align` (IntEnum). + + === ================ + int LayoutAlignment + === ================ + 1 TOP_LEFT + 2 TOP_CENTER + 3 TOP_RIGHT + 4 MIDDLE_LEFT + 5 MIDDLE_CENTER + 6 MIDDLE_RIGHT + 7 BOTTOM_LEFT + 8 BOTTOM_CENTER + 9 BOTTOM_RIGHT + === ================ + + It is possible to add content after calling :meth:`place`, but + :meth:`place` has to be called again before calling :meth:`render`. + + It is recommended to place the layout at origin (0, 0) and use a + transformation matrix to move the layout to the final location in + the target DXF layout. + + """ + + width = self.total_width + height = self.total_height + left, top = insert_location(align, width, height) + super().place(x + left, y + top) + + def place_content(self): + """Place content at the final location.""" + x, y = self.final_location() + x = x + self.left_margin + y = y - self.top_margin + for column in self: + column.place(x, y) + x += column.total_width + column.gutter + + def append_column( + self, + width: Optional[float] = None, + height: Optional[float] = None, + gutter: float = 0, + margins: Optional[Sequence[float]] = None, + renderer: Optional[ContentRenderer] = None, + ) -> Column: + """Append a new column to the layout.""" + if not width: + width = self._reference_column_width + column = Column( + width, height, gutter=gutter, margins=margins, renderer=renderer + ) + self._columns.append(column) + return column + + def append_paragraphs(self, paragraphs: Iterable[Paragraph]): + remainder = list(paragraphs) + # 1. fill existing columns: + columns = self._columns + while self._current_column < len(columns): + column = columns[self._current_column] + remainder = column.append_paragraphs(remainder) + if len(remainder) == 0: + return + self._current_column += 1 + + # 2. create additional columns + while remainder: + column = self._new_column() + self._current_column = len(self._columns) - 1 + remainder = column.append_paragraphs(remainder) + if self._current_column > 100: + raise LayoutError("Internal error - not enough space!?") + + def _new_column(self) -> Column: + if len(self._columns) == 0: + raise LayoutError("no column exist") + empty = self._columns[-1].clone_empty() + self._columns.append(empty) + return empty + + def next_column(self) -> None: + self._current_column += 1 + if self._current_column >= len(self._columns): + self._new_column() + + +def linear_placing(cells: Sequence[Cell], x: float, y: float): + for cell in cells: + cell.place(x, y) + x += cell.total_width + + +class RigidConnection(ContentCell): + def __init__( + self, cells: Optional[Iterable[Cell]] = None, valign=CellAlignment.BOTTOM + ): + super().__init__(0, 0, valign=valign) + self._cells: list[Cell] = list(cells) if cells else [] + + def __iter__(self): + return iter(self._cells) + + @property + def total_width(self) -> float: + return sum(cell.total_width for cell in self._cells) + + @property + def total_height(self) -> float: + return max(cell.total_height for cell in self._cells) + + def render(self, m: Optional[Matrix44] = None) -> None: + render_cells(self._cells, m) + render_text_strokes(self._cells, m) + + def place(self, x: float, y: float): + super().place(x, y) + linear_placing(self._cells, x, y) + + def growable_glue(self) -> Iterable[Glue]: + return ( + cell for cell in self._cells if isinstance(cell, Glue) and cell.can_grow + ) + + +def group_non_breakable_cells(cells: list[Cell]) -> list[Cell]: + def append_rigid_content(s: int, e: int): + _rigid_content = cells[s:e] + if len(_rigid_content) > 1: + new_cells.append(RigidConnection(_rigid_content)) + else: + new_cells.append(_rigid_content[0]) + + index = 0 + count = len(cells) + new_cells = [] + while index < count: + cell = cells[index] + if isinstance(cell, _no_break): + start = index + index += 1 + while index < count: + if not isinstance(cells[index], _no_break): + append_rigid_content(start, index) + break + index += 1 + if index == count: + append_rigid_content(start, index) + else: + continue + else: + new_cells.append(cell) + index += 1 + return new_cells + + +def vertical_cell_shift(cell: Cell, group_height: float) -> float: + dy = 0.0 + if isinstance(cell, ContentCell) and cell.valign != CellAlignment.TOP: + dy = cell.total_height - group_height + if cell.valign == CellAlignment.CENTER: + dy /= 2.0 + return dy + + +class LineCell(NamedTuple): + cell: Cell + offset: float + locked: bool + + +class AppendType(enum.IntEnum): + FAIL = 0 + SUCCESS = 1 + FORCED = 2 + + +class AbstractLine(ContentCell): # ABC + has_tab_support = False + + def __init__(self, width: float): + super().__init__(width=width, height=0, valign=CellAlignment.BOTTOM) + self._cells: list[LineCell] = [] + self._current_offset: float = 0.0 + + def __iter__(self): + return self.flatten() + + @abc.abstractmethod + def append(self, cell: Cell) -> AppendType: + """Append cell to the line content and report SUCCESS or FAIL.""" + pass + + @abc.abstractmethod + def append_with_tab(self, cell: Cell, tab: Tabulator) -> AppendType: + """Append cell with preceding tabulator cell to the line content + and report SUCCESS or FAIL. + """ + pass + + @property + def has_content(self): + return bool(self._cells) + + def place(self, x: float, y: float): + super().place(x, y) + group_height = self.total_height + for line_cell in self._cells: + cell = line_cell.cell + cx = x + line_cell.offset + cy = y + vertical_cell_shift(cell, group_height) + cell.place(cx, cy) + + @property + def line_width(self) -> float: + return self._width + + @property + def total_width(self) -> float: + width: float = 0.0 + if len(self._cells): + last_cell = self._cells[-1] + width = last_cell.offset + last_cell.cell.total_width + return width + + @property + def total_height(self) -> float: + if len(self._cells): + return max(c.cell.total_height for c in self._cells) + return 0.0 + + def cells(self) -> Iterable[Cell]: + """Yield line content including RigidConnections.""" + return [c.cell for c in self._cells] + + def flatten(self) -> Iterable[Cell]: + """Yield line content with resolved RigidConnections.""" + for cell in self.cells(): + if isinstance(cell, RigidConnection): + yield from cell + else: + yield cell + + def render(self, m: Matrix44 = None) -> None: + cells = list(self.cells()) + render_cells(cells, m) + render_text_strokes(cells, m) + + def remove_line_breaking_space(self) -> bool: + """Remove the last space in the line. Returns True if such a space was + removed. + """ + _cells = self._cells + if _cells and isinstance(_cells[-1].cell, Space): + _cells.pop() + return True + return False + + +class LeftLine(AbstractLine): + has_tab_support = True + + def __init__(self, width: float, tab_stops: Optional[Sequence[TabStop]] = None): + super().__init__(width=width) + self._tab_stops = tab_stops or [] # tab stops relative to line start + + def _append_line_cell( + self, cell: Cell, offset: float, locked: bool = False + ) -> None: + self._cells.append(LineCell(cell, offset, locked)) + + def append(self, cell: Cell) -> AppendType: + width = cell.total_width + if self._current_offset + width <= self.line_width: + self._append_line_cell(cell, self._current_offset) + self._current_offset += width + return AppendType.SUCCESS + if len(self._cells) == 0: + # single cell is too wide for a line, + # forced rendering with oversize + self._append_line_cell(cell, 0) + return AppendType.FORCED + return AppendType.FAIL + + def append_with_tab(self, cell: Cell, tab: Tabulator) -> AppendType: + width = cell.total_width + pos = self._current_offset + # does content fit into line: + if pos + width > self.line_width: + return AppendType.FAIL + + # next possible tab stop location: + left_pos = pos + center_pos = pos + width / 2 + right_pos = pos + width + tab_stop = self._next_tab_stop(left_pos, center_pos, right_pos) + if tab_stop is None: # no tab stop found + self.append(tab.to_space()) # replace tabulator by space + return self.append(cell) + else: + if tab_stop.kind == TabStopType.LEFT: + return self._append_left(cell, tab_stop.pos) + elif tab_stop.kind == TabStopType.CENTER: + return self._append_center(cell, tab_stop.pos) + else: + return self._append_right(cell, tab_stop.pos) + + def _append_left(self, cell, pos) -> AppendType: + width = cell.total_width + if pos + width <= self.line_width: + self._append_line_cell(cell, pos, True) + self._current_offset = pos + width + return AppendType.SUCCESS + return AppendType.FAIL + + def _append_center(self, cell, pos) -> AppendType: + width2 = cell.total_width / 2 + if self._current_offset + width2 > pos: + return self.append(cell) + elif pos + width2 <= self.line_width: + self._append_line_cell(cell, pos - width2, True) + self._current_offset = pos + width2 + return AppendType.SUCCESS + return AppendType.FAIL + + def _append_right(self, cell, pos) -> AppendType: + width = cell.total_width + end_of_cell_pos = self._current_offset + width + if end_of_cell_pos > self.line_width: + return AppendType.FAIL + if end_of_cell_pos > pos: + return self.append(cell) + self._append_line_cell(cell, pos - width, True) + self._current_offset = pos + return AppendType.SUCCESS + + def _next_tab_stop(self, left, center, right): + for tab in self._tab_stops: + if tab.kind == TabStopType.LEFT and tab.pos > left: + return tab + elif tab.kind == TabStopType.CENTER and tab.pos > center: + return tab + elif tab.kind == TabStopType.RIGHT and tab.pos > right: + return tab + return None + + +def content_width(cells: Iterable[Cell]) -> float: + return sum(cell.total_width for cell in cells) + + +def growable_cells(cells: Iterable[Cell]) -> list[Glue]: + growable = [] + for cell in cells: + if isinstance(cell, Glue) and cell.can_grow: + growable.append(cell) + elif isinstance(cell, RigidConnection): + growable.extend(cell.growable_glue()) + return growable + + +def update_offsets(cells: list[LineCell], index: int) -> None: + count = len(cells) + if count == 0 or index > count: + return + + last_cell = cells[index - 1] + offset = last_cell.offset + last_cell.cell.total_width + while index < count: + cell = cells[index].cell + cells[index] = LineCell(cell, offset, False) + offset += cell.total_width + index += 1 + + +class JustifiedLine(LeftLine): + def distribute(self): + cells = self._cells + last_locked_cell = self._last_locked_cell() + if last_locked_cell == len(cells): + return + + available_space = self._available_space(last_locked_cell) + cells = [c.cell for c in cells[last_locked_cell + 1 :]] + modified = False + while True: + growable = growable_cells(cells) + if len(growable) == 0: + break + + space_to_distribute = available_space - content_width(cells) + if space_to_distribute <= 1e-9: + break + + delta = space_to_distribute / len(growable) + for cell in growable: + cell.resize(cell.total_width + delta) + modified = True + + if modified: + update_offsets(self._cells, last_locked_cell + 1) + + def _end_offset(self, index): + cell = self._cells[index] + return cell.offset + cell.cell.total_width + + def _available_space(self, index): + return self.line_width - self._end_offset(index) + + def _last_locked_cell(self): + cells = self._cells + index = len(cells) - 1 + while index > 0: + if cells[index].locked: + return index + index -= 1 + return 0 + + +class NoTabLine(AbstractLine): + """Base class for lines without tab stop support!""" + + has_tab_support = False + + def append(self, cell: Cell) -> AppendType: + if isinstance(cell, Tabulator): + cell = cell.to_space() + width = cell.total_width + if self._current_offset + width < self.line_width: + self._cells.append(LineCell(cell, self._current_offset, False)) + self._current_offset += width + return AppendType.SUCCESS + if len(self._cells) == 0: + # single cell is too wide for a line, + # forced rendering with oversize + self._cells.append(LineCell(cell, 0, False)) + return AppendType.FORCED + return AppendType.FAIL + + def append_with_tab(self, cell: Cell, tab: Tabulator) -> AppendType: + """No tabulator support!""" + raise NotImplementedError() + + def place(self, x: float, y: float): + # shift the line cell: + super().place(x + self.start_offset(), y) + + @abc.abstractmethod + def start_offset(self) -> float: + pass + + +class CenterLine(NoTabLine): + """Right aligned lines do not support tab stops!""" + + def start_offset(self) -> float: + real_width = sum(c.cell.total_width for c in self._cells) + return (self.line_width - real_width) / 2 + + +class RightLine(NoTabLine): + """Right aligned lines do not support tab stops!""" + + def start_offset(self) -> float: + real_width = sum(c.cell.total_width for c in self._cells) + return self.line_width - real_width + + +def shift_tab_stops( + tab_stops: Iterable[TabStop], offset: float, right_border: float +) -> list[TabStop]: + return [ + tab_stop + for tab_stop in (TabStop(pos + offset, kind) for pos, kind in tab_stops) + if 0 < tab_stop.pos <= right_border + ] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/text_size.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/text_size.py new file mode 100644 index 0000000..7032771 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/text_size.py @@ -0,0 +1,198 @@ +# Copyright (c) 2021-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Sequence, Optional +from dataclasses import dataclass + +from ezdxf.math import Matrix44, Vec2 +from ezdxf.entities import Text, MText, get_font_name +from ezdxf.fonts import fonts +from ezdxf.tools import text_layout as tl +from ezdxf.tools.text import MTextContext +from ezdxf.render.abstract_mtext_renderer import AbstractMTextRenderer +from ezdxf.tools.text import estimate_mtext_extents + +__all__ = [ + "text_size", + "mtext_size", + "TextSize", + "MTextSize", + "WordSizeDetector", + # estimate_mtext_extents() belongs also to the topic of this module, users + # may look here first + "estimate_mtext_extents", +] + + +@dataclass(frozen=True) +class TextSize: + width: float + # The text entity has a fixed font: + cap_height: float # height of "X" without descender + total_height: float # including the descender + + +@dataclass(frozen=True) +class MTextSize: + total_width: float + total_height: float + column_width: float + gutter_width: float + column_heights: Sequence[float] + + # Storing additional font metrics like "cap_height" makes no sense, because + # the font metrics can be variable by using inline codes to vary the text + # height or the width factor or even changing the used font at all. + @property + def column_count(self) -> int: + return len(self.column_heights) + + +def text_size(text: Text) -> TextSize: + """Returns the measured text width, the font cap-height and the font + total-height for a :class:`~ezdxf.entities.Text` entity. + This function uses the optional `Matplotlib` package if available to measure + the final rendering width and font-height for the :class:`Text` entity as + close as possible. This function does not measure the real char height! + Without access to the `Matplotlib` package the + :class:`~ezdxf.tools.fonts.MonospaceFont` is used and the measurements are + very inaccurate. + + See the :mod:`~ezdxf.addons.text2path` add-on for more tools to work + with the text path objects created by the `Matplotlib` package. + + """ + width_factor: float = text.dxf.get_default("width") + text_width: float = 0.0 + cap_height: float = text.dxf.get_default("height") + font: fonts.AbstractFont = fonts.MonospaceFont(cap_height, width_factor) + if text.doc is not None: + style = text.doc.styles.get(text.dxf.get_default("style")) + font_name = get_font_name(style) + font = fonts.make_font(font_name, cap_height, width_factor) + + total_height = font.measurements.total_height + content = text.plain_text() + if content: + text_width = font.text_width(content) + return TextSize(text_width, cap_height, total_height) + + +def mtext_size( + mtext: MText, tool: Optional[MTextSizeDetector] = None +) -> MTextSize: + """Returns the total-width, -height and columns information for a + :class:`~ezdxf.entities.MText` entity. + + This function uses the optional `Matplotlib` package if available to do + font measurements and the internal text layout engine to determine the final + rendering size for the :class:`MText` entity as close as possible. + Without access to the `Matplotlib` package the :class:`~ezdxf.tools.fonts.MonospaceFont` + is used and the measurements are very inaccurate. + + Attention: The required full layout calculation is slow! + + The first call to this function with `Matplotlib` support is very slow, + because `Matplotlib` lookup all available fonts on the system. To speedup + the calculation and accepting inaccurate results you can disable the + `Matplotlib` support manually:: + + ezdxf.option.use_matplotlib = False + + """ + tool = tool or MTextSizeDetector() + column_heights: list[float] = [0.0] + gutter_width = 0.0 + column_width = 0.0 + if mtext.text: + columns: list[tl.Column] = list(tool.measure(mtext)) + if len(columns): + first_column = columns[0] + # same values for all columns + column_width = first_column.total_width + gutter_width = first_column.gutter + column_heights = [column.total_height for column in columns] + + count = len(column_heights) + return MTextSize( + total_width=column_width * count + gutter_width * (count - 1), + total_height=max(column_heights), + column_width=column_width, + gutter_width=gutter_width, + column_heights=tuple(column_heights), + ) + + +class MTextSizeDetector(AbstractMTextRenderer): + def __init__(self): + super().__init__() + self.do_nothing = tl.DoNothingRenderer() + self.renderer = self.do_nothing + + def reset(self): + pass + + def word(self, text: str, ctx: MTextContext) -> tl.ContentCell: + return tl.Text( + # The first call to get_font() is very slow! + width=self.get_font(ctx).text_width(text), + height=ctx.cap_height, + valign=tl.CellAlignment(ctx.align), + renderer=self.renderer, + ) + + def fraction(self, data: tuple, ctx: MTextContext) -> tl.ContentCell: + upr, lwr, type_ = data + if type_: + return tl.Fraction( + top=self.word(upr, ctx), + bottom=self.word(lwr, ctx), + stacking=self.get_stacking(type_), + renderer=self.renderer, + ) + else: + return self.word(upr, ctx) + + def get_font_face(self, mtext: MText) -> fonts.FontFace: + return fonts.get_entity_font_face(mtext) + + def make_bg_renderer(self, mtext: MText) -> tl.ContentRenderer: + return self.do_nothing + + def measure(self, mtext: MText) -> tl.Layout: + self.reset() + layout = self.layout_engine(mtext) + layout.place() + return layout + + +class WordSizeCollector(tl.DoNothingRenderer): + """Collects word sizes as tuples of the lower left corner and the upper + right corner as Vec2 objects, ignores lines. + """ + + def __init__(self) -> None: + self.word_boxes: list[tuple[Vec2, Vec2]] = [] + + def render( + self, + left: float, + bottom: float, + right: float, + top: float, + m: Optional[Matrix44] = None, + ) -> None: + self.word_boxes.append((Vec2(left, bottom), Vec2(right, top))) + + +class WordSizeDetector(MTextSizeDetector): + def reset(self): + self.renderer = WordSizeCollector() + + def measure(self, mtext: MText) -> tl.Layout: + layout = super().measure(mtext) + layout.render() + return layout + + def word_boxes(self) -> list[tuple[Vec2, Vec2]]: + return self.renderer.word_boxes diff --git a/.venv/lib/python3.12/site-packages/ezdxf/tools/zipmanager.py b/.venv/lib/python3.12/site-packages/ezdxf/tools/zipmanager.py new file mode 100644 index 0000000..985dc63 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/tools/zipmanager.py @@ -0,0 +1,87 @@ +# Copyright (c) 2014-2023, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import BinaryIO, cast, TextIO, Optional, Iterator +import zipfile +from contextlib import contextmanager + +from ezdxf.lldxf.validator import is_dxf_stream, dxf_info + +CRLF = b"\r\n" +LF = b"\n" + + +class ZipReader: + def __init__(self, zip_archive_name: str, errors="surrogateescape"): + if not zipfile.is_zipfile(zip_archive_name): + raise IOError(f"'{zip_archive_name}' is not a zip archive.") + self.zip_archive_name = zip_archive_name + self.zip_archive: Optional[zipfile.ZipFile] = None + self.dxf_file_name: Optional[str] = None + self.dxf_file: Optional[BinaryIO] = None + self.encoding = "cp1252" + self.errors = errors + self.dxfversion = "AC1009" + + def open(self, dxf_file_name: Optional[str] = None) -> None: + def open_dxf_file() -> BinaryIO: + # Open always in binary mode: + return cast(BinaryIO, self.zip_archive.open(self.dxf_file_name)) # type: ignore + + self.zip_archive = zipfile.ZipFile(self.zip_archive_name) + self.dxf_file_name = ( + dxf_file_name + if dxf_file_name is not None + else self.get_first_dxf_file_name() + ) + self.dxf_file = open_dxf_file() + + # Reading with standard encoding 'cp1252' - readline() fails if leading + # comments contain none ASCII characters. + if not is_dxf_stream(cast(TextIO, self)): + raise IOError(f"'{self.dxf_file_name}' is not a DXF file.") + self.dxf_file = open_dxf_file() # restart + self.get_dxf_info() + self.dxf_file = open_dxf_file() # restart + + def get_first_dxf_file_name(self) -> str: + dxf_file_names = self.get_dxf_file_names() + if len(dxf_file_names) > 0: + return dxf_file_names[0] + else: + raise IOError("No DXF files found.") + + def get_dxf_file_names(self) -> list[str]: + assert self.zip_archive is not None + return [ + name + for name in self.zip_archive.namelist() + if name.lower().endswith(".dxf") + ] + + def get_dxf_info(self) -> None: + info = dxf_info(cast(TextIO, self)) + # Since DXF R2007 (AC1021) file encoding is always 'utf-8' + self.encoding = info.encoding if info.version < "AC1021" else "utf-8" + self.dxfversion = info.version + + def readline(self) -> str: + assert self.dxf_file is not None + next_line = self.dxf_file.readline().replace(CRLF, LF) + return str(next_line, self.encoding, self.errors) + + def close(self) -> None: + assert self.zip_archive is not None + self.zip_archive.close() + + +@contextmanager +def ctxZipReader( + zipfilename: str, + filename: Optional[str] = None, + errors: str = "surrogateescape", +) -> Iterator[ZipReader]: + zip_reader = ZipReader(zipfilename, errors=errors) + zip_reader.open(filename) + yield zip_reader + zip_reader.close() diff --git a/.venv/lib/python3.12/site-packages/ezdxf/transform.py b/.venv/lib/python3.12/site-packages/ezdxf/transform.py new file mode 100644 index 0000000..c5e7757 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/transform.py @@ -0,0 +1,398 @@ +# Copyright (c) 2023-2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import ( + Iterable, + Iterator, + NamedTuple, + Optional, + Tuple, + List, + TYPE_CHECKING, + Sequence, +) +import enum +import logging + +from ezdxf.math import ( + Matrix44, + UVec, + Vec3, + NonUniformScalingError, + InsertTransformationError, +) +from ezdxf.entities import ( + DXFEntity, + DXFGraphic, + Circle, + LWPolyline, + Polyline, + Ellipse, + is_graphic_entity, +) +from ezdxf.entities.copy import default_copy, CopyNotSupported +from ezdxf.protocols import SupportsTemporaryTransformation +from ezdxf.document import Drawing + +if TYPE_CHECKING: + from ezdxf.layouts import BlockLayout + +__all__ = [ + "Logger", + "Error", + "inplace", + "copies", + "translate", + "scale_uniform", + "scale", + "x_rotate", + "y_rotate", + "z_rotate", + "axis_rotate", + "transform_entity_by_blockref", + "transform_entities_by_blockref", +] +MIN_SCALING_FACTOR = 1e-12 +logger = logging.getLogger("ezdxf") + + +class Error(enum.Enum): + NONE = 0 + TRANSFORMATION_NOT_SUPPORTED = enum.auto() + COPY_NOT_SUPPORTED = enum.auto() + NON_UNIFORM_SCALING_ERROR = enum.auto() + INSERT_TRANSFORMATION_ERROR = enum.auto() + VIRTUAL_ENTITY_NOT_SUPPORTED = enum.auto() + + +class Logger: + class Entry(NamedTuple): + error: Error + message: str + entity: DXFEntity + + def __init__(self) -> None: + self._entries: list[Logger.Entry] = [] + + def __getitem__(self, index: int) -> Entry: + """Returns the error entry at `index`.""" + return self._entries[index] + + def __iter__(self) -> Iterator[Entry]: + """Iterates over all error entries.""" + return iter(self._entries) + + def __len__(self) -> int: + """Returns the count of error entries.""" + return len(self._entries) + + def add(self, error: Error, message: str, entity: DXFEntity): + self._entries.append(Logger.Entry(error, message, entity)) + + def messages(self) -> list[str]: + """Returns all error messages as list of strings.""" + return [entry.message for entry in self._entries] + + def purge(self, entries: Iterable[Entry]) -> None: + for entry in entries: + try: + self._entries.remove(entry) + except ValueError: + pass + + +def _inplace(entities: Iterable[DXFEntity], m: Matrix44) -> Logger: + """Transforms the given `entities` inplace by the transformation matrix `m`, + non-uniform scaling is not supported. The function logs errors and does not raise + errors for unsupported entities or transformations that cannot be performed, + see enum :class:`Error`. + The :func:`inplace` function supports virtual entities as well. + + """ + log = Logger() + for entity in entities: + if not entity.is_alive: + continue + try: + entity.transform(m) # type: ignore + except (AttributeError, NotImplementedError): + log.add( + Error.TRANSFORMATION_NOT_SUPPORTED, + f"{str(entity)} entity does not support transformation", + entity, + ) + except NonUniformScalingError: + log.add( + Error.NON_UNIFORM_SCALING_ERROR, + f"{str(entity)} entity does not support non-uniform scaling", + entity, + ) + except InsertTransformationError: + log.add( + Error.INSERT_TRANSFORMATION_ERROR, + f"{str(entity)} entity can not represent a non-orthogonal target coordinate system", + entity, + ) + + return log + + +def inplace( + entities: Iterable[DXFEntity], + m: Matrix44, +) -> Logger: + """Transforms the given `entities` inplace by the transformation matrix `m`, + non-uniform scaling is supported. The function converts circular arcs into ellipses + to perform non-uniform scaling. The function logs errors and does not raise errors + for unsupported entities or transformation errors, see enum :class:`Error`. + + .. important:: + + The :func:`inplace` function does not support type conversion for virtual + entities e.g. non-uniform scaling for CIRCLE, ARC or POLYLINE with bulges, + see also function :func:`copies`. + + """ + log = _inplace(entities, m) + errors: list[Logger.Entry] = [] + for entry in log: + if entry.error != Error.NON_UNIFORM_SCALING_ERROR: + continue + + entity = entry.entity + if entity.is_virtual: + errors.append(entry) + log.add( + Error.VIRTUAL_ENTITY_NOT_SUPPORTED, + f"non-uniform scaling is not supported for virtual entity {str(entity)}", + entity, + ) + continue + + if isinstance(entity, Circle): # CIRCLE, ARC + errors.append(entry) + ellipse = entity.to_ellipse(replace=True) + ellipse.transform(m) + elif isinstance(entity, (LWPolyline, Polyline)): # has bulges (circular arcs) + errors.append(entry) + for sub_entity in entity.explode(): + if isinstance(sub_entity, Circle): + sub_entity = sub_entity.to_ellipse() + sub_entity.transform(m) # type: ignore + # else: NON_UNIFORM_SCALING_ERROR stays unchanged + log.purge(errors) + return log + + +def copies( + entities: Iterable[DXFEntity], m: Optional[Matrix44] = None +) -> Tuple[Logger, List[DXFEntity]]: + """Copy entities and transform them by matrix `m`. Does not raise any exception + and ignores all entities that cannot be copied or transformed. Just copies the input + entities if matrix `m` is ``None``. Returns a tuple of :class:`Logger` and a list of + transformed virtual copies. The function supports virtual entities as input and + converts circular arcs into ellipses to perform non-uniform scaling. + """ + + log = Logger() + clones = _copy_entities(entities, log) + if isinstance(m, Matrix44): + clones = _transform_clones(clones, m, log) + return log, clones + + +def _copy_entities(entities: Iterable[DXFEntity], log: Logger) -> list[DXFEntity]: + clones: list[DXFEntity] = [] + for entity in entities: + if not entity.is_alive: + continue + try: + clone = entity.copy(copy_strategy=default_copy) + except CopyNotSupported: + log.add( + Error.COPY_NOT_SUPPORTED, + f"{str(entity)} entity does not support copy", + entity, + ) + else: + clones.append(clone) + return clones + + +def _transform_clones(clones: Iterable[DXFEntity], m: Matrix44, log: Logger): + entities: List[DXFEntity] = [] + for entity in clones: + try: + entity.transform(m) # type: ignore + except (AttributeError, NotImplementedError): + log.add( + Error.TRANSFORMATION_NOT_SUPPORTED, + f"{str(entity)} entity does not support transformation", + entity, + ) + except InsertTransformationError: + log.add( + Error.INSERT_TRANSFORMATION_ERROR, + f"{str(entity)} entity can not represent a non-orthogonal target coordinate system", + entity, + ) + except NonUniformScalingError: + try: + entities.extend(_scale_non_uniform(entity, m)) + except TypeError: + log.add( + Error.NON_UNIFORM_SCALING_ERROR, + f"{str(entity)} entity does not support non-uniform scaling", + entity, + ) + else: + entities.append(entity) + + return entities + + +def _scale_non_uniform(entity: DXFEntity, m: Matrix44): + sub_entity: DXFGraphic + if isinstance(entity, Circle): + sub_entity = Ellipse.from_arc(entity) + sub_entity.transform(m) + yield sub_entity + elif isinstance(entity, (LWPolyline, Polyline)): + for sub_entity in entity.virtual_entities(): + if isinstance(sub_entity, Circle): + sub_entity = Ellipse.from_arc(sub_entity) + sub_entity.transform(m) + yield sub_entity + else: + raise TypeError + + +def translate(entities: Iterable[DXFEntity], offset: UVec) -> Logger: + """Translates (moves) `entities` inplace by the `offset` vector.""" + v = Vec3(offset) + if v: + return _inplace(entities, m=Matrix44.translate(v.x, v.y, v.z)) + return Logger() + + +def scale_uniform(entities: Iterable[DXFEntity], factor: float) -> Logger: + """Scales `entities` inplace by a `factor` in all axis. Scaling factors smaller than + :attr:`MIN_SCALING_FACTOR` are ignored. + + """ + f = float(factor) + if abs(f) > MIN_SCALING_FACTOR: + return _inplace(entities, m=Matrix44.scale(f, f, f)) + return Logger() + + +def scale(entities: Iterable[DXFEntity], sx: float, sy: float, sz: float) -> Logger: + """Scales `entities` inplace by the factors `sx` in x-axis, `sy` in y-axis and `sz` + in z-axis. Scaling factors smaller than :attr:`MIN_SCALING_FACTOR` are ignored. + + .. important:: + + same limitations for virtual entities as the :func:`inplace` function + + """ + + def safe(f: float) -> float: + f = float(f) + return f if abs(f) > MIN_SCALING_FACTOR else 1.0 + + return inplace(entities, Matrix44.scale(safe(sx), safe(sy), safe(sz))) + + +def x_rotate(entities: Iterable[DXFEntity], angle: float) -> Logger: + """Rotates `entities` inplace by `angle` in radians about the x-axis.""" + a = float(angle) + if a: + return _inplace(entities, m=Matrix44.x_rotate(a)) + return Logger() + + +def y_rotate(entities: Iterable[DXFEntity], angle: float) -> Logger: + """Rotates `entities` inplace by `angle` in radians about the y-axis.""" + a = float(angle) + if a: + return _inplace(entities, m=Matrix44.y_rotate(a)) + return Logger() + + +def z_rotate(entities: Iterable[DXFEntity], angle: float) -> Logger: + """Rotates `entities` inplace by `angle` in radians about the x-axis.""" + a = float(angle) + if a: + return _inplace(entities, m=Matrix44.z_rotate(a)) + return Logger() + + +def axis_rotate(entities: Iterable[DXFEntity], axis: UVec, angle: float) -> Logger: + """Rotates `entities` inplace by `angle` in radians about the rotation axis starting + at the origin pointing in `axis` direction. + """ + a = float(angle) + if not a: + return Logger() + + v = Vec3(axis) + if not v.is_null: + return _inplace(entities, m=Matrix44.axis_rotate(v, a)) + return Logger() + + +def transform_entity_by_blockref(entity: DXFEntity, m: Matrix44) -> bool: + """Apply a transformation by moving an entity into a block and replacing the entity + by a block reference with the applied transformation. + """ + return _transform_by_blockref([entity], m) is not None + + +def transform_entities_by_blockref( + entities: Iterable[DXFEntity], m: Matrix44 +) -> BlockLayout | None: + """Apply a transformation by moving entities into a block and replacing the entities + by a block reference with the applied transformation. + """ + return _transform_by_blockref(list(entities), m) + + +def _transform_by_blockref( + entities: Sequence[DXFEntity], m: Matrix44 +) -> BlockLayout | None: + if len(entities) == 0: + return None + + first_entity = entities[0] + if not is_graphic_entity(first_entity): + return None + + doc = first_entity.doc + if doc is None: + return None + + layout = first_entity.get_layout() + if layout is None: + return None + + block = doc.blocks.new_anonymous_block() + insert = layout.add_blockref(block.name, (0, 0, 0)) + try: + insert.transform(m) + except InsertTransformationError: + logger.warning(f"cannot apply invalid transformation") + layout.delete_entity(insert) + doc.blocks.delete_block(block.name, safe=False) + return None + + for e in entities: + if is_graphic_entity(e): + layout.move_to_layout(e, block) + return block + + +def apply_temporary_transformations(entities: Iterable[DXFEntity]) -> None: + for entity in entities: + if isinstance(entity, SupportsTemporaryTransformation): + tt = entity.temporary_transformation() + tt.apply_transformation(entity) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/units.py b/.venv/lib/python3.12/site-packages/ezdxf/units.py new file mode 100644 index 0000000..a82ae0f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/units.py @@ -0,0 +1,219 @@ +# Copyright (c) 2019-2023 Manfred Moitzi +# License: MIT License +from typing import Optional +from ezdxf.enums import InsertUnits + +# Documentation: https://ezdxf.mozman.at/docs/concepts/units.html#insunits + +MSP_METRIC_UNITS_FACTORS = { + # length in units / factor = length in meters + # length in meters * factor = length in units + "km": 0.001, + "m": 1.0, + "dm": 10.0, + "cm": 100.0, + "mm": 1000.0, + "µm": 1000000.0, + "yd": 1.093613298, + "ft": 3.280839895, + "in": 39.37007874, + "mi": 0.00062137119, +} + +IN = 1 +FT = 2 +MI = 3 +MM = 4 +CM = 5 +M = 6 +KM = 7 +YD = 10 +DM = 14 + +IMPERIAL_UNITS = { + InsertUnits.Inches, + InsertUnits.Feet, + InsertUnits.Miles, + InsertUnits.Microinches, + InsertUnits.Mils, + InsertUnits.Yards, + InsertUnits.USSurveyFeet, + InsertUnits.USSurveyInch, + InsertUnits.USSurveyYard, + InsertUnits.USSurveyMile, +} + +# Conversion factor from meters to unit +# 1 meter is ... [unit] +METER_FACTOR = [ + None, # 0 = Unitless - not supported + 39.37007874, # 1 = Inches + 3.280839895, # 2 = Feet + 0.00062137119, # 3 = Miles + 1000.0, # 4 = Millimeters + 100.0, # 5 = Centimeters + 1.0, # 6 = Meters + 0.001, # 7 = Kilometers + None, # 8 = Microinches = 1e-6 in + None, # 9 = Mils = 0.001 in + 1.093613298, # 10 = Yards + 10000000000.0, # 11 = Angstroms = 1e-10m + 1000000000.0, # 12 = Nanometers = 1e-9m + 1000000.0, # 13 = Microns = 1e-6m + 10.0, # 14 = Decimeters = 0.1m + 0.1, # 15 = Decameters = 10m + 0.01, # 16 = Hectometers = 100m + 0.000000001, # 17 = Gigameters = 1e+9 m + 1.0 / 149597870700, # 18 = Astronomical units = 149597870700m + 1.0 / 9.46e15, # 19 = Light years = 9.46e15 m + 1.0 / 3.09e16, # 20 = Parsecs = 3.09e16 m + None, # 21 = US Survey Feet + None, # 22 = US Survey Inch + None, # 23 = US Survey Yard + None, # 24 = US Survey Mile +] + + +class DrawingUnits: + def __init__(self, base: float = 1.0, unit: str = "m"): + self.base = float(base) + self.unit = unit.lower() + self._units = MSP_METRIC_UNITS_FACTORS + self._msp_factor = base * self._units[self.unit] + + def factor(self, unit: str = "m") -> float: + return self._msp_factor / self._units[unit.lower()] + + def __call__(self, unit: str) -> float: + return self.factor(unit) + + +class PaperSpaceUnits: + def __init__(self, msp=DrawingUnits(), unit: str = "mm", scale: float = 1): + self.unit = unit.lower() + self.scale = scale + self._msp = msp + self._psp = DrawingUnits(1, self.unit) + + def from_msp(self, value: float, unit: str): + drawing_units = value * self._msp(unit.lower()) + return drawing_units / (self._msp(self.unit) * self.scale) + + def to_msp(self, value: float, unit: str): + paper_space_units = value * self.scale * self._psp.factor(unit) + model_space_units = paper_space_units * self._msp.factor(self.unit) + return model_space_units + + +# Layout units are stored as enum in the associated BLOCK_RECORD: BlockRecord.dxf.units +# or as optional XDATA for all DXF versions +# 1000: "ACAD" +# 1001: "DesignCenter Data" (optional) +# 1002: "{" +# 1070: Autodesk Design Center version number +# 1070: Insert units: like 'units' +# 1002: "}" + +# The units of the modelspace block record is always 0, the real modelspace +# units and therefore the document units are stored as enum in the header var +# $INSUNITS + +# units stored as enum in BlockRecord.dxf.units +# 0 = Unitless +# 1 = Inches +# 2 = Feet +# 3 = Miles +# 4 = Millimeters +# 5 = Centimeters +# 6 = Meters +# 7 = Kilometers +# 8 = Microinches = 1e-6 in +# 9 = Mils = 0.001 in +# 10 = Yards +# 11 = Angstroms = 1e-10m +# 12 = Nanometers = 1e-9m +# 13 = Microns = 1e-6m +# 14 = Decimeters = 0.1m +# 15 = Decameters = 10m +# 16 = Hectometers = 100m +# 17 = Gigameters = 1e+9 m +# 18 = Astronomical units = 149597870700m = 1.58125074e−5 ly = 4.84813681e−6 Parsec +# 19 = Light years = 9.46e15 m +# 20 = Parsecs = 3.09e16 m +# 21 = US Survey Feet +# 22 = US Survey Inch +# 23 = US Survey Yard +# 24 = US Survey Mile +_unit_spec = [ + None, + "in", + "ft", + "mi", + "mm", + "cm", + "m", + "km", + "µin", + "mil", + "yd", + "Å", + "nm", + "µm", + "dm", + "dam", + "hm", + "gm", + "au", + "ly", + "pc", + None, + None, + None, + None, +] + + +def decode(enum: int) -> Optional[str]: + return _unit_spec[int(enum)] + + +def conversion_factor( + source_units: InsertUnits, target_units: InsertUnits +) -> float: + """Returns the conversion factor to represent `source_units` in + `target_units`. + + E.g. millimeter in centimeter :code:`conversion_factor(MM, CM)` returns 0.1, + because 1 mm = 0.1 cm + + """ + try: + source_factor = METER_FACTOR[source_units] + target_factor = METER_FACTOR[target_units] + if source_factor is None or target_factor is None: + raise TypeError("Unsupported conversion.") + return target_factor / source_factor + + except IndexError: + raise ValueError("Invalid unit enum.") + + +def unit_name(enum: int) -> str: + """Returns the name of the unit enum.""" + try: + return InsertUnits(enum).name + except ValueError: + return "unitless" + + +ANGLE_UNITS = { + 0: "Decimal Degrees", + 1: "Degrees/Minutes/Seconds", + 2: "Grad", + 3: "Radians", +} + + +def angle_unit_name(enum: int) -> str: + """Returns the name of the angle unit enum.""" + return ANGLE_UNITS.get(enum, f"unknown unit <{enum}>") diff --git a/.venv/lib/python3.12/site-packages/ezdxf/upright.py b/.venv/lib/python3.12/site-packages/ezdxf/upright.py new file mode 100644 index 0000000..07937cf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/upright.py @@ -0,0 +1,270 @@ +# Copyright (c) 2021, Manfred Moitzi +# License: MIT License +# +# Purpose: +# Flips an inverted OCS defined by extrusion vector (0, 0, -1) into a WCS +# aligned OCS defined by extrusion vector (0, 0, 1). +# +# This simplifies 2D entity processing for ezdxf users and creates DXF +# output for 3rd party DXF libraries which ignore the existence of the OCS. +# +# Warning: +# The WCS representation of OCS entities with flipped extrusion vector +# is not 100% identical to the source entity, curve orientation and vertex order +# may change. A mirrored text represented by an extrusion vector (0, 0, -1) +# cannot represented by an extrusion vector (0, 0, 1), therefore this CANNOT +# work for text entities or entities including text: +# TEXT, ATTRIB, ATTDEF, MTEXT, DIMENSION, LEADER, MLEADER +from __future__ import annotations +from typing import Iterable, Sequence +from functools import singledispatch +import math +from ezdxf.math import Z_AXIS, Vec3, Vec2 +from ezdxf.entities import ( + DXFGraphic, + DXFNamespace, + Circle, + Arc, + Ellipse, + Solid, + Insert, + LWPolyline, + Polyline, +) +from ezdxf.entities.polygon import DXFPolygon +from ezdxf.entities.boundary_paths import ( + PolylinePath, + EdgePath, + LineEdge, + ArcEdge, + EllipseEdge, + SplineEdge, +) +from ezdxf.lldxf import const + +__all__ = ["upright", "upright_all"] + + +def upright(entity: DXFGraphic) -> None: + """Flips an inverted :ref:`OCS` defined by extrusion vector (0, 0, -1) into + a :ref:`WCS` aligned :ref:`OCS` defined by extrusion vector (0, 0, 1). + DXF entities with other extrusion vectors and unsupported DXF entities will + be silently ignored. For more information about the limitations read the + documentation of the :mod:`ezdxf.upright` module. + + """ + if not ( + isinstance(entity, DXFGraphic) + and entity.is_alive + and entity.dxf.hasattr("extrusion") + ): + return + extrusion = Vec3(entity.dxf.extrusion).normalize() + if extrusion.isclose(FLIPPED_Z_AXIS): + _flip_dxf_graphic(entity) + + +def upright_all(entities: Iterable[DXFGraphic]) -> None: + """Call function :func:`upright` for all DXF entities in iterable + `entities`:: + + upright_all(doc.modelspace()) + + """ + for e in entities: + upright(e) + + +FLIPPED_Z_AXIS = -Z_AXIS + + +def _flip_deg_angle(angle: float) -> float: + return (180.0 if angle >= 0.0 else -180.0) - angle + + +def _flip_rad_angle(angle: float) -> float: + return (math.pi if angle >= 0.0 else -math.pi) - angle + + +def _flip_vertex(vertex: Vec3) -> Vec3: + return Vec3(-vertex.x, vertex.y, -vertex.z) + + +def _flip_2d_vertex(vertex: Vec2) -> Vec2: + return Vec2(-vertex.x, vertex.y) + + +def _flip_existing_vertex(dxf: DXFNamespace, name: str) -> None: + if dxf.hasattr(name): + vertex = _flip_vertex(dxf.get(name)) + dxf.set(name, vertex) + + +def _flip_thickness(dxf: DXFNamespace) -> None: + if dxf.hasattr("thickness"): + dxf.thickness = -dxf.thickness + + +def _flip_elevation(dxf: DXFNamespace) -> None: + if dxf.hasattr("elevation"): + # works with float (LWPOLYLINE) and Vec3 (POLYLINE) + dxf.elevation = -dxf.elevation + + +@singledispatch +def _flip_dxf_graphic(entity: DXFGraphic) -> None: + pass # ignore unsupported types on purpose + + +@_flip_dxf_graphic.register(Circle) +def _flip_circle(circle: Circle) -> None: + dxf = circle.dxf + _flip_existing_vertex(dxf, "center") + _flip_thickness(dxf) + dxf.discard("extrusion") + + +@_flip_dxf_graphic.register(Arc) +def _flip_arc(arc: Arc) -> None: + _flip_circle(arc) + dxf = arc.dxf + end_angle = dxf.end_angle + dxf.end_angle = _flip_deg_angle(dxf.start_angle) + dxf.start_angle = _flip_deg_angle(end_angle) + + +# SOLID and TRACE - but not 3DFACE! +@_flip_dxf_graphic.register(Solid) +def _flip_solid(solid: Solid) -> None: + dxf = solid.dxf + for name in const.VERTEXNAMES: + _flip_existing_vertex(dxf, name) + _flip_thickness(dxf) + dxf.discard("extrusion") + + +@_flip_dxf_graphic.register(Insert) +def _flip_insert(insert: Insert) -> None: + # see exploration/upright_insert.py + dxf = insert.dxf + _flip_existing_vertex(dxf, "insert") + dxf.rotation = -dxf.rotation + dxf.xscale = -dxf.xscale + dxf.zscale = -dxf.zscale + # Attached attributes cannot be flipped! + dxf.discard("extrusion") + + +@_flip_dxf_graphic.register(Ellipse) +def _flip_ellipse(ellipse: Ellipse) -> None: + # ELLIPSE is a WCS entity! + # just process start- and end params + dxf = ellipse.dxf + end_param = -dxf.end_param + dxf.end_param = -dxf.start_param + dxf.start_param = end_param + dxf.discard("extrusion") + + +@_flip_dxf_graphic.register(LWPolyline) +def _flip_lwpolyline(polyline: LWPolyline) -> None: + flipped_points: list[Sequence[float]] = [] + for x, y, start_width, end_width, bulge in polyline.lwpoints: + bulge = -bulge + v = _flip_2d_vertex(Vec2(x, y)) + flipped_points.append((v.x, v.y, start_width, end_width, bulge)) + polyline.set_points(flipped_points, format="xyseb") + _finalize_polyline(polyline.dxf) + + +def _finalize_polyline(dxf: DXFNamespace): + _flip_thickness(dxf) + _flip_elevation(dxf) + dxf.discard("extrusion") + + +@_flip_dxf_graphic.register(Polyline) +def _flip_polyline2d(polyline: Polyline) -> None: + if not polyline.is_2d_polyline: + return # ignore silently + for vertex in polyline.vertices: + dxf = vertex.dxf + _flip_existing_vertex(dxf, "location") + if dxf.hasattr("bulge"): + dxf.bulge = -dxf.bulge + _finalize_polyline(polyline.dxf) + + +# HATCH and MPOLYGON +@_flip_dxf_graphic.register(DXFPolygon) +def _flip_polygon(polygon: DXFPolygon) -> None: + for p in polygon.paths: + _flip_boundary_path(p) + _flip_elevation(polygon.dxf) + polygon.dxf.discard("extrusion") + + +@singledispatch +def _flip_boundary_path(path) -> None: + raise TypeError(f"unsupported path type: {path!r}") + + +@_flip_boundary_path.register(PolylinePath) +def _flip_polyline_path(polyline: PolylinePath) -> None: + flipped_vertices: list[tuple[float, float, float]] = [] + for x, y, bulge in polyline.vertices: + bulge = -bulge + v = _flip_2d_vertex(Vec2(x, y)) + flipped_vertices.append((v.x, v.y, bulge)) + polyline.vertices = flipped_vertices + + +@_flip_boundary_path.register(EdgePath) +def _flip_edge_path(edges: EdgePath) -> None: + # see exploration/upright_hatch.py + for edge in edges: + _flip_edge(edge) + + +@singledispatch +def _flip_edge(edge) -> None: + raise TypeError(f"unsupported edge type: {edge!r}") + + +@_flip_edge.register(LineEdge) +def _flip_line_edge(edge: LineEdge) -> None: + edge.start = _flip_2d_vertex(edge.start) + edge.end = _flip_2d_vertex(edge.end) + + +@_flip_edge.register(ArcEdge) +def _flip_arc_edge(edge: ArcEdge) -> None: + edge.center = _flip_2d_vertex(edge.center) + # Start- and end angles are always stored in counter-clockwise orientation! + end_angle = edge.end_angle + edge.end_angle = _flip_deg_angle(edge.start_angle) + edge.start_angle = _flip_deg_angle(end_angle) + edge.ccw = not edge.ccw + + +@_flip_edge.register(EllipseEdge) +def _flip_ellipse_edge(edge: EllipseEdge) -> None: + edge.center = _flip_2d_vertex(edge.center) + edge.major_axis = _flip_2d_vertex(edge.major_axis) + # Ellipse params as angles in degrees - not radians! + # Do not exchange start- and end angles! + # see exploration/upright_hatch.py + edge.start_angle = _flip_deg_angle(edge.start_angle) + edge.end_angle = _flip_deg_angle(edge.end_angle) + edge.ccw = not edge.ccw + + +@_flip_edge.register(SplineEdge) +def _flip_spline_edge(edge: SplineEdge) -> None: + flip_2d_vertex = _flip_2d_vertex + if edge.start_tangent is not None: + edge.start_tangent = flip_2d_vertex(edge.start_tangent) + if edge.end_tangent is not None: + edge.end_tangent = flip_2d_vertex(edge.end_tangent) + edge.control_points = [flip_2d_vertex(v) for v in edge.control_points] + edge.fit_points = [flip_2d_vertex(v) for v in edge.fit_points] diff --git a/.venv/lib/python3.12/site-packages/ezdxf/urecord.py b/.venv/lib/python3.12/site-packages/ezdxf/urecord.py new file mode 100644 index 0000000..46b4a20 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/urecord.py @@ -0,0 +1,302 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +""" +UserRecord(): store user data in a XRECORD entity. + +The group code 302 is used as a structure tag. + +All supported data types have a fixed group code: + - str: 1 + - int: 90 - 32-bit values + - float: 40 - doubles + - Vec3, Vec2: 10, 20, 30 - Vec2 is stored as Vec3 + - list, tuple: starts with tag (302, "[") and ends with tag (302, "]") + - dict: starts with tag (302, "{") and ends with tag (302, "}") + +The str type can have a max. length of 2049 characters and cannot contain "\n" +or "\r". + +This is an advanced feature for experienced programmers, handle with care! +The attribute UserRecord.data is a simple Python list with read/write access. + +The UserRecord can store nested list and dict objects. + +BinaryData(): store arbitrary binary data in a XRECORD entity + +""" +from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Optional, + Iterable, + Sequence, + Mapping, + MutableSequence, + cast, +) +from ezdxf.lldxf import const +from ezdxf.entities import XRecord +from ezdxf.lldxf.tags import Tags, binary_data_to_dxf_tags +from ezdxf.lldxf.types import dxftag +from ezdxf.math import Vec3, Vec2 +from ezdxf.tools import take2 +from ezdxf.tools.binarydata import bytes_to_hexstr + +if TYPE_CHECKING: + from ezdxf.document import Drawing + +TYPE_GROUP_CODE = 2 +STR_GROUP_CODE = 1 +INT_GROUP_CODE = 90 +FLOAT_GROUP_CODE = 40 +VEC3_GROUP_CODE = 10 +COLLECTION_GROUP_CODE = 302 +START_LIST = "[" +END_LIST = "]" +START_DICT = "{" +END_DICT = "}" +DEFAULT_NAME = "UserRecord" + +__all__ = ["UserRecord", "BinaryRecord"] + + +class UserRecord: + def __init__( + self, + xrecord: Optional[XRecord] = None, + *, + name: str = DEFAULT_NAME, + doc: Optional[Drawing] = None, + ): + """Setup a :class:`UserRecord` with the given `name`. + + The data is stored in the given `xrecord` object, or in a new created + :class:`~ezdxf.entities.XRecord` instance if ``None``. If `doc` is not + ``None`` the new xrecord is added to the OBJECTS section of the DXF + document. + + Changes of the content has to be committed at the end to be stored in + the underlying :attr:`xrecord` object. + + Args: + xrecord (XRecord): underlying :class:`~ezdxf.entities.XRecord` instance, + if ``None`` a new one will be created + name (str): name of the user list + doc (Drawing): DXF document or ``None`` + + """ + if xrecord is None: + if doc is None: + xrecord = XRecord.new() + else: + xrecord = cast(XRecord, doc.objects.new_entity("XRECORD", {})) + + self.xrecord = xrecord + self.name = str(name) + self.data: MutableSequence = parse_xrecord(self.xrecord, self.name) + + @property + def handle(self) -> Optional[str]: + """DXF handle of the underlying :class:`~ezdxf.entities.XRecord` instance.""" + return self.xrecord.dxf.get("handle") + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.commit() + + def __str__(self): + """Return str(self).""" + return str(self.data) + + def commit(self) -> XRecord: + """Store :attr:`data` in the underlying :class:`~ezdxf.entities.XRecord` + instance. This call is not required if using the class by the ``with`` + statement. + + Raises: + DXFValueError: invalid chars ``"\\n"`` or ``"\\r"`` in a string + DXFTypeError: invalid data type + + """ + self.xrecord.tags = compile_user_record(self.name, self.data) + return self.xrecord + + +def parse_xrecord(xrecord: XRecord, name: str) -> list: + data: list = [] + tags = xrecord.tags + if tags: + code, value = tags[0] + if code != TYPE_GROUP_CODE and value != name: + raise const.DXFTypeError( + f"{str(xrecord)} is not an user record of type {name}" + ) + data.extend(item for item in parse_items(tags[1:])) + return data + + +def parse_items(tags: Tags) -> list: + stack: list = [] + items: list = [] + for tag in tags: + code, value = tag + if code == STR_GROUP_CODE: + items.append(str(value)) + elif code == INT_GROUP_CODE: + items.append(int(value)) + elif code == FLOAT_GROUP_CODE: + items.append(float(value)) + elif code == VEC3_GROUP_CODE: + items.append(Vec3(value)) + elif code == COLLECTION_GROUP_CODE and ( + value == START_LIST or value == START_DICT + ): + stack.append(items) + items = [] + elif code == COLLECTION_GROUP_CODE and ( + value == END_LIST or value == END_DICT + ): + try: + prev_level = stack.pop() + except IndexError: + raise const.DXFStructureError( + f"invalid nested structure, mismatch of structure tags" + f" ({COLLECTION_GROUP_CODE}, ...)" + ) + if value == END_DICT: + prev_level.append(dict(take2(items))) + else: + prev_level.append(items) + items = prev_level + else: + raise const.DXFValueError( + f"invalid group code in tag: ({code}, {value})" + ) + if stack: + raise const.DXFStructureError( + f"invalid nested structure, mismatch of structure tags" + f"({COLLECTION_GROUP_CODE}, ...)" + ) + return items + + +def compile_user_record(name: str, data: Iterable) -> Tags: + tags = Tags() + tags.append(dxftag(TYPE_GROUP_CODE, name)) + tags.extend(tags_from_list(data)) + return tags + + +def tags_from_list(items: Iterable) -> Tags: + tags = Tags() + for item in items: + if isinstance(item, str): + if len(item) > 2049: # DXF R2000 limit for group codes 0-9 + raise const.DXFValueError( + "string too long, max. 2049 characters" + ) + if "\n" in item or "\r" in item: + raise const.DXFValueError( + "found invalid line break '\\n' or '\\r'" + ) + tags.append(dxftag(STR_GROUP_CODE, item)) + elif isinstance(item, int): + tags.append(dxftag(INT_GROUP_CODE, item)) + elif isinstance(item, float): + tags.append(dxftag(FLOAT_GROUP_CODE, item)) + elif isinstance(item, Vec3): + tags.append(dxftag(VEC3_GROUP_CODE, item)) + elif isinstance(item, Vec2): + tags.append(dxftag(VEC3_GROUP_CODE, Vec3(item))) + elif isinstance(item, Sequence): + tags.append(dxftag(COLLECTION_GROUP_CODE, START_LIST)) + tags.extend(tags_from_list(item)) + tags.append(dxftag(COLLECTION_GROUP_CODE, END_LIST)) + elif isinstance(item, Mapping): + tags.append(dxftag(COLLECTION_GROUP_CODE, START_DICT)) + tags.extend(tags_from_list(key_value_list(item))) + tags.append(dxftag(COLLECTION_GROUP_CODE, END_DICT)) + else: + raise const.DXFTypeError(f"unsupported type: {type(item)}") + return tags + + +def key_value_list(data: Mapping) -> Iterable: + for k, v in data.items(): + yield k + yield v + + +class BinaryRecord: + def __init__( + self, + xrecord: Optional[XRecord] = None, + *, + doc: Optional[Drawing] = None, + ): + """Setup a :class:`BinaryRecord`. + + The data is stored in the given `xrecord` object, or in a new created + :class:`~ezdxf.entities.XRecord` instance if ``None``. If `doc` is not + ``None`` the new xrecord is added to the OBJECTS section of the DXF + document. + + Changes of the content has to be committed at the end to be stored in + the underlying :attr:`xrecord` object. + + Args: + xrecord (XRecord): underlying :class:`~ezdxf.entities.XRecord` instance, + if ``None`` a new one will be created + doc (Drawing): DXF document or ``None`` + + """ + if xrecord is None: + if doc is None: + xrecord = XRecord.new() + else: + xrecord = cast(XRecord, doc.objects.new_entity("XRECORD", {})) + + self.xrecord = xrecord + self.data: bytes = parse_binary_data(self.xrecord.tags) + + @property + def handle(self) -> Optional[str]: + """DXF handle of the underlying :class:`~ezdxf.entities.XRecord` instance.""" + return self.xrecord.dxf.get("handle") + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.commit() + + def __str__(self) -> str: + """Return str(self).""" + return bytes_to_hexstr(self.data) + + def commit(self) -> XRecord: + """Store binary :attr:`data` in the underlying :class:`~ezdxf.entities.XRecord` + instance. This call is not required if using the class by the ``with`` + statement. + + """ + + assert isinstance( + self.data, (bytes, bytearray, memoryview) + ), "expected binary data" + self.xrecord.tags = binary_data_to_dxf_tags( + self.data, + length_group_code=160, + value_group_code=310, + value_size=127, + ) + return self.xrecord + + +def parse_binary_data(tags: Tags) -> bytes: + if tags and tags[0].code == 160: + return b"".join(t.value for t in tags if t.code == 310) + else: + return b"" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/version.py b/.venv/lib/python3.12/site-packages/ezdxf/version.py new file mode 100644 index 0000000..c72c3f5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/version.py @@ -0,0 +1,28 @@ +# version scheme: (major, minor, micro, release_level) +# +# major: +# 0 .. not all planned features done +# 1 .. all features available +# 2 .. if significant API change (2, 3, ...) +# +# minor: +# changes with new features or minor API changes +# +# micro: +# changes with bug fixes, maybe also minor API changes +# +# release_state: +# a .. alpha: adding new features - non-public development state +# b .. beta: testing new features - public development state +# rc .. release candidate: testing release - public testing +# release: public release +# +# examples: +# major pre-release alpha 2: VERSION = "0.9.0a2"; version = (0, 9, 0, 'a2') +# major release candidate 0: VERSION = "0.9.0rc0"; version = (0, 9, 0, 'rc0') +# major release: VERSION = "0.9.0"; version = (0, 9, 0, 'release') +# 1. bug fix release beta0: VERSION = "0.9.1b0"; version = (0, 9, 1, 'b0') +# 2. bug fix release: VERSION = "0.9.2"; version = (0, 9, 2, 'release') + +version = (1, 3, 4, "release") +__version__ = "1.3.4" diff --git a/.venv/lib/python3.12/site-packages/ezdxf/xclip.py b/.venv/lib/python3.12/site-packages/ezdxf/xclip.py new file mode 100644 index 0000000..9cf9323 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/xclip.py @@ -0,0 +1,450 @@ +# Copyright (c) 2024, Manfred Moitzi +# License: MIT License +from __future__ import annotations +from typing import Iterable, Sequence +import dataclasses + +from ezdxf.lldxf import const +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.types import dxftag +from ezdxf.entities import SpatialFilter, DXFEntity, Dictionary, Insert, XRecord +from ezdxf.math import Vec2, Vec3, UVec, Z_AXIS, Matrix44, BoundingBox2d +from ezdxf.entities.acad_xrec_roundtrip import RoundtripXRecord + +__all__ = ["get_spatial_filter", "XClip", "ClippingPath"] + +ACAD_FILTER = "ACAD_FILTER" +ACAD_XREC_ROUNDTRIP = "ACAD_XREC_ROUNDTRIP" +ACAD_INVERTEDCLIP_ROUNDTRIP = "ACAD_INVERTEDCLIP_ROUNDTRIP" +ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE = "ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE" + +SPATIAL = "SPATIAL" + + +@dataclasses.dataclass +class ClippingPath: + """Stores the SPATIAL_FILTER clipping paths in original form that I still don't fully + understand for `inverted` clipping paths. All boundary paths are simple polygons as a + sequence of :class:`~ezdxf.math.Vec2`. + + Attributes: + vertices: Contains the boundary polygon for regular clipping paths. + Contains the outer boundary path for inverted clippings paths - but not always! + inverted_clip: + Contains the inner boundary for inverted clipping paths - but not always! + inverted_clip_compare: + Contains the combined inner- and the outer boundaries for inverted + clipping paths - but not always! + is_inverted_clip: ``True`` for inverted clipping paths + + """ + + vertices: Sequence[Vec2] = tuple() + inverted_clip: Sequence[Vec2] = tuple() + inverted_clip_compare: Sequence[Vec2] = tuple() + is_inverted_clip: bool = False + + def inner_polygon(self) -> Sequence[Vec2]: + """Returns the inner clipping polygon as sequence of Vec2.""" + # The exact data structure of inverted clippings polygons is still not + # clear to me, so use the smallest polygon as inner clipping polygon. + if not self.is_inverted_clip: + return self.vertices + inner_polygon = self.vertices + if bbox_area(self.inverted_clip) < bbox_area(inner_polygon): + inner_polygon = self.inverted_clip + return inner_polygon + + def outer_bounds(self) -> BoundingBox2d: + """Returns the maximum extents as BoundingBox2d.""" + if not self.is_inverted_clip: + return BoundingBox2d(self.vertices) + # The exact data structure of inverted clippings polygons is still not + # clear to me, this is my best guess: + return BoundingBox2d(self.inverted_clip_compare) + + +class XClip: + """Helper class to manage the clipping path of INSERT entities. + + Provides a similar functionality as the XCLIP command in CAD applications. + + .. important:: + + This class handles only 2D clipping paths. + + The visibility of the clipping path can be set individually for each block + reference, but the HEADER variable $XCLIPFRAME ultimately determines whether the + clipping path is displayed or plotted by the application: + + === =============== === + 0 not displayed not plotted + 1 displayed not plotted + 2 displayed plotted + === =============== === + + The default setting is 2. + + """ + + def __init__(self, insert: Insert) -> None: + if not isinstance(insert, Insert): + raise const.DXFTypeError(f"INSERT entity required, got {str(insert)}") + self._insert = insert + self._spatial_filter = get_spatial_filter(insert) + + def get_spatial_filter(self) -> SpatialFilter | None: + """Returns the underlaying SPATIAL_FILTER entity if the INSERT entity has a + clipping path and returns ``None`` otherwise. + """ + return self._spatial_filter + + def get_xclip_frame_policy(self) -> int: + policy: int = 2 + if self._insert.doc is not None: + policy = self._insert.doc.header.get("$XCLIPFRAME", 2) + return policy + + @property + def has_clipping_path(self) -> bool: + """Returns if the INSERT entity has a clipping path.""" + return self._spatial_filter is not None + + @property + def is_clipping_enabled(self) -> bool: + """Returns ``True`` if block reference clipping is enabled.""" + if isinstance(self._spatial_filter, SpatialFilter): + return bool(self._spatial_filter.dxf.is_clipping_enabled) + return False + + @property + def is_inverted_clip(self) -> bool: + """Returns ``True`` if clipping path is inverted.""" + xrec = get_roundtrip_xrecord(self._spatial_filter) + if xrec is None: + return False + return xrec.has_section(ACAD_INVERTEDCLIP_ROUNDTRIP) + + def enable_clipping(self) -> None: + """Enable block reference clipping.""" + if isinstance(self._spatial_filter, SpatialFilter): + self._spatial_filter.dxf.is_clipping_enabled = 1 + + def disable_clipping(self) -> None: + """Disable block reference clipping.""" + if isinstance(self._spatial_filter, SpatialFilter): + self._spatial_filter.dxf.is_clipping_enabled = 0 + + def get_block_clipping_path(self) -> ClippingPath: + """Returns the clipping path in block coordinates (relative to the block origin).""" + vertices: Sequence[Vec2] = [] + if not isinstance(self._spatial_filter, SpatialFilter): + return ClippingPath() + m = self._spatial_filter.inverse_insert_matrix + vertices = Vec2.tuple( + m.transform_vertices(self._spatial_filter.boundary_vertices) + ) + if len(vertices) == 2: + vertices = _rect_path(vertices) + + clipping_path = ClippingPath(vertices, is_inverted_clip=False) + xrec = get_roundtrip_xrecord(self._spatial_filter) + if isinstance(xrec, RoundtripXRecord): + clipping_path.inverted_clip = get_roundtrip_vertices( + xrec, ACAD_INVERTEDCLIP_ROUNDTRIP, m + ) + clipping_path.inverted_clip_compare = get_roundtrip_vertices( + xrec, ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE, m + ) + clipping_path.is_inverted_clip = True + return clipping_path + + def get_wcs_clipping_path(self) -> ClippingPath: + """Returns the clipping path in WCS coordinates (relative to the WCS origin) as + 2D path projected onto the xy-plane. + """ + vertices: Sequence[Vec2] = tuple() + if not isinstance(self._spatial_filter, SpatialFilter): + return ClippingPath(vertices, vertices) + block_clipping_path = self.get_block_clipping_path() + m = self._insert.matrix44() + vertices = Vec2.tuple(m.transform_vertices(block_clipping_path.vertices)) + if len(vertices) == 2: # rectangle by diagonal corner vertices + vertices = BoundingBox2d(vertices).rect_vertices() + wcs_clipping_path = ClippingPath( + vertices, is_inverted_clip=block_clipping_path.is_inverted_clip + ) + if block_clipping_path.is_inverted_clip: + inverted_clip = Vec2.tuple( + m.transform_vertices(block_clipping_path.inverted_clip) + ) + if len(inverted_clip) == 2: # rectangle by diagonal corner vertices + inverted_clip = BoundingBox2d(inverted_clip).rect_vertices() + wcs_clipping_path.inverted_clip = inverted_clip + wcs_clipping_path.inverted_clip_compare = Vec2.tuple( + m.transform_vertices(block_clipping_path.inverted_clip_compare) + ) + return wcs_clipping_path + + def set_block_clipping_path(self, vertices: Iterable[UVec]) -> None: + """Set clipping path in block coordinates (relative to block origin). + + The clipping path is located in the xy-plane, the z-axis of all vertices will + be ignored. The clipping path doesn't have to be closed (first vertex != last vertex). + Two vertices define a rectangle where the sides are parallel to x- and y-axis. + + Raises: + DXFValueError: clipping path has less than two vertrices + + """ + if self._spatial_filter is None: + self._spatial_filter = new_spatial_filter(self._insert) + spatial_filter = self._spatial_filter + spatial_filter.set_boundary_vertices(vertices) + spatial_filter.dxf.origin = Vec3(0, 0, 0) + spatial_filter.dxf.extrusion = Z_AXIS + spatial_filter.dxf.has_front_clipping_plane = 0 + spatial_filter.dxf.front_clipping_plane_distance = 0.0 + spatial_filter.dxf.has_back_clipping_plane = 0 + spatial_filter.dxf.back_clipping_plane_distance = 0.0 + + # The clipping path set by ezdxf is always relative to the block origin and + # therefore both transformation matrices are the identity matrix - which does + # nothing. + m = Matrix44() + spatial_filter.set_inverse_insert_matrix(m) + spatial_filter.set_transform_matrix(m) + self._discard_inverted_clip() + + def set_wcs_clipping_path(self, vertices: Iterable[UVec]) -> None: + """Set clipping path in WCS coordinates (relative to WCS origin). + + The clipping path is located in the xy-plane, the z-axis of all vertices will + be ignored. The clipping path doesn't have to be closed (first vertex != last vertex). + Two vertices define a rectangle where the sides are parallel to x- and y-axis. + + Raises: + DXFValueError: clipping path has less than two vertrices + ZeroDivisionError: Block reference transformation matrix is not invertible + + """ + m = self._insert.matrix44() + try: + m.inverse() + except ZeroDivisionError: + raise ZeroDivisionError( + "Block reference transformation matrix is not invertible." + ) + _vertices = Vec2.list(vertices) + if len(_vertices) == 2: + _vertices = _rect_path(_vertices) + self.set_block_clipping_path(m.transform_vertices(_vertices)) + + def invert_clipping_path( + self, extents: Iterable[UVec] | None = None, *, ignore_acad_compatibility=False + ) -> None: + """Invert clipping path. (experimental feature) + + The outer boundary is defined by the bounding box of the given `extents` + vertices or auto-detected if `extents` is ``None``. + + The `extents` are BLOCK coordinates. + Requires an existing clipping path and that clipping path cannot be inverted. + + .. warning:: + + You have to set the flag `ignore_acad_compatibility` to ``True`` to use + this feature. AutoCAD will not load DXF files with inverted clipping paths + created by ezdxf!!!! + + """ + if ignore_acad_compatibility is False: + return + + current_clipping_path = self.get_block_clipping_path() + if len(current_clipping_path.vertices) < 2: + raise const.DXFValueError("no clipping path set") + if current_clipping_path.is_inverted_clip: + raise const.DXFValueError("clipping path is already inverted") + + assert self._insert.doc is not None + self._insert.doc.add_acad_incompatibility_message( + "\nAutoCAD will not load DXF files with inverted clipping paths created by ezdxf" + ) + grow_factor = 0.0 + if extents is None: + extents = self._detect_block_extents() + # grow bounding box by 10%, bbox detection is not very precise for text + # based entities: + grow_factor = 0.1 + + bbox = BoundingBox2d(extents) + bbox.extend(current_clipping_path.vertices) + if not bbox.has_data: + raise const.DXFValueError("extents not detectable") + + if grow_factor: + bbox.grow(max(bbox.size) * grow_factor) + + # inverted_clip is the regular clipping path + inverted_clip = current_clipping_path.vertices + # construct an inverted clipping path + inverted_clip_compare = _get_inverted_clip_compare_vertices(bbox, inverted_clip) + # set inverted_clip_compare as regular clipping path + self.set_block_clipping_path(inverted_clip_compare) + self._set_inverted_clipping_path(inverted_clip, inverted_clip_compare) + + def _detect_block_extents(self) -> Sequence[Vec2]: + from ezdxf import bbox + + insert = self._insert + doc = insert.doc + assert doc is not None, "valid DXF document required" + no_vertices: Sequence[Vec2] = tuple() + block = doc.blocks.get(insert.dxf.name) + if block is None: + return no_vertices + + _bbox = bbox.extents(block, fast=True) + if not _bbox.has_data: + return no_vertices + return Vec2.tuple([_bbox.extmin, _bbox.extmax]) + + def _set_inverted_clipping_path( + self, clip_vertices: Iterable[Vec2], compare_vertices: Iterable[Vec2] + ) -> None: + spatial_filter = self._spatial_filter + assert isinstance(spatial_filter, SpatialFilter) + xrec = get_roundtrip_xrecord(spatial_filter) + if xrec is None: + xrec = new_roundtrip_xrecord(spatial_filter) + + clip_tags = Tags(dxftag(10, Vec3(v)) for v in clip_vertices) + compare_tags = Tags(dxftag(10, Vec3(v)) for v in compare_vertices) + xrec.set_section(ACAD_INVERTEDCLIP_ROUNDTRIP, clip_tags) + xrec.set_section(ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE, compare_tags) + + def discard_clipping_path(self) -> None: + """Delete the clipping path. The clipping path doesn't have to exist. + + This method does not discard the extension dictionary of the base entity, + even when its empty. + """ + if not isinstance(self._spatial_filter, SpatialFilter): + return + + xdict = self._insert.get_extension_dict() + xdict.discard(ACAD_FILTER) + entitydb = self._insert.doc.entitydb # type: ignore + assert entitydb is not None + entitydb.delete_entity(self._spatial_filter) + self._spatial_filter = None + + def _discard_inverted_clip(self) -> None: + if isinstance(self._spatial_filter, SpatialFilter): + self._spatial_filter.discard_extension_dict() + + def cleanup(self): + """Discard the extension dictionary of the base entity when empty.""" + self._insert.discard_empty_extension_dict() + + +def _rect_path(vertices: Iterable[Vec2]) -> Sequence[Vec2]: + """Returns the path vertices for the smallest rectangular boundary around the given + vertices. + """ + return BoundingBox2d(vertices).rect_vertices() + + +def _get_inverted_clip_compare_vertices( + bbox: BoundingBox2d, hole: Sequence[Vec2] +) -> Sequence[Vec2]: + # AutoCAD does not accept this paths and from further tests it's clear that the + # geometry of the inverted clipping path is the problem not the DXF structure! + from ezdxf.math.clipping import make_inverted_clipping_polygon + + assert (bbox.extmax is not None) and (bbox.extmin is not None) + return make_inverted_clipping_polygon(inner_polygon=list(hole), outer_bounds=bbox) + + +def get_spatial_filter(entity: DXFEntity) -> SpatialFilter | None: + """Returns the underlaying SPATIAL_FILTER entity if the given `entity` has a + clipping path and returns ``None`` otherwise. + """ + try: + xdict = entity.get_extension_dict() + except AttributeError: + return None + acad_filter = xdict.get(ACAD_FILTER) + if not isinstance(acad_filter, Dictionary): + return None + acad_spatial_filter = acad_filter.get(SPATIAL) + if isinstance(acad_spatial_filter, SpatialFilter): + return acad_spatial_filter + return None + + +def new_spatial_filter(entity: DXFEntity) -> SpatialFilter: + """Creates the extension dict, the sub-dictionary ACAD_FILTER and the SPATIAL_FILTER + entity if not exist. + """ + doc = entity.doc + if doc is None: + raise const.DXFTypeError("Cannot add new clipping path to virtual entity.") + try: + xdict = entity.get_extension_dict() + except AttributeError: + xdict = entity.new_extension_dict() + acad_filter_dict = xdict.dictionary.get_required_dict(ACAD_FILTER) + spatial_filter = acad_filter_dict.get(SPATIAL) + if not isinstance(spatial_filter, SpatialFilter): + spatial_filter = doc.objects.add_dxf_object_with_reactor( + "SPATIAL_FILTER", {"owner": acad_filter_dict.dxf.handle} + ) + acad_filter_dict.add(SPATIAL, spatial_filter) + assert isinstance(spatial_filter, SpatialFilter) + return spatial_filter + + +def new_roundtrip_xrecord(spatial_filter: SpatialFilter) -> RoundtripXRecord: + try: + xdict = spatial_filter.get_extension_dict() + except AttributeError: + xdict = spatial_filter.new_extension_dict() + xrec = xdict.get(ACAD_XREC_ROUNDTRIP) + if xrec is None: + xrec = xdict.add_xrecord(ACAD_XREC_ROUNDTRIP) + xrec.set_reactors([xdict.handle]) + assert isinstance(xrec, XRecord) + return RoundtripXRecord(xrec) + + +def get_roundtrip_xrecord( + spatial_filter: SpatialFilter | None, +) -> RoundtripXRecord | None: + if spatial_filter is None: + return None + try: + xdict = spatial_filter.get_extension_dict() + except AttributeError: + return None + xrecord = xdict.get(ACAD_XREC_ROUNDTRIP) + if isinstance(xrecord, XRecord): + return RoundtripXRecord(xrecord) + return None + + +def get_roundtrip_vertices( + xrec: RoundtripXRecord, section_name: str, m: Matrix44 +) -> Sequence[Vec2]: + tags = xrec.get_section(section_name) + vertices = m.transform_vertices(Vec3(t.value) for t in tags) + return Vec2.tuple(vertices) + + +def bbox_area(vertice: Sequence[Vec2]) -> float: + bbox = BoundingBox2d(vertice) + if bbox.has_data: + size = bbox.size + return size.x * size.y + return 0.0 diff --git a/.venv/lib/python3.12/site-packages/ezdxf/xref.py b/.venv/lib/python3.12/site-packages/ezdxf/xref.py new file mode 100644 index 0000000..83cbeb1 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/xref.py @@ -0,0 +1,1664 @@ +# Copyright (c) 2023-2024, Manfred Moitzi +# License: MIT License +""" Resource management module for transferring DXF resources between documents. +""" +from __future__ import annotations +from typing import Optional, Sequence, Callable, Iterable +from typing_extensions import Protocol, TypeAlias +import enum +import pathlib +import logging +import os + +import ezdxf +from ezdxf.lldxf import const, validator, types +from ezdxf.lldxf.tags import Tags +from ezdxf.lldxf.validator import DXFInfo +from ezdxf.document import Drawing +from ezdxf.layouts import BaseLayout, Paperspace, BlockLayout +from ezdxf.entities import ( + is_graphic_entity, + is_dxf_object, + DXFEntity, + DXFClass, + factory, + BlockRecord, + Layer, + Linetype, + Textstyle, + DimStyle, + UCSTableEntry, + Material, + MLineStyle, + MLeaderStyle, + Block, + EndBlk, + Insert, + DXFLayout, + VisualStyle, +) +from ezdxf.entities.copy import CopyStrategy, CopySettings +from ezdxf.math import UVec, Vec3 + +__all__ = [ + "define", + "attach", + "embed", + "detach", + "write_block", + "load_modelspace", + "load_paperspace", + "Registry", + "ResourceMapper", + "ConflictPolicy", + "Loader", + "dxf_info", + "DXFInfo", + "XrefError", + "XrefDefinitionError", + "EntityError", + "LayoutError", +] + +logger = logging.getLogger("ezdxf") +NO_BLOCK = "0" +DEFAULT_LINETYPES = {"CONTINUOUS", "BYLAYER", "BYBLOCK"} +DEFAULT_LAYER = "0" +STANDARD = "STANDARD" +FilterFunction: TypeAlias = Callable[[DXFEntity], bool] +LoadFunction: TypeAlias = Callable[[str], Drawing] + + +# I prefer to see the debug messages stored in the object, because I mostly debug test +# code and pytest does not show logging or print messages by default. +def _log_debug_messages(messages: Iterable[str]) -> None: + for msg in messages: + logger.debug(msg) + + +class XrefError(Exception): + """base exception for the xref module""" + + pass + + +class XrefDefinitionError(XrefError): + pass + + +class EntityError(XrefError): + pass + + +class LayoutError(XrefError): + pass + + +class InternalError(XrefError): + pass + + +class ConflictPolicy(enum.Enum): + """These conflict policies define how to handle resource name conflicts. + + .. versionadded:: 1.1 + + Attributes: + KEEP: Keeps the existing resource name of the target document and ignore the + resource from the source document. + XREF_PREFIX: This policy handles the resource import like CAD applications by + **always** renaming the loaded resources to `$0$`, where `xref` + is the name of source document, the `$0$` part is a number to create a + unique resource name and `` is the name of the resource itself. + NUM_PREFIX: This policy renames the loaded resources to `$0$` only if the + resource `` already exists. The `$0$` prefix is a number to create a + unique resource name and `` is the name of the resource itself. + + """ + + KEEP = enum.auto() + XREF_PREFIX = enum.auto() + NUM_PREFIX = enum.auto() + + +def dxf_info(filename: str | os.PathLike) -> DXFInfo: + """Scans the HEADER section of a DXF document and returns a :class:`DXFInfo` + object, which contains information about the DXF version, text encoding, drawing + units and insertion base point. + + Raises: + IOError: not a DXF file or a generic IO error + + """ + filename = str(filename) + if validator.is_binary_dxf_file(filename): + with open(filename, "rb") as fp: + # The HEADER section of a DXF R2018 file has a length of ~5300 bytes. + data = fp.read(8192) + return validator.binary_dxf_info(data) + if validator.is_dxf_file(filename): + # the relevant information has 7-bit ASCII encoding + with open(filename, "rt", errors="ignore") as fp: + return validator.dxf_info(fp) + else: + raise IOError("Not a DXF files.") + + +# Exceptions from the ConflictPolicy +# ---------------------------------- +# Resources named "STANDARD" will be preserved (KEEP). +# Materials "GLOBAL", "BYLAYER" and "BYBLOCK" will be preserved (KEEP). +# Plot style "NORMAL" will be preserved (KEEP). +# Layers "0", "DEFPOINTS" and special Autodesk layers starting with "*" will be preserved (KEEP). +# Linetypes "CONTINUOUS", "BYLAYER" and "BYBLOCK" will be preserved (KEEP) +# Special blocks like arrow heads will be preserved (KEEP). +# Anonymous blocks get a new arbitrary name following the rules of anonymous block names. + +# Notes about DXF files as XREFs +# ------------------------------ +# AutoCAD cannot use DXF R12 files as external references (BricsCAD can)! +# AutoCAD may use DXF R2000+ as external references, but does not accept DXF files +# created by ezdxf nor BricsCAD, which opened for itself are total valid DXF documents. +# +# Autodesk DWG TrueView V2022: +# > Error: Unable to load . +# > Drawing may need recovery. +# +# Using the RECOVER command of BricsCAD and rewriting the DXF files by BricsCAD does +# not work. Replacing the XREF by a newly created DXF file by BricsCAD does not work +# either. +# +# BricsCAD accepts any DXF/DWG file as XREF! + +# Idea for automated object loading from the OBJECTS section: +# ----------------------------------------------------------- +# EXT_DICT = Extension DICTIONARY; ROOT_DICT = "unnamed" DICTIONARY +# Pointer and owner handles in XRECORD or unknown objects and entities have well-defined +# group codes, if the creator app follow the rules of the DXF reference. +# +# Object types: +# A. object owner path ends at a graphical entity, e.g. LINE -> EXT_DICT -> XRECORD +# B. owner path of an object ends at the root dictionary and contains only objects +# from the OBJECTS section, e.g. ROOT_DICT -> DICTIONARY -> MATERIAL +# or ROOT_DICT -> XRECORD -> CUSTOM_OBJECT -> XRECORD. +# The owner path of object type B cannot contain a graphical entity because the owner +# of a graphical entity is always a BLOCK_RECORD. +# C. owner path ends at an object that does not exist or with an owner handle "0", +# so the last owner handle of the owner path is invalid, this seems to be an invalid +# construct +# +# Automated object loading with reconstruction of the owner path: +# --------------------------------------------------------------- +# example MATERIAL object: +# - find the owner path of the source MATERIAL object: +# ROOT_DICT -> DICTIONARY (material collection) -> MATERIAL +# 1 does the parent object of MATERIAL in the target doc exist: +# 2 YES: add MATERIAL to the owner DICTIONARY (conflict policy!) +# 3 NO: +# 4 create the immediate parent DICTIONARY of MATERIAL in the target dict and add +# it to the ROOT_DICT of the target doc +# GOTO 2 add the MATERIAL to the new owner DICTIONARY +# +# Top management layer of the OBJECTS section +# ------------------------------------------- +# Create a standard mapping for the ROOT_DICT and its entries (DICTIONARY objects) +# from the source doc to the target doc. I think these are always basic management +# structures which shouldn't be duplicated. + + +def define(doc: Drawing, block_name: str, filename: str, overlay=False) -> None: + """Add an external reference (xref) definition to a document. + + XREF attachment types: + + - attached: the XREF that's inserted into this drawing is also present in a + document to which this document is inserted as an XREF. + - overlay: the XREF that's inserted into this document is **not** present in a + document to which this document is inserted as an XREF. + + Args: + doc: host document + block_name: name of the xref block + filename: external reference filename + overlay: creates an XREF overlay if ``True`` and an XREF attachment otherwise + + Raises: + XrefDefinitionError: block with same name exist + + .. versionadded:: 1.1 + + """ + if block_name in doc.blocks: + raise XrefDefinitionError(f"block '{block_name}' already exist") + doc.blocks.new( + name=block_name, + dxfattribs={ + "flags": make_xref_flags(overlay), + "xref_path": filename, + }, + ) + + +def make_xref_flags(overlay: bool) -> int: + if overlay: + return const.BLK_XREF_OVERLAY | const.BLK_EXTERNAL + else: + return const.BLK_XREF | const.BLK_EXTERNAL + + +def attach( + doc: Drawing, + *, + block_name: str, + filename: str, + insert: UVec = (0, 0, 0), + scale: float = 1.0, + rotation: float = 0.0, + overlay=False, +) -> Insert: + """Attach the file `filename` to the host document as external reference (XREF) and + creates a default block reference for the XREF in the modelspace of the document. + The function raises an :class:`XrefDefinitionError` exception if the block definition + already exist, but an XREF can be inserted multiple times by adding additional block + references:: + + msp.add_blockref(block_name, insert=another_location) + + .. important:: + + If the XREF has different drawing units than the host document, the scale + factor between these units must be applied as a uniform scale factor to the + block reference! Unfortunately the XREF drawing units can only be detected by + scanning the HEADER section of a document by the function :func:`dxf_info` and + is therefore not done automatically by this function. + Advice: always use the same units for all drawings of a project! + + Args: + doc: host DXF document + block_name: name of the XREF definition block + filename: file name of the XREF + insert: location of the default block reference + scale: uniform scaling factor + rotation: rotation angle in degrees + overlay: creates an XREF overlay if ``True`` and an XREF attachment otherwise + + Returns: + Insert: default block reference for the XREF + + Raises: + XrefDefinitionError: block with same name exist + + .. versionadded:: 1.1 + + """ + define(doc, block_name, filename, overlay=overlay) + dxfattribs = dict() + if rotation: + dxfattribs["rotation"] = float(rotation) + if scale != 1.0: + scale = float(scale) + dxfattribs["xscale"] = scale + dxfattribs["yscale"] = scale + dxfattribs["zscale"] = scale + location = Vec3(insert) + msp = doc.modelspace() + return msp.add_blockref(block_name, insert=location, dxfattribs=dxfattribs) + + +def find_xref(xref_filename: str, search_paths: Sequence[pathlib.Path]) -> pathlib.Path: + """Returns the path of the XREF file. + + Args: + xref_filename: filename of the XREF, absolute or relative path + search_paths: search paths where to look for the XREF file + + .. versionadded:: 1.1 + + """ + filepath = pathlib.Path(xref_filename) + # 1. check absolute xref_filename + if filepath.exists(): + return filepath + + name = filepath.name + for path in search_paths: + if not path.is_dir(): + path = path.parent + search_path = path.resolve() + # 2. check relative xref path to search path + filepath = search_path / xref_filename + if filepath.exists(): + return filepath + # 3. check if the file is in the search folder + filepath = search_path / name + if filepath.exists(): + return filepath + + return pathlib.Path(xref_filename) + + +def embed( + xref: BlockLayout, + *, + load_fn: Optional[LoadFunction] = None, + search_paths: Iterable[pathlib.Path | str] = tuple(), + conflict_policy=ConflictPolicy.XREF_PREFIX, +) -> None: + """Loads the modelspace of the XREF as content into a block layout. + + The loader function loads the XREF as `Drawing` object, by default the + function :func:`ezdxf.readfile` is used to load DXF files. To load DWG files use the + :func:`~ezdxf.addons.odafc.readfile` function from the :mod:`ezdxf.addons.odafc` + add-on. The :func:`ezdxf.recover.readfile` function is very robust for reading DXF + files with errors. + + If the XREF path isn't absolute the XREF is searched in the folder of the host DXF + document and in the `search_path` folders. + + Args: + xref: :class:`BlockLayout` of the XREF document + load_fn: function to load the content of the XREF as `Drawing` object + search_paths: list of folders to search for XREFS, default is the folder of the + host document or the current directory if no filepath is set + conflict_policy: how to resolve name conflicts + + Raises: + XrefDefinitionError: argument `xref` is not a XREF definition + FileNotFoundError: XREF file not found + DXFVersionError: cannot load a XREF with a newer DXF version than the host + document, try the :mod:`~ezdxf.addons.odafc` add-on to downgrade the XREF + document or upgrade the host document + + .. versionadded:: 1.1 + + """ + assert isinstance(xref, BlockLayout), "expected BLOCK definition of XREF" + target_doc = xref.doc + assert target_doc is not None, "valid DXF document required" + block = xref.block + assert isinstance(block, Block) + if not block.is_xref: + raise XrefDefinitionError("argument 'xref' is not a XREF definition") + + xref_path: str = block.dxf.get("xref_path", "") + if not xref_path: + raise XrefDefinitionError("no xref path defined") + + _search_paths = [pathlib.Path(p) for p in search_paths] + _search_paths.insert(0, target_doc.get_abs_filepath()) + + filepath = find_xref(xref_path, _search_paths) + if not filepath.exists(): + raise FileNotFoundError(f"file not found: '{filepath}'") + + if load_fn: + source_doc = load_fn(str(filepath)) + else: + source_doc = ezdxf.readfile(filepath) + if source_doc.dxfversion > target_doc.dxfversion: + raise const.DXFVersionError( + "cannot embed a XREF with a newer DXF version into the host document" + ) + loader = Loader(source_doc, target_doc, conflict_policy=conflict_policy) + loader.load_modelspace(xref) + loader.execute(xref_prefix=xref.name) + # reset XREF flags: + block.set_flag_state(const.BLK_XREF | const.BLK_EXTERNAL, state=False) + # update BLOCK origin: + origin = source_doc.header.get("$INSBASE") + if origin: + block.dxf.base_point = Vec3(origin) + + +def detach( + block: BlockLayout, *, xref_filename: str | os.PathLike, overlay=False +) -> Drawing: + """Write the content of `block` into the modelspace of a new DXF document and + convert `block` to an external reference (XREF). The new DXF document has to be + written by the caller: :code:`xref_doc.saveas(xref_filename)`. + This way it is possible to convert the DXF document to DWG by the + :mod:`~ezdxf.addons.odafc` add-on if necessary:: + + xref_doc = xref.detach(my_block, "my_block.dwg") + odafc.export_dwg(xref_doc, "my_block.dwg") + + It's recommended to clean up the entity database of the host document afterwards:: + + doc.entitydb.purge() + + The function does not create any block references. These references should already + exist and do not need to be changed since references to blocks and XREFs are the + same. + + Args: + block: block definition to detach + xref_filename: name of the external referenced file + overlay: creates an XREF overlay if ``True`` and an XREF attachment otherwise + + .. versionadded:: 1.1 + + """ + source_doc = block.doc + assert source_doc is not None, "valid DXF document required" + target_doc = ezdxf.new(dxfversion=source_doc.dxfversion, units=block.units) + loader = Loader(source_doc, target_doc, conflict_policy=ConflictPolicy.KEEP) + loader.load_block_layout_into(block, target_doc.modelspace()) + loader.execute() + target_doc.header["$INSBASE"] = block.base_point + block_to_xref(block, xref_filename, overlay=overlay) + return target_doc + + +def block_to_xref( + block: BlockLayout, xref_filename: str | os.PathLike, *, overlay=False +) -> None: + """Convert a block definition into an external reference. + + (internal API) + """ + block.delete_all_entities() + block_entity = block.block + assert block_entity is not None, "invalid BlockLayout" + block_entity.dxf.xref_path = str(xref_filename) + block_entity.dxf.flags = make_xref_flags(overlay) + + +def write_block(entities: Sequence[DXFEntity], *, origin: UVec = (0, 0, 0)) -> Drawing: + """Write `entities` into the modelspace of a new DXF document. + + This function is called "write_block" because the new DXF document can be used as + an external referenced block. This function is similar to the WBLOCK command in CAD + applications. + + Virtual entities are not supported, because each entity needs a real database- and + owner handle. + + Args: + entities: DXF entities to write + origin: block origin, defines the point in the modelspace which will be inserted + at the insert location of the block reference + + Raises: + EntityError: virtual entities are not supported + + .. versionadded:: 1.1 + + """ + if len(entities) == 0: + return ezdxf.new() + if any(e.dxf.owner is None for e in entities): + raise EntityError("virtual entities are not supported") + source_doc = entities[0].doc + assert source_doc is not None, "expected a valid source document" + target_doc = ezdxf.new(dxfversion=source_doc.dxfversion, units=source_doc.units) + loader = Loader(source_doc, target_doc) + loader.add_command(LoadEntities(entities, target_doc.modelspace())) + loader.execute() + target_doc.header["$INSBASE"] = Vec3(origin) + return target_doc + + +def load_modelspace( + sdoc: Drawing, + tdoc: Drawing, + filter_fn: Optional[FilterFunction] = None, + conflict_policy=ConflictPolicy.KEEP, +) -> None: + """Loads the modelspace content of the source document into the modelspace + of the target document. The filter function `filter_fn` gets every source entity as + input and returns ``True`` to load the entity or ``False`` otherwise. + + Args: + sdoc: source document + tdoc: target document + filter_fn: optional function to filter entities from the source modelspace + conflict_policy: how to resolve name conflicts + + .. versionadded:: 1.1 + + """ + loader = Loader(sdoc, tdoc, conflict_policy=conflict_policy) + loader.load_modelspace(filter_fn=filter_fn) + loader.execute() + + +def load_paperspace( + psp: Paperspace, + tdoc: Drawing, + filter_fn: Optional[FilterFunction] = None, + conflict_policy=ConflictPolicy.KEEP, +) -> None: + """Loads the paperspace layout `psp` into the target document. The filter function + `filter_fn` gets every source entity as input and returns ``True`` to load the + entity or ``False`` otherwise. + + Args: + psp: paperspace layout to load + tdoc: target document + filter_fn: optional function to filter entities from the source paperspace layout + conflict_policy: how to resolve name conflicts + + .. versionadded:: 1.1 + + """ + if psp.doc is tdoc: + raise LayoutError("Source paperspace layout cannot be from target document.") + loader = Loader(psp.doc, tdoc, conflict_policy=conflict_policy) + loader.load_paperspace_layout(psp, filter_fn=filter_fn) + loader.execute() + + +class Registry(Protocol): + def add_entity(self, entity: DXFEntity, block_key: str = NO_BLOCK) -> None: + ... + + def add_block(self, block_record: BlockRecord) -> None: + ... + + def add_handle(self, handle: Optional[str]) -> None: + ... + + def add_layer(self, name: str) -> None: + ... + + def add_linetype(self, name: str) -> None: + ... + + def add_text_style(self, name: str) -> None: + ... + + def add_dim_style(self, name: str) -> None: + ... + + def add_block_name(self, name: str) -> None: + ... + + def add_appid(self, name: str) -> None: + ... + + +class ResourceMapper(Protocol): + def get_handle(self, handle: str, default="0") -> str: + ... + + def get_reference_of_copy(self, handle: str) -> Optional[DXFEntity]: + ... + + def get_layer(self, name: str) -> str: + ... + + def get_linetype(self, name: str) -> str: + ... + + def get_text_style(self, name: str) -> str: + ... + + def get_dim_style(self, name: str) -> str: + ... + + def get_block_name(self, name: str) -> str: + ... + + def map_resources_of_copy(self, entity: DXFEntity) -> None: + ... + + def map_pointers(self, tags: Tags, new_owner_handle: str = "") -> None: + ... + + def map_acad_dict_entry( + self, dict_name: str, entry_name: str, entity: DXFEntity + ) -> tuple[str, DXFEntity]: + ... + + def map_existing_handle( + self, source: DXFEntity, clone: DXFEntity, attrib_name: str, *, optional=False + ) -> None: + ... + + +class LoadingCommand: + def register_resources(self, registry: Registry) -> None: + pass + + def execute(self, transfer: _Transfer) -> None: + pass + + +class LoadEntities(LoadingCommand): + """Loads all given entities into the target layout.""" + + def __init__( + self, entities: Sequence[DXFEntity], target_layout: BaseLayout + ) -> None: + self.entities = entities + if not isinstance(target_layout, BaseLayout): + raise LayoutError(f"invalid target layout type: {type(target_layout)}") + self.target_layout = target_layout + + def register_resources(self, registry: Registry) -> None: + for e in self.entities: + registry.add_entity(e, block_key=e.dxf.owner) + + def execute(self, transfer: _Transfer) -> None: + target_layout = self.target_layout + for entity in self.entities: + clone = transfer.get_entity_copy(entity) + if clone is None: + transfer.debug(f"xref:cannot copy {str(entity)}") + continue + if is_graphic_entity(clone): + target_layout.add_entity(clone) # type: ignore + else: + transfer.debug( + f"found non-graphic entity {str(clone)} as layout content" + ) + if isinstance(target_layout, Paperspace): + _reorganize_paperspace_viewports(target_layout) + + +def _reorganize_paperspace_viewports(paperspace: Paperspace) -> None: + main_vp = paperspace.main_viewport() + if main_vp is None: + main_vp = paperspace.add_new_main_viewport() + # destroy loaded main VIEWPORT entities + for vp in paperspace.viewports(): + if vp.dxf.id == 1 and vp is not main_vp: + paperspace.delete_entity(vp) + paperspace.set_current_viewport_handle(main_vp.dxf.handle) + + +class LoadPaperspaceLayout(LoadingCommand): + """Loads a paperspace layout as a new paperspace layout into the target document. + If a paperspace layout with same name already exists the layout will be renamed + to " (x)" where x is 2 or the next free number. + """ + + def __init__(self, psp: Paperspace, filter_fn: Optional[FilterFunction]) -> None: + if not isinstance(psp, Paperspace): + raise LayoutError(f"invalid paperspace layout type: {type(psp)}") + self.paperspace_layout = psp + self.filter_fn = filter_fn + + def source_entities(self) -> list[DXFEntity]: + filter_fn = self.filter_fn + if filter_fn: + return [e for e in self.paperspace_layout if filter_fn(e)] + else: + return list(self.paperspace_layout) + + def register_resources(self, registry: Registry) -> None: + registry.add_entity(self.paperspace_layout.dxf_layout) + block_key = self.paperspace_layout.layout_key + for e in self.source_entities(): + registry.add_entity(e, block_key=block_key) + + def execute(self, transfer: _Transfer) -> None: + source_dxf_layout = self.paperspace_layout.dxf_layout + target_dxf_layout = transfer.get_reference_of_copy(source_dxf_layout.dxf.handle) + assert isinstance(target_dxf_layout, DXFLayout) + target_layout = transfer.registry.target_doc.paperspace( + target_dxf_layout.dxf.name + ) + for entity in self.source_entities(): + clone = transfer.get_entity_copy(entity) + if clone and is_graphic_entity(clone): + target_layout.add_entity(clone) # type: ignore + else: + transfer.debug( + f"found non-graphic entity {str(clone)} as layout content" + ) + _reorganize_paperspace_viewports(target_layout) + + +class LoadBlockLayout(LoadingCommand): + """Loads a block layout as a new block layout into the target document. If a block + layout with the same name exists the conflict policy will be applied. + """ + + def __init__(self, block: BlockLayout) -> None: + if not isinstance(block, BlockLayout): + raise LayoutError(f"invalid block layout type: {type(block)}") + self.block_layout = block + + def register_resources(self, registry: Registry) -> None: + block_record = self.block_layout.block_record + if isinstance(block_record, BlockRecord): + registry.add_entity(block_record) + + +class LoadResources(LoadingCommand): + """Loads table entries into the target document. If a table entry with the same name + exists the conflict policy will be applied. + """ + + def __init__(self, entities: Sequence[DXFEntity]) -> None: + self.entities = entities + + def register_resources(self, registry: Registry) -> None: + for e in self.entities: + registry.add_entity(e, block_key=NO_BLOCK) + + +class Loader: + """Load entities and resources from the source DXF document `sdoc` into the + target DXF document. + + Args: + sdoc: source DXF document + tdoc: target DXF document + conflict_policy: :class:`ConflictPolicy` + + """ + + def __init__( + self, sdoc: Drawing, tdoc: Drawing, conflict_policy=ConflictPolicy.KEEP + ) -> None: + assert isinstance(sdoc, Drawing), "a valid source document is mandatory" + assert isinstance(tdoc, Drawing), "a valid target document is mandatory" + assert sdoc is not tdoc, "source and target document cannot be the same" + if tdoc.dxfversion < sdoc.dxfversion: + logger.warning( + "target document has older DXF version than the source document" + ) + self.sdoc: Drawing = sdoc + self.tdoc: Drawing = tdoc + self.conflict_policy = conflict_policy + self._commands: list[LoadingCommand] = [] + + def add_command(self, command: LoadingCommand) -> None: + self._commands.append(command) + + def load_modelspace( + self, + target_layout: Optional[BaseLayout] = None, + filter_fn: Optional[FilterFunction] = None, + ) -> None: + """Loads the content of the modelspace of the source document into a layout of + the target document, the modelspace of the target document is the default target + layout. The filter function `filter_fn` is used to skip source entities, the + function should return ``False`` for entities to ignore and ``True`` otherwise. + + Args: + target_layout: target layout can be any layout: modelspace, paperspace + layout or block layout. + filter_fn: function to filter source entities + + """ + if target_layout is None: + target_layout = self.tdoc.modelspace() + elif not isinstance(target_layout, BaseLayout): + raise LayoutError(f"invalid target layout type: {type(target_layout)}") + if target_layout.doc is not self.tdoc: + raise LayoutError( + f"given target layout does not belong to the target document" + ) + if filter_fn is None: + entities = list(self.sdoc.modelspace()) + else: + entities = [e for e in self.sdoc.modelspace() if filter_fn(e)] + self.add_command(LoadEntities(entities, target_layout)) + + def load_paperspace_layout( + self, + psp: Paperspace, + filter_fn: Optional[FilterFunction] = None, + ) -> None: + """Loads a paperspace layout as a new paperspace layout into the target document. + If a paperspace layout with same name already exists the layout will be renamed + to " (2)" or " (3)" and so on. The filter function + `filter_fn` is used to skip source entities, the function should return ``False`` + for entities to ignore and ``True`` otherwise. + + The content of the modelspace which may be displayed through a VIEWPORT entity + will **not** be loaded! + + Args: + psp: the source paperspace layout + filter_fn: function to filter source entities + + """ + if not isinstance(psp, Paperspace): + raise const.DXFTypeError(f"invalid paperspace layout type: {type(psp)}") + if psp.doc is not self.sdoc: + raise LayoutError( + f"given paperspace layout does not belong to the source document" + ) + self.add_command(LoadPaperspaceLayout(psp, filter_fn)) + + def load_paperspace_layout_into( + self, + psp: Paperspace, + target_layout: BaseLayout, + filter_fn: Optional[FilterFunction] = None, + ) -> None: + """Loads the content of a paperspace layout into an existing layout of the target + document. The filter function `filter_fn` is used to skip source entities, the + function should return ``False`` for entities to ignore and ``True`` otherwise. + + The content of the modelspace which may be displayed through a + VIEWPORT entity will **not** be loaded! + + Args: + psp: the source paperspace layout + target_layout: target layout can be any layout: modelspace, paperspace + layout or block layout. + filter_fn: function to filter source entities + + """ + if not isinstance(psp, Paperspace): + raise LayoutError(f"invalid paperspace layout type: {type(psp)}") + if not isinstance(target_layout, BaseLayout): + raise LayoutError(f"invalid target layout type: {type(target_layout)}") + if psp.doc is not self.sdoc: + raise LayoutError( + f"given paperspace layout does not belong to the source document" + ) + if target_layout.doc is not self.tdoc: + raise LayoutError( + f"given target layout does not belong to the target document" + ) + if filter_fn is None: + entities = list(psp) + else: + entities = [e for e in psp if filter_fn(e)] + self.add_command(LoadEntities(entities, target_layout)) + + def load_block_layout( + self, + block_layout: BlockLayout, + ) -> None: + """Loads a block layout (block definition) as a new block layout into the target + document. If a block layout with the same name exists the conflict policy will + be applied. This method cannot load modelspace or paperspace layouts. + + Args: + block_layout: the source block layout + + """ + if not isinstance(block_layout, BlockLayout): + raise LayoutError(f"invalid block layout type: {type(block_layout)}") + if block_layout.doc is not self.sdoc: + raise LayoutError( + f"given block layout does not belong to the source document" + ) + self.add_command(LoadBlockLayout(block_layout)) + + def load_block_layout_into( + self, + block_layout: BlockLayout, + target_layout: BaseLayout, + ) -> None: + """Loads the content of a block layout (block definition) into an existing layout + of the target document. This method cannot load the content of + modelspace or paperspace layouts. + + Args: + block_layout: the source block layout + target_layout: target layout can be any layout: modelspace, paperspace + layout or block layout. + + """ + if not isinstance(block_layout, BlockLayout): + raise LayoutError(f"invalid block layout type: {type(block_layout)}") + if not isinstance(target_layout, BaseLayout): + raise LayoutError(f"invalid target layout type: {type(target_layout)}") + if block_layout.doc is not self.sdoc: + raise LayoutError( + f"given block layout does not belong to the source document" + ) + if target_layout.doc is not self.tdoc: + raise LayoutError( + f"given target layout does not belong to the target document" + ) + self.add_command(LoadEntities(list(block_layout), target_layout)) + + def load_layers(self, names: Sequence[str]) -> None: + """Loads the layers defined by the argument `names` into the target document. + In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.layers) + self.add_command(LoadResources(entities)) + + def load_linetypes(self, names: Sequence[str]) -> None: + """Loads the linetypes defined by the argument `names` into the target document. + In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.linetypes) + self.add_command(LoadResources(entities)) + + def load_text_styles(self, names: Sequence[str]) -> None: + """Loads the TEXT styles defined by the argument `names` into the target document. + In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.styles) + self.add_command(LoadResources(entities)) + + def load_dim_styles(self, names: Sequence[str]) -> None: + """Loads the DIMENSION styles defined by the argument `names` into the target + document. In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.dimstyles) + self.add_command(LoadResources(entities)) + + def load_mline_styles(self, names: Sequence[str]) -> None: + """Loads the MLINE styles defined by the argument `names` into the target + document. In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.mline_styles) + self.add_command(LoadResources(entities)) + + def load_mleader_styles(self, names: Sequence[str]) -> None: + """Loads the MULTILEADER styles defined by the argument `names` into the target + document. In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.mleader_styles) + self.add_command(LoadResources(entities)) + + def load_materials(self, names: Sequence[str]) -> None: + """Loads the MATERIALS defined by the argument `names` into the target + document. In the case of a name conflict the conflict policy will be applied. + """ + entities = _get_table_entries(names, self.sdoc.materials) + self.add_command(LoadResources(entities)) + + def execute(self, xref_prefix: str = "") -> None: + """Execute all loading commands. The `xref_prefix` string is used as XREF name + when the conflict policy :attr:`ConflictPolicy.XREF_PREFIX` is applied. + """ + registry = _Registry(self.sdoc, self.tdoc) + debug = ezdxf.options.debug + + for cmd in self._commands: + cmd.register_resources(registry) + + if debug: + _log_debug_messages(registry.debug_messages) + + cpm = CopyMachine(self.tdoc) + + cpm.copy_blocks(registry.source_blocks) + transfer = _Transfer( + registry=registry, + copies=cpm.copies, + objects=cpm.objects, + handle_mapping=cpm.handle_mapping, + conflict_policy=self.conflict_policy, + copy_errors=cpm.copy_errors, + ) + if xref_prefix: + transfer.xref_prefix = str(xref_prefix) + transfer.add_object_copies(cpm.objects) + transfer.register_classes(cpm.classes) + transfer.register_table_resources() + transfer.register_object_resources() + transfer.redirect_handle_mapping() + transfer.map_object_resources() + transfer.map_entity_resources() + transfer.copy_settings() + + for cmd in self._commands: + cmd.execute(transfer) + transfer.finalize() + + +def _get_table_entries(names: Iterable[str], table) -> list[DXFEntity]: + entities: list[DXFEntity] = [] + for name in names: + try: + entry = table.get(name) + if entry: + entities.append(entry) + except const.DXFTableEntryError: + pass + return entities + + +class _Registry: + def __init__(self, sdoc: Drawing, tdoc: Drawing) -> None: + self.source_doc = sdoc + self.target_doc = tdoc + + # source_blocks: + # - key is the owner handle (layout key) + # - value is a dict(): key is source-entity-handle, value is source-entity + # Storing the entities to copy in a dict() guarantees that each entity is only + # copied once and a dict() preserves the order which a set() doesn't and + # that is nice for testing. + # - entry NO_BLOCK (layout key "0") contains table entries and DXF objects + self.source_blocks: dict[str, dict[str, DXFEntity]] = {NO_BLOCK: {}} + self.appids: set[str] = set() + self.debug_messages: list[str] = [] + + def debug(self, msg: str) -> None: + self.debug_messages.append(msg) + + def add_entity(self, entity: DXFEntity, block_key: str = NO_BLOCK) -> None: + assert entity is not None, "internal error: entity is None" + block = self.source_blocks.setdefault(block_key, {}) + entity_handle = entity.dxf.handle + if entity_handle in block: + return + block[entity_handle] = entity + entity.register_resources(self) + + def add_block(self, block_record: BlockRecord) -> None: + # add resource entity BLOCK_RECORD to NO_BLOCK + self.add_entity(block_record) + # block content in block + block_handle = block_record.dxf.handle + self.add_entity(block_record.block, block_handle) # type: ignore + for entity in block_record.entity_space: + self.add_entity(entity, block_handle) + self.add_entity(block_record.endblk, block_handle) # type: ignore + + def add_handle(self, handle: Optional[str]) -> None: + """Add resource by handle (table entry or object), cannot add graphic entities. + + Raises: + EntityError: cannot add graphic entity + + """ + if handle is None or handle == "0": + return + entity = self.source_doc.entitydb.get(handle) + if entity is None: + self.debug(f"source entity #{handle} does not exist") + return + if is_graphic_entity(entity): + raise EntityError(f"cannot add graphic entity: {str(entity)}") + self.add_entity(entity) + + def add_layer(self, name: str) -> None: + if name == DEFAULT_LAYER: + # Layer name "0" gets never mangled and always exist in the target document. + return + try: + layer = self.source_doc.layers.get(name) + self.add_entity(layer) + except const.DXFTableEntryError: + self.debug(f"source layer '{name}' does not exist") + + def add_linetype(self, name: str) -> None: + # These linetype names get never mangled and always exist in the target document. + if name.upper() in DEFAULT_LINETYPES: + return + try: + linetype = self.source_doc.linetypes.get(name) + self.add_entity(linetype) + except const.DXFTableEntryError: + self.debug(f"source linetype '{name}' does not exist") + + def add_text_style(self, name) -> None: + try: + text_style = self.source_doc.styles.get(name) + self.add_entity(text_style) + except const.DXFTableEntryError: + self.debug(f"source text style '{name}' does not exist") + + def add_dim_style(self, name: str) -> None: + try: + dim_style = self.source_doc.dimstyles.get(name) + self.add_entity(dim_style) + except const.DXFTableEntryError: + self.debug(f"source dimension style '{name}' does not exist") + + def add_block_name(self, name: str) -> None: + try: + block_record = self.source_doc.block_records.get(name) + self.add_entity(block_record) + except const.DXFTableEntryError: + self.debug(f"source block '{name}' does not exist") + + def add_appid(self, name: str) -> None: + self.appids.add(name.upper()) + + +class _Transfer: + def __init__( + self, + registry: _Registry, + copies: dict[str, dict[str, DXFEntity]], + objects: dict[str, DXFEntity], + handle_mapping: dict[str, str], + *, + conflict_policy=ConflictPolicy.KEEP, + copy_errors: set[str], + ) -> None: + self.registry = registry + # entry NO_BLOCK (layout key "0") contains table entries + self.copied_blocks = copies + self.copied_objects = objects + self.copy_errors = copy_errors + self.conflict_policy = conflict_policy + self.xref_prefix = get_xref_name(registry.source_doc) + self.layer_mapping: dict[str, str] = {} + self.linetype_mapping: dict[str, str] = {} + self.text_style_mapping: dict[str, str] = {} + self.dim_style_mapping: dict[str, str] = {} + self.block_name_mapping: dict[str, str] = {} + self.handle_mapping: dict[str, str] = handle_mapping + self._replace_handles: dict[str, str] = {} + self.debug_messages: list[str] = [] + + def debug(self, msg: str) -> None: + self.debug_messages.append(msg) + + def get_handle(self, handle: str, default="0") -> str: + return self.handle_mapping.get(handle, default) + + def get_reference_of_copy(self, handle: str) -> Optional[DXFEntity]: + handle_of_copy = self.handle_mapping.get(handle) + if handle_of_copy: + return self.registry.target_doc.entitydb.get(handle_of_copy) + return None + + def get_layer(self, name: str) -> str: + return self.layer_mapping.get(name, name) + + def get_linetype(self, name: str) -> str: + return self.linetype_mapping.get(name, name) + + def get_text_style(self, name: str) -> str: + return self.text_style_mapping.get(name, name) + + def get_dim_style(self, name: str) -> str: + return self.dim_style_mapping.get(name, name) + + def get_block_name(self, name: str) -> str: + return self.block_name_mapping.get(name, name) + + def get_entity_copy(self, entity: DXFEntity) -> Optional[DXFEntity]: + """Returns the copy of graphic entities.""" + try: + return self.copied_blocks[entity.dxf.owner][entity.dxf.handle] + except KeyError: + pass + return None + + def map_resources_of_copy(self, entity: DXFEntity) -> None: + clone = self.get_entity_copy(entity) + if clone: + entity.map_resources(clone, self) + elif entity.dxf.handle in self.copy_errors: + pass + else: + raise InternalError(f"copy of {entity} not found") + + def map_pointers(self, tags: Tags, new_owner_handle: str = "") -> None: + for index, tag in enumerate(tags): + if types.is_translatable_pointer(tag): + handle = self.get_handle(tag.value, default="0") + tags[index] = types.DXFTag(tag.code, handle) + if new_owner_handle and types.is_hard_owner(tag): + copied_object = self.registry.target_doc.entitydb.get(handle) + if copied_object is None: + continue + copied_object.dxf.owner = new_owner_handle + + def map_acad_dict_entry( + self, dict_name: str, entry_name: str, entity: DXFEntity + ) -> tuple[str, DXFEntity]: + """Map and add `entity` to a top level ACAD dictionary `dict_name` in root + dictionary. + """ + tdoc = self.registry.target_doc + acad_dict = tdoc.rootdict.get_required_dict(dict_name) + existing_entry = acad_dict.get(entry_name) + + # DICTIONARY entries are only renamed if they exist, this is different to TABLE + # entries: + if isinstance(existing_entry, DXFEntity): + if self.conflict_policy == ConflictPolicy.KEEP: + return entry_name, existing_entry + elif self.conflict_policy == ConflictPolicy.XREF_PREFIX: + entry_name = get_unique_dict_key( + entry_name, self.xref_prefix, acad_dict + ) + elif self.conflict_policy == ConflictPolicy.NUM_PREFIX: + entry_name = get_unique_dict_key(entry_name, "", acad_dict) + + loaded_entry = self.get_reference_of_copy(entity.dxf.handle) + if loaded_entry is None: + return "", entity + acad_dict.add(entry_name, loaded_entry) # type: ignore + loaded_entry.dxf.owner = acad_dict.dxf.handle + return entry_name, loaded_entry + + def map_existing_handle( + self, source: DXFEntity, clone: DXFEntity, attrib_name: str, *, optional=False + ) -> None: + """Map handle attribute if the original handle exist and the references entity + was really copied. + """ + handle = source.dxf.get(attrib_name, "") + if not handle: + return # handle does not exist in source entity + new_handle = self.get_handle(handle) + if new_handle and new_handle != "0": # copied entity exist + clone.dxf.set(attrib_name, new_handle) + else: + if optional: # discard handle attribute + clone.dxf.discard(attrib_name) + else: # set mandatory attribute to null-ptr + clone.dxf.set(attrib_name, "0") + + def register_table_resources(self) -> None: + """Register copied table-entries in resource tables of the target document.""" + self.register_appids() + # process copied table-entries, layout key is "0": + for source_entity_handle, entity in self.copied_blocks[NO_BLOCK].items(): + if entity.dxf.owner is not None: + continue # already processed! + + # add copied table-entries to tables in the target document + if isinstance(entity, Layer): + self.add_layer_entry(entity) + elif isinstance(entity, Linetype): + self.add_linetype_entry(entity) + elif isinstance(entity, Textstyle): + if entity.is_shape_file: + self.add_shape_file_entry(entity) + else: + self.add_text_style_entry(entity) + elif isinstance(entity, DimStyle): + self.add_dim_style_entry(entity) + elif isinstance(entity, BlockRecord): + self.add_block_record_entry(entity, source_entity_handle) + elif isinstance(entity, UCSTableEntry): + self.add_ucs_entry(entity) + + def register_object_resources(self) -> None: + """Register copied objects in object collections of the target document.""" + # Note: BricsCAD does not rename conflicting entries in object collections and + # always keeps the existing entry: + # - MATERIAL + # - MLINESTYLE + # - MLEADERSTYLE + # Ezdxf does rename conflicting entries according to self.conflict_policy, + # exceptions are only the system entries. + tdoc = self.registry.target_doc + for _, entity in self.copied_objects.items(): + if isinstance(entity, Material): + self.add_collection_entry( + tdoc.materials, + entity, + system_entries={"GLOBAL", "BYLAYER", "BYBLOCK"}, + ) + elif isinstance(entity, MLineStyle): + self.add_collection_entry( + tdoc.mline_styles, + entity, + system_entries={ + STANDARD, + }, + ) + elif isinstance(entity, MLeaderStyle): + self.add_collection_entry( + tdoc.mleader_styles, + entity, + system_entries={ + STANDARD, + }, + ) + elif isinstance(entity, VisualStyle): + self.add_visualstyle_entry(entity) + elif isinstance(entity, DXFLayout): + self.create_empty_paperspace_layout(entity) + # TODO: + # add GROUP to ACAD_GROUP dictionary + # add SCALE to ACAD_SCALELIST dictionary + # add TABLESTYLE to ACAD_TABLESTYLE dictionary + + def replace_handle_mapping(self, old_target, new_target) -> None: + self._replace_handles[old_target] = new_target + + def redirect_handle_mapping(self) -> None: + """Redirect handle mapping from copied entity to a handle of an existing entity + in the target document. + """ + temp_mapping: dict[str, str] = {} + replace_handles = self._replace_handles + # redirect source entity -> new target entity + for source_handle, target_handle in self.handle_mapping.items(): + if target_handle in replace_handles: + # build temp mapping, while iterating dict + temp_mapping[source_handle] = replace_handles[target_handle] + + for source_handle, new_target_handle in temp_mapping.items(): + self.handle_mapping[source_handle] = new_target_handle + + def register_appids(self) -> None: + tdoc = self.registry.target_doc + for appid in self.registry.appids: + try: + tdoc.appids.new(appid) + except const.DXFTableEntryError: + pass + + def register_classes(self, classes: Sequence[DXFClass]) -> None: + self.registry.target_doc.classes.register(classes) + + def map_entity_resources(self) -> None: + source_db = self.registry.source_doc.entitydb + for block_key, block in self.copied_blocks.items(): + for source_entity_handle, clone in block.items(): + source_entity = source_db.get(source_entity_handle) + if source_entity is None: + raise InternalError("database error, source entity not found") + if clone is not None and clone.is_alive: + source_entity.map_resources(clone, self) + + def map_object_resources(self) -> None: + source_db = self.registry.source_doc.entitydb + for source_object_handle, clone in self.copied_objects.items(): + source_entity = source_db.get(source_object_handle) + if source_entity is None: + raise InternalError("database error, source object not found") + if clone is not None and clone.is_alive: + source_entity.map_resources(clone, self) + + def add_layer_entry(self, layer: Layer) -> None: + tdoc = self.registry.target_doc + layer_name = layer.dxf.name.upper() + + # special layers - only copy if not exist + if layer_name in ("0", "DEFPOINTS") or validator.is_adsk_special_layer( + layer_name + ): + try: + special = tdoc.layers.get(layer_name) + except const.DXFTableEntryError: + special = None + if special: + # map copied layer handle to existing special layer + self.replace_handle_mapping(layer.dxf.handle, special.dxf.handle) + layer.destroy() + return + old_name = layer.dxf.name + self.add_table_entry(tdoc.layers, layer) + if layer.is_alive: + self.layer_mapping[old_name] = layer.dxf.name + + def add_linetype_entry(self, linetype: Linetype) -> None: + tdoc = self.registry.target_doc + if linetype.dxf.name.upper() in DEFAULT_LINETYPES: + standard = tdoc.linetypes.get(linetype.dxf.name) + self.replace_handle_mapping(linetype.dxf.handle, standard.dxf.handle) + linetype.destroy() + return + old_name = linetype.dxf.name + self.add_table_entry(tdoc.linetypes, linetype) + if linetype.is_alive: + self.linetype_mapping[old_name] = linetype.dxf.name + + def add_text_style_entry(self, text_style: Textstyle) -> None: + tdoc = self.registry.target_doc + old_name = text_style.dxf.name + self.add_table_entry(tdoc.styles, text_style) + if text_style.is_alive: + self.text_style_mapping[old_name] = text_style.dxf.name + + def add_shape_file_entry(self, text_style: Textstyle) -> None: + # A shape file (SHX file) entry is a special text style entry which name is "". + shape_file_name = text_style.dxf.font + if not shape_file_name: + return + tdoc = self.registry.target_doc + shape_file = tdoc.styles.find_shx(shape_file_name) + if shape_file is None: + shape_file = tdoc.styles.add_shx(shape_file_name) + self.replace_handle_mapping(text_style.dxf.handle, shape_file.dxf.handle) + + def add_dim_style_entry(self, dim_style: DimStyle) -> None: + tdoc = self.registry.target_doc + old_name = dim_style.dxf.name + self.add_table_entry(tdoc.dimstyles, dim_style) + if dim_style.is_alive: + self.dim_style_mapping[old_name] = dim_style.dxf.name + + def add_block_record_entry(self, block_record: BlockRecord, handle: str) -> None: + tdoc = self.registry.target_doc + block_name = block_record.dxf.name.upper() + old_name = block_record.dxf.name + + # is anonymous block name? + if len(block_name) > 1 and block_name[0] == "*": + # anonymous block names are always translated to another non-existing + # anonymous block name in the target document of the same type: + # e.g. "*D01" -> "*D0815" + block_record.dxf.name = tdoc.blocks.anonymous_block_name(block_name[1]) + tdoc.block_records.add_entry(block_record) + else: + # Standard arrow blocks are handled the same way as every other block, + # tested with BricsCAD V23: + # e.g. arrow block "_Dot" is loaded as "$0$_Dot" + self.add_table_entry(tdoc.block_records, block_record) + + if block_record.is_alive: + self.block_name_mapping[old_name] = block_record.dxf.name + self.restore_block_content(block_record, handle) + tdoc.blocks.add(block_record) # create BlockLayout + + def restore_block_content(self, block_record: BlockRecord, handle: str) -> None: + content = self.copied_blocks.get(handle, dict()) + block: Optional[Block] = None + endblk: Optional[EndBlk] = None + for entity in content.values(): + if isinstance(entity, (Block, EndBlk)): + if isinstance(entity, Block): + block = entity + else: + endblk = entity + elif is_graphic_entity(entity): + block_record.add_entity(entity) # type: ignore + else: + name = block_record.dxf.name + msg = f"skipping non-graphic DXF entity in BLOCK_RECORD('{name}', #{handle}): {str(entity)}" + logging.warning(msg) # this is a DXF structure error + self.debug(msg) + if isinstance(block, Block) and isinstance(endblk, EndBlk): + block_record.set_block(block, endblk) + else: + raise InternalError("invalid BLOCK_RECORD copy") + + def add_ucs_entry(self, ucs: UCSTableEntry) -> None: + # name mapping is not supported for UCS table entries + tdoc = self.registry.target_doc + self.add_table_entry(tdoc.ucs, ucs) + + def add_table_entry(self, table, entity: DXFEntity) -> None: + name = entity.dxf.name + if self.conflict_policy == ConflictPolicy.KEEP: + if table.has_entry(name): + existing_entry = table.get(name) + self.replace_handle_mapping( + entity.dxf.handle, existing_entry.dxf.handle + ) + entity.destroy() + return + elif self.conflict_policy == ConflictPolicy.XREF_PREFIX: + # always rename + entity.dxf.name = get_unique_table_name(name, self.xref_prefix, table) + elif self.conflict_policy == ConflictPolicy.NUM_PREFIX: + if table.has_entry(name): # rename only if exist + entity.dxf.name = get_unique_table_name(name, "", table) + table.add_entry(entity) + + def add_collection_entry( + self, collection, entry: DXFEntity, system_entries: set[str] + ) -> None: + # Note: BricsCAD does not rename conflicting entries in object collections and + # always keeps the existing entry: + # - MATERIAL + # - MLINESTYLE + # - MLEADERSTYLE + # Ezdxf does rename conflicting entries according to self.conflict_policy, + # exceptions are only the given `system_entries`. + name = entry.dxf.name + if name.upper() in system_entries: + special = collection.object_dict.get(name) + if special: + self.replace_handle_mapping(entry.dxf.handle, special.dxf.handle) + entry.destroy() + return + if self.conflict_policy == ConflictPolicy.KEEP: + existing_entry = collection.get(name) + if existing_entry: + self.replace_handle_mapping(entry.dxf.handle, existing_entry.dxf.handle) + entry.destroy() + return + elif self.conflict_policy == ConflictPolicy.XREF_PREFIX: + # always rename + entry.dxf.name = get_unique_table_name(name, self.xref_prefix, collection) + elif self.conflict_policy == ConflictPolicy.NUM_PREFIX: + if collection.has_entry(name): # rename only if exist + entry.dxf.name = get_unique_table_name(name, "", collection) + collection.object_dict.add(entry.dxf.name, entry) + # a resource collection is hard owner + entry.dxf.owner = collection.handle + + def add_visualstyle_entry(self, visualstyle: VisualStyle) -> None: + visualstyle_dict = self.registry.target_doc.rootdict.get_required_dict( + "ACAD_VISUALSTYLE" + ) + name = visualstyle.dxf.description + existing_entry = visualstyle_dict.get(name) + if existing_entry: # keep existing + self.replace_handle_mapping( + visualstyle.dxf.handle, existing_entry.dxf.handle + ) + visualstyle.destroy() + else: # add new entry; rename policy is not supported + visualstyle_dict.take_ownership(name, visualstyle) + + def create_empty_paperspace_layout(self, layout: DXFLayout) -> None: + tdoc = self.registry.target_doc + # The layout content will not be copied automatically! + # create new empty block layout: + block_name = tdoc.layouts.unique_paperspace_name() + block_layout = tdoc.blocks.new(block_name) + # link block layout and layout entity: + layout.dxf.block_record_handle = block_layout.block_record_handle + block_layout.block_record.dxf.layout = layout.dxf.handle + + paperspace = Paperspace(layout, tdoc) + tdoc.layouts.append_layout(paperspace) + + def add_object_copies(self, copies: dict[str, DXFEntity]) -> None: + """Add copied DXF objects to the OBJECTS section of the target document.""" + objects = self.registry.target_doc.objects + for _, obj in copies.items(): + if obj and obj.is_alive: + objects.add_object(obj) # type: ignore + + def copy_settings(self): + self.copy_raster_vars() + self.copy_wipeout_vars() + + def copy_raster_vars(self): + sdoc = self.registry.source_doc + tdoc = self.registry.target_doc + if ( + "ACAD_IMAGE_VARS" not in sdoc.rootdict # not required + or "ACAD_IMAGE_VARS" in tdoc.rootdict # do not replace existing values + ): + return + frame, quality, units = sdoc.objects.get_raster_variables() + tdoc.objects.set_raster_variables(frame=frame, quality=quality, units=units) + + def copy_wipeout_vars(self): + sdoc = self.registry.source_doc + tdoc = self.registry.target_doc + if ( + "ACAD_WIPEOUT_VARS" not in sdoc.rootdict # not required + or "ACAD_WIPEOUT_VARS" in tdoc.rootdict # do not replace existing values + ): + return + tdoc.objects.set_wipeout_variables( + frame=sdoc.objects.get_wipeout_frame_setting() + ) + + def finalize(self) -> None: + # remove replaced entities: + self.registry.target_doc.entitydb.purge() + for msg in self.debug_messages: + logger.log(logging.INFO, msg) + + +def get_xref_name(doc: Drawing) -> str: + if doc.filename: + return pathlib.Path(doc.filename).stem + return "" + + +def is_anonymous_block_name(name: str) -> bool: + return len(name) > 1 and name.startswith("*") + + +def get_unique_table_name(name: str, xref: str, table) -> str: + index: int = 0 + while True: + new_name = f"{xref}${index}${name}" + if not table.has_entry(new_name): + return new_name + index += 1 + + +def get_unique_dict_key(key: str, xref: str, dictionary) -> str: + index: int = 0 + while True: + new_key = f"{xref}${index}${key}" + if new_key not in dictionary: + return new_key + index += 1 + + +class CopyMachine: + def __init__(self, tdoc: Drawing) -> None: + self.target_doc = tdoc + self.copies: dict[str, dict[str, DXFEntity]] = {} + self.classes: list[DXFClass] = [] + self.objects: dict[str, DXFEntity] = {} + self.copy_errors: set[str] = set() + self.copy_strategy = CopyStrategy(CopySettings(set_source_of_copy=False)) + + # mapping from the source entity handle to the handle of the copied entity + self.handle_mapping: dict[str, str] = {} + + def copy_blocks(self, blocks: dict[str, dict[str, DXFEntity]]) -> None: + for handle, block in blocks.items(): + self.copies[handle] = self.copy_block(block) + + def copy_block(self, block: dict[str, DXFEntity]) -> dict[str, DXFEntity]: + copies: dict[str, DXFEntity] = {} + tdoc = self.target_doc + handle_mapping = self.handle_mapping + + for handle, entity in block.items(): + if isinstance(entity, DXFClass): + self.copy_dxf_class(entity) + continue + clone = self.copy_entity(entity) + if clone is None: + continue + factory.bind(clone, tdoc) + handle_mapping[handle] = clone.dxf.handle + # Get handle mapping for in-object copies: DICTIONARY + if hasattr(entity, "get_handle_mapping"): + self.handle_mapping.update(entity.get_handle_mapping(clone)) + + if is_dxf_object(clone): + self.objects[handle] = clone + else: + copies[handle] = clone + return copies + + def copy_entity(self, entity: DXFEntity) -> Optional[DXFEntity]: + try: + return entity.copy(copy_strategy=self.copy_strategy) + except const.DXFError: + self.copy_errors.add(entity.dxf.handle) + return None + + def copy_dxf_class(self, cls: DXFClass) -> None: + self.classes.append(cls.copy(copy_strategy=self.copy_strategy)) diff --git a/.venv/lib/python3.12/site-packages/ezdxf/zoom.py b/.venv/lib/python3.12/site-packages/ezdxf/zoom.py new file mode 100644 index 0000000..75b6e53 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/ezdxf/zoom.py @@ -0,0 +1,80 @@ +# Copyright (c) 2021-2022, Manfred Moitzi +# License: MIT License +from typing import Iterable, cast + +from ezdxf.math import UVec, Vec2, BoundingBox2d +from ezdxf.layouts import Layout, Paperspace +from ezdxf.entities import DXFEntity +from ezdxf import bbox + +__all__ = ["center", "objects", "extents", "window"] + + +def center(layout: Layout, point: UVec, size: UVec): + """Resets the active viewport center of `layout` to the given `point`, + argument `size` defines the width and height of the viewport. + Replaces the current viewport configuration by a single window + configuration. + + """ + doc = layout.doc + if doc: + if layout.is_modelspace: + height = guess_height(Vec2(size)) + doc.set_modelspace_vport(height, Vec2(point)) + elif layout.is_any_paperspace: + psp = cast(Paperspace, layout) + psp.reset_main_viewport(Vec2(point), Vec2(size)) + else: + raise TypeError("unsupported layout type") + + +def guess_height(size): + width = size.x + height = size.y + # expected aspect ratio: 16:10 + return max(width / 2.0, height) + + +def zoom_to_entities(layout: Layout, entities: Iterable[DXFEntity], factor): + if isinstance(layout, Paperspace): # filter main viewport + main_viewport = layout.main_viewport() + if main_viewport is not None: + entities = (e for e in entities if e is not main_viewport) + extents = bbox.extents(entities, fast=True) + if extents.has_data: + center(layout, extents.center, extents.size * factor) + + +def objects(layout: Layout, entities: Iterable[DXFEntity], factor: float = 1): + """Resets the active viewport limits of `layout` to the extents of the + given `entities`. Only entities in the given `layout` are taken into + account. The argument `factor` scales the viewport limits. + Replaces the current viewport configuration by a single window + configuration. + + """ + owner = layout.layout_key + content = (e for e in entities if e.dxf.owner == owner) + zoom_to_entities(layout, content, factor) + + +def extents(layout: Layout, factor: float = 1): + """Resets the active viewport limits of `layout` to the extents of all + entities in this `layout`. The argument `factor` scales the viewport limits. + Replaces the current viewport configuration by a single window + configuration. + + """ + zoom_to_entities(layout, layout, factor) + + +def window(layout: Layout, p1: UVec, p2: UVec): + """Resets the active viewport limits of `layout` to the lower left corner + `p1` and the upper right corner `p2`. + Replaces the current viewport configuration by a single window + configuration. + + """ + extents = BoundingBox2d([p1, p2]) + center(layout, extents.center, extents.size) diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA new file mode 100644 index 0000000..5a02107 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA @@ -0,0 +1,101 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 3.0.3 +Summary: A simple framework for building complex web applications. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Typing :: Typed +Requires-Dist: Werkzeug>=3.0.0 +Requires-Dist: Jinja2>=3.1.2 +Requires-Dist: itsdangerous>=2.1.2 +Requires-Dist: click>=8.1.3 +Requires-Dist: blinker>=1.6.2 +Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10' +Requires-Dist: asgiref>=3.2 ; extra == "async" +Requires-Dist: python-dotenv ; extra == "dotenv" +Project-URL: Changes, https://flask.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/flask/ +Provides-Extra: async +Provides-Extra: dotenv + +# Flask + +Flask is a lightweight [WSGI][] web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around [Werkzeug][] +and [Jinja][], and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +[WSGI]: https://wsgi.readthedocs.io/ +[Werkzeug]: https://werkzeug.palletsprojects.com/ +[Jinja]: https://jinja.palletsprojects.com/ + + +## Installing + +Install and update from [PyPI][] using an installer such as [pip][]: + +``` +$ pip install -U Flask +``` + +[PyPI]: https://pypi.org/project/Flask/ +[pip]: https://pip.pypa.io/en/stable/getting-started/ + + +## A Simple Example + +```python +# save this as app.py +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def hello(): + return "Hello, World!" +``` + +``` +$ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + + +## Contributing + +For guidance on setting up a development environment and how to make a +contribution to Flask, see the [contributing guidelines][]. + +[contributing guidelines]: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst + + +## Donate + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD new file mode 100644 index 0000000..0010f76 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD @@ -0,0 +1,58 @@ +../../../bin/flask,sha256=q9Gsokdag0EXj0zx4GnGjdrMWMVFO5iFdwuWCbV-H0Q,242 +flask-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.0.3.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask-3.0.3.dist-info/METADATA,sha256=exPahy4aahjV-mYqd9qb5HNP8haB_IxTuaotoSvCtag,3177 +flask-3.0.3.dist-info/RECORD,, +flask-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask-3.0.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +flask-3.0.3.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask/__init__.py,sha256=6xMqdVA0FIQ2U1KVaGX3lzNCdXPzoHPaa0hvQCNcfSk,2625 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-312.pyc,, +flask/__pycache__/__main__.cpython-312.pyc,, +flask/__pycache__/app.cpython-312.pyc,, +flask/__pycache__/blueprints.cpython-312.pyc,, +flask/__pycache__/cli.cpython-312.pyc,, +flask/__pycache__/config.cpython-312.pyc,, +flask/__pycache__/ctx.cpython-312.pyc,, +flask/__pycache__/debughelpers.cpython-312.pyc,, +flask/__pycache__/globals.cpython-312.pyc,, +flask/__pycache__/helpers.cpython-312.pyc,, +flask/__pycache__/logging.cpython-312.pyc,, +flask/__pycache__/sessions.cpython-312.pyc,, +flask/__pycache__/signals.cpython-312.pyc,, +flask/__pycache__/templating.cpython-312.pyc,, +flask/__pycache__/testing.cpython-312.pyc,, +flask/__pycache__/typing.cpython-312.pyc,, +flask/__pycache__/views.cpython-312.pyc,, +flask/__pycache__/wrappers.cpython-312.pyc,, +flask/app.py,sha256=7-lh6cIj27riTE1Q18Ok1p5nOZ8qYiMux4Btc6o6mNc,60143 +flask/blueprints.py,sha256=7INXPwTkUxfOQXOOv1yu52NpHPmPGI5fMTMFZ-BG9yY,4430 +flask/cli.py,sha256=OOaf_Efqih1i2in58j-5ZZZmQnPpaSfiUFbEjlL9bzw,35825 +flask/config.py,sha256=bLzLVAj-cq-Xotu9erqOFte0xSFaVXyfz0AkP4GbwmY,13312 +flask/ctx.py,sha256=4atDhJJ_cpV1VMq4qsfU4E_61M1oN93jlS2H9gjrl58,15120 +flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 +flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 +flask/helpers.py,sha256=tYrcQ_73GuSZVEgwFr-eMmV69UriFQDBmt8wZJIAqvg,23084 +flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602 +flask/json/__pycache__/__init__.cpython-312.pyc,, +flask/json/__pycache__/provider.cpython-312.pyc,, +flask/json/__pycache__/tag.cpython-312.pyc,, +flask/json/provider.py,sha256=q6iB83lSiopy80DZPrU-9mGcWwrD0mvLjiv9fHrRZgc,7646 +flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281 +flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228 +flask/sansio/__pycache__/app.cpython-312.pyc,, +flask/sansio/__pycache__/blueprints.cpython-312.pyc,, +flask/sansio/__pycache__/scaffold.cpython-312.pyc,, +flask/sansio/app.py,sha256=YG5Gf7JVf1c0yccWDZ86q5VSfJUidOVp27HFxFNxC7U,38053 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=WLV9TRQMMhGlXz-1OKtQ3lv6mtIBQZxdW2HezYrGxoI,30633 +flask/sessions.py,sha256=RU4lzm9MQW9CtH8rVLRTDm8USMJyT4LbvYe7sxM2__k,14807 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=2TcXLT85Asflm2W9WOSFxKCmYn5e49w_Jkg9-NaaJWo,7537 +flask/testing.py,sha256=3BFXb3bP7R5r-XLBuobhczbxDu8-1LWRzYuhbr-lwaE,10163 +flask/typing.py,sha256=ZavK-wV28Yv8CQB7u73qZp_jLalpbWdrXS37QR1ftN0,3190 +flask/views.py,sha256=B66bTvYBBcHMYk4dA1ScZD0oTRTBl0I5smp1lRm9riI,6939 +flask/wrappers.py,sha256=m1j5tIJxIu8_sPPgTAB_G4TTh52Q-HoDuw_qHV5J59g,5831 diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/REQUESTED b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.txt b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.txt new file mode 100644 index 0000000..eec6733 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask=flask.cli:main + diff --git a/.venv/lib/python3.12/site-packages/flask/__init__.py b/.venv/lib/python3.12/site-packages/flask/__init__.py new file mode 100644 index 0000000..e86eb43 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/__init__.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import typing as t + +from . import json as json +from .app import Flask as Flask +from .blueprints import Blueprint as Blueprint +from .config import Config as Config +from .ctx import after_this_request as after_this_request +from .ctx import copy_current_request_context as copy_current_request_context +from .ctx import has_app_context as has_app_context +from .ctx import has_request_context as has_request_context +from .globals import current_app as current_app +from .globals import g as g +from .globals import request as request +from .globals import session as session +from .helpers import abort as abort +from .helpers import flash as flash +from .helpers import get_flashed_messages as get_flashed_messages +from .helpers import get_template_attribute as get_template_attribute +from .helpers import make_response as make_response +from .helpers import redirect as redirect +from .helpers import send_file as send_file +from .helpers import send_from_directory as send_from_directory +from .helpers import stream_with_context as stream_with_context +from .helpers import url_for as url_for +from .json import jsonify as jsonify +from .signals import appcontext_popped as appcontext_popped +from .signals import appcontext_pushed as appcontext_pushed +from .signals import appcontext_tearing_down as appcontext_tearing_down +from .signals import before_render_template as before_render_template +from .signals import got_request_exception as got_request_exception +from .signals import message_flashed as message_flashed +from .signals import request_finished as request_finished +from .signals import request_started as request_started +from .signals import request_tearing_down as request_tearing_down +from .signals import template_rendered as template_rendered +from .templating import render_template as render_template +from .templating import render_template_string as render_template_string +from .templating import stream_template as stream_template +from .templating import stream_template_string as stream_template_string +from .wrappers import Request as Request +from .wrappers import Response as Response + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Flask 3.1. Use feature detection or" + " 'importlib.metadata.version(\"flask\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("flask") + + raise AttributeError(name) diff --git a/.venv/lib/python3.12/site-packages/flask/__main__.py b/.venv/lib/python3.12/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..d164df9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..652a3ae Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000..0c220a7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000..728092b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc new file mode 100644 index 0000000..066895e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000..ceae942 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc new file mode 100644 index 0000000..66baf0e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc new file mode 100644 index 0000000..52a231f Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc new file mode 100644 index 0000000..b7e6a70 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc new file mode 100644 index 0000000..e3945b0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc new file mode 100644 index 0000000..a9429b2 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc new file mode 100644 index 0000000..a479494 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc new file mode 100644 index 0000000..558ddd9 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc new file mode 100644 index 0000000..12f8ceb Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000..a9ee3f4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc new file mode 100644 index 0000000..c64a573 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000..ed8780a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc new file mode 100644 index 0000000..de69182 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/app.py b/.venv/lib/python3.12/site-packages/flask/app.py new file mode 100644 index 0000000..7622b5e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/app.py @@ -0,0 +1,1498 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import sys +import typing as t +import weakref +from datetime import timedelta +from inspect import iscoroutinefunction +from itertools import chain +from types import TracebackType +from urllib.parse import quote as _url_quote + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import MapAdapter +from werkzeug.routing import RequestRedirect +from werkzeug.routing import RoutingException +from werkzeug.routing import Rule +from werkzeug.serving import is_running_from_reloader +from werkzeug.wrappers import Response as BaseResponse + +from . import cli +from . import typing as ft +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import send_from_directory +from .sansio.app import App +from .sansio.scaffold import _sentinel +from .sessions import SecureCookieSessionInterface +from .sessions import SessionInterface +from .signals import appcontext_tearing_down +from .signals import got_request_exception +from .signals import request_finished +from .signals import request_started +from .signals import request_tearing_down +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + + from .testing import FlaskClient + from .testing import FlaskCliRunner + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(App): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + default_config = ImmutableDict( + { + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + } + ) + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class: type[Request] = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class: type[Response] = Response + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface: SessionInterface = SecureCookieSessionInterface() + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_url_path=static_url_path, + static_folder=static_folder, + static_host=static_host, + host_matching=host_matching, + subdomain_matching=subdomain_matching, + template_folder=template_folder, + instance_path=instance_path, + instance_relative_config=instance_relative_config, + root_path=root_path, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = cli.AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert ( + bool(static_host) == host_matching + ), "Invalid static_host/host_matching combination" + # Use a weakref to avoid creating a reference cycle between the app + # and the view function (see #3761). + self_ref = weakref.ref(self) + self.add_url_rule( + f"{self.static_url_path}/", + endpoint="static", + host=static_host, + view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950 + ) + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for + reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to + :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is + supported, valid values are "r" (or "rt") and "rb". + + Note this is a duplicate of the same method in the Flask + class. + + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + return open(os.path.join(self.root_path, resource), mode) + + def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + def create_jinja_environment(self) -> Environment: + """Create the Jinja environment based on :attr:`jinja_options` + and the various Jinja-related methods of the app. Changing + :attr:`jinja_options` after this will have no effect. Also adds + Flask-related globals and filters to the environment. + + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + + if "autoescape" not in options: + options["autoescape"] = self.select_jinja_autoescape + + if "auto_reload" not in options: + auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] + + if auto_reload is None: + auto_reload = self.debug + + options["auto_reload"] = auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=self.url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g, + ) + rv.policies["json.dumps_function"] = self.json.dumps + return rv + + def create_url_adapter(self, request: Request | None) -> MapAdapter | None: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + """ + if request is not None: + # If subdomain matching is disabled (the default), use the + # default subdomain in all cases. This should be the default + # in Werkzeug but it currently does not have that feature. + if not self.subdomain_matching: + subdomain = self.url_map.default_subdomain or None + else: + subdomain = None + + return self.url_map.bind_to_environ( + request.environ, + server_name=self.config["SERVER_NAME"], + subdomain=subdomain, + ) + # We need at the very least the server name to be set for this + # to work. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def raise_routing_exception(self, request: Request) -> t.NoReturn: + """Intercept routing exceptions and possibly do something else. + + In debug mode, intercept a routing redirect and replace it with + an error if the body will be discarded. + + With modern Werkzeug this shouldn't occur, since it now uses a + 308 status which tells the browser to resend the method and + body. + + .. versionchanged:: 2.1 + Don't intercept 307 and 308 redirects. + + :meta private: + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.routing_exception.code in {307, 308} + or request.method in {"GET", "HEAD", "OPTIONS"} + ): + raise request.routing_exception # type: ignore[misc] + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def update_template_context(self, context: dict[str, t.Any]) -> None: + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + names: t.Iterable[str | None] = (None,) + + # A template may be rendered outside a request context. + if request: + names = chain(names, reversed(request.blueprints)) + + # The values passed to render_template take precedence. Keep a + # copy to re-apply after all context functions. + orig_ctx = context.copy() + + for name in names: + if name in self.template_context_processors: + for func in self.template_context_processors[name]: + context.update(self.ensure_sync(func)()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict[str, t.Any]: + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {"app": self, "g": g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + def run( + self, + host: str | None = None, + port: int | None = None, + debug: bool | None = None, + load_dotenv: bool = True, + **options: t.Any, + ) -> None: + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :doc:`/deploying/index` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Ignore this call so that it doesn't start another server if + # the 'flask run' command is used. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + if not is_running_from_reloader(): + click.secho( + " * Ignoring a call to 'app.run()' that would block" + " the current 'flask' CLI command.\n" + " Only call 'app.run()' in an 'if __name__ ==" + ' "__main__"\' guard.', + fg="red", + ) + + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, env var overrides existing value + if "FLASK_DEBUG" in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + server_name = self.config.get("SERVER_NAME") + sn_host = sn_port = None + + if server_name: + sn_host, _, sn_port = server_name.partition(":") + + if not host: + if sn_host: + host = sn_host + else: + host = "127.0.0.1" + + if port or port == 0: + port = int(port) + elif sn_port: + port = int(sn_port) + else: + port = 5000 + + options.setdefault("use_reloader", self.debug) + options.setdefault("use_debugger", self.debug) + options.setdefault("threaded", True) + + cli.show_server_banner(self.debug, self.name) + + from werkzeug.serving import run_simple + + try: + run_simple(t.cast(str, host), port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: + """Creates a test client for this application. For information + about unit testing head over to :doc:`/testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from .testing import FlaskClient as cls + return cls( # type: ignore + self, self.response_class, use_cookies=use_cookies, **kwargs + ) + + def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from .testing import FlaskCliRunner as cls + + return cls(self, **kwargs) # type: ignore + + def handle_http_exception( + self, e: HTTPException + ) -> HTTPException | ft.ResponseReturnValue: + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPException`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. + if isinstance(e, RoutingException): + return e + + handler = self._find_error_handler(e, request.blueprints) + if handler is None: + return e + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_user_exception( + self, e: Exception + ) -> HTTPException | ft.ResponseReturnValue: + """This method is called whenever an exception occurs that + should be handled. A special case is :class:`~werkzeug + .exceptions.HTTPException` which is forwarded to the + :meth:`handle_http_exception` method. This function will either + return a response value or reraise the exception with the same + traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the + bad key in debug mode rather than a generic bad request + message. + + .. versionadded:: 0.7 + """ + if isinstance(e, BadRequestKeyError) and ( + self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] + ): + e.show_exception = True + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e, request.blueprints) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_exception(self, e: Exception) -> Response: + """Handle an exception that did not have an error handler + associated with it, or that was raised from an error handler. + This always causes a 500 ``InternalServerError``. + + Always sends the :data:`got_request_exception` signal. + + If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug + mode, the error will be re-raised so that the debugger can + display it. Otherwise, the original exception is logged, and + an :exc:`~werkzeug.exceptions.InternalServerError` is returned. + + If an error handler is registered for ``InternalServerError`` or + ``500``, it will be used. For consistency, the handler will + always receive the ``InternalServerError``. The original + unhandled exception is available as ``e.original_exception``. + + .. versionchanged:: 1.1.0 + Always passes the ``InternalServerError`` instance to the + handler, setting ``original_exception`` to the unhandled + error. + + .. versionchanged:: 1.1.0 + ``after_request`` functions and other finalization is done + even for the default 500 response when there is no handler. + + .. versionadded:: 0.3 + """ + exc_info = sys.exc_info() + got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) + propagate = self.config["PROPAGATE_EXCEPTIONS"] + + if propagate is None: + propagate = self.testing or self.debug + + if propagate: + # Re-raise if called with an active exception, otherwise + # raise the passed in exception. + if exc_info[1] is e: + raise + + raise e + + self.log_exception(exc_info) + server_error: InternalServerError | ft.ResponseReturnValue + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error, request.blueprints) + + if handler is not None: + server_error = self.ensure_sync(handler)(server_error) + + return self.finalize_request(server_error, from_error_handler=True) + + def log_exception( + self, + exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), + ) -> None: + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error( + f"Exception on {request.path} [{request.method}]", exc_info=exc_info + ) + + def dispatch_request(self) -> ft.ResponseReturnValue: + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = request_ctx.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule: Rule = req.url_rule # type: ignore[assignment] + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if ( + getattr(rule, "provide_automatic_options", False) + and req.method == "OPTIONS" + ): + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] + + def full_dispatch_request(self) -> Response: + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self._got_first_request = True + + try: + request_started.send(self, _async_wrapper=self.ensure_sync) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request( + self, + rv: ft.ResponseReturnValue | HTTPException, + from_error_handler: bool = False, + ) -> Response: + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) + except Exception: + if not from_error_handler: + raise + self.logger.exception( + "Request finalizing failed with an error while handling an error" + ) + return response + + def make_default_options_response(self) -> Response: + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = request_ctx.url_adapter + methods = adapter.allowed_methods() # type: ignore[union-attr] + rv = self.response_class() + rv.allow.update(methods) + return rv + + def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Ensure that the function is synchronous for WSGI workers. + Plain ``def`` functions are returned as-is. ``async def`` + functions are wrapped to run and wait for the response. + + Override this method to change how the app runs async views. + + .. versionadded:: 2.0 + """ + if iscoroutinefunction(func): + return self.async_to_sync(func) + + return func + + def async_to_sync( + self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]] + ) -> t.Callable[..., t.Any]: + """Return a sync function that will run the coroutine function. + + .. code-block:: python + + result = app.async_to_sync(func)(*args, **kwargs) + + Override this method to change how the app converts async code + to be synchronously callable. + + .. versionadded:: 2.0 + """ + try: + from asgiref.sync import async_to_sync as asgiref_async_to_sync + except ImportError: + raise RuntimeError( + "Install Flask with the 'async' extra in order to use async views." + ) from None + + return asgiref_async_to_sync(func) + + def url_for( + self, + /, + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, + ) -> str: + """Generate a URL to the given endpoint with the given values. + + This is called by :func:`flask.url_for`, and can be called + directly as well. + + An *endpoint* is the name of a URL rule, usually added with + :meth:`@app.route() `, and usually the same name as the + view function. A route defined in a :class:`~flask.Blueprint` + will prepend the blueprint's name separated by a ``.`` to the + endpoint. + + In some cases, such as email messages, you want URLs to include + the scheme and domain, like ``https://example.com/hello``. When + not in an active request, URLs will be external by default, but + this requires setting :data:`SERVER_NAME` so Flask knows what + domain to use. :data:`APPLICATION_ROOT` and + :data:`PREFERRED_URL_SCHEME` should also be configured as + needed. This config is only used when not in an active request. + + Functions can be decorated with :meth:`url_defaults` to modify + keyword arguments before the URL is built. + + If building fails for some reason, such as an unknown endpoint + or incorrect values, the app's :meth:`handle_url_build_error` + method is called. If that returns a string, that is returned, + otherwise a :exc:`~werkzeug.routing.BuildError` is raised. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it + is external. + :param _external: If given, prefer the URL to be internal + (False) or require it to be external (True). External URLs + include the scheme and domain. When not in an active + request, URLs are external by default. + :param values: Values to use for the variable parts of the URL + rule. Unknown keys are appended as query string arguments, + like ``?a=b&c=d``. + + .. versionadded:: 2.2 + Moved from ``flask.url_for``, which calls this method. + """ + req_ctx = _cv_request.get(None) + + if req_ctx is not None: + url_adapter = req_ctx.url_adapter + blueprint_name = req_ctx.request.blueprint + + # If the endpoint starts with "." and the request matches a + # blueprint, the endpoint is relative to the blueprint. + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + # When in a request, generate a URL without scheme and + # domain by default, unless a scheme is given. + if _external is None: + _external = _scheme is not None + else: + app_ctx = _cv_app.get(None) + + # If called by helpers.url_for, an app context is active, + # use its url_adapter. Otherwise, app.url_for was called + # directly, build an adapter. + if app_ctx is not None: + url_adapter = app_ctx.url_adapter + else: + url_adapter = self.create_url_adapter(None) + + if url_adapter is None: + raise RuntimeError( + "Unable to build URLs outside an active request" + " without 'SERVER_NAME' configured. Also configure" + " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" + " needed." + ) + + # When outside a request, generate a URL with scheme and + # domain by default. + if _external is None: + _external = True + + # It is an error to set _scheme when _external=False, in order + # to avoid accidental insecure URLs. + if _scheme is not None and not _external: + raise ValueError("When specifying '_scheme', '_external' must be True.") + + self.inject_url_defaults(endpoint, values) + + try: + rv = url_adapter.build( # type: ignore[union-attr] + endpoint, + values, + method=_method, + url_scheme=_scheme, + force_external=_external, + ) + except BuildError as error: + values.update( + _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external + ) + return self.handle_url_build_error(error, endpoint, values) + + if _anchor is not None: + _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") + rv = f"{rv}#{_anchor}" + + return rv + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status = headers = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, # type: ignore[arg-type] + request.environ, + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) # type: ignore[arg-type] + + return rv + + def preprocess_request(self) -> ft.ResponseReturnValue | None: + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + names = (None, *reversed(request.blueprints)) + + for name in names: + if name in self.url_value_preprocessors: + for url_func in self.url_value_preprocessors[name]: + url_func(request.endpoint, request.view_args) + + for name in names: + if name in self.before_request_funcs: + for before_func in self.before_request_funcs[name]: + rv = self.ensure_sync(before_func)() + + if rv is not None: + return rv # type: ignore[no-any-return] + + return None + + def process_response(self, response: Response) -> Response: + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = request_ctx._get_current_object() # type: ignore[attr-defined] + + for func in ctx._after_request_functions: + response = self.ensure_sync(func)(response) + + for name in chain(request.blueprints, (None,)): + if name in self.after_request_funcs: + for func in reversed(self.after_request_funcs[name]): + response = self.ensure_sync(func)(response) + + if not self.session_interface.is_null_session(ctx.session): + self.session_interface.save_session(self, ctx.session, response) + + return response + + def do_teardown_request( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for name in chain(request.blueprints, (None,)): + if name in self.teardown_request_funcs: + for func in reversed(self.teardown_request_funcs[name]): + self.ensure_sync(func)(exc) + + request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def do_teardown_appcontext( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for func in reversed(self.teardown_appcontext_funcs): + self.ensure_sync(func)(exc) + + appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def app_context(self) -> AppContext: + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ: WSGIEnvironment) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` representing a + WSGI environment. Use a ``with`` block to push the context, + which will make :data:`request` point at this request. + + See :doc:`/reqcontext`. + + Typically you should not call this from your own code. A request + context is automatically pushed by the :meth:`wsgi_app` when + handling a request. Use :meth:`test_request_context` to create + an environment and context instead of this method. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` for a WSGI + environment created from the given values. This is mostly useful + during testing, where you may want to run a function that uses + request data without dispatching a full request. + + See :doc:`/reqcontext`. + + Use a ``with`` block to push the context, which will make + :data:`request` point at the request for the created + environment. :: + + with app.test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from .testing import EnvironBuilder + + builder = EnvironBuilder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The actual WSGI application. This is not implemented in + :meth:`__call__` so that middlewares can be applied without + losing a reference to the app object. Instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + Teardown events for the request and app contexts are called + even if an unhandled error occurs. Other events may not be + called depending on when an error occurs during dispatch. + See :ref:`callbacks-and-errors`. + + :param environ: A WSGI environment. + :param start_response: A callable accepting a status code, + a list of headers, and an optional exception context to + start the response. + """ + ctx = self.request_context(environ) + error: BaseException | None = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: # noqa: B001 + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if "werkzeug.debug.preserve_context" in environ: + environ["werkzeug.debug.preserve_context"](_cv_app.get()) + environ["werkzeug.debug.preserve_context"](_cv_request.get()) + + if error is not None and self.should_ignore_error(error): + error = None + + ctx.pop(error) + + def __call__( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The WSGI server calls the Flask application object as the + WSGI application. This calls :meth:`wsgi_app`, which can be + wrapped to apply middleware. + """ + return self.wsgi_app(environ, start_response) diff --git a/.venv/lib/python3.12/site-packages/flask/blueprints.py b/.venv/lib/python3.12/site-packages/flask/blueprints.py new file mode 100644 index 0000000..aa9eacf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/blueprints.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +import os +import typing as t +from datetime import timedelta + +from .cli import AppGroup +from .globals import current_app +from .helpers import send_from_directory +from .sansio.blueprints import Blueprint as SansioBlueprint +from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa +from .sansio.scaffold import _sentinel + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +class Blueprint(SansioBlueprint): + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore + ) -> None: + super().__init__( + name, + import_name, + static_folder, + static_url_path, + template_folder, + url_prefix, + subdomain, + url_defaults, + root_path, + cli_group, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for + reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to + :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is + supported, valid values are "r" (or "rt") and "rb". + + Note this is a duplicate of the same method in the Flask + class. + + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + return open(os.path.join(self.root_path, resource), mode) diff --git a/.venv/lib/python3.12/site-packages/flask/cli.py b/.venv/lib/python3.12/site-packages/flask/cli.py new file mode 100644 index 0000000..ecb292a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/cli.py @@ -0,0 +1,1109 @@ +from __future__ import annotations + +import ast +import collections.abc as cabc +import importlib.metadata +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import itemgetter +from types import ModuleType + +import click +from click.core import ParameterSource +from werkzeug import run_simple +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_load_dotenv + +if t.TYPE_CHECKING: + import ssl + + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module: ModuleType) -> Flask: + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ("app", "application"): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + "Detected multiple Flask applications in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify the correct one." + ) + + # Search for app factory functions. + for attr_name in ("create_app", "make_app"): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = app_factory() + + if isinstance(app, Flask): + return app + except TypeError as e: + if not _called_with_wrong_args(app_factory): + raise + + raise NoAppException( + f"Detected factory '{attr_name}' in module '{module.__name__}'," + " but could not call it without arguments. Use" + f" '{module.__name__}:{attr_name}(args)'" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify one." + ) + + +def _called_with_wrong_args(f: t.Callable[..., Flask]) -> bool: + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param f: The function that was called. + :return: ``True`` if the call failed. + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is f.__code__: + # In the function, it was called successfully. + return False + + tb = tb.tb_next + + # Didn't reach the function. + return True + finally: + # Delete tb to break a circular reference. + # https://docs.python.org/2/library/sys.html#sys.exc_info + del tb + + +def find_app_by_string(module: ModuleType, app_name: str) -> Flask: + """Check if the given string is a variable name or a function. Call + a function to get the app instance, or return the variable directly. + """ + from . import Flask + + # Parse app_name as a single expression to determine if it's a valid + # attribute name or function call. + try: + expr = ast.parse(app_name.strip(), mode="eval").body + except SyntaxError: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) from None + + if isinstance(expr, ast.Name): + name = expr.id + args = [] + kwargs = {} + elif isinstance(expr, ast.Call): + # Ensure the function name is an attribute name only. + if not isinstance(expr.func, ast.Name): + raise NoAppException( + f"Function reference must be a simple name: {app_name!r}." + ) + + name = expr.func.id + + # Parse the positional and keyword arguments as literals. + try: + args = [ast.literal_eval(arg) for arg in expr.args] + kwargs = { + kw.arg: ast.literal_eval(kw.value) + for kw in expr.keywords + if kw.arg is not None + } + except ValueError: + # literal_eval gives cryptic error messages, show a generic + # message with the full expression instead. + raise NoAppException( + f"Failed to parse arguments as literal values: {app_name!r}." + ) from None + else: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException( + f"Failed to find attribute {name!r} in {module.__name__!r}." + ) from e + + # If the attribute is a function, call it with any args and kwargs + # to get the real application. + if inspect.isfunction(attr): + try: + app = attr(*args, **kwargs) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + f"The factory {app_name!r} in module" + f" {module.__name__!r} could not be called with the" + " specified arguments." + ) from e + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + "A valid Flask application was not obtained from" + f" '{module.__name__}:{app_name}'." + ) + + +def prepare_import(path: str) -> str: + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + fname, ext = os.path.splitext(path) + if ext == ".py": + path = fname + + if os.path.basename(path) == "__init__": + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, "__init__.py")): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return ".".join(module_name[::-1]) + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True +) -> Flask: ... + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ... +) -> Flask | None: ... + + +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: bool = True +) -> Flask | None: + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[2].tb_next: # type: ignore[union-attr] + raise NoAppException( + f"While importing {module_name!r}, an ImportError was" + f" raised:\n\n{traceback.format_exc()}" + ) from None + elif raise_if_not_found: + raise NoAppException(f"Could not import {module_name!r}.") from None + else: + return None + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(module) + else: + return find_app_by_string(module, app_name) + + +def get_version(ctx: click.Context, param: click.Parameter, value: t.Any) -> None: + if not value or ctx.resilient_parsing: + return + + flask_version = importlib.metadata.version("flask") + werkzeug_version = importlib.metadata.version("werkzeug") + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {flask_version}\n" + f"Werkzeug {werkzeug_version}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + + if self.create_app is not None: + app: Flask | None = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, maxsplit=1) + [None] + )[:2] + import_name = prepare_import(path) + app = locate_app(import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(import_name, None, raise_if_not_found=False) + + if app is not None: + break + + if app is None: + raise NoAppException( + "Could not locate a Flask application. Use the" + " 'flask --app' option, 'FLASK_APP' environment" + " variable, or a 'wsgi.py' or 'app.py' file in the" + " current directory." + ) + + if self.set_debug_flag: + # Update the app's debug flag through the descriptor so that + # other values repopulate as well. + app.debug = get_debug_flag() + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def with_appcontext(f: F) -> F: + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. + + Custom commands (and their options) registered under ``app.cli`` or + ``blueprint.cli`` will always have an app context available, this + decorator is not required in that case. + + .. versionchanged:: 2.2 + The app context is active for subcommands as well as the + decorated callback. The app context is always available to + ``app.cli`` command and parameter callbacks. + """ + + @click.pass_context + def decorator(ctx: click.Context, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + if not current_app: + app = ctx.ensure_object(ScriptInfo).load_app() + ctx.with_resource(app.app_context()) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper(decorator, f) # type: ignore[return-value] + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Command]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop("with_appcontext", True) + + def decorator(f: t.Callable[..., t.Any]) -> click.Command: + if wrap_for_ctx: + f = with_appcontext(f) + return super(AppGroup, self).command(*args, **kwargs)(f) # type: ignore[no-any-return] + + return decorator + + def group( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Group]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault("cls", AppGroup) + return super().group(*args, **kwargs) # type: ignore[no-any-return] + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + if value is None: + return None + + import importlib + + try: + importlib.import_module("dotenv") + except ImportError: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Don't check FLASK_SKIP_DOTENV, that only disables automatically + # loading .env and .flaskenv files. + load_dotenv(value) + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help="Load environment variables from this file. python-dotenv must be installed.", + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self) -> None: + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx: click.Context, name: str) -> click.Command | None: + self._load_plugin_commands() + # Look up built-in and plugin commands, which should be + # available even if the app fails to load. + rv = super().get_command(ctx, name) + + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + + # Look up commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + app = info.load_app() + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + return None + + # Push an app context for the loaded app unless it is already + # active somehow. This makes the context available to parameter + # and command callbacks without needing @with_appcontext. + if not current_app or current_app._get_current_object() is not app: # type: ignore[attr-defined] + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx: click.Context) -> list[str]: + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + # Attempt to load .env and .flask env files. The --env-file + # option can cause another file to be loaded. + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, set_debug_flag=self.set_debug_flag + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help: + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path: str, other: str) -> bool: + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other + + +def load_dotenv(path: str | os.PathLike[str] | None = None) -> bool: + """Load "dotenv" files in order of precedence to set environment variables. + + If an env var is already set it is not overwritten, so earlier files in the + list are preferred over later files. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location instead of searching. + :return: ``True`` if a file was loaded. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env or .flaskenv files present." + ' Do "pip install python-dotenv" to use them.', + fg="yellow", + err=True, + ) + + return False + + # Always return after attempting to load a given path, don't load + # the default files. + if path is not None: + if os.path.isfile(path): + return dotenv.load_dotenv(path, encoding="utf-8") + + return False + + loaded = False + + for name in (".env", ".flaskenv"): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + dotenv.load_dotenv(path, encoding="utf-8") + loaded = True + + return loaded # True if at least one file was located and loaded. + + +def show_server_banner(debug: bool, app_import_path: str | None) -> None: + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if is_running_from_reloader(): + return + + if app_import_path is not None: + click.echo(f" * Serving Flask app '{app_import_path}'") + + if debug is not None: + click.echo(f" * Debug mode: {'on' if debug else 'off'}") + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = "path" + + def __init__(self) -> None: + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + try: + import ssl + except ImportError: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) from None + + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == "adhoc": + try: + import cryptography # noqa: F401 + except ImportError: + raise click.BadParameter( + "Using ad-hoc certificates requires the cryptography library.", + ctx, + param, + ) from None + + return value + + obj = import_string(value, silent=True) + + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any: + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get("cert") + is_adhoc = cert == "adhoc" + + try: + import ssl + except ImportError: + is_context = False + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', ctx, param + ) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key" is not used.', + ctx, + param, + ) + + if not cert: + raise click.BadParameter('"--cert" must also be specified.', ctx, param) + + ctx.params["cert"] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter('Required when using "--cert".', ctx, param) + + return value + + +class SeparatedPathType(click.Path): + """Click option type that accepts a list of values separated by the + OS's path separator (``:``, ``;`` on Windows). Each value is + validated as a :class:`click.Path` type. + """ + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + items = self.split_envvar_value(value) + # can't call no-arg super() inside list comprehension until Python 3.12 + super_convert = super().convert + return [super_convert(item, param, ctx) for item in items] + + +@click.command("run", short_help="Run a development server.") +@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") +@click.option("--port", "-p", default=5000, help="The port to bind to.") +@click.option( + "--cert", + type=CertParamType(), + help="Specify a certificate file to use HTTPS.", + is_eager=True, +) +@click.option( + "--key", + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, + expose_value=False, + help="The key file to use when specifying a certificate.", +) +@click.option( + "--reload/--no-reload", + default=None, + help="Enable or disable the reloader. By default the reloader " + "is active if debug is enabled.", +) +@click.option( + "--debugger/--no-debugger", + default=None, + help="Enable or disable the debugger. By default the debugger " + "is active if debug is enabled.", +) +@click.option( + "--with-threads/--without-threads", + default=True, + help="Enable or disable multithreading.", +) +@click.option( + "--extra-files", + default=None, + type=SeparatedPathType(), + help=( + "Extra files that trigger a reload on change. Multiple paths" + f" are separated by {os.path.pathsep!r}." + ), +) +@click.option( + "--exclude-patterns", + default=None, + type=SeparatedPathType(), + help=( + "Files matching these fnmatch patterns will not trigger a reload" + " on change. Multiple patterns are separated by" + f" {os.path.pathsep!r}." + ), +) +@pass_script_info +def run_command( + info: ScriptInfo, + host: str, + port: int, + reload: bool, + debugger: bool, + with_threads: bool, + cert: ssl.SSLContext | tuple[str, str | None] | t.Literal["adhoc"] | None, + extra_files: list[str] | None, + exclude_patterns: list[str] | None, +) -> None: + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default with the '--debug' + option. + """ + try: + app: WSGIApplication = info.load_app() + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app( + environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict[str, t.Any] = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/.venv/lib/python3.12/site-packages/flask/config.py b/.venv/lib/python3.12/site-packages/flask/config.py new file mode 100644 index 0000000..7e3ba17 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/config.py @@ -0,0 +1,370 @@ +from __future__ import annotations + +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .sansio.app import App + + +T = t.TypeVar("T") + + +class ConfigAttribute(t.Generic[T]): + """Makes an attribute forward to the config""" + + def __init__( + self, name: str, get_converter: t.Callable[[t.Any], T] | None = None + ) -> None: + self.__name__ = name + self.get_converter = get_converter + + @t.overload + def __get__(self, obj: None, owner: None) -> te.Self: ... + + @t.overload + def __get__(self, obj: App, owner: type[App]) -> T: ... + + def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self: + if obj is None: + return self + + rv = obj.config[self.__name__] + + if self.get_converter is not None: + rv = self.get_converter(rv) + + return rv # type: ignore[no-any-return] + + def __set__(self, obj: App, value: t.Any) -> None: + obj.config[self.__name__] = value + + +class Config(dict): # type: ignore[type-arg] + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__( + self, + root_path: str | os.PathLike[str], + defaults: dict[str, t.Any] | None = None, + ) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + len_prefix = len(prefix) + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + # Change to key.removeprefix(prefix) on Python >= 3.9. + key = key[len_prefix:] + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile( + self, filename: str | os.PathLike[str], silent: bool = False + ) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str | os.PathLike[str], + load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/.venv/lib/python3.12/site-packages/flask/ctx.py b/.venv/lib/python3.12/site-packages/flask/ctx.py new file mode 100644 index 0000000..9b164d3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/ctx.py @@ -0,0 +1,449 @@ +from __future__ import annotations + +import contextvars +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from . import typing as ft +from .globals import _cv_app +from .globals import _cv_request +from .signals import appcontext_popped +from .signals import appcontext_pushed + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + from .sessions import SessionMixin + from .wrappers import Request + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals: + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + # Define attr methods to let mypy know this is a namespace object + # that has arbitrary attributes. + + def __getattr__(self, name: str) -> t.Any: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def __setattr__(self, name: str, value: t.Any) -> None: + self.__dict__[name] = value + + def __delattr__(self, name: str) -> None: + try: + del self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def get(self, name: str, default: t.Any | None = None) -> t.Any: + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raising a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name: str, default: t.Any = None) -> t.Any: + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item: str) -> bool: + return item in self.__dict__ + + def __iter__(self) -> t.Iterator[str]: + return iter(self.__dict__) + + def __repr__(self) -> str: + ctx = _cv_app.get(None) + if ctx is not None: + return f"" + return object.__repr__(self) + + +def after_this_request( + f: ft.AfterRequestCallable[t.Any], +) -> ft.AfterRequestCallable[t.Any]: + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'after_this_request' can only be used when a request" + " context is active, such as in a view function." + ) + + ctx._after_request_functions.append(f) + return f + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def copy_current_request_context(f: F) -> F: + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. The current session is also + included in the copied request context. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request or + # flask.session like you would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'copy_current_request_context' can only be used when a" + " request context is active, such as in a view function." + ) + + ctx = ctx.copy() + + def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any: + with ctx: # type: ignore[union-attr] + return ctx.app.ensure_sync(f)(*args, **kwargs) # type: ignore[union-attr] + + return update_wrapper(wrapper, f) # type: ignore[return-value] + + +def has_request_context() -> bool: + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g`) for truthness:: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _cv_request.get(None) is not None + + +def has_app_context() -> bool: + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _cv_app.get(None) is not None + + +class AppContext: + """The app context contains application-specific information. An app + context is created and pushed at the beginning of each request if + one is not already active. An app context is also pushed when + running CLI commands. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g: _AppCtxGlobals = app.app_ctx_globals_class() + self._cv_tokens: list[contextvars.Token[AppContext]] = [] + + def push(self) -> None: + """Binds the app context to the current context.""" + self._cv_tokens.append(_cv_app.set(self)) + appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + if len(self._cv_tokens) == 1: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + ctx = _cv_app.get() + _cv_app.reset(self._cv_tokens.pop()) + + if ctx is not self: + raise AssertionError( + f"Popped wrong app context. ({ctx!r} instead of {self!r})" + ) + + appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) + + def __enter__(self) -> AppContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains per-request information. The Flask + app creates and pushes it at the beginning of the request, then pops + it at the end of the request. It will create the URL adapter and + request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the + request. When using the interactive debugger, the context will be + restored so ``request`` is still accessible. Similarly, the test + client can preserve the context after the request ends. However, + teardown functions may already have closed some resources such as + database connections. + """ + + def __init__( + self, + app: Flask, + environ: WSGIEnvironment, + request: Request | None = None, + session: SessionMixin | None = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json + self.request: Request = request + self.url_adapter = None + try: + self.url_adapter = app.create_url_adapter(self.request) + except HTTPException as e: + self.request.routing_exception = e + self.flashes: list[tuple[str, str]] | None = None + self.session: SessionMixin | None = session + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = [] + + self._cv_tokens: list[ + tuple[contextvars.Token[RequestContext], AppContext | None] + ] = [] + + def copy(self) -> RequestContext: + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + + .. versionchanged:: 1.1 + The current session object is used instead of reloading the original + data. This prevents `flask.session` pointing to an out-of-date object. + """ + return self.__class__( + self.app, + environ=self.request.environ, + request=self.request, + session=self.session, + ) + + def match_request(self) -> None: + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + result = self.url_adapter.match(return_rule=True) # type: ignore + self.request.url_rule, self.request.view_args = result # type: ignore + except HTTPException as e: + self.request.routing_exception = e + + def push(self) -> None: + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _cv_app.get(None) + + if app_ctx is None or app_ctx.app is not self.app: + app_ctx = self.app.app_context() + app_ctx.push() + else: + app_ctx = None + + self._cv_tokens.append((_cv_request.set(self), app_ctx)) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self.session is None: + session_interface = self.app.session_interface + self.session = session_interface.open_session(self.app, self.request) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) + + # Match the request URL after loading the session, so that the + # session is available in custom URL converters. + if self.url_adapter is not None: + self.match_request() + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + clear_request = len(self._cv_tokens) == 1 + + try: + if clear_request: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + request_close = getattr(self.request, "close", None) + if request_close is not None: + request_close() + finally: + ctx = _cv_request.get() + token, app_ctx = self._cv_tokens.pop() + _cv_request.reset(token) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + ctx.request.environ["werkzeug.request"] = None + + if app_ctx is not None: + app_ctx.pop(exc) + + if ctx is not self: + raise AssertionError( + f"Popped wrong request context. ({ctx!r} instead of {self!r})" + ) + + def __enter__(self) -> RequestContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + def __repr__(self) -> str: + return ( + f"<{type(self).__name__} {self.request.url!r}" + f" [{self.request.method}] of {self.app.name}>" + ) diff --git a/.venv/lib/python3.12/site-packages/flask/debughelpers.py b/.venv/lib/python3.12/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..2c8c4c4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/debughelpers.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import typing as t + +from jinja2.loaders import BaseLoader +from werkzeug.routing import RequestRedirect + +from .blueprints import Blueprint +from .globals import request_ctx +from .sansio.app import App + +if t.TYPE_CHECKING: + from .sansio.scaffold import Scaffold + from .wrappers import Request + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request: Request, key: str) -> None: + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self) -> str: + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request: Request) -> None: + exc = request.routing_exception + assert isinstance(exc, RequestRedirect) + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request: Request) -> None: + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): # type: ignore[valid-type, misc] + def __getitem__(self, key: str) -> t.Any: + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts( + app: App, + template: str, + attempts: list[ + tuple[ + BaseLoader, + Scaffold, + tuple[str, str | None, t.Callable[[], bool] | None] | None, + ] + ], +) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, App): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/.venv/lib/python3.12/site-packages/flask/globals.py b/.venv/lib/python3.12/site-packages/flask/globals.py new file mode 100644 index 0000000..e2c410c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/globals.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) diff --git a/.venv/lib/python3.12/site-packages/flask/helpers.py b/.venv/lib/python3.12/site-packages/flask/helpers.py new file mode 100644 index 0000000..359a842 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,621 @@ +from __future__ import annotations + +import importlib.util +import os +import sys +import typing as t +from datetime import datetime +from functools import lru_cache +from functools import update_wrapper + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .globals import request_ctx +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +def get_debug_flag() -> bool: + """Get whether debug mode should be enabled for the app, indicated by the + :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. + """ + val = os.environ.get("FLASK_DEBUG") + return bool(val and val.lower() not in {"0", "false", "no"}) + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Iterator[t.AnyStr]: + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) # type: ignore[arg-type] + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore[operator] + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore[arg-type] + + def generator() -> t.Iterator[t.AnyStr | None]: + ctx = _cv_request.get(None) + if ctx is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + yield from gen + finally: + if hasattr(gen, "close"): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g # type: ignore[return-value] + + +def make_response(*args: t.Any) -> Response: + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for( + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, +) -> str: + """Generate a URL to the given endpoint with the given values. + + This requires an active request or application context, and calls + :meth:`current_app.url_for() `. See that method + for full documentation. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it is + external. + :param _external: If given, prefer the URL to be internal (False) or + require it to be external (True). External URLs include the + scheme and domain. When not in an active request, URLs are + external by default. + :param values: Values to use for the variable parts of the URL rule. + Unknown keys are appended as query string arguments, like + ``?a=b&c=d``. + + .. versionchanged:: 2.2 + Calls ``current_app.url_for``, allowing an app to override the + behavior. + + .. versionchanged:: 0.10 + The ``_scheme`` parameter was added. + + .. versionchanged:: 0.9 + The ``_anchor`` and ``_method`` parameters were added. + + .. versionchanged:: 0.9 + Calls ``app.handle_url_build_error`` on build errors. + """ + return current_app.url_for( + endpoint, + _anchor=_anchor, + _method=_method, + _scheme=_scheme, + _external=_external, + **values, + ) + + +def redirect( + location: str, code: int = 302, Response: type[BaseResponse] | None = None +) -> BaseResponse: + """Create a redirect response object. + + If :data:`~flask.current_app` is available, it will use its + :meth:`~flask.Flask.redirect` method, otherwise it will use + :func:`werkzeug.utils.redirect`. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + :param Response: The response class to use. Not used when + ``current_app`` is active, which uses ``app.response_class``. + + .. versionadded:: 2.2 + Calls ``current_app.redirect`` if available instead of always + using Werkzeug's default ``redirect``. + """ + if current_app: + return current_app.redirect(location, code=code) + + return _wz_redirect(location, code=code, Response=Response) + + +def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given + status code. + + If :data:`~flask.current_app` is available, it will call its + :attr:`~flask.Flask.aborter` object, otherwise it will use + :func:`werkzeug.exceptions.abort`. + + :param code: The status code for the exception, which must be + registered in ``app.aborter``. + :param args: Passed to the exception. + :param kwargs: Passed to the exception. + + .. versionadded:: 2.2 + Calls ``current_app.aborter`` if available instead of always + using Werkzeug's default ``abort``. + """ + if current_app: + current_app.aborter(code, *args, **kwargs) + + _wz_abort(code, *args, **kwargs) + + +def get_template_attribute(template_name: str, attribute: str) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, attribute) + + +def flash(message: str, category: str = "message") -> None: + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get("_flashes", []) + flashes.append((category, message)) + session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore + message_flashed.send( + app, + _async_wrapper=app.ensure_sync, + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> list[str] | list[tuple[str, str]]: + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :doc:`/patterns/flashing` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: filter of categories to limit return values. Only + categories in the list will be returned. + """ + flashes = request_ctx.flashes + if flashes is None: + flashes = session.pop("_flashes") if "_flashes" in session else [] + request_ctx.flashes = flashes + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: + if kwargs.get("max_age") is None: + kwargs["max_age"] = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + use_x_sendfile=current_app.config["USE_X_SENDFILE"], + response_class=current_app.response_class, + _root_path=current_app.root_path, # type: ignore + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike[t.AnyStr] | str | t.BinaryIO, + mimetype: str | None = None, + as_attachment: bool = False, + download_name: str | None = None, + conditional: bool = True, + etag: bool | str = True, + last_modified: datetime | int | float | None = None, + max_age: None | (int | t.Callable[[str | None], int | None]) = None, +) -> Response: + """Send the contents of a file to the client. + + The first argument can be a file path or a file-like object. Paths + are preferred in most cases because Werkzeug can manage the file and + get extra information from the path. Passing a file-like object + requires that the file is opened in binary mode, and is mostly + useful when building a file in memory with :class:`io.BytesIO`. + + Never pass file paths provided by a user. The path is assumed to be + trusted, so a user could craft a path to access a file you didn't + intend. Use :func:`send_from_directory` to safely serve + user-requested paths from within a directory. + + If the WSGI server sets a ``file_wrapper`` in ``environ``, it is + used, otherwise Werkzeug's built-in wrapper is used. Alternatively, + if the HTTP server supports ``X-Sendfile``, configuring Flask with + ``USE_X_SENDFILE = True`` will tell the server to send the given + path, which is much more efficient than reading it in Python. + + :param path_or_file: The path to the file to send, relative to the + current working directory if a relative path is given. + Alternatively, a file-like object opened in binary mode. Make + sure the file pointer is seeked to the start of the data. + :param mimetype: The MIME type to send for the file. If not + provided, it will try to detect it from the file name. + :param as_attachment: Indicate to a browser that it should offer to + save the file instead of displaying it. + :param download_name: The default name browsers will use when saving + the file. Defaults to the passed file name. + :param conditional: Enable conditional and range responses based on + request headers. Requires passing a file path and ``environ``. + :param etag: Calculate an ETag for the file, which requires passing + a file path. Can also be a string to use instead. + :param last_modified: The last modified time to send for the file, + in seconds. If not provided, it will try to detect it from the + file path. + :param max_age: How long the client should cache the file, in + seconds. If set, ``Cache-Control`` will be ``public``, otherwise + it will be ``no-cache`` to prefer conditional caching. + + .. versionchanged:: 2.0 + ``download_name`` replaces the ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces the ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces the ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + Passing a file-like object that inherits from + :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather + than sending an empty file. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionchanged:: 1.1 + ``filename`` may be a :class:`~os.PathLike` object. + + .. versionchanged:: 1.1 + Passing a :class:`~io.BytesIO` object supports range requests. + + .. versionchanged:: 1.0.3 + Filenames are encoded with ASCII instead of Latin-1 for broader + compatibility with WSGI servers. + + .. versionchanged:: 1.0 + UTF-8 filenames as specified in :rfc:`2231` are supported. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file + objects. If you want to use automatic MIME and etag support, + pass a filename via ``filename_or_fp`` or + ``attachment_filename``. + + .. versionchanged:: 0.12 + ``attachment_filename`` is preferred over ``filename`` for MIME + detection. + + .. versionchanged:: 0.9 + ``cache_timeout`` defaults to + :meth:`Flask.get_send_file_max_age`. + + .. versionchanged:: 0.7 + MIME guessing and etag support for file-like objects was + removed because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. + + .. versionchanged:: 0.5 + The ``add_etags``, ``cache_timeout`` and ``conditional`` + parameters were added. The default behavior is to add etags. + + .. versionadded:: 0.2 + """ + return werkzeug.utils.send_file( # type: ignore[return-value] + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + conditional=conditional, + etag=etag, + last_modified=last_modified, + max_age=max_age, + ) + ) + + +def send_from_directory( + directory: os.PathLike[str] | str, + path: os.PathLike[str] | str, + **kwargs: t.Any, +) -> Response: + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + try: + spec = importlib.util.find_spec(import_name) + + if spec is None: + raise ValueError + except (ImportError, ValueError): + loader = None + else: + loader = spec.loader + + # Loader does not exist or we're referring to an unloaded main + # module or a main module without path (interactive sessions), go + # with the current working directory. + if loader is None: + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, "__file__", None) + + # If we don't have a file path it might be because it is a + # namespace package. In this case pick the root path from the + # first module that is contained in the package. + if filepath is None: + raise RuntimeError( + "No root path can be found for the provided module" + f" {import_name!r}. This can happen because the module" + " came from an import hook that does not provide file" + " name information or because it's a namespace package." + " In this case the root path needs to be explicitly" + " provided." + ) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] + + +@lru_cache(maxsize=None) +def _split_blueprint_path(name: str) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/.venv/lib/python3.12/site-packages/flask/json/__init__.py b/.venv/lib/python3.12/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..c0941d0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/.venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..292f9b6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc new file mode 100644 index 0000000..f338a62 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc new file mode 100644 index 0000000..bd22ca0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/json/provider.py b/.venv/lib/python3.12/site-packages/flask/json/provider.py new file mode 100644 index 0000000..f9b2e8f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/json/provider.py @@ -0,0 +1,215 @@ +from __future__ import annotations + +import dataclasses +import decimal +import json +import typing as t +import uuid +import weakref +from datetime import date + +from werkzeug.http import http_date + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.sansio.response import Response + + from ..sansio.app import App + + +class JSONProvider: + """A standard set of JSON operations for an application. Subclasses + of this can be used to customize JSON behavior or use different + JSON libraries. + + To implement a provider for a specific library, subclass this base + class and implement at least :meth:`dumps` and :meth:`loads`. All + other methods have default implementations. + + To use a different provider, either subclass ``Flask`` and set + :attr:`~flask.Flask.json_provider_class` to a provider class, or set + :attr:`app.json ` to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: App) -> None: + self._app: App = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/.venv/lib/python3.12/site-packages/flask/json/tag.py b/.venv/lib/python3.12/site-packages/flask/json/tag.py new file mode 100644 index 0000000..8dc3629 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/json/tag.py @@ -0,0 +1,327 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" + +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If empty, this tag is + #: only used as an intermediate step during tagging. + key: str = "" + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> t.Any: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def _untag_scan(self, value: t.Any) -> t.Any: + if isinstance(value, dict): + # untag each item recursively + value = {k: self._untag_scan(v) for k, v in value.items()} + # untag the dict itself + value = self.untag(value) + elif isinstance(value, list): + # untag each item recursively + value = [self._untag_scan(item) for item in value] + + return value + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return self._untag_scan(loads(value)) diff --git a/.venv/lib/python3.12/site-packages/flask/logging.py b/.venv/lib/python3.12/site-packages/flask/logging.py new file mode 100644 index 0000000..0cb8f43 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/logging.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .sansio.app import App + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + if request: + return request.environ["wsgi.errors"] # type: ignore[no-any-return] + + return sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: App) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/.venv/lib/python3.12/site-packages/flask/py.typed b/.venv/lib/python3.12/site-packages/flask/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/README.md b/.venv/lib/python3.12/site-packages/flask/sansio/README.md new file mode 100644 index 0000000..623ac19 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/sansio/README.md @@ -0,0 +1,6 @@ +# Sansio + +This folder contains code that can be used by alternative Flask +implementations, for example Quart. The code therefore cannot do any +IO, nor be part of a likely IO path. Finally this code cannot use the +Flask globals. diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000..218b91e Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000..024f7e7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc new file mode 100644 index 0000000..cbdd738 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/app.py b/.venv/lib/python3.12/site-packages/flask/sansio/app.py new file mode 100644 index 0000000..01fd5db --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/sansio/app.py @@ -0,0 +1,964 @@ +from __future__ import annotations + +import logging +import os +import sys +import typing as t +from datetime import timedelta +from itertools import chain + +from werkzeug.exceptions import Aborter +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.routing import BuildError +from werkzeug.routing import Map +from werkzeug.routing import Rule +from werkzeug.sansio.response import Response +from werkzeug.utils import cached_property +from werkzeug.utils import redirect as _wz_redirect + +from .. import typing as ft +from ..config import Config +from ..config import ConfigAttribute +from ..ctx import _AppCtxGlobals +from ..helpers import _split_blueprint_path +from ..helpers import get_debug_flag +from ..json.provider import DefaultJSONProvider +from ..json.provider import JSONProvider +from ..logging import create_logger +from ..templating import DispatchingJinjaLoader +from ..templating import Environment +from .scaffold import _endpoint_from_view_func +from .scaffold import find_package +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.wrappers import Response as BaseResponse + + from ..testing import FlaskClient + from ..testing import FlaskCliRunner + from .blueprints import Blueprint + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class App(Scaffold): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + #: The class of the object assigned to :attr:`aborter`, created by + #: :meth:`create_aborter`. That object is called by + #: :func:`flask.abort` to raise HTTP errors, and can be + #: called directly as well. + #: + #: Defaults to :class:`werkzeug.exceptions.Aborter`. + #: + #: .. versionadded:: 2.2 + aborter_class = Aborter + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate test helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute[bool]("TESTING") + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute[t.Union[str, bytes, None]]("SECRET_KEY") + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute[timedelta]( + "PERMANENT_SESSION_LIFETIME", + get_converter=_make_timedelta, # type: ignore[arg-type] + ) + + json_provider_class: type[JSONProvider] = DefaultJSONProvider + """A subclass of :class:`~flask.json.provider.JSONProvider`. An + instance is created and assigned to :attr:`app.json` when creating + the app. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses + Python's built-in :mod:`json` library. A different provider can use + a different JSON library. + + .. versionadded:: 2.2 + """ + + #: Options that are passed to the Jinja environment in + #: :meth:`create_jinja_environment`. Changing these options after + #: the environment is created (accessing :attr:`jinja_env`) will + #: have no effect. + #: + #: .. versionchanged:: 1.1.0 + #: This is a ``dict`` instead of an ``ImmutableDict`` to allow + #: easier configuration. + #: + jinja_options: dict[str, t.Any] = {} + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: The map object to use for storing the URL rules and routing + #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. + #: + #: .. versionadded:: 1.1.0 + url_map_class = Map + + #: The :meth:`test_client` method creates an instance of this test + #: client class. Defaults to :class:`~flask.testing.FlaskClient`. + #: + #: .. versionadded:: 0.7 + test_client_class: type[FlaskClient] | None = None + + #: The :class:`~click.testing.CliRunner` subclass, by default + #: :class:`~flask.testing.FlaskCliRunner` that is used by + #: :meth:`test_cli_runner`. Its ``__init__`` method should take a + #: Flask app object as the first argument. + #: + #: .. versionadded:: 1.0 + test_cli_runner_class: type[FlaskCliRunner] | None = None + + default_config: dict[str, t.Any] + response_class: type[Response] + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + "If an instance path is provided it must be absolute." + " A relative path was given instead." + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: An instance of :attr:`aborter_class` created by + #: :meth:`make_aborter`. This is called by :func:`flask.abort` + #: to raise HTTP errors, and can be called directly as well. + #: + #: .. versionadded:: 2.2 + #: Moved from ``flask.abort``, which calls this object. + self.aborter = self.make_aborter() + + self.json: JSONProvider = self.json_provider_class(self) + """Provides access to JSON methods. Functions in ``flask.json`` + will call methods on this provider when the application context + is active. Used for handling JSON requests and responses. + + An instance of :attr:`json_provider_class`. Can be customized by + changing that attribute on a subclass, or by assigning to this + attribute afterwards. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, + uses Python's built-in :mod:`json` library. A different provider + can use a different JSON library. + + .. versionadded:: 2.2 + """ + + #: A list of functions that are called by + #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function is called + #: with ``error``, ``endpoint`` and ``values``. If a function + #: returns ``None`` or raises a ``BuildError``, it is skipped. + #: Otherwise, its return value is returned by ``url_for``. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: list[ + t.Callable[[Exception, str, dict[str, t.Any]], str] + ] = [] + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] + + #: Maps registered blueprint names to blueprint objects. The + #: dict retains the order the blueprints were registered in. + #: Blueprints can be registered multiple times, this dict does + #: not track how often they were attached. + #: + #: .. versionadded:: 0.7 + self.blueprints: dict[str, Blueprint] = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions: dict[str, t.Any] = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = self.url_map_class(host_matching=host_matching) + + self.subdomain_matching = subdomain_matching + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_first_request: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called" + " on the application. It has already handled its first" + " request, any changes will not be applied" + " consistently.\n" + "Make sure all imports, decorators, functions, etc." + " needed to set up the application are done before" + " running it." + ) + + @cached_property + def name(self) -> str: # type: ignore + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == "__main__": + fn: str | None = getattr(sys.modules["__main__"], "__file__", None) + if fn is None: + return "__main__" + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @cached_property + def logger(self) -> logging.Logger: + """A standard Python :class:`~logging.Logger` for the app, with + the same name as :attr:`name`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will + be set to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be + added. See :doc:`/logging` for more information. + + .. versionchanged:: 1.1.0 + The logger takes the same name as :attr:`name` rather than + hard-coding ``"flask.app"``. + + .. versionchanged:: 1.0.0 + Behavior was simplified. The logger is always named + ``"flask.app"``. The level is only set during configuration, + it doesn't check ``app.debug`` each time. Only one format is + used, not different ones depending on ``app.debug``. No + handlers are removed, and a handler is only added if no + handlers are already configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @cached_property + def jinja_env(self) -> Environment: + """The Jinja environment used to load templates. + + The environment is created the first time this property is + accessed. Changing :attr:`jinja_options` after that will have no + effect. + """ + return self.create_jinja_environment() + + def create_jinja_environment(self) -> Environment: + raise NotImplementedError() + + def make_config(self, instance_relative: bool = False) -> Config: + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + defaults = dict(self.default_config) + defaults["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + def make_aborter(self) -> Aborter: + """Create the object to assign to :attr:`aborter`. That object + is called by :func:`flask.abort` to raise HTTP errors, and can + be called directly as well. + + By default, this creates an instance of :attr:`aborter_class`, + which defaults to :class:`werkzeug.exceptions.Aborter`. + + .. versionadded:: 2.2 + """ + return self.aborter_class() + + def auto_find_instance_path(self) -> str: + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, "instance") + return os.path.join(prefix, "var", f"{self.name}-instance") + + def create_global_jinja_loader(self) -> DispatchingJinjaLoader: + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename: str) -> bool: + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionchanged:: 2.2 + Autoescaping is now enabled by default for ``.svg`` files. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) + + @property + def debug(self) -> bool: + """Whether debug mode is enabled. When using ``flask run`` to start the + development server, an interactive debugger will be shown for unhandled + exceptions, and the server will be reloaded when code changes. This maps to the + :data:`DEBUG` config key. It may not behave as expected if set late. + + **Do not enable debug mode when deploying in production.** + + Default: ``False`` + """ + return self.config["DEBUG"] # type: ignore[no-any-return] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + + if self.config["TEMPLATES_AUTO_RELOAD"] is None: + self.jinja_env.auto_reload = value + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 0.7 + """ + blueprint.register(self, options) + + def iter_blueprints(self) -> t.ValuesView[Blueprint]: + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return self.blueprints.values() + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule_obj = self.url_rule_class(rule, methods=methods, **options) + rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] + + self.url_map.add(rule_obj) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError( + "View function mapping is overwriting an existing" + f" endpoint function: {endpoint}" + ) + self.view_functions[endpoint] = view_func + + @setupmethod + def template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler( + self, e: Exception, blueprints: list[str] + ) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*blueprints, None) + + for c in (code, None) if code is not None else (None,): + for name in names: + handler_map = self.error_handler_spec[name][c] + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + return None + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect( + location, + code=code, + Response=self.response_class, # type: ignore[arg-type] + ) + + def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + names: t.Iterable[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/blueprints.py b/.venv/lib/python3.12/site-packages/flask/sansio/blueprints.py new file mode 100644 index 0000000..4f912cc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/sansio/blueprints.py @@ -0,0 +1,632 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .. import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import App + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: App, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore[assignment] + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: DeferredSetupFunction) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: DeferredSetupFunction) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: App, options: dict[str, t.Any], first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: App, options: dict[str, t.Any]) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, # type: ignore[attr-defined] + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + self._merge_blueprint_funcs(app, name) + + for deferred in self.deferred_functions: + deferred(state) + + cli_resolved_group = options.get("cli_group", self.cli_group) + + if self.cli.commands: + if cli_resolved_group is None: + app.cli.commands.update(self.cli.commands) + elif cli_resolved_group is _sentinel: + self.cli.name = name + app.cli.add_command(self.cli) + else: + self.cli.name = cli_resolved_group + app.cli.add_command(self.cli) + + for blueprint, bp_options in self._blueprints: + bp_options = bp_options.copy() + bp_url_prefix = bp_options.get("url_prefix") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + def _merge_blueprint_funcs(self, app: App, name: str) -> None: + def extend( + bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + ) -> None: + for key, values in bp_dict.items(): + key = name if key is None else f"{name}.{key}" + parent_dict[key].extend(values) + + for key, value in self.error_handler_spec.items(): + key = name if key is None else f"{name}.{key}" + value = defaultdict( + dict, + { + code: {exc_class: func for exc_class, func in code_values.items()} + for code, code_values in value.items() + }, + ) + app.error_handler_spec[key] = value + + for endpoint, func in self.view_functions.items(): + app.view_functions[endpoint] = func + + extend(self.before_request_funcs, app.before_request_funcs) + extend(self.after_request_funcs, app.after_request_funcs) + extend( + self.teardown_request_funcs, + app.teardown_request_funcs, + ) + extend(self.url_default_functions, app.url_default_functions) + extend(self.url_value_preprocessors, app.url_value_preprocessors) + extend(self.template_context_processors, app.template_context_processors) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + def from_blueprint(state: BlueprintSetupState) -> None: + state.app.errorhandler(code)(f) + + self.record_once(from_blueprint) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/.venv/lib/python3.12/site-packages/flask/sansio/scaffold.py b/.venv/lib/python3.12/site-packages/flask/sansio/scaffold.py new file mode 100644 index 0000000..69e33a0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/sansio/scaffold.py @@ -0,0 +1,801 @@ +from __future__ import annotations + +import importlib.util +import os +import pathlib +import sys +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from jinja2 import BaseLoader +from jinja2 import FileSystemLoader +from werkzeug.exceptions import default_exceptions +from werkzeug.exceptions import HTTPException +from werkzeug.utils import cached_property + +from .. import typing as ft +from ..helpers import get_root_path +from ..templating import _default_template_ctx_processor + +if t.TYPE_CHECKING: # pragma: no cover + from click import Group + +# a singleton sentinel value for parameter defaults +_sentinel = object() + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) +T_route = t.TypeVar("T_route", bound=ft.RouteCallable) + + +def setupmethod(f: F) -> F: + f_name = f.__name__ + + def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: + self._check_setup_finished(f_name) + return f(self, *args, **kwargs) + + return t.cast(F, update_wrapper(wrapper_func, f)) + + +class Scaffold: + """Common behavior shared between :class:`~flask.Flask` and + :class:`~flask.blueprints.Blueprint`. + + :param import_name: The import name of the module where this object + is defined. Usually :attr:`__name__` should be used. + :param static_folder: Path to a folder of static files to serve. + If this is set, a static route will be added. + :param static_url_path: URL prefix for the static route. + :param template_folder: Path to a folder containing template files. + for rendering. If this is set, a Jinja loader will be added. + :param root_path: The path that static, template, and resource files + are relative to. Typically not set, it is discovered based on + the ``import_name``. + + .. versionadded:: 2.0 + """ + + cli: Group + name: str + _static_folder: str | None = None + _static_url_path: str | None = None + + def __init__( + self, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + root_path: str | None = None, + ): + #: The name of the package or module that this object belongs + #: to. Do not change this once it is set by the constructor. + self.import_name = import_name + + self.static_folder = static_folder # type: ignore + self.static_url_path = static_url_path + + #: The path to the templates folder, relative to + #: :attr:`root_path`, to add to the template loader. ``None`` if + #: templates should not be added. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Absolute path to the package on the filesystem. Used to look + #: up resources contained in the package. + self.root_path = root_path + + #: A dictionary mapping endpoint names to view functions. + #: + #: To register a view function, use the :meth:`route` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.view_functions: dict[str, ft.RouteCallable] = {} + + #: A data structure of registered error handlers, in the format + #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is + #: the name of a blueprint the handlers are active for, or + #: ``None`` for all requests. The ``code`` key is the HTTP + #: status code for ``HTTPException``, or ``None`` for + #: other exceptions. The innermost dictionary maps exception + #: classes to handler functions. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.error_handler_spec: dict[ + ft.AppOrBlueprintKey, + dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], + ] = defaultdict(lambda: defaultdict(dict)) + + #: A data structure of functions to call at the beginning of + #: each request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`before_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.before_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`after_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.after_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request even if an exception is raised, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`teardown_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.teardown_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.TeardownCallable] + ] = defaultdict(list) + + #: A data structure of functions to call to pass extra context + #: values when rendering templates, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`context_processor` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.template_context_processors: dict[ + ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] + ] = defaultdict(list, {None: [_default_template_ctx_processor]}) + + #: A data structure of functions to call to modify the keyword + #: arguments passed to the view function, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the + #: :meth:`url_value_preprocessor` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_value_preprocessors: dict[ + ft.AppOrBlueprintKey, + list[ft.URLValuePreprocessorCallable], + ] = defaultdict(list) + + #: A data structure of functions to call to modify the keyword + #: arguments when generating URLs, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`url_defaults` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_default_functions: dict[ + ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] + ] = defaultdict(list) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.name!r}>" + + def _check_setup_finished(self, f_name: str) -> None: + raise NotImplementedError + + @property + def static_folder(self) -> str | None: + """The absolute path to the configured static folder. ``None`` + if no static folder is set. + """ + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + else: + return None + + @static_folder.setter + def static_folder(self, value: str | os.PathLike[str] | None) -> None: + if value is not None: + value = os.fspath(value).rstrip(r"\/") + + self._static_folder = value + + @property + def has_static_folder(self) -> bool: + """``True`` if :attr:`static_folder` is set. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @property + def static_url_path(self) -> str | None: + """The URL prefix that the static route will be accessible from. + + If it was not configured during init, it is derived from + :attr:`static_folder`. + """ + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + basename = os.path.basename(self.static_folder) + return f"/{basename}".rstrip("/") + + return None + + @static_url_path.setter + def static_url_path(self, value: str | None) -> None: + if value is not None: + value = value.rstrip("/") + + self._static_url_path = value + + @cached_property + def jinja_loader(self) -> BaseLoader | None: + """The Jinja loader for this object's templates. By default this + is a class :class:`jinja2.loaders.FileSystemLoader` to + :attr:`template_folder` if it is set. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) + else: + return None + + def _method_route( + self, + method: str, + rule: str, + options: dict[str, t.Any], + ) -> t.Callable[[T_route], T_route]: + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + @setupmethod + def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + @setupmethod + def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + @setupmethod + def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + @setupmethod + def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + @setupmethod + def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + + @setupmethod + def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Decorate a view function to register it with the given URL + rule and options. Calls :meth:`add_url_rule`, which has more + details about the implementation. + + .. code-block:: python + + @app.route("/") + def index(): + return "Hello, World!" + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and + ``OPTIONS`` are added automatically. + + :param rule: The URL rule string. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + + def decorator(f: T_route) -> T_route: + endpoint = options.pop("endpoint", None) + self.add_url_rule(rule, endpoint, f, **options) + return f + + return decorator + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a rule for routing incoming requests and building + URLs. The :meth:`route` decorator is a shortcut to call this + with the ``view_func`` argument. These are equivalent: + + .. code-block:: python + + @app.route("/") + def index(): + ... + + .. code-block:: python + + def index(): + ... + + app.add_url_rule("/", view_func=index) + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. An error + will be raised if a function has already been registered for the + endpoint. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is + always added automatically, and ``OPTIONS`` is added + automatically by default. + + ``view_func`` does not necessarily need to be passed, but if the + rule should participate in routing an endpoint name must be + associated with a view function at some point with the + :meth:`endpoint` decorator. + + .. code-block:: python + + app.add_url_rule("/", endpoint="index") + + @app.endpoint("index") + def index(): + ... + + If ``view_func`` has a ``required_methods`` attribute, those + methods are added to the passed and automatic methods. If it + has a ``provide_automatic_methods`` attribute, it is used as the + default if the parameter is not passed. + + :param rule: The URL rule string. + :param endpoint: The endpoint name to associate with the rule + and view function. Used when routing and building URLs. + Defaults to ``view_func.__name__``. + :param view_func: The view function to associate with the + endpoint name. + :param provide_automatic_options: Add the ``OPTIONS`` method and + respond to ``OPTIONS`` requests automatically. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + raise NotImplementedError + + @setupmethod + def endpoint(self, endpoint: str) -> t.Callable[[F], F]: + """Decorate a view function to register it for the given + endpoint. Used if a rule is added without a ``view_func`` with + :meth:`add_url_rule`. + + .. code-block:: python + + app.add_url_rule("/ex", endpoint="example") + + @app.endpoint("example") + def example(): + ... + + :param endpoint: The endpoint name to associate with the view + function. + """ + + def decorator(f: F) -> F: + self.view_functions[endpoint] = f + return f + + return decorator + + @setupmethod + def before_request(self, f: T_before_request) -> T_before_request: + """Register a function to run before each request. + + For example, this can be used to open a database connection, or + to load the logged in user from the session. + + .. code-block:: python + + @app.before_request + def load_user(): + if "user_id" in session: + g.user = db.session.get(session["user_id"]) + + The function will be called without any arguments. If it returns + a non-``None`` value, the value is handled as if it was the + return value from the view, and further request handling is + stopped. + + This is available on both app and blueprint objects. When used on an app, this + executes before every request. When used on a blueprint, this executes before + every request that the blueprint handles. To register with a blueprint and + execute before every request, use :meth:`.Blueprint.before_app_request`. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def after_request(self, f: T_after_request) -> T_after_request: + """Register a function to run after each request to this object. + + The function is called with the response object, and must return + a response object. This allows the functions to modify or + replace the response before it is sent. + + If a function raises an exception, any remaining + ``after_request`` functions will not be called. Therefore, this + should not be used for actions that must execute, such as to + close resources. Use :meth:`teardown_request` for that. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.after_app_request`. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f: T_teardown) -> T_teardown: + """Register a function to be called when the request context is + popped. Typically this happens at the end of each request, but + contexts may be pushed manually as well during testing. + + .. code-block:: python + + with app.test_request_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the request context is + made inactive. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.teardown_app_request`. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def context_processor( + self, + f: T_template_context_processor, + ) -> T_template_context_processor: + """Registers a template context processor function. These functions run before + rendering a template. The keys of the returned dict are added as variables + available in the template. + + This is available on both app and blueprint objects. When used on an app, this + is called for every rendered template. When used on a blueprint, this is called + for templates rendered from the blueprint's views. To register with a blueprint + and affect every template, use :meth:`.Blueprint.app_context_processor`. + """ + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor( + self, + f: T_url_value_preprocessor, + ) -> T_url_value_preprocessor: + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_value_preprocessor`. + """ + self.url_value_preprocessors[None].append(f) + return f + + @setupmethod + def url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_defaults`. + """ + self.url_default_functions[None].append(f) + return f + + @setupmethod + def errorhandler( + self, code_or_exception: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + This is available on both app and blueprint objects. When used on an app, this + can handle errors from every request. When used on a blueprint, this can handle + errors from requests that the blueprint handles. To register with a blueprint + and affect every request, use :meth:`.Blueprint.app_errorhandler`. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.register_error_handler(code_or_exception, f) + return f + + return decorator + + @setupmethod + def register_error_handler( + self, + code_or_exception: type[Exception] | int, + f: ft.ErrorHandlerCallable, + ) -> None: + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + exc_class, code = self._get_exc_class_and_code(code_or_exception) + self.error_handler_spec[None][code][exc_class] = f + + @staticmethod + def _get_exc_class_and_code( + exc_class_or_code: type[Exception] | int, + ) -> tuple[type[Exception], int | None]: + """Get the exception class being handled. For HTTP status codes + or ``HTTPException`` subclasses, return both the exception and + status code. + + :param exc_class_or_code: Any exception class, or an HTTP status + code as an integer. + """ + exc_class: type[Exception] + + if isinstance(exc_class_or_code, int): + try: + exc_class = default_exceptions[exc_class_or_code] + except KeyError: + raise ValueError( + f"'{exc_class_or_code}' is not a recognized HTTP" + " error code. Use a subclass of HTTPException with" + " that code instead." + ) from None + else: + exc_class = exc_class_or_code + + if isinstance(exc_class, Exception): + raise TypeError( + f"{exc_class!r} is an instance, not a class. Handlers" + " can only be registered for Exception classes or HTTP" + " error codes." + ) + + if not issubclass(exc_class, Exception): + raise ValueError( + f"'{exc_class.__name__}' is not a subclass of Exception." + " Handlers can only be registered for Exception classes" + " or HTTP error codes." + ) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + +def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, "expected view func if endpoint is not provided." + return view_func.__name__ + + +def _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool: + # Path.is_relative_to doesn't exist until Python 3.9 + try: + path.relative_to(base) + return True + except ValueError: + return False + + +def _find_package_path(import_name: str) -> str: + """Find the path that contains the package or module.""" + root_mod_name, _, _ = import_name.partition(".") + + try: + root_spec = importlib.util.find_spec(root_mod_name) + + if root_spec is None: + raise ValueError("not found") + except (ImportError, ValueError): + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - we raised `ValueError` due to `root_spec` being `None` + return os.getcwd() + + if root_spec.submodule_search_locations: + if root_spec.origin is None or root_spec.origin == "namespace": + # namespace package + package_spec = importlib.util.find_spec(import_name) + + if package_spec is not None and package_spec.submodule_search_locations: + # Pick the path in the namespace that contains the submodule. + package_path = pathlib.Path( + os.path.commonpath(package_spec.submodule_search_locations) + ) + search_location = next( + location + for location in root_spec.submodule_search_locations + if _path_is_relative_to(package_path, location) + ) + else: + # Pick the first path. + search_location = root_spec.submodule_search_locations[0] + + return os.path.dirname(search_location) + else: + # package with __init__.py + return os.path.dirname(os.path.dirname(root_spec.origin)) + else: + # module + return os.path.dirname(root_spec.origin) # type: ignore[type-var, return-value] + + +def find_package(import_name: str) -> tuple[str | None, str]: + """Find the prefix that a package is installed under, and the path + that it would be imported from. + + The prefix is the directory containing the standard directory + hierarchy (lib, bin, etc.). If the package is not installed to the + system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), + ``None`` is returned. + + The path is the entry in :attr:`sys.path` that contains the package + for import. If the package is not installed, it's assumed that the + package was imported from the current working directory. + """ + package_path = _find_package_path(import_name) + py_prefix = os.path.abspath(sys.prefix) + + # installed to the system + if _path_is_relative_to(pathlib.PurePath(package_path), py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/.venv/lib/python3.12/site-packages/flask/sessions.py b/.venv/lib/python3.12/site-packages/flask/sessions.py new file mode 100644 index 0000000..ee19ad6 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,379 @@ +from __future__ import annotations + +import hashlib +import typing as t +from collections.abc import MutableMapping +from datetime import datetime +from datetime import timezone + +from itsdangerous import BadSignature +from itsdangerous import URLSafeTimedSerializer +from werkzeug.datastructures import CallbackDict + +from .json.tag import TaggedJSONSerializer + +if t.TYPE_CHECKING: # pragma: no cover + import typing_extensions as te + + from .app import Flask + from .wrappers import Request + from .wrappers import Response + + +# TODO generic when Python > 3.8 +class SessionMixin(MutableMapping): # type: ignore[type-arg] + """Expands a basic dictionary with session attributes.""" + + @property + def permanent(self) -> bool: + """This reflects the ``'_permanent'`` key in the dict.""" + return self.get("_permanent", False) + + @permanent.setter + def permanent(self, value: bool) -> None: + self["_permanent"] = bool(value) + + #: Some implementations can detect whether a session is newly + #: created, but that is not guaranteed. Use with caution. The mixin + # default is hard-coded ``False``. + new = False + + #: Some implementations can detect changes to the session and set + #: this when that happens. The mixin default is hard coded to + #: ``True``. + modified = True + + #: Some implementations can detect when session data is read or + #: written and set this when that happens. The mixin default is hard + #: coded to ``True``. + accessed = True + + +# TODO generic when Python > 3.8 +class SecureCookieSession(CallbackDict, SessionMixin): # type: ignore[type-arg] + """Base class for sessions based on signed cookies. + + This session backend will set the :attr:`modified` and + :attr:`accessed` attributes. It cannot reliably track whether a + session is new (vs. empty), so :attr:`new` remains hard coded to + ``False``. + """ + + #: When data is changed, this is set to ``True``. Only the session + #: dictionary itself is tracked; if the session contains mutable + #: data (for example a nested dict) then this must be set to + #: ``True`` manually when modifying that data. The session cookie + #: will only be written to the response if this is ``True``. + modified = False + + #: When data is read or written, this is set to ``True``. Used by + # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` + #: header, which allows caching proxies to cache different pages for + #: different users. + accessed = False + + def __init__(self, initial: t.Any = None) -> None: + def on_update(self: te.Self) -> None: + self.modified = True + self.accessed = True + + super().__init__(initial, on_update) + + def __getitem__(self, key: str) -> t.Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().setdefault(key, default) + + +class NullSession(SecureCookieSession): + """Class used to generate nicer error messages if sessions are not + available. Will still allow read-only access to the empty session + but fail on setting. + """ + + def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + raise RuntimeError( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." + ) + + __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950 + del _fail + + +class SessionInterface: + """The basic interface you have to implement in order to replace the + default session interface which uses werkzeug's securecookie + implementation. The only methods you have to implement are + :meth:`open_session` and :meth:`save_session`, the others have + useful defaults which you don't need to change. + + The session object returned by the :meth:`open_session` method has to + provide a dictionary like interface plus the properties and methods + from the :class:`SessionMixin`. We recommend just subclassing a dict + and adding that mixin:: + + class Session(dict, SessionMixin): + pass + + If :meth:`open_session` returns ``None`` Flask will call into + :meth:`make_null_session` to create a session that acts as replacement + if the session support cannot work because some requirement is not + fulfilled. The default :class:`NullSession` class that is created + will complain that the secret key was not set. + + To replace the session interface on an application all you have to do + is to assign :attr:`flask.Flask.session_interface`:: + + app = Flask(__name__) + app.session_interface = MySessionInterface() + + Multiple requests with the same session may be sent and handled + concurrently. When implementing a new session interface, consider + whether reads or writes to the backing store must be synchronized. + There is no guarantee on the order in which the session for each + request is opened or saved, it will occur in the order that requests + begin and end processing. + + .. versionadded:: 0.8 + """ + + #: :meth:`make_null_session` will look here for the class that should + #: be created when a null session is requested. Likewise the + #: :meth:`is_null_session` method will perform a typecheck against + #: this type. + null_session_class = NullSession + + #: A flag that indicates if the session interface is pickle based. + #: This can be used by Flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + + def make_null_session(self, app: Flask) -> NullSession: + """Creates a null session which acts as a replacement object if the + real session support could not be loaded due to a configuration + error. This mainly aids the user experience because the job of the + null session is to still support lookup without complaining but + modifications are answered with a helpful error message of what + failed. + + This creates an instance of :attr:`null_session_class` by default. + """ + return self.null_session_class() + + def is_null_session(self, obj: object) -> bool: + """Checks if a given object is a null session. Null sessions are + not asked to be saved. + + This checks if the object is an instance of :attr:`null_session_class` + by default. + """ + return isinstance(obj, self.null_session_class) + + def get_cookie_name(self, app: Flask) -> str: + """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" + return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return] + + def get_cookie_domain(self, app: Flask) -> str | None: + """The value of the ``Domain`` parameter on the session cookie. If not set, + browsers will only send the cookie to the exact domain it was set from. + Otherwise, they will send it to any subdomain of the given value as well. + + Uses the :data:`SESSION_COOKIE_DOMAIN` config. + + .. versionchanged:: 2.3 + Not set by default, does not fall back to ``SERVER_NAME``. + """ + return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return] + + def get_cookie_path(self, app: Flask) -> str: + """Returns the path for which the cookie should be valid. The + default implementation uses the value from the ``SESSION_COOKIE_PATH`` + config var if it's set, and falls back to ``APPLICATION_ROOT`` or + uses ``/`` if it's ``None``. + """ + return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return] + + def get_cookie_httponly(self, app: Flask) -> bool: + """Returns True if the session cookie should be httponly. This + currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` + config var. + """ + return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return] + + def get_cookie_secure(self, app: Flask) -> bool: + """Returns True if the cookie should be secure. This currently + just returns the value of the ``SESSION_COOKIE_SECURE`` setting. + """ + return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return] + + def get_cookie_samesite(self, app: Flask) -> str | None: + """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the + ``SameSite`` attribute. This currently just returns the value of + the :data:`SESSION_COOKIE_SAMESITE` setting. + """ + return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] + + def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: + """A helper method that returns an expiration date for the session + or ``None`` if the session is linked to the browser session. The + default implementation returns now + the permanent session + lifetime configured on the application. + """ + if session.permanent: + return datetime.now(timezone.utc) + app.permanent_session_lifetime + return None + + def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: + """Used by session backends to determine if a ``Set-Cookie`` header + should be set for this session cookie for this response. If the session + has been modified, the cookie is set. If the session is permanent and + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is + always set. + + This check is usually skipped if the session was deleted. + + .. versionadded:: 0.11 + """ + + return session.modified or ( + session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] + ) + + def open_session(self, app: Flask, request: Request) -> SessionMixin | None: + """This is called at the beginning of each request, after + pushing the request context, before matching the URL. + + This must return an object which implements a dictionary-like + interface as well as the :class:`SessionMixin` interface. + + This will return ``None`` to indicate that loading failed in + some way that is not immediately an error. The request + context will fall back to using :meth:`make_null_session` + in this case. + """ + raise NotImplementedError() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + """This is called at the end of each request, after generating + a response, before removing the request context. It is skipped + if :meth:`is_null_session` returns ``True``. + """ + raise NotImplementedError() + + +session_json_serializer = TaggedJSONSerializer() + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. + salt = "cookie-session" + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(_lazy_sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = "hmac" + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. + serializer = session_json_serializer + session_class = SecureCookieSession + + def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: + if not app.secret_key: + return None + signer_kwargs = dict( + key_derivation=self.key_derivation, digest_method=self.digest_method + ) + return URLSafeTimedSerializer( + app.secret_key, + salt=self.salt, + serializer=self.serializer, + signer_kwargs=signer_kwargs, + ) + + def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: + s = self.get_signing_serializer(app) + if s is None: + return None + val = request.cookies.get(self.get_cookie_name(app)) + if not val: + return self.session_class() + max_age = int(app.permanent_session_lifetime.total_seconds()) + try: + data = s.loads(val, max_age=max_age) + return self.session_class(data) + except BadSignature: + return self.session_class() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + name = self.get_cookie_name(app) + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + secure = self.get_cookie_secure(app) + samesite = self.get_cookie_samesite(app) + httponly = self.get_cookie_httponly(app) + + # Add a "Vary: Cookie" header if the session was accessed at all. + if session.accessed: + response.vary.add("Cookie") + + # If the session is modified to be empty, remove the cookie. + # If the session is empty, return without setting the cookie. + if not session: + if session.modified: + response.delete_cookie( + name, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + httponly=httponly, + ) + response.vary.add("Cookie") + + return + + if not self.should_set_cookie(app, session): + return + + expires = self.get_expiration_time(app, session) + val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore + response.set_cookie( + name, + val, # type: ignore + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/.venv/lib/python3.12/site-packages/flask/signals.py b/.venv/lib/python3.12/site-packages/flask/signals.py new file mode 100644 index 0000000..444fda9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/signals.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") diff --git a/.venv/lib/python3.12/site-packages/flask/templating.py b/.venv/lib/python3.12/site-packages/flask/templating.py new file mode 100644 index 0000000..618a3b3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/templating.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +import typing as t + +from jinja2 import BaseLoader +from jinja2 import Environment as BaseEnvironment +from jinja2 import Template +from jinja2 import TemplateNotFound + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .helpers import stream_with_context +from .signals import before_render_template +from .signals import template_rendered + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .sansio.app import App + from .sansio.scaffold import Scaffold + + +def _default_template_ctx_processor() -> dict[str, t.Any]: + """Default template context processor. Injects `request`, + `session` and `g`. + """ + appctx = _cv_app.get(None) + reqctx = _cv_request.get(None) + rv: dict[str, t.Any] = {} + if appctx is not None: + rv["g"] = appctx.g + if reqctx is not None: + rv["request"] = reqctx.request + rv["session"] = reqctx.session + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja2 environment but has some additional + knowledge of how Flask's blueprint works so that it can prepend the + name of the blueprint to referenced templates if necessary. + """ + + def __init__(self, app: App, **options: t.Any) -> None: + if "loader" not in options: + options["loader"] = app.create_global_jinja_loader() + BaseEnvironment.__init__(self, **options) + self.app = app + + +class DispatchingJinjaLoader(BaseLoader): + """A loader that looks for templates in the application and all + the blueprint folders. + """ + + def __init__(self, app: App) -> None: + self.app = app + + def get_source( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: + return self._get_source_explained(environment, template) + return self._get_source_fast(environment, template) + + def _get_source_explained( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + attempts = [] + rv: tuple[str, str | None, t.Callable[[], bool] | None] | None + trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None + + for srcobj, loader in self._iter_loaders(template): + try: + rv = loader.get_source(environment, template) + if trv is None: + trv = rv + except TemplateNotFound: + rv = None + attempts.append((loader, srcobj, rv)) + + from .debughelpers import explain_template_loading_attempts + + explain_template_loading_attempts(self.app, template, attempts) + + if trv is not None: + return trv + raise TemplateNotFound(template) + + def _get_source_fast( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + for _srcobj, loader in self._iter_loaders(template): + try: + return loader.get_source(environment, template) + except TemplateNotFound: + continue + raise TemplateNotFound(template) + + def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]: + loader = self.app.jinja_loader + if loader is not None: + yield self.app, loader + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + yield blueprint, loader + + def list_templates(self) -> list[str]: + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + result.add(template) + + return list(result) + + +def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + rv = template.render(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + return rv + + +def render_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> str: + """Render a template by name with the given context. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _render(app, template, context) + + +def render_template_string(source: str, **context: t.Any) -> str: + """Render a template from the given source string with the given + context. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _render(app, template, context) + + +def _stream( + app: Flask, template: Template, context: dict[str, t.Any] +) -> t.Iterator[str]: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + def generate() -> t.Iterator[str]: + yield from template.generate(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + rv = generate() + + # If a request context is active, keep it while generating. + if request: + rv = stream_with_context(rv) + + return rv + + +def stream_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> t.Iterator[str]: + """Render a template by name with the given context as a stream. + This returns an iterator of strings, which can be used as a + streaming response from a view. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _stream(app, template, context) + + +def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: + """Render a template from the given source string with the given + context as a stream. This returns an iterator of strings, which can + be used as a streaming response from a view. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _stream(app, template, context) diff --git a/.venv/lib/python3.12/site-packages/flask/testing.py b/.venv/lib/python3.12/site-packages/flask/testing.py new file mode 100644 index 0000000..a27b7c8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/testing.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import importlib.metadata +import typing as t +from contextlib import contextmanager +from contextlib import ExitStack +from copy import copy +from types import TracebackType +from urllib.parse import urlsplit + +import werkzeug.test +from click.testing import CliRunner +from werkzeug.test import Client +from werkzeug.wrappers import Request as BaseRequest + +from .cli import ScriptInfo +from .sessions import SessionMixin + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + from werkzeug.test import TestResponse + + from .app import Flask + + +class EnvironBuilder(werkzeug.test.EnvironBuilder): + """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the + application. + + :param app: The Flask application to configure the environment from. + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + + def __init__( + self, + app: Flask, + path: str = "/", + base_url: str | None = None, + subdomain: str | None = None, + url_scheme: str | None = None, + *args: t.Any, + **kwargs: t.Any, + ) -> None: + assert not (base_url or subdomain or url_scheme) or ( + base_url is not None + ) != bool( + subdomain or url_scheme + ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' + + if base_url is None: + http_host = app.config.get("SERVER_NAME") or "localhost" + app_root = app.config["APPLICATION_ROOT"] + + if subdomain: + http_host = f"{subdomain}.{http_host}" + + if url_scheme is None: + url_scheme = app.config["PREFERRED_URL_SCHEME"] + + url = urlsplit(path) + base_url = ( + f"{url.scheme or url_scheme}://{url.netloc or http_host}" + f"/{app_root.lstrip('/')}" + ) + path = url.path + + if url.query: + sep = b"?" if isinstance(url.query, bytes) else "?" + path += sep + url.query + + self.app = app + super().__init__(path, base_url, *args, **kwargs) + + def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: # type: ignore + """Serialize ``obj`` to a JSON-formatted string. + + The serialization will be configured according to the config associated + with this EnvironBuilder's ``app``. + """ + return self.app.json.dumps(obj, **kwargs) + + +_werkzeug_version = "" + + +def _get_werkzeug_version() -> str: + global _werkzeug_version + + if not _werkzeug_version: + _werkzeug_version = importlib.metadata.version("werkzeug") + + return _werkzeug_version + + +class FlaskClient(Client): + """Works like a regular Werkzeug test client but has knowledge about + Flask's contexts to defer the cleanup of the request context until + the end of a ``with`` block. For general information about how to + use this class refer to :class:`werkzeug.test.Client`. + + .. versionchanged:: 0.12 + `app.test_client()` includes preset default environment, which can be + set after instantiation of the `app.test_client()` object in + `client.environ_base`. + + Basic usage is outlined in the :doc:`/testing` chapter. + """ + + application: Flask + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.preserve_context = False + self._new_contexts: list[t.ContextManager[t.Any]] = [] + self._context_stack = ExitStack() + self.environ_base = { + "REMOTE_ADDR": "127.0.0.1", + "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}", + } + + @contextmanager + def session_transaction( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Iterator[SessionMixin]: + """When used in combination with a ``with`` statement this opens a + session transaction. This can be used to modify the session that + the test client uses. Once the ``with`` block is left the session is + stored back. + + :: + + with client.session_transaction() as session: + session['value'] = 42 + + Internally this is implemented by going through a temporary test + request context and since session handling could depend on + request variables this function accepts the same arguments as + :meth:`~flask.Flask.test_request_context` which are directly + passed through. + """ + if self._cookies is None: + raise TypeError( + "Cookies are disabled. Create a client with 'use_cookies=True'." + ) + + app = self.application + ctx = app.test_request_context(*args, **kwargs) + self._add_cookies_to_wsgi(ctx.request.environ) + + with ctx: + sess = app.session_interface.open_session(app, ctx.request) + + if sess is None: + raise RuntimeError("Session backend did not open a session.") + + yield sess + resp = app.response_class() + + if app.session_interface.is_null_session(sess): + return + + with ctx: + app.session_interface.save_session(app, sess, resp) + + self._update_cookies_from_response( + ctx.request.host.partition(":")[0], + ctx.request.path, + resp.headers.getlist("Set-Cookie"), + ) + + def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment: + out = {**self.environ_base, **other} + + if self.preserve_context: + out["werkzeug.debug.preserve_context"] = self._new_contexts.append + + return out + + def _request_from_builder_args( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> BaseRequest: + kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) + builder = EnvironBuilder(self.application, *args, **kwargs) + + try: + return builder.get_request() + finally: + builder.close() + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> TestResponse: + if args and isinstance( + args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) + ): + if isinstance(args[0], werkzeug.test.EnvironBuilder): + builder = copy(args[0]) + builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type] + request = builder.get_request() + elif isinstance(args[0], dict): + request = EnvironBuilder.from_environ( + args[0], app=self.application, environ_base=self._copy_environ({}) + ).get_request() + else: + # isinstance(args[0], BaseRequest) + request = copy(args[0]) + request.environ = self._copy_environ(request.environ) + else: + # request is None + request = self._request_from_builder_args(args, kwargs) + + # Pop any previously preserved contexts. This prevents contexts + # from being preserved across redirects or multiple requests + # within a single block. + self._context_stack.close() + + response = super().open( + request, + buffered=buffered, + follow_redirects=follow_redirects, + ) + response.json_module = self.application.json # type: ignore[assignment] + + # Re-push contexts that were preserved during the request. + while self._new_contexts: + cm = self._new_contexts.pop() + self._context_stack.enter_context(cm) + + return response + + def __enter__(self) -> FlaskClient: + if self.preserve_context: + raise RuntimeError("Cannot nest client invocations") + self.preserve_context = True + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.preserve_context = False + self._context_stack.close() + + +class FlaskCliRunner(CliRunner): + """A :class:`~click.testing.CliRunner` for testing a Flask app's + CLI commands. Typically created using + :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. + """ + + def __init__(self, app: Flask, **kwargs: t.Any) -> None: + self.app = app + super().__init__(**kwargs) + + def invoke( # type: ignore + self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any + ) -> t.Any: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/.venv/lib/python3.12/site-packages/flask/typing.py b/.venv/lib/python3.12/site-packages/flask/typing.py new file mode 100644 index 0000000..cf6d4ae --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/typing.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import typing as t + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIApplication # noqa: F401 + from werkzeug.datastructures import Headers # noqa: F401 + from werkzeug.sansio.response import Response # noqa: F401 + +# The possible types that are directly convertible or are a Response object. +ResponseValue = t.Union[ + "Response", + str, + bytes, + t.List[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[bytes], +] + +# the possible types for an individual HTTP header +# This should be a Union, but mypy doesn't pass unless it's a TypeVar. +HeaderValue = t.Union[str, t.List[str], t.Tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[t.Tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + t.Tuple[ResponseValue, HeadersValue], + t.Tuple[ResponseValue, int], + t.Tuple[ResponseValue, int, HeadersValue], + "WSGIApplication", +] + +# Allow any subclass of werkzeug.Response, such as the one from Flask, +# as a callback argument. Using werkzeug.Response directly makes a +# callback annotated with flask.Response fail type checking. +ResponseClass = t.TypeVar("ResponseClass", bound="Response") + +AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named +AfterRequestCallable = t.Union[ + t.Callable[[ResponseClass], ResponseClass], + t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], +] +BeforeFirstRequestCallable = t.Union[ + t.Callable[[], None], t.Callable[[], t.Awaitable[None]] +] +BeforeRequestCallable = t.Union[ + t.Callable[[], t.Optional[ResponseReturnValue]], + t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], +] +ShellContextProcessorCallable = t.Callable[[], t.Dict[str, t.Any]] +TeardownCallable = t.Union[ + t.Callable[[t.Optional[BaseException]], None], + t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], +] +TemplateContextProcessorCallable = t.Union[ + t.Callable[[], t.Dict[str, t.Any]], + t.Callable[[], t.Awaitable[t.Dict[str, t.Any]]], +] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, t.Dict[str, t.Any]], None] +URLValuePreprocessorCallable = t.Callable[ + [t.Optional[str], t.Optional[t.Dict[str, t.Any]]], None +] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Union[ + t.Callable[[t.Any], ResponseReturnValue], + t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], +] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/.venv/lib/python3.12/site-packages/flask/views.py b/.venv/lib/python3.12/site-packages/flask/views.py new file mode 100644 index 0000000..794fdc0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/views.py @@ -0,0 +1,191 @@ +from __future__ import annotations + +import typing as t + +from . import typing as ft +from .globals import current_app +from .globals import request + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +http_method_funcs = frozenset( + ["get", "post", "head", "options", "delete", "put", "trace", "patch"] +) + + +class View: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class Hello(View): + init_every_request = False + + def dispatch_request(self, name): + return f"Hello, {name}!" + + app.add_url_rule( + "/hello/", view_func=Hello.as_view("hello") + ) + + Set :attr:`methods` on the class to change what methods the view + accepts. + + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! + + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. + """ + + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Collection[str] | None] = None + + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[bool | None] = None + + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. + #: + #: .. versionadded:: 0.8 + decorators: t.ClassVar[list[t.Callable[[F], F]]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True + + def dispatch_request(self) -> ft.ResponseReturnValue: + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. + """ + raise NotImplementedError() + + @classmethod + def as_view( + cls, name: str, *class_args: t.Any, **class_kwargs: t.Any + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. + """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + else: + self = cls(*class_args, **class_kwargs) + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/.venv/lib/python3.12/site-packages/flask/wrappers.py b/.venv/lib/python3.12/site-packages/flask/wrappers.py new file mode 100644 index 0000000..c1eca80 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/flask/wrappers.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +import typing as t + +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import HTTPException +from werkzeug.wrappers import Request as RequestBase +from werkzeug.wrappers import Response as ResponseBase + +from . import json +from .globals import current_app +from .helpers import _split_blueprint_path + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.routing import Rule + + +class Request(RequestBase): + """The request object used by default in Flask. Remembers the + matched endpoint and view arguments. + + It is what ends up as :class:`~flask.request`. If you want to replace + the request object used you can subclass this and set + :attr:`~flask.Flask.request_class` to your subclass. + + The request object is a :class:`~werkzeug.wrappers.Request` subclass and + provides all of the attributes Werkzeug defines plus a few Flask + specific ones. + """ + + json_module: t.Any = json + + #: The internal URL rule that matched the request. This can be + #: useful to inspect which methods are allowed for the URL from + #: a before/after handler (``request.url_rule.methods``) etc. + #: Though if the request's method was invalid for the URL rule, + #: the valid list is available in ``routing_exception.valid_methods`` + #: instead (an attribute of the Werkzeug exception + #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) + #: because the request was never internally bound. + #: + #: .. versionadded:: 0.6 + url_rule: Rule | None = None + + #: A dict of view arguments that matched the request. If an exception + #: happened when matching, this will be ``None``. + view_args: dict[str, t.Any] | None = None + + #: If matching the URL failed, this is the exception that will be + #: raised / was raised as part of the request handling. This is + #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or + #: something similar. + routing_exception: HTTPException | None = None + + @property + def max_content_length(self) -> int | None: # type: ignore[override] + """Read-only view of the ``MAX_CONTENT_LENGTH`` config key.""" + if current_app: + return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] + else: + return None + + @property + def endpoint(self) -> str | None: + """The endpoint that matched the request URL. + + This will be ``None`` if matching failed or has not been + performed yet. + + This in combination with :attr:`view_args` can be used to + reconstruct the same URL or a modified URL. + """ + if self.url_rule is not None: + return self.url_rule.endpoint + + return None + + @property + def blueprint(self) -> str | None: + """The registered name of the current blueprint. + + This will be ``None`` if the endpoint is not part of a + blueprint, or if URL matching failed or has not been performed + yet. + + This does not necessarily match the name the blueprint was + created with. It may have been nested, or registered with a + different name. + """ + endpoint = self.endpoint + + if endpoint is not None and "." in endpoint: + return endpoint.rpartition(".")[0] + + return None + + @property + def blueprints(self) -> list[str]: + """The registered names of the current blueprint upwards through + parent blueprints. + + This will be an empty list if there is no current blueprint, or + if URL matching failed. + + .. versionadded:: 2.0.1 + """ + name = self.blueprint + + if name is None: + return [] + + return _split_blueprint_path(name) + + def _load_form_data(self) -> None: + super()._load_form_data() + + # In debug mode we're replacing the files multidict with an ad-hoc + # subclass that raises a different error for key errors. + if ( + current_app + and current_app.debug + and self.mimetype != "multipart/form-data" + and not self.files + ): + from .debughelpers import attach_enctype_error_multidict + + attach_enctype_error_multidict(self) + + def on_json_loading_failed(self, e: ValueError | None) -> t.Any: + try: + return super().on_json_loading_failed(e) + except BadRequest as e: + if current_app and current_app.debug: + raise + + raise BadRequest() from e + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/.venv/lib/python3.12/site-packages/fontTools/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/__init__.py new file mode 100644 index 0000000..953cda0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/__init__.py @@ -0,0 +1,8 @@ +import logging +from fontTools.misc.loggingTools import configLogger + +log = logging.getLogger(__name__) + +version = __version__ = "4.61.1" + +__all__ = ["version", "log", "configLogger"] diff --git a/.venv/lib/python3.12/site-packages/fontTools/__main__.py b/.venv/lib/python3.12/site-packages/fontTools/__main__.py new file mode 100644 index 0000000..7c74ad3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/__main__.py @@ -0,0 +1,35 @@ +import sys + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + # TODO Handle library-wide options. Eg.: + # --unicodedata + # --verbose / other logging stuff + + # TODO Allow a way to run arbitrary modules? Useful for setting + # library-wide options and calling another library. Eg.: + # + # $ fonttools --unicodedata=... fontmake ... + # + # This allows for a git-like command where thirdparty commands + # can be added. Should we just try importing the fonttools + # module first and try without if it fails? + + if len(sys.argv) < 2: + sys.argv.append("help") + if sys.argv[1] == "-h" or sys.argv[1] == "--help": + sys.argv[1] = "help" + mod = "fontTools." + sys.argv[1] + sys.argv[1] = sys.argv[0] + " " + sys.argv[1] + del sys.argv[0] + + import runpy + + runpy.run_module(mod, run_name="__main__") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..b7d8bb4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..471a17a Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/__main__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/afmLib.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/afmLib.cpython-312.pyc new file mode 100644 index 0000000..6fa5be0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/afmLib.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/agl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/agl.cpython-312.pyc new file mode 100644 index 0000000..f123661 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/agl.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/annotations.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/annotations.cpython-312.pyc new file mode 100644 index 0000000..26f4b49 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/annotations.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/fontBuilder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/fontBuilder.cpython-312.pyc new file mode 100644 index 0000000..10a41bc Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/fontBuilder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/help.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/help.cpython-312.pyc new file mode 100644 index 0000000..3515815 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/help.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/tfmLib.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/tfmLib.cpython-312.pyc new file mode 100644 index 0000000..6cd773b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/tfmLib.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/ttx.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/ttx.cpython-312.pyc new file mode 100644 index 0000000..e0eb6ee Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/ttx.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/__pycache__/unicode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/unicode.cpython-312.pyc new file mode 100644 index 0000000..58490b1 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/__pycache__/unicode.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/afmLib.py b/.venv/lib/python3.12/site-packages/fontTools/afmLib.py new file mode 100644 index 0000000..0aabf7f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/afmLib.py @@ -0,0 +1,439 @@ +"""Module for reading and writing AFM (Adobe Font Metrics) files. + +Note that this has been designed to read in AFM files generated by Fontographer +and has not been tested on many other files. In particular, it does not +implement the whole Adobe AFM specification [#f1]_ but, it should read most +"common" AFM files. + +Here is an example of using `afmLib` to read, modify and write an AFM file: + + >>> from fontTools.afmLib import AFM + >>> f = AFM("Tests/afmLib/data/TestAFM.afm") + >>> + >>> # Accessing a pair gets you the kern value + >>> f[("V","A")] + -60 + >>> + >>> # Accessing a glyph name gets you metrics + >>> f["A"] + (65, 668, (8, -25, 660, 666)) + >>> # (charnum, width, bounding box) + >>> + >>> # Accessing an attribute gets you metadata + >>> f.FontName + 'TestFont-Regular' + >>> f.FamilyName + 'TestFont' + >>> f.Weight + 'Regular' + >>> f.XHeight + 500 + >>> f.Ascender + 750 + >>> + >>> # Attributes and items can also be set + >>> f[("A","V")] = -150 # Tighten kerning + >>> f.FontName = "TestFont Squished" + >>> + >>> # And the font written out again (remove the # in front) + >>> #f.write("testfont-squished.afm") + +.. rubric:: Footnotes + +.. [#f1] `Adobe Technote 5004 `_, + Adobe Font Metrics File Format Specification. + +""" + +import re + +# every single line starts with a "word" +identifierRE = re.compile(r"^([A-Za-z]+).*") + +# regular expression to parse char lines +charRE = re.compile( + r"(-?\d+)" # charnum + r"\s*;\s*WX\s+" # ; WX + r"(-?\d+)" # width + r"\s*;\s*N\s+" # ; N + r"([.A-Za-z0-9_]+)" # charname + r"\s*;\s*B\s+" # ; B + r"(-?\d+)" # left + r"\s+" + r"(-?\d+)" # bottom + r"\s+" + r"(-?\d+)" # right + r"\s+" + r"(-?\d+)" # top + r"\s*;\s*" # ; +) + +# regular expression to parse kerning lines +kernRE = re.compile( + r"([.A-Za-z0-9_]+)" # leftchar + r"\s+" + r"([.A-Za-z0-9_]+)" # rightchar + r"\s+" + r"(-?\d+)" # value + r"\s*" +) + +# regular expressions to parse composite info lines of the form: +# Aacute 2 ; PCC A 0 0 ; PCC acute 182 211 ; +compositeRE = re.compile( + r"([.A-Za-z0-9_]+)" # char name + r"\s+" + r"(\d+)" # number of parts + r"\s*;\s*" +) +componentRE = re.compile( + r"PCC\s+" # PPC + r"([.A-Za-z0-9_]+)" # base char name + r"\s+" + r"(-?\d+)" # x offset + r"\s+" + r"(-?\d+)" # y offset + r"\s*;\s*" +) + +preferredAttributeOrder = [ + "FontName", + "FullName", + "FamilyName", + "Weight", + "ItalicAngle", + "IsFixedPitch", + "FontBBox", + "UnderlinePosition", + "UnderlineThickness", + "Version", + "Notice", + "EncodingScheme", + "CapHeight", + "XHeight", + "Ascender", + "Descender", +] + + +class error(Exception): + pass + + +class AFM(object): + _attrs = None + + _keywords = [ + "StartFontMetrics", + "EndFontMetrics", + "StartCharMetrics", + "EndCharMetrics", + "StartKernData", + "StartKernPairs", + "EndKernPairs", + "EndKernData", + "StartComposites", + "EndComposites", + ] + + def __init__(self, path=None): + """AFM file reader. + + Instantiating an object with a path name will cause the file to be opened, + read, and parsed. Alternatively the path can be left unspecified, and a + file can be parsed later with the :meth:`read` method.""" + self._attrs = {} + self._chars = {} + self._kerning = {} + self._index = {} + self._comments = [] + self._composites = {} + if path is not None: + self.read(path) + + def read(self, path): + """Opens, reads and parses a file.""" + lines = readlines(path) + for line in lines: + if not line.strip(): + continue + m = identifierRE.match(line) + if m is None: + raise error("syntax error in AFM file: " + repr(line)) + + pos = m.regs[1][1] + word = line[:pos] + rest = line[pos:].strip() + if word in self._keywords: + continue + if word == "C": + self.parsechar(rest) + elif word == "KPX": + self.parsekernpair(rest) + elif word == "CC": + self.parsecomposite(rest) + else: + self.parseattr(word, rest) + + def parsechar(self, rest): + m = charRE.match(rest) + if m is None: + raise error("syntax error in AFM file: " + repr(rest)) + things = [] + for fr, to in m.regs[1:]: + things.append(rest[fr:to]) + charname = things[2] + del things[2] + charnum, width, l, b, r, t = (int(thing) for thing in things) + self._chars[charname] = charnum, width, (l, b, r, t) + + def parsekernpair(self, rest): + m = kernRE.match(rest) + if m is None: + raise error("syntax error in AFM file: " + repr(rest)) + things = [] + for fr, to in m.regs[1:]: + things.append(rest[fr:to]) + leftchar, rightchar, value = things + value = int(value) + self._kerning[(leftchar, rightchar)] = value + + def parseattr(self, word, rest): + if word == "FontBBox": + l, b, r, t = [int(thing) for thing in rest.split()] + self._attrs[word] = l, b, r, t + elif word == "Comment": + self._comments.append(rest) + else: + try: + value = int(rest) + except (ValueError, OverflowError): + self._attrs[word] = rest + else: + self._attrs[word] = value + + def parsecomposite(self, rest): + m = compositeRE.match(rest) + if m is None: + raise error("syntax error in AFM file: " + repr(rest)) + charname = m.group(1) + ncomponents = int(m.group(2)) + rest = rest[m.regs[0][1] :] + components = [] + while True: + m = componentRE.match(rest) + if m is None: + raise error("syntax error in AFM file: " + repr(rest)) + basechar = m.group(1) + xoffset = int(m.group(2)) + yoffset = int(m.group(3)) + components.append((basechar, xoffset, yoffset)) + rest = rest[m.regs[0][1] :] + if not rest: + break + assert len(components) == ncomponents + self._composites[charname] = components + + def write(self, path, sep="\r"): + """Writes out an AFM font to the given path.""" + import time + + lines = [ + "StartFontMetrics 2.0", + "Comment Generated by afmLib; at %s" + % (time.strftime("%m/%d/%Y %H:%M:%S", time.localtime(time.time()))), + ] + + # write comments, assuming (possibly wrongly!) they should + # all appear at the top + for comment in self._comments: + lines.append("Comment " + comment) + + # write attributes, first the ones we know about, in + # a preferred order + attrs = self._attrs + for attr in preferredAttributeOrder: + if attr in attrs: + value = attrs[attr] + if attr == "FontBBox": + value = "%s %s %s %s" % value + lines.append(attr + " " + str(value)) + # then write the attributes we don't know about, + # in alphabetical order + items = sorted(attrs.items()) + for attr, value in items: + if attr in preferredAttributeOrder: + continue + lines.append(attr + " " + str(value)) + + # write char metrics + lines.append("StartCharMetrics " + repr(len(self._chars))) + items = [ + (charnum, (charname, width, box)) + for charname, (charnum, width, box) in self._chars.items() + ] + + def myKey(a): + """Custom key function to make sure unencoded chars (-1) + end up at the end of the list after sorting.""" + if a[0] == -1: + a = (0xFFFF,) + a[1:] # 0xffff is an arbitrary large number + return a + + items.sort(key=myKey) + + for charnum, (charname, width, (l, b, r, t)) in items: + lines.append( + "C %d ; WX %d ; N %s ; B %d %d %d %d ;" + % (charnum, width, charname, l, b, r, t) + ) + lines.append("EndCharMetrics") + + # write kerning info + lines.append("StartKernData") + lines.append("StartKernPairs " + repr(len(self._kerning))) + items = sorted(self._kerning.items()) + for (leftchar, rightchar), value in items: + lines.append("KPX %s %s %d" % (leftchar, rightchar, value)) + lines.append("EndKernPairs") + lines.append("EndKernData") + + if self._composites: + composites = sorted(self._composites.items()) + lines.append("StartComposites %s" % len(self._composites)) + for charname, components in composites: + line = "CC %s %s ;" % (charname, len(components)) + for basechar, xoffset, yoffset in components: + line = line + " PCC %s %s %s ;" % (basechar, xoffset, yoffset) + lines.append(line) + lines.append("EndComposites") + + lines.append("EndFontMetrics") + + writelines(path, lines, sep) + + def has_kernpair(self, pair): + """Returns `True` if the given glyph pair (specified as a tuple) exists + in the kerning dictionary.""" + return pair in self._kerning + + def kernpairs(self): + """Returns a list of all kern pairs in the kerning dictionary.""" + return list(self._kerning.keys()) + + def has_char(self, char): + """Returns `True` if the given glyph exists in the font.""" + return char in self._chars + + def chars(self): + """Returns a list of all glyph names in the font.""" + return list(self._chars.keys()) + + def comments(self): + """Returns all comments from the file.""" + return self._comments + + def addComment(self, comment): + """Adds a new comment to the file.""" + self._comments.append(comment) + + def addComposite(self, glyphName, components): + """Specifies that the glyph `glyphName` is made up of the given components. + The components list should be of the following form:: + + [ + (glyphname, xOffset, yOffset), + ... + ] + + """ + self._composites[glyphName] = components + + def __getattr__(self, attr): + if attr in self._attrs: + return self._attrs[attr] + else: + raise AttributeError(attr) + + def __setattr__(self, attr, value): + # all attrs *not* starting with "_" are consider to be AFM keywords + if attr[:1] == "_": + self.__dict__[attr] = value + else: + self._attrs[attr] = value + + def __delattr__(self, attr): + # all attrs *not* starting with "_" are consider to be AFM keywords + if attr[:1] == "_": + try: + del self.__dict__[attr] + except KeyError: + raise AttributeError(attr) + else: + try: + del self._attrs[attr] + except KeyError: + raise AttributeError(attr) + + def __getitem__(self, key): + if isinstance(key, tuple): + # key is a tuple, return the kernpair + return self._kerning[key] + else: + # return the metrics instead + return self._chars[key] + + def __setitem__(self, key, value): + if isinstance(key, tuple): + # key is a tuple, set kernpair + self._kerning[key] = value + else: + # set char metrics + self._chars[key] = value + + def __delitem__(self, key): + if isinstance(key, tuple): + # key is a tuple, del kernpair + del self._kerning[key] + else: + # del char metrics + del self._chars[key] + + def __repr__(self): + if hasattr(self, "FullName"): + return "" % self.FullName + else: + return "" % id(self) + + +def readlines(path): + with open(path, "r", encoding="ascii") as f: + data = f.read() + return data.splitlines() + + +def writelines(path, lines, sep="\r"): + with open(path, "w", encoding="ascii", newline=sep) as f: + f.write("\n".join(lines) + "\n") + + +if __name__ == "__main__": + import EasyDialogs + + path = EasyDialogs.AskFileForOpen() + if path: + afm = AFM(path) + char = "A" + if afm.has_char(char): + print(afm[char]) # print charnum, width and boundingbox + pair = ("A", "V") + if afm.has_kernpair(pair): + print(afm[pair]) # print kerning value for pair + print(afm.Version) # various other afm entries have become attributes + print(afm.Weight) + # afm.comments() returns a list of all Comment lines found in the AFM + print(afm.comments()) + # print afm.chars() + # print afm.kernpairs() + print(afm) + afm.write(path + ".muck") diff --git a/.venv/lib/python3.12/site-packages/fontTools/agl.py b/.venv/lib/python3.12/site-packages/fontTools/agl.py new file mode 100644 index 0000000..d699462 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/agl.py @@ -0,0 +1,5233 @@ +# -*- coding: utf-8 -*- +# The tables below are taken from +# https://github.com/adobe-type-tools/agl-aglfn/raw/4036a9ca80a62f64f9de4f7321a9a045ad0ecfd6/glyphlist.txt +# and +# https://github.com/adobe-type-tools/agl-aglfn/raw/4036a9ca80a62f64f9de4f7321a9a045ad0ecfd6/aglfn.txt +""" +Interface to the Adobe Glyph List + +This module exists to convert glyph names from the Adobe Glyph List +to their Unicode equivalents. Example usage: + + >>> from fontTools.agl import toUnicode + >>> toUnicode("nahiragana") + 'な' + +It also contains two dictionaries, ``UV2AGL`` and ``AGL2UV``, which map from +Unicode codepoints to AGL names and vice versa: + + >>> import fontTools + >>> fontTools.agl.UV2AGL[ord("?")] + 'question' + >>> fontTools.agl.AGL2UV["wcircumflex"] + 373 + +This is used by fontTools when it has to construct glyph names for a font which +doesn't include any (e.g. format 3.0 post tables). +""" + +from fontTools.misc.textTools import tostr +import re + + +_aglText = """\ +# ----------------------------------------------------------- +# Copyright 2002-2019 Adobe (http://www.adobe.com/). +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the +# following conditions are met: +# +# Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# Neither the name of Adobe nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------- +# Name: Adobe Glyph List +# Table version: 2.0 +# Date: September 20, 2002 +# URL: https://github.com/adobe-type-tools/agl-aglfn +# +# Format: two semicolon-delimited fields: +# (1) glyph name--upper/lowercase letters and digits +# (2) Unicode scalar value--four uppercase hexadecimal digits +# +A;0041 +AE;00C6 +AEacute;01FC +AEmacron;01E2 +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Abreveacute;1EAE +Abrevecyrillic;04D0 +Abrevedotbelow;1EB6 +Abrevegrave;1EB0 +Abrevehookabove;1EB2 +Abrevetilde;1EB4 +Acaron;01CD +Acircle;24B6 +Acircumflex;00C2 +Acircumflexacute;1EA4 +Acircumflexdotbelow;1EAC +Acircumflexgrave;1EA6 +Acircumflexhookabove;1EA8 +Acircumflexsmall;F7E2 +Acircumflextilde;1EAA +Acute;F6C9 +Acutesmall;F7B4 +Acyrillic;0410 +Adblgrave;0200 +Adieresis;00C4 +Adieresiscyrillic;04D2 +Adieresismacron;01DE +Adieresissmall;F7E4 +Adotbelow;1EA0 +Adotmacron;01E0 +Agrave;00C0 +Agravesmall;F7E0 +Ahookabove;1EA2 +Aiecyrillic;04D4 +Ainvertedbreve;0202 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Amonospace;FF21 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringbelow;1E00 +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +Aybarmenian;0531 +B;0042 +Bcircle;24B7 +Bdotaccent;1E02 +Bdotbelow;1E04 +Becyrillic;0411 +Benarmenian;0532 +Beta;0392 +Bhook;0181 +Blinebelow;1E06 +Bmonospace;FF22 +Brevesmall;F6F4 +Bsmall;F762 +Btopbar;0182 +C;0043 +Caarmenian;053E +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillaacute;1E08 +Ccedillasmall;F7E7 +Ccircle;24B8 +Ccircumflex;0108 +Cdot;010A +Cdotaccent;010A +Cedillasmall;F7B8 +Chaarmenian;0549 +Cheabkhasiancyrillic;04BC +Checyrillic;0427 +Chedescenderabkhasiancyrillic;04BE +Chedescendercyrillic;04B6 +Chedieresiscyrillic;04F4 +Cheharmenian;0543 +Chekhakassiancyrillic;04CB +Cheverticalstrokecyrillic;04B8 +Chi;03A7 +Chook;0187 +Circumflexsmall;F6F6 +Cmonospace;FF23 +Coarmenian;0551 +Csmall;F763 +D;0044 +DZ;01F1 +DZcaron;01C4 +Daarmenian;0534 +Dafrican;0189 +Dcaron;010E +Dcedilla;1E10 +Dcircle;24B9 +Dcircumflexbelow;1E12 +Dcroat;0110 +Ddotaccent;1E0A +Ddotbelow;1E0C +Decyrillic;0414 +Deicoptic;03EE +Delta;2206 +Deltagreek;0394 +Dhook;018A +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Digammagreek;03DC +Djecyrillic;0402 +Dlinebelow;1E0E +Dmonospace;FF24 +Dotaccentsmall;F6F7 +Dslash;0110 +Dsmall;F764 +Dtopbar;018B +Dz;01F2 +Dzcaron;01C5 +Dzeabkhasiancyrillic;04E0 +Dzecyrillic;0405 +Dzhecyrillic;040F +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecedillabreve;1E1C +Echarmenian;0535 +Ecircle;24BA +Ecircumflex;00CA +Ecircumflexacute;1EBE +Ecircumflexbelow;1E18 +Ecircumflexdotbelow;1EC6 +Ecircumflexgrave;1EC0 +Ecircumflexhookabove;1EC2 +Ecircumflexsmall;F7EA +Ecircumflextilde;1EC4 +Ecyrillic;0404 +Edblgrave;0204 +Edieresis;00CB +Edieresissmall;F7EB +Edot;0116 +Edotaccent;0116 +Edotbelow;1EB8 +Efcyrillic;0424 +Egrave;00C8 +Egravesmall;F7E8 +Eharmenian;0537 +Ehookabove;1EBA +Eightroman;2167 +Einvertedbreve;0206 +Eiotifiedcyrillic;0464 +Elcyrillic;041B +Elevenroman;216A +Emacron;0112 +Emacronacute;1E16 +Emacrongrave;1E14 +Emcyrillic;041C +Emonospace;FF25 +Encyrillic;041D +Endescendercyrillic;04A2 +Eng;014A +Enghecyrillic;04A4 +Enhookcyrillic;04C7 +Eogonek;0118 +Eopen;0190 +Epsilon;0395 +Epsilontonos;0388 +Ercyrillic;0420 +Ereversed;018E +Ereversedcyrillic;042D +Escyrillic;0421 +Esdescendercyrillic;04AA +Esh;01A9 +Esmall;F765 +Eta;0397 +Etarmenian;0538 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Etilde;1EBC +Etildebelow;1E1A +Euro;20AC +Ezh;01B7 +Ezhcaron;01EE +Ezhreversed;01B8 +F;0046 +Fcircle;24BB +Fdotaccent;1E1E +Feharmenian;0556 +Feicoptic;03E4 +Fhook;0191 +Fitacyrillic;0472 +Fiveroman;2164 +Fmonospace;FF26 +Fourroman;2163 +Fsmall;F766 +G;0047 +GBsquare;3387 +Gacute;01F4 +Gamma;0393 +Gammaafrican;0194 +Gangiacoptic;03EA +Gbreve;011E +Gcaron;01E6 +Gcedilla;0122 +Gcircle;24BC +Gcircumflex;011C +Gcommaaccent;0122 +Gdot;0120 +Gdotaccent;0120 +Gecyrillic;0413 +Ghadarmenian;0542 +Ghemiddlehookcyrillic;0494 +Ghestrokecyrillic;0492 +Gheupturncyrillic;0490 +Ghook;0193 +Gimarmenian;0533 +Gjecyrillic;0403 +Gmacron;1E20 +Gmonospace;FF27 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +Gsmallhook;029B +Gstroke;01E4 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +HPsquare;33CB +Haabkhasiancyrillic;04A8 +Hadescendercyrillic;04B2 +Hardsigncyrillic;042A +Hbar;0126 +Hbrevebelow;1E2A +Hcedilla;1E28 +Hcircle;24BD +Hcircumflex;0124 +Hdieresis;1E26 +Hdotaccent;1E22 +Hdotbelow;1E24 +Hmonospace;FF28 +Hoarmenian;0540 +Horicoptic;03E8 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +Hzsquare;3390 +I;0049 +IAcyrillic;042F +IJ;0132 +IUcyrillic;042E +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icaron;01CF +Icircle;24BE +Icircumflex;00CE +Icircumflexsmall;F7EE +Icyrillic;0406 +Idblgrave;0208 +Idieresis;00CF +Idieresisacute;1E2E +Idieresiscyrillic;04E4 +Idieresissmall;F7EF +Idot;0130 +Idotaccent;0130 +Idotbelow;1ECA +Iebrevecyrillic;04D6 +Iecyrillic;0415 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Ihookabove;1EC8 +Iicyrillic;0418 +Iinvertedbreve;020A +Iishortcyrillic;0419 +Imacron;012A +Imacroncyrillic;04E2 +Imonospace;FF29 +Iniarmenian;053B +Iocyrillic;0401 +Iogonek;012E +Iota;0399 +Iotaafrican;0196 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Istroke;0197 +Itilde;0128 +Itildebelow;1E2C +Izhitsacyrillic;0474 +Izhitsadblgravecyrillic;0476 +J;004A +Jaarmenian;0541 +Jcircle;24BF +Jcircumflex;0134 +Jecyrillic;0408 +Jheharmenian;054B +Jmonospace;FF2A +Jsmall;F76A +K;004B +KBsquare;3385 +KKsquare;33CD +Kabashkircyrillic;04A0 +Kacute;1E30 +Kacyrillic;041A +Kadescendercyrillic;049A +Kahookcyrillic;04C3 +Kappa;039A +Kastrokecyrillic;049E +Kaverticalstrokecyrillic;049C +Kcaron;01E8 +Kcedilla;0136 +Kcircle;24C0 +Kcommaaccent;0136 +Kdotbelow;1E32 +Keharmenian;0554 +Kenarmenian;053F +Khacyrillic;0425 +Kheicoptic;03E6 +Khook;0198 +Kjecyrillic;040C +Klinebelow;1E34 +Kmonospace;FF2B +Koppacyrillic;0480 +Koppagreek;03DE +Ksicyrillic;046E +Ksmall;F76B +L;004C +LJ;01C7 +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcedilla;013B +Lcircle;24C1 +Lcircumflexbelow;1E3C +Lcommaaccent;013B +Ldot;013F +Ldotaccent;013F +Ldotbelow;1E36 +Ldotbelowmacron;1E38 +Liwnarmenian;053C +Lj;01C8 +Ljecyrillic;0409 +Llinebelow;1E3A +Lmonospace;FF2C +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +MBsquare;3386 +Macron;F6D0 +Macronsmall;F7AF +Macute;1E3E +Mcircle;24C2 +Mdotaccent;1E40 +Mdotbelow;1E42 +Menarmenian;0544 +Mmonospace;FF2D +Msmall;F76D +Mturned;019C +Mu;039C +N;004E +NJ;01CA +Nacute;0143 +Ncaron;0147 +Ncedilla;0145 +Ncircle;24C3 +Ncircumflexbelow;1E4A +Ncommaaccent;0145 +Ndotaccent;1E44 +Ndotbelow;1E46 +Nhookleft;019D +Nineroman;2168 +Nj;01CB +Njecyrillic;040A +Nlinebelow;1E48 +Nmonospace;FF2E +Nowarmenian;0546 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obarredcyrillic;04E8 +Obarreddieresiscyrillic;04EA +Obreve;014E +Ocaron;01D1 +Ocenteredtilde;019F +Ocircle;24C4 +Ocircumflex;00D4 +Ocircumflexacute;1ED0 +Ocircumflexdotbelow;1ED8 +Ocircumflexgrave;1ED2 +Ocircumflexhookabove;1ED4 +Ocircumflexsmall;F7F4 +Ocircumflextilde;1ED6 +Ocyrillic;041E +Odblacute;0150 +Odblgrave;020C +Odieresis;00D6 +Odieresiscyrillic;04E6 +Odieresissmall;F7F6 +Odotbelow;1ECC +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Oharmenian;0555 +Ohm;2126 +Ohookabove;1ECE +Ohorn;01A0 +Ohornacute;1EDA +Ohorndotbelow;1EE2 +Ohorngrave;1EDC +Ohornhookabove;1EDE +Ohorntilde;1EE0 +Ohungarumlaut;0150 +Oi;01A2 +Oinvertedbreve;020E +Omacron;014C +Omacronacute;1E52 +Omacrongrave;1E50 +Omega;2126 +Omegacyrillic;0460 +Omegagreek;03A9 +Omegaroundcyrillic;047A +Omegatitlocyrillic;047C +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Omonospace;FF2F +Oneroman;2160 +Oogonek;01EA +Oogonekmacron;01EC +Oopen;0186 +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Ostrokeacute;01FE +Otcyrillic;047E +Otilde;00D5 +Otildeacute;1E4C +Otildedieresis;1E4E +Otildesmall;F7F5 +P;0050 +Pacute;1E54 +Pcircle;24C5 +Pdotaccent;1E56 +Pecyrillic;041F +Peharmenian;054A +Pemiddlehookcyrillic;04A6 +Phi;03A6 +Phook;01A4 +Pi;03A0 +Piwrarmenian;0553 +Pmonospace;FF30 +Psi;03A8 +Psicyrillic;0470 +Psmall;F770 +Q;0051 +Qcircle;24C6 +Qmonospace;FF31 +Qsmall;F771 +R;0052 +Raarmenian;054C +Racute;0154 +Rcaron;0158 +Rcedilla;0156 +Rcircle;24C7 +Rcommaaccent;0156 +Rdblgrave;0210 +Rdotaccent;1E58 +Rdotbelow;1E5A +Rdotbelowmacron;1E5C +Reharmenian;0550 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rinvertedbreve;0212 +Rlinebelow;1E5E +Rmonospace;FF32 +Rsmall;F772 +Rsmallinverted;0281 +Rsmallinvertedsuperior;02B6 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Sacutedotaccent;1E64 +Sampigreek;03E0 +Scaron;0160 +Scarondotaccent;1E66 +Scaronsmall;F6FD +Scedilla;015E +Schwa;018F +Schwacyrillic;04D8 +Schwadieresiscyrillic;04DA +Scircle;24C8 +Scircumflex;015C +Scommaaccent;0218 +Sdotaccent;1E60 +Sdotbelow;1E62 +Sdotbelowdotaccent;1E68 +Seharmenian;054D +Sevenroman;2166 +Shaarmenian;0547 +Shacyrillic;0428 +Shchacyrillic;0429 +Sheicoptic;03E2 +Shhacyrillic;04BA +Shimacoptic;03EC +Sigma;03A3 +Sixroman;2165 +Smonospace;FF33 +Softsigncyrillic;042C +Ssmall;F773 +Stigmagreek;03DA +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcedilla;0162 +Tcircle;24C9 +Tcircumflexbelow;1E70 +Tcommaaccent;0162 +Tdotaccent;1E6A +Tdotbelow;1E6C +Tecyrillic;0422 +Tedescendercyrillic;04AC +Tenroman;2169 +Tetsecyrillic;04B4 +Theta;0398 +Thook;01AC +Thorn;00DE +Thornsmall;F7FE +Threeroman;2162 +Tildesmall;F6FE +Tiwnarmenian;054F +Tlinebelow;1E6E +Tmonospace;FF34 +Toarmenian;0539 +Tonefive;01BC +Tonesix;0184 +Tonetwo;01A7 +Tretroflexhook;01AE +Tsecyrillic;0426 +Tshecyrillic;040B +Tsmall;F774 +Twelveroman;216B +Tworoman;2161 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucaron;01D3 +Ucircle;24CA +Ucircumflex;00DB +Ucircumflexbelow;1E76 +Ucircumflexsmall;F7FB +Ucyrillic;0423 +Udblacute;0170 +Udblgrave;0214 +Udieresis;00DC +Udieresisacute;01D7 +Udieresisbelow;1E72 +Udieresiscaron;01D9 +Udieresiscyrillic;04F0 +Udieresisgrave;01DB +Udieresismacron;01D5 +Udieresissmall;F7FC +Udotbelow;1EE4 +Ugrave;00D9 +Ugravesmall;F7F9 +Uhookabove;1EE6 +Uhorn;01AF +Uhornacute;1EE8 +Uhorndotbelow;1EF0 +Uhorngrave;1EEA +Uhornhookabove;1EEC +Uhorntilde;1EEE +Uhungarumlaut;0170 +Uhungarumlautcyrillic;04F2 +Uinvertedbreve;0216 +Ukcyrillic;0478 +Umacron;016A +Umacroncyrillic;04EE +Umacrondieresis;1E7A +Umonospace;FF35 +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilonacutehooksymbolgreek;03D3 +Upsilonafrican;01B1 +Upsilondieresis;03AB +Upsilondieresishooksymbolgreek;03D4 +Upsilonhooksymbol;03D2 +Upsilontonos;038E +Uring;016E +Ushortcyrillic;040E +Usmall;F775 +Ustraightcyrillic;04AE +Ustraightstrokecyrillic;04B0 +Utilde;0168 +Utildeacute;1E78 +Utildebelow;1E74 +V;0056 +Vcircle;24CB +Vdotbelow;1E7E +Vecyrillic;0412 +Vewarmenian;054E +Vhook;01B2 +Vmonospace;FF36 +Voarmenian;0548 +Vsmall;F776 +Vtilde;1E7C +W;0057 +Wacute;1E82 +Wcircle;24CC +Wcircumflex;0174 +Wdieresis;1E84 +Wdotaccent;1E86 +Wdotbelow;1E88 +Wgrave;1E80 +Wmonospace;FF37 +Wsmall;F777 +X;0058 +Xcircle;24CD +Xdieresis;1E8C +Xdotaccent;1E8A +Xeharmenian;053D +Xi;039E +Xmonospace;FF38 +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Yatcyrillic;0462 +Ycircle;24CE +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ydotaccent;1E8E +Ydotbelow;1EF4 +Yericyrillic;042B +Yerudieresiscyrillic;04F8 +Ygrave;1EF2 +Yhook;01B3 +Yhookabove;1EF6 +Yiarmenian;0545 +Yicyrillic;0407 +Yiwnarmenian;0552 +Ymonospace;FF39 +Ysmall;F779 +Ytilde;1EF8 +Yusbigcyrillic;046A +Yusbigiotifiedcyrillic;046C +Yuslittlecyrillic;0466 +Yuslittleiotifiedcyrillic;0468 +Z;005A +Zaarmenian;0536 +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zcircle;24CF +Zcircumflex;1E90 +Zdot;017B +Zdotaccent;017B +Zdotbelow;1E92 +Zecyrillic;0417 +Zedescendercyrillic;0498 +Zedieresiscyrillic;04DE +Zeta;0396 +Zhearmenian;053A +Zhebrevecyrillic;04C1 +Zhecyrillic;0416 +Zhedescendercyrillic;0496 +Zhedieresiscyrillic;04DC +Zlinebelow;1E94 +Zmonospace;FF3A +Zsmall;F77A +Zstroke;01B5 +a;0061 +aabengali;0986 +aacute;00E1 +aadeva;0906 +aagujarati;0A86 +aagurmukhi;0A06 +aamatragurmukhi;0A3E +aarusquare;3303 +aavowelsignbengali;09BE +aavowelsigndeva;093E +aavowelsigngujarati;0ABE +abbreviationmarkarmenian;055F +abbreviationsigndeva;0970 +abengali;0985 +abopomofo;311A +abreve;0103 +abreveacute;1EAF +abrevecyrillic;04D1 +abrevedotbelow;1EB7 +abrevegrave;1EB1 +abrevehookabove;1EB3 +abrevetilde;1EB5 +acaron;01CE +acircle;24D0 +acircumflex;00E2 +acircumflexacute;1EA5 +acircumflexdotbelow;1EAD +acircumflexgrave;1EA7 +acircumflexhookabove;1EA9 +acircumflextilde;1EAB +acute;00B4 +acutebelowcmb;0317 +acutecmb;0301 +acutecomb;0301 +acutedeva;0954 +acutelowmod;02CF +acutetonecmb;0341 +acyrillic;0430 +adblgrave;0201 +addakgurmukhi;0A71 +adeva;0905 +adieresis;00E4 +adieresiscyrillic;04D3 +adieresismacron;01DF +adotbelow;1EA1 +adotmacron;01E1 +ae;00E6 +aeacute;01FD +aekorean;3150 +aemacron;01E3 +afii00208;2015 +afii08941;20A4 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +agujarati;0A85 +agurmukhi;0A05 +ahiragana;3042 +ahookabove;1EA3 +aibengali;0990 +aibopomofo;311E +aideva;0910 +aiecyrillic;04D5 +aigujarati;0A90 +aigurmukhi;0A10 +aimatragurmukhi;0A48 +ainarabic;0639 +ainfinalarabic;FECA +aininitialarabic;FECB +ainmedialarabic;FECC +ainvertedbreve;0203 +aivowelsignbengali;09C8 +aivowelsigndeva;0948 +aivowelsigngujarati;0AC8 +akatakana;30A2 +akatakanahalfwidth;FF71 +akorean;314F +alef;05D0 +alefarabic;0627 +alefdageshhebrew;FB30 +aleffinalarabic;FE8E +alefhamzaabovearabic;0623 +alefhamzaabovefinalarabic;FE84 +alefhamzabelowarabic;0625 +alefhamzabelowfinalarabic;FE88 +alefhebrew;05D0 +aleflamedhebrew;FB4F +alefmaddaabovearabic;0622 +alefmaddaabovefinalarabic;FE82 +alefmaksuraarabic;0649 +alefmaksurafinalarabic;FEF0 +alefmaksurainitialarabic;FEF3 +alefmaksuramedialarabic;FEF4 +alefpatahhebrew;FB2E +alefqamatshebrew;FB2F +aleph;2135 +allequal;224C +alpha;03B1 +alphatonos;03AC +amacron;0101 +amonospace;FF41 +ampersand;0026 +ampersandmonospace;FF06 +ampersandsmall;F726 +amsquare;33C2 +anbopomofo;3122 +angbopomofo;3124 +angkhankhuthai;0E5A +angle;2220 +anglebracketleft;3008 +anglebracketleftvertical;FE3F +anglebracketright;3009 +anglebracketrightvertical;FE40 +angleleft;2329 +angleright;232A +angstrom;212B +anoteleia;0387 +anudattadeva;0952 +anusvarabengali;0982 +anusvaradeva;0902 +anusvaragujarati;0A82 +aogonek;0105 +apaatosquare;3300 +aparen;249C +apostrophearmenian;055A +apostrophemod;02BC +apple;F8FF +approaches;2250 +approxequal;2248 +approxequalorimage;2252 +approximatelyequal;2245 +araeaekorean;318E +araeakorean;318D +arc;2312 +arighthalfring;1E9A +aring;00E5 +aringacute;01FB +aringbelow;1E01 +arrowboth;2194 +arrowdashdown;21E3 +arrowdashleft;21E0 +arrowdashright;21E2 +arrowdashup;21E1 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowdownleft;2199 +arrowdownright;2198 +arrowdownwhite;21E9 +arrowheaddownmod;02C5 +arrowheadleftmod;02C2 +arrowheadrightmod;02C3 +arrowheadupmod;02C4 +arrowhorizex;F8E7 +arrowleft;2190 +arrowleftdbl;21D0 +arrowleftdblstroke;21CD +arrowleftoverright;21C6 +arrowleftwhite;21E6 +arrowright;2192 +arrowrightdblstroke;21CF +arrowrightheavy;279E +arrowrightoverleft;21C4 +arrowrightwhite;21E8 +arrowtableft;21E4 +arrowtabright;21E5 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowupdownbase;21A8 +arrowupleft;2196 +arrowupleftofdown;21C5 +arrowupright;2197 +arrowupwhite;21E7 +arrowvertex;F8E6 +asciicircum;005E +asciicircummonospace;FF3E +asciitilde;007E +asciitildemonospace;FF5E +ascript;0251 +ascriptturned;0252 +asmallhiragana;3041 +asmallkatakana;30A1 +asmallkatakanahalfwidth;FF67 +asterisk;002A +asteriskaltonearabic;066D +asteriskarabic;066D +asteriskmath;2217 +asteriskmonospace;FF0A +asterisksmall;FE61 +asterism;2042 +asuperior;F6E9 +asymptoticallyequal;2243 +at;0040 +atilde;00E3 +atmonospace;FF20 +atsmall;FE6B +aturned;0250 +aubengali;0994 +aubopomofo;3120 +audeva;0914 +augujarati;0A94 +augurmukhi;0A14 +aulengthmarkbengali;09D7 +aumatragurmukhi;0A4C +auvowelsignbengali;09CC +auvowelsigndeva;094C +auvowelsigngujarati;0ACC +avagrahadeva;093D +aybarmenian;0561 +ayin;05E2 +ayinaltonehebrew;FB20 +ayinhebrew;05E2 +b;0062 +babengali;09AC +backslash;005C +backslashmonospace;FF3C +badeva;092C +bagujarati;0AAC +bagurmukhi;0A2C +bahiragana;3070 +bahtthai;0E3F +bakatakana;30D0 +bar;007C +barmonospace;FF5C +bbopomofo;3105 +bcircle;24D1 +bdotaccent;1E03 +bdotbelow;1E05 +beamedsixteenthnotes;266C +because;2235 +becyrillic;0431 +beharabic;0628 +behfinalarabic;FE90 +behinitialarabic;FE91 +behiragana;3079 +behmedialarabic;FE92 +behmeeminitialarabic;FC9F +behmeemisolatedarabic;FC08 +behnoonfinalarabic;FC6D +bekatakana;30D9 +benarmenian;0562 +bet;05D1 +beta;03B2 +betasymbolgreek;03D0 +betdagesh;FB31 +betdageshhebrew;FB31 +bethebrew;05D1 +betrafehebrew;FB4C +bhabengali;09AD +bhadeva;092D +bhagujarati;0AAD +bhagurmukhi;0A2D +bhook;0253 +bihiragana;3073 +bikatakana;30D3 +bilabialclick;0298 +bindigurmukhi;0A02 +birusquare;3331 +blackcircle;25CF +blackdiamond;25C6 +blackdownpointingtriangle;25BC +blackleftpointingpointer;25C4 +blackleftpointingtriangle;25C0 +blacklenticularbracketleft;3010 +blacklenticularbracketleftvertical;FE3B +blacklenticularbracketright;3011 +blacklenticularbracketrightvertical;FE3C +blacklowerlefttriangle;25E3 +blacklowerrighttriangle;25E2 +blackrectangle;25AC +blackrightpointingpointer;25BA +blackrightpointingtriangle;25B6 +blacksmallsquare;25AA +blacksmilingface;263B +blacksquare;25A0 +blackstar;2605 +blackupperlefttriangle;25E4 +blackupperrighttriangle;25E5 +blackuppointingsmalltriangle;25B4 +blackuppointingtriangle;25B2 +blank;2423 +blinebelow;1E07 +block;2588 +bmonospace;FF42 +bobaimaithai;0E1A +bohiragana;307C +bokatakana;30DC +bparen;249D +bqsquare;33C3 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +braceleftmonospace;FF5B +braceleftsmall;FE5B +bracelefttp;F8F1 +braceleftvertical;FE37 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerightmonospace;FF5D +bracerightsmall;FE5C +bracerighttp;F8FC +bracerightvertical;FE38 +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketleftmonospace;FF3B +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrightmonospace;FF3D +bracketrighttp;F8F9 +breve;02D8 +brevebelowcmb;032E +brevecmb;0306 +breveinvertedbelowcmb;032F +breveinvertedcmb;0311 +breveinverteddoublecmb;0361 +bridgebelowcmb;032A +bridgeinvertedbelowcmb;033A +brokenbar;00A6 +bstroke;0180 +bsuperior;F6EA +btopbar;0183 +buhiragana;3076 +bukatakana;30D6 +bullet;2022 +bulletinverse;25D8 +bulletoperator;2219 +bullseye;25CE +c;0063 +caarmenian;056E +cabengali;099A +cacute;0107 +cadeva;091A +cagujarati;0A9A +cagurmukhi;0A1A +calsquare;3388 +candrabindubengali;0981 +candrabinducmb;0310 +candrabindudeva;0901 +candrabindugujarati;0A81 +capslock;21EA +careof;2105 +caron;02C7 +caronbelowcmb;032C +caroncmb;030C +carriagereturn;21B5 +cbopomofo;3118 +ccaron;010D +ccedilla;00E7 +ccedillaacute;1E09 +ccircle;24D2 +ccircumflex;0109 +ccurl;0255 +cdot;010B +cdotaccent;010B +cdsquare;33C5 +cedilla;00B8 +cedillacmb;0327 +cent;00A2 +centigrade;2103 +centinferior;F6DF +centmonospace;FFE0 +centoldstyle;F7A2 +centsuperior;F6E0 +chaarmenian;0579 +chabengali;099B +chadeva;091B +chagujarati;0A9B +chagurmukhi;0A1B +chbopomofo;3114 +cheabkhasiancyrillic;04BD +checkmark;2713 +checyrillic;0447 +chedescenderabkhasiancyrillic;04BF +chedescendercyrillic;04B7 +chedieresiscyrillic;04F5 +cheharmenian;0573 +chekhakassiancyrillic;04CC +cheverticalstrokecyrillic;04B9 +chi;03C7 +chieuchacirclekorean;3277 +chieuchaparenkorean;3217 +chieuchcirclekorean;3269 +chieuchkorean;314A +chieuchparenkorean;3209 +chochangthai;0E0A +chochanthai;0E08 +chochingthai;0E09 +chochoethai;0E0C +chook;0188 +cieucacirclekorean;3276 +cieucaparenkorean;3216 +cieuccirclekorean;3268 +cieuckorean;3148 +cieucparenkorean;3208 +cieucuparenkorean;321C +circle;25CB +circlemultiply;2297 +circleot;2299 +circleplus;2295 +circlepostalmark;3036 +circlewithlefthalfblack;25D0 +circlewithrighthalfblack;25D1 +circumflex;02C6 +circumflexbelowcmb;032D +circumflexcmb;0302 +clear;2327 +clickalveolar;01C2 +clickdental;01C0 +clicklateral;01C1 +clickretroflex;01C3 +club;2663 +clubsuitblack;2663 +clubsuitwhite;2667 +cmcubedsquare;33A4 +cmonospace;FF43 +cmsquaredsquare;33A0 +coarmenian;0581 +colon;003A +colonmonetary;20A1 +colonmonospace;FF1A +colonsign;20A1 +colonsmall;FE55 +colontriangularhalfmod;02D1 +colontriangularmod;02D0 +comma;002C +commaabovecmb;0313 +commaaboverightcmb;0315 +commaaccent;F6C3 +commaarabic;060C +commaarmenian;055D +commainferior;F6E1 +commamonospace;FF0C +commareversedabovecmb;0314 +commareversedmod;02BD +commasmall;FE50 +commasuperior;F6E2 +commaturnedabovecmb;0312 +commaturnedmod;02BB +compass;263C +congruent;2245 +contourintegral;222E +control;2303 +controlACK;0006 +controlBEL;0007 +controlBS;0008 +controlCAN;0018 +controlCR;000D +controlDC1;0011 +controlDC2;0012 +controlDC3;0013 +controlDC4;0014 +controlDEL;007F +controlDLE;0010 +controlEM;0019 +controlENQ;0005 +controlEOT;0004 +controlESC;001B +controlETB;0017 +controlETX;0003 +controlFF;000C +controlFS;001C +controlGS;001D +controlHT;0009 +controlLF;000A +controlNAK;0015 +controlRS;001E +controlSI;000F +controlSO;000E +controlSOT;0002 +controlSTX;0001 +controlSUB;001A +controlSYN;0016 +controlUS;001F +controlVT;000B +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +cornerbracketleft;300C +cornerbracketlefthalfwidth;FF62 +cornerbracketleftvertical;FE41 +cornerbracketright;300D +cornerbracketrighthalfwidth;FF63 +cornerbracketrightvertical;FE42 +corporationsquare;337F +cosquare;33C7 +coverkgsquare;33C6 +cparen;249E +cruzeiro;20A2 +cstretched;0297 +curlyand;22CF +curlyor;22CE +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +daarmenian;0564 +dabengali;09A6 +dadarabic;0636 +dadeva;0926 +dadfinalarabic;FEBE +dadinitialarabic;FEBF +dadmedialarabic;FEC0 +dagesh;05BC +dageshhebrew;05BC +dagger;2020 +daggerdbl;2021 +dagujarati;0AA6 +dagurmukhi;0A26 +dahiragana;3060 +dakatakana;30C0 +dalarabic;062F +dalet;05D3 +daletdagesh;FB33 +daletdageshhebrew;FB33 +dalethatafpatah;05D3 05B2 +dalethatafpatahhebrew;05D3 05B2 +dalethatafsegol;05D3 05B1 +dalethatafsegolhebrew;05D3 05B1 +dalethebrew;05D3 +dalethiriq;05D3 05B4 +dalethiriqhebrew;05D3 05B4 +daletholam;05D3 05B9 +daletholamhebrew;05D3 05B9 +daletpatah;05D3 05B7 +daletpatahhebrew;05D3 05B7 +daletqamats;05D3 05B8 +daletqamatshebrew;05D3 05B8 +daletqubuts;05D3 05BB +daletqubutshebrew;05D3 05BB +daletsegol;05D3 05B6 +daletsegolhebrew;05D3 05B6 +daletsheva;05D3 05B0 +daletshevahebrew;05D3 05B0 +dalettsere;05D3 05B5 +dalettserehebrew;05D3 05B5 +dalfinalarabic;FEAA +dammaarabic;064F +dammalowarabic;064F +dammatanaltonearabic;064C +dammatanarabic;064C +danda;0964 +dargahebrew;05A7 +dargalefthebrew;05A7 +dasiapneumatacyrilliccmb;0485 +dblGrave;F6D3 +dblanglebracketleft;300A +dblanglebracketleftvertical;FE3D +dblanglebracketright;300B +dblanglebracketrightvertical;FE3E +dblarchinvertedbelowcmb;032B +dblarrowleft;21D4 +dblarrowright;21D2 +dbldanda;0965 +dblgrave;F6D6 +dblgravecmb;030F +dblintegral;222C +dbllowline;2017 +dbllowlinecmb;0333 +dbloverlinecmb;033F +dblprimemod;02BA +dblverticalbar;2016 +dblverticallineabovecmb;030E +dbopomofo;3109 +dbsquare;33C8 +dcaron;010F +dcedilla;1E11 +dcircle;24D3 +dcircumflexbelow;1E13 +dcroat;0111 +ddabengali;09A1 +ddadeva;0921 +ddagujarati;0AA1 +ddagurmukhi;0A21 +ddalarabic;0688 +ddalfinalarabic;FB89 +dddhadeva;095C +ddhabengali;09A2 +ddhadeva;0922 +ddhagujarati;0AA2 +ddhagurmukhi;0A22 +ddotaccent;1E0B +ddotbelow;1E0D +decimalseparatorarabic;066B +decimalseparatorpersian;066B +decyrillic;0434 +degree;00B0 +dehihebrew;05AD +dehiragana;3067 +deicoptic;03EF +dekatakana;30C7 +deleteleft;232B +deleteright;2326 +delta;03B4 +deltaturned;018D +denominatorminusonenumeratorbengali;09F8 +dezh;02A4 +dhabengali;09A7 +dhadeva;0927 +dhagujarati;0AA7 +dhagurmukhi;0A27 +dhook;0257 +dialytikatonos;0385 +dialytikatonoscmb;0344 +diamond;2666 +diamondsuitwhite;2662 +dieresis;00A8 +dieresisacute;F6D7 +dieresisbelowcmb;0324 +dieresiscmb;0308 +dieresisgrave;F6D8 +dieresistonos;0385 +dihiragana;3062 +dikatakana;30C2 +dittomark;3003 +divide;00F7 +divides;2223 +divisionslash;2215 +djecyrillic;0452 +dkshade;2593 +dlinebelow;1E0F +dlsquare;3397 +dmacron;0111 +dmonospace;FF44 +dnblock;2584 +dochadathai;0E0E +dodekthai;0E14 +dohiragana;3069 +dokatakana;30C9 +dollar;0024 +dollarinferior;F6E3 +dollarmonospace;FF04 +dollaroldstyle;F724 +dollarsmall;FE69 +dollarsuperior;F6E4 +dong;20AB +dorusquare;3326 +dotaccent;02D9 +dotaccentcmb;0307 +dotbelowcmb;0323 +dotbelowcomb;0323 +dotkatakana;30FB +dotlessi;0131 +dotlessj;F6BE +dotlessjstrokehook;0284 +dotmath;22C5 +dottedcircle;25CC +doubleyodpatah;FB1F +doubleyodpatahhebrew;FB1F +downtackbelowcmb;031E +downtackmod;02D5 +dparen;249F +dsuperior;F6EB +dtail;0256 +dtopbar;018C +duhiragana;3065 +dukatakana;30C5 +dz;01F3 +dzaltone;02A3 +dzcaron;01C6 +dzcurl;02A5 +dzeabkhasiancyrillic;04E1 +dzecyrillic;0455 +dzhecyrillic;045F +e;0065 +eacute;00E9 +earth;2641 +ebengali;098F +ebopomofo;311C +ebreve;0115 +ecandradeva;090D +ecandragujarati;0A8D +ecandravowelsigndeva;0945 +ecandravowelsigngujarati;0AC5 +ecaron;011B +ecedillabreve;1E1D +echarmenian;0565 +echyiwnarmenian;0587 +ecircle;24D4 +ecircumflex;00EA +ecircumflexacute;1EBF +ecircumflexbelow;1E19 +ecircumflexdotbelow;1EC7 +ecircumflexgrave;1EC1 +ecircumflexhookabove;1EC3 +ecircumflextilde;1EC5 +ecyrillic;0454 +edblgrave;0205 +edeva;090F +edieresis;00EB +edot;0117 +edotaccent;0117 +edotbelow;1EB9 +eegurmukhi;0A0F +eematragurmukhi;0A47 +efcyrillic;0444 +egrave;00E8 +egujarati;0A8F +eharmenian;0567 +ehbopomofo;311D +ehiragana;3048 +ehookabove;1EBB +eibopomofo;311F +eight;0038 +eightarabic;0668 +eightbengali;09EE +eightcircle;2467 +eightcircleinversesansserif;2791 +eightdeva;096E +eighteencircle;2471 +eighteenparen;2485 +eighteenperiod;2499 +eightgujarati;0AEE +eightgurmukhi;0A6E +eighthackarabic;0668 +eighthangzhou;3028 +eighthnotebeamed;266B +eightideographicparen;3227 +eightinferior;2088 +eightmonospace;FF18 +eightoldstyle;F738 +eightparen;247B +eightperiod;248F +eightpersian;06F8 +eightroman;2177 +eightsuperior;2078 +eightthai;0E58 +einvertedbreve;0207 +eiotifiedcyrillic;0465 +ekatakana;30A8 +ekatakanahalfwidth;FF74 +ekonkargurmukhi;0A74 +ekorean;3154 +elcyrillic;043B +element;2208 +elevencircle;246A +elevenparen;247E +elevenperiod;2492 +elevenroman;217A +ellipsis;2026 +ellipsisvertical;22EE +emacron;0113 +emacronacute;1E17 +emacrongrave;1E15 +emcyrillic;043C +emdash;2014 +emdashvertical;FE31 +emonospace;FF45 +emphasismarkarmenian;055B +emptyset;2205 +enbopomofo;3123 +encyrillic;043D +endash;2013 +endashvertical;FE32 +endescendercyrillic;04A3 +eng;014B +engbopomofo;3125 +enghecyrillic;04A5 +enhookcyrillic;04C8 +enspace;2002 +eogonek;0119 +eokorean;3153 +eopen;025B +eopenclosed;029A +eopenreversed;025C +eopenreversedclosed;025E +eopenreversedhook;025D +eparen;24A0 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equalmonospace;FF1D +equalsmall;FE66 +equalsuperior;207C +equivalence;2261 +erbopomofo;3126 +ercyrillic;0440 +ereversed;0258 +ereversedcyrillic;044D +escyrillic;0441 +esdescendercyrillic;04AB +esh;0283 +eshcurl;0286 +eshortdeva;090E +eshortvowelsigndeva;0946 +eshreversedloop;01AA +eshsquatreversed;0285 +esmallhiragana;3047 +esmallkatakana;30A7 +esmallkatakanahalfwidth;FF6A +estimated;212E +esuperior;F6EC +eta;03B7 +etarmenian;0568 +etatonos;03AE +eth;00F0 +etilde;1EBD +etildebelow;1E1B +etnahtafoukhhebrew;0591 +etnahtafoukhlefthebrew;0591 +etnahtahebrew;0591 +etnahtalefthebrew;0591 +eturned;01DD +eukorean;3161 +euro;20AC +evowelsignbengali;09C7 +evowelsigndeva;0947 +evowelsigngujarati;0AC7 +exclam;0021 +exclamarmenian;055C +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclammonospace;FF01 +exclamsmall;F721 +existential;2203 +ezh;0292 +ezhcaron;01EF +ezhcurl;0293 +ezhreversed;01B9 +ezhtail;01BA +f;0066 +fadeva;095E +fagurmukhi;0A5E +fahrenheit;2109 +fathaarabic;064E +fathalowarabic;064E +fathatanarabic;064B +fbopomofo;3108 +fcircle;24D5 +fdotaccent;1E1F +feharabic;0641 +feharmenian;0586 +fehfinalarabic;FED2 +fehinitialarabic;FED3 +fehmedialarabic;FED4 +feicoptic;03E5 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +fifteencircle;246E +fifteenparen;2482 +fifteenperiod;2496 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +finalkaf;05DA +finalkafdagesh;FB3A +finalkafdageshhebrew;FB3A +finalkafhebrew;05DA +finalkafqamats;05DA 05B8 +finalkafqamatshebrew;05DA 05B8 +finalkafsheva;05DA 05B0 +finalkafshevahebrew;05DA 05B0 +finalmem;05DD +finalmemhebrew;05DD +finalnun;05DF +finalnunhebrew;05DF +finalpe;05E3 +finalpehebrew;05E3 +finaltsadi;05E5 +finaltsadihebrew;05E5 +firsttonechinese;02C9 +fisheye;25C9 +fitacyrillic;0473 +five;0035 +fivearabic;0665 +fivebengali;09EB +fivecircle;2464 +fivecircleinversesansserif;278E +fivedeva;096B +fiveeighths;215D +fivegujarati;0AEB +fivegurmukhi;0A6B +fivehackarabic;0665 +fivehangzhou;3025 +fiveideographicparen;3224 +fiveinferior;2085 +fivemonospace;FF15 +fiveoldstyle;F735 +fiveparen;2478 +fiveperiod;248C +fivepersian;06F5 +fiveroman;2174 +fivesuperior;2075 +fivethai;0E55 +fl;FB02 +florin;0192 +fmonospace;FF46 +fmsquare;3399 +fofanthai;0E1F +fofathai;0E1D +fongmanthai;0E4F +forall;2200 +four;0034 +fourarabic;0664 +fourbengali;09EA +fourcircle;2463 +fourcircleinversesansserif;278D +fourdeva;096A +fourgujarati;0AEA +fourgurmukhi;0A6A +fourhackarabic;0664 +fourhangzhou;3024 +fourideographicparen;3223 +fourinferior;2084 +fourmonospace;FF14 +fournumeratorbengali;09F7 +fouroldstyle;F734 +fourparen;2477 +fourperiod;248B +fourpersian;06F4 +fourroman;2173 +foursuperior;2074 +fourteencircle;246D +fourteenparen;2481 +fourteenperiod;2495 +fourthai;0E54 +fourthtonechinese;02CB +fparen;24A1 +fraction;2044 +franc;20A3 +g;0067 +gabengali;0997 +gacute;01F5 +gadeva;0917 +gafarabic;06AF +gaffinalarabic;FB93 +gafinitialarabic;FB94 +gafmedialarabic;FB95 +gagujarati;0A97 +gagurmukhi;0A17 +gahiragana;304C +gakatakana;30AC +gamma;03B3 +gammalatinsmall;0263 +gammasuperior;02E0 +gangiacoptic;03EB +gbopomofo;310D +gbreve;011F +gcaron;01E7 +gcedilla;0123 +gcircle;24D6 +gcircumflex;011D +gcommaaccent;0123 +gdot;0121 +gdotaccent;0121 +gecyrillic;0433 +gehiragana;3052 +gekatakana;30B2 +geometricallyequal;2251 +gereshaccenthebrew;059C +gereshhebrew;05F3 +gereshmuqdamhebrew;059D +germandbls;00DF +gershayimaccenthebrew;059E +gershayimhebrew;05F4 +getamark;3013 +ghabengali;0998 +ghadarmenian;0572 +ghadeva;0918 +ghagujarati;0A98 +ghagurmukhi;0A18 +ghainarabic;063A +ghainfinalarabic;FECE +ghaininitialarabic;FECF +ghainmedialarabic;FED0 +ghemiddlehookcyrillic;0495 +ghestrokecyrillic;0493 +gheupturncyrillic;0491 +ghhadeva;095A +ghhagurmukhi;0A5A +ghook;0260 +ghzsquare;3393 +gihiragana;304E +gikatakana;30AE +gimarmenian;0563 +gimel;05D2 +gimeldagesh;FB32 +gimeldageshhebrew;FB32 +gimelhebrew;05D2 +gjecyrillic;0453 +glottalinvertedstroke;01BE +glottalstop;0294 +glottalstopinverted;0296 +glottalstopmod;02C0 +glottalstopreversed;0295 +glottalstopreversedmod;02C1 +glottalstopreversedsuperior;02E4 +glottalstopstroke;02A1 +glottalstopstrokereversed;02A2 +gmacron;1E21 +gmonospace;FF47 +gohiragana;3054 +gokatakana;30B4 +gparen;24A2 +gpasquare;33AC +gradient;2207 +grave;0060 +gravebelowcmb;0316 +gravecmb;0300 +gravecomb;0300 +gravedeva;0953 +gravelowmod;02CE +gravemonospace;FF40 +gravetonecmb;0340 +greater;003E +greaterequal;2265 +greaterequalorless;22DB +greatermonospace;FF1E +greaterorequivalent;2273 +greaterorless;2277 +greateroverequal;2267 +greatersmall;FE65 +gscript;0261 +gstroke;01E5 +guhiragana;3050 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +gukatakana;30B0 +guramusquare;3318 +gysquare;33C9 +h;0068 +haabkhasiancyrillic;04A9 +haaltonearabic;06C1 +habengali;09B9 +hadescendercyrillic;04B3 +hadeva;0939 +hagujarati;0AB9 +hagurmukhi;0A39 +haharabic;062D +hahfinalarabic;FEA2 +hahinitialarabic;FEA3 +hahiragana;306F +hahmedialarabic;FEA4 +haitusquare;332A +hakatakana;30CF +hakatakanahalfwidth;FF8A +halantgurmukhi;0A4D +hamzaarabic;0621 +hamzadammaarabic;0621 064F +hamzadammatanarabic;0621 064C +hamzafathaarabic;0621 064E +hamzafathatanarabic;0621 064B +hamzalowarabic;0621 +hamzalowkasraarabic;0621 0650 +hamzalowkasratanarabic;0621 064D +hamzasukunarabic;0621 0652 +hangulfiller;3164 +hardsigncyrillic;044A +harpoonleftbarbup;21BC +harpoonrightbarbup;21C0 +hasquare;33CA +hatafpatah;05B2 +hatafpatah16;05B2 +hatafpatah23;05B2 +hatafpatah2f;05B2 +hatafpatahhebrew;05B2 +hatafpatahnarrowhebrew;05B2 +hatafpatahquarterhebrew;05B2 +hatafpatahwidehebrew;05B2 +hatafqamats;05B3 +hatafqamats1b;05B3 +hatafqamats28;05B3 +hatafqamats34;05B3 +hatafqamatshebrew;05B3 +hatafqamatsnarrowhebrew;05B3 +hatafqamatsquarterhebrew;05B3 +hatafqamatswidehebrew;05B3 +hatafsegol;05B1 +hatafsegol17;05B1 +hatafsegol24;05B1 +hatafsegol30;05B1 +hatafsegolhebrew;05B1 +hatafsegolnarrowhebrew;05B1 +hatafsegolquarterhebrew;05B1 +hatafsegolwidehebrew;05B1 +hbar;0127 +hbopomofo;310F +hbrevebelow;1E2B +hcedilla;1E29 +hcircle;24D7 +hcircumflex;0125 +hdieresis;1E27 +hdotaccent;1E23 +hdotbelow;1E25 +he;05D4 +heart;2665 +heartsuitblack;2665 +heartsuitwhite;2661 +hedagesh;FB34 +hedageshhebrew;FB34 +hehaltonearabic;06C1 +heharabic;0647 +hehebrew;05D4 +hehfinalaltonearabic;FBA7 +hehfinalalttwoarabic;FEEA +hehfinalarabic;FEEA +hehhamzaabovefinalarabic;FBA5 +hehhamzaaboveisolatedarabic;FBA4 +hehinitialaltonearabic;FBA8 +hehinitialarabic;FEEB +hehiragana;3078 +hehmedialaltonearabic;FBA9 +hehmedialarabic;FEEC +heiseierasquare;337B +hekatakana;30D8 +hekatakanahalfwidth;FF8D +hekutaarusquare;3336 +henghook;0267 +herutusquare;3339 +het;05D7 +hethebrew;05D7 +hhook;0266 +hhooksuperior;02B1 +hieuhacirclekorean;327B +hieuhaparenkorean;321B +hieuhcirclekorean;326D +hieuhkorean;314E +hieuhparenkorean;320D +hihiragana;3072 +hikatakana;30D2 +hikatakanahalfwidth;FF8B +hiriq;05B4 +hiriq14;05B4 +hiriq21;05B4 +hiriq2d;05B4 +hiriqhebrew;05B4 +hiriqnarrowhebrew;05B4 +hiriqquarterhebrew;05B4 +hiriqwidehebrew;05B4 +hlinebelow;1E96 +hmonospace;FF48 +hoarmenian;0570 +hohipthai;0E2B +hohiragana;307B +hokatakana;30DB +hokatakanahalfwidth;FF8E +holam;05B9 +holam19;05B9 +holam26;05B9 +holam32;05B9 +holamhebrew;05B9 +holamnarrowhebrew;05B9 +holamquarterhebrew;05B9 +holamwidehebrew;05B9 +honokhukthai;0E2E +hookabovecomb;0309 +hookcmb;0309 +hookpalatalizedbelowcmb;0321 +hookretroflexbelowcmb;0322 +hoonsquare;3342 +horicoptic;03E9 +horizontalbar;2015 +horncmb;031B +hotsprings;2668 +house;2302 +hparen;24A3 +hsuperior;02B0 +hturned;0265 +huhiragana;3075 +huiitosquare;3333 +hukatakana;30D5 +hukatakanahalfwidth;FF8C +hungarumlaut;02DD +hungarumlautcmb;030B +hv;0195 +hyphen;002D +hypheninferior;F6E5 +hyphenmonospace;FF0D +hyphensmall;FE63 +hyphensuperior;F6E6 +hyphentwo;2010 +i;0069 +iacute;00ED +iacyrillic;044F +ibengali;0987 +ibopomofo;3127 +ibreve;012D +icaron;01D0 +icircle;24D8 +icircumflex;00EE +icyrillic;0456 +idblgrave;0209 +ideographearthcircle;328F +ideographfirecircle;328B +ideographicallianceparen;323F +ideographiccallparen;323A +ideographiccentrecircle;32A5 +ideographicclose;3006 +ideographiccomma;3001 +ideographiccommaleft;FF64 +ideographiccongratulationparen;3237 +ideographiccorrectcircle;32A3 +ideographicearthparen;322F +ideographicenterpriseparen;323D +ideographicexcellentcircle;329D +ideographicfestivalparen;3240 +ideographicfinancialcircle;3296 +ideographicfinancialparen;3236 +ideographicfireparen;322B +ideographichaveparen;3232 +ideographichighcircle;32A4 +ideographiciterationmark;3005 +ideographiclaborcircle;3298 +ideographiclaborparen;3238 +ideographicleftcircle;32A7 +ideographiclowcircle;32A6 +ideographicmedicinecircle;32A9 +ideographicmetalparen;322E +ideographicmoonparen;322A +ideographicnameparen;3234 +ideographicperiod;3002 +ideographicprintcircle;329E +ideographicreachparen;3243 +ideographicrepresentparen;3239 +ideographicresourceparen;323E +ideographicrightcircle;32A8 +ideographicsecretcircle;3299 +ideographicselfparen;3242 +ideographicsocietyparen;3233 +ideographicspace;3000 +ideographicspecialparen;3235 +ideographicstockparen;3231 +ideographicstudyparen;323B +ideographicsunparen;3230 +ideographicsuperviseparen;323C +ideographicwaterparen;322C +ideographicwoodparen;322D +ideographiczero;3007 +ideographmetalcircle;328E +ideographmooncircle;328A +ideographnamecircle;3294 +ideographsuncircle;3290 +ideographwatercircle;328C +ideographwoodcircle;328D +ideva;0907 +idieresis;00EF +idieresisacute;1E2F +idieresiscyrillic;04E5 +idotbelow;1ECB +iebrevecyrillic;04D7 +iecyrillic;0435 +ieungacirclekorean;3275 +ieungaparenkorean;3215 +ieungcirclekorean;3267 +ieungkorean;3147 +ieungparenkorean;3207 +igrave;00EC +igujarati;0A87 +igurmukhi;0A07 +ihiragana;3044 +ihookabove;1EC9 +iibengali;0988 +iicyrillic;0438 +iideva;0908 +iigujarati;0A88 +iigurmukhi;0A08 +iimatragurmukhi;0A40 +iinvertedbreve;020B +iishortcyrillic;0439 +iivowelsignbengali;09C0 +iivowelsigndeva;0940 +iivowelsigngujarati;0AC0 +ij;0133 +ikatakana;30A4 +ikatakanahalfwidth;FF72 +ikorean;3163 +ilde;02DC +iluyhebrew;05AC +imacron;012B +imacroncyrillic;04E3 +imageorapproximatelyequal;2253 +imatragurmukhi;0A3F +imonospace;FF49 +increment;2206 +infinity;221E +iniarmenian;056B +integral;222B +integralbottom;2321 +integralbt;2321 +integralex;F8F5 +integraltop;2320 +integraltp;2320 +intersection;2229 +intisquare;3305 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iocyrillic;0451 +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotalatin;0269 +iotatonos;03AF +iparen;24A4 +irigurmukhi;0A72 +ismallhiragana;3043 +ismallkatakana;30A3 +ismallkatakanahalfwidth;FF68 +issharbengali;09FA +istroke;0268 +isuperior;F6ED +iterationhiragana;309D +iterationkatakana;30FD +itilde;0129 +itildebelow;1E2D +iubopomofo;3129 +iucyrillic;044E +ivowelsignbengali;09BF +ivowelsigndeva;093F +ivowelsigngujarati;0ABF +izhitsacyrillic;0475 +izhitsadblgravecyrillic;0477 +j;006A +jaarmenian;0571 +jabengali;099C +jadeva;091C +jagujarati;0A9C +jagurmukhi;0A1C +jbopomofo;3110 +jcaron;01F0 +jcircle;24D9 +jcircumflex;0135 +jcrossedtail;029D +jdotlessstroke;025F +jecyrillic;0458 +jeemarabic;062C +jeemfinalarabic;FE9E +jeeminitialarabic;FE9F +jeemmedialarabic;FEA0 +jeharabic;0698 +jehfinalarabic;FB8B +jhabengali;099D +jhadeva;091D +jhagujarati;0A9D +jhagurmukhi;0A1D +jheharmenian;057B +jis;3004 +jmonospace;FF4A +jparen;24A5 +jsuperior;02B2 +k;006B +kabashkircyrillic;04A1 +kabengali;0995 +kacute;1E31 +kacyrillic;043A +kadescendercyrillic;049B +kadeva;0915 +kaf;05DB +kafarabic;0643 +kafdagesh;FB3B +kafdageshhebrew;FB3B +kaffinalarabic;FEDA +kafhebrew;05DB +kafinitialarabic;FEDB +kafmedialarabic;FEDC +kafrafehebrew;FB4D +kagujarati;0A95 +kagurmukhi;0A15 +kahiragana;304B +kahookcyrillic;04C4 +kakatakana;30AB +kakatakanahalfwidth;FF76 +kappa;03BA +kappasymbolgreek;03F0 +kapyeounmieumkorean;3171 +kapyeounphieuphkorean;3184 +kapyeounpieupkorean;3178 +kapyeounssangpieupkorean;3179 +karoriisquare;330D +kashidaautoarabic;0640 +kashidaautonosidebearingarabic;0640 +kasmallkatakana;30F5 +kasquare;3384 +kasraarabic;0650 +kasratanarabic;064D +kastrokecyrillic;049F +katahiraprolongmarkhalfwidth;FF70 +kaverticalstrokecyrillic;049D +kbopomofo;310E +kcalsquare;3389 +kcaron;01E9 +kcedilla;0137 +kcircle;24DA +kcommaaccent;0137 +kdotbelow;1E33 +keharmenian;0584 +kehiragana;3051 +kekatakana;30B1 +kekatakanahalfwidth;FF79 +kenarmenian;056F +kesmallkatakana;30F6 +kgreenlandic;0138 +khabengali;0996 +khacyrillic;0445 +khadeva;0916 +khagujarati;0A96 +khagurmukhi;0A16 +khaharabic;062E +khahfinalarabic;FEA6 +khahinitialarabic;FEA7 +khahmedialarabic;FEA8 +kheicoptic;03E7 +khhadeva;0959 +khhagurmukhi;0A59 +khieukhacirclekorean;3278 +khieukhaparenkorean;3218 +khieukhcirclekorean;326A +khieukhkorean;314B +khieukhparenkorean;320A +khokhaithai;0E02 +khokhonthai;0E05 +khokhuatthai;0E03 +khokhwaithai;0E04 +khomutthai;0E5B +khook;0199 +khorakhangthai;0E06 +khzsquare;3391 +kihiragana;304D +kikatakana;30AD +kikatakanahalfwidth;FF77 +kiroguramusquare;3315 +kiromeetorusquare;3316 +kirosquare;3314 +kiyeokacirclekorean;326E +kiyeokaparenkorean;320E +kiyeokcirclekorean;3260 +kiyeokkorean;3131 +kiyeokparenkorean;3200 +kiyeoksioskorean;3133 +kjecyrillic;045C +klinebelow;1E35 +klsquare;3398 +kmcubedsquare;33A6 +kmonospace;FF4B +kmsquaredsquare;33A2 +kohiragana;3053 +kohmsquare;33C0 +kokaithai;0E01 +kokatakana;30B3 +kokatakanahalfwidth;FF7A +kooposquare;331E +koppacyrillic;0481 +koreanstandardsymbol;327F +koroniscmb;0343 +kparen;24A6 +kpasquare;33AA +ksicyrillic;046F +ktsquare;33CF +kturned;029E +kuhiragana;304F +kukatakana;30AF +kukatakanahalfwidth;FF78 +kvsquare;33B8 +kwsquare;33BE +l;006C +labengali;09B2 +lacute;013A +ladeva;0932 +lagujarati;0AB2 +lagurmukhi;0A32 +lakkhangyaothai;0E45 +lamaleffinalarabic;FEFC +lamalefhamzaabovefinalarabic;FEF8 +lamalefhamzaaboveisolatedarabic;FEF7 +lamalefhamzabelowfinalarabic;FEFA +lamalefhamzabelowisolatedarabic;FEF9 +lamalefisolatedarabic;FEFB +lamalefmaddaabovefinalarabic;FEF6 +lamalefmaddaaboveisolatedarabic;FEF5 +lamarabic;0644 +lambda;03BB +lambdastroke;019B +lamed;05DC +lameddagesh;FB3C +lameddageshhebrew;FB3C +lamedhebrew;05DC +lamedholam;05DC 05B9 +lamedholamdagesh;05DC 05B9 05BC +lamedholamdageshhebrew;05DC 05B9 05BC +lamedholamhebrew;05DC 05B9 +lamfinalarabic;FEDE +lamhahinitialarabic;FCCA +laminitialarabic;FEDF +lamjeeminitialarabic;FCC9 +lamkhahinitialarabic;FCCB +lamlamhehisolatedarabic;FDF2 +lammedialarabic;FEE0 +lammeemhahinitialarabic;FD88 +lammeeminitialarabic;FCCC +lammeemjeeminitialarabic;FEDF FEE4 FEA0 +lammeemkhahinitialarabic;FEDF FEE4 FEA8 +largecircle;25EF +lbar;019A +lbelt;026C +lbopomofo;310C +lcaron;013E +lcedilla;013C +lcircle;24DB +lcircumflexbelow;1E3D +lcommaaccent;013C +ldot;0140 +ldotaccent;0140 +ldotbelow;1E37 +ldotbelowmacron;1E39 +leftangleabovecmb;031A +lefttackbelowcmb;0318 +less;003C +lessequal;2264 +lessequalorgreater;22DA +lessmonospace;FF1C +lessorequivalent;2272 +lessorgreater;2276 +lessoverequal;2266 +lesssmall;FE64 +lezh;026E +lfblock;258C +lhookretroflex;026D +lira;20A4 +liwnarmenian;056C +lj;01C9 +ljecyrillic;0459 +ll;F6C0 +lladeva;0933 +llagujarati;0AB3 +llinebelow;1E3B +llladeva;0934 +llvocalicbengali;09E1 +llvocalicdeva;0961 +llvocalicvowelsignbengali;09E3 +llvocalicvowelsigndeva;0963 +lmiddletilde;026B +lmonospace;FF4C +lmsquare;33D0 +lochulathai;0E2C +logicaland;2227 +logicalnot;00AC +logicalnotreversed;2310 +logicalor;2228 +lolingthai;0E25 +longs;017F +lowlinecenterline;FE4E +lowlinecmb;0332 +lowlinedashed;FE4D +lozenge;25CA +lparen;24A7 +lslash;0142 +lsquare;2113 +lsuperior;F6EE +ltshade;2591 +luthai;0E26 +lvocalicbengali;098C +lvocalicdeva;090C +lvocalicvowelsignbengali;09E2 +lvocalicvowelsigndeva;0962 +lxsquare;33D3 +m;006D +mabengali;09AE +macron;00AF +macronbelowcmb;0331 +macroncmb;0304 +macronlowmod;02CD +macronmonospace;FFE3 +macute;1E3F +madeva;092E +magujarati;0AAE +magurmukhi;0A2E +mahapakhhebrew;05A4 +mahapakhlefthebrew;05A4 +mahiragana;307E +maichattawalowleftthai;F895 +maichattawalowrightthai;F894 +maichattawathai;0E4B +maichattawaupperleftthai;F893 +maieklowleftthai;F88C +maieklowrightthai;F88B +maiekthai;0E48 +maiekupperleftthai;F88A +maihanakatleftthai;F884 +maihanakatthai;0E31 +maitaikhuleftthai;F889 +maitaikhuthai;0E47 +maitholowleftthai;F88F +maitholowrightthai;F88E +maithothai;0E49 +maithoupperleftthai;F88D +maitrilowleftthai;F892 +maitrilowrightthai;F891 +maitrithai;0E4A +maitriupperleftthai;F890 +maiyamokthai;0E46 +makatakana;30DE +makatakanahalfwidth;FF8F +male;2642 +mansyonsquare;3347 +maqafhebrew;05BE +mars;2642 +masoracirclehebrew;05AF +masquare;3383 +mbopomofo;3107 +mbsquare;33D4 +mcircle;24DC +mcubedsquare;33A5 +mdotaccent;1E41 +mdotbelow;1E43 +meemarabic;0645 +meemfinalarabic;FEE2 +meeminitialarabic;FEE3 +meemmedialarabic;FEE4 +meemmeeminitialarabic;FCD1 +meemmeemisolatedarabic;FC48 +meetorusquare;334D +mehiragana;3081 +meizierasquare;337E +mekatakana;30E1 +mekatakanahalfwidth;FF92 +mem;05DE +memdagesh;FB3E +memdageshhebrew;FB3E +memhebrew;05DE +menarmenian;0574 +merkhahebrew;05A5 +merkhakefulahebrew;05A6 +merkhakefulalefthebrew;05A6 +merkhalefthebrew;05A5 +mhook;0271 +mhzsquare;3392 +middledotkatakanahalfwidth;FF65 +middot;00B7 +mieumacirclekorean;3272 +mieumaparenkorean;3212 +mieumcirclekorean;3264 +mieumkorean;3141 +mieumpansioskorean;3170 +mieumparenkorean;3204 +mieumpieupkorean;316E +mieumsioskorean;316F +mihiragana;307F +mikatakana;30DF +mikatakanahalfwidth;FF90 +minus;2212 +minusbelowcmb;0320 +minuscircle;2296 +minusmod;02D7 +minusplus;2213 +minute;2032 +miribaarusquare;334A +mirisquare;3349 +mlonglegturned;0270 +mlsquare;3396 +mmcubedsquare;33A3 +mmonospace;FF4D +mmsquaredsquare;339F +mohiragana;3082 +mohmsquare;33C1 +mokatakana;30E2 +mokatakanahalfwidth;FF93 +molsquare;33D6 +momathai;0E21 +moverssquare;33A7 +moverssquaredsquare;33A8 +mparen;24A8 +mpasquare;33AB +mssquare;33B3 +msuperior;F6EF +mturned;026F +mu;00B5 +mu1;00B5 +muasquare;3382 +muchgreater;226B +muchless;226A +mufsquare;338C +mugreek;03BC +mugsquare;338D +muhiragana;3080 +mukatakana;30E0 +mukatakanahalfwidth;FF91 +mulsquare;3395 +multiply;00D7 +mumsquare;339B +munahhebrew;05A3 +munahlefthebrew;05A3 +musicalnote;266A +musicalnotedbl;266B +musicflatsign;266D +musicsharpsign;266F +mussquare;33B2 +muvsquare;33B6 +muwsquare;33BC +mvmegasquare;33B9 +mvsquare;33B7 +mwmegasquare;33BF +mwsquare;33BD +n;006E +nabengali;09A8 +nabla;2207 +nacute;0144 +nadeva;0928 +nagujarati;0AA8 +nagurmukhi;0A28 +nahiragana;306A +nakatakana;30CA +nakatakanahalfwidth;FF85 +napostrophe;0149 +nasquare;3381 +nbopomofo;310B +nbspace;00A0 +ncaron;0148 +ncedilla;0146 +ncircle;24DD +ncircumflexbelow;1E4B +ncommaaccent;0146 +ndotaccent;1E45 +ndotbelow;1E47 +nehiragana;306D +nekatakana;30CD +nekatakanahalfwidth;FF88 +newsheqelsign;20AA +nfsquare;338B +ngabengali;0999 +ngadeva;0919 +ngagujarati;0A99 +ngagurmukhi;0A19 +ngonguthai;0E07 +nhiragana;3093 +nhookleft;0272 +nhookretroflex;0273 +nieunacirclekorean;326F +nieunaparenkorean;320F +nieuncieuckorean;3135 +nieuncirclekorean;3261 +nieunhieuhkorean;3136 +nieunkorean;3134 +nieunpansioskorean;3168 +nieunparenkorean;3201 +nieunsioskorean;3167 +nieuntikeutkorean;3166 +nihiragana;306B +nikatakana;30CB +nikatakanahalfwidth;FF86 +nikhahitleftthai;F899 +nikhahitthai;0E4D +nine;0039 +ninearabic;0669 +ninebengali;09EF +ninecircle;2468 +ninecircleinversesansserif;2792 +ninedeva;096F +ninegujarati;0AEF +ninegurmukhi;0A6F +ninehackarabic;0669 +ninehangzhou;3029 +nineideographicparen;3228 +nineinferior;2089 +ninemonospace;FF19 +nineoldstyle;F739 +nineparen;247C +nineperiod;2490 +ninepersian;06F9 +nineroman;2178 +ninesuperior;2079 +nineteencircle;2472 +nineteenparen;2486 +nineteenperiod;249A +ninethai;0E59 +nj;01CC +njecyrillic;045A +nkatakana;30F3 +nkatakanahalfwidth;FF9D +nlegrightlong;019E +nlinebelow;1E49 +nmonospace;FF4E +nmsquare;339A +nnabengali;09A3 +nnadeva;0923 +nnagujarati;0AA3 +nnagurmukhi;0A23 +nnnadeva;0929 +nohiragana;306E +nokatakana;30CE +nokatakanahalfwidth;FF89 +nonbreakingspace;00A0 +nonenthai;0E13 +nonuthai;0E19 +noonarabic;0646 +noonfinalarabic;FEE6 +noonghunnaarabic;06BA +noonghunnafinalarabic;FB9F +noonhehinitialarabic;FEE7 FEEC +nooninitialarabic;FEE7 +noonjeeminitialarabic;FCD2 +noonjeemisolatedarabic;FC4B +noonmedialarabic;FEE8 +noonmeeminitialarabic;FCD5 +noonmeemisolatedarabic;FC4E +noonnoonfinalarabic;FC8D +notcontains;220C +notelement;2209 +notelementof;2209 +notequal;2260 +notgreater;226F +notgreaternorequal;2271 +notgreaternorless;2279 +notidentical;2262 +notless;226E +notlessnorequal;2270 +notparallel;2226 +notprecedes;2280 +notsubset;2284 +notsucceeds;2281 +notsuperset;2285 +nowarmenian;0576 +nparen;24A9 +nssquare;33B1 +nsuperior;207F +ntilde;00F1 +nu;03BD +nuhiragana;306C +nukatakana;30CC +nukatakanahalfwidth;FF87 +nuktabengali;09BC +nuktadeva;093C +nuktagujarati;0ABC +nuktagurmukhi;0A3C +numbersign;0023 +numbersignmonospace;FF03 +numbersignsmall;FE5F +numeralsigngreek;0374 +numeralsignlowergreek;0375 +numero;2116 +nun;05E0 +nundagesh;FB40 +nundageshhebrew;FB40 +nunhebrew;05E0 +nvsquare;33B5 +nwsquare;33BB +nyabengali;099E +nyadeva;091E +nyagujarati;0A9E +nyagurmukhi;0A1E +o;006F +oacute;00F3 +oangthai;0E2D +obarred;0275 +obarredcyrillic;04E9 +obarreddieresiscyrillic;04EB +obengali;0993 +obopomofo;311B +obreve;014F +ocandradeva;0911 +ocandragujarati;0A91 +ocandravowelsigndeva;0949 +ocandravowelsigngujarati;0AC9 +ocaron;01D2 +ocircle;24DE +ocircumflex;00F4 +ocircumflexacute;1ED1 +ocircumflexdotbelow;1ED9 +ocircumflexgrave;1ED3 +ocircumflexhookabove;1ED5 +ocircumflextilde;1ED7 +ocyrillic;043E +odblacute;0151 +odblgrave;020D +odeva;0913 +odieresis;00F6 +odieresiscyrillic;04E7 +odotbelow;1ECD +oe;0153 +oekorean;315A +ogonek;02DB +ogonekcmb;0328 +ograve;00F2 +ogujarati;0A93 +oharmenian;0585 +ohiragana;304A +ohookabove;1ECF +ohorn;01A1 +ohornacute;1EDB +ohorndotbelow;1EE3 +ohorngrave;1EDD +ohornhookabove;1EDF +ohorntilde;1EE1 +ohungarumlaut;0151 +oi;01A3 +oinvertedbreve;020F +okatakana;30AA +okatakanahalfwidth;FF75 +okorean;3157 +olehebrew;05AB +omacron;014D +omacronacute;1E53 +omacrongrave;1E51 +omdeva;0950 +omega;03C9 +omega1;03D6 +omegacyrillic;0461 +omegalatinclosed;0277 +omegaroundcyrillic;047B +omegatitlocyrillic;047D +omegatonos;03CE +omgujarati;0AD0 +omicron;03BF +omicrontonos;03CC +omonospace;FF4F +one;0031 +onearabic;0661 +onebengali;09E7 +onecircle;2460 +onecircleinversesansserif;278A +onedeva;0967 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onegujarati;0AE7 +onegurmukhi;0A67 +onehackarabic;0661 +onehalf;00BD +onehangzhou;3021 +oneideographicparen;3220 +oneinferior;2081 +onemonospace;FF11 +onenumeratorbengali;09F4 +oneoldstyle;F731 +oneparen;2474 +oneperiod;2488 +onepersian;06F1 +onequarter;00BC +oneroman;2170 +onesuperior;00B9 +onethai;0E51 +onethird;2153 +oogonek;01EB +oogonekmacron;01ED +oogurmukhi;0A13 +oomatragurmukhi;0A4B +oopen;0254 +oparen;24AA +openbullet;25E6 +option;2325 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oshortdeva;0912 +oshortvowelsigndeva;094A +oslash;00F8 +oslashacute;01FF +osmallhiragana;3049 +osmallkatakana;30A9 +osmallkatakanahalfwidth;FF6B +ostrokeacute;01FF +osuperior;F6F0 +otcyrillic;047F +otilde;00F5 +otildeacute;1E4D +otildedieresis;1E4F +oubopomofo;3121 +overline;203E +overlinecenterline;FE4A +overlinecmb;0305 +overlinedashed;FE49 +overlinedblwavy;FE4C +overlinewavy;FE4B +overscore;00AF +ovowelsignbengali;09CB +ovowelsigndeva;094B +ovowelsigngujarati;0ACB +p;0070 +paampssquare;3380 +paasentosquare;332B +pabengali;09AA +pacute;1E55 +padeva;092A +pagedown;21DF +pageup;21DE +pagujarati;0AAA +pagurmukhi;0A2A +pahiragana;3071 +paiyannoithai;0E2F +pakatakana;30D1 +palatalizationcyrilliccmb;0484 +palochkacyrillic;04C0 +pansioskorean;317F +paragraph;00B6 +parallel;2225 +parenleft;0028 +parenleftaltonearabic;FD3E +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftmonospace;FF08 +parenleftsmall;FE59 +parenleftsuperior;207D +parenlefttp;F8EB +parenleftvertical;FE35 +parenright;0029 +parenrightaltonearabic;FD3F +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightmonospace;FF09 +parenrightsmall;FE5A +parenrightsuperior;207E +parenrighttp;F8F6 +parenrightvertical;FE36 +partialdiff;2202 +paseqhebrew;05C0 +pashtahebrew;0599 +pasquare;33A9 +patah;05B7 +patah11;05B7 +patah1d;05B7 +patah2a;05B7 +patahhebrew;05B7 +patahnarrowhebrew;05B7 +patahquarterhebrew;05B7 +patahwidehebrew;05B7 +pazerhebrew;05A1 +pbopomofo;3106 +pcircle;24DF +pdotaccent;1E57 +pe;05E4 +pecyrillic;043F +pedagesh;FB44 +pedageshhebrew;FB44 +peezisquare;333B +pefinaldageshhebrew;FB43 +peharabic;067E +peharmenian;057A +pehebrew;05E4 +pehfinalarabic;FB57 +pehinitialarabic;FB58 +pehiragana;307A +pehmedialarabic;FB59 +pekatakana;30DA +pemiddlehookcyrillic;04A7 +perafehebrew;FB4E +percent;0025 +percentarabic;066A +percentmonospace;FF05 +percentsmall;FE6A +period;002E +periodarmenian;0589 +periodcentered;00B7 +periodhalfwidth;FF61 +periodinferior;F6E7 +periodmonospace;FF0E +periodsmall;FE52 +periodsuperior;F6E8 +perispomenigreekcmb;0342 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +pfsquare;338A +phabengali;09AB +phadeva;092B +phagujarati;0AAB +phagurmukhi;0A2B +phi;03C6 +phi1;03D5 +phieuphacirclekorean;327A +phieuphaparenkorean;321A +phieuphcirclekorean;326C +phieuphkorean;314D +phieuphparenkorean;320C +philatin;0278 +phinthuthai;0E3A +phisymbolgreek;03D5 +phook;01A5 +phophanthai;0E1E +phophungthai;0E1C +phosamphaothai;0E20 +pi;03C0 +pieupacirclekorean;3273 +pieupaparenkorean;3213 +pieupcieuckorean;3176 +pieupcirclekorean;3265 +pieupkiyeokkorean;3172 +pieupkorean;3142 +pieupparenkorean;3205 +pieupsioskiyeokkorean;3174 +pieupsioskorean;3144 +pieupsiostikeutkorean;3175 +pieupthieuthkorean;3177 +pieuptikeutkorean;3173 +pihiragana;3074 +pikatakana;30D4 +pisymbolgreek;03D6 +piwrarmenian;0583 +plus;002B +plusbelowcmb;031F +pluscircle;2295 +plusminus;00B1 +plusmod;02D6 +plusmonospace;FF0B +plussmall;FE62 +plussuperior;207A +pmonospace;FF50 +pmsquare;33D8 +pohiragana;307D +pointingindexdownwhite;261F +pointingindexleftwhite;261C +pointingindexrightwhite;261E +pointingindexupwhite;261D +pokatakana;30DD +poplathai;0E1B +postalmark;3012 +postalmarkface;3020 +pparen;24AB +precedes;227A +prescription;211E +primemod;02B9 +primereversed;2035 +product;220F +projective;2305 +prolongedkana;30FC +propellor;2318 +propersubset;2282 +propersuperset;2283 +proportion;2237 +proportional;221D +psi;03C8 +psicyrillic;0471 +psilipneumatacyrilliccmb;0486 +pssquare;33B0 +puhiragana;3077 +pukatakana;30D7 +pvsquare;33B4 +pwsquare;33BA +q;0071 +qadeva;0958 +qadmahebrew;05A8 +qafarabic;0642 +qaffinalarabic;FED6 +qafinitialarabic;FED7 +qafmedialarabic;FED8 +qamats;05B8 +qamats10;05B8 +qamats1a;05B8 +qamats1c;05B8 +qamats27;05B8 +qamats29;05B8 +qamats33;05B8 +qamatsde;05B8 +qamatshebrew;05B8 +qamatsnarrowhebrew;05B8 +qamatsqatanhebrew;05B8 +qamatsqatannarrowhebrew;05B8 +qamatsqatanquarterhebrew;05B8 +qamatsqatanwidehebrew;05B8 +qamatsquarterhebrew;05B8 +qamatswidehebrew;05B8 +qarneyparahebrew;059F +qbopomofo;3111 +qcircle;24E0 +qhook;02A0 +qmonospace;FF51 +qof;05E7 +qofdagesh;FB47 +qofdageshhebrew;FB47 +qofhatafpatah;05E7 05B2 +qofhatafpatahhebrew;05E7 05B2 +qofhatafsegol;05E7 05B1 +qofhatafsegolhebrew;05E7 05B1 +qofhebrew;05E7 +qofhiriq;05E7 05B4 +qofhiriqhebrew;05E7 05B4 +qofholam;05E7 05B9 +qofholamhebrew;05E7 05B9 +qofpatah;05E7 05B7 +qofpatahhebrew;05E7 05B7 +qofqamats;05E7 05B8 +qofqamatshebrew;05E7 05B8 +qofqubuts;05E7 05BB +qofqubutshebrew;05E7 05BB +qofsegol;05E7 05B6 +qofsegolhebrew;05E7 05B6 +qofsheva;05E7 05B0 +qofshevahebrew;05E7 05B0 +qoftsere;05E7 05B5 +qoftserehebrew;05E7 05B5 +qparen;24AC +quarternote;2669 +qubuts;05BB +qubuts18;05BB +qubuts25;05BB +qubuts31;05BB +qubutshebrew;05BB +qubutsnarrowhebrew;05BB +qubutsquarterhebrew;05BB +qubutswidehebrew;05BB +question;003F +questionarabic;061F +questionarmenian;055E +questiondown;00BF +questiondownsmall;F7BF +questiongreek;037E +questionmonospace;FF1F +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblmonospace;FF02 +quotedblprime;301E +quotedblprimereversed;301D +quotedblright;201D +quoteleft;2018 +quoteleftreversed;201B +quotereversed;201B +quoteright;2019 +quoterightn;0149 +quotesinglbase;201A +quotesingle;0027 +quotesinglemonospace;FF07 +r;0072 +raarmenian;057C +rabengali;09B0 +racute;0155 +radeva;0930 +radical;221A +radicalex;F8E5 +radoverssquare;33AE +radoverssquaredsquare;33AF +radsquare;33AD +rafe;05BF +rafehebrew;05BF +ragujarati;0AB0 +ragurmukhi;0A30 +rahiragana;3089 +rakatakana;30E9 +rakatakanahalfwidth;FF97 +ralowerdiagonalbengali;09F1 +ramiddlediagonalbengali;09F0 +ramshorn;0264 +ratio;2236 +rbopomofo;3116 +rcaron;0159 +rcedilla;0157 +rcircle;24E1 +rcommaaccent;0157 +rdblgrave;0211 +rdotaccent;1E59 +rdotbelow;1E5B +rdotbelowmacron;1E5D +referencemark;203B +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +reharabic;0631 +reharmenian;0580 +rehfinalarabic;FEAE +rehiragana;308C +rehyehaleflamarabic;0631 FEF3 FE8E 0644 +rekatakana;30EC +rekatakanahalfwidth;FF9A +resh;05E8 +reshdageshhebrew;FB48 +reshhatafpatah;05E8 05B2 +reshhatafpatahhebrew;05E8 05B2 +reshhatafsegol;05E8 05B1 +reshhatafsegolhebrew;05E8 05B1 +reshhebrew;05E8 +reshhiriq;05E8 05B4 +reshhiriqhebrew;05E8 05B4 +reshholam;05E8 05B9 +reshholamhebrew;05E8 05B9 +reshpatah;05E8 05B7 +reshpatahhebrew;05E8 05B7 +reshqamats;05E8 05B8 +reshqamatshebrew;05E8 05B8 +reshqubuts;05E8 05BB +reshqubutshebrew;05E8 05BB +reshsegol;05E8 05B6 +reshsegolhebrew;05E8 05B6 +reshsheva;05E8 05B0 +reshshevahebrew;05E8 05B0 +reshtsere;05E8 05B5 +reshtserehebrew;05E8 05B5 +reversedtilde;223D +reviahebrew;0597 +reviamugrashhebrew;0597 +revlogicalnot;2310 +rfishhook;027E +rfishhookreversed;027F +rhabengali;09DD +rhadeva;095D +rho;03C1 +rhook;027D +rhookturned;027B +rhookturnedsuperior;02B5 +rhosymbolgreek;03F1 +rhotichookmod;02DE +rieulacirclekorean;3271 +rieulaparenkorean;3211 +rieulcirclekorean;3263 +rieulhieuhkorean;3140 +rieulkiyeokkorean;313A +rieulkiyeoksioskorean;3169 +rieulkorean;3139 +rieulmieumkorean;313B +rieulpansioskorean;316C +rieulparenkorean;3203 +rieulphieuphkorean;313F +rieulpieupkorean;313C +rieulpieupsioskorean;316B +rieulsioskorean;313D +rieulthieuthkorean;313E +rieultikeutkorean;316A +rieulyeorinhieuhkorean;316D +rightangle;221F +righttackbelowcmb;0319 +righttriangle;22BF +rihiragana;308A +rikatakana;30EA +rikatakanahalfwidth;FF98 +ring;02DA +ringbelowcmb;0325 +ringcmb;030A +ringhalfleft;02BF +ringhalfleftarmenian;0559 +ringhalfleftbelowcmb;031C +ringhalfleftcentered;02D3 +ringhalfright;02BE +ringhalfrightbelowcmb;0339 +ringhalfrightcentered;02D2 +rinvertedbreve;0213 +rittorusquare;3351 +rlinebelow;1E5F +rlongleg;027C +rlonglegturned;027A +rmonospace;FF52 +rohiragana;308D +rokatakana;30ED +rokatakanahalfwidth;FF9B +roruathai;0E23 +rparen;24AD +rrabengali;09DC +rradeva;0931 +rragurmukhi;0A5C +rreharabic;0691 +rrehfinalarabic;FB8D +rrvocalicbengali;09E0 +rrvocalicdeva;0960 +rrvocalicgujarati;0AE0 +rrvocalicvowelsignbengali;09C4 +rrvocalicvowelsigndeva;0944 +rrvocalicvowelsigngujarati;0AC4 +rsuperior;F6F1 +rtblock;2590 +rturned;0279 +rturnedsuperior;02B4 +ruhiragana;308B +rukatakana;30EB +rukatakanahalfwidth;FF99 +rupeemarkbengali;09F2 +rupeesignbengali;09F3 +rupiah;F6DD +ruthai;0E24 +rvocalicbengali;098B +rvocalicdeva;090B +rvocalicgujarati;0A8B +rvocalicvowelsignbengali;09C3 +rvocalicvowelsigndeva;0943 +rvocalicvowelsigngujarati;0AC3 +s;0073 +sabengali;09B8 +sacute;015B +sacutedotaccent;1E65 +sadarabic;0635 +sadeva;0938 +sadfinalarabic;FEBA +sadinitialarabic;FEBB +sadmedialarabic;FEBC +sagujarati;0AB8 +sagurmukhi;0A38 +sahiragana;3055 +sakatakana;30B5 +sakatakanahalfwidth;FF7B +sallallahoualayhewasallamarabic;FDFA +samekh;05E1 +samekhdagesh;FB41 +samekhdageshhebrew;FB41 +samekhhebrew;05E1 +saraaathai;0E32 +saraaethai;0E41 +saraaimaimalaithai;0E44 +saraaimaimuanthai;0E43 +saraamthai;0E33 +saraathai;0E30 +saraethai;0E40 +saraiileftthai;F886 +saraiithai;0E35 +saraileftthai;F885 +saraithai;0E34 +saraothai;0E42 +saraueeleftthai;F888 +saraueethai;0E37 +saraueleftthai;F887 +sarauethai;0E36 +sarauthai;0E38 +sarauuthai;0E39 +sbopomofo;3119 +scaron;0161 +scarondotaccent;1E67 +scedilla;015F +schwa;0259 +schwacyrillic;04D9 +schwadieresiscyrillic;04DB +schwahook;025A +scircle;24E2 +scircumflex;015D +scommaaccent;0219 +sdotaccent;1E61 +sdotbelow;1E63 +sdotbelowdotaccent;1E69 +seagullbelowcmb;033C +second;2033 +secondtonechinese;02CA +section;00A7 +seenarabic;0633 +seenfinalarabic;FEB2 +seeninitialarabic;FEB3 +seenmedialarabic;FEB4 +segol;05B6 +segol13;05B6 +segol1f;05B6 +segol2c;05B6 +segolhebrew;05B6 +segolnarrowhebrew;05B6 +segolquarterhebrew;05B6 +segoltahebrew;0592 +segolwidehebrew;05B6 +seharmenian;057D +sehiragana;305B +sekatakana;30BB +sekatakanahalfwidth;FF7E +semicolon;003B +semicolonarabic;061B +semicolonmonospace;FF1B +semicolonsmall;FE54 +semivoicedmarkkana;309C +semivoicedmarkkanahalfwidth;FF9F +sentisquare;3322 +sentosquare;3323 +seven;0037 +sevenarabic;0667 +sevenbengali;09ED +sevencircle;2466 +sevencircleinversesansserif;2790 +sevendeva;096D +seveneighths;215E +sevengujarati;0AED +sevengurmukhi;0A6D +sevenhackarabic;0667 +sevenhangzhou;3027 +sevenideographicparen;3226 +seveninferior;2087 +sevenmonospace;FF17 +sevenoldstyle;F737 +sevenparen;247A +sevenperiod;248E +sevenpersian;06F7 +sevenroman;2176 +sevensuperior;2077 +seventeencircle;2470 +seventeenparen;2484 +seventeenperiod;2498 +seventhai;0E57 +sfthyphen;00AD +shaarmenian;0577 +shabengali;09B6 +shacyrillic;0448 +shaddaarabic;0651 +shaddadammaarabic;FC61 +shaddadammatanarabic;FC5E +shaddafathaarabic;FC60 +shaddafathatanarabic;0651 064B +shaddakasraarabic;FC62 +shaddakasratanarabic;FC5F +shade;2592 +shadedark;2593 +shadelight;2591 +shademedium;2592 +shadeva;0936 +shagujarati;0AB6 +shagurmukhi;0A36 +shalshelethebrew;0593 +shbopomofo;3115 +shchacyrillic;0449 +sheenarabic;0634 +sheenfinalarabic;FEB6 +sheeninitialarabic;FEB7 +sheenmedialarabic;FEB8 +sheicoptic;03E3 +sheqel;20AA +sheqelhebrew;20AA +sheva;05B0 +sheva115;05B0 +sheva15;05B0 +sheva22;05B0 +sheva2e;05B0 +shevahebrew;05B0 +shevanarrowhebrew;05B0 +shevaquarterhebrew;05B0 +shevawidehebrew;05B0 +shhacyrillic;04BB +shimacoptic;03ED +shin;05E9 +shindagesh;FB49 +shindageshhebrew;FB49 +shindageshshindot;FB2C +shindageshshindothebrew;FB2C +shindageshsindot;FB2D +shindageshsindothebrew;FB2D +shindothebrew;05C1 +shinhebrew;05E9 +shinshindot;FB2A +shinshindothebrew;FB2A +shinsindot;FB2B +shinsindothebrew;FB2B +shook;0282 +sigma;03C3 +sigma1;03C2 +sigmafinal;03C2 +sigmalunatesymbolgreek;03F2 +sihiragana;3057 +sikatakana;30B7 +sikatakanahalfwidth;FF7C +siluqhebrew;05BD +siluqlefthebrew;05BD +similar;223C +sindothebrew;05C2 +siosacirclekorean;3274 +siosaparenkorean;3214 +sioscieuckorean;317E +sioscirclekorean;3266 +sioskiyeokkorean;317A +sioskorean;3145 +siosnieunkorean;317B +siosparenkorean;3206 +siospieupkorean;317D +siostikeutkorean;317C +six;0036 +sixarabic;0666 +sixbengali;09EC +sixcircle;2465 +sixcircleinversesansserif;278F +sixdeva;096C +sixgujarati;0AEC +sixgurmukhi;0A6C +sixhackarabic;0666 +sixhangzhou;3026 +sixideographicparen;3225 +sixinferior;2086 +sixmonospace;FF16 +sixoldstyle;F736 +sixparen;2479 +sixperiod;248D +sixpersian;06F6 +sixroman;2175 +sixsuperior;2076 +sixteencircle;246F +sixteencurrencydenominatorbengali;09F9 +sixteenparen;2483 +sixteenperiod;2497 +sixthai;0E56 +slash;002F +slashmonospace;FF0F +slong;017F +slongdotaccent;1E9B +smileface;263A +smonospace;FF53 +sofpasuqhebrew;05C3 +softhyphen;00AD +softsigncyrillic;044C +sohiragana;305D +sokatakana;30BD +sokatakanahalfwidth;FF7F +soliduslongoverlaycmb;0338 +solidusshortoverlaycmb;0337 +sorusithai;0E29 +sosalathai;0E28 +sosothai;0E0B +sosuathai;0E2A +space;0020 +spacehackarabic;0020 +spade;2660 +spadesuitblack;2660 +spadesuitwhite;2664 +sparen;24AE +squarebelowcmb;033B +squarecc;33C4 +squarecm;339D +squarediagonalcrosshatchfill;25A9 +squarehorizontalfill;25A4 +squarekg;338F +squarekm;339E +squarekmcapital;33CE +squareln;33D1 +squarelog;33D2 +squaremg;338E +squaremil;33D5 +squaremm;339C +squaremsquared;33A1 +squareorthogonalcrosshatchfill;25A6 +squareupperlefttolowerrightfill;25A7 +squareupperrighttolowerleftfill;25A8 +squareverticalfill;25A5 +squarewhitewithsmallblack;25A3 +srsquare;33DB +ssabengali;09B7 +ssadeva;0937 +ssagujarati;0AB7 +ssangcieuckorean;3149 +ssanghieuhkorean;3185 +ssangieungkorean;3180 +ssangkiyeokkorean;3132 +ssangnieunkorean;3165 +ssangpieupkorean;3143 +ssangsioskorean;3146 +ssangtikeutkorean;3138 +ssuperior;F6F2 +sterling;00A3 +sterlingmonospace;FFE1 +strokelongoverlaycmb;0336 +strokeshortoverlaycmb;0335 +subset;2282 +subsetnotequal;228A +subsetorequal;2286 +succeeds;227B +suchthat;220B +suhiragana;3059 +sukatakana;30B9 +sukatakanahalfwidth;FF7D +sukunarabic;0652 +summation;2211 +sun;263C +superset;2283 +supersetnotequal;228B +supersetorequal;2287 +svsquare;33DC +syouwaerasquare;337C +t;0074 +tabengali;09A4 +tackdown;22A4 +tackleft;22A3 +tadeva;0924 +tagujarati;0AA4 +tagurmukhi;0A24 +taharabic;0637 +tahfinalarabic;FEC2 +tahinitialarabic;FEC3 +tahiragana;305F +tahmedialarabic;FEC4 +taisyouerasquare;337D +takatakana;30BF +takatakanahalfwidth;FF80 +tatweelarabic;0640 +tau;03C4 +tav;05EA +tavdages;FB4A +tavdagesh;FB4A +tavdageshhebrew;FB4A +tavhebrew;05EA +tbar;0167 +tbopomofo;310A +tcaron;0165 +tccurl;02A8 +tcedilla;0163 +tcheharabic;0686 +tchehfinalarabic;FB7B +tchehinitialarabic;FB7C +tchehmedialarabic;FB7D +tchehmeeminitialarabic;FB7C FEE4 +tcircle;24E3 +tcircumflexbelow;1E71 +tcommaaccent;0163 +tdieresis;1E97 +tdotaccent;1E6B +tdotbelow;1E6D +tecyrillic;0442 +tedescendercyrillic;04AD +teharabic;062A +tehfinalarabic;FE96 +tehhahinitialarabic;FCA2 +tehhahisolatedarabic;FC0C +tehinitialarabic;FE97 +tehiragana;3066 +tehjeeminitialarabic;FCA1 +tehjeemisolatedarabic;FC0B +tehmarbutaarabic;0629 +tehmarbutafinalarabic;FE94 +tehmedialarabic;FE98 +tehmeeminitialarabic;FCA4 +tehmeemisolatedarabic;FC0E +tehnoonfinalarabic;FC73 +tekatakana;30C6 +tekatakanahalfwidth;FF83 +telephone;2121 +telephoneblack;260E +telishagedolahebrew;05A0 +telishaqetanahebrew;05A9 +tencircle;2469 +tenideographicparen;3229 +tenparen;247D +tenperiod;2491 +tenroman;2179 +tesh;02A7 +tet;05D8 +tetdagesh;FB38 +tetdageshhebrew;FB38 +tethebrew;05D8 +tetsecyrillic;04B5 +tevirhebrew;059B +tevirlefthebrew;059B +thabengali;09A5 +thadeva;0925 +thagujarati;0AA5 +thagurmukhi;0A25 +thalarabic;0630 +thalfinalarabic;FEAC +thanthakhatlowleftthai;F898 +thanthakhatlowrightthai;F897 +thanthakhatthai;0E4C +thanthakhatupperleftthai;F896 +theharabic;062B +thehfinalarabic;FE9A +thehinitialarabic;FE9B +thehmedialarabic;FE9C +thereexists;2203 +therefore;2234 +theta;03B8 +theta1;03D1 +thetasymbolgreek;03D1 +thieuthacirclekorean;3279 +thieuthaparenkorean;3219 +thieuthcirclekorean;326B +thieuthkorean;314C +thieuthparenkorean;320B +thirteencircle;246C +thirteenparen;2480 +thirteenperiod;2494 +thonangmonthothai;0E11 +thook;01AD +thophuthaothai;0E12 +thorn;00FE +thothahanthai;0E17 +thothanthai;0E10 +thothongthai;0E18 +thothungthai;0E16 +thousandcyrillic;0482 +thousandsseparatorarabic;066C +thousandsseparatorpersian;066C +three;0033 +threearabic;0663 +threebengali;09E9 +threecircle;2462 +threecircleinversesansserif;278C +threedeva;0969 +threeeighths;215C +threegujarati;0AE9 +threegurmukhi;0A69 +threehackarabic;0663 +threehangzhou;3023 +threeideographicparen;3222 +threeinferior;2083 +threemonospace;FF13 +threenumeratorbengali;09F6 +threeoldstyle;F733 +threeparen;2476 +threeperiod;248A +threepersian;06F3 +threequarters;00BE +threequartersemdash;F6DE +threeroman;2172 +threesuperior;00B3 +threethai;0E53 +thzsquare;3394 +tihiragana;3061 +tikatakana;30C1 +tikatakanahalfwidth;FF81 +tikeutacirclekorean;3270 +tikeutaparenkorean;3210 +tikeutcirclekorean;3262 +tikeutkorean;3137 +tikeutparenkorean;3202 +tilde;02DC +tildebelowcmb;0330 +tildecmb;0303 +tildecomb;0303 +tildedoublecmb;0360 +tildeoperator;223C +tildeoverlaycmb;0334 +tildeverticalcmb;033E +timescircle;2297 +tipehahebrew;0596 +tipehalefthebrew;0596 +tippigurmukhi;0A70 +titlocyrilliccmb;0483 +tiwnarmenian;057F +tlinebelow;1E6F +tmonospace;FF54 +toarmenian;0569 +tohiragana;3068 +tokatakana;30C8 +tokatakanahalfwidth;FF84 +tonebarextrahighmod;02E5 +tonebarextralowmod;02E9 +tonebarhighmod;02E6 +tonebarlowmod;02E8 +tonebarmidmod;02E7 +tonefive;01BD +tonesix;0185 +tonetwo;01A8 +tonos;0384 +tonsquare;3327 +topatakthai;0E0F +tortoiseshellbracketleft;3014 +tortoiseshellbracketleftsmall;FE5D +tortoiseshellbracketleftvertical;FE39 +tortoiseshellbracketright;3015 +tortoiseshellbracketrightsmall;FE5E +tortoiseshellbracketrightvertical;FE3A +totaothai;0E15 +tpalatalhook;01AB +tparen;24AF +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +tretroflexhook;0288 +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +ts;02A6 +tsadi;05E6 +tsadidagesh;FB46 +tsadidageshhebrew;FB46 +tsadihebrew;05E6 +tsecyrillic;0446 +tsere;05B5 +tsere12;05B5 +tsere1e;05B5 +tsere2b;05B5 +tserehebrew;05B5 +tserenarrowhebrew;05B5 +tserequarterhebrew;05B5 +tserewidehebrew;05B5 +tshecyrillic;045B +tsuperior;F6F3 +ttabengali;099F +ttadeva;091F +ttagujarati;0A9F +ttagurmukhi;0A1F +tteharabic;0679 +ttehfinalarabic;FB67 +ttehinitialarabic;FB68 +ttehmedialarabic;FB69 +tthabengali;09A0 +tthadeva;0920 +tthagujarati;0AA0 +tthagurmukhi;0A20 +tturned;0287 +tuhiragana;3064 +tukatakana;30C4 +tukatakanahalfwidth;FF82 +tusmallhiragana;3063 +tusmallkatakana;30C3 +tusmallkatakanahalfwidth;FF6F +twelvecircle;246B +twelveparen;247F +twelveperiod;2493 +twelveroman;217B +twentycircle;2473 +twentyhangzhou;5344 +twentyparen;2487 +twentyperiod;249B +two;0032 +twoarabic;0662 +twobengali;09E8 +twocircle;2461 +twocircleinversesansserif;278B +twodeva;0968 +twodotenleader;2025 +twodotleader;2025 +twodotleadervertical;FE30 +twogujarati;0AE8 +twogurmukhi;0A68 +twohackarabic;0662 +twohangzhou;3022 +twoideographicparen;3221 +twoinferior;2082 +twomonospace;FF12 +twonumeratorbengali;09F5 +twooldstyle;F732 +twoparen;2475 +twoperiod;2489 +twopersian;06F2 +tworoman;2171 +twostroke;01BB +twosuperior;00B2 +twothai;0E52 +twothirds;2154 +u;0075 +uacute;00FA +ubar;0289 +ubengali;0989 +ubopomofo;3128 +ubreve;016D +ucaron;01D4 +ucircle;24E4 +ucircumflex;00FB +ucircumflexbelow;1E77 +ucyrillic;0443 +udattadeva;0951 +udblacute;0171 +udblgrave;0215 +udeva;0909 +udieresis;00FC +udieresisacute;01D8 +udieresisbelow;1E73 +udieresiscaron;01DA +udieresiscyrillic;04F1 +udieresisgrave;01DC +udieresismacron;01D6 +udotbelow;1EE5 +ugrave;00F9 +ugujarati;0A89 +ugurmukhi;0A09 +uhiragana;3046 +uhookabove;1EE7 +uhorn;01B0 +uhornacute;1EE9 +uhorndotbelow;1EF1 +uhorngrave;1EEB +uhornhookabove;1EED +uhorntilde;1EEF +uhungarumlaut;0171 +uhungarumlautcyrillic;04F3 +uinvertedbreve;0217 +ukatakana;30A6 +ukatakanahalfwidth;FF73 +ukcyrillic;0479 +ukorean;315C +umacron;016B +umacroncyrillic;04EF +umacrondieresis;1E7B +umatragurmukhi;0A41 +umonospace;FF55 +underscore;005F +underscoredbl;2017 +underscoremonospace;FF3F +underscorevertical;FE33 +underscorewavy;FE4F +union;222A +universal;2200 +uogonek;0173 +uparen;24B0 +upblock;2580 +upperdothebrew;05C4 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilonlatin;028A +upsilontonos;03CD +uptackbelowcmb;031D +uptackmod;02D4 +uragurmukhi;0A73 +uring;016F +ushortcyrillic;045E +usmallhiragana;3045 +usmallkatakana;30A5 +usmallkatakanahalfwidth;FF69 +ustraightcyrillic;04AF +ustraightstrokecyrillic;04B1 +utilde;0169 +utildeacute;1E79 +utildebelow;1E75 +uubengali;098A +uudeva;090A +uugujarati;0A8A +uugurmukhi;0A0A +uumatragurmukhi;0A42 +uuvowelsignbengali;09C2 +uuvowelsigndeva;0942 +uuvowelsigngujarati;0AC2 +uvowelsignbengali;09C1 +uvowelsigndeva;0941 +uvowelsigngujarati;0AC1 +v;0076 +vadeva;0935 +vagujarati;0AB5 +vagurmukhi;0A35 +vakatakana;30F7 +vav;05D5 +vavdagesh;FB35 +vavdagesh65;FB35 +vavdageshhebrew;FB35 +vavhebrew;05D5 +vavholam;FB4B +vavholamhebrew;FB4B +vavvavhebrew;05F0 +vavyodhebrew;05F1 +vcircle;24E5 +vdotbelow;1E7F +vecyrillic;0432 +veharabic;06A4 +vehfinalarabic;FB6B +vehinitialarabic;FB6C +vehmedialarabic;FB6D +vekatakana;30F9 +venus;2640 +verticalbar;007C +verticallineabovecmb;030D +verticallinebelowcmb;0329 +verticallinelowmod;02CC +verticallinemod;02C8 +vewarmenian;057E +vhook;028B +vikatakana;30F8 +viramabengali;09CD +viramadeva;094D +viramagujarati;0ACD +visargabengali;0983 +visargadeva;0903 +visargagujarati;0A83 +vmonospace;FF56 +voarmenian;0578 +voicediterationhiragana;309E +voicediterationkatakana;30FE +voicedmarkkana;309B +voicedmarkkanahalfwidth;FF9E +vokatakana;30FA +vparen;24B1 +vtilde;1E7D +vturned;028C +vuhiragana;3094 +vukatakana;30F4 +w;0077 +wacute;1E83 +waekorean;3159 +wahiragana;308F +wakatakana;30EF +wakatakanahalfwidth;FF9C +wakorean;3158 +wasmallhiragana;308E +wasmallkatakana;30EE +wattosquare;3357 +wavedash;301C +wavyunderscorevertical;FE34 +wawarabic;0648 +wawfinalarabic;FEEE +wawhamzaabovearabic;0624 +wawhamzaabovefinalarabic;FE86 +wbsquare;33DD +wcircle;24E6 +wcircumflex;0175 +wdieresis;1E85 +wdotaccent;1E87 +wdotbelow;1E89 +wehiragana;3091 +weierstrass;2118 +wekatakana;30F1 +wekorean;315E +weokorean;315D +wgrave;1E81 +whitebullet;25E6 +whitecircle;25CB +whitecircleinverse;25D9 +whitecornerbracketleft;300E +whitecornerbracketleftvertical;FE43 +whitecornerbracketright;300F +whitecornerbracketrightvertical;FE44 +whitediamond;25C7 +whitediamondcontainingblacksmalldiamond;25C8 +whitedownpointingsmalltriangle;25BF +whitedownpointingtriangle;25BD +whiteleftpointingsmalltriangle;25C3 +whiteleftpointingtriangle;25C1 +whitelenticularbracketleft;3016 +whitelenticularbracketright;3017 +whiterightpointingsmalltriangle;25B9 +whiterightpointingtriangle;25B7 +whitesmallsquare;25AB +whitesmilingface;263A +whitesquare;25A1 +whitestar;2606 +whitetelephone;260F +whitetortoiseshellbracketleft;3018 +whitetortoiseshellbracketright;3019 +whiteuppointingsmalltriangle;25B5 +whiteuppointingtriangle;25B3 +wihiragana;3090 +wikatakana;30F0 +wikorean;315F +wmonospace;FF57 +wohiragana;3092 +wokatakana;30F2 +wokatakanahalfwidth;FF66 +won;20A9 +wonmonospace;FFE6 +wowaenthai;0E27 +wparen;24B2 +wring;1E98 +wsuperior;02B7 +wturned;028D +wynn;01BF +x;0078 +xabovecmb;033D +xbopomofo;3112 +xcircle;24E7 +xdieresis;1E8D +xdotaccent;1E8B +xeharmenian;056D +xi;03BE +xmonospace;FF58 +xparen;24B3 +xsuperior;02E3 +y;0079 +yaadosquare;334E +yabengali;09AF +yacute;00FD +yadeva;092F +yaekorean;3152 +yagujarati;0AAF +yagurmukhi;0A2F +yahiragana;3084 +yakatakana;30E4 +yakatakanahalfwidth;FF94 +yakorean;3151 +yamakkanthai;0E4E +yasmallhiragana;3083 +yasmallkatakana;30E3 +yasmallkatakanahalfwidth;FF6C +yatcyrillic;0463 +ycircle;24E8 +ycircumflex;0177 +ydieresis;00FF +ydotaccent;1E8F +ydotbelow;1EF5 +yeharabic;064A +yehbarreearabic;06D2 +yehbarreefinalarabic;FBAF +yehfinalarabic;FEF2 +yehhamzaabovearabic;0626 +yehhamzaabovefinalarabic;FE8A +yehhamzaaboveinitialarabic;FE8B +yehhamzaabovemedialarabic;FE8C +yehinitialarabic;FEF3 +yehmedialarabic;FEF4 +yehmeeminitialarabic;FCDD +yehmeemisolatedarabic;FC58 +yehnoonfinalarabic;FC94 +yehthreedotsbelowarabic;06D1 +yekorean;3156 +yen;00A5 +yenmonospace;FFE5 +yeokorean;3155 +yeorinhieuhkorean;3186 +yerahbenyomohebrew;05AA +yerahbenyomolefthebrew;05AA +yericyrillic;044B +yerudieresiscyrillic;04F9 +yesieungkorean;3181 +yesieungpansioskorean;3183 +yesieungsioskorean;3182 +yetivhebrew;059A +ygrave;1EF3 +yhook;01B4 +yhookabove;1EF7 +yiarmenian;0575 +yicyrillic;0457 +yikorean;3162 +yinyang;262F +yiwnarmenian;0582 +ymonospace;FF59 +yod;05D9 +yoddagesh;FB39 +yoddageshhebrew;FB39 +yodhebrew;05D9 +yodyodhebrew;05F2 +yodyodpatahhebrew;FB1F +yohiragana;3088 +yoikorean;3189 +yokatakana;30E8 +yokatakanahalfwidth;FF96 +yokorean;315B +yosmallhiragana;3087 +yosmallkatakana;30E7 +yosmallkatakanahalfwidth;FF6E +yotgreek;03F3 +yoyaekorean;3188 +yoyakorean;3187 +yoyakthai;0E22 +yoyingthai;0E0D +yparen;24B4 +ypogegrammeni;037A +ypogegrammenigreekcmb;0345 +yr;01A6 +yring;1E99 +ysuperior;02B8 +ytilde;1EF9 +yturned;028E +yuhiragana;3086 +yuikorean;318C +yukatakana;30E6 +yukatakanahalfwidth;FF95 +yukorean;3160 +yusbigcyrillic;046B +yusbigiotifiedcyrillic;046D +yuslittlecyrillic;0467 +yuslittleiotifiedcyrillic;0469 +yusmallhiragana;3085 +yusmallkatakana;30E5 +yusmallkatakanahalfwidth;FF6D +yuyekorean;318B +yuyeokorean;318A +yyabengali;09DF +yyadeva;095F +z;007A +zaarmenian;0566 +zacute;017A +zadeva;095B +zagurmukhi;0A5B +zaharabic;0638 +zahfinalarabic;FEC6 +zahinitialarabic;FEC7 +zahiragana;3056 +zahmedialarabic;FEC8 +zainarabic;0632 +zainfinalarabic;FEB0 +zakatakana;30B6 +zaqefgadolhebrew;0595 +zaqefqatanhebrew;0594 +zarqahebrew;0598 +zayin;05D6 +zayindagesh;FB36 +zayindageshhebrew;FB36 +zayinhebrew;05D6 +zbopomofo;3117 +zcaron;017E +zcircle;24E9 +zcircumflex;1E91 +zcurl;0291 +zdot;017C +zdotaccent;017C +zdotbelow;1E93 +zecyrillic;0437 +zedescendercyrillic;0499 +zedieresiscyrillic;04DF +zehiragana;305C +zekatakana;30BC +zero;0030 +zeroarabic;0660 +zerobengali;09E6 +zerodeva;0966 +zerogujarati;0AE6 +zerogurmukhi;0A66 +zerohackarabic;0660 +zeroinferior;2080 +zeromonospace;FF10 +zerooldstyle;F730 +zeropersian;06F0 +zerosuperior;2070 +zerothai;0E50 +zerowidthjoiner;FEFF +zerowidthnonjoiner;200C +zerowidthspace;200B +zeta;03B6 +zhbopomofo;3113 +zhearmenian;056A +zhebrevecyrillic;04C2 +zhecyrillic;0436 +zhedescendercyrillic;0497 +zhedieresiscyrillic;04DD +zihiragana;3058 +zikatakana;30B8 +zinorhebrew;05AE +zlinebelow;1E95 +zmonospace;FF5A +zohiragana;305E +zokatakana;30BE +zparen;24B5 +zretroflexhook;0290 +zstroke;01B6 +zuhiragana;305A +zukatakana;30BA +# END +""" + + +_aglfnText = """\ +# ----------------------------------------------------------- +# Copyright 2002-2019 Adobe (http://www.adobe.com/). +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the +# following conditions are met: +# +# Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# Neither the name of Adobe nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------- +# Name: Adobe Glyph List For New Fonts +# Table version: 1.7 +# Date: November 6, 2008 +# URL: https://github.com/adobe-type-tools/agl-aglfn +# +# Description: +# +# AGLFN (Adobe Glyph List For New Fonts) provides a list of base glyph +# names that are recommended for new fonts, which are compatible with +# the AGL (Adobe Glyph List) Specification, and which should be used +# as described in Section 6 of that document. AGLFN comprises the set +# of glyph names from AGL that map via the AGL Specification rules to +# the semantically correct UV (Unicode Value). For example, "Asmall" +# is omitted because AGL maps this glyph name to the PUA (Private Use +# Area) value U+F761, rather than to the UV that maps from the glyph +# name "A." Also omitted is "ffi," because AGL maps this to the +# Alphabetic Presentation Forms value U+FB03, rather than decomposing +# it into the following sequence of three UVs: U+0066, U+0066, and +# U+0069. The name "arrowvertex" has been omitted because this glyph +# now has a real UV, and AGL is now incorrect in mapping it to the PUA +# value U+F8E6. If you do not find an appropriate name for your glyph +# in this list, then please refer to Section 6 of the AGL +# Specification. +# +# Format: three semicolon-delimited fields: +# (1) Standard UV or CUS UV--four uppercase hexadecimal digits +# (2) Glyph name--upper/lowercase letters and digits +# (3) Character names: Unicode character names for standard UVs, and +# descriptive names for CUS UVs--uppercase letters, hyphen, and +# space +# +# The records are sorted by glyph name in increasing ASCII order, +# entries with the same glyph name are sorted in decreasing priority +# order, the UVs and Unicode character names are provided for +# convenience, lines starting with "#" are comments, and blank lines +# should be ignored. +# +# Revision History: +# +# 1.7 [6 November 2008] +# - Reverted to the original 1.4 and earlier mappings for Delta, +# Omega, and mu. +# - Removed mappings for "afii" names. These should now be assigned +# "uni" names. +# - Removed mappings for "commaaccent" names. These should now be +# assigned "uni" names. +# +# 1.6 [30 January 2006] +# - Completed work intended in 1.5. +# +# 1.5 [23 November 2005] +# - Removed duplicated block at end of file. +# - Changed mappings: +# 2206;Delta;INCREMENT changed to 0394;Delta;GREEK CAPITAL LETTER DELTA +# 2126;Omega;OHM SIGN changed to 03A9;Omega;GREEK CAPITAL LETTER OMEGA +# 03BC;mu;MICRO SIGN changed to 03BC;mu;GREEK SMALL LETTER MU +# - Corrected statement above about why "ffi" is omitted. +# +# 1.4 [24 September 2003] +# - Changed version to 1.4, to avoid confusion with the AGL 1.3. +# - Fixed spelling errors in the header. +# - Fully removed "arrowvertex," as it is mapped only to a PUA Unicode +# value in some fonts. +# +# 1.1 [17 April 2003] +# - Renamed [Tt]cedilla back to [Tt]commaaccent. +# +# 1.0 [31 January 2003] +# - Original version. +# - Derived from the AGLv1.2 by: +# removing the PUA area codes; +# removing duplicate Unicode mappings; and +# renaming "tcommaaccent" to "tcedilla" and "Tcommaaccent" to "Tcedilla" +# +0041;A;LATIN CAPITAL LETTER A +00C6;AE;LATIN CAPITAL LETTER AE +01FC;AEacute;LATIN CAPITAL LETTER AE WITH ACUTE +00C1;Aacute;LATIN CAPITAL LETTER A WITH ACUTE +0102;Abreve;LATIN CAPITAL LETTER A WITH BREVE +00C2;Acircumflex;LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C4;Adieresis;LATIN CAPITAL LETTER A WITH DIAERESIS +00C0;Agrave;LATIN CAPITAL LETTER A WITH GRAVE +0391;Alpha;GREEK CAPITAL LETTER ALPHA +0386;Alphatonos;GREEK CAPITAL LETTER ALPHA WITH TONOS +0100;Amacron;LATIN CAPITAL LETTER A WITH MACRON +0104;Aogonek;LATIN CAPITAL LETTER A WITH OGONEK +00C5;Aring;LATIN CAPITAL LETTER A WITH RING ABOVE +01FA;Aringacute;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +00C3;Atilde;LATIN CAPITAL LETTER A WITH TILDE +0042;B;LATIN CAPITAL LETTER B +0392;Beta;GREEK CAPITAL LETTER BETA +0043;C;LATIN CAPITAL LETTER C +0106;Cacute;LATIN CAPITAL LETTER C WITH ACUTE +010C;Ccaron;LATIN CAPITAL LETTER C WITH CARON +00C7;Ccedilla;LATIN CAPITAL LETTER C WITH CEDILLA +0108;Ccircumflex;LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010A;Cdotaccent;LATIN CAPITAL LETTER C WITH DOT ABOVE +03A7;Chi;GREEK CAPITAL LETTER CHI +0044;D;LATIN CAPITAL LETTER D +010E;Dcaron;LATIN CAPITAL LETTER D WITH CARON +0110;Dcroat;LATIN CAPITAL LETTER D WITH STROKE +2206;Delta;INCREMENT +0045;E;LATIN CAPITAL LETTER E +00C9;Eacute;LATIN CAPITAL LETTER E WITH ACUTE +0114;Ebreve;LATIN CAPITAL LETTER E WITH BREVE +011A;Ecaron;LATIN CAPITAL LETTER E WITH CARON +00CA;Ecircumflex;LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB;Edieresis;LATIN CAPITAL LETTER E WITH DIAERESIS +0116;Edotaccent;LATIN CAPITAL LETTER E WITH DOT ABOVE +00C8;Egrave;LATIN CAPITAL LETTER E WITH GRAVE +0112;Emacron;LATIN CAPITAL LETTER E WITH MACRON +014A;Eng;LATIN CAPITAL LETTER ENG +0118;Eogonek;LATIN CAPITAL LETTER E WITH OGONEK +0395;Epsilon;GREEK CAPITAL LETTER EPSILON +0388;Epsilontonos;GREEK CAPITAL LETTER EPSILON WITH TONOS +0397;Eta;GREEK CAPITAL LETTER ETA +0389;Etatonos;GREEK CAPITAL LETTER ETA WITH TONOS +00D0;Eth;LATIN CAPITAL LETTER ETH +20AC;Euro;EURO SIGN +0046;F;LATIN CAPITAL LETTER F +0047;G;LATIN CAPITAL LETTER G +0393;Gamma;GREEK CAPITAL LETTER GAMMA +011E;Gbreve;LATIN CAPITAL LETTER G WITH BREVE +01E6;Gcaron;LATIN CAPITAL LETTER G WITH CARON +011C;Gcircumflex;LATIN CAPITAL LETTER G WITH CIRCUMFLEX +0120;Gdotaccent;LATIN CAPITAL LETTER G WITH DOT ABOVE +0048;H;LATIN CAPITAL LETTER H +25CF;H18533;BLACK CIRCLE +25AA;H18543;BLACK SMALL SQUARE +25AB;H18551;WHITE SMALL SQUARE +25A1;H22073;WHITE SQUARE +0126;Hbar;LATIN CAPITAL LETTER H WITH STROKE +0124;Hcircumflex;LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0049;I;LATIN CAPITAL LETTER I +0132;IJ;LATIN CAPITAL LIGATURE IJ +00CD;Iacute;LATIN CAPITAL LETTER I WITH ACUTE +012C;Ibreve;LATIN CAPITAL LETTER I WITH BREVE +00CE;Icircumflex;LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF;Idieresis;LATIN CAPITAL LETTER I WITH DIAERESIS +0130;Idotaccent;LATIN CAPITAL LETTER I WITH DOT ABOVE +2111;Ifraktur;BLACK-LETTER CAPITAL I +00CC;Igrave;LATIN CAPITAL LETTER I WITH GRAVE +012A;Imacron;LATIN CAPITAL LETTER I WITH MACRON +012E;Iogonek;LATIN CAPITAL LETTER I WITH OGONEK +0399;Iota;GREEK CAPITAL LETTER IOTA +03AA;Iotadieresis;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +038A;Iotatonos;GREEK CAPITAL LETTER IOTA WITH TONOS +0128;Itilde;LATIN CAPITAL LETTER I WITH TILDE +004A;J;LATIN CAPITAL LETTER J +0134;Jcircumflex;LATIN CAPITAL LETTER J WITH CIRCUMFLEX +004B;K;LATIN CAPITAL LETTER K +039A;Kappa;GREEK CAPITAL LETTER KAPPA +004C;L;LATIN CAPITAL LETTER L +0139;Lacute;LATIN CAPITAL LETTER L WITH ACUTE +039B;Lambda;GREEK CAPITAL LETTER LAMDA +013D;Lcaron;LATIN CAPITAL LETTER L WITH CARON +013F;Ldot;LATIN CAPITAL LETTER L WITH MIDDLE DOT +0141;Lslash;LATIN CAPITAL LETTER L WITH STROKE +004D;M;LATIN CAPITAL LETTER M +039C;Mu;GREEK CAPITAL LETTER MU +004E;N;LATIN CAPITAL LETTER N +0143;Nacute;LATIN CAPITAL LETTER N WITH ACUTE +0147;Ncaron;LATIN CAPITAL LETTER N WITH CARON +00D1;Ntilde;LATIN CAPITAL LETTER N WITH TILDE +039D;Nu;GREEK CAPITAL LETTER NU +004F;O;LATIN CAPITAL LETTER O +0152;OE;LATIN CAPITAL LIGATURE OE +00D3;Oacute;LATIN CAPITAL LETTER O WITH ACUTE +014E;Obreve;LATIN CAPITAL LETTER O WITH BREVE +00D4;Ocircumflex;LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D6;Odieresis;LATIN CAPITAL LETTER O WITH DIAERESIS +00D2;Ograve;LATIN CAPITAL LETTER O WITH GRAVE +01A0;Ohorn;LATIN CAPITAL LETTER O WITH HORN +0150;Ohungarumlaut;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +014C;Omacron;LATIN CAPITAL LETTER O WITH MACRON +2126;Omega;OHM SIGN +038F;Omegatonos;GREEK CAPITAL LETTER OMEGA WITH TONOS +039F;Omicron;GREEK CAPITAL LETTER OMICRON +038C;Omicrontonos;GREEK CAPITAL LETTER OMICRON WITH TONOS +00D8;Oslash;LATIN CAPITAL LETTER O WITH STROKE +01FE;Oslashacute;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +00D5;Otilde;LATIN CAPITAL LETTER O WITH TILDE +0050;P;LATIN CAPITAL LETTER P +03A6;Phi;GREEK CAPITAL LETTER PHI +03A0;Pi;GREEK CAPITAL LETTER PI +03A8;Psi;GREEK CAPITAL LETTER PSI +0051;Q;LATIN CAPITAL LETTER Q +0052;R;LATIN CAPITAL LETTER R +0154;Racute;LATIN CAPITAL LETTER R WITH ACUTE +0158;Rcaron;LATIN CAPITAL LETTER R WITH CARON +211C;Rfraktur;BLACK-LETTER CAPITAL R +03A1;Rho;GREEK CAPITAL LETTER RHO +0053;S;LATIN CAPITAL LETTER S +250C;SF010000;BOX DRAWINGS LIGHT DOWN AND RIGHT +2514;SF020000;BOX DRAWINGS LIGHT UP AND RIGHT +2510;SF030000;BOX DRAWINGS LIGHT DOWN AND LEFT +2518;SF040000;BOX DRAWINGS LIGHT UP AND LEFT +253C;SF050000;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +252C;SF060000;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +2534;SF070000;BOX DRAWINGS LIGHT UP AND HORIZONTAL +251C;SF080000;BOX DRAWINGS LIGHT VERTICAL AND RIGHT +2524;SF090000;BOX DRAWINGS LIGHT VERTICAL AND LEFT +2500;SF100000;BOX DRAWINGS LIGHT HORIZONTAL +2502;SF110000;BOX DRAWINGS LIGHT VERTICAL +2561;SF190000;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +2562;SF200000;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +2556;SF210000;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +2555;SF220000;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +2563;SF230000;BOX DRAWINGS DOUBLE VERTICAL AND LEFT +2551;SF240000;BOX DRAWINGS DOUBLE VERTICAL +2557;SF250000;BOX DRAWINGS DOUBLE DOWN AND LEFT +255D;SF260000;BOX DRAWINGS DOUBLE UP AND LEFT +255C;SF270000;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +255B;SF280000;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +255E;SF360000;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +255F;SF370000;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +255A;SF380000;BOX DRAWINGS DOUBLE UP AND RIGHT +2554;SF390000;BOX DRAWINGS DOUBLE DOWN AND RIGHT +2569;SF400000;BOX DRAWINGS DOUBLE UP AND HORIZONTAL +2566;SF410000;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +2560;SF420000;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +2550;SF430000;BOX DRAWINGS DOUBLE HORIZONTAL +256C;SF440000;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +2567;SF450000;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +2568;SF460000;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +2564;SF470000;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +2565;SF480000;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +2559;SF490000;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +2558;SF500000;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +2552;SF510000;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +2553;SF520000;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +256B;SF530000;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +256A;SF540000;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +015A;Sacute;LATIN CAPITAL LETTER S WITH ACUTE +0160;Scaron;LATIN CAPITAL LETTER S WITH CARON +015E;Scedilla;LATIN CAPITAL LETTER S WITH CEDILLA +015C;Scircumflex;LATIN CAPITAL LETTER S WITH CIRCUMFLEX +03A3;Sigma;GREEK CAPITAL LETTER SIGMA +0054;T;LATIN CAPITAL LETTER T +03A4;Tau;GREEK CAPITAL LETTER TAU +0166;Tbar;LATIN CAPITAL LETTER T WITH STROKE +0164;Tcaron;LATIN CAPITAL LETTER T WITH CARON +0398;Theta;GREEK CAPITAL LETTER THETA +00DE;Thorn;LATIN CAPITAL LETTER THORN +0055;U;LATIN CAPITAL LETTER U +00DA;Uacute;LATIN CAPITAL LETTER U WITH ACUTE +016C;Ubreve;LATIN CAPITAL LETTER U WITH BREVE +00DB;Ucircumflex;LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC;Udieresis;LATIN CAPITAL LETTER U WITH DIAERESIS +00D9;Ugrave;LATIN CAPITAL LETTER U WITH GRAVE +01AF;Uhorn;LATIN CAPITAL LETTER U WITH HORN +0170;Uhungarumlaut;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +016A;Umacron;LATIN CAPITAL LETTER U WITH MACRON +0172;Uogonek;LATIN CAPITAL LETTER U WITH OGONEK +03A5;Upsilon;GREEK CAPITAL LETTER UPSILON +03D2;Upsilon1;GREEK UPSILON WITH HOOK SYMBOL +03AB;Upsilondieresis;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +038E;Upsilontonos;GREEK CAPITAL LETTER UPSILON WITH TONOS +016E;Uring;LATIN CAPITAL LETTER U WITH RING ABOVE +0168;Utilde;LATIN CAPITAL LETTER U WITH TILDE +0056;V;LATIN CAPITAL LETTER V +0057;W;LATIN CAPITAL LETTER W +1E82;Wacute;LATIN CAPITAL LETTER W WITH ACUTE +0174;Wcircumflex;LATIN CAPITAL LETTER W WITH CIRCUMFLEX +1E84;Wdieresis;LATIN CAPITAL LETTER W WITH DIAERESIS +1E80;Wgrave;LATIN CAPITAL LETTER W WITH GRAVE +0058;X;LATIN CAPITAL LETTER X +039E;Xi;GREEK CAPITAL LETTER XI +0059;Y;LATIN CAPITAL LETTER Y +00DD;Yacute;LATIN CAPITAL LETTER Y WITH ACUTE +0176;Ycircumflex;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0178;Ydieresis;LATIN CAPITAL LETTER Y WITH DIAERESIS +1EF2;Ygrave;LATIN CAPITAL LETTER Y WITH GRAVE +005A;Z;LATIN CAPITAL LETTER Z +0179;Zacute;LATIN CAPITAL LETTER Z WITH ACUTE +017D;Zcaron;LATIN CAPITAL LETTER Z WITH CARON +017B;Zdotaccent;LATIN CAPITAL LETTER Z WITH DOT ABOVE +0396;Zeta;GREEK CAPITAL LETTER ZETA +0061;a;LATIN SMALL LETTER A +00E1;aacute;LATIN SMALL LETTER A WITH ACUTE +0103;abreve;LATIN SMALL LETTER A WITH BREVE +00E2;acircumflex;LATIN SMALL LETTER A WITH CIRCUMFLEX +00B4;acute;ACUTE ACCENT +0301;acutecomb;COMBINING ACUTE ACCENT +00E4;adieresis;LATIN SMALL LETTER A WITH DIAERESIS +00E6;ae;LATIN SMALL LETTER AE +01FD;aeacute;LATIN SMALL LETTER AE WITH ACUTE +00E0;agrave;LATIN SMALL LETTER A WITH GRAVE +2135;aleph;ALEF SYMBOL +03B1;alpha;GREEK SMALL LETTER ALPHA +03AC;alphatonos;GREEK SMALL LETTER ALPHA WITH TONOS +0101;amacron;LATIN SMALL LETTER A WITH MACRON +0026;ampersand;AMPERSAND +2220;angle;ANGLE +2329;angleleft;LEFT-POINTING ANGLE BRACKET +232A;angleright;RIGHT-POINTING ANGLE BRACKET +0387;anoteleia;GREEK ANO TELEIA +0105;aogonek;LATIN SMALL LETTER A WITH OGONEK +2248;approxequal;ALMOST EQUAL TO +00E5;aring;LATIN SMALL LETTER A WITH RING ABOVE +01FB;aringacute;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +2194;arrowboth;LEFT RIGHT ARROW +21D4;arrowdblboth;LEFT RIGHT DOUBLE ARROW +21D3;arrowdbldown;DOWNWARDS DOUBLE ARROW +21D0;arrowdblleft;LEFTWARDS DOUBLE ARROW +21D2;arrowdblright;RIGHTWARDS DOUBLE ARROW +21D1;arrowdblup;UPWARDS DOUBLE ARROW +2193;arrowdown;DOWNWARDS ARROW +2190;arrowleft;LEFTWARDS ARROW +2192;arrowright;RIGHTWARDS ARROW +2191;arrowup;UPWARDS ARROW +2195;arrowupdn;UP DOWN ARROW +21A8;arrowupdnbse;UP DOWN ARROW WITH BASE +005E;asciicircum;CIRCUMFLEX ACCENT +007E;asciitilde;TILDE +002A;asterisk;ASTERISK +2217;asteriskmath;ASTERISK OPERATOR +0040;at;COMMERCIAL AT +00E3;atilde;LATIN SMALL LETTER A WITH TILDE +0062;b;LATIN SMALL LETTER B +005C;backslash;REVERSE SOLIDUS +007C;bar;VERTICAL LINE +03B2;beta;GREEK SMALL LETTER BETA +2588;block;FULL BLOCK +007B;braceleft;LEFT CURLY BRACKET +007D;braceright;RIGHT CURLY BRACKET +005B;bracketleft;LEFT SQUARE BRACKET +005D;bracketright;RIGHT SQUARE BRACKET +02D8;breve;BREVE +00A6;brokenbar;BROKEN BAR +2022;bullet;BULLET +0063;c;LATIN SMALL LETTER C +0107;cacute;LATIN SMALL LETTER C WITH ACUTE +02C7;caron;CARON +21B5;carriagereturn;DOWNWARDS ARROW WITH CORNER LEFTWARDS +010D;ccaron;LATIN SMALL LETTER C WITH CARON +00E7;ccedilla;LATIN SMALL LETTER C WITH CEDILLA +0109;ccircumflex;LATIN SMALL LETTER C WITH CIRCUMFLEX +010B;cdotaccent;LATIN SMALL LETTER C WITH DOT ABOVE +00B8;cedilla;CEDILLA +00A2;cent;CENT SIGN +03C7;chi;GREEK SMALL LETTER CHI +25CB;circle;WHITE CIRCLE +2297;circlemultiply;CIRCLED TIMES +2295;circleplus;CIRCLED PLUS +02C6;circumflex;MODIFIER LETTER CIRCUMFLEX ACCENT +2663;club;BLACK CLUB SUIT +003A;colon;COLON +20A1;colonmonetary;COLON SIGN +002C;comma;COMMA +2245;congruent;APPROXIMATELY EQUAL TO +00A9;copyright;COPYRIGHT SIGN +00A4;currency;CURRENCY SIGN +0064;d;LATIN SMALL LETTER D +2020;dagger;DAGGER +2021;daggerdbl;DOUBLE DAGGER +010F;dcaron;LATIN SMALL LETTER D WITH CARON +0111;dcroat;LATIN SMALL LETTER D WITH STROKE +00B0;degree;DEGREE SIGN +03B4;delta;GREEK SMALL LETTER DELTA +2666;diamond;BLACK DIAMOND SUIT +00A8;dieresis;DIAERESIS +0385;dieresistonos;GREEK DIALYTIKA TONOS +00F7;divide;DIVISION SIGN +2593;dkshade;DARK SHADE +2584;dnblock;LOWER HALF BLOCK +0024;dollar;DOLLAR SIGN +20AB;dong;DONG SIGN +02D9;dotaccent;DOT ABOVE +0323;dotbelowcomb;COMBINING DOT BELOW +0131;dotlessi;LATIN SMALL LETTER DOTLESS I +22C5;dotmath;DOT OPERATOR +0065;e;LATIN SMALL LETTER E +00E9;eacute;LATIN SMALL LETTER E WITH ACUTE +0115;ebreve;LATIN SMALL LETTER E WITH BREVE +011B;ecaron;LATIN SMALL LETTER E WITH CARON +00EA;ecircumflex;LATIN SMALL LETTER E WITH CIRCUMFLEX +00EB;edieresis;LATIN SMALL LETTER E WITH DIAERESIS +0117;edotaccent;LATIN SMALL LETTER E WITH DOT ABOVE +00E8;egrave;LATIN SMALL LETTER E WITH GRAVE +0038;eight;DIGIT EIGHT +2208;element;ELEMENT OF +2026;ellipsis;HORIZONTAL ELLIPSIS +0113;emacron;LATIN SMALL LETTER E WITH MACRON +2014;emdash;EM DASH +2205;emptyset;EMPTY SET +2013;endash;EN DASH +014B;eng;LATIN SMALL LETTER ENG +0119;eogonek;LATIN SMALL LETTER E WITH OGONEK +03B5;epsilon;GREEK SMALL LETTER EPSILON +03AD;epsilontonos;GREEK SMALL LETTER EPSILON WITH TONOS +003D;equal;EQUALS SIGN +2261;equivalence;IDENTICAL TO +212E;estimated;ESTIMATED SYMBOL +03B7;eta;GREEK SMALL LETTER ETA +03AE;etatonos;GREEK SMALL LETTER ETA WITH TONOS +00F0;eth;LATIN SMALL LETTER ETH +0021;exclam;EXCLAMATION MARK +203C;exclamdbl;DOUBLE EXCLAMATION MARK +00A1;exclamdown;INVERTED EXCLAMATION MARK +2203;existential;THERE EXISTS +0066;f;LATIN SMALL LETTER F +2640;female;FEMALE SIGN +2012;figuredash;FIGURE DASH +25A0;filledbox;BLACK SQUARE +25AC;filledrect;BLACK RECTANGLE +0035;five;DIGIT FIVE +215D;fiveeighths;VULGAR FRACTION FIVE EIGHTHS +0192;florin;LATIN SMALL LETTER F WITH HOOK +0034;four;DIGIT FOUR +2044;fraction;FRACTION SLASH +20A3;franc;FRENCH FRANC SIGN +0067;g;LATIN SMALL LETTER G +03B3;gamma;GREEK SMALL LETTER GAMMA +011F;gbreve;LATIN SMALL LETTER G WITH BREVE +01E7;gcaron;LATIN SMALL LETTER G WITH CARON +011D;gcircumflex;LATIN SMALL LETTER G WITH CIRCUMFLEX +0121;gdotaccent;LATIN SMALL LETTER G WITH DOT ABOVE +00DF;germandbls;LATIN SMALL LETTER SHARP S +2207;gradient;NABLA +0060;grave;GRAVE ACCENT +0300;gravecomb;COMBINING GRAVE ACCENT +003E;greater;GREATER-THAN SIGN +2265;greaterequal;GREATER-THAN OR EQUAL TO +00AB;guillemotleft;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00BB;guillemotright;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +2039;guilsinglleft;SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A;guilsinglright;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0068;h;LATIN SMALL LETTER H +0127;hbar;LATIN SMALL LETTER H WITH STROKE +0125;hcircumflex;LATIN SMALL LETTER H WITH CIRCUMFLEX +2665;heart;BLACK HEART SUIT +0309;hookabovecomb;COMBINING HOOK ABOVE +2302;house;HOUSE +02DD;hungarumlaut;DOUBLE ACUTE ACCENT +002D;hyphen;HYPHEN-MINUS +0069;i;LATIN SMALL LETTER I +00ED;iacute;LATIN SMALL LETTER I WITH ACUTE +012D;ibreve;LATIN SMALL LETTER I WITH BREVE +00EE;icircumflex;LATIN SMALL LETTER I WITH CIRCUMFLEX +00EF;idieresis;LATIN SMALL LETTER I WITH DIAERESIS +00EC;igrave;LATIN SMALL LETTER I WITH GRAVE +0133;ij;LATIN SMALL LIGATURE IJ +012B;imacron;LATIN SMALL LETTER I WITH MACRON +221E;infinity;INFINITY +222B;integral;INTEGRAL +2321;integralbt;BOTTOM HALF INTEGRAL +2320;integraltp;TOP HALF INTEGRAL +2229;intersection;INTERSECTION +25D8;invbullet;INVERSE BULLET +25D9;invcircle;INVERSE WHITE CIRCLE +263B;invsmileface;BLACK SMILING FACE +012F;iogonek;LATIN SMALL LETTER I WITH OGONEK +03B9;iota;GREEK SMALL LETTER IOTA +03CA;iotadieresis;GREEK SMALL LETTER IOTA WITH DIALYTIKA +0390;iotadieresistonos;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AF;iotatonos;GREEK SMALL LETTER IOTA WITH TONOS +0129;itilde;LATIN SMALL LETTER I WITH TILDE +006A;j;LATIN SMALL LETTER J +0135;jcircumflex;LATIN SMALL LETTER J WITH CIRCUMFLEX +006B;k;LATIN SMALL LETTER K +03BA;kappa;GREEK SMALL LETTER KAPPA +0138;kgreenlandic;LATIN SMALL LETTER KRA +006C;l;LATIN SMALL LETTER L +013A;lacute;LATIN SMALL LETTER L WITH ACUTE +03BB;lambda;GREEK SMALL LETTER LAMDA +013E;lcaron;LATIN SMALL LETTER L WITH CARON +0140;ldot;LATIN SMALL LETTER L WITH MIDDLE DOT +003C;less;LESS-THAN SIGN +2264;lessequal;LESS-THAN OR EQUAL TO +258C;lfblock;LEFT HALF BLOCK +20A4;lira;LIRA SIGN +2227;logicaland;LOGICAL AND +00AC;logicalnot;NOT SIGN +2228;logicalor;LOGICAL OR +017F;longs;LATIN SMALL LETTER LONG S +25CA;lozenge;LOZENGE +0142;lslash;LATIN SMALL LETTER L WITH STROKE +2591;ltshade;LIGHT SHADE +006D;m;LATIN SMALL LETTER M +00AF;macron;MACRON +2642;male;MALE SIGN +2212;minus;MINUS SIGN +2032;minute;PRIME +00B5;mu;MICRO SIGN +00D7;multiply;MULTIPLICATION SIGN +266A;musicalnote;EIGHTH NOTE +266B;musicalnotedbl;BEAMED EIGHTH NOTES +006E;n;LATIN SMALL LETTER N +0144;nacute;LATIN SMALL LETTER N WITH ACUTE +0149;napostrophe;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +0148;ncaron;LATIN SMALL LETTER N WITH CARON +0039;nine;DIGIT NINE +2209;notelement;NOT AN ELEMENT OF +2260;notequal;NOT EQUAL TO +2284;notsubset;NOT A SUBSET OF +00F1;ntilde;LATIN SMALL LETTER N WITH TILDE +03BD;nu;GREEK SMALL LETTER NU +0023;numbersign;NUMBER SIGN +006F;o;LATIN SMALL LETTER O +00F3;oacute;LATIN SMALL LETTER O WITH ACUTE +014F;obreve;LATIN SMALL LETTER O WITH BREVE +00F4;ocircumflex;LATIN SMALL LETTER O WITH CIRCUMFLEX +00F6;odieresis;LATIN SMALL LETTER O WITH DIAERESIS +0153;oe;LATIN SMALL LIGATURE OE +02DB;ogonek;OGONEK +00F2;ograve;LATIN SMALL LETTER O WITH GRAVE +01A1;ohorn;LATIN SMALL LETTER O WITH HORN +0151;ohungarumlaut;LATIN SMALL LETTER O WITH DOUBLE ACUTE +014D;omacron;LATIN SMALL LETTER O WITH MACRON +03C9;omega;GREEK SMALL LETTER OMEGA +03D6;omega1;GREEK PI SYMBOL +03CE;omegatonos;GREEK SMALL LETTER OMEGA WITH TONOS +03BF;omicron;GREEK SMALL LETTER OMICRON +03CC;omicrontonos;GREEK SMALL LETTER OMICRON WITH TONOS +0031;one;DIGIT ONE +2024;onedotenleader;ONE DOT LEADER +215B;oneeighth;VULGAR FRACTION ONE EIGHTH +00BD;onehalf;VULGAR FRACTION ONE HALF +00BC;onequarter;VULGAR FRACTION ONE QUARTER +2153;onethird;VULGAR FRACTION ONE THIRD +25E6;openbullet;WHITE BULLET +00AA;ordfeminine;FEMININE ORDINAL INDICATOR +00BA;ordmasculine;MASCULINE ORDINAL INDICATOR +221F;orthogonal;RIGHT ANGLE +00F8;oslash;LATIN SMALL LETTER O WITH STROKE +01FF;oslashacute;LATIN SMALL LETTER O WITH STROKE AND ACUTE +00F5;otilde;LATIN SMALL LETTER O WITH TILDE +0070;p;LATIN SMALL LETTER P +00B6;paragraph;PILCROW SIGN +0028;parenleft;LEFT PARENTHESIS +0029;parenright;RIGHT PARENTHESIS +2202;partialdiff;PARTIAL DIFFERENTIAL +0025;percent;PERCENT SIGN +002E;period;FULL STOP +00B7;periodcentered;MIDDLE DOT +22A5;perpendicular;UP TACK +2030;perthousand;PER MILLE SIGN +20A7;peseta;PESETA SIGN +03C6;phi;GREEK SMALL LETTER PHI +03D5;phi1;GREEK PHI SYMBOL +03C0;pi;GREEK SMALL LETTER PI +002B;plus;PLUS SIGN +00B1;plusminus;PLUS-MINUS SIGN +211E;prescription;PRESCRIPTION TAKE +220F;product;N-ARY PRODUCT +2282;propersubset;SUBSET OF +2283;propersuperset;SUPERSET OF +221D;proportional;PROPORTIONAL TO +03C8;psi;GREEK SMALL LETTER PSI +0071;q;LATIN SMALL LETTER Q +003F;question;QUESTION MARK +00BF;questiondown;INVERTED QUESTION MARK +0022;quotedbl;QUOTATION MARK +201E;quotedblbase;DOUBLE LOW-9 QUOTATION MARK +201C;quotedblleft;LEFT DOUBLE QUOTATION MARK +201D;quotedblright;RIGHT DOUBLE QUOTATION MARK +2018;quoteleft;LEFT SINGLE QUOTATION MARK +201B;quotereversed;SINGLE HIGH-REVERSED-9 QUOTATION MARK +2019;quoteright;RIGHT SINGLE QUOTATION MARK +201A;quotesinglbase;SINGLE LOW-9 QUOTATION MARK +0027;quotesingle;APOSTROPHE +0072;r;LATIN SMALL LETTER R +0155;racute;LATIN SMALL LETTER R WITH ACUTE +221A;radical;SQUARE ROOT +0159;rcaron;LATIN SMALL LETTER R WITH CARON +2286;reflexsubset;SUBSET OF OR EQUAL TO +2287;reflexsuperset;SUPERSET OF OR EQUAL TO +00AE;registered;REGISTERED SIGN +2310;revlogicalnot;REVERSED NOT SIGN +03C1;rho;GREEK SMALL LETTER RHO +02DA;ring;RING ABOVE +2590;rtblock;RIGHT HALF BLOCK +0073;s;LATIN SMALL LETTER S +015B;sacute;LATIN SMALL LETTER S WITH ACUTE +0161;scaron;LATIN SMALL LETTER S WITH CARON +015F;scedilla;LATIN SMALL LETTER S WITH CEDILLA +015D;scircumflex;LATIN SMALL LETTER S WITH CIRCUMFLEX +2033;second;DOUBLE PRIME +00A7;section;SECTION SIGN +003B;semicolon;SEMICOLON +0037;seven;DIGIT SEVEN +215E;seveneighths;VULGAR FRACTION SEVEN EIGHTHS +2592;shade;MEDIUM SHADE +03C3;sigma;GREEK SMALL LETTER SIGMA +03C2;sigma1;GREEK SMALL LETTER FINAL SIGMA +223C;similar;TILDE OPERATOR +0036;six;DIGIT SIX +002F;slash;SOLIDUS +263A;smileface;WHITE SMILING FACE +0020;space;SPACE +2660;spade;BLACK SPADE SUIT +00A3;sterling;POUND SIGN +220B;suchthat;CONTAINS AS MEMBER +2211;summation;N-ARY SUMMATION +263C;sun;WHITE SUN WITH RAYS +0074;t;LATIN SMALL LETTER T +03C4;tau;GREEK SMALL LETTER TAU +0167;tbar;LATIN SMALL LETTER T WITH STROKE +0165;tcaron;LATIN SMALL LETTER T WITH CARON +2234;therefore;THEREFORE +03B8;theta;GREEK SMALL LETTER THETA +03D1;theta1;GREEK THETA SYMBOL +00FE;thorn;LATIN SMALL LETTER THORN +0033;three;DIGIT THREE +215C;threeeighths;VULGAR FRACTION THREE EIGHTHS +00BE;threequarters;VULGAR FRACTION THREE QUARTERS +02DC;tilde;SMALL TILDE +0303;tildecomb;COMBINING TILDE +0384;tonos;GREEK TONOS +2122;trademark;TRADE MARK SIGN +25BC;triagdn;BLACK DOWN-POINTING TRIANGLE +25C4;triaglf;BLACK LEFT-POINTING POINTER +25BA;triagrt;BLACK RIGHT-POINTING POINTER +25B2;triagup;BLACK UP-POINTING TRIANGLE +0032;two;DIGIT TWO +2025;twodotenleader;TWO DOT LEADER +2154;twothirds;VULGAR FRACTION TWO THIRDS +0075;u;LATIN SMALL LETTER U +00FA;uacute;LATIN SMALL LETTER U WITH ACUTE +016D;ubreve;LATIN SMALL LETTER U WITH BREVE +00FB;ucircumflex;LATIN SMALL LETTER U WITH CIRCUMFLEX +00FC;udieresis;LATIN SMALL LETTER U WITH DIAERESIS +00F9;ugrave;LATIN SMALL LETTER U WITH GRAVE +01B0;uhorn;LATIN SMALL LETTER U WITH HORN +0171;uhungarumlaut;LATIN SMALL LETTER U WITH DOUBLE ACUTE +016B;umacron;LATIN SMALL LETTER U WITH MACRON +005F;underscore;LOW LINE +2017;underscoredbl;DOUBLE LOW LINE +222A;union;UNION +2200;universal;FOR ALL +0173;uogonek;LATIN SMALL LETTER U WITH OGONEK +2580;upblock;UPPER HALF BLOCK +03C5;upsilon;GREEK SMALL LETTER UPSILON +03CB;upsilondieresis;GREEK SMALL LETTER UPSILON WITH DIALYTIKA +03B0;upsilondieresistonos;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03CD;upsilontonos;GREEK SMALL LETTER UPSILON WITH TONOS +016F;uring;LATIN SMALL LETTER U WITH RING ABOVE +0169;utilde;LATIN SMALL LETTER U WITH TILDE +0076;v;LATIN SMALL LETTER V +0077;w;LATIN SMALL LETTER W +1E83;wacute;LATIN SMALL LETTER W WITH ACUTE +0175;wcircumflex;LATIN SMALL LETTER W WITH CIRCUMFLEX +1E85;wdieresis;LATIN SMALL LETTER W WITH DIAERESIS +2118;weierstrass;SCRIPT CAPITAL P +1E81;wgrave;LATIN SMALL LETTER W WITH GRAVE +0078;x;LATIN SMALL LETTER X +03BE;xi;GREEK SMALL LETTER XI +0079;y;LATIN SMALL LETTER Y +00FD;yacute;LATIN SMALL LETTER Y WITH ACUTE +0177;ycircumflex;LATIN SMALL LETTER Y WITH CIRCUMFLEX +00FF;ydieresis;LATIN SMALL LETTER Y WITH DIAERESIS +00A5;yen;YEN SIGN +1EF3;ygrave;LATIN SMALL LETTER Y WITH GRAVE +007A;z;LATIN SMALL LETTER Z +017A;zacute;LATIN SMALL LETTER Z WITH ACUTE +017E;zcaron;LATIN SMALL LETTER Z WITH CARON +017C;zdotaccent;LATIN SMALL LETTER Z WITH DOT ABOVE +0030;zero;DIGIT ZERO +03B6;zeta;GREEK SMALL LETTER ZETA +# END +""" + + +class AGLError(Exception): + pass + + +LEGACY_AGL2UV = {} +AGL2UV = {} +UV2AGL = {} + + +def _builddicts(): + import re + + lines = _aglText.splitlines() + + parseAGL_RE = re.compile("([A-Za-z0-9]+);((?:[0-9A-F]{4})(?: (?:[0-9A-F]{4}))*)$") + + for line in lines: + if not line or line[:1] == "#": + continue + m = parseAGL_RE.match(line) + if not m: + raise AGLError("syntax error in glyphlist.txt: %s" % repr(line[:20])) + unicodes = m.group(2) + assert len(unicodes) % 5 == 4 + unicodes = [int(unicode, 16) for unicode in unicodes.split()] + glyphName = tostr(m.group(1)) + LEGACY_AGL2UV[glyphName] = unicodes + + lines = _aglfnText.splitlines() + + parseAGLFN_RE = re.compile("([0-9A-F]{4});([A-Za-z0-9]+);.*?$") + + for line in lines: + if not line or line[:1] == "#": + continue + m = parseAGLFN_RE.match(line) + if not m: + raise AGLError("syntax error in aglfn.txt: %s" % repr(line[:20])) + unicode = m.group(1) + assert len(unicode) == 4 + unicode = int(unicode, 16) + glyphName = tostr(m.group(2)) + AGL2UV[glyphName] = unicode + UV2AGL[unicode] = glyphName + + +_builddicts() + + +def toUnicode(glyph, isZapfDingbats=False): + """Convert glyph names to Unicode, such as ``'longs_t.oldstyle'`` --> ``u'ſt'`` + + If ``isZapfDingbats`` is ``True``, the implementation recognizes additional + glyph names (as required by the AGL specification). + """ + # https://github.com/adobe-type-tools/agl-specification#2-the-mapping + # + # 1. Drop all the characters from the glyph name starting with + # the first occurrence of a period (U+002E; FULL STOP), if any. + glyph = glyph.split(".", 1)[0] + + # 2. Split the remaining string into a sequence of components, + # using underscore (U+005F; LOW LINE) as the delimiter. + components = glyph.split("_") + + # 3. Map each component to a character string according to the + # procedure below, and concatenate those strings; the result + # is the character string to which the glyph name is mapped. + result = [_glyphComponentToUnicode(c, isZapfDingbats) for c in components] + return "".join(result) + + +def _glyphComponentToUnicode(component, isZapfDingbats): + # If the font is Zapf Dingbats (PostScript FontName: ZapfDingbats), + # and the component is in the ITC Zapf Dingbats Glyph List, then + # map it to the corresponding character in that list. + dingbat = _zapfDingbatsToUnicode(component) if isZapfDingbats else None + if dingbat: + return dingbat + + # Otherwise, if the component is in AGL, then map it + # to the corresponding character in that list. + uchars = LEGACY_AGL2UV.get(component) + if uchars: + return "".join(map(chr, uchars)) + + # Otherwise, if the component is of the form "uni" (U+0075, + # U+006E, and U+0069) followed by a sequence of uppercase + # hexadecimal digits (0–9 and A–F, meaning U+0030 through + # U+0039 and U+0041 through U+0046), if the length of that + # sequence is a multiple of four, and if each group of four + # digits represents a value in the ranges 0000 through D7FF + # or E000 through FFFF, then interpret each as a Unicode scalar + # value and map the component to the string made of those + # scalar values. Note that the range and digit-length + # restrictions mean that the "uni" glyph name prefix can be + # used only with UVs in the Basic Multilingual Plane (BMP). + uni = _uniToUnicode(component) + if uni: + return uni + + # Otherwise, if the component is of the form "u" (U+0075) + # followed by a sequence of four to six uppercase hexadecimal + # digits (0–9 and A–F, meaning U+0030 through U+0039 and + # U+0041 through U+0046), and those digits represents a value + # in the ranges 0000 through D7FF or E000 through 10FFFF, then + # interpret it as a Unicode scalar value and map the component + # to the string made of this scalar value. + uni = _uToUnicode(component) + if uni: + return uni + + # Otherwise, map the component to an empty string. + return "" + + +# https://github.com/adobe-type-tools/agl-aglfn/blob/master/zapfdingbats.txt +_AGL_ZAPF_DINGBATS = ( + " ✁✂✄☎✆✝✞✟✠✡☛☞✌✍✎✏✑✒✓✔✕✖✗✘✙✚✛✜✢✣✤✥✦✧★✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀" + "❁❂❃❄❅❆❇❈❉❊❋●❍■❏❑▲▼◆❖ ◗❘❙❚❯❱❲❳❨❩❬❭❪❫❴❵❛❜❝❞❡❢❣❤✐❥❦❧♠♥♦♣ ✉✈✇" + "①②③④⑤⑥⑦⑧⑨⑩❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔→➣↔" + "↕➙➛➜➝➞➟➠➡➢➤➥➦➧➨➩➫➭➯➲➳➵➸➺➻➼➽➾➚➪➶➹➘➴➷➬➮➱✃❐❒❮❰" +) + + +def _zapfDingbatsToUnicode(glyph): + """Helper for toUnicode().""" + if len(glyph) < 2 or glyph[0] != "a": + return None + try: + gid = int(glyph[1:]) + except ValueError: + return None + if gid < 0 or gid >= len(_AGL_ZAPF_DINGBATS): + return None + uchar = _AGL_ZAPF_DINGBATS[gid] + return uchar if uchar != " " else None + + +_re_uni = re.compile("^uni([0-9A-F]+)$") + + +def _uniToUnicode(component): + """Helper for toUnicode() to handle "uniABCD" components.""" + match = _re_uni.match(component) + if match is None: + return None + digits = match.group(1) + if len(digits) % 4 != 0: + return None + chars = [int(digits[i : i + 4], 16) for i in range(0, len(digits), 4)] + if any(c >= 0xD800 and c <= 0xDFFF for c in chars): + # The AGL specification explicitly excluded surrogate pairs. + return None + return "".join([chr(c) for c in chars]) + + +_re_u = re.compile("^u([0-9A-F]{4,6})$") + + +def _uToUnicode(component): + """Helper for toUnicode() to handle "u1ABCD" components.""" + match = _re_u.match(component) + if match is None: + return None + digits = match.group(1) + try: + value = int(digits, 16) + except ValueError: + return None + if (value >= 0x0000 and value <= 0xD7FF) or (value >= 0xE000 and value <= 0x10FFFF): + return chr(value) + return None diff --git a/.venv/lib/python3.12/site-packages/fontTools/annotations.py b/.venv/lib/python3.12/site-packages/fontTools/annotations.py new file mode 100644 index 0000000..5ff5972 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/annotations.py @@ -0,0 +1,30 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Iterable, Optional, TypeVar, Union +from collections.abc import Callable, Sequence +from fontTools.misc.filesystem._base import FS +from os import PathLike +from xml.etree.ElementTree import Element as ElementTreeElement + +if TYPE_CHECKING: + from fontTools.ufoLib import UFOFormatVersion + from fontTools.ufoLib.glifLib import GLIFFormatVersion + from lxml.etree import _Element as LxmlElement + + +T = TypeVar("T") # Generic type +K = TypeVar("K") # Generic dict key type +V = TypeVar("V") # Generic dict value type + +GlyphNameToFileNameFunc = Optional[Callable[[str, set[str]], str]] +ElementType = Union[ElementTreeElement, "LxmlElement"] +FormatVersion = Union[int, tuple[int, int]] +FormatVersions = Optional[Iterable[FormatVersion]] +GLIFFormatVersionInput = Optional[Union[int, tuple[int, int], "GLIFFormatVersion"]] +UFOFormatVersionInput = Optional[Union[int, tuple[int, int], "UFOFormatVersion"]] +IntFloat = Union[int, float] +KerningPair = tuple[str, str] +KerningDict = dict[KerningPair, IntFloat] +KerningGroups = dict[str, Sequence[str]] +KerningNested = dict[str, dict[str, IntFloat]] +PathStr = Union[str, PathLike[str]] +PathOrFS = Union[PathStr, FS] diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFF2ToCFF.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFF2ToCFF.py new file mode 100644 index 0000000..f33e48c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFF2ToCFF.py @@ -0,0 +1,258 @@ +"""CFF2 to CFF converter.""" + +from fontTools.ttLib import TTFont, newTable +from fontTools.misc.cliTools import makeOutputFileName +from fontTools.misc.psCharStrings import T2StackUseExtractor +from fontTools.cffLib import ( + TopDictIndex, + buildOrder, + buildDefaults, + topDictOperators, + privateDictOperators, + FDSelect, +) +from .transforms import desubroutinizeCharString +from .specializer import specializeProgram +from .width import optimizeWidths +from collections import defaultdict +import logging + + +__all__ = ["convertCFF2ToCFF", "main"] + + +log = logging.getLogger("fontTools.cffLib") + + +def _convertCFF2ToCFF(cff, otFont): + """Converts this object from CFF2 format to CFF format. This conversion + is done 'in-place'. The conversion cannot be reversed. + + The CFF2 font cannot be variable. (TODO Accept those and convert to the + default instance?) + + This assumes a decompiled CFF2 table. (i.e. that the object has been + filled via :meth:`decompile` and e.g. not loaded from XML.)""" + + cff.major = 1 + + topDictData = TopDictIndex(None) + for item in cff.topDictIndex: + # Iterate over, such that all are decompiled + item.cff2GetGlyphOrder = None + topDictData.append(item) + cff.topDictIndex = topDictData + topDict = topDictData[0] + + if hasattr(topDict, "VarStore"): + raise ValueError("Variable CFF2 font cannot be converted to CFF format.") + + opOrder = buildOrder(topDictOperators) + topDict.order = opOrder + for key in topDict.rawDict.keys(): + if key not in opOrder: + del topDict.rawDict[key] + if hasattr(topDict, key): + delattr(topDict, key) + + charStrings = topDict.CharStrings + + fdArray = topDict.FDArray + if not hasattr(topDict, "FDSelect"): + # FDSelect is optional in CFF2, but required in CFF. + fdSelect = topDict.FDSelect = FDSelect() + fdSelect.gidArray = [0] * len(charStrings.charStrings) + + defaults = buildDefaults(privateDictOperators) + order = buildOrder(privateDictOperators) + for fd in fdArray: + fd.setCFF2(False) + privateDict = fd.Private + privateDict.order = order + for key in order: + if key not in privateDict.rawDict and key in defaults: + privateDict.rawDict[key] = defaults[key] + for key in privateDict.rawDict.keys(): + if key not in order: + del privateDict.rawDict[key] + if hasattr(privateDict, key): + delattr(privateDict, key) + + # Add ending operators + for cs in charStrings.values(): + cs.decompile() + cs.program.append("endchar") + for subrSets in [cff.GlobalSubrs] + [ + getattr(fd.Private, "Subrs", []) for fd in fdArray + ]: + for cs in subrSets: + cs.program.append("return") + + # Add (optimal) width to CharStrings that need it. + widths = defaultdict(list) + metrics = otFont["hmtx"].metrics + for glyphName in charStrings.keys(): + cs, fdIndex = charStrings.getItemAndSelector(glyphName) + if fdIndex == None: + fdIndex = 0 + widths[fdIndex].append(metrics[glyphName][0]) + for fdIndex, widthList in widths.items(): + bestDefault, bestNominal = optimizeWidths(widthList) + private = fdArray[fdIndex].Private + private.defaultWidthX = bestDefault + private.nominalWidthX = bestNominal + for glyphName in charStrings.keys(): + cs, fdIndex = charStrings.getItemAndSelector(glyphName) + if fdIndex == None: + fdIndex = 0 + private = fdArray[fdIndex].Private + width = metrics[glyphName][0] + if width != private.defaultWidthX: + cs.program.insert(0, width - private.nominalWidthX) + + # Handle stack use since stack-depth is lower in CFF than in CFF2. + for glyphName in charStrings.keys(): + cs, fdIndex = charStrings.getItemAndSelector(glyphName) + if fdIndex is None: + fdIndex = 0 + private = fdArray[fdIndex].Private + extractor = T2StackUseExtractor( + getattr(private, "Subrs", []), cff.GlobalSubrs, private=private + ) + stackUse = extractor.execute(cs) + if stackUse > 48: # CFF stack depth is 48 + desubroutinizeCharString(cs) + cs.program = specializeProgram(cs.program) + + # Unused subroutines are still in CFF2 (ie. lacking 'return' operator) + # because they were not decompiled when we added the 'return'. + # Moreover, some used subroutines may have become unused after the + # stack-use fixup. So we remove all unused subroutines now. + cff.remove_unused_subroutines() + + mapping = { + name: ("cid" + str(n).zfill(5) if n else ".notdef") + for n, name in enumerate(topDict.charset) + } + topDict.charset = [ + "cid" + str(n).zfill(5) if n else ".notdef" for n in range(len(topDict.charset)) + ] + charStrings.charStrings = { + mapping[name]: v for name, v in charStrings.charStrings.items() + } + + topDict.ROS = ("Adobe", "Identity", 0) + + +def convertCFF2ToCFF(font, *, updatePostTable=True): + if "CFF2" not in font: + raise ValueError("Input font does not contain a CFF2 table.") + cff = font["CFF2"].cff + _convertCFF2ToCFF(cff, font) + del font["CFF2"] + table = font["CFF "] = newTable("CFF ") + table.cff = cff + + if updatePostTable and "post" in font: + # Only version supported for fonts with CFF table is 0x00030000 not 0x20000 + post = font["post"] + if post.formatType == 2.0: + post.formatType = 3.0 + + +def main(args=None): + """Convert CFF2 OTF font to CFF OTF font""" + if args is None: + import sys + + args = sys.argv[1:] + + import argparse + + parser = argparse.ArgumentParser( + "fonttools cffLib.CFF2ToCFF", + description="Convert a non-variable CFF2 font to CFF.", + ) + parser.add_argument( + "input", metavar="INPUT.ttf", help="Input OTF file with CFF table." + ) + parser.add_argument( + "-o", + "--output", + metavar="OUTPUT.ttf", + default=None, + help="Output instance OTF file (default: INPUT-CFF2.ttf).", + ) + parser.add_argument( + "--no-recalc-timestamp", + dest="recalc_timestamp", + action="store_false", + help="Don't set the output font's timestamp to the current time.", + ) + parser.add_argument( + "--remove-overlaps", + action="store_true", + help="Merge overlapping contours and components. Requires skia-pathops", + ) + parser.add_argument( + "--ignore-overlap-errors", + action="store_true", + help="Don't crash if the remove-overlaps operation fails for some glyphs.", + ) + loggingGroup = parser.add_mutually_exclusive_group(required=False) + loggingGroup.add_argument( + "-v", "--verbose", action="store_true", help="Run more verbosely." + ) + loggingGroup.add_argument( + "-q", "--quiet", action="store_true", help="Turn verbosity off." + ) + options = parser.parse_args(args) + + from fontTools import configLogger + + configLogger( + level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO") + ) + + import os + + infile = options.input + if not os.path.isfile(infile): + parser.error("No such file '{}'".format(infile)) + + outfile = ( + makeOutputFileName(infile, overWrite=True, suffix="-CFF") + if not options.output + else options.output + ) + + font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False) + + convertCFF2ToCFF(font) + + if options.remove_overlaps: + from fontTools.ttLib.removeOverlaps import removeOverlaps + from io import BytesIO + + log.debug("Removing overlaps") + + stream = BytesIO() + font.save(stream) + stream.seek(0) + font = TTFont(stream, recalcTimestamp=False, recalcBBoxes=False) + removeOverlaps( + font, + ignoreErrors=options.ignore_overlap_errors, + ) + + log.info( + "Saving %s", + outfile, + ) + font.save(outfile) + + +if __name__ == "__main__": + import sys + + sys.exit(main(sys.argv[1:])) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFFToCFF2.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFFToCFF2.py new file mode 100644 index 0000000..2555f0b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/CFFToCFF2.py @@ -0,0 +1,305 @@ +"""CFF to CFF2 converter.""" + +from fontTools.ttLib import TTFont, newTable +from fontTools.misc.cliTools import makeOutputFileName +from fontTools.misc.psCharStrings import T2WidthExtractor +from fontTools.cffLib import ( + TopDictIndex, + FDArrayIndex, + FontDict, + buildOrder, + topDictOperators, + privateDictOperators, + topDictOperators2, + privateDictOperators2, +) +from io import BytesIO +import logging + +__all__ = ["convertCFFToCFF2", "main"] + + +log = logging.getLogger("fontTools.cffLib") + + +class _NominalWidthUsedError(Exception): + def __add__(self, other): + raise self + + def __radd__(self, other): + raise self + + +def _convertCFFToCFF2(cff, otFont): + """Converts this object from CFF format to CFF2 format. This conversion + is done 'in-place'. The conversion cannot be reversed. + + This assumes a decompiled CFF table. (i.e. that the object has been + filled via :meth:`decompile` and e.g. not loaded from XML.)""" + + # Clean up T2CharStrings + + topDict = cff.topDictIndex[0] + fdArray = topDict.FDArray if hasattr(topDict, "FDArray") else None + charStrings = topDict.CharStrings + globalSubrs = cff.GlobalSubrs + localSubrs = ( + [getattr(fd.Private, "Subrs", []) for fd in fdArray] + if fdArray + else ( + [topDict.Private.Subrs] + if hasattr(topDict, "Private") and hasattr(topDict.Private, "Subrs") + else [] + ) + ) + + for glyphName in charStrings.keys(): + cs, fdIndex = charStrings.getItemAndSelector(glyphName) + cs.decompile() + + # Clean up subroutines first + for subrs in [globalSubrs] + localSubrs: + for subr in subrs: + program = subr.program + i = j = len(program) + try: + i = program.index("return") + except ValueError: + pass + try: + j = program.index("endchar") + except ValueError: + pass + program[min(i, j) :] = [] + + # Clean up glyph charstrings + removeUnusedSubrs = False + nominalWidthXError = _NominalWidthUsedError() + for glyphName in charStrings.keys(): + cs, fdIndex = charStrings.getItemAndSelector(glyphName) + program = cs.program + + thisLocalSubrs = ( + localSubrs[fdIndex] + if fdIndex is not None + else ( + getattr(topDict.Private, "Subrs", []) + if hasattr(topDict, "Private") + else [] + ) + ) + + # Intentionally use custom type for nominalWidthX, such that any + # CharString that has an explicit width encoded will throw back to us. + extractor = T2WidthExtractor( + thisLocalSubrs, + globalSubrs, + nominalWidthXError, + 0, + ) + try: + extractor.execute(cs) + except _NominalWidthUsedError: + # Program has explicit width. We want to drop it, but can't + # just pop the first number since it may be a subroutine call. + # Instead, when seeing that, we embed the subroutine and recurse. + # If this ever happened, we later prune unused subroutines. + while len(program) >= 2 and program[1] in ["callsubr", "callgsubr"]: + removeUnusedSubrs = True + subrNumber = program.pop(0) + assert isinstance(subrNumber, int), subrNumber + op = program.pop(0) + bias = extractor.localBias if op == "callsubr" else extractor.globalBias + subrNumber += bias + subrSet = thisLocalSubrs if op == "callsubr" else globalSubrs + subrProgram = subrSet[subrNumber].program + program[:0] = subrProgram + # Now pop the actual width + assert len(program) >= 1, program + program.pop(0) + + if program and program[-1] == "endchar": + program.pop() + + if removeUnusedSubrs: + cff.remove_unused_subroutines() + + # Upconvert TopDict + + cff.major = 2 + cff2GetGlyphOrder = cff.otFont.getGlyphOrder + topDictData = TopDictIndex(None, cff2GetGlyphOrder) + for item in cff.topDictIndex: + # Iterate over, such that all are decompiled + topDictData.append(item) + cff.topDictIndex = topDictData + topDict = topDictData[0] + if hasattr(topDict, "Private"): + privateDict = topDict.Private + else: + privateDict = None + opOrder = buildOrder(topDictOperators2) + topDict.order = opOrder + topDict.cff2GetGlyphOrder = cff2GetGlyphOrder + + if not hasattr(topDict, "FDArray"): + fdArray = topDict.FDArray = FDArrayIndex() + fdArray.strings = None + fdArray.GlobalSubrs = topDict.GlobalSubrs + topDict.GlobalSubrs.fdArray = fdArray + charStrings = topDict.CharStrings + if charStrings.charStringsAreIndexed: + charStrings.charStringsIndex.fdArray = fdArray + else: + charStrings.fdArray = fdArray + fontDict = FontDict() + fontDict.setCFF2(True) + fdArray.append(fontDict) + fontDict.Private = privateDict + privateOpOrder = buildOrder(privateDictOperators2) + if privateDict is not None: + for entry in privateDictOperators: + key = entry[1] + if key not in privateOpOrder: + if key in privateDict.rawDict: + # print "Removing private dict", key + del privateDict.rawDict[key] + if hasattr(privateDict, key): + delattr(privateDict, key) + # print "Removing privateDict attr", key + else: + # clean up the PrivateDicts in the fdArray + fdArray = topDict.FDArray + privateOpOrder = buildOrder(privateDictOperators2) + for fontDict in fdArray: + fontDict.setCFF2(True) + for key in list(fontDict.rawDict.keys()): + if key not in fontDict.order: + del fontDict.rawDict[key] + if hasattr(fontDict, key): + delattr(fontDict, key) + + privateDict = fontDict.Private + for entry in privateDictOperators: + key = entry[1] + if key not in privateOpOrder: + if key in list(privateDict.rawDict.keys()): + # print "Removing private dict", key + del privateDict.rawDict[key] + if hasattr(privateDict, key): + delattr(privateDict, key) + # print "Removing privateDict attr", key + + # Now delete up the deprecated topDict operators from CFF 1.0 + for entry in topDictOperators: + key = entry[1] + # We seem to need to keep the charset operator for now, + # or we fail to compile with some fonts, like AdditionFont.otf. + # I don't know which kind of CFF font those are. But keeping + # charset seems to work. It will be removed when we save and + # read the font again. + # + # AdditionFont.otf has . + if key == "charset": + continue + if key not in opOrder: + if key in topDict.rawDict: + del topDict.rawDict[key] + if hasattr(topDict, key): + delattr(topDict, key) + + # TODO(behdad): What does the following comment even mean? Both CFF and CFF2 + # use the same T2Charstring class. I *think* what it means is that the CharStrings + # were loaded for CFF1, and we need to reload them for CFF2 to set varstore, etc + # on them. At least that's what I understand. It's probably safe to remove this + # and just set vstore where needed. + # + # See comment above about charset as well. + + # At this point, the Subrs and Charstrings are all still T2Charstring class + # easiest to fix this by compiling, then decompiling again + file = BytesIO() + cff.compile(file, otFont, isCFF2=True) + file.seek(0) + cff.decompile(file, otFont, isCFF2=True) + + +def convertCFFToCFF2(font): + cff = font["CFF "].cff + del font["CFF "] + _convertCFFToCFF2(cff, font) + table = font["CFF2"] = newTable("CFF2") + table.cff = cff + + +def main(args=None): + """Convert CFF OTF font to CFF2 OTF font""" + if args is None: + import sys + + args = sys.argv[1:] + + import argparse + + parser = argparse.ArgumentParser( + "fonttools cffLib.CFFToCFF2", + description="Upgrade a CFF font to CFF2.", + ) + parser.add_argument( + "input", metavar="INPUT.ttf", help="Input OTF file with CFF table." + ) + parser.add_argument( + "-o", + "--output", + metavar="OUTPUT.ttf", + default=None, + help="Output instance OTF file (default: INPUT-CFF2.ttf).", + ) + parser.add_argument( + "--no-recalc-timestamp", + dest="recalc_timestamp", + action="store_false", + help="Don't set the output font's timestamp to the current time.", + ) + loggingGroup = parser.add_mutually_exclusive_group(required=False) + loggingGroup.add_argument( + "-v", "--verbose", action="store_true", help="Run more verbosely." + ) + loggingGroup.add_argument( + "-q", "--quiet", action="store_true", help="Turn verbosity off." + ) + options = parser.parse_args(args) + + from fontTools import configLogger + + configLogger( + level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO") + ) + + import os + + infile = options.input + if not os.path.isfile(infile): + parser.error("No such file '{}'".format(infile)) + + outfile = ( + makeOutputFileName(infile, overWrite=True, suffix="-CFF2") + if not options.output + else options.output + ) + + font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False) + + convertCFFToCFF2(font) + + log.info( + "Saving %s", + outfile, + ) + font.save(outfile) + + +if __name__ == "__main__": + import sys + + sys.exit(main(sys.argv[1:])) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__init__.py new file mode 100644 index 0000000..4ad724a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__init__.py @@ -0,0 +1,3694 @@ +"""cffLib: read/write Adobe CFF fonts + +OpenType fonts with PostScript outlines embed a completely independent +font file in Adobe's *Compact Font Format*. So dealing with OpenType fonts +requires also dealing with CFF. This module allows you to read and write +fonts written in the CFF format. + +In 2016, OpenType 1.8 introduced the `CFF2 `_ +format which, along with other changes, extended the CFF format to deal with +the demands of variable fonts. This module parses both original CFF and CFF2. + +""" + +from fontTools.misc import sstruct +from fontTools.misc import psCharStrings +from fontTools.misc.arrayTools import unionRect, intRect +from fontTools.misc.textTools import ( + bytechr, + byteord, + bytesjoin, + tobytes, + tostr, + safeEval, +) +from fontTools.ttLib import TTFont +from fontTools.ttLib.tables.otBase import OTTableWriter +from fontTools.ttLib.tables.otBase import OTTableReader +from fontTools.ttLib.tables import otTables as ot +from io import BytesIO +import struct +import logging +import re + +# mute cffLib debug messages when running ttx in verbose mode +DEBUG = logging.DEBUG - 1 +log = logging.getLogger(__name__) + +cffHeaderFormat = """ + major: B + minor: B + hdrSize: B +""" + +maxStackLimit = 513 +# maxstack operator has been deprecated. max stack is now always 513. + + +class CFFFontSet(object): + """A CFF font "file" can contain more than one font, although this is + extremely rare (and not allowed within OpenType fonts). + + This class is the entry point for parsing a CFF table. To actually + manipulate the data inside the CFF font, you will want to access the + ``CFFFontSet``'s :class:`TopDict` object. To do this, a ``CFFFontSet`` + object can either be treated as a dictionary (with appropriate + ``keys()`` and ``values()`` methods) mapping font names to :class:`TopDict` + objects, or as a list. + + .. code:: python + + from fontTools import ttLib + tt = ttLib.TTFont("Tests/cffLib/data/LinLibertine_RBI.otf") + tt["CFF "].cff + # + tt["CFF "].cff[0] # Here's your actual font data + # + + """ + + def decompile(self, file, otFont, isCFF2=None): + """Parse a binary CFF file into an internal representation. ``file`` + should be a file handle object. ``otFont`` is the top-level + :py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file. + + If ``isCFF2`` is passed and set to ``True`` or ``False``, then the + library makes an assertion that the CFF header is of the appropriate + version. + """ + + self.otFont = otFont + sstruct.unpack(cffHeaderFormat, file.read(3), self) + if isCFF2 is not None: + # called from ttLib: assert 'major' as read from file matches the + # expected version + expected_major = 2 if isCFF2 else 1 + if self.major != expected_major: + raise ValueError( + "Invalid CFF 'major' version: expected %d, found %d" + % (expected_major, self.major) + ) + else: + # use 'major' version from file to determine if isCFF2 + assert self.major in (1, 2), "Unknown CFF format" + isCFF2 = self.major == 2 + if not isCFF2: + self.offSize = struct.unpack("B", file.read(1))[0] + file.seek(self.hdrSize) + self.fontNames = list(tostr(s) for s in Index(file, isCFF2=isCFF2)) + self.topDictIndex = TopDictIndex(file, isCFF2=isCFF2) + self.strings = IndexedStrings(file) + else: # isCFF2 + self.topDictSize = struct.unpack(">H", file.read(2))[0] + file.seek(self.hdrSize) + self.fontNames = ["CFF2Font"] + cff2GetGlyphOrder = otFont.getGlyphOrder + # in CFF2, offsetSize is the size of the TopDict data. + self.topDictIndex = TopDictIndex( + file, cff2GetGlyphOrder, self.topDictSize, isCFF2=isCFF2 + ) + self.strings = None + self.GlobalSubrs = GlobalSubrsIndex(file, isCFF2=isCFF2) + self.topDictIndex.strings = self.strings + self.topDictIndex.GlobalSubrs = self.GlobalSubrs + + def __len__(self): + return len(self.fontNames) + + def keys(self): + return list(self.fontNames) + + def values(self): + return self.topDictIndex + + def __getitem__(self, nameOrIndex): + """Return TopDict instance identified by name (str) or index (int + or any object that implements `__index__`). + """ + if hasattr(nameOrIndex, "__index__"): + index = nameOrIndex.__index__() + elif isinstance(nameOrIndex, str): + name = nameOrIndex + try: + index = self.fontNames.index(name) + except ValueError: + raise KeyError(nameOrIndex) + else: + raise TypeError(nameOrIndex) + return self.topDictIndex[index] + + def compile(self, file, otFont, isCFF2=None): + """Write the object back into binary representation onto the given file. + ``file`` should be a file handle object. ``otFont`` is the top-level + :py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file. + + If ``isCFF2`` is passed and set to ``True`` or ``False``, then the + library makes an assertion that the CFF header is of the appropriate + version. + """ + self.otFont = otFont + if isCFF2 is not None: + # called from ttLib: assert 'major' value matches expected version + expected_major = 2 if isCFF2 else 1 + if self.major != expected_major: + raise ValueError( + "Invalid CFF 'major' version: expected %d, found %d" + % (expected_major, self.major) + ) + else: + # use current 'major' value to determine output format + assert self.major in (1, 2), "Unknown CFF format" + isCFF2 = self.major == 2 + + if otFont.recalcBBoxes and not isCFF2: + for topDict in self.topDictIndex: + topDict.recalcFontBBox() + + if not isCFF2: + strings = IndexedStrings() + else: + strings = None + writer = CFFWriter(isCFF2) + topCompiler = self.topDictIndex.getCompiler(strings, self, isCFF2=isCFF2) + if isCFF2: + self.hdrSize = 5 + writer.add(sstruct.pack(cffHeaderFormat, self)) + # Note: topDictSize will most likely change in CFFWriter.toFile(). + self.topDictSize = topCompiler.getDataLength() + writer.add(struct.pack(">H", self.topDictSize)) + else: + self.hdrSize = 4 + self.offSize = 4 # will most likely change in CFFWriter.toFile(). + writer.add(sstruct.pack(cffHeaderFormat, self)) + writer.add(struct.pack("B", self.offSize)) + if not isCFF2: + fontNames = Index() + for name in self.fontNames: + fontNames.append(name) + writer.add(fontNames.getCompiler(strings, self, isCFF2=isCFF2)) + writer.add(topCompiler) + if not isCFF2: + writer.add(strings.getCompiler()) + writer.add(self.GlobalSubrs.getCompiler(strings, self, isCFF2=isCFF2)) + + for topDict in self.topDictIndex: + if not hasattr(topDict, "charset") or topDict.charset is None: + charset = otFont.getGlyphOrder() + topDict.charset = charset + children = topCompiler.getChildren(strings) + for child in children: + writer.add(child) + + writer.toFile(file) + + def toXML(self, xmlWriter): + """Write the object into XML representation onto the given + :class:`fontTools.misc.xmlWriter.XMLWriter`. + + .. code:: python + + writer = xmlWriter.XMLWriter(sys.stdout) + tt["CFF "].cff.toXML(writer) + + """ + + xmlWriter.simpletag("major", value=self.major) + xmlWriter.newline() + xmlWriter.simpletag("minor", value=self.minor) + xmlWriter.newline() + for fontName in self.fontNames: + xmlWriter.begintag("CFFFont", name=tostr(fontName)) + xmlWriter.newline() + font = self[fontName] + font.toXML(xmlWriter) + xmlWriter.endtag("CFFFont") + xmlWriter.newline() + xmlWriter.newline() + xmlWriter.begintag("GlobalSubrs") + xmlWriter.newline() + self.GlobalSubrs.toXML(xmlWriter) + xmlWriter.endtag("GlobalSubrs") + xmlWriter.newline() + + def fromXML(self, name, attrs, content, otFont=None): + """Reads data from the XML element into the ``CFFFontSet`` object.""" + self.otFont = otFont + + # set defaults. These will be replaced if there are entries for them + # in the XML file. + if not hasattr(self, "major"): + self.major = 1 + if not hasattr(self, "minor"): + self.minor = 0 + + if name == "CFFFont": + if self.major == 1: + if not hasattr(self, "offSize"): + # this will be recalculated when the cff is compiled. + self.offSize = 4 + if not hasattr(self, "hdrSize"): + self.hdrSize = 4 + if not hasattr(self, "GlobalSubrs"): + self.GlobalSubrs = GlobalSubrsIndex() + if not hasattr(self, "fontNames"): + self.fontNames = [] + self.topDictIndex = TopDictIndex() + fontName = attrs["name"] + self.fontNames.append(fontName) + topDict = TopDict(GlobalSubrs=self.GlobalSubrs) + topDict.charset = None # gets filled in later + elif self.major == 2: + if not hasattr(self, "hdrSize"): + self.hdrSize = 5 + if not hasattr(self, "GlobalSubrs"): + self.GlobalSubrs = GlobalSubrsIndex() + if not hasattr(self, "fontNames"): + self.fontNames = ["CFF2Font"] + cff2GetGlyphOrder = self.otFont.getGlyphOrder + topDict = TopDict( + GlobalSubrs=self.GlobalSubrs, cff2GetGlyphOrder=cff2GetGlyphOrder + ) + self.topDictIndex = TopDictIndex(None, cff2GetGlyphOrder) + self.topDictIndex.append(topDict) + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + topDict.fromXML(name, attrs, content) + + if hasattr(topDict, "VarStore") and topDict.FDArray[0].vstore is None: + fdArray = topDict.FDArray + for fontDict in fdArray: + if hasattr(fontDict, "Private"): + fontDict.Private.vstore = topDict.VarStore + + elif name == "GlobalSubrs": + subrCharStringClass = psCharStrings.T2CharString + if not hasattr(self, "GlobalSubrs"): + self.GlobalSubrs = GlobalSubrsIndex() + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + subr = subrCharStringClass() + subr.fromXML(name, attrs, content) + self.GlobalSubrs.append(subr) + elif name == "major": + self.major = int(attrs["value"]) + elif name == "minor": + self.minor = int(attrs["value"]) + + def convertCFFToCFF2(self, otFont): + from .CFFToCFF2 import _convertCFFToCFF2 + + _convertCFFToCFF2(self, otFont) + + def convertCFF2ToCFF(self, otFont): + from .CFF2ToCFF import _convertCFF2ToCFF + + _convertCFF2ToCFF(self, otFont) + + def desubroutinize(self): + from .transforms import desubroutinize + + desubroutinize(self) + + def remove_hints(self): + from .transforms import remove_hints + + remove_hints(self) + + def remove_unused_subroutines(self): + from .transforms import remove_unused_subroutines + + remove_unused_subroutines(self) + + +class CFFWriter(object): + """Helper class for serializing CFF data to binary. Used by + :meth:`CFFFontSet.compile`.""" + + def __init__(self, isCFF2): + self.data = [] + self.isCFF2 = isCFF2 + + def add(self, table): + self.data.append(table) + + def toFile(self, file): + lastPosList = None + count = 1 + while True: + log.log(DEBUG, "CFFWriter.toFile() iteration: %d", count) + count = count + 1 + pos = 0 + posList = [pos] + for item in self.data: + if hasattr(item, "getDataLength"): + endPos = pos + item.getDataLength() + if isinstance(item, TopDictIndexCompiler) and item.isCFF2: + self.topDictSize = item.getDataLength() + else: + endPos = pos + len(item) + if hasattr(item, "setPos"): + item.setPos(pos, endPos) + pos = endPos + posList.append(pos) + if posList == lastPosList: + break + lastPosList = posList + log.log(DEBUG, "CFFWriter.toFile() writing to file.") + begin = file.tell() + if self.isCFF2: + self.data[1] = struct.pack(">H", self.topDictSize) + else: + self.offSize = calcOffSize(lastPosList[-1]) + self.data[1] = struct.pack("B", self.offSize) + posList = [0] + for item in self.data: + if hasattr(item, "toFile"): + item.toFile(file) + else: + file.write(item) + posList.append(file.tell() - begin) + assert posList == lastPosList + + +def calcOffSize(largestOffset): + if largestOffset < 0x100: + offSize = 1 + elif largestOffset < 0x10000: + offSize = 2 + elif largestOffset < 0x1000000: + offSize = 3 + else: + offSize = 4 + return offSize + + +class IndexCompiler(object): + """Base class for writing CFF `INDEX data `_ + to binary.""" + + def __init__(self, items, strings, parent, isCFF2=None): + if isCFF2 is None and hasattr(parent, "isCFF2"): + isCFF2 = parent.isCFF2 + assert isCFF2 is not None + self.isCFF2 = isCFF2 + self.items = self.getItems(items, strings) + self.parent = parent + + def getItems(self, items, strings): + return items + + def getOffsets(self): + # An empty INDEX contains only the count field. + if self.items: + pos = 1 + offsets = [pos] + for item in self.items: + if hasattr(item, "getDataLength"): + pos = pos + item.getDataLength() + else: + pos = pos + len(item) + offsets.append(pos) + else: + offsets = [] + return offsets + + def getDataLength(self): + if self.isCFF2: + countSize = 4 + else: + countSize = 2 + + if self.items: + lastOffset = self.getOffsets()[-1] + offSize = calcOffSize(lastOffset) + dataLength = ( + countSize + + 1 # count + + (len(self.items) + 1) * offSize # offSize + + lastOffset # the offsets + - 1 # size of object data + ) + else: + # count. For empty INDEX tables, this is the only entry. + dataLength = countSize + + return dataLength + + def toFile(self, file): + offsets = self.getOffsets() + if self.isCFF2: + writeCard32(file, len(self.items)) + else: + writeCard16(file, len(self.items)) + # An empty INDEX contains only the count field. + if self.items: + offSize = calcOffSize(offsets[-1]) + writeCard8(file, offSize) + offSize = -offSize + pack = struct.pack + for offset in offsets: + binOffset = pack(">l", offset)[offSize:] + assert len(binOffset) == -offSize + file.write(binOffset) + for item in self.items: + if hasattr(item, "toFile"): + item.toFile(file) + else: + data = tobytes(item, encoding="latin1") + file.write(data) + + +class IndexedStringsCompiler(IndexCompiler): + def getItems(self, items, strings): + return items.strings + + +class TopDictIndexCompiler(IndexCompiler): + """Helper class for writing the TopDict to binary.""" + + def getItems(self, items, strings): + out = [] + for item in items: + out.append(item.getCompiler(strings, self)) + return out + + def getChildren(self, strings): + children = [] + for topDict in self.items: + children.extend(topDict.getChildren(strings)) + return children + + def getOffsets(self): + if self.isCFF2: + offsets = [0, self.items[0].getDataLength()] + return offsets + else: + return super(TopDictIndexCompiler, self).getOffsets() + + def getDataLength(self): + if self.isCFF2: + dataLength = self.items[0].getDataLength() + return dataLength + else: + return super(TopDictIndexCompiler, self).getDataLength() + + def toFile(self, file): + if self.isCFF2: + self.items[0].toFile(file) + else: + super(TopDictIndexCompiler, self).toFile(file) + + +class FDArrayIndexCompiler(IndexCompiler): + """Helper class for writing the + `Font DICT INDEX `_ + to binary.""" + + def getItems(self, items, strings): + out = [] + for item in items: + out.append(item.getCompiler(strings, self)) + return out + + def getChildren(self, strings): + children = [] + for fontDict in self.items: + children.extend(fontDict.getChildren(strings)) + return children + + def toFile(self, file): + offsets = self.getOffsets() + if self.isCFF2: + writeCard32(file, len(self.items)) + else: + writeCard16(file, len(self.items)) + offSize = calcOffSize(offsets[-1]) + writeCard8(file, offSize) + offSize = -offSize + pack = struct.pack + for offset in offsets: + binOffset = pack(">l", offset)[offSize:] + assert len(binOffset) == -offSize + file.write(binOffset) + for item in self.items: + if hasattr(item, "toFile"): + item.toFile(file) + else: + file.write(item) + + def setPos(self, pos, endPos): + self.parent.rawDict["FDArray"] = pos + + +class GlobalSubrsCompiler(IndexCompiler): + """Helper class for writing the `global subroutine INDEX `_ + to binary.""" + + def getItems(self, items, strings): + out = [] + for cs in items: + cs.compile(self.isCFF2) + out.append(cs.bytecode) + return out + + +class SubrsCompiler(GlobalSubrsCompiler): + """Helper class for writing the `local subroutine INDEX `_ + to binary.""" + + def setPos(self, pos, endPos): + offset = pos - self.parent.pos + self.parent.rawDict["Subrs"] = offset + + +class CharStringsCompiler(GlobalSubrsCompiler): + """Helper class for writing the `CharStrings INDEX `_ + to binary.""" + + def getItems(self, items, strings): + out = [] + for cs in items: + cs.compile(self.isCFF2) + out.append(cs.bytecode) + return out + + def setPos(self, pos, endPos): + self.parent.rawDict["CharStrings"] = pos + + +class Index(object): + """This class represents what the CFF spec calls an INDEX (an array of + variable-sized objects). `Index` items can be addressed and set using + Python list indexing.""" + + compilerClass = IndexCompiler + + def __init__(self, file=None, isCFF2=None): + self.items = [] + self.offsets = offsets = [] + name = self.__class__.__name__ + if file is None: + return + self._isCFF2 = isCFF2 + log.log(DEBUG, "loading %s at %s", name, file.tell()) + self.file = file + if isCFF2: + count = readCard32(file) + else: + count = readCard16(file) + if count == 0: + return + self.items = [None] * count + offSize = readCard8(file) + log.log(DEBUG, " index count: %s offSize: %s", count, offSize) + assert offSize <= 4, "offSize too large: %s" % offSize + pad = b"\0" * (4 - offSize) + for index in range(count + 1): + chunk = file.read(offSize) + chunk = pad + chunk + (offset,) = struct.unpack(">L", chunk) + offsets.append(int(offset)) + self.offsetBase = file.tell() - 1 + file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot + log.log(DEBUG, " end of %s at %s", name, file.tell()) + + def __len__(self): + return len(self.items) + + def __getitem__(self, index): + item = self.items[index] + if item is not None: + return item + offset = self.offsets[index] + self.offsetBase + size = self.offsets[index + 1] - self.offsets[index] + file = self.file + file.seek(offset) + data = file.read(size) + assert len(data) == size + item = self.produceItem(index, data, file, offset) + self.items[index] = item + return item + + def __setitem__(self, index, item): + self.items[index] = item + + def produceItem(self, index, data, file, offset): + return data + + def append(self, item): + """Add an item to an INDEX.""" + self.items.append(item) + + def getCompiler(self, strings, parent, isCFF2=None): + return self.compilerClass(self, strings, parent, isCFF2=isCFF2) + + def clear(self): + """Empty the INDEX.""" + del self.items[:] + + +class GlobalSubrsIndex(Index): + """This index contains all the global subroutines in the font. A global + subroutine is a set of ``CharString`` data which is accessible to any + glyph in the font, and are used to store repeated instructions - for + example, components may be encoded as global subroutines, but so could + hinting instructions. + + Remember that when interpreting a ``callgsubr`` instruction (or indeed + a ``callsubr`` instruction) that you will need to add the "subroutine + number bias" to number given: + + .. code:: python + + tt = ttLib.TTFont("Almendra-Bold.otf") + u = tt["CFF "].cff[0].CharStrings["udieresis"] + u.decompile() + + u.toXML(XMLWriter(sys.stdout)) + # + # -64 callgsubr <-- Subroutine which implements the dieresis mark + # + + tt["CFF "].cff[0].GlobalSubrs[-64] # <-- WRONG + # + + tt["CFF "].cff[0].GlobalSubrs[-64 + 107] # <-- RIGHT + # + + ("The bias applied depends on the number of subrs (gsubrs). If the number of + subrs (gsubrs) is less than 1240, the bias is 107. Otherwise if it is less + than 33900, it is 1131; otherwise it is 32768.", + `Subroutine Operators `) + """ + + compilerClass = GlobalSubrsCompiler + subrClass = psCharStrings.T2CharString + charStringClass = psCharStrings.T2CharString + + def __init__( + self, + file=None, + globalSubrs=None, + private=None, + fdSelect=None, + fdArray=None, + isCFF2=None, + ): + super(GlobalSubrsIndex, self).__init__(file, isCFF2=isCFF2) + self.globalSubrs = globalSubrs + self.private = private + if fdSelect: + self.fdSelect = fdSelect + if fdArray: + self.fdArray = fdArray + + def produceItem(self, index, data, file, offset): + if self.private is not None: + private = self.private + elif hasattr(self, "fdArray") and self.fdArray is not None: + if hasattr(self, "fdSelect") and self.fdSelect is not None: + fdIndex = self.fdSelect[index] + else: + fdIndex = 0 + private = self.fdArray[fdIndex].Private + else: + private = None + return self.subrClass(data, private=private, globalSubrs=self.globalSubrs) + + def toXML(self, xmlWriter): + """Write the subroutines index into XML representation onto the given + :class:`fontTools.misc.xmlWriter.XMLWriter`. + + .. code:: python + + writer = xmlWriter.XMLWriter(sys.stdout) + tt["CFF "].cff[0].GlobalSubrs.toXML(writer) + + """ + xmlWriter.comment( + "The 'index' attribute is only for humans; " "it is ignored when parsed." + ) + xmlWriter.newline() + for i in range(len(self)): + subr = self[i] + if subr.needsDecompilation(): + xmlWriter.begintag("CharString", index=i, raw=1) + else: + xmlWriter.begintag("CharString", index=i) + xmlWriter.newline() + subr.toXML(xmlWriter) + xmlWriter.endtag("CharString") + xmlWriter.newline() + + def fromXML(self, name, attrs, content): + if name != "CharString": + return + subr = self.subrClass() + subr.fromXML(name, attrs, content) + self.append(subr) + + def getItemAndSelector(self, index): + sel = None + if hasattr(self, "fdSelect"): + sel = self.fdSelect[index] + return self[index], sel + + +class SubrsIndex(GlobalSubrsIndex): + """This index contains a glyph's local subroutines. A local subroutine is a + private set of ``CharString`` data which is accessible only to the glyph to + which the index is attached.""" + + compilerClass = SubrsCompiler + + +class TopDictIndex(Index): + """This index represents the array of ``TopDict`` structures in the font + (again, usually only one entry is present). Hence the following calls are + equivalent: + + .. code:: python + + tt["CFF "].cff[0] + # + tt["CFF "].cff.topDictIndex[0] + # + + """ + + compilerClass = TopDictIndexCompiler + + def __init__(self, file=None, cff2GetGlyphOrder=None, topSize=0, isCFF2=None): + self.cff2GetGlyphOrder = cff2GetGlyphOrder + if file is not None and isCFF2: + self._isCFF2 = isCFF2 + self.items = [] + name = self.__class__.__name__ + log.log(DEBUG, "loading %s at %s", name, file.tell()) + self.file = file + count = 1 + self.items = [None] * count + self.offsets = [0, topSize] + self.offsetBase = file.tell() + # pretend we've read the whole lot + file.seek(self.offsetBase + topSize) + log.log(DEBUG, " end of %s at %s", name, file.tell()) + else: + super(TopDictIndex, self).__init__(file, isCFF2=isCFF2) + + def produceItem(self, index, data, file, offset): + top = TopDict( + self.strings, + file, + offset, + self.GlobalSubrs, + self.cff2GetGlyphOrder, + isCFF2=self._isCFF2, + ) + top.decompile(data) + return top + + def toXML(self, xmlWriter): + for i in range(len(self)): + xmlWriter.begintag("FontDict", index=i) + xmlWriter.newline() + self[i].toXML(xmlWriter) + xmlWriter.endtag("FontDict") + xmlWriter.newline() + + +class FDArrayIndex(Index): + compilerClass = FDArrayIndexCompiler + + def toXML(self, xmlWriter): + for i in range(len(self)): + xmlWriter.begintag("FontDict", index=i) + xmlWriter.newline() + self[i].toXML(xmlWriter) + xmlWriter.endtag("FontDict") + xmlWriter.newline() + + def produceItem(self, index, data, file, offset): + fontDict = FontDict( + self.strings, + file, + offset, + self.GlobalSubrs, + isCFF2=self._isCFF2, + vstore=self.vstore, + ) + fontDict.decompile(data) + return fontDict + + def fromXML(self, name, attrs, content): + if name != "FontDict": + return + fontDict = FontDict() + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + fontDict.fromXML(name, attrs, content) + self.append(fontDict) + + +class VarStoreData(object): + def __init__(self, file=None, otVarStore=None): + self.file = file + self.data = None + self.otVarStore = otVarStore + self.font = TTFont() # dummy font for the decompile function. + + def decompile(self): + if self.file: + # read data in from file. Assume position is correct. + length = readCard16(self.file) + # https://github.com/fonttools/fonttools/issues/3673 + if length == 65535: + self.data = self.file.read() + else: + self.data = self.file.read(length) + globalState = {} + reader = OTTableReader(self.data, globalState) + self.otVarStore = ot.VarStore() + self.otVarStore.decompile(reader, self.font) + self.data = None + return self + + def compile(self): + writer = OTTableWriter() + self.otVarStore.compile(writer, self.font) + # Note that this omits the initial Card16 length from the CFF2 + # VarStore data block + self.data = writer.getAllData() + + def writeXML(self, xmlWriter, name): + self.otVarStore.toXML(xmlWriter, self.font) + + def xmlRead(self, name, attrs, content, parent): + self.otVarStore = ot.VarStore() + for element in content: + if isinstance(element, tuple): + name, attrs, content = element + self.otVarStore.fromXML(name, attrs, content, self.font) + else: + pass + return None + + def __len__(self): + return len(self.data) + + def getNumRegions(self, vsIndex): + if vsIndex is None: + vsIndex = 0 + varData = self.otVarStore.VarData[vsIndex] + numRegions = varData.VarRegionCount + return numRegions + + +class FDSelect(object): + def __init__(self, file=None, numGlyphs=None, format=None): + if file: + # read data in from file + self.format = readCard8(file) + if self.format == 0: + from array import array + + self.gidArray = array("B", file.read(numGlyphs)).tolist() + elif self.format == 3: + gidArray = [None] * numGlyphs + nRanges = readCard16(file) + fd = None + prev = None + for i in range(nRanges): + first = readCard16(file) + if prev is not None: + for glyphID in range(prev, first): + gidArray[glyphID] = fd + prev = first + fd = readCard8(file) + if prev is not None: + first = readCard16(file) + for glyphID in range(prev, first): + gidArray[glyphID] = fd + self.gidArray = gidArray + elif self.format == 4: + gidArray = [None] * numGlyphs + nRanges = readCard32(file) + fd = None + prev = None + for i in range(nRanges): + first = readCard32(file) + if prev is not None: + for glyphID in range(prev, first): + gidArray[glyphID] = fd + prev = first + fd = readCard16(file) + if prev is not None: + first = readCard32(file) + for glyphID in range(prev, first): + gidArray[glyphID] = fd + self.gidArray = gidArray + else: + assert False, "unsupported FDSelect format: %s" % format + else: + # reading from XML. Make empty gidArray, and leave format as passed in. + # format is None will result in the smallest representation being used. + self.format = format + self.gidArray = [] + + def __len__(self): + return len(self.gidArray) + + def __getitem__(self, index): + return self.gidArray[index] + + def __setitem__(self, index, fdSelectValue): + self.gidArray[index] = fdSelectValue + + def append(self, fdSelectValue): + self.gidArray.append(fdSelectValue) + + +class CharStrings(object): + """The ``CharStrings`` in the font represent the instructions for drawing + each glyph. This object presents a dictionary interface to the font's + CharStrings, indexed by glyph name: + + .. code:: python + + tt["CFF "].cff[0].CharStrings["a"] + # + + See :class:`fontTools.misc.psCharStrings.T1CharString` and + :class:`fontTools.misc.psCharStrings.T2CharString` for how to decompile, + compile and interpret the glyph drawing instructions in the returned objects. + + """ + + def __init__( + self, + file, + charset, + globalSubrs, + private, + fdSelect, + fdArray, + isCFF2=None, + varStore=None, + ): + self.globalSubrs = globalSubrs + self.varStore = varStore + if file is not None: + self.charStringsIndex = SubrsIndex( + file, globalSubrs, private, fdSelect, fdArray, isCFF2=isCFF2 + ) + self.charStrings = charStrings = {} + for i in range(len(charset)): + charStrings[charset[i]] = i + # read from OTF file: charStrings.values() are indices into + # charStringsIndex. + self.charStringsAreIndexed = 1 + else: + self.charStrings = {} + # read from ttx file: charStrings.values() are actual charstrings + self.charStringsAreIndexed = 0 + self.private = private + if fdSelect is not None: + self.fdSelect = fdSelect + if fdArray is not None: + self.fdArray = fdArray + + def keys(self): + return list(self.charStrings.keys()) + + def values(self): + if self.charStringsAreIndexed: + return self.charStringsIndex + else: + return list(self.charStrings.values()) + + def has_key(self, name): + return name in self.charStrings + + __contains__ = has_key + + def __len__(self): + return len(self.charStrings) + + def __getitem__(self, name): + charString = self.charStrings[name] + if self.charStringsAreIndexed: + charString = self.charStringsIndex[charString] + return charString + + def __setitem__(self, name, charString): + if self.charStringsAreIndexed: + index = self.charStrings[name] + self.charStringsIndex[index] = charString + else: + self.charStrings[name] = charString + + def getItemAndSelector(self, name): + if self.charStringsAreIndexed: + index = self.charStrings[name] + return self.charStringsIndex.getItemAndSelector(index) + else: + if hasattr(self, "fdArray"): + if hasattr(self, "fdSelect"): + sel = self.charStrings[name].fdSelectIndex + else: + sel = 0 + else: + sel = None + return self.charStrings[name], sel + + def toXML(self, xmlWriter): + names = sorted(self.keys()) + for name in names: + charStr, fdSelectIndex = self.getItemAndSelector(name) + if charStr.needsDecompilation(): + raw = [("raw", 1)] + else: + raw = [] + if fdSelectIndex is None: + xmlWriter.begintag("CharString", [("name", name)] + raw) + else: + xmlWriter.begintag( + "CharString", + [("name", name), ("fdSelectIndex", fdSelectIndex)] + raw, + ) + xmlWriter.newline() + charStr.toXML(xmlWriter) + xmlWriter.endtag("CharString") + xmlWriter.newline() + + def fromXML(self, name, attrs, content): + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + if name != "CharString": + continue + fdID = -1 + if hasattr(self, "fdArray"): + try: + fdID = safeEval(attrs["fdSelectIndex"]) + except KeyError: + fdID = 0 + private = self.fdArray[fdID].Private + else: + private = self.private + + glyphName = attrs["name"] + charStringClass = psCharStrings.T2CharString + charString = charStringClass(private=private, globalSubrs=self.globalSubrs) + charString.fromXML(name, attrs, content) + if fdID >= 0: + charString.fdSelectIndex = fdID + self[glyphName] = charString + + +def readCard8(file): + return byteord(file.read(1)) + + +def readCard16(file): + (value,) = struct.unpack(">H", file.read(2)) + return value + + +def readCard32(file): + (value,) = struct.unpack(">L", file.read(4)) + return value + + +def writeCard8(file, value): + file.write(bytechr(value)) + + +def writeCard16(file, value): + file.write(struct.pack(">H", value)) + + +def writeCard32(file, value): + file.write(struct.pack(">L", value)) + + +def packCard8(value): + return bytechr(value) + + +def packCard16(value): + return struct.pack(">H", value) + + +def packCard32(value): + return struct.pack(">L", value) + + +def buildOperatorDict(table): + d = {} + for op, name, arg, default, conv in table: + d[op] = (name, arg) + return d + + +def buildOpcodeDict(table): + d = {} + for op, name, arg, default, conv in table: + if isinstance(op, tuple): + op = bytechr(op[0]) + bytechr(op[1]) + else: + op = bytechr(op) + d[name] = (op, arg) + return d + + +def buildOrder(table): + l = [] + for op, name, arg, default, conv in table: + l.append(name) + return l + + +def buildDefaults(table): + d = {} + for op, name, arg, default, conv in table: + if default is not None: + d[name] = default + return d + + +def buildConverters(table): + d = {} + for op, name, arg, default, conv in table: + d[name] = conv + return d + + +class SimpleConverter(object): + def read(self, parent, value): + if not hasattr(parent, "file"): + return self._read(parent, value) + file = parent.file + pos = file.tell() + try: + return self._read(parent, value) + finally: + file.seek(pos) + + def _read(self, parent, value): + return value + + def write(self, parent, value): + return value + + def xmlWrite(self, xmlWriter, name, value): + xmlWriter.simpletag(name, value=value) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + return attrs["value"] + + +class ASCIIConverter(SimpleConverter): + def _read(self, parent, value): + return tostr(value, encoding="ascii") + + def write(self, parent, value): + return tobytes(value, encoding="ascii") + + def xmlWrite(self, xmlWriter, name, value): + xmlWriter.simpletag(name, value=tostr(value, encoding="ascii")) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + return tobytes(attrs["value"], encoding=("ascii")) + + +class Latin1Converter(SimpleConverter): + def _read(self, parent, value): + return tostr(value, encoding="latin1") + + def write(self, parent, value): + return tobytes(value, encoding="latin1") + + def xmlWrite(self, xmlWriter, name, value): + value = tostr(value, encoding="latin1") + if name in ["Notice", "Copyright"]: + value = re.sub(r"[\r\n]\s+", " ", value) + xmlWriter.simpletag(name, value=value) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + return tobytes(attrs["value"], encoding=("latin1")) + + +def parseNum(s): + try: + value = int(s) + except: + value = float(s) + return value + + +def parseBlendList(s): + valueList = [] + for element in s: + if isinstance(element, str): + continue + name, attrs, content = element + blendList = attrs["value"].split() + blendList = [eval(val) for val in blendList] + valueList.append(blendList) + if len(valueList) == 1: + valueList = valueList[0] + return valueList + + +class NumberConverter(SimpleConverter): + def xmlWrite(self, xmlWriter, name, value): + if isinstance(value, list): + xmlWriter.begintag(name) + xmlWriter.newline() + xmlWriter.indent() + blendValue = " ".join([str(val) for val in value]) + xmlWriter.simpletag(kBlendDictOpName, value=blendValue) + xmlWriter.newline() + xmlWriter.dedent() + xmlWriter.endtag(name) + xmlWriter.newline() + else: + xmlWriter.simpletag(name, value=value) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + valueString = attrs.get("value", None) + if valueString is None: + value = parseBlendList(content) + else: + value = parseNum(attrs["value"]) + return value + + +class ArrayConverter(SimpleConverter): + def xmlWrite(self, xmlWriter, name, value): + if value and isinstance(value[0], list): + xmlWriter.begintag(name) + xmlWriter.newline() + xmlWriter.indent() + for valueList in value: + blendValue = " ".join([str(val) for val in valueList]) + xmlWriter.simpletag(kBlendDictOpName, value=blendValue) + xmlWriter.newline() + xmlWriter.dedent() + xmlWriter.endtag(name) + xmlWriter.newline() + else: + value = " ".join([str(val) for val in value]) + xmlWriter.simpletag(name, value=value) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + valueString = attrs.get("value", None) + if valueString is None: + valueList = parseBlendList(content) + else: + values = valueString.split() + valueList = [parseNum(value) for value in values] + return valueList + + +class TableConverter(SimpleConverter): + def xmlWrite(self, xmlWriter, name, value): + xmlWriter.begintag(name) + xmlWriter.newline() + value.toXML(xmlWriter) + xmlWriter.endtag(name) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + ob = self.getClass()() + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + ob.fromXML(name, attrs, content) + return ob + + +class PrivateDictConverter(TableConverter): + def getClass(self): + return PrivateDict + + def _read(self, parent, value): + size, offset = value + file = parent.file + isCFF2 = parent._isCFF2 + try: + vstore = parent.vstore + except AttributeError: + vstore = None + priv = PrivateDict(parent.strings, file, offset, isCFF2=isCFF2, vstore=vstore) + file.seek(offset) + data = file.read(size) + assert len(data) == size + priv.decompile(data) + return priv + + def write(self, parent, value): + return (0, 0) # dummy value + + +class SubrsConverter(TableConverter): + def getClass(self): + return SubrsIndex + + def _read(self, parent, value): + file = parent.file + isCFF2 = parent._isCFF2 + file.seek(parent.offset + value) # Offset(self) + return SubrsIndex(file, isCFF2=isCFF2) + + def write(self, parent, value): + return 0 # dummy value + + +class CharStringsConverter(TableConverter): + def _read(self, parent, value): + file = parent.file + isCFF2 = parent._isCFF2 + charset = parent.charset + varStore = getattr(parent, "VarStore", None) + globalSubrs = parent.GlobalSubrs + if hasattr(parent, "FDArray"): + fdArray = parent.FDArray + if hasattr(parent, "FDSelect"): + fdSelect = parent.FDSelect + else: + fdSelect = None + private = None + else: + fdSelect, fdArray = None, None + private = parent.Private + file.seek(value) # Offset(0) + charStrings = CharStrings( + file, + charset, + globalSubrs, + private, + fdSelect, + fdArray, + isCFF2=isCFF2, + varStore=varStore, + ) + return charStrings + + def write(self, parent, value): + return 0 # dummy value + + def xmlRead(self, name, attrs, content, parent): + if hasattr(parent, "FDArray"): + # if it is a CID-keyed font, then the private Dict is extracted from the + # parent.FDArray + fdArray = parent.FDArray + if hasattr(parent, "FDSelect"): + fdSelect = parent.FDSelect + else: + fdSelect = None + private = None + else: + # if it is a name-keyed font, then the private dict is in the top dict, + # and + # there is no fdArray. + private, fdSelect, fdArray = parent.Private, None, None + charStrings = CharStrings( + None, + None, + parent.GlobalSubrs, + private, + fdSelect, + fdArray, + varStore=getattr(parent, "VarStore", None), + ) + charStrings.fromXML(name, attrs, content) + return charStrings + + +class CharsetConverter(SimpleConverter): + def _read(self, parent, value): + isCID = hasattr(parent, "ROS") + if value > 2: + numGlyphs = parent.numGlyphs + file = parent.file + file.seek(value) + log.log(DEBUG, "loading charset at %s", value) + format = readCard8(file) + if format == 0: + charset = parseCharset0(numGlyphs, file, parent.strings, isCID) + elif format == 1 or format == 2: + charset = parseCharset(numGlyphs, file, parent.strings, isCID, format) + else: + raise NotImplementedError + assert len(charset) == numGlyphs + log.log(DEBUG, " charset end at %s", file.tell()) + # make sure glyph names are unique + allNames = {} + newCharset = [] + for glyphName in charset: + if glyphName in allNames: + # make up a new glyphName that's unique + n = allNames[glyphName] + names = set(allNames) | set(charset) + while (glyphName + "." + str(n)) in names: + n += 1 + allNames[glyphName] = n + 1 + glyphName = glyphName + "." + str(n) + allNames[glyphName] = 1 + newCharset.append(glyphName) + charset = newCharset + else: # offset == 0 -> no charset data. + if isCID or "CharStrings" not in parent.rawDict: + # We get here only when processing fontDicts from the FDArray of + # CFF-CID fonts. Only the real topDict references the charset. + assert value == 0 + charset = None + elif value == 0: + charset = cffISOAdobeStrings + elif value == 1: + charset = cffIExpertStrings + elif value == 2: + charset = cffExpertSubsetStrings + if charset and (len(charset) != parent.numGlyphs): + charset = charset[: parent.numGlyphs] + return charset + + def write(self, parent, value): + return 0 # dummy value + + def xmlWrite(self, xmlWriter, name, value): + # XXX only write charset when not in OT/TTX context, where we + # dump charset as a separate "GlyphOrder" table. + # # xmlWriter.simpletag("charset") + xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element") + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + pass + + +class CharsetCompiler(object): + def __init__(self, strings, charset, parent): + assert charset[0] == ".notdef" + isCID = hasattr(parent.dictObj, "ROS") + data0 = packCharset0(charset, isCID, strings) + data = packCharset(charset, isCID, strings) + if len(data) < len(data0): + self.data = data + else: + self.data = data0 + self.parent = parent + + def setPos(self, pos, endPos): + self.parent.rawDict["charset"] = pos + + def getDataLength(self): + return len(self.data) + + def toFile(self, file): + file.write(self.data) + + +def getStdCharSet(charset): + # check to see if we can use a predefined charset value. + predefinedCharSetVal = None + predefinedCharSets = [ + (cffISOAdobeStringCount, cffISOAdobeStrings, 0), + (cffExpertStringCount, cffIExpertStrings, 1), + (cffExpertSubsetStringCount, cffExpertSubsetStrings, 2), + ] + lcs = len(charset) + for cnt, pcs, csv in predefinedCharSets: + if predefinedCharSetVal is not None: + break + if lcs > cnt: + continue + predefinedCharSetVal = csv + for i in range(lcs): + if charset[i] != pcs[i]: + predefinedCharSetVal = None + break + return predefinedCharSetVal + + +def getCIDfromName(name, strings): + return int(name[3:]) + + +def getSIDfromName(name, strings): + return strings.getSID(name) + + +def packCharset0(charset, isCID, strings): + fmt = 0 + data = [packCard8(fmt)] + if isCID: + getNameID = getCIDfromName + else: + getNameID = getSIDfromName + + for name in charset[1:]: + data.append(packCard16(getNameID(name, strings))) + return bytesjoin(data) + + +def packCharset(charset, isCID, strings): + fmt = 1 + ranges = [] + first = None + end = 0 + if isCID: + getNameID = getCIDfromName + else: + getNameID = getSIDfromName + + for name in charset[1:]: + SID = getNameID(name, strings) + if first is None: + first = SID + elif end + 1 != SID: + nLeft = end - first + if nLeft > 255: + fmt = 2 + ranges.append((first, nLeft)) + first = SID + end = SID + if end: + nLeft = end - first + if nLeft > 255: + fmt = 2 + ranges.append((first, nLeft)) + + data = [packCard8(fmt)] + if fmt == 1: + nLeftFunc = packCard8 + else: + nLeftFunc = packCard16 + for first, nLeft in ranges: + data.append(packCard16(first) + nLeftFunc(nLeft)) + return bytesjoin(data) + + +def parseCharset0(numGlyphs, file, strings, isCID): + charset = [".notdef"] + if isCID: + for i in range(numGlyphs - 1): + CID = readCard16(file) + charset.append("cid" + str(CID).zfill(5)) + else: + for i in range(numGlyphs - 1): + SID = readCard16(file) + charset.append(strings[SID]) + return charset + + +def parseCharset(numGlyphs, file, strings, isCID, fmt): + charset = [".notdef"] + count = 1 + if fmt == 1: + nLeftFunc = readCard8 + else: + nLeftFunc = readCard16 + while count < numGlyphs: + first = readCard16(file) + nLeft = nLeftFunc(file) + if isCID: + for CID in range(first, first + nLeft + 1): + charset.append("cid" + str(CID).zfill(5)) + else: + for SID in range(first, first + nLeft + 1): + charset.append(strings[SID]) + count = count + nLeft + 1 + return charset + + +class EncodingCompiler(object): + def __init__(self, strings, encoding, parent): + assert not isinstance(encoding, str) + data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings) + data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings) + if len(data0) < len(data1): + self.data = data0 + else: + self.data = data1 + self.parent = parent + + def setPos(self, pos, endPos): + self.parent.rawDict["Encoding"] = pos + + def getDataLength(self): + return len(self.data) + + def toFile(self, file): + file.write(self.data) + + +class EncodingConverter(SimpleConverter): + def _read(self, parent, value): + if value == 0: + return "StandardEncoding" + elif value == 1: + return "ExpertEncoding" + # custom encoding at offset `value` + assert value > 1 + file = parent.file + file.seek(value) + log.log(DEBUG, "loading Encoding at %s", value) + fmt = readCard8(file) + haveSupplement = bool(fmt & 0x80) + fmt = fmt & 0x7F + + if fmt == 0: + encoding = parseEncoding0(parent.charset, file) + elif fmt == 1: + encoding = parseEncoding1(parent.charset, file) + else: + raise ValueError(f"Unknown Encoding format: {fmt}") + + if haveSupplement: + parseEncodingSupplement(file, encoding, parent.strings) + + return encoding + + def write(self, parent, value): + if value == "StandardEncoding": + return 0 + elif value == "ExpertEncoding": + return 1 + return 0 # dummy value + + def xmlWrite(self, xmlWriter, name, value): + if value in ("StandardEncoding", "ExpertEncoding"): + xmlWriter.simpletag(name, name=value) + xmlWriter.newline() + return + xmlWriter.begintag(name) + xmlWriter.newline() + for code in range(len(value)): + glyphName = value[code] + if glyphName != ".notdef": + xmlWriter.simpletag("map", code=hex(code), name=glyphName) + xmlWriter.newline() + xmlWriter.endtag(name) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + if "name" in attrs: + return attrs["name"] + encoding = [".notdef"] * 256 + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + code = safeEval(attrs["code"]) + glyphName = attrs["name"] + encoding[code] = glyphName + return encoding + + +def readSID(file): + """Read a String ID (SID) — 2-byte unsigned integer.""" + data = file.read(2) + if len(data) != 2: + raise EOFError("Unexpected end of file while reading SID") + return struct.unpack(">H", data)[0] # big-endian uint16 + + +def parseEncodingSupplement(file, encoding, strings): + """ + Parse the CFF Encoding supplement data: + - nSups: number of supplementary mappings + - each mapping: (code, SID) pair + and apply them to the `encoding` list in place. + """ + nSups = readCard8(file) + for _ in range(nSups): + code = readCard8(file) + sid = readSID(file) + name = strings[sid] + encoding[code] = name + + +def parseEncoding0(charset, file): + """ + Format 0: simple list of codes. + After reading the base table, optionally parse the supplement. + """ + nCodes = readCard8(file) + encoding = [".notdef"] * 256 + for glyphID in range(1, nCodes + 1): + code = readCard8(file) + if code != 0: + encoding[code] = charset[glyphID] + + return encoding + + +def parseEncoding1(charset, file): + """ + Format 1: range-based encoding. + After reading the base ranges, optionally parse the supplement. + """ + nRanges = readCard8(file) + encoding = [".notdef"] * 256 + glyphID = 1 + for _ in range(nRanges): + code = readCard8(file) + nLeft = readCard8(file) + for _ in range(nLeft + 1): + encoding[code] = charset[glyphID] + code += 1 + glyphID += 1 + + return encoding + + +def packEncoding0(charset, encoding, strings): + fmt = 0 + m = {} + for code in range(len(encoding)): + name = encoding[code] + if name != ".notdef": + m[name] = code + codes = [] + for name in charset[1:]: + code = m.get(name) + codes.append(code) + + while codes and codes[-1] is None: + codes.pop() + + data = [packCard8(fmt), packCard8(len(codes))] + for code in codes: + if code is None: + code = 0 + data.append(packCard8(code)) + return bytesjoin(data) + + +def packEncoding1(charset, encoding, strings): + fmt = 1 + m = {} + for code in range(len(encoding)): + name = encoding[code] + if name != ".notdef": + m[name] = code + ranges = [] + first = None + end = 0 + for name in charset[1:]: + code = m.get(name, -1) + if first is None: + first = code + elif end + 1 != code: + nLeft = end - first + ranges.append((first, nLeft)) + first = code + end = code + nLeft = end - first + ranges.append((first, nLeft)) + + # remove unencoded glyphs at the end. + while ranges and ranges[-1][0] == -1: + ranges.pop() + + data = [packCard8(fmt), packCard8(len(ranges))] + for first, nLeft in ranges: + if first == -1: # unencoded + first = 0 + data.append(packCard8(first) + packCard8(nLeft)) + return bytesjoin(data) + + +class FDArrayConverter(TableConverter): + def _read(self, parent, value): + try: + vstore = parent.VarStore + except AttributeError: + vstore = None + file = parent.file + isCFF2 = parent._isCFF2 + file.seek(value) + fdArray = FDArrayIndex(file, isCFF2=isCFF2) + fdArray.vstore = vstore + fdArray.strings = parent.strings + fdArray.GlobalSubrs = parent.GlobalSubrs + return fdArray + + def write(self, parent, value): + return 0 # dummy value + + def xmlRead(self, name, attrs, content, parent): + fdArray = FDArrayIndex() + for element in content: + if isinstance(element, str): + continue + name, attrs, content = element + fdArray.fromXML(name, attrs, content) + return fdArray + + +class FDSelectConverter(SimpleConverter): + def _read(self, parent, value): + file = parent.file + file.seek(value) + fdSelect = FDSelect(file, parent.numGlyphs) + return fdSelect + + def write(self, parent, value): + return 0 # dummy value + + # The FDSelect glyph data is written out to XML in the charstring keys, + # so we write out only the format selector + def xmlWrite(self, xmlWriter, name, value): + xmlWriter.simpletag(name, [("format", value.format)]) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + fmt = safeEval(attrs["format"]) + file = None + numGlyphs = None + fdSelect = FDSelect(file, numGlyphs, fmt) + return fdSelect + + +class VarStoreConverter(SimpleConverter): + def _read(self, parent, value): + file = parent.file + file.seek(value) + varStore = VarStoreData(file) + varStore.decompile() + return varStore + + def write(self, parent, value): + return 0 # dummy value + + def xmlWrite(self, xmlWriter, name, value): + value.writeXML(xmlWriter, name) + + def xmlRead(self, name, attrs, content, parent): + varStore = VarStoreData() + varStore.xmlRead(name, attrs, content, parent) + return varStore + + +def packFDSelect0(fdSelectArray): + fmt = 0 + data = [packCard8(fmt)] + for index in fdSelectArray: + data.append(packCard8(index)) + return bytesjoin(data) + + +def packFDSelect3(fdSelectArray): + fmt = 3 + fdRanges = [] + lenArray = len(fdSelectArray) + lastFDIndex = -1 + for i in range(lenArray): + fdIndex = fdSelectArray[i] + if lastFDIndex != fdIndex: + fdRanges.append([i, fdIndex]) + lastFDIndex = fdIndex + sentinelGID = i + 1 + + data = [packCard8(fmt)] + data.append(packCard16(len(fdRanges))) + for fdRange in fdRanges: + data.append(packCard16(fdRange[0])) + data.append(packCard8(fdRange[1])) + data.append(packCard16(sentinelGID)) + return bytesjoin(data) + + +def packFDSelect4(fdSelectArray): + fmt = 4 + fdRanges = [] + lenArray = len(fdSelectArray) + lastFDIndex = -1 + for i in range(lenArray): + fdIndex = fdSelectArray[i] + if lastFDIndex != fdIndex: + fdRanges.append([i, fdIndex]) + lastFDIndex = fdIndex + sentinelGID = i + 1 + + data = [packCard8(fmt)] + data.append(packCard32(len(fdRanges))) + for fdRange in fdRanges: + data.append(packCard32(fdRange[0])) + data.append(packCard16(fdRange[1])) + data.append(packCard32(sentinelGID)) + return bytesjoin(data) + + +class FDSelectCompiler(object): + def __init__(self, fdSelect, parent): + fmt = fdSelect.format + fdSelectArray = fdSelect.gidArray + if fmt == 0: + self.data = packFDSelect0(fdSelectArray) + elif fmt == 3: + self.data = packFDSelect3(fdSelectArray) + elif fmt == 4: + self.data = packFDSelect4(fdSelectArray) + else: + # choose smaller of the two formats + data0 = packFDSelect0(fdSelectArray) + data3 = packFDSelect3(fdSelectArray) + if len(data0) < len(data3): + self.data = data0 + fdSelect.format = 0 + else: + self.data = data3 + fdSelect.format = 3 + + self.parent = parent + + def setPos(self, pos, endPos): + self.parent.rawDict["FDSelect"] = pos + + def getDataLength(self): + return len(self.data) + + def toFile(self, file): + file.write(self.data) + + +class VarStoreCompiler(object): + def __init__(self, varStoreData, parent): + self.parent = parent + if not varStoreData.data: + varStoreData.compile() + varStoreDataLen = min(0xFFFF, len(varStoreData.data)) + data = [packCard16(varStoreDataLen), varStoreData.data] + self.data = bytesjoin(data) + + def setPos(self, pos, endPos): + self.parent.rawDict["VarStore"] = pos + + def getDataLength(self): + return len(self.data) + + def toFile(self, file): + file.write(self.data) + + +class ROSConverter(SimpleConverter): + def xmlWrite(self, xmlWriter, name, value): + registry, order, supplement = value + xmlWriter.simpletag( + name, + [ + ("Registry", tostr(registry)), + ("Order", tostr(order)), + ("Supplement", supplement), + ], + ) + xmlWriter.newline() + + def xmlRead(self, name, attrs, content, parent): + return (attrs["Registry"], attrs["Order"], safeEval(attrs["Supplement"])) + + +topDictOperators = [ + # opcode name argument type default converter + (25, "maxstack", "number", None, None), + ((12, 30), "ROS", ("SID", "SID", "number"), None, ROSConverter()), + ((12, 20), "SyntheticBase", "number", None, None), + (0, "version", "SID", None, None), + (1, "Notice", "SID", None, Latin1Converter()), + ((12, 0), "Copyright", "SID", None, Latin1Converter()), + (2, "FullName", "SID", None, Latin1Converter()), + ((12, 38), "FontName", "SID", None, Latin1Converter()), + (3, "FamilyName", "SID", None, Latin1Converter()), + (4, "Weight", "SID", None, None), + ((12, 1), "isFixedPitch", "number", 0, None), + ((12, 2), "ItalicAngle", "number", 0, None), + ((12, 3), "UnderlinePosition", "number", -100, None), + ((12, 4), "UnderlineThickness", "number", 50, None), + ((12, 5), "PaintType", "number", 0, None), + ((12, 6), "CharstringType", "number", 2, None), + ((12, 7), "FontMatrix", "array", [0.001, 0, 0, 0.001, 0, 0], None), + (13, "UniqueID", "number", None, None), + (5, "FontBBox", "array", [0, 0, 0, 0], None), + ((12, 8), "StrokeWidth", "number", 0, None), + (14, "XUID", "array", None, None), + ((12, 21), "PostScript", "SID", None, None), + ((12, 22), "BaseFontName", "SID", None, None), + ((12, 23), "BaseFontBlend", "delta", None, None), + ((12, 31), "CIDFontVersion", "number", 0, None), + ((12, 32), "CIDFontRevision", "number", 0, None), + ((12, 33), "CIDFontType", "number", 0, None), + ((12, 34), "CIDCount", "number", 8720, None), + (15, "charset", "number", None, CharsetConverter()), + ((12, 35), "UIDBase", "number", None, None), + (16, "Encoding", "number", 0, EncodingConverter()), + (18, "Private", ("number", "number"), None, PrivateDictConverter()), + ((12, 37), "FDSelect", "number", None, FDSelectConverter()), + ((12, 36), "FDArray", "number", None, FDArrayConverter()), + (17, "CharStrings", "number", None, CharStringsConverter()), + (24, "VarStore", "number", None, VarStoreConverter()), +] + +topDictOperators2 = [ + # opcode name argument type default converter + (25, "maxstack", "number", None, None), + ((12, 7), "FontMatrix", "array", [0.001, 0, 0, 0.001, 0, 0], None), + ((12, 37), "FDSelect", "number", None, FDSelectConverter()), + ((12, 36), "FDArray", "number", None, FDArrayConverter()), + (17, "CharStrings", "number", None, CharStringsConverter()), + (24, "VarStore", "number", None, VarStoreConverter()), +] + +# Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order, +# in order for the font to compile back from xml. + +kBlendDictOpName = "blend" +blendOp = 23 + +privateDictOperators = [ + # opcode name argument type default converter + (22, "vsindex", "number", None, None), + ( + blendOp, + kBlendDictOpName, + "blendList", + None, + None, + ), # This is for reading to/from XML: it not written to CFF. + (6, "BlueValues", "delta", None, None), + (7, "OtherBlues", "delta", None, None), + (8, "FamilyBlues", "delta", None, None), + (9, "FamilyOtherBlues", "delta", None, None), + ((12, 9), "BlueScale", "number", 0.039625, None), + ((12, 10), "BlueShift", "number", 7, None), + ((12, 11), "BlueFuzz", "number", 1, None), + (10, "StdHW", "number", None, None), + (11, "StdVW", "number", None, None), + ((12, 12), "StemSnapH", "delta", None, None), + ((12, 13), "StemSnapV", "delta", None, None), + ((12, 14), "ForceBold", "number", 0, None), + ((12, 15), "ForceBoldThreshold", "number", None, None), # deprecated + ((12, 16), "lenIV", "number", None, None), # deprecated + ((12, 17), "LanguageGroup", "number", 0, None), + ((12, 18), "ExpansionFactor", "number", 0.06, None), + ((12, 19), "initialRandomSeed", "number", 0, None), + (20, "defaultWidthX", "number", 0, None), + (21, "nominalWidthX", "number", 0, None), + (19, "Subrs", "number", None, SubrsConverter()), +] + +privateDictOperators2 = [ + # opcode name argument type default converter + (22, "vsindex", "number", None, None), + ( + blendOp, + kBlendDictOpName, + "blendList", + None, + None, + ), # This is for reading to/from XML: it not written to CFF. + (6, "BlueValues", "delta", None, None), + (7, "OtherBlues", "delta", None, None), + (8, "FamilyBlues", "delta", None, None), + (9, "FamilyOtherBlues", "delta", None, None), + ((12, 9), "BlueScale", "number", 0.039625, None), + ((12, 10), "BlueShift", "number", 7, None), + ((12, 11), "BlueFuzz", "number", 1, None), + (10, "StdHW", "number", None, None), + (11, "StdVW", "number", None, None), + ((12, 12), "StemSnapH", "delta", None, None), + ((12, 13), "StemSnapV", "delta", None, None), + ((12, 17), "LanguageGroup", "number", 0, None), + ((12, 18), "ExpansionFactor", "number", 0.06, None), + (19, "Subrs", "number", None, SubrsConverter()), +] + + +def addConverters(table): + for i in range(len(table)): + op, name, arg, default, conv = table[i] + if conv is not None: + continue + if arg in ("delta", "array"): + conv = ArrayConverter() + elif arg == "number": + conv = NumberConverter() + elif arg == "SID": + conv = ASCIIConverter() + elif arg == "blendList": + conv = None + else: + assert False + table[i] = op, name, arg, default, conv + + +addConverters(privateDictOperators) +addConverters(topDictOperators) + + +class TopDictDecompiler(psCharStrings.DictDecompiler): + operators = buildOperatorDict(topDictOperators) + + +class PrivateDictDecompiler(psCharStrings.DictDecompiler): + operators = buildOperatorDict(privateDictOperators) + + +class DictCompiler(object): + maxBlendStack = 0 + + def __init__(self, dictObj, strings, parent, isCFF2=None): + if strings: + assert isinstance(strings, IndexedStrings) + if isCFF2 is None and hasattr(parent, "isCFF2"): + isCFF2 = parent.isCFF2 + assert isCFF2 is not None + self.isCFF2 = isCFF2 + self.dictObj = dictObj + self.strings = strings + self.parent = parent + rawDict = {} + for name in dictObj.order: + value = getattr(dictObj, name, None) + if value is None: + continue + conv = dictObj.converters[name] + value = conv.write(dictObj, value) + if value == dictObj.defaults.get(name): + continue + rawDict[name] = value + self.rawDict = rawDict + + def setPos(self, pos, endPos): + pass + + def getDataLength(self): + return len(self.compile("getDataLength")) + + def compile(self, reason): + log.log(DEBUG, "-- compiling %s for %s", self.__class__.__name__, reason) + rawDict = self.rawDict + data = [] + for name in self.dictObj.order: + value = rawDict.get(name) + if value is None: + continue + op, argType = self.opcodes[name] + if isinstance(argType, tuple): + l = len(argType) + assert len(value) == l, "value doesn't match arg type" + for i in range(l): + arg = argType[i] + v = value[i] + arghandler = getattr(self, "arg_" + arg) + data.append(arghandler(v)) + else: + arghandler = getattr(self, "arg_" + argType) + data.append(arghandler(value)) + data.append(op) + data = bytesjoin(data) + return data + + def toFile(self, file): + data = self.compile("toFile") + file.write(data) + + def arg_number(self, num): + if isinstance(num, list): + data = [encodeNumber(val) for val in num] + data.append(encodeNumber(1)) + data.append(bytechr(blendOp)) + datum = bytesjoin(data) + else: + datum = encodeNumber(num) + return datum + + def arg_SID(self, s): + return psCharStrings.encodeIntCFF(self.strings.getSID(s)) + + def arg_array(self, value): + data = [] + for num in value: + data.append(self.arg_number(num)) + return bytesjoin(data) + + def arg_delta(self, value): + if not value: + return b"" + val0 = value[0] + if isinstance(val0, list): + data = self.arg_delta_blend(value) + else: + out = [] + last = 0 + for v in value: + out.append(v - last) + last = v + data = [] + for num in out: + data.append(encodeNumber(num)) + return bytesjoin(data) + + def arg_delta_blend(self, value): + """A delta list with blend lists has to be *all* blend lists. + + The value is a list is arranged as follows:: + + [ + [V0, d0..dn] + [V1, d0..dn] + ... + [Vm, d0..dn] + ] + + ``V`` is the absolute coordinate value from the default font, and ``d0-dn`` + are the delta values from the *n* regions. Each ``V`` is an absolute + coordinate from the default font. + + We want to return a list:: + + [ + [v0, v1..vm] + [d0..dn] + ... + [d0..dn] + numBlends + blendOp + ] + + where each ``v`` is relative to the previous default font value. + """ + numMasters = len(value[0]) + numBlends = len(value) + numStack = (numBlends * numMasters) + 1 + if numStack > self.maxBlendStack: + # Figure out the max number of value we can blend + # and divide this list up into chunks of that size. + + numBlendValues = int((self.maxBlendStack - 1) / numMasters) + out = [] + while True: + numVal = min(len(value), numBlendValues) + if numVal == 0: + break + valList = value[0:numVal] + out1 = self.arg_delta_blend(valList) + out.extend(out1) + value = value[numVal:] + else: + firstList = [0] * numBlends + deltaList = [None] * numBlends + i = 0 + prevVal = 0 + while i < numBlends: + # For PrivateDict BlueValues, the default font + # values are absolute, not relative. + # Must convert these back to relative coordinates + # before writing to CFF2. + defaultValue = value[i][0] + firstList[i] = defaultValue - prevVal + prevVal = defaultValue + deltaList[i] = value[i][1:] + i += 1 + + relValueList = firstList + for blendList in deltaList: + relValueList.extend(blendList) + out = [encodeNumber(val) for val in relValueList] + out.append(encodeNumber(numBlends)) + out.append(bytechr(blendOp)) + return out + + +def encodeNumber(num): + if isinstance(num, float): + return psCharStrings.encodeFloat(num) + else: + return psCharStrings.encodeIntCFF(num) + + +class TopDictCompiler(DictCompiler): + opcodes = buildOpcodeDict(topDictOperators) + + def getChildren(self, strings): + isCFF2 = self.isCFF2 + children = [] + if self.dictObj.cff2GetGlyphOrder is None: + if hasattr(self.dictObj, "charset") and self.dictObj.charset: + if hasattr(self.dictObj, "ROS"): # aka isCID + charsetCode = None + else: + charsetCode = getStdCharSet(self.dictObj.charset) + if charsetCode is None: + children.append( + CharsetCompiler(strings, self.dictObj.charset, self) + ) + else: + self.rawDict["charset"] = charsetCode + if hasattr(self.dictObj, "Encoding") and self.dictObj.Encoding: + encoding = self.dictObj.Encoding + if not isinstance(encoding, str): + children.append(EncodingCompiler(strings, encoding, self)) + else: + if hasattr(self.dictObj, "VarStore"): + varStoreData = self.dictObj.VarStore + varStoreComp = VarStoreCompiler(varStoreData, self) + children.append(varStoreComp) + if hasattr(self.dictObj, "FDSelect"): + # I have not yet supported merging a ttx CFF-CID font, as there are + # interesting issues about merging the FDArrays. Here I assume that + # either the font was read from XML, and the FDSelect indices are all + # in the charstring data, or the FDSelect array is already fully defined. + fdSelect = self.dictObj.FDSelect + # probably read in from XML; assume fdIndex in CharString data + if len(fdSelect) == 0: + charStrings = self.dictObj.CharStrings + for name in self.dictObj.charset: + fdSelect.append(charStrings[name].fdSelectIndex) + fdSelectComp = FDSelectCompiler(fdSelect, self) + children.append(fdSelectComp) + if hasattr(self.dictObj, "CharStrings"): + items = [] + charStrings = self.dictObj.CharStrings + for name in self.dictObj.charset: + items.append(charStrings[name]) + charStringsComp = CharStringsCompiler(items, strings, self, isCFF2=isCFF2) + children.append(charStringsComp) + if hasattr(self.dictObj, "FDArray"): + # I have not yet supported merging a ttx CFF-CID font, as there are + # interesting issues about merging the FDArrays. Here I assume that the + # FDArray info is correct and complete. + fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self) + children.append(fdArrayIndexComp) + children.extend(fdArrayIndexComp.getChildren(strings)) + if hasattr(self.dictObj, "Private"): + privComp = self.dictObj.Private.getCompiler(strings, self) + children.append(privComp) + children.extend(privComp.getChildren(strings)) + return children + + +class FontDictCompiler(DictCompiler): + opcodes = buildOpcodeDict(topDictOperators) + + def __init__(self, dictObj, strings, parent, isCFF2=None): + super(FontDictCompiler, self).__init__(dictObj, strings, parent, isCFF2=isCFF2) + # + # We now take some effort to detect if there were any key/value pairs + # supplied that were ignored in the FontDict context, and issue a warning + # for those cases. + # + ignoredNames = [] + dictObj = self.dictObj + for name in sorted(set(dictObj.converters) - set(dictObj.order)): + if name in dictObj.rawDict: + # The font was directly read from binary. In this + # case, we want to report *all* "useless" key/value + # pairs that are in the font, not just the ones that + # are different from the default. + ignoredNames.append(name) + else: + # The font was probably read from a TTX file. We only + # warn about keys whos value is not the default. The + # ones that have the default value will not be written + # to binary anyway. + default = dictObj.defaults.get(name) + if default is not None: + conv = dictObj.converters[name] + default = conv.read(dictObj, default) + if getattr(dictObj, name, None) != default: + ignoredNames.append(name) + if ignoredNames: + log.warning( + "Some CFF FDArray/FontDict keys were ignored upon compile: " + + " ".join(sorted(ignoredNames)) + ) + + def getChildren(self, strings): + children = [] + if hasattr(self.dictObj, "Private"): + privComp = self.dictObj.Private.getCompiler(strings, self) + children.append(privComp) + children.extend(privComp.getChildren(strings)) + return children + + +class PrivateDictCompiler(DictCompiler): + maxBlendStack = maxStackLimit + opcodes = buildOpcodeDict(privateDictOperators) + + def setPos(self, pos, endPos): + size = endPos - pos + self.parent.rawDict["Private"] = size, pos + self.pos = pos + + def getChildren(self, strings): + children = [] + if hasattr(self.dictObj, "Subrs"): + children.append(self.dictObj.Subrs.getCompiler(strings, self)) + return children + + +class BaseDict(object): + def __init__(self, strings=None, file=None, offset=None, isCFF2=None): + assert (isCFF2 is None) == (file is None) + self.rawDict = {} + self.skipNames = [] + self.strings = strings + if file is None: + return + self._isCFF2 = isCFF2 + self.file = file + if offset is not None: + log.log(DEBUG, "loading %s at %s", self.__class__.__name__, offset) + self.offset = offset + + def decompile(self, data): + log.log(DEBUG, " length %s is %d", self.__class__.__name__, len(data)) + dec = self.decompilerClass(self.strings, self) + dec.decompile(data) + self.rawDict = dec.getDict() + self.postDecompile() + + def postDecompile(self): + pass + + def getCompiler(self, strings, parent, isCFF2=None): + return self.compilerClass(self, strings, parent, isCFF2=isCFF2) + + def __getattr__(self, name): + if name[:2] == name[-2:] == "__": + # to make deepcopy() and pickle.load() work, we need to signal with + # AttributeError that dunder methods like '__deepcopy__' or '__getstate__' + # aren't implemented. For more details, see: + # https://github.com/fonttools/fonttools/pull/1488 + raise AttributeError(name) + value = self.rawDict.get(name, None) + if value is None: + value = self.defaults.get(name) + if value is None: + raise AttributeError(name) + conv = self.converters[name] + value = conv.read(self, value) + setattr(self, name, value) + return value + + def toXML(self, xmlWriter): + for name in self.order: + if name in self.skipNames: + continue + value = getattr(self, name, None) + # XXX For "charset" we never skip calling xmlWrite even if the + # value is None, so we always write the following XML comment: + # + # + # + # Charset is None when 'CFF ' table is imported from XML into an + # empty TTFont(). By writing this comment all the time, we obtain + # the same XML output whether roundtripping XML-to-XML or + # dumping binary-to-XML + if value is None and name != "charset": + continue + conv = self.converters[name] + conv.xmlWrite(xmlWriter, name, value) + ignoredNames = set(self.rawDict) - set(self.order) + if ignoredNames: + xmlWriter.comment( + "some keys were ignored: %s" % " ".join(sorted(ignoredNames)) + ) + xmlWriter.newline() + + def fromXML(self, name, attrs, content): + conv = self.converters[name] + value = conv.xmlRead(name, attrs, content, self) + setattr(self, name, value) + + +class TopDict(BaseDict): + """The ``TopDict`` represents the top-level dictionary holding font + information. CFF2 tables contain a restricted set of top-level entries + as described `here `_, + but CFF tables may contain a wider range of information. This information + can be accessed through attributes or through the dictionary returned + through the ``rawDict`` property: + + .. code:: python + + font = tt["CFF "].cff[0] + font.FamilyName + # 'Linux Libertine O' + font.rawDict["FamilyName"] + # 'Linux Libertine O' + + More information is available in the CFF file's private dictionary, accessed + via the ``Private`` property: + + .. code:: python + + tt["CFF "].cff[0].Private.BlueValues + # [-15, 0, 515, 515, 666, 666] + + """ + + defaults = buildDefaults(topDictOperators) + converters = buildConverters(topDictOperators) + compilerClass = TopDictCompiler + order = buildOrder(topDictOperators) + decompilerClass = TopDictDecompiler + + def __init__( + self, + strings=None, + file=None, + offset=None, + GlobalSubrs=None, + cff2GetGlyphOrder=None, + isCFF2=None, + ): + super(TopDict, self).__init__(strings, file, offset, isCFF2=isCFF2) + self.cff2GetGlyphOrder = cff2GetGlyphOrder + self.GlobalSubrs = GlobalSubrs + if isCFF2: + self.defaults = buildDefaults(topDictOperators2) + self.charset = cff2GetGlyphOrder() + self.order = buildOrder(topDictOperators2) + else: + self.defaults = buildDefaults(topDictOperators) + self.order = buildOrder(topDictOperators) + + def getGlyphOrder(self): + """Returns a list of glyph names in the CFF font.""" + return self.charset + + def postDecompile(self): + offset = self.rawDict.get("CharStrings") + if offset is None: + return + # get the number of glyphs beforehand. + self.file.seek(offset) + if self._isCFF2: + self.numGlyphs = readCard32(self.file) + else: + self.numGlyphs = readCard16(self.file) + + def toXML(self, xmlWriter): + if hasattr(self, "CharStrings"): + self.decompileAllCharStrings() + if hasattr(self, "ROS"): + self.skipNames = ["Encoding"] + if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"): + # these values have default values, but I only want them to show up + # in CID fonts. + self.skipNames = [ + "CIDFontVersion", + "CIDFontRevision", + "CIDFontType", + "CIDCount", + ] + BaseDict.toXML(self, xmlWriter) + + def decompileAllCharStrings(self): + # Make sure that all the Private Dicts have been instantiated. + for i, charString in enumerate(self.CharStrings.values()): + try: + charString.decompile() + except: + log.error("Error in charstring %s", i) + raise + + def recalcFontBBox(self): + fontBBox = None + for charString in self.CharStrings.values(): + bounds = charString.calcBounds(self.CharStrings) + if bounds is not None: + if fontBBox is not None: + fontBBox = unionRect(fontBBox, bounds) + else: + fontBBox = bounds + + if fontBBox is None: + self.FontBBox = self.defaults["FontBBox"][:] + else: + self.FontBBox = list(intRect(fontBBox)) + + +class FontDict(BaseDict): + # + # Since fonttools used to pass a lot of fields that are not relevant in the FDArray + # FontDict, there are 'ttx' files in the wild that contain all these. These got in + # the ttx files because fonttools writes explicit values for all the TopDict default + # values. These are not actually illegal in the context of an FDArray FontDict - you + # can legally, per spec, put any arbitrary key/value pair in a FontDict - but are + # useless since current major company CFF interpreters ignore anything but the set + # listed in this file. So, we just silently skip them. An exception is Weight: this + # is not used by any interpreter, but some foundries have asked that this be + # supported in FDArray FontDicts just to preserve information about the design when + # the font is being inspected. + # + # On top of that, there are fonts out there that contain such useless FontDict values. + # + # By subclassing TopDict, we *allow* all key/values from TopDict, both when reading + # from binary or when reading from XML, but by overriding `order` with a limited + # list of names, we ensure that only the useful names ever get exported to XML and + # ever get compiled into the binary font. + # + # We override compilerClass so we can warn about "useless" key/value pairs, either + # from the original binary font or from TTX input. + # + # See: + # - https://github.com/fonttools/fonttools/issues/740 + # - https://github.com/fonttools/fonttools/issues/601 + # - https://github.com/adobe-type-tools/afdko/issues/137 + # + defaults = {} + converters = buildConverters(topDictOperators) + compilerClass = FontDictCompiler + orderCFF = ["FontName", "FontMatrix", "Weight", "Private"] + orderCFF2 = ["Private"] + decompilerClass = TopDictDecompiler + + def __init__( + self, + strings=None, + file=None, + offset=None, + GlobalSubrs=None, + isCFF2=None, + vstore=None, + ): + super(FontDict, self).__init__(strings, file, offset, isCFF2=isCFF2) + self.vstore = vstore + self.setCFF2(isCFF2) + + def setCFF2(self, isCFF2): + # isCFF2 may be None. + if isCFF2: + self.order = self.orderCFF2 + self._isCFF2 = True + else: + self.order = self.orderCFF + self._isCFF2 = False + + +class PrivateDict(BaseDict): + defaults = buildDefaults(privateDictOperators) + converters = buildConverters(privateDictOperators) + order = buildOrder(privateDictOperators) + decompilerClass = PrivateDictDecompiler + compilerClass = PrivateDictCompiler + + def __init__(self, strings=None, file=None, offset=None, isCFF2=None, vstore=None): + super(PrivateDict, self).__init__(strings, file, offset, isCFF2=isCFF2) + self.vstore = vstore + if isCFF2: + self.defaults = buildDefaults(privateDictOperators2) + self.order = buildOrder(privateDictOperators2) + # Provide dummy values. This avoids needing to provide + # an isCFF2 state in a lot of places. + self.nominalWidthX = self.defaultWidthX = None + self._isCFF2 = True + else: + self.defaults = buildDefaults(privateDictOperators) + self.order = buildOrder(privateDictOperators) + self._isCFF2 = False + + @property + def in_cff2(self): + return self._isCFF2 + + def getNumRegions(self, vi=None): # called from misc/psCharStrings.py + # if getNumRegions is being called, we can assume that VarStore exists. + if vi is None: + if hasattr(self, "vsindex"): + vi = self.vsindex + else: + vi = 0 + numRegions = self.vstore.getNumRegions(vi) + return numRegions + + +class IndexedStrings(object): + """SID -> string mapping.""" + + def __init__(self, file=None): + if file is None: + strings = [] + else: + strings = [tostr(s, encoding="latin1") for s in Index(file, isCFF2=False)] + self.strings = strings + + def getCompiler(self): + return IndexedStringsCompiler(self, None, self, isCFF2=False) + + def __len__(self): + return len(self.strings) + + def __getitem__(self, SID): + if SID < cffStandardStringCount: + return cffStandardStrings[SID] + else: + return self.strings[SID - cffStandardStringCount] + + def getSID(self, s): + if not hasattr(self, "stringMapping"): + self.buildStringMapping() + s = tostr(s, encoding="latin1") + if s in cffStandardStringMapping: + SID = cffStandardStringMapping[s] + elif s in self.stringMapping: + SID = self.stringMapping[s] + else: + SID = len(self.strings) + cffStandardStringCount + self.strings.append(s) + self.stringMapping[s] = SID + return SID + + def getStrings(self): + return self.strings + + def buildStringMapping(self): + self.stringMapping = {} + for index in range(len(self.strings)): + self.stringMapping[self.strings[index]] = index + cffStandardStringCount + + +# The 391 Standard Strings as used in the CFF format. +# from Adobe Technical None #5176, version 1.0, 18 March 1998 + +cffStandardStrings = [ + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold", +] + +cffStandardStringCount = 391 +assert len(cffStandardStrings) == cffStandardStringCount +# build reverse mapping +cffStandardStringMapping = {} +for _i in range(cffStandardStringCount): + cffStandardStringMapping[cffStandardStrings[_i]] = _i + +cffISOAdobeStrings = [ + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", +] + +cffISOAdobeStringCount = 229 +assert len(cffISOAdobeStrings) == cffISOAdobeStringCount + +cffIExpertStrings = [ + ".notdef", + "space", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", +] + +cffExpertStringCount = 166 +assert len(cffIExpertStrings) == cffExpertStringCount + +cffExpertSubsetStrings = [ + ".notdef", + "space", + "dollaroldstyle", + "dollarsuperior", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "hyphensuperior", + "colonmonetary", + "onefitted", + "rupiah", + "centoldstyle", + "figuredash", + "hypheninferior", + "onequarter", + "onehalf", + "threequarters", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", +] + +cffExpertSubsetStringCount = 87 +assert len(cffExpertSubsetStrings) == cffExpertSubsetStringCount diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFF2ToCFF.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFF2ToCFF.cpython-312.pyc new file mode 100644 index 0000000..1fdc0bf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFF2ToCFF.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFFToCFF2.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFFToCFF2.cpython-312.pyc new file mode 100644 index 0000000..01da5b4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/CFFToCFF2.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..cce03b4 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/specializer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/specializer.cpython-312.pyc new file mode 100644 index 0000000..4e53aee Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/specializer.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/transforms.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/transforms.cpython-312.pyc new file mode 100644 index 0000000..41094fd Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/transforms.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/width.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/width.cpython-312.pyc new file mode 100644 index 0000000..8aa3192 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cffLib/__pycache__/width.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/specializer.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/specializer.py new file mode 100644 index 0000000..974060c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/specializer.py @@ -0,0 +1,927 @@ +# -*- coding: utf-8 -*- + +"""T2CharString operator specializer and generalizer. + +PostScript glyph drawing operations can be expressed in multiple different +ways. For example, as well as the ``lineto`` operator, there is also a +``hlineto`` operator which draws a horizontal line, removing the need to +specify a ``dx`` coordinate, and a ``vlineto`` operator which draws a +vertical line, removing the need to specify a ``dy`` coordinate. As well +as decompiling :class:`fontTools.misc.psCharStrings.T2CharString` objects +into lists of operations, this module allows for conversion between general +and specific forms of the operation. + +""" + +from fontTools.cffLib import maxStackLimit + + +def stringToProgram(string): + if isinstance(string, str): + string = string.split() + program = [] + for token in string: + try: + token = int(token) + except ValueError: + try: + token = float(token) + except ValueError: + pass + program.append(token) + return program + + +def programToString(program): + return " ".join(str(x) for x in program) + + +def programToCommands(program, getNumRegions=None): + """Takes a T2CharString program list and returns list of commands. + Each command is a two-tuple of commandname,arg-list. The commandname might + be empty string if no commandname shall be emitted (used for glyph width, + hintmask/cntrmask argument, as well as stray arguments at the end of the + program (🤷). + 'getNumRegions' may be None, or a callable object. It must return the + number of regions. 'getNumRegions' takes a single argument, vsindex. It + returns the numRegions for the vsindex. + The Charstring may or may not start with a width value. If the first + non-blend operator has an odd number of arguments, then the first argument is + a width, and is popped off. This is complicated with blend operators, as + there may be more than one before the first hint or moveto operator, and each + one reduces several arguments to just one list argument. We have to sum the + number of arguments that are not part of the blend arguments, and all the + 'numBlends' values. We could instead have said that by definition, if there + is a blend operator, there is no width value, since CFF2 Charstrings don't + have width values. I discussed this with Behdad, and we are allowing for an + initial width value in this case because developers may assemble a CFF2 + charstring from CFF Charstrings, which could have width values. + """ + + seenWidthOp = False + vsIndex = 0 + lenBlendStack = 0 + lastBlendIndex = 0 + commands = [] + stack = [] + it = iter(program) + + for token in it: + if not isinstance(token, str): + stack.append(token) + continue + + if token == "blend": + assert getNumRegions is not None + numSourceFonts = 1 + getNumRegions(vsIndex) + # replace the blend op args on the stack with a single list + # containing all the blend op args. + numBlends = stack[-1] + numBlendArgs = numBlends * numSourceFonts + 1 + # replace first blend op by a list of the blend ops. + stack[-numBlendArgs:] = [stack[-numBlendArgs:]] + lenStack = len(stack) + lenBlendStack += numBlends + lenStack - 1 + lastBlendIndex = lenStack + # if a blend op exists, this is or will be a CFF2 charstring. + continue + + elif token == "vsindex": + vsIndex = stack[-1] + assert type(vsIndex) is int + + elif (not seenWidthOp) and token in { + "hstem", + "hstemhm", + "vstem", + "vstemhm", + "cntrmask", + "hintmask", + "hmoveto", + "vmoveto", + "rmoveto", + "endchar", + }: + seenWidthOp = True + parity = token in {"hmoveto", "vmoveto"} + if lenBlendStack: + # lenBlendStack has the number of args represented by the last blend + # arg and all the preceding args. We need to now add the number of + # args following the last blend arg. + numArgs = lenBlendStack + len(stack[lastBlendIndex:]) + else: + numArgs = len(stack) + if numArgs and (numArgs % 2) ^ parity: + width = stack.pop(0) + commands.append(("", [width])) + + if token in {"hintmask", "cntrmask"}: + if stack: + commands.append(("", stack)) + commands.append((token, [])) + commands.append(("", [next(it)])) + else: + commands.append((token, stack)) + stack = [] + if stack: + commands.append(("", stack)) + return commands + + +def _flattenBlendArgs(args): + token_list = [] + for arg in args: + if isinstance(arg, list): + token_list.extend(arg) + token_list.append("blend") + else: + token_list.append(arg) + return token_list + + +def commandsToProgram(commands): + """Takes a commands list as returned by programToCommands() and converts + it back to a T2CharString program list.""" + program = [] + for op, args in commands: + if any(isinstance(arg, list) for arg in args): + args = _flattenBlendArgs(args) + program.extend(args) + if op: + program.append(op) + return program + + +def _everyN(el, n): + """Group the list el into groups of size n""" + l = len(el) + if l % n != 0: + raise ValueError(el) + for i in range(0, l, n): + yield el[i : i + n] + + +class _GeneralizerDecombinerCommandsMap(object): + @staticmethod + def rmoveto(args): + if len(args) != 2: + raise ValueError(args) + yield ("rmoveto", args) + + @staticmethod + def hmoveto(args): + if len(args) != 1: + raise ValueError(args) + yield ("rmoveto", [args[0], 0]) + + @staticmethod + def vmoveto(args): + if len(args) != 1: + raise ValueError(args) + yield ("rmoveto", [0, args[0]]) + + @staticmethod + def rlineto(args): + if not args: + raise ValueError(args) + for args in _everyN(args, 2): + yield ("rlineto", args) + + @staticmethod + def hlineto(args): + if not args: + raise ValueError(args) + it = iter(args) + try: + while True: + yield ("rlineto", [next(it), 0]) + yield ("rlineto", [0, next(it)]) + except StopIteration: + pass + + @staticmethod + def vlineto(args): + if not args: + raise ValueError(args) + it = iter(args) + try: + while True: + yield ("rlineto", [0, next(it)]) + yield ("rlineto", [next(it), 0]) + except StopIteration: + pass + + @staticmethod + def rrcurveto(args): + if not args: + raise ValueError(args) + for args in _everyN(args, 6): + yield ("rrcurveto", args) + + @staticmethod + def hhcurveto(args): + l = len(args) + if l < 4 or l % 4 > 1: + raise ValueError(args) + if l % 2 == 1: + yield ("rrcurveto", [args[1], args[0], args[2], args[3], args[4], 0]) + args = args[5:] + for args in _everyN(args, 4): + yield ("rrcurveto", [args[0], 0, args[1], args[2], args[3], 0]) + + @staticmethod + def vvcurveto(args): + l = len(args) + if l < 4 or l % 4 > 1: + raise ValueError(args) + if l % 2 == 1: + yield ("rrcurveto", [args[0], args[1], args[2], args[3], 0, args[4]]) + args = args[5:] + for args in _everyN(args, 4): + yield ("rrcurveto", [0, args[0], args[1], args[2], 0, args[3]]) + + @staticmethod + def hvcurveto(args): + l = len(args) + if l < 4 or l % 8 not in {0, 1, 4, 5}: + raise ValueError(args) + last_args = None + if l % 2 == 1: + lastStraight = l % 8 == 5 + args, last_args = args[:-5], args[-5:] + it = _everyN(args, 4) + try: + while True: + args = next(it) + yield ("rrcurveto", [args[0], 0, args[1], args[2], 0, args[3]]) + args = next(it) + yield ("rrcurveto", [0, args[0], args[1], args[2], args[3], 0]) + except StopIteration: + pass + if last_args: + args = last_args + if lastStraight: + yield ("rrcurveto", [args[0], 0, args[1], args[2], args[4], args[3]]) + else: + yield ("rrcurveto", [0, args[0], args[1], args[2], args[3], args[4]]) + + @staticmethod + def vhcurveto(args): + l = len(args) + if l < 4 or l % 8 not in {0, 1, 4, 5}: + raise ValueError(args) + last_args = None + if l % 2 == 1: + lastStraight = l % 8 == 5 + args, last_args = args[:-5], args[-5:] + it = _everyN(args, 4) + try: + while True: + args = next(it) + yield ("rrcurveto", [0, args[0], args[1], args[2], args[3], 0]) + args = next(it) + yield ("rrcurveto", [args[0], 0, args[1], args[2], 0, args[3]]) + except StopIteration: + pass + if last_args: + args = last_args + if lastStraight: + yield ("rrcurveto", [0, args[0], args[1], args[2], args[3], args[4]]) + else: + yield ("rrcurveto", [args[0], 0, args[1], args[2], args[4], args[3]]) + + @staticmethod + def rcurveline(args): + l = len(args) + if l < 8 or l % 6 != 2: + raise ValueError(args) + args, last_args = args[:-2], args[-2:] + for args in _everyN(args, 6): + yield ("rrcurveto", args) + yield ("rlineto", last_args) + + @staticmethod + def rlinecurve(args): + l = len(args) + if l < 8 or l % 2 != 0: + raise ValueError(args) + args, last_args = args[:-6], args[-6:] + for args in _everyN(args, 2): + yield ("rlineto", args) + yield ("rrcurveto", last_args) + + +def _convertBlendOpToArgs(blendList): + # args is list of blend op args. Since we are supporting + # recursive blend op calls, some of these args may also + # be a list of blend op args, and need to be converted before + # we convert the current list. + if any([isinstance(arg, list) for arg in blendList]): + args = [ + i + for e in blendList + for i in (_convertBlendOpToArgs(e) if isinstance(e, list) else [e]) + ] + else: + args = blendList + + # We now know that blendList contains a blend op argument list, even if + # some of the args are lists that each contain a blend op argument list. + # Convert from: + # [default font arg sequence x0,...,xn] + [delta tuple for x0] + ... + [delta tuple for xn] + # to: + # [ [x0] + [delta tuple for x0], + # ..., + # [xn] + [delta tuple for xn] ] + numBlends = args[-1] + # Can't use args.pop() when the args are being used in a nested list + # comprehension. See calling context + args = args[:-1] + + l = len(args) + numRegions = l // numBlends - 1 + if not (numBlends * (numRegions + 1) == l): + raise ValueError(blendList) + + defaultArgs = [[arg] for arg in args[:numBlends]] + deltaArgs = args[numBlends:] + numDeltaValues = len(deltaArgs) + deltaList = [ + deltaArgs[i : i + numRegions] for i in range(0, numDeltaValues, numRegions) + ] + blend_args = [a + b + [1] for a, b in zip(defaultArgs, deltaList)] + return blend_args + + +def generalizeCommands(commands, ignoreErrors=False): + result = [] + mapping = _GeneralizerDecombinerCommandsMap + for op, args in commands: + # First, generalize any blend args in the arg list. + if any([isinstance(arg, list) for arg in args]): + try: + args = [ + n + for arg in args + for n in ( + _convertBlendOpToArgs(arg) if isinstance(arg, list) else [arg] + ) + ] + except ValueError: + if ignoreErrors: + # Store op as data, such that consumers of commands do not have to + # deal with incorrect number of arguments. + result.append(("", args)) + result.append(("", [op])) + else: + raise + + func = getattr(mapping, op, None) + if func is None: + result.append((op, args)) + continue + try: + for command in func(args): + result.append(command) + except ValueError: + if ignoreErrors: + # Store op as data, such that consumers of commands do not have to + # deal with incorrect number of arguments. + result.append(("", args)) + result.append(("", [op])) + else: + raise + return result + + +def generalizeProgram(program, getNumRegions=None, **kwargs): + return commandsToProgram( + generalizeCommands(programToCommands(program, getNumRegions), **kwargs) + ) + + +def _categorizeVector(v): + """ + Takes X,Y vector v and returns one of r, h, v, or 0 depending on which + of X and/or Y are zero, plus tuple of nonzero ones. If both are zero, + it returns a single zero still. + + >>> _categorizeVector((0,0)) + ('0', (0,)) + >>> _categorizeVector((1,0)) + ('h', (1,)) + >>> _categorizeVector((0,2)) + ('v', (2,)) + >>> _categorizeVector((1,2)) + ('r', (1, 2)) + """ + if not v[0]: + if not v[1]: + return "0", v[:1] + else: + return "v", v[1:] + else: + if not v[1]: + return "h", v[:1] + else: + return "r", v + + +def _mergeCategories(a, b): + if a == "0": + return b + if b == "0": + return a + if a == b: + return a + return None + + +def _negateCategory(a): + if a == "h": + return "v" + if a == "v": + return "h" + assert a in "0r" + return a + + +def _convertToBlendCmds(args): + # return a list of blend commands, and + # the remaining non-blended args, if any. + num_args = len(args) + stack_use = 0 + new_args = [] + i = 0 + while i < num_args: + arg = args[i] + i += 1 + if not isinstance(arg, list): + new_args.append(arg) + stack_use += 1 + else: + prev_stack_use = stack_use + # The arg is a tuple of blend values. + # These are each (master 0,delta 1..delta n, 1) + # Combine as many successive tuples as we can, + # up to the max stack limit. + num_sources = len(arg) - 1 + blendlist = [arg] + stack_use += 1 + num_sources # 1 for the num_blends arg + + # if we are here, max stack is the CFF2 max stack. + # I use the CFF2 max stack limit here rather than + # the 'maxstack' chosen by the client, as the default + # maxstack may have been used unintentionally. For all + # the other operators, this just produces a little less + # optimization, but here it puts a hard (and low) limit + # on the number of source fonts that can be used. + # + # Make sure the stack depth does not exceed (maxstack - 1), so + # that subroutinizer can insert subroutine calls at any point. + while ( + (i < num_args) + and isinstance(args[i], list) + and stack_use + num_sources < maxStackLimit + ): + blendlist.append(args[i]) + i += 1 + stack_use += num_sources + # blendList now contains as many single blend tuples as can be + # combined without exceeding the CFF2 stack limit. + num_blends = len(blendlist) + # append the 'num_blends' default font values + blend_args = [] + for arg in blendlist: + blend_args.append(arg[0]) + for arg in blendlist: + assert arg[-1] == 1 + blend_args.extend(arg[1:-1]) + blend_args.append(num_blends) + new_args.append(blend_args) + stack_use = prev_stack_use + num_blends + + return new_args + + +def _addArgs(a, b): + if isinstance(b, list): + if isinstance(a, list): + if len(a) != len(b) or a[-1] != b[-1]: + raise ValueError() + return [_addArgs(va, vb) for va, vb in zip(a[:-1], b[:-1])] + [a[-1]] + else: + a, b = b, a + if isinstance(a, list): + assert a[-1] == 1 + return [_addArgs(a[0], b)] + a[1:] + return a + b + + +def _argsStackUse(args): + stackLen = 0 + maxLen = 0 + for arg in args: + if type(arg) is list: + # Blended arg + maxLen = max(maxLen, stackLen + _argsStackUse(arg)) + stackLen += arg[-1] + else: + stackLen += 1 + return max(stackLen, maxLen) + + +def specializeCommands( + commands, + ignoreErrors=False, + generalizeFirst=True, + preserveTopology=False, + maxstack=48, +): + # We perform several rounds of optimizations. They are carefully ordered and are: + # + # 0. Generalize commands. + # This ensures that they are in our expected simple form, with each line/curve only + # having arguments for one segment, and using the generic form (rlineto/rrcurveto). + # If caller is sure the input is in this form, they can turn off generalization to + # save time. + # + # 1. Combine successive rmoveto operations. + # + # 2. Specialize rmoveto/rlineto/rrcurveto operators into horizontal/vertical variants. + # We specialize into some, made-up, variants as well, which simplifies following + # passes. + # + # 3. Merge or delete redundant operations, to the extent requested. + # OpenType spec declares point numbers in CFF undefined. As such, we happily + # change topology. If client relies on point numbers (in GPOS anchors, or for + # hinting purposes(what?)) they can turn this off. + # + # 4. Peephole optimization to revert back some of the h/v variants back into their + # original "relative" operator (rline/rrcurveto) if that saves a byte. + # + # 5. Combine adjacent operators when possible, minding not to go over max stack size. + # + # 6. Resolve any remaining made-up operators into real operators. + # + # I have convinced myself that this produces optimal bytecode (except for, possibly + # one byte each time maxstack size prohibits combining.) YMMV, but you'd be wrong. :-) + # A dynamic-programming approach can do the same but would be significantly slower. + # + # 7. For any args which are blend lists, convert them to a blend command. + + # 0. Generalize commands. + if generalizeFirst: + commands = generalizeCommands(commands, ignoreErrors=ignoreErrors) + else: + commands = list(commands) # Make copy since we modify in-place later. + + # 1. Combine successive rmoveto operations. + for i in range(len(commands) - 1, 0, -1): + if "rmoveto" == commands[i][0] == commands[i - 1][0]: + v1, v2 = commands[i - 1][1], commands[i][1] + commands[i - 1] = ( + "rmoveto", + [_addArgs(v1[0], v2[0]), _addArgs(v1[1], v2[1])], + ) + del commands[i] + + # 2. Specialize rmoveto/rlineto/rrcurveto operators into horizontal/vertical variants. + # + # We, in fact, specialize into more, made-up, variants that special-case when both + # X and Y components are zero. This simplifies the following optimization passes. + # This case is rare, but OCD does not let me skip it. + # + # After this round, we will have four variants that use the following mnemonics: + # + # - 'r' for relative, ie. non-zero X and non-zero Y, + # - 'h' for horizontal, ie. zero X and non-zero Y, + # - 'v' for vertical, ie. non-zero X and zero Y, + # - '0' for zeros, ie. zero X and zero Y. + # + # The '0' pseudo-operators are not part of the spec, but help simplify the following + # optimization rounds. We resolve them at the end. So, after this, we will have four + # moveto and four lineto variants: + # + # - 0moveto, 0lineto + # - hmoveto, hlineto + # - vmoveto, vlineto + # - rmoveto, rlineto + # + # and sixteen curveto variants. For example, a '0hcurveto' operator means a curve + # dx0,dy0,dx1,dy1,dx2,dy2,dx3,dy3 where dx0, dx1, and dy3 are zero but not dx3. + # An 'rvcurveto' means dx3 is zero but not dx0,dy0,dy3. + # + # There are nine different variants of curves without the '0'. Those nine map exactly + # to the existing curve variants in the spec: rrcurveto, and the four variants hhcurveto, + # vvcurveto, hvcurveto, and vhcurveto each cover two cases, one with an odd number of + # arguments and one without. Eg. an hhcurveto with an extra argument (odd number of + # arguments) is in fact an rhcurveto. The operators in the spec are designed such that + # all four of rhcurveto, rvcurveto, hrcurveto, and vrcurveto are encodable for one curve. + # + # Of the curve types with '0', the 00curveto is equivalent to a lineto variant. The rest + # of the curve types with a 0 need to be encoded as a h or v variant. Ie. a '0' can be + # thought of a "don't care" and can be used as either an 'h' or a 'v'. As such, we always + # encode a number 0 as argument when we use a '0' variant. Later on, we can just substitute + # the '0' with either 'h' or 'v' and it works. + # + # When we get to curve splines however, things become more complicated... XXX finish this. + # There's one more complexity with splines. If one side of the spline is not horizontal or + # vertical (or zero), ie. if it's 'r', then it limits which spline types we can encode. + # Only hhcurveto and vvcurveto operators can encode a spline starting with 'r', and + # only hvcurveto and vhcurveto operators can encode a spline ending with 'r'. + # This limits our merge opportunities later. + # + for i in range(len(commands)): + op, args = commands[i] + + if op in {"rmoveto", "rlineto"}: + c, args = _categorizeVector(args) + commands[i] = c + op[1:], args + continue + + if op == "rrcurveto": + c1, args1 = _categorizeVector(args[:2]) + c2, args2 = _categorizeVector(args[-2:]) + commands[i] = c1 + c2 + "curveto", args1 + args[2:4] + args2 + continue + + # 3. Merge or delete redundant operations, to the extent requested. + # + # TODO + # A 0moveto that comes before all other path operations can be removed. + # though I find conflicting evidence for this. + # + # TODO + # "If hstem and vstem hints are both declared at the beginning of a + # CharString, and this sequence is followed directly by the hintmask or + # cntrmask operators, then the vstem hint operator (or, if applicable, + # the vstemhm operator) need not be included." + # + # "The sequence and form of a CFF2 CharString program may be represented as: + # {hs* vs* cm* hm* mt subpath}? {mt subpath}*" + # + # https://www.microsoft.com/typography/otspec/cff2charstr.htm#section3.1 + # + # For Type2 CharStrings the sequence is: + # w? {hs* vs* cm* hm* mt subpath}? {mt subpath}* endchar" + + # Some other redundancies change topology (point numbers). + if not preserveTopology: + for i in range(len(commands) - 1, -1, -1): + op, args = commands[i] + + # A 00curveto is demoted to a (specialized) lineto. + if op == "00curveto": + assert len(args) == 4 + c, args = _categorizeVector(args[1:3]) + op = c + "lineto" + commands[i] = op, args + # and then... + + # A 0lineto can be deleted. + if op == "0lineto": + del commands[i] + continue + + # Merge adjacent hlineto's and vlineto's. + # In CFF2 charstrings from variable fonts, each + # arg item may be a list of blendable values, one from + # each source font. + if i and op in {"hlineto", "vlineto"} and (op == commands[i - 1][0]): + _, other_args = commands[i - 1] + assert len(args) == 1 and len(other_args) == 1 + try: + new_args = [_addArgs(args[0], other_args[0])] + except ValueError: + continue + commands[i - 1] = (op, new_args) + del commands[i] + continue + + # 4. Peephole optimization to revert back some of the h/v variants back into their + # original "relative" operator (rline/rrcurveto) if that saves a byte. + for i in range(1, len(commands) - 1): + op, args = commands[i] + prv, nxt = commands[i - 1][0], commands[i + 1][0] + + if op in {"0lineto", "hlineto", "vlineto"} and prv == nxt == "rlineto": + assert len(args) == 1 + args = [0, args[0]] if op[0] == "v" else [args[0], 0] + commands[i] = ("rlineto", args) + continue + + if op[2:] == "curveto" and len(args) == 5 and prv == nxt == "rrcurveto": + assert (op[0] == "r") ^ (op[1] == "r") + if op[0] == "v": + pos = 0 + elif op[0] != "r": + pos = 1 + elif op[1] == "v": + pos = 4 + else: + pos = 5 + # Insert, while maintaining the type of args (can be tuple or list). + args = args[:pos] + type(args)((0,)) + args[pos:] + commands[i] = ("rrcurveto", args) + continue + + # 5. Combine adjacent operators when possible, minding not to go over max stack size. + stackUse = _argsStackUse(commands[-1][1]) if commands else 0 + for i in range(len(commands) - 1, 0, -1): + op1, args1 = commands[i - 1] + op2, args2 = commands[i] + new_op = None + + # Merge logic... + if {op1, op2} <= {"rlineto", "rrcurveto"}: + if op1 == op2: + new_op = op1 + else: + l = len(args2) + if op2 == "rrcurveto" and l == 6: + new_op = "rlinecurve" + elif l == 2: + new_op = "rcurveline" + + elif (op1, op2) in {("rlineto", "rlinecurve"), ("rrcurveto", "rcurveline")}: + new_op = op2 + + elif {op1, op2} == {"vlineto", "hlineto"}: + new_op = op1 + + elif "curveto" == op1[2:] == op2[2:]: + d0, d1 = op1[:2] + d2, d3 = op2[:2] + + if d1 == "r" or d2 == "r" or d0 == d3 == "r": + continue + + d = _mergeCategories(d1, d2) + if d is None: + continue + if d0 == "r": + d = _mergeCategories(d, d3) + if d is None: + continue + new_op = "r" + d + "curveto" + elif d3 == "r": + d0 = _mergeCategories(d0, _negateCategory(d)) + if d0 is None: + continue + new_op = d0 + "r" + "curveto" + else: + d0 = _mergeCategories(d0, d3) + if d0 is None: + continue + new_op = d0 + d + "curveto" + + # Make sure the stack depth does not exceed (maxstack - 1), so + # that subroutinizer can insert subroutine calls at any point. + args1StackUse = _argsStackUse(args1) + combinedStackUse = max(args1StackUse, len(args1) + stackUse) + if new_op and combinedStackUse < maxstack: + commands[i - 1] = (new_op, args1 + args2) + del commands[i] + stackUse = combinedStackUse + else: + stackUse = args1StackUse + + # 6. Resolve any remaining made-up operators into real operators. + for i in range(len(commands)): + op, args = commands[i] + + if op in {"0moveto", "0lineto"}: + commands[i] = "h" + op[1:], args + continue + + if op[2:] == "curveto" and op[:2] not in {"rr", "hh", "vv", "vh", "hv"}: + l = len(args) + + op0, op1 = op[:2] + if (op0 == "r") ^ (op1 == "r"): + assert l % 2 == 1 + if op0 == "0": + op0 = "h" + if op1 == "0": + op1 = "h" + if op0 == "r": + op0 = op1 + if op1 == "r": + op1 = _negateCategory(op0) + assert {op0, op1} <= {"h", "v"}, (op0, op1) + + if l % 2: + if op0 != op1: # vhcurveto / hvcurveto + if (op0 == "h") ^ (l % 8 == 1): + # Swap last two args order + args = args[:-2] + args[-1:] + args[-2:-1] + else: # hhcurveto / vvcurveto + if op0 == "h": # hhcurveto + # Swap first two args order + args = args[1:2] + args[:1] + args[2:] + + commands[i] = op0 + op1 + "curveto", args + continue + + # 7. For any series of args which are blend lists, convert the series to a single blend arg. + for i in range(len(commands)): + op, args = commands[i] + if any(isinstance(arg, list) for arg in args): + commands[i] = op, _convertToBlendCmds(args) + + return commands + + +def specializeProgram(program, getNumRegions=None, **kwargs): + return commandsToProgram( + specializeCommands(programToCommands(program, getNumRegions), **kwargs) + ) + + +if __name__ == "__main__": + import sys + + if len(sys.argv) == 1: + import doctest + + sys.exit(doctest.testmod().failed) + + import argparse + + parser = argparse.ArgumentParser( + "fonttools cffLib.specializer", + description="CFF CharString generalizer/specializer", + ) + parser.add_argument("program", metavar="command", nargs="*", help="Commands.") + parser.add_argument( + "--num-regions", + metavar="NumRegions", + nargs="*", + default=None, + help="Number of variable-font regions for blend opertaions.", + ) + parser.add_argument( + "--font", + metavar="FONTFILE", + default=None, + help="CFF2 font to specialize.", + ) + parser.add_argument( + "-o", + "--output-file", + type=str, + help="Output font file name.", + ) + + options = parser.parse_args(sys.argv[1:]) + + if options.program: + getNumRegions = ( + None + if options.num_regions is None + else lambda vsIndex: int( + options.num_regions[0 if vsIndex is None else vsIndex] + ) + ) + + program = stringToProgram(options.program) + print("Program:") + print(programToString(program)) + commands = programToCommands(program, getNumRegions) + print("Commands:") + print(commands) + program2 = commandsToProgram(commands) + print("Program from commands:") + print(programToString(program2)) + assert program == program2 + print("Generalized program:") + print(programToString(generalizeProgram(program, getNumRegions))) + print("Specialized program:") + print(programToString(specializeProgram(program, getNumRegions))) + + if options.font: + from fontTools.ttLib import TTFont + + font = TTFont(options.font) + cff2 = font["CFF2"].cff.topDictIndex[0] + charstrings = cff2.CharStrings + for glyphName in charstrings.keys(): + charstring = charstrings[glyphName] + charstring.decompile() + getNumRegions = charstring.private.getNumRegions + charstring.program = specializeProgram( + charstring.program, getNumRegions, maxstack=maxStackLimit + ) + + if options.output_file is None: + from fontTools.misc.cliTools import makeOutputFileName + + outfile = makeOutputFileName( + options.font, overWrite=True, suffix=".specialized" + ) + else: + outfile = options.output_file + if outfile: + print("Saving", outfile) + font.save(outfile) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/transforms.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/transforms.py new file mode 100644 index 0000000..b9b7c86 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/transforms.py @@ -0,0 +1,495 @@ +from fontTools.misc.psCharStrings import ( + SimpleT2Decompiler, + T2WidthExtractor, + calcSubrBias, +) + + +def _uniq_sort(l): + return sorted(set(l)) + + +class StopHintCountEvent(Exception): + pass + + +class _DesubroutinizingT2Decompiler(SimpleT2Decompiler): + stop_hintcount_ops = ( + "op_hintmask", + "op_cntrmask", + "op_rmoveto", + "op_hmoveto", + "op_vmoveto", + ) + + def __init__(self, localSubrs, globalSubrs, private=None): + SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs, private) + + def execute(self, charString): + self.need_hintcount = True # until proven otherwise + for op_name in self.stop_hintcount_ops: + setattr(self, op_name, self.stop_hint_count) + + if hasattr(charString, "_desubroutinized"): + # If a charstring has already been desubroutinized, we will still + # need to execute it if we need to count hints in order to + # compute the byte length for mask arguments, and haven't finished + # counting hints pairs. + if self.need_hintcount and self.callingStack: + try: + SimpleT2Decompiler.execute(self, charString) + except StopHintCountEvent: + del self.callingStack[-1] + return + + charString._patches = [] + SimpleT2Decompiler.execute(self, charString) + desubroutinized = charString.program[:] + for idx, expansion in reversed(charString._patches): + assert idx >= 2 + assert desubroutinized[idx - 1] in [ + "callsubr", + "callgsubr", + ], desubroutinized[idx - 1] + assert type(desubroutinized[idx - 2]) == int + if expansion[-1] == "return": + expansion = expansion[:-1] + desubroutinized[idx - 2 : idx] = expansion + if not self.private.in_cff2: + if "endchar" in desubroutinized: + # Cut off after first endchar + desubroutinized = desubroutinized[ + : desubroutinized.index("endchar") + 1 + ] + + charString._desubroutinized = desubroutinized + del charString._patches + + def op_callsubr(self, index): + subr = self.localSubrs[self.operandStack[-1] + self.localBias] + SimpleT2Decompiler.op_callsubr(self, index) + self.processSubr(index, subr) + + def op_callgsubr(self, index): + subr = self.globalSubrs[self.operandStack[-1] + self.globalBias] + SimpleT2Decompiler.op_callgsubr(self, index) + self.processSubr(index, subr) + + def stop_hint_count(self, *args): + self.need_hintcount = False + for op_name in self.stop_hintcount_ops: + setattr(self, op_name, None) + cs = self.callingStack[-1] + if hasattr(cs, "_desubroutinized"): + raise StopHintCountEvent() + + def op_hintmask(self, index): + SimpleT2Decompiler.op_hintmask(self, index) + if self.need_hintcount: + self.stop_hint_count() + + def processSubr(self, index, subr): + cs = self.callingStack[-1] + if not hasattr(cs, "_desubroutinized"): + cs._patches.append((index, subr._desubroutinized)) + + +def desubroutinizeCharString(cs): + """Desubroutinize a charstring in-place.""" + cs.decompile() + subrs = getattr(cs.private, "Subrs", []) + decompiler = _DesubroutinizingT2Decompiler(subrs, cs.globalSubrs, cs.private) + decompiler.execute(cs) + cs.program = cs._desubroutinized + del cs._desubroutinized + + +def desubroutinize(cff): + for fontName in cff.fontNames: + font = cff[fontName] + cs = font.CharStrings + for c in cs.values(): + desubroutinizeCharString(c) + # Delete all the local subrs + if hasattr(font, "FDArray"): + for fd in font.FDArray: + pd = fd.Private + if hasattr(pd, "Subrs"): + del pd.Subrs + if "Subrs" in pd.rawDict: + del pd.rawDict["Subrs"] + else: + pd = font.Private + if hasattr(pd, "Subrs"): + del pd.Subrs + if "Subrs" in pd.rawDict: + del pd.rawDict["Subrs"] + # as well as the global subrs + cff.GlobalSubrs.clear() + + +class _MarkingT2Decompiler(SimpleT2Decompiler): + def __init__(self, localSubrs, globalSubrs, private): + SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs, private) + for subrs in [localSubrs, globalSubrs]: + if subrs and not hasattr(subrs, "_used"): + subrs._used = set() + + def op_callsubr(self, index): + self.localSubrs._used.add(self.operandStack[-1] + self.localBias) + SimpleT2Decompiler.op_callsubr(self, index) + + def op_callgsubr(self, index): + self.globalSubrs._used.add(self.operandStack[-1] + self.globalBias) + SimpleT2Decompiler.op_callgsubr(self, index) + + +class _DehintingT2Decompiler(T2WidthExtractor): + class Hints(object): + def __init__(self): + # Whether calling this charstring produces any hint stems + # Note that if a charstring starts with hintmask, it will + # have has_hint set to True, because it *might* produce an + # implicit vstem if called under certain conditions. + self.has_hint = False + # Index to start at to drop all hints + self.last_hint = 0 + # Index up to which we know more hints are possible. + # Only relevant if status is 0 or 1. + self.last_checked = 0 + # The status means: + # 0: after dropping hints, this charstring is empty + # 1: after dropping hints, there may be more hints + # continuing after this, or there might be + # other things. Not clear yet. + # 2: no more hints possible after this charstring + self.status = 0 + # Has hintmask instructions; not recursive + self.has_hintmask = False + # List of indices of calls to empty subroutines to remove. + self.deletions = [] + + pass + + def __init__( + self, css, localSubrs, globalSubrs, nominalWidthX, defaultWidthX, private=None + ): + self._css = css + T2WidthExtractor.__init__( + self, localSubrs, globalSubrs, nominalWidthX, defaultWidthX + ) + self.private = private + + def execute(self, charString): + old_hints = charString._hints if hasattr(charString, "_hints") else None + charString._hints = self.Hints() + + T2WidthExtractor.execute(self, charString) + + hints = charString._hints + + if hints.has_hint or hints.has_hintmask: + self._css.add(charString) + + if hints.status != 2: + # Check from last_check, make sure we didn't have any operators. + for i in range(hints.last_checked, len(charString.program) - 1): + if isinstance(charString.program[i], str): + hints.status = 2 + break + else: + hints.status = 1 # There's *something* here + hints.last_checked = len(charString.program) + + if old_hints: + assert hints.__dict__ == old_hints.__dict__ + + def op_callsubr(self, index): + subr = self.localSubrs[self.operandStack[-1] + self.localBias] + T2WidthExtractor.op_callsubr(self, index) + self.processSubr(index, subr) + + def op_callgsubr(self, index): + subr = self.globalSubrs[self.operandStack[-1] + self.globalBias] + T2WidthExtractor.op_callgsubr(self, index) + self.processSubr(index, subr) + + def op_hstem(self, index): + T2WidthExtractor.op_hstem(self, index) + self.processHint(index) + + def op_vstem(self, index): + T2WidthExtractor.op_vstem(self, index) + self.processHint(index) + + def op_hstemhm(self, index): + T2WidthExtractor.op_hstemhm(self, index) + self.processHint(index) + + def op_vstemhm(self, index): + T2WidthExtractor.op_vstemhm(self, index) + self.processHint(index) + + def op_hintmask(self, index): + rv = T2WidthExtractor.op_hintmask(self, index) + self.processHintmask(index) + return rv + + def op_cntrmask(self, index): + rv = T2WidthExtractor.op_cntrmask(self, index) + self.processHintmask(index) + return rv + + def processHintmask(self, index): + cs = self.callingStack[-1] + hints = cs._hints + hints.has_hintmask = True + if hints.status != 2: + # Check from last_check, see if we may be an implicit vstem + for i in range(hints.last_checked, index - 1): + if isinstance(cs.program[i], str): + hints.status = 2 + break + else: + # We are an implicit vstem + hints.has_hint = True + hints.last_hint = index + 1 + hints.status = 0 + hints.last_checked = index + 1 + + def processHint(self, index): + cs = self.callingStack[-1] + hints = cs._hints + hints.has_hint = True + hints.last_hint = index + hints.last_checked = index + + def processSubr(self, index, subr): + cs = self.callingStack[-1] + hints = cs._hints + subr_hints = subr._hints + + # Check from last_check, make sure we didn't have + # any operators. + if hints.status != 2: + for i in range(hints.last_checked, index - 1): + if isinstance(cs.program[i], str): + hints.status = 2 + break + hints.last_checked = index + + if hints.status != 2: + if subr_hints.has_hint: + hints.has_hint = True + + # Decide where to chop off from + if subr_hints.status == 0: + hints.last_hint = index + else: + hints.last_hint = index - 2 # Leave the subr call in + + elif subr_hints.status == 0: + hints.deletions.append(index) + + hints.status = max(hints.status, subr_hints.status) + + +def _cs_subset_subroutines(charstring, subrs, gsubrs): + p = charstring.program + for i in range(1, len(p)): + if p[i] == "callsubr": + assert isinstance(p[i - 1], int) + p[i - 1] = subrs._used.index(p[i - 1] + subrs._old_bias) - subrs._new_bias + elif p[i] == "callgsubr": + assert isinstance(p[i - 1], int) + p[i - 1] = ( + gsubrs._used.index(p[i - 1] + gsubrs._old_bias) - gsubrs._new_bias + ) + + +def _cs_drop_hints(charstring): + hints = charstring._hints + + if hints.deletions: + p = charstring.program + for idx in reversed(hints.deletions): + del p[idx - 2 : idx] + + if hints.has_hint: + assert not hints.deletions or hints.last_hint <= hints.deletions[0] + charstring.program = charstring.program[hints.last_hint :] + if not charstring.program: + # TODO CFF2 no need for endchar. + charstring.program.append("endchar") + if hasattr(charstring, "width"): + # Insert width back if needed + if charstring.width != charstring.private.defaultWidthX: + # For CFF2 charstrings, this should never happen + assert ( + charstring.private.defaultWidthX is not None + ), "CFF2 CharStrings must not have an initial width value" + charstring.program.insert( + 0, charstring.width - charstring.private.nominalWidthX + ) + + if hints.has_hintmask: + i = 0 + p = charstring.program + while i < len(p): + if p[i] in ["hintmask", "cntrmask"]: + assert i + 1 <= len(p) + del p[i : i + 2] + continue + i += 1 + + assert len(charstring.program) + + del charstring._hints + + +def remove_hints(cff, *, removeUnusedSubrs: bool = True): + for fontname in cff.keys(): + font = cff[fontname] + cs = font.CharStrings + # This can be tricky, but doesn't have to. What we do is: + # + # - Run all used glyph charstrings and recurse into subroutines, + # - For each charstring (including subroutines), if it has any + # of the hint stem operators, we mark it as such. + # Upon returning, for each charstring we note all the + # subroutine calls it makes that (recursively) contain a stem, + # - Dropping hinting then consists of the following two ops: + # * Drop the piece of the program in each charstring before the + # last call to a stem op or a stem-calling subroutine, + # * Drop all hintmask operations. + # - It's trickier... A hintmask right after hints and a few numbers + # will act as an implicit vstemhm. As such, we track whether + # we have seen any non-hint operators so far and do the right + # thing, recursively... Good luck understanding that :( + css = set() + for c in cs.values(): + c.decompile() + subrs = getattr(c.private, "Subrs", []) + decompiler = _DehintingT2Decompiler( + css, + subrs, + c.globalSubrs, + c.private.nominalWidthX, + c.private.defaultWidthX, + c.private, + ) + decompiler.execute(c) + c.width = decompiler.width + for charstring in css: + _cs_drop_hints(charstring) + del css + + # Drop font-wide hinting values + all_privs = [] + if hasattr(font, "FDArray"): + all_privs.extend(fd.Private for fd in font.FDArray) + else: + all_privs.append(font.Private) + for priv in all_privs: + for k in [ + "BlueValues", + "OtherBlues", + "FamilyBlues", + "FamilyOtherBlues", + "BlueScale", + "BlueShift", + "BlueFuzz", + "StemSnapH", + "StemSnapV", + "StdHW", + "StdVW", + "ForceBold", + "LanguageGroup", + "ExpansionFactor", + ]: + if hasattr(priv, k): + setattr(priv, k, None) + if removeUnusedSubrs: + remove_unused_subroutines(cff) + + +def _pd_delete_empty_subrs(private_dict): + if hasattr(private_dict, "Subrs") and not private_dict.Subrs: + if "Subrs" in private_dict.rawDict: + del private_dict.rawDict["Subrs"] + del private_dict.Subrs + + +def remove_unused_subroutines(cff): + for fontname in cff.keys(): + font = cff[fontname] + cs = font.CharStrings + # Renumber subroutines to remove unused ones + + # Mark all used subroutines + for c in cs.values(): + subrs = getattr(c.private, "Subrs", []) + decompiler = _MarkingT2Decompiler(subrs, c.globalSubrs, c.private) + decompiler.execute(c) + + all_subrs = [font.GlobalSubrs] + if hasattr(font, "FDArray"): + all_subrs.extend( + fd.Private.Subrs + for fd in font.FDArray + if hasattr(fd.Private, "Subrs") and fd.Private.Subrs + ) + elif hasattr(font.Private, "Subrs") and font.Private.Subrs: + all_subrs.append(font.Private.Subrs) + + subrs = set(subrs) # Remove duplicates + + # Prepare + for subrs in all_subrs: + if not hasattr(subrs, "_used"): + subrs._used = set() + subrs._used = _uniq_sort(subrs._used) + subrs._old_bias = calcSubrBias(subrs) + subrs._new_bias = calcSubrBias(subrs._used) + + # Renumber glyph charstrings + for c in cs.values(): + subrs = getattr(c.private, "Subrs", None) + _cs_subset_subroutines(c, subrs, font.GlobalSubrs) + + # Renumber subroutines themselves + for subrs in all_subrs: + if subrs == font.GlobalSubrs: + if not hasattr(font, "FDArray") and hasattr(font.Private, "Subrs"): + local_subrs = font.Private.Subrs + elif ( + hasattr(font, "FDArray") + and len(font.FDArray) == 1 + and hasattr(font.FDArray[0].Private, "Subrs") + ): + # Technically we shouldn't do this. But I've run into fonts that do it. + local_subrs = font.FDArray[0].Private.Subrs + else: + local_subrs = None + else: + local_subrs = subrs + + subrs.items = [subrs.items[i] for i in subrs._used] + if hasattr(subrs, "file"): + del subrs.file + if hasattr(subrs, "offsets"): + del subrs.offsets + + for subr in subrs.items: + _cs_subset_subroutines(subr, local_subrs, font.GlobalSubrs) + + # Delete local SubrsIndex if empty + if hasattr(font, "FDArray"): + for fd in font.FDArray: + _pd_delete_empty_subrs(fd.Private) + else: + _pd_delete_empty_subrs(font.Private) + + # Cleanup + for subrs in all_subrs: + del subrs._used, subrs._old_bias, subrs._new_bias diff --git a/.venv/lib/python3.12/site-packages/fontTools/cffLib/width.py b/.venv/lib/python3.12/site-packages/fontTools/cffLib/width.py new file mode 100644 index 0000000..78ff27e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cffLib/width.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- + +"""T2CharString glyph width optimizer. + +CFF glyphs whose width equals the CFF Private dictionary's ``defaultWidthX`` +value do not need to specify their width in their charstring, saving bytes. +This module determines the optimum ``defaultWidthX`` and ``nominalWidthX`` +values for a font, when provided with a list of glyph widths.""" + +from fontTools.ttLib import TTFont +from collections import defaultdict +from operator import add +from functools import reduce + + +__all__ = ["optimizeWidths", "main"] + + +class missingdict(dict): + def __init__(self, missing_func): + self.missing_func = missing_func + + def __missing__(self, v): + return self.missing_func(v) + + +def cumSum(f, op=add, start=0, decreasing=False): + keys = sorted(f.keys()) + minx, maxx = keys[0], keys[-1] + + total = reduce(op, f.values(), start) + + if decreasing: + missing = lambda x: start if x > maxx else total + domain = range(maxx, minx - 1, -1) + else: + missing = lambda x: start if x < minx else total + domain = range(minx, maxx + 1) + + out = missingdict(missing) + + v = start + for x in domain: + v = op(v, f[x]) + out[x] = v + + return out + + +def byteCost(widths, default, nominal): + if not hasattr(widths, "items"): + d = defaultdict(int) + for w in widths: + d[w] += 1 + widths = d + + cost = 0 + for w, freq in widths.items(): + if w == default: + continue + diff = abs(w - nominal) + if diff <= 107: + cost += freq + elif diff <= 1131: + cost += freq * 2 + else: + cost += freq * 5 + return cost + + +def optimizeWidthsBruteforce(widths): + """Bruteforce version. Veeeeeeeeeeeeeeeeery slow. Only works for smallests of fonts.""" + + d = defaultdict(int) + for w in widths: + d[w] += 1 + + # Maximum number of bytes using default can possibly save + maxDefaultAdvantage = 5 * max(d.values()) + + minw, maxw = min(widths), max(widths) + domain = list(range(minw, maxw + 1)) + + bestCostWithoutDefault = min(byteCost(widths, None, nominal) for nominal in domain) + + bestCost = len(widths) * 5 + 1 + for nominal in domain: + if byteCost(widths, None, nominal) > bestCost + maxDefaultAdvantage: + continue + for default in domain: + cost = byteCost(widths, default, nominal) + if cost < bestCost: + bestCost = cost + bestDefault = default + bestNominal = nominal + + return bestDefault, bestNominal + + +def optimizeWidths(widths): + """Given a list of glyph widths, or dictionary mapping glyph width to number of + glyphs having that, returns a tuple of best CFF default and nominal glyph widths. + + This algorithm is linear in UPEM+numGlyphs.""" + + if not hasattr(widths, "items"): + d = defaultdict(int) + for w in widths: + d[w] += 1 + widths = d + + keys = sorted(widths.keys()) + minw, maxw = keys[0], keys[-1] + domain = list(range(minw, maxw + 1)) + + # Cumulative sum/max forward/backward. + cumFrqU = cumSum(widths, op=add) + cumMaxU = cumSum(widths, op=max) + cumFrqD = cumSum(widths, op=add, decreasing=True) + cumMaxD = cumSum(widths, op=max, decreasing=True) + + # Cost per nominal choice, without default consideration. + nomnCostU = missingdict( + lambda x: cumFrqU[x] + cumFrqU[x - 108] + cumFrqU[x - 1132] * 3 + ) + nomnCostD = missingdict( + lambda x: cumFrqD[x] + cumFrqD[x + 108] + cumFrqD[x + 1132] * 3 + ) + nomnCost = missingdict(lambda x: nomnCostU[x] + nomnCostD[x] - widths[x]) + + # Cost-saving per nominal choice, by best default choice. + dfltCostU = missingdict( + lambda x: max(cumMaxU[x], cumMaxU[x - 108] * 2, cumMaxU[x - 1132] * 5) + ) + dfltCostD = missingdict( + lambda x: max(cumMaxD[x], cumMaxD[x + 108] * 2, cumMaxD[x + 1132] * 5) + ) + dfltCost = missingdict(lambda x: max(dfltCostU[x], dfltCostD[x])) + + # Combined cost per nominal choice. + bestCost = missingdict(lambda x: nomnCost[x] - dfltCost[x]) + + # Best nominal. + nominal = min(domain, key=lambda x: bestCost[x]) + + # Work back the best default. + bestC = bestCost[nominal] + dfltC = nomnCost[nominal] - bestCost[nominal] + ends = [] + if dfltC == dfltCostU[nominal]: + starts = [nominal, nominal - 108, nominal - 1132] + for start in starts: + while cumMaxU[start] and cumMaxU[start] == cumMaxU[start - 1]: + start -= 1 + ends.append(start) + else: + starts = [nominal, nominal + 108, nominal + 1132] + for start in starts: + while cumMaxD[start] and cumMaxD[start] == cumMaxD[start + 1]: + start += 1 + ends.append(start) + default = min(ends, key=lambda default: byteCost(widths, default, nominal)) + + return default, nominal + + +def main(args=None): + """Calculate optimum defaultWidthX/nominalWidthX values""" + + import argparse + + parser = argparse.ArgumentParser( + "fonttools cffLib.width", + description=main.__doc__, + ) + parser.add_argument( + "inputs", metavar="FILE", type=str, nargs="+", help="Input TTF files" + ) + parser.add_argument( + "-b", + "--brute-force", + dest="brute", + action="store_true", + help="Use brute-force approach (VERY slow)", + ) + + args = parser.parse_args(args) + + for fontfile in args.inputs: + font = TTFont(fontfile) + hmtx = font["hmtx"] + widths = [m[0] for m in hmtx.metrics.values()] + if args.brute: + default, nominal = optimizeWidthsBruteforce(widths) + else: + default, nominal = optimizeWidths(widths) + print( + "glyphs=%d default=%d nominal=%d byteCost=%d" + % (len(widths), default, nominal, byteCost(widths, default, nominal)) + ) + + +if __name__ == "__main__": + import sys + + if len(sys.argv) == 1: + import doctest + + sys.exit(doctest.testmod().failed) + main() diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..bf6e58b Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/builder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/builder.cpython-312.pyc new file mode 100644 index 0000000..72391b7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/builder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/errors.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000..1867654 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/errors.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/geometry.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/geometry.cpython-312.pyc new file mode 100644 index 0000000..1146cc3 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/geometry.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/table_builder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/table_builder.cpython-312.pyc new file mode 100644 index 0000000..804cce6 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/table_builder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/unbuilder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/unbuilder.cpython-312.pyc new file mode 100644 index 0000000..fae9399 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/colorLib/__pycache__/unbuilder.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/builder.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/builder.py new file mode 100644 index 0000000..6e45e7a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/colorLib/builder.py @@ -0,0 +1,664 @@ +""" +colorLib.builder: Build COLR/CPAL tables from scratch + +""" + +import collections +import copy +import enum +from functools import partial +from math import ceil, log +from typing import ( + Any, + Dict, + Generator, + Iterable, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, +) +from fontTools.misc.arrayTools import intRect +from fontTools.misc.fixedTools import fixedToFloat +from fontTools.misc.treeTools import build_n_ary_tree +from fontTools.ttLib.tables import C_O_L_R_ +from fontTools.ttLib.tables import C_P_A_L_ +from fontTools.ttLib.tables import _n_a_m_e +from fontTools.ttLib.tables import otTables as ot +from fontTools.ttLib.tables.otTables import ExtendMode, CompositeMode +from .errors import ColorLibError +from .geometry import round_start_circle_stable_containment +from .table_builder import BuildCallback, TableBuilder + + +# TODO move type aliases to colorLib.types? +T = TypeVar("T") +_Kwargs = Mapping[str, Any] +_PaintInput = Union[int, _Kwargs, ot.Paint, Tuple[str, "_PaintInput"]] +_PaintInputList = Sequence[_PaintInput] +_ColorGlyphsDict = Dict[str, Union[_PaintInputList, _PaintInput]] +_ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]] +_ClipBoxInput = Union[ + Tuple[int, int, int, int, int], # format 1, variable + Tuple[int, int, int, int], # format 0, non-variable + ot.ClipBox, +] + + +MAX_PAINT_COLR_LAYER_COUNT = 255 +_DEFAULT_ALPHA = 1.0 +_MAX_REUSE_LEN = 32 + + +def _beforeBuildPaintRadialGradient(paint, source): + x0 = source["x0"] + y0 = source["y0"] + r0 = source["r0"] + x1 = source["x1"] + y1 = source["y1"] + r1 = source["r1"] + + # TODO apparently no builder_test confirms this works (?) + + # avoid abrupt change after rounding when c0 is near c1's perimeter + c = round_start_circle_stable_containment((x0, y0), r0, (x1, y1), r1) + x0, y0 = c.centre + r0 = c.radius + + # update source to ensure paint is built with corrected values + source["x0"] = x0 + source["y0"] = y0 + source["r0"] = r0 + source["x1"] = x1 + source["y1"] = y1 + source["r1"] = r1 + + return paint, source + + +def _defaultColorStop(): + colorStop = ot.ColorStop() + colorStop.Alpha = _DEFAULT_ALPHA + return colorStop + + +def _defaultVarColorStop(): + colorStop = ot.VarColorStop() + colorStop.Alpha = _DEFAULT_ALPHA + return colorStop + + +def _defaultColorLine(): + colorLine = ot.ColorLine() + colorLine.Extend = ExtendMode.PAD + return colorLine + + +def _defaultVarColorLine(): + colorLine = ot.VarColorLine() + colorLine.Extend = ExtendMode.PAD + return colorLine + + +def _defaultPaintSolid(): + paint = ot.Paint() + paint.Alpha = _DEFAULT_ALPHA + return paint + + +def _buildPaintCallbacks(): + return { + ( + BuildCallback.BEFORE_BUILD, + ot.Paint, + ot.PaintFormat.PaintRadialGradient, + ): _beforeBuildPaintRadialGradient, + ( + BuildCallback.BEFORE_BUILD, + ot.Paint, + ot.PaintFormat.PaintVarRadialGradient, + ): _beforeBuildPaintRadialGradient, + (BuildCallback.CREATE_DEFAULT, ot.ColorStop): _defaultColorStop, + (BuildCallback.CREATE_DEFAULT, ot.VarColorStop): _defaultVarColorStop, + (BuildCallback.CREATE_DEFAULT, ot.ColorLine): _defaultColorLine, + (BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine, + ( + BuildCallback.CREATE_DEFAULT, + ot.Paint, + ot.PaintFormat.PaintSolid, + ): _defaultPaintSolid, + ( + BuildCallback.CREATE_DEFAULT, + ot.Paint, + ot.PaintFormat.PaintVarSolid, + ): _defaultPaintSolid, + } + + +def populateCOLRv0( + table: ot.COLR, + colorGlyphsV0: _ColorGlyphsV0Dict, + glyphMap: Optional[Mapping[str, int]] = None, +): + """Build v0 color layers and add to existing COLR table. + + Args: + table: a raw ``otTables.COLR()`` object (not ttLib's ``table_C_O_L_R_``). + colorGlyphsV0: map of base glyph names to lists of (layer glyph names, + color palette index) tuples. Can be empty. + glyphMap: a map from glyph names to glyph indices, as returned from + ``TTFont.getReverseGlyphMap()``, to optionally sort base records by GID. + """ + if glyphMap is not None: + colorGlyphItems = sorted( + colorGlyphsV0.items(), key=lambda item: glyphMap[item[0]] + ) + else: + colorGlyphItems = colorGlyphsV0.items() + baseGlyphRecords = [] + layerRecords = [] + for baseGlyph, layers in colorGlyphItems: + baseRec = ot.BaseGlyphRecord() + baseRec.BaseGlyph = baseGlyph + baseRec.FirstLayerIndex = len(layerRecords) + baseRec.NumLayers = len(layers) + baseGlyphRecords.append(baseRec) + + for layerGlyph, paletteIndex in layers: + layerRec = ot.LayerRecord() + layerRec.LayerGlyph = layerGlyph + layerRec.PaletteIndex = paletteIndex + layerRecords.append(layerRec) + + table.BaseGlyphRecordArray = table.LayerRecordArray = None + if baseGlyphRecords: + table.BaseGlyphRecordArray = ot.BaseGlyphRecordArray() + table.BaseGlyphRecordArray.BaseGlyphRecord = baseGlyphRecords + if layerRecords: + table.LayerRecordArray = ot.LayerRecordArray() + table.LayerRecordArray.LayerRecord = layerRecords + table.BaseGlyphRecordCount = len(baseGlyphRecords) + table.LayerRecordCount = len(layerRecords) + + +def buildCOLR( + colorGlyphs: _ColorGlyphsDict, + version: Optional[int] = None, + *, + glyphMap: Optional[Mapping[str, int]] = None, + varStore: Optional[ot.VarStore] = None, + varIndexMap: Optional[ot.DeltaSetIndexMap] = None, + clipBoxes: Optional[Dict[str, _ClipBoxInput]] = None, + allowLayerReuse: bool = True, +) -> C_O_L_R_.table_C_O_L_R_: + """Build COLR table from color layers mapping. + + Args: + + colorGlyphs: map of base glyph name to, either list of (layer glyph name, + color palette index) tuples for COLRv0; or a single ``Paint`` (dict) or + list of ``Paint`` for COLRv1. + version: the version of COLR table. If None, the version is determined + by the presence of COLRv1 paints or variation data (varStore), which + require version 1; otherwise, if all base glyphs use only simple color + layers, version 0 is used. + glyphMap: a map from glyph names to glyph indices, as returned from + TTFont.getReverseGlyphMap(), to optionally sort base records by GID. + varStore: Optional ItemVarationStore for deltas associated with v1 layer. + varIndexMap: Optional DeltaSetIndexMap for deltas associated with v1 layer. + clipBoxes: Optional map of base glyph name to clip box 4- or 5-tuples: + (xMin, yMin, xMax, yMax) or (xMin, yMin, xMax, yMax, varIndexBase). + + Returns: + A new COLR table. + """ + self = C_O_L_R_.table_C_O_L_R_() + + if varStore is not None and version == 0: + raise ValueError("Can't add VarStore to COLRv0") + + if version in (None, 0) and not varStore: + # split color glyphs into v0 and v1 and encode separately + colorGlyphsV0, colorGlyphsV1 = _split_color_glyphs_by_version(colorGlyphs) + if version == 0 and colorGlyphsV1: + raise ValueError("Can't encode COLRv1 glyphs in COLRv0") + else: + # unless explicitly requested for v1 or have variations, in which case + # we encode all color glyph as v1 + colorGlyphsV0, colorGlyphsV1 = {}, colorGlyphs + + colr = ot.COLR() + + populateCOLRv0(colr, colorGlyphsV0, glyphMap) + + colr.LayerList, colr.BaseGlyphList = buildColrV1( + colorGlyphsV1, + glyphMap, + allowLayerReuse=allowLayerReuse, + ) + + if version is None: + version = 1 if (varStore or colorGlyphsV1) else 0 + elif version not in (0, 1): + raise NotImplementedError(version) + self.version = colr.Version = version + + if version == 0: + self.ColorLayers = self._decompileColorLayersV0(colr) + else: + colr.ClipList = buildClipList(clipBoxes) if clipBoxes else None + colr.VarIndexMap = varIndexMap + colr.VarStore = varStore + self.table = colr + + return self + + +def buildClipList(clipBoxes: Dict[str, _ClipBoxInput]) -> ot.ClipList: + clipList = ot.ClipList() + clipList.Format = 1 + clipList.clips = {name: buildClipBox(box) for name, box in clipBoxes.items()} + return clipList + + +def buildClipBox(clipBox: _ClipBoxInput) -> ot.ClipBox: + if isinstance(clipBox, ot.ClipBox): + return clipBox + n = len(clipBox) + clip = ot.ClipBox() + if n not in (4, 5): + raise ValueError(f"Invalid ClipBox: expected 4 or 5 values, found {n}") + clip.xMin, clip.yMin, clip.xMax, clip.yMax = intRect(clipBox[:4]) + clip.Format = int(n == 5) + 1 + if n == 5: + clip.VarIndexBase = int(clipBox[4]) + return clip + + +class ColorPaletteType(enum.IntFlag): + USABLE_WITH_LIGHT_BACKGROUND = 0x0001 + USABLE_WITH_DARK_BACKGROUND = 0x0002 + + @classmethod + def _missing_(cls, value): + # enforce reserved bits + if isinstance(value, int) and (value < 0 or value & 0xFFFC != 0): + raise ValueError(f"{value} is not a valid {cls.__name__}") + return super()._missing_(value) + + +# None, 'abc' or {'en': 'abc', 'de': 'xyz'} +_OptionalLocalizedString = Union[None, str, Dict[str, str]] + + +def buildPaletteLabels( + labels: Iterable[_OptionalLocalizedString], nameTable: _n_a_m_e.table__n_a_m_e +) -> List[Optional[int]]: + return [ + ( + nameTable.addMultilingualName(l, mac=False) + if isinstance(l, dict) + else ( + C_P_A_L_.table_C_P_A_L_.NO_NAME_ID + if l is None + else nameTable.addMultilingualName({"en": l}, mac=False) + ) + ) + for l in labels + ] + + +def buildCPAL( + palettes: Sequence[Sequence[Tuple[float, float, float, float]]], + paletteTypes: Optional[Sequence[ColorPaletteType]] = None, + paletteLabels: Optional[Sequence[_OptionalLocalizedString]] = None, + paletteEntryLabels: Optional[Sequence[_OptionalLocalizedString]] = None, + nameTable: Optional[_n_a_m_e.table__n_a_m_e] = None, +) -> C_P_A_L_.table_C_P_A_L_: + """Build CPAL table from list of color palettes. + + Args: + palettes: list of lists of colors encoded as tuples of (R, G, B, A) floats + in the range [0..1]. + paletteTypes: optional list of ColorPaletteType, one for each palette. + paletteLabels: optional list of palette labels. Each lable can be either: + None (no label), a string (for for default English labels), or a + localized string (as a dict keyed with BCP47 language codes). + paletteEntryLabels: optional list of palette entry labels, one for each + palette entry (see paletteLabels). + nameTable: optional name table where to store palette and palette entry + labels. Required if either paletteLabels or paletteEntryLabels is set. + + Return: + A new CPAL v0 or v1 table, if custom palette types or labels are specified. + """ + if len({len(p) for p in palettes}) != 1: + raise ColorLibError("color palettes have different lengths") + + if (paletteLabels or paletteEntryLabels) and not nameTable: + raise TypeError( + "nameTable is required if palette or palette entries have labels" + ) + + cpal = C_P_A_L_.table_C_P_A_L_() + cpal.numPaletteEntries = len(palettes[0]) + + cpal.palettes = [] + for i, palette in enumerate(palettes): + colors = [] + for j, color in enumerate(palette): + if not isinstance(color, tuple) or len(color) != 4: + raise ColorLibError( + f"In palette[{i}][{j}]: expected (R, G, B, A) tuple, got {color!r}" + ) + if any(v > 1 or v < 0 for v in color): + raise ColorLibError( + f"palette[{i}][{j}] has invalid out-of-range [0..1] color: {color!r}" + ) + # input colors are RGBA, CPAL encodes them as BGRA + red, green, blue, alpha = color + colors.append( + C_P_A_L_.Color(*(round(v * 255) for v in (blue, green, red, alpha))) + ) + cpal.palettes.append(colors) + + if any(v is not None for v in (paletteTypes, paletteLabels, paletteEntryLabels)): + cpal.version = 1 + + if paletteTypes is not None: + if len(paletteTypes) != len(palettes): + raise ColorLibError( + f"Expected {len(palettes)} paletteTypes, got {len(paletteTypes)}" + ) + cpal.paletteTypes = [ColorPaletteType(t).value for t in paletteTypes] + else: + cpal.paletteTypes = [C_P_A_L_.table_C_P_A_L_.DEFAULT_PALETTE_TYPE] * len( + palettes + ) + + if paletteLabels is not None: + if len(paletteLabels) != len(palettes): + raise ColorLibError( + f"Expected {len(palettes)} paletteLabels, got {len(paletteLabels)}" + ) + cpal.paletteLabels = buildPaletteLabels(paletteLabels, nameTable) + else: + cpal.paletteLabels = [C_P_A_L_.table_C_P_A_L_.NO_NAME_ID] * len(palettes) + + if paletteEntryLabels is not None: + if len(paletteEntryLabels) != cpal.numPaletteEntries: + raise ColorLibError( + f"Expected {cpal.numPaletteEntries} paletteEntryLabels, " + f"got {len(paletteEntryLabels)}" + ) + cpal.paletteEntryLabels = buildPaletteLabels(paletteEntryLabels, nameTable) + else: + cpal.paletteEntryLabels = [ + C_P_A_L_.table_C_P_A_L_.NO_NAME_ID + ] * cpal.numPaletteEntries + else: + cpal.version = 0 + + return cpal + + +# COLR v1 tables +# See draft proposal at: https://github.com/googlefonts/colr-gradients-spec + + +def _is_colrv0_layer(layer: Any) -> bool: + # Consider as COLRv0 layer any sequence of length 2 (be it tuple or list) in which + # the first element is a str (the layerGlyph) and the second element is an int + # (CPAL paletteIndex). + # https://github.com/googlefonts/ufo2ft/issues/426 + try: + layerGlyph, paletteIndex = layer + except (TypeError, ValueError): + return False + else: + return isinstance(layerGlyph, str) and isinstance(paletteIndex, int) + + +def _split_color_glyphs_by_version( + colorGlyphs: _ColorGlyphsDict, +) -> Tuple[_ColorGlyphsV0Dict, _ColorGlyphsDict]: + colorGlyphsV0 = {} + colorGlyphsV1 = {} + for baseGlyph, layers in colorGlyphs.items(): + if all(_is_colrv0_layer(l) for l in layers): + colorGlyphsV0[baseGlyph] = layers + else: + colorGlyphsV1[baseGlyph] = layers + + # sanity check + assert set(colorGlyphs) == (set(colorGlyphsV0) | set(colorGlyphsV1)) + + return colorGlyphsV0, colorGlyphsV1 + + +def _reuse_ranges(num_layers: int) -> Generator[Tuple[int, int], None, None]: + # TODO feels like something itertools might have already + for lbound in range(num_layers): + # Reuse of very large #s of layers is relatively unlikely + # +2: we want sequences of at least 2 + # otData handles single-record duplication + for ubound in range( + lbound + 2, min(num_layers + 1, lbound + 2 + _MAX_REUSE_LEN) + ): + yield (lbound, ubound) + + +class LayerReuseCache: + reusePool: Mapping[Tuple[Any, ...], int] + tuples: Mapping[int, Tuple[Any, ...]] + keepAlive: List[ot.Paint] # we need id to remain valid + + def __init__(self): + self.reusePool = {} + self.tuples = {} + self.keepAlive = [] + + def _paint_tuple(self, paint: ot.Paint): + # start simple, who even cares about cyclic graphs or interesting field types + def _tuple_safe(value): + if isinstance(value, enum.Enum): + return value + elif hasattr(value, "__dict__"): + return tuple( + (k, _tuple_safe(v)) for k, v in sorted(value.__dict__.items()) + ) + elif isinstance(value, collections.abc.MutableSequence): + return tuple(_tuple_safe(e) for e in value) + return value + + # Cache the tuples for individual Paint instead of the whole sequence + # because the seq could be a transient slice + result = self.tuples.get(id(paint), None) + if result is None: + result = _tuple_safe(paint) + self.tuples[id(paint)] = result + self.keepAlive.append(paint) + return result + + def _as_tuple(self, paints: Sequence[ot.Paint]) -> Tuple[Any, ...]: + return tuple(self._paint_tuple(p) for p in paints) + + def try_reuse(self, layers: List[ot.Paint]) -> List[ot.Paint]: + found_reuse = True + while found_reuse: + found_reuse = False + + ranges = sorted( + _reuse_ranges(len(layers)), + key=lambda t: (t[1] - t[0], t[1], t[0]), + reverse=True, + ) + for lbound, ubound in ranges: + reuse_lbound = self.reusePool.get( + self._as_tuple(layers[lbound:ubound]), -1 + ) + if reuse_lbound == -1: + continue + new_slice = ot.Paint() + new_slice.Format = int(ot.PaintFormat.PaintColrLayers) + new_slice.NumLayers = ubound - lbound + new_slice.FirstLayerIndex = reuse_lbound + layers = layers[:lbound] + [new_slice] + layers[ubound:] + found_reuse = True + break + return layers + + def add(self, layers: List[ot.Paint], first_layer_index: int): + for lbound, ubound in _reuse_ranges(len(layers)): + self.reusePool[self._as_tuple(layers[lbound:ubound])] = ( + lbound + first_layer_index + ) + + +class LayerListBuilder: + layers: List[ot.Paint] + cache: LayerReuseCache + allowLayerReuse: bool + + def __init__(self, *, allowLayerReuse=True): + self.layers = [] + if allowLayerReuse: + self.cache = LayerReuseCache() + else: + self.cache = None + + # We need to intercept construction of PaintColrLayers + callbacks = _buildPaintCallbacks() + callbacks[ + ( + BuildCallback.BEFORE_BUILD, + ot.Paint, + ot.PaintFormat.PaintColrLayers, + ) + ] = self._beforeBuildPaintColrLayers + self.tableBuilder = TableBuilder(callbacks) + + # COLR layers is unusual in that it modifies shared state + # so we need a callback into an object + def _beforeBuildPaintColrLayers(self, dest, source): + # Sketchy gymnastics: a sequence input will have dropped it's layers + # into NumLayers; get it back + if isinstance(source.get("NumLayers", None), collections.abc.Sequence): + layers = source["NumLayers"] + else: + layers = source["Layers"] + + # Convert maps seqs or whatever into typed objects + layers = [self.buildPaint(l) for l in layers] + + # No reason to have a colr layers with just one entry + if len(layers) == 1: + return layers[0], {} + + if self.cache is not None: + # Look for reuse, with preference to longer sequences + # This may make the layer list smaller + layers = self.cache.try_reuse(layers) + + # The layer list is now final; if it's too big we need to tree it + is_tree = len(layers) > MAX_PAINT_COLR_LAYER_COUNT + layers = build_n_ary_tree(layers, n=MAX_PAINT_COLR_LAYER_COUNT) + + # We now have a tree of sequences with Paint leaves. + # Convert the sequences into PaintColrLayers. + def listToColrLayers(layer): + if isinstance(layer, collections.abc.Sequence): + return self.buildPaint( + { + "Format": ot.PaintFormat.PaintColrLayers, + "Layers": [listToColrLayers(l) for l in layer], + } + ) + return layer + + layers = [listToColrLayers(l) for l in layers] + + # No reason to have a colr layers with just one entry + if len(layers) == 1: + return layers[0], {} + + paint = ot.Paint() + paint.Format = int(ot.PaintFormat.PaintColrLayers) + paint.NumLayers = len(layers) + paint.FirstLayerIndex = len(self.layers) + self.layers.extend(layers) + + # Register our parts for reuse provided we aren't a tree + # If we are a tree the leaves registered for reuse and that will suffice + if self.cache is not None and not is_tree: + self.cache.add(layers, paint.FirstLayerIndex) + + # we've fully built dest; empty source prevents generalized build from kicking in + return paint, {} + + def buildPaint(self, paint: _PaintInput) -> ot.Paint: + return self.tableBuilder.build(ot.Paint, paint) + + def build(self) -> Optional[ot.LayerList]: + if not self.layers: + return None + layers = ot.LayerList() + layers.LayerCount = len(self.layers) + layers.Paint = self.layers + return layers + + +def buildBaseGlyphPaintRecord( + baseGlyph: str, layerBuilder: LayerListBuilder, paint: _PaintInput +) -> ot.BaseGlyphList: + self = ot.BaseGlyphPaintRecord() + self.BaseGlyph = baseGlyph + self.Paint = layerBuilder.buildPaint(paint) + return self + + +def _format_glyph_errors(errors: Mapping[str, Exception]) -> str: + lines = [] + for baseGlyph, error in sorted(errors.items()): + lines.append(f" {baseGlyph} => {type(error).__name__}: {error}") + return "\n".join(lines) + + +def buildColrV1( + colorGlyphs: _ColorGlyphsDict, + glyphMap: Optional[Mapping[str, int]] = None, + *, + allowLayerReuse: bool = True, +) -> Tuple[Optional[ot.LayerList], ot.BaseGlyphList]: + if glyphMap is not None: + colorGlyphItems = sorted( + colorGlyphs.items(), key=lambda item: glyphMap[item[0]] + ) + else: + colorGlyphItems = colorGlyphs.items() + + errors = {} + baseGlyphs = [] + layerBuilder = LayerListBuilder(allowLayerReuse=allowLayerReuse) + for baseGlyph, paint in colorGlyphItems: + try: + baseGlyphs.append(buildBaseGlyphPaintRecord(baseGlyph, layerBuilder, paint)) + + except (ColorLibError, OverflowError, ValueError, TypeError) as e: + errors[baseGlyph] = e + + if errors: + failed_glyphs = _format_glyph_errors(errors) + exc = ColorLibError(f"Failed to build BaseGlyphList:\n{failed_glyphs}") + exc.errors = errors + raise exc from next(iter(errors.values())) + + layers = layerBuilder.build() + glyphs = ot.BaseGlyphList() + glyphs.BaseGlyphCount = len(baseGlyphs) + glyphs.BaseGlyphPaintRecord = baseGlyphs + return (layers, glyphs) diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/errors.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/errors.py new file mode 100644 index 0000000..18cbebb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/colorLib/errors.py @@ -0,0 +1,2 @@ +class ColorLibError(Exception): + pass diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/geometry.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/geometry.py new file mode 100644 index 0000000..1ce161b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/colorLib/geometry.py @@ -0,0 +1,143 @@ +"""Helpers for manipulating 2D points and vectors in COLR table.""" + +from math import copysign, cos, hypot, isclose, pi +from fontTools.misc.roundTools import otRound + + +def _vector_between(origin, target): + return (target[0] - origin[0], target[1] - origin[1]) + + +def _round_point(pt): + return (otRound(pt[0]), otRound(pt[1])) + + +def _unit_vector(vec): + length = hypot(*vec) + if length == 0: + return None + return (vec[0] / length, vec[1] / length) + + +_CIRCLE_INSIDE_TOLERANCE = 1e-4 + + +# The unit vector's X and Y components are respectively +# U = (cos(α), sin(α)) +# where α is the angle between the unit vector and the positive x axis. +_UNIT_VECTOR_THRESHOLD = cos(3 / 8 * pi) # == sin(1/8 * pi) == 0.38268343236508984 + + +def _rounding_offset(direction): + # Return 2-tuple of -/+ 1.0 or 0.0 approximately based on the direction vector. + # We divide the unit circle in 8 equal slices oriented towards the cardinal + # (N, E, S, W) and intermediate (NE, SE, SW, NW) directions. To each slice we + # map one of the possible cases: -1, 0, +1 for either X and Y coordinate. + # E.g. Return (+1.0, -1.0) if unit vector is oriented towards SE, or + # (-1.0, 0.0) if it's pointing West, etc. + uv = _unit_vector(direction) + if not uv: + return (0, 0) + + result = [] + for uv_component in uv: + if -_UNIT_VECTOR_THRESHOLD <= uv_component < _UNIT_VECTOR_THRESHOLD: + # unit vector component near 0: direction almost orthogonal to the + # direction of the current axis, thus keep coordinate unchanged + result.append(0) + else: + # nudge coord by +/- 1.0 in direction of unit vector + result.append(copysign(1.0, uv_component)) + return tuple(result) + + +class Circle: + def __init__(self, centre, radius): + self.centre = centre + self.radius = radius + + def __repr__(self): + return f"Circle(centre={self.centre}, radius={self.radius})" + + def round(self): + return Circle(_round_point(self.centre), otRound(self.radius)) + + def inside(self, outer_circle, tolerance=_CIRCLE_INSIDE_TOLERANCE): + dist = self.radius + hypot(*_vector_between(self.centre, outer_circle.centre)) + return ( + isclose(outer_circle.radius, dist, rel_tol=_CIRCLE_INSIDE_TOLERANCE) + or outer_circle.radius > dist + ) + + def concentric(self, other): + return self.centre == other.centre + + def move(self, dx, dy): + self.centre = (self.centre[0] + dx, self.centre[1] + dy) + + +def round_start_circle_stable_containment(c0, r0, c1, r1): + """Round start circle so that it stays inside/outside end circle after rounding. + + The rounding of circle coordinates to integers may cause an abrupt change + if the start circle c0 is so close to the end circle c1's perimiter that + it ends up falling outside (or inside) as a result of the rounding. + To keep the gradient unchanged, we nudge it in the right direction. + + See: + https://github.com/googlefonts/colr-gradients-spec/issues/204 + https://github.com/googlefonts/picosvg/issues/158 + """ + start, end = Circle(c0, r0), Circle(c1, r1) + + inside_before_round = start.inside(end) + + round_start = start.round() + round_end = end.round() + inside_after_round = round_start.inside(round_end) + + if inside_before_round == inside_after_round: + return round_start + elif inside_after_round: + # start was outside before rounding: we need to push start away from end + direction = _vector_between(round_end.centre, round_start.centre) + radius_delta = +1.0 + else: + # start was inside before rounding: we need to push start towards end + direction = _vector_between(round_start.centre, round_end.centre) + radius_delta = -1.0 + dx, dy = _rounding_offset(direction) + + # At most 2 iterations ought to be enough to converge. Before the loop, we + # know the start circle didn't keep containment after normal rounding; thus + # we continue adjusting by -/+ 1.0 until containment is restored. + # Normal rounding can at most move each coordinates -/+0.5; in the worst case + # both the start and end circle's centres and radii will be rounded in opposite + # directions, e.g. when they move along a 45 degree diagonal: + # c0 = (1.5, 1.5) ===> (2.0, 2.0) + # r0 = 0.5 ===> 1.0 + # c1 = (0.499, 0.499) ===> (0.0, 0.0) + # r1 = 2.499 ===> 2.0 + # In this example, the relative distance between the circles, calculated + # as r1 - (r0 + distance(c0, c1)) is initially 0.57437 (c0 is inside c1), and + # -1.82842 after rounding (c0 is now outside c1). Nudging c0 by -1.0 on both + # x and y axes moves it towards c1 by hypot(-1.0, -1.0) = 1.41421. Two of these + # moves cover twice that distance, which is enough to restore containment. + max_attempts = 2 + for _ in range(max_attempts): + if round_start.concentric(round_end): + # can't move c0 towards c1 (they are the same), so we change the radius + round_start.radius += radius_delta + assert round_start.radius >= 0 + else: + round_start.move(dx, dy) + if inside_before_round == round_start.inside(round_end): + break + else: # likely a bug + raise AssertionError( + f"Rounding circle {start} " + f"{'inside' if inside_before_round else 'outside'} " + f"{end} failed after {max_attempts} attempts!" + ) + + return round_start diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/table_builder.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/table_builder.py new file mode 100644 index 0000000..f1e182c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/colorLib/table_builder.py @@ -0,0 +1,223 @@ +""" +colorLib.table_builder: Generic helper for filling in BaseTable derivatives from tuples and maps and such. + +""" + +import collections +import enum +from fontTools.ttLib.tables.otBase import ( + BaseTable, + FormatSwitchingBaseTable, + UInt8FormatSwitchingBaseTable, +) +from fontTools.ttLib.tables.otConverters import ( + ComputedInt, + SimpleValue, + Struct, + Short, + UInt8, + UShort, + IntValue, + FloatValue, + OptionalValue, +) +from fontTools.misc.roundTools import otRound + + +class BuildCallback(enum.Enum): + """Keyed on (BEFORE_BUILD, class[, Format if available]). + Receives (dest, source). + Should return (dest, source), which can be new objects. + """ + + BEFORE_BUILD = enum.auto() + + """Keyed on (AFTER_BUILD, class[, Format if available]). + Receives (dest). + Should return dest, which can be a new object. + """ + AFTER_BUILD = enum.auto() + + """Keyed on (CREATE_DEFAULT, class[, Format if available]). + Receives no arguments. + Should return a new instance of class. + """ + CREATE_DEFAULT = enum.auto() + + +def _assignable(convertersByName): + return {k: v for k, v in convertersByName.items() if not isinstance(v, ComputedInt)} + + +def _isNonStrSequence(value): + return isinstance(value, collections.abc.Sequence) and not isinstance(value, str) + + +def _split_format(cls, source): + if _isNonStrSequence(source): + assert len(source) > 0, f"{cls} needs at least format from {source}" + fmt, remainder = source[0], source[1:] + elif isinstance(source, collections.abc.Mapping): + assert "Format" in source, f"{cls} needs at least Format from {source}" + remainder = source.copy() + fmt = remainder.pop("Format") + else: + raise ValueError(f"Not sure how to populate {cls} from {source}") + + assert isinstance( + fmt, collections.abc.Hashable + ), f"{cls} Format is not hashable: {fmt!r}" + assert fmt in cls.convertersByName, f"{cls} invalid Format: {fmt!r}" + + return fmt, remainder + + +class TableBuilder: + """ + Helps to populate things derived from BaseTable from maps, tuples, etc. + + A table of lifecycle callbacks may be provided to add logic beyond what is possible + based on otData info for the target class. See BuildCallbacks. + """ + + def __init__(self, callbackTable=None): + if callbackTable is None: + callbackTable = {} + self._callbackTable = callbackTable + + def _convert(self, dest, field, converter, value): + enumClass = getattr(converter, "enumClass", None) + + if enumClass: + if isinstance(value, enumClass): + pass + elif isinstance(value, str): + try: + value = getattr(enumClass, value.upper()) + except AttributeError: + raise ValueError(f"{value} is not a valid {enumClass}") + else: + value = enumClass(value) + + elif isinstance(converter, IntValue): + value = otRound(value) + elif isinstance(converter, FloatValue): + value = float(value) + + elif isinstance(converter, Struct): + if converter.repeat: + if _isNonStrSequence(value): + value = [self.build(converter.tableClass, v) for v in value] + else: + value = [self.build(converter.tableClass, value)] + setattr(dest, converter.repeat, len(value)) + else: + value = self.build(converter.tableClass, value) + elif callable(converter): + value = converter(value) + + setattr(dest, field, value) + + def build(self, cls, source): + assert issubclass(cls, BaseTable) + + if isinstance(source, cls): + return source + + callbackKey = (cls,) + fmt = None + if issubclass(cls, FormatSwitchingBaseTable): + fmt, source = _split_format(cls, source) + callbackKey = (cls, fmt) + + dest = self._callbackTable.get( + (BuildCallback.CREATE_DEFAULT,) + callbackKey, lambda: cls() + )() + assert isinstance(dest, cls) + + convByName = _assignable(cls.convertersByName) + skippedFields = set() + + # For format switchers we need to resolve converters based on format + if issubclass(cls, FormatSwitchingBaseTable): + dest.Format = fmt + convByName = _assignable(convByName[dest.Format]) + skippedFields.add("Format") + + # Convert sequence => mapping so before thunk only has to handle one format + if _isNonStrSequence(source): + # Sequence (typically list or tuple) assumed to match fields in declaration order + assert len(source) <= len( + convByName + ), f"Sequence of {len(source)} too long for {cls}; expected <= {len(convByName)} values" + source = dict(zip(convByName.keys(), source)) + + dest, source = self._callbackTable.get( + (BuildCallback.BEFORE_BUILD,) + callbackKey, lambda d, s: (d, s) + )(dest, source) + + if isinstance(source, collections.abc.Mapping): + for field, value in source.items(): + if field in skippedFields: + continue + converter = convByName.get(field, None) + if not converter: + raise ValueError( + f"Unrecognized field {field} for {cls}; expected one of {sorted(convByName.keys())}" + ) + self._convert(dest, field, converter, value) + else: + # let's try as a 1-tuple + dest = self.build(cls, (source,)) + + for field, conv in convByName.items(): + if not hasattr(dest, field) and isinstance(conv, OptionalValue): + setattr(dest, field, conv.DEFAULT) + + dest = self._callbackTable.get( + (BuildCallback.AFTER_BUILD,) + callbackKey, lambda d: d + )(dest) + + return dest + + +class TableUnbuilder: + def __init__(self, callbackTable=None): + if callbackTable is None: + callbackTable = {} + self._callbackTable = callbackTable + + def unbuild(self, table): + assert isinstance(table, BaseTable) + + source = {} + + callbackKey = (type(table),) + if isinstance(table, FormatSwitchingBaseTable): + source["Format"] = int(table.Format) + callbackKey += (table.Format,) + + for converter in table.getConverters(): + if isinstance(converter, ComputedInt): + continue + value = getattr(table, converter.name) + + enumClass = getattr(converter, "enumClass", None) + if enumClass: + source[converter.name] = value.name.lower() + elif isinstance(converter, Struct): + if converter.repeat: + source[converter.name] = [self.unbuild(v) for v in value] + else: + source[converter.name] = self.unbuild(value) + elif isinstance(converter, SimpleValue): + # "simple" values (e.g. int, float, str) need no further un-building + source[converter.name] = value + else: + raise NotImplementedError( + "Don't know how unbuild {value!r} with {converter!r}" + ) + + source = self._callbackTable.get(callbackKey, lambda s: s)(source) + + return source diff --git a/.venv/lib/python3.12/site-packages/fontTools/colorLib/unbuilder.py b/.venv/lib/python3.12/site-packages/fontTools/colorLib/unbuilder.py new file mode 100644 index 0000000..ac24355 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/colorLib/unbuilder.py @@ -0,0 +1,81 @@ +from fontTools.ttLib.tables import otTables as ot +from .table_builder import TableUnbuilder + + +def unbuildColrV1(layerList, baseGlyphList): + layers = [] + if layerList: + layers = layerList.Paint + unbuilder = LayerListUnbuilder(layers) + return { + rec.BaseGlyph: unbuilder.unbuildPaint(rec.Paint) + for rec in baseGlyphList.BaseGlyphPaintRecord + } + + +def _flatten_layers(lst): + for paint in lst: + if paint["Format"] == ot.PaintFormat.PaintColrLayers: + yield from _flatten_layers(paint["Layers"]) + else: + yield paint + + +class LayerListUnbuilder: + def __init__(self, layers): + self.layers = layers + + callbacks = { + ( + ot.Paint, + ot.PaintFormat.PaintColrLayers, + ): self._unbuildPaintColrLayers, + } + self.tableUnbuilder = TableUnbuilder(callbacks) + + def unbuildPaint(self, paint): + assert isinstance(paint, ot.Paint) + return self.tableUnbuilder.unbuild(paint) + + def _unbuildPaintColrLayers(self, source): + assert source["Format"] == ot.PaintFormat.PaintColrLayers + + layers = list( + _flatten_layers( + [ + self.unbuildPaint(childPaint) + for childPaint in self.layers[ + source["FirstLayerIndex"] : source["FirstLayerIndex"] + + source["NumLayers"] + ] + ] + ) + ) + + if len(layers) == 1: + return layers[0] + + return {"Format": source["Format"], "Layers": layers} + + +if __name__ == "__main__": + from pprint import pprint + import sys + from fontTools.ttLib import TTFont + + try: + fontfile = sys.argv[1] + except IndexError: + sys.exit("usage: fonttools colorLib.unbuilder FONTFILE") + + font = TTFont(fontfile) + colr = font["COLR"] + if colr.version < 1: + sys.exit(f"error: No COLR table version=1 found in {fontfile}") + + colorGlyphs = unbuildColrV1( + colr.table.LayerList, + colr.table.BaseGlyphList, + ) + + pprint(colorGlyphs) diff --git a/.venv/lib/python3.12/site-packages/fontTools/config/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/config/__init__.py new file mode 100644 index 0000000..ff0328a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/config/__init__.py @@ -0,0 +1,90 @@ +""" +Define all configuration options that can affect the working of fontTools +modules. E.g. optimization levels of varLib IUP, otlLib GPOS compression level, +etc. If this file gets too big, split it into smaller files per-module. + +An instance of the Config class can be attached to a TTFont object, so that +the various modules can access their configuration options from it. +""" + +from textwrap import dedent + +from fontTools.misc.configTools import * + + +class Config(AbstractConfig): + options = Options() + + +OPTIONS = Config.options + + +Config.register_option( + name="fontTools.otlLib.optimize.gpos:COMPRESSION_LEVEL", + help=dedent( + """\ + GPOS Lookup type 2 (PairPos) compression level: + 0 = do not attempt to compact PairPos lookups; + 1 to 8 = create at most 1 to 8 new subtables for each existing + subtable, provided that it would yield a 50%% file size saving; + 9 = create as many new subtables as needed to yield a file size saving. + Default: 0. + + This compaction aims to save file size, by splitting large class + kerning subtables (Format 2) that contain many zero values into + smaller and denser subtables. It's a trade-off between the overhead + of several subtables versus the sparseness of one big subtable. + + See the pull request: https://github.com/fonttools/fonttools/pull/2326 + """ + ), + default=0, + parse=int, + validate=lambda v: v in range(10), +) + +Config.register_option( + name="fontTools.ttLib.tables.otBase:USE_HARFBUZZ_REPACKER", + help=dedent( + """\ + FontTools tries to use the HarfBuzz Repacker to serialize GPOS/GSUB tables + if the uharfbuzz python bindings are importable, otherwise falls back to its + slower, less efficient serializer. Set to False to always use the latter. + Set to True to explicitly request the HarfBuzz Repacker (will raise an + error if uharfbuzz cannot be imported). + """ + ), + default=None, + parse=Option.parse_optional_bool, + validate=Option.validate_optional_bool, +) + +Config.register_option( + name="fontTools.otlLib.builder:WRITE_GPOS7", + help=dedent( + """\ + macOS before 13.2 didn’t support GPOS LookupType 7 (non-chaining + ContextPos lookups), so FontTools.otlLib.builder disables a file size + optimisation that would use LookupType 7 instead of 8 when there is no + chaining (no prefix or suffix). Set to True to enable the optimization. + """ + ), + default=False, + parse=Option.parse_optional_bool, + validate=Option.validate_optional_bool, +) + +Config.register_option( + name="fontTools.ttLib:OPTIMIZE_FONT_SPEED", + help=dedent( + """\ + Enable optimizations that prioritize speed over file size. This + mainly affects how glyf table and gvar / VARC tables are compiled. + The produced fonts will be larger, but rendering performance will + be improved with HarfBuzz and other text layout engines. + """ + ), + default=False, + parse=Option.parse_optional_bool, + validate=Option.validate_optional_bool, +) diff --git a/.venv/lib/python3.12/site-packages/fontTools/config/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/config/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..32de264 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/config/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__init__.py new file mode 100644 index 0000000..4ae6356 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .cu2qu import * diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__main__.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__main__.py new file mode 100644 index 0000000..5205ffe --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__main__.py @@ -0,0 +1,6 @@ +import sys +from .cli import _main as main + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..cf739c0 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__init__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..c7d3aa7 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/__main__.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/benchmark.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/benchmark.cpython-312.pyc new file mode 100644 index 0000000..424a1cf Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/benchmark.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cli.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cli.cpython-312.pyc new file mode 100644 index 0000000..5de3d71 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cli.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cu2qu.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cu2qu.cpython-312.pyc new file mode 100644 index 0000000..4e2abd8 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/cu2qu.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/errors.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000..7af7921 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/errors.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/ufo.cpython-312.pyc b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/ufo.cpython-312.pyc new file mode 100644 index 0000000..21a8df5 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/__pycache__/ufo.cpython-312.pyc differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/benchmark.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/benchmark.py new file mode 100644 index 0000000..007f75d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/benchmark.py @@ -0,0 +1,54 @@ +"""Benchmark the cu2qu algorithm performance.""" + +from .cu2qu import * +import random +import timeit + +MAX_ERR = 0.05 + + +def generate_curve(): + return [ + tuple(float(random.randint(0, 2048)) for coord in range(2)) + for point in range(4) + ] + + +def setup_curve_to_quadratic(): + return generate_curve(), MAX_ERR + + +def setup_curves_to_quadratic(): + num_curves = 3 + return ([generate_curve() for curve in range(num_curves)], [MAX_ERR] * num_curves) + + +def run_benchmark(module, function, setup_suffix="", repeat=5, number=1000): + setup_func = "setup_" + function + if setup_suffix: + print("%s with %s:" % (function, setup_suffix), end="") + setup_func += "_" + setup_suffix + else: + print("%s:" % function, end="") + + def wrapper(function, setup_func): + function = globals()[function] + setup_func = globals()[setup_func] + + def wrapped(): + return function(*setup_func()) + + return wrapped + + results = timeit.repeat(wrapper(function, setup_func), repeat=repeat, number=number) + print("\t%5.1fus" % (min(results) * 1000000.0 / number)) + + +def main(): + run_benchmark("cu2qu", "curve_to_quadratic") + run_benchmark("cu2qu", "curves_to_quadratic") + + +if __name__ == "__main__": + random.seed(1) + main() diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cli.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cli.py new file mode 100644 index 0000000..ddc6450 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cli.py @@ -0,0 +1,198 @@ +import os +import argparse +import logging +import shutil +import multiprocessing as mp +from contextlib import closing +from functools import partial + +import fontTools +from .ufo import font_to_quadratic, fonts_to_quadratic + +ufo_module = None +try: + import ufoLib2 as ufo_module +except ImportError: + try: + import defcon as ufo_module + except ImportError as e: + pass + + +logger = logging.getLogger("fontTools.cu2qu") + + +def _cpu_count(): + try: + return mp.cpu_count() + except NotImplementedError: # pragma: no cover + return 1 + + +def open_ufo(path): + if hasattr(ufo_module.Font, "open"): # ufoLib2 + return ufo_module.Font.open(path) + return ufo_module.Font(path) # defcon + + +def _font_to_quadratic(input_path, output_path=None, **kwargs): + ufo = open_ufo(input_path) + logger.info("Converting curves for %s", input_path) + if font_to_quadratic(ufo, **kwargs): + logger.info("Saving %s", output_path) + if output_path: + ufo.save(output_path) + else: + ufo.save() # save in-place + elif output_path: + _copytree(input_path, output_path) + + +def _samepath(path1, path2): + # TODO on python3+, there's os.path.samefile + path1 = os.path.normcase(os.path.abspath(os.path.realpath(path1))) + path2 = os.path.normcase(os.path.abspath(os.path.realpath(path2))) + return path1 == path2 + + +def _copytree(input_path, output_path): + if _samepath(input_path, output_path): + logger.debug("input and output paths are the same file; skipped copy") + return + if os.path.exists(output_path): + shutil.rmtree(output_path) + shutil.copytree(input_path, output_path) + + +def _main(args=None): + """Convert a UFO font from cubic to quadratic curves""" + parser = argparse.ArgumentParser(prog="cu2qu") + parser.add_argument("--version", action="version", version=fontTools.__version__) + parser.add_argument( + "infiles", + nargs="+", + metavar="INPUT", + help="one or more input UFO source file(s).", + ) + parser.add_argument("-v", "--verbose", action="count", default=0) + parser.add_argument( + "-e", + "--conversion-error", + type=float, + metavar="ERROR", + default=None, + help="maxiumum approximation error measured in EM (default: 0.001)", + ) + parser.add_argument( + "-m", + "--mixed", + default=False, + action="store_true", + help="whether to used mixed quadratic and cubic curves", + ) + parser.add_argument( + "--keep-direction", + dest="reverse_direction", + action="store_false", + help="do not reverse the contour direction", + ) + + mode_parser = parser.add_mutually_exclusive_group() + mode_parser.add_argument( + "-i", + "--interpolatable", + action="store_true", + help="whether curve conversion should keep interpolation compatibility", + ) + mode_parser.add_argument( + "-j", + "--jobs", + type=int, + nargs="?", + default=1, + const=_cpu_count(), + metavar="N", + help="Convert using N multiple processes (default: %(default)s)", + ) + + output_parser = parser.add_mutually_exclusive_group() + output_parser.add_argument( + "-o", + "--output-file", + default=None, + metavar="OUTPUT", + help=( + "output filename for the converted UFO. By default fonts are " + "modified in place. This only works with a single input." + ), + ) + output_parser.add_argument( + "-d", + "--output-dir", + default=None, + metavar="DIRECTORY", + help="output directory where to save converted UFOs", + ) + + options = parser.parse_args(args) + + if ufo_module is None: + parser.error("Either ufoLib2 or defcon are required to run this script.") + + if not options.verbose: + level = "WARNING" + elif options.verbose == 1: + level = "INFO" + else: + level = "DEBUG" + logging.basicConfig(level=level) + + if len(options.infiles) > 1 and options.output_file: + parser.error("-o/--output-file can't be used with multile inputs") + + if options.output_dir: + output_dir = options.output_dir + if not os.path.exists(output_dir): + os.mkdir(output_dir) + elif not os.path.isdir(output_dir): + parser.error("'%s' is not a directory" % output_dir) + output_paths = [ + os.path.join(output_dir, os.path.basename(p)) for p in options.infiles + ] + elif options.output_file: + output_paths = [options.output_file] + else: + # save in-place + output_paths = [None] * len(options.infiles) + + kwargs = dict( + dump_stats=options.verbose > 0, + max_err_em=options.conversion_error, + reverse_direction=options.reverse_direction, + all_quadratic=False if options.mixed else True, + ) + + if options.interpolatable: + logger.info("Converting curves compatibly") + ufos = [open_ufo(infile) for infile in options.infiles] + if fonts_to_quadratic(ufos, **kwargs): + for ufo, output_path in zip(ufos, output_paths): + logger.info("Saving %s", output_path) + if output_path: + ufo.save(output_path) + else: + ufo.save() + else: + for input_path, output_path in zip(options.infiles, output_paths): + if output_path: + _copytree(input_path, output_path) + else: + jobs = min(len(options.infiles), options.jobs) if options.jobs > 1 else 1 + if jobs > 1: + func = partial(_font_to_quadratic, **kwargs) + logger.info("Running %d parallel processes", jobs) + with closing(mp.Pool(jobs)) as pool: + pool.starmap(func, zip(options.infiles, output_paths)) + else: + for input_path, output_path in zip(options.infiles, output_paths): + _font_to_quadratic(input_path, output_path, **kwargs) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.c b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.c new file mode 100644 index 0000000..170811a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.c @@ -0,0 +1,15817 @@ +/* Generated by Cython 3.2.2 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "define_macros": [ + [ + "CYTHON_TRACE_NOGIL", + "1" + ] + ], + "name": "fontTools.cu2qu.cu2qu", + "sources": [ + "Lib/fontTools/cu2qu/cu2qu.py" + ] + }, + "module_name": "fontTools.cu2qu.cu2qu" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +/* InitLimitedAPI */ +#if defined(Py_LIMITED_API) + #if !defined(CYTHON_LIMITED_API) + #define CYTHON_LIMITED_API 1 + #endif +#elif defined(CYTHON_LIMITED_API) + #ifdef _MSC_VER + #pragma message ("Limited API usage is enabled with 'CYTHON_LIMITED_API' but 'Py_LIMITED_API' does not define a Python target version. Consider setting 'Py_LIMITED_API' instead.") + #else + #warning Limited API usage is enabled with 'CYTHON_LIMITED_API' but 'Py_LIMITED_API' does not define a Python target version. Consider setting 'Py_LIMITED_API' instead. + #endif +#endif + +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x03080000 + #error Cython requires Python 3.8+. +#else +#define __PYX_ABI_VERSION "3_2_2" +#define CYTHON_HEX_VERSION 0x030202F0 +#define CYTHON_FUTURE_DIVISION 1 +/* CModulePreamble */ +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX +#if defined(GRAALVM_PYTHON) + /* For very preliminary testing purposes. Most variables are set the same as PyPy. + The existence of this section does not imply that anything works or is even tested */ + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 1 + #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_ASSUME_SAFE_SIZE + #define CYTHON_ASSUME_SAFE_SIZE 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_SYS_MONITORING + #define CYTHON_USE_SYS_MONITORING 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_AM_SEND + #define CYTHON_USE_AM_SEND 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 1 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #undef CYTHON_IMMORTAL_CONSTANTS + #define CYTHON_IMMORTAL_CONSTANTS 0 +#elif defined(PYPY_VERSION) + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #ifndef CYTHON_ASSUME_SAFE_SIZE + #define CYTHON_ASSUME_SAFE_SIZE 1 + #endif + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #if PY_VERSION_HEX < 0x03090000 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #undef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #undef CYTHON_USE_SYS_MONITORING + #define CYTHON_USE_SYS_MONITORING 0 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PYPY_VERSION_NUM >= 0x07030C00) + #endif + #undef CYTHON_USE_AM_SEND + #define CYTHON_USE_AM_SEND 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC (PYPY_VERSION_NUM >= 0x07031100) + #endif + #undef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 0 + #undef CYTHON_IMMORTAL_CONSTANTS + #define CYTHON_IMMORTAL_CONSTANTS 0 +#elif defined(CYTHON_LIMITED_API) + #ifdef Py_LIMITED_API + #undef __PYX_LIMITED_VERSION_HEX + #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API + #endif + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_LIMITED_API 1 + #define CYTHON_COMPILING_IN_GRAAL 0 + #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 1 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #endif + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 + #endif + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_ASSUME_SAFE_SIZE + #define CYTHON_ASSUME_SAFE_SIZE 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #undef CYTHON_USE_SYS_MONITORING + #define CYTHON_USE_SYS_MONITORING 0 + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #endif + #ifndef CYTHON_USE_AM_SEND + #define CYTHON_USE_AM_SEND (__PYX_LIMITED_VERSION_HEX >= 0x030A0000) + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS 1 + #endif + #undef CYTHON_IMMORTAL_CONSTANTS + #define CYTHON_IMMORTAL_CONSTANTS 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_LIMITED_API 0 + #define CYTHON_COMPILING_IN_GRAAL 0 + #ifdef Py_GIL_DISABLED + #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 1 + #else + #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 + #endif + #if PY_VERSION_HEX < 0x030A0000 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #elif !defined(CYTHON_USE_TYPE_SLOTS) + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #ifndef CYTHON_USE_TYPE_SPECS + #define CYTHON_USE_TYPE_SPECS 0 + #endif + #ifndef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #ifndef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLIST_INTERNALS) + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 + #elif !defined(CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS) + #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_ASSUME_SAFE_SIZE + #define CYTHON_ASSUME_SAFE_SIZE 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #elif !defined(CYTHON_FAST_GIL) + #define CYTHON_FAST_GIL (PY_VERSION_HEX < 0x030C00A6) + #endif + #ifndef CYTHON_METH_FASTCALL + #define CYTHON_METH_FASTCALL 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_MODULE_STATE + #define CYTHON_USE_MODULE_STATE 0 + #endif + #ifndef CYTHON_USE_SYS_MONITORING + #define CYTHON_USE_SYS_MONITORING (PY_VERSION_HEX >= 0x030d00B1) + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #ifndef CYTHON_USE_AM_SEND + #define CYTHON_USE_AM_SEND 1 + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #elif !defined(CYTHON_USE_DICT_VERSIONS) + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5 && !CYTHON_USE_MODULE_STATE) + #endif + #ifndef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 1 + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif + #ifndef CYTHON_USE_FREELISTS + #define CYTHON_USE_FREELISTS (!CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) + #endif + #if defined(CYTHON_IMMORTAL_CONSTANTS) && PY_VERSION_HEX < 0x030C0000 + #undef CYTHON_IMMORTAL_CONSTANTS + #define CYTHON_IMMORTAL_CONSTANTS 0 // definitely won't work + #elif !defined(CYTHON_IMMORTAL_CONSTANTS) + #define CYTHON_IMMORTAL_CONSTANTS (PY_VERSION_HEX >= 0x030C0000 && !CYTHON_USE_MODULE_STATE && CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) + #endif +#endif +#ifndef CYTHON_COMPRESS_STRINGS + #define CYTHON_COMPRESS_STRINGS 1 +#endif +#ifndef CYTHON_FAST_PYCCALL +#define CYTHON_FAST_PYCCALL CYTHON_FAST_PYCALL +#endif +#ifndef CYTHON_VECTORCALL +#if CYTHON_COMPILING_IN_LIMITED_API +#define CYTHON_VECTORCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) +#else +#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL) +#endif +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(maybe_unused) + #define CYTHON_UNUSED [[maybe_unused]] + #endif + #endif + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR + #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON && !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_USE_CPP_STD_MOVE + #if defined(__cplusplus) && (\ + __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define CYTHON_USE_CPP_STD_MOVE 1 + #else + #define CYTHON_USE_CPP_STD_MOVE 0 + #endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#include +typedef uintptr_t __pyx_uintptr_t; +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) + /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 + * but leads to warnings with -pedantic, since it is a C++17 feature */ + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif +#ifndef Py_UNREACHABLE + #define Py_UNREACHABLE() assert(0); abort() +#endif +#ifdef __cplusplus + template + struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; + #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) +#else + #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) +#endif +#if CYTHON_COMPILING_IN_PYPY == 1 + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX < 0x030A0000) +#else + #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX < 0x03090000) +#endif +#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) + +/* CInitCode */ +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +/* PythonCompatibility */ +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#define __Pyx_BUILTIN_MODULE_NAME "builtins" +#define __Pyx_DefaultClassType PyType_Type +#if CYTHON_COMPILING_IN_LIMITED_API + #ifndef CO_OPTIMIZED + static int CO_OPTIMIZED; + #endif + #ifndef CO_NEWLOCALS + static int CO_NEWLOCALS; + #endif + #ifndef CO_VARARGS + static int CO_VARARGS; + #endif + #ifndef CO_VARKEYWORDS + static int CO_VARKEYWORDS; + #endif + #ifndef CO_ASYNC_GENERATOR + static int CO_ASYNC_GENERATOR; + #endif + #ifndef CO_GENERATOR + static int CO_GENERATOR; + #endif + #ifndef CO_COROUTINE + static int CO_COROUTINE; + #endif +#else + #ifndef CO_COROUTINE + #define CO_COROUTINE 0x80 + #endif + #ifndef CO_ASYNC_GENERATOR + #define CO_ASYNC_GENERATOR 0x200 + #endif +#endif +static int __Pyx_init_co_variables(void); +#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) + #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) +#else + #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) + #define __Pyx_Py_Is(x, y) Py_Is(x, y) +#else + #define __Pyx_Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) + #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) +#else + #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) + #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) +#else + #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) +#endif +#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) + #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) +#else + #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) +#endif +#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) +#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) +#else + #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_SEQUENCE + #define Py_TPFLAGS_SEQUENCE 0 +#endif +#ifndef Py_TPFLAGS_MAPPING + #define Py_TPFLAGS_MAPPING 0 +#endif +#ifndef Py_TPFLAGS_IMMUTABLETYPE + #define Py_TPFLAGS_IMMUTABLETYPE (1UL << 8) +#endif +#ifndef Py_TPFLAGS_DISALLOW_INSTANTIATION + #define Py_TPFLAGS_DISALLOW_INSTANTIATION (1UL << 7) +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#ifndef METH_FASTCALL + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #if PY_VERSION_HEX >= 0x030d00A4 + # define __Pyx_PyCFunctionFast PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords + #else + # define __Pyx_PyCFunctionFast _PyCFunctionFast + # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords + #endif +#endif +#if CYTHON_METH_FASTCALL + #define __Pyx_METH_FASTCALL METH_FASTCALL + #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast + #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords +#else + #define __Pyx_METH_FASTCALL METH_VARARGS + #define __Pyx_PyCFunction_FastCall PyCFunction + #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords +#endif +#if CYTHON_VECTORCALL + #define __pyx_vectorcallfunc vectorcallfunc + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET + #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) +#else + #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 + #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) +#endif +#if PY_VERSION_HEX >= 0x030900B1 +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) +#else +#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) +#endif +#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) +#elif !CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) +#endif +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) +static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { + return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; +} +#endif +static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void (*cfunc)(void)) { +#if CYTHON_COMPILING_IN_LIMITED_API + return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; +#else + return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +#endif +} +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) +#if PY_VERSION_HEX < 0x03090000 || (CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000) + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) + typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +#else + #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) + #define __Pyx_PyCMethod PyCMethod +#endif +#ifndef METH_METHOD + #define METH_METHOD 0x200 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) +#elif CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM > 0x19000000 + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) GraalPyFrame_SetLineNumber((frame), (lineno)) +#elif CYTHON_COMPILING_IN_GRAAL + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) _PyFrame_SetLineNumber((frame), (lineno)) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyThreadState_Current PyThreadState_Get() +#elif !CYTHON_FAST_THREAD_STATE + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x030d00A1 + #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#endif +#if CYTHON_USE_MODULE_STATE +static CYTHON_INLINE void *__Pyx__PyModule_GetState(PyObject *op) +{ + void *result; + result = PyModule_GetState(op); + if (!result) + Py_FatalError("Couldn't find the module state"); + return result; +} +#define __Pyx_PyModule_GetState(o) (__pyx_mstatetype *)__Pyx__PyModule_GetState(o) +#else +#define __Pyx_PyModule_GetState(op) ((void)op,__pyx_mstate_global) +#endif +#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE((PyObject *) obj), name, func_ctype) +#define __Pyx_PyObject_TryGetSlot(obj, name, func_ctype) __Pyx_PyType_TryGetSlot(Py_TYPE(obj), name, func_ctype) +#define __Pyx_PyObject_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(Py_TYPE(obj), sub, name, func_ctype) +#define __Pyx_PyObject_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSubSlot(Py_TYPE(obj), sub, name, func_ctype) +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) + #define __Pyx_PyType_TryGetSlot(type, name, func_ctype) __Pyx_PyType_GetSlot(type, name, func_ctype) + #define __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) (((type)->sub) ? ((type)->sub->name) : NULL) + #define __Pyx_PyType_TryGetSubSlot(type, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) +#else + #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) + #define __Pyx_PyType_TryGetSlot(type, name, func_ctype)\ + ((__PYX_LIMITED_VERSION_HEX >= 0x030A0000 ||\ + (PyType_GetFlags(type) & Py_TPFLAGS_HEAPTYPE) || __Pyx_get_runtime_version() >= 0x030A0000) ?\ + __Pyx_PyType_GetSlot(type, name, func_ctype) : NULL) + #define __Pyx_PyType_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSlot(obj, name, func_ctype) + #define __Pyx_PyType_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSlot(obj, name, func_ctype) +#endif +#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) +#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { + PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); + if (res == NULL) PyErr_Clear(); + return res; +} +#elif !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000 +#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#else +static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { +#if CYTHON_COMPILING_IN_PYPY + return PyDict_GetItem(dict, name); +#else + PyDictEntry *ep; + PyDictObject *mp = (PyDictObject*) dict; + long hash = ((PyStringObject *) name)->ob_shash; + assert(hash != -1); + ep = (mp->ma_lookup)(mp, name, hash); + if (ep == NULL) { + return NULL; + } + return ep->me_value; +#endif +} +#define __Pyx_PyDict_GetItemStr PyDict_GetItem +#endif +#if CYTHON_USE_TYPE_SLOTS + #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) + #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) +#else + #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) + #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) +#endif +#define __Pyx_PyObject_GetIterNextFunc(iterator) __Pyx_PyObject_GetSlot(iterator, tp_iternext, iternextfunc) +#if CYTHON_USE_TYPE_SPECS +#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ + PyTypeObject *type = Py_TYPE((PyObject*)obj);\ + assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ + PyObject_GC_Del(obj);\ + Py_DECREF(type);\ +} +#else +#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) + #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) + #define __Pyx_PyUnicode_DATA(u) ((void*)u) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) +#else + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #if !defined(PyUnicode_DecodeUnicodeEscape) + #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) + #endif + #if !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) + #endif + #if !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) + #endif + #if !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) + #endif +#endif +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030E0000 + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && PyUnstable_Object_IsUniquelyReferenced(obj)) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#elif CYTHON_COMPILING_IN_CPYTHON + #define __Pyx_PySequence_ListKeepNew(obj)\ + (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) +#else + #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +enum __Pyx_ReferenceSharing { + __Pyx_ReferenceSharing_DefinitelyUnique, // We created it so we know it's unshared - no need to check + __Pyx_ReferenceSharing_OwnStrongReference, + __Pyx_ReferenceSharing_FunctionArgument, + __Pyx_ReferenceSharing_SharedReference, // Never trust it to be unshared because it's a global or similar +}; +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && PY_VERSION_HEX >= 0x030E0000 +#define __Pyx_IS_UNIQUELY_REFERENCED(o, sharing)\ + (sharing == __Pyx_ReferenceSharing_DefinitelyUnique ? 1 :\ + (sharing == __Pyx_ReferenceSharing_FunctionArgument ? PyUnstable_Object_IsUniqueReferencedTemporary(o) :\ + (sharing == __Pyx_ReferenceSharing_OwnStrongReference ? PyUnstable_Object_IsUniquelyReferenced(o) : 0))) +#elif (CYTHON_COMPILING_IN_CPYTHON && !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_IS_UNIQUELY_REFERENCED(o, sharing) (((void)sharing), Py_REFCNT(o) == 1) +#else +#define __Pyx_IS_UNIQUELY_REFERENCED(o, sharing) (((void)o), ((void)sharing), 0) +#endif +#if CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + #define __Pyx_PyList_GetItemRef(o, i) PyList_GetItemRef(o, i) + #elif CYTHON_COMPILING_IN_LIMITED_API || !CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PyList_GetItemRef(o, i) (likely((i) >= 0) ? PySequence_GetItem(o, i) : (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) + #else + #define __Pyx_PyList_GetItemRef(o, i) PySequence_ITEM(o, i) + #endif +#elif CYTHON_COMPILING_IN_LIMITED_API || !CYTHON_ASSUME_SAFE_MACROS + #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + #define __Pyx_PyList_GetItemRef(o, i) PyList_GetItemRef(o, i) + #else + #define __Pyx_PyList_GetItemRef(o, i) __Pyx_XNewRef(PyList_GetItem(o, i)) + #endif +#else + #define __Pyx_PyList_GetItemRef(o, i) __Pyx_NewRef(PyList_GET_ITEM(o, i)) +#endif +#if CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS && !CYTHON_COMPILING_IN_LIMITED_API && CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PyList_GetItemRefFast(o, i, unsafe_shared) (__Pyx_IS_UNIQUELY_REFERENCED(o, unsafe_shared) ?\ + __Pyx_NewRef(PyList_GET_ITEM(o, i)) : __Pyx_PyList_GetItemRef(o, i)) +#else + #define __Pyx_PyList_GetItemRefFast(o, i, unsafe_shared) __Pyx_PyList_GetItemRef(o, i) +#endif +#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 +#define __Pyx_PyDict_GetItemRef(dict, key, result) PyDict_GetItemRef(dict, key, result) +#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS +static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { + *result = PyObject_GetItem(dict, key); + if (*result == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); + return 0; + } + return -1; + } + return 1; +} +#else +static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { + *result = PyDict_GetItemWithError(dict, key); + if (*result == NULL) { + return PyErr_Occurred() ? -1 : 0; + } + Py_INCREF(*result); + return 1; +} +#endif +#if defined(CYTHON_DEBUG_VISIT_CONST) && CYTHON_DEBUG_VISIT_CONST + #define __Pyx_VISIT_CONST(obj) Py_VISIT(obj) +#else + #define __Pyx_VISIT_CONST(obj) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GET_ITEM(o, i) + #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) + #define __Pyx_PyList_GET_ITEM(o, i) PyList_GET_ITEM(o, i) +#else + #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) + #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) + #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GetItem(o, i) + #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) + #define __Pyx_PyList_GET_ITEM(o, i) PyList_GetItem(o, i) +#endif +#if CYTHON_ASSUME_SAFE_SIZE + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) + #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GET_LENGTH(o) +#else + #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) + #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) + #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) + #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) + #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) + #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GetLength(o) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_InternFromString) + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) +#endif +#define __Pyx_PyLong_FromHash_t PyLong_FromSsize_t +#define __Pyx_PyLong_AsHash_t __Pyx_PyIndex_AsSsize_t +#if __PYX_LIMITED_VERSION_HEX >= 0x030A0000 + #define __Pyx_PySendResult PySendResult +#else + typedef enum { + PYGEN_RETURN = 0, + PYGEN_ERROR = -1, + PYGEN_NEXT = 1, + } __Pyx_PySendResult; +#endif +#if CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030A00A3 + typedef __Pyx_PySendResult (*__Pyx_pyiter_sendfunc)(PyObject *iter, PyObject *value, PyObject **result); +#else + #define __Pyx_pyiter_sendfunc sendfunc +#endif +#if !CYTHON_USE_AM_SEND +#define __PYX_HAS_PY_AM_SEND 0 +#elif __PYX_LIMITED_VERSION_HEX >= 0x030A0000 +#define __PYX_HAS_PY_AM_SEND 1 +#else +#define __PYX_HAS_PY_AM_SEND 2 // our own backported implementation +#endif +#if __PYX_HAS_PY_AM_SEND < 2 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods +#else + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + __Pyx_pyiter_sendfunc am_send; + } __Pyx_PyAsyncMethodsStruct; + #define __Pyx_SlotTpAsAsync(s) ((PyAsyncMethods*)(s)) +#endif +#if CYTHON_USE_AM_SEND && PY_VERSION_HEX < 0x030A00F0 + #define __Pyx_TPFLAGS_HAVE_AM_SEND (1UL << 21) +#else + #define __Pyx_TPFLAGS_HAVE_AM_SEND (0) +#endif +#if PY_VERSION_HEX >= 0x03090000 +#define __Pyx_PyInterpreterState_Get() PyInterpreterState_Get() +#else +#define __Pyx_PyInterpreterState_Get() PyThreadState_Get()->interp +#endif +#if CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030A0000 +#ifdef __cplusplus +extern "C" +#endif +PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static int __Pyx_init_co_variable(PyObject *inspect, const char* name, int *write_to) { + int value; + PyObject *py_value = PyObject_GetAttrString(inspect, name); + if (!py_value) return 0; + value = (int) PyLong_AsLong(py_value); + Py_DECREF(py_value); + *write_to = value; + return value != -1 || !PyErr_Occurred(); +} +static int __Pyx_init_co_variables(void) { + PyObject *inspect; + int result; + inspect = PyImport_ImportModule("inspect"); + result = +#if !defined(CO_OPTIMIZED) + __Pyx_init_co_variable(inspect, "CO_OPTIMIZED", &CO_OPTIMIZED) && +#endif +#if !defined(CO_NEWLOCALS) + __Pyx_init_co_variable(inspect, "CO_NEWLOCALS", &CO_NEWLOCALS) && +#endif +#if !defined(CO_VARARGS) + __Pyx_init_co_variable(inspect, "CO_VARARGS", &CO_VARARGS) && +#endif +#if !defined(CO_VARKEYWORDS) + __Pyx_init_co_variable(inspect, "CO_VARKEYWORDS", &CO_VARKEYWORDS) && +#endif +#if !defined(CO_ASYNC_GENERATOR) + __Pyx_init_co_variable(inspect, "CO_ASYNC_GENERATOR", &CO_ASYNC_GENERATOR) && +#endif +#if !defined(CO_GENERATOR) + __Pyx_init_co_variable(inspect, "CO_GENERATOR", &CO_GENERATOR) && +#endif +#if !defined(CO_COROUTINE) + __Pyx_init_co_variable(inspect, "CO_COROUTINE", &CO_COROUTINE) && +#endif + 1; + Py_DECREF(inspect); + return result ? 0 : -1; +} +#else +static int __Pyx_init_co_variables(void) { + return 0; // It's a limited API-only feature +} +#endif + +/* MathInitCode */ +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #ifndef _USE_MATH_DEFINES + #define _USE_MATH_DEFINES + #endif +#endif +#include +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#ifndef CYTHON_CLINE_IN_TRACEBACK_RUNTIME +#define CYTHON_CLINE_IN_TRACEBACK_RUNTIME 0 +#endif +#ifndef CYTHON_CLINE_IN_TRACEBACK +#define CYTHON_CLINE_IN_TRACEBACK CYTHON_CLINE_IN_TRACEBACK_RUNTIME +#endif +#if CYTHON_CLINE_IN_TRACEBACK +#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; __pyx_clineno = __LINE__; (void) __pyx_clineno; } +#else +#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; (void) __pyx_clineno; } +#endif +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifdef CYTHON_EXTERN_C + #undef __PYX_EXTERN_C + #define __PYX_EXTERN_C CYTHON_EXTERN_C +#elif defined(__PYX_EXTERN_C) + #ifdef _MSC_VER + #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") + #else + #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. + #endif +#else + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__fontTools__cu2qu__cu2qu +#define __PYX_HAVE_API__fontTools__cu2qu__cu2qu +/* Early includes */ +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) + #define __Pyx_PyByteArray_AsString(s) PyByteArray_AS_STRING(s) +#else + #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AsString(s)) + #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AsString(s)) + #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AsString(s)) + #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AsString(s)) + #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AsString(s)) + #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AsString(s)) + #define __Pyx_PyByteArray_AsString(s) PyByteArray_AsString(s) +#endif +#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +static CYTHON_INLINE PyObject *__Pyx_NewRef(PyObject *obj) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_NewRef) + return Py_NewRef(obj); +#else + Py_INCREF(obj); + return obj; +#endif +} +static CYTHON_INLINE PyObject *__Pyx_XNewRef(PyObject *obj) { +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_XNewRef) + return Py_XNewRef(obj); +#else + Py_XINCREF(obj); + return obj; +#endif +} +static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b); +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __Pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AS_DOUBLE(x) +#else +#define __Pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AsDouble(x) +#endif +#define __Pyx_PyFloat_AsFloat(x) ((float) __Pyx_PyFloat_AsDouble(x)) +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_VERSION_HEX >= 0x030C00A7 + #ifndef _PyLong_SIGN_MASK + #define _PyLong_SIGN_MASK 3 + #endif + #ifndef _PyLong_NON_SIZE_BITS + #define _PyLong_NON_SIZE_BITS 3 + #endif + #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) + #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) + #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) + #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) + #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_SignedDigitCount(x)\ + ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) + #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) + #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) + #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) + #else + #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) + #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) + #endif + typedef Py_ssize_t __Pyx_compact_pylong; + typedef size_t __Pyx_compact_upylong; + #else + #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) + #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) + #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) + #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) + #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) + #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) + #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) + #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) + #define __Pyx_PyLong_CompactValue(x)\ + ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) + typedef sdigit __Pyx_compact_pylong; + typedef digit __Pyx_compact_upylong; + #endif + #if PY_VERSION_HEX >= 0x030C00A5 + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) + #else + #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) + #endif +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 + #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#elif __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeASCII(c_str, size, NULL) +#else + #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +/* PretendToInitialize */ +#ifdef __cplusplus +#if __cplusplus > 201103L +#include +#endif +template +static void __Pyx_pretend_to_initialize(T* ptr) { +#if __cplusplus > 201103L + if ((std::is_trivially_default_constructible::value)) +#endif + *ptr = T(); + (void)ptr; +} +#else +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } +#endif + + +#if !CYTHON_USE_MODULE_STATE +static PyObject *__pyx_m = NULL; +#endif +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * const __pyx_cfilenm = __FILE__; +static const char *__pyx_filename; + +/* Header.proto */ +#if !defined(CYTHON_CCOMPLEX) + #if defined(__cplusplus) + #define CYTHON_CCOMPLEX 1 + #elif (defined(_Complex_I) && !defined(_MSC_VER)) || ((defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_COMPLEX__) && !defined(_MSC_VER)) + #define CYTHON_CCOMPLEX 1 + #else + #define CYTHON_CCOMPLEX 0 + #endif +#endif +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + #include + #else + #include + #endif +#endif +#if CYTHON_CCOMPLEX && !defined(__cplusplus) && defined(__sun__) && defined(__GNUC__) + #undef _Complex_I + #define _Complex_I 1.0fj +#endif + +/* #### Code section: filename_table ### */ + +static const char* const __pyx_f[] = { + "Lib/fontTools/cu2qu/cu2qu.py", +}; +/* #### Code section: utility_code_proto_before_types ### */ +/* Atomics.proto (used by UnpackUnboundCMethod) */ +#include +#ifndef CYTHON_ATOMICS + #define CYTHON_ATOMICS 1 +#endif +#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS +#define __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING() CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +#define __pyx_atomic_int_type int +#define __pyx_nonatomic_int_type int +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__)) + #include +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ + (defined(_MSC_VER) && _MSC_VER >= 1700))) + #include +#endif +#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ + (__STDC_VERSION__ >= 201112L) &&\ + !defined(__STDC_NO_ATOMICS__) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type atomic_int + #define __pyx_atomic_ptr_type atomic_uintptr_t + #define __pyx_nonatomic_ptr_type uintptr_t + #define __pyx_atomic_incr_relaxed(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) + #define __pyx_atomic_incr_acq_rel(value) atomic_fetch_add_explicit(value, 1, memory_order_acq_rel) + #define __pyx_atomic_decr_acq_rel(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) + #define __pyx_atomic_sub(value, arg) atomic_fetch_sub(value, arg) + #define __pyx_atomic_int_cmp_exchange(value, expected, desired) atomic_compare_exchange_strong(value, expected, desired) + #define __pyx_atomic_load(value) atomic_load(value) + #define __pyx_atomic_store(value, new_value) atomic_store(value, new_value) + #define __pyx_atomic_pointer_load_relaxed(value) atomic_load_explicit(value, memory_order_relaxed) + #define __pyx_atomic_pointer_load_acquire(value) atomic_load_explicit(value, memory_order_acquire) + #define __pyx_atomic_pointer_exchange(value, new_value) atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) + #define __pyx_atomic_pointer_cmp_exchange(value, expected, desired) atomic_compare_exchange_strong(value, expected, desired) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C atomics" + #endif +#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ + (__cplusplus >= 201103L) ||\ +\ + (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ + ATOMIC_INT_LOCK_FREE == 2) + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type std::atomic_int + #define __pyx_atomic_ptr_type std::atomic_uintptr_t + #define __pyx_nonatomic_ptr_type uintptr_t + #define __pyx_atomic_incr_relaxed(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) + #define __pyx_atomic_incr_acq_rel(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_acq_rel) + #define __pyx_atomic_decr_acq_rel(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) + #define __pyx_atomic_sub(value, arg) std::atomic_fetch_sub(value, arg) + #define __pyx_atomic_int_cmp_exchange(value, expected, desired) std::atomic_compare_exchange_strong(value, expected, desired) + #define __pyx_atomic_load(value) std::atomic_load(value) + #define __pyx_atomic_store(value, new_value) std::atomic_store(value, new_value) + #define __pyx_atomic_pointer_load_relaxed(value) std::atomic_load_explicit(value, std::memory_order_relaxed) + #define __pyx_atomic_pointer_load_acquire(value) std::atomic_load_explicit(value, std::memory_order_acquire) + #define __pyx_atomic_pointer_exchange(value, new_value) std::atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) + #define __pyx_atomic_pointer_cmp_exchange(value, expected, desired) std::atomic_compare_exchange_strong(value, expected, desired) + #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) + #pragma message ("Using standard C++ atomics") + #elif defined(__PYX_DEBUG_ATOMICS) + #warning "Using standard C++ atomics" + #endif +#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ + (__GNUC_MINOR__ > 1 ||\ + (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) + #define __pyx_atomic_ptr_type void* + #define __pyx_nonatomic_ptr_type void* + #define __pyx_atomic_incr_relaxed(value) __sync_fetch_and_add(value, 1) + #define __pyx_atomic_incr_acq_rel(value) __sync_fetch_and_add(value, 1) + #define __pyx_atomic_decr_acq_rel(value) __sync_fetch_and_sub(value, 1) + #define __pyx_atomic_sub(value, arg) __sync_fetch_and_sub(value, arg) + static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { + __pyx_nonatomic_int_type old = __sync_val_compare_and_swap(value, *expected, desired); + int result = old == *expected; + *expected = old; + return result; + } + #define __pyx_atomic_load(value) __sync_fetch_and_add(value, 0) + #define __pyx_atomic_store(value, new_value) __sync_lock_test_and_set(value, new_value) + #define __pyx_atomic_pointer_load_relaxed(value) __sync_fetch_and_add(value, 0) + #define __pyx_atomic_pointer_load_acquire(value) __sync_fetch_and_add(value, 0) + #define __pyx_atomic_pointer_exchange(value, new_value) __sync_lock_test_and_set(value, (__pyx_atomic_ptr_type)new_value) + static CYTHON_INLINE int __pyx_atomic_pointer_cmp_exchange(__pyx_atomic_ptr_type* value, __pyx_nonatomic_ptr_type* expected, __pyx_nonatomic_ptr_type desired) { + __pyx_nonatomic_ptr_type old = __sync_val_compare_and_swap(value, *expected, desired); + int result = old == *expected; + *expected = old; + return result; + } + #ifdef __PYX_DEBUG_ATOMICS + #warning "Using GNU atomics" + #endif +#elif CYTHON_ATOMICS && defined(_MSC_VER) + #include + #undef __pyx_atomic_int_type + #define __pyx_atomic_int_type long + #define __pyx_atomic_ptr_type void* + #undef __pyx_nonatomic_int_type + #define __pyx_nonatomic_int_type long + #define __pyx_nonatomic_ptr_type void* + #pragma intrinsic (_InterlockedExchangeAdd, _InterlockedExchange, _InterlockedCompareExchange, _InterlockedCompareExchangePointer, _InterlockedExchangePointer) + #define __pyx_atomic_incr_relaxed(value) _InterlockedExchangeAdd(value, 1) + #define __pyx_atomic_incr_acq_rel(value) _InterlockedExchangeAdd(value, 1) + #define __pyx_atomic_decr_acq_rel(value) _InterlockedExchangeAdd(value, -1) + #define __pyx_atomic_sub(value, arg) _InterlockedExchangeAdd(value, -arg) + static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { + __pyx_nonatomic_int_type old = _InterlockedCompareExchange(value, desired, *expected); + int result = old == *expected; + *expected = old; + return result; + } + #define __pyx_atomic_load(value) _InterlockedExchangeAdd(value, 0) + #define __pyx_atomic_store(value, new_value) _InterlockedExchange(value, new_value) + #define __pyx_atomic_pointer_load_relaxed(value) *(void * volatile *)value + #define __pyx_atomic_pointer_load_acquire(value) _InterlockedCompareExchangePointer(value, 0, 0) + #define __pyx_atomic_pointer_exchange(value, new_value) _InterlockedExchangePointer(value, (__pyx_atomic_ptr_type)new_value) + static CYTHON_INLINE int __pyx_atomic_pointer_cmp_exchange(__pyx_atomic_ptr_type* value, __pyx_nonatomic_ptr_type* expected, __pyx_nonatomic_ptr_type desired) { + __pyx_atomic_ptr_type old = _InterlockedCompareExchangePointer(value, desired, *expected); + int result = old == *expected; + *expected = old; + return result; + } + #ifdef __PYX_DEBUG_ATOMICS + #pragma message ("Using MSVC atomics") + #endif +#else + #undef CYTHON_ATOMICS + #define CYTHON_ATOMICS 0 + #ifdef __PYX_DEBUG_ATOMICS + #warning "Not using atomics" + #endif +#endif + +/* CriticalSectionsDefinition.proto (used by CriticalSections) */ +#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +#define __Pyx_PyCriticalSection void* +#define __Pyx_PyCriticalSection2 void* +#define __Pyx_PyCriticalSection_End(cs) +#define __Pyx_PyCriticalSection2_End(cs) +#else +#define __Pyx_PyCriticalSection PyCriticalSection +#define __Pyx_PyCriticalSection2 PyCriticalSection2 +#define __Pyx_PyCriticalSection_End PyCriticalSection_End +#define __Pyx_PyCriticalSection2_End PyCriticalSection2_End +#endif + +/* CriticalSections.proto (used by ParseKeywordsImpl) */ +#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +#define __Pyx_PyCriticalSection_Begin(cs, arg) (void)(cs) +#define __Pyx_PyCriticalSection2_Begin(cs, arg1, arg2) (void)(cs) +#else +#define __Pyx_PyCriticalSection_Begin PyCriticalSection_Begin +#define __Pyx_PyCriticalSection2_Begin PyCriticalSection2_Begin +#endif +#if PY_VERSION_HEX < 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_BEGIN_CRITICAL_SECTION(o) { +#define __Pyx_END_CRITICAL_SECTION() } +#else +#define __Pyx_BEGIN_CRITICAL_SECTION Py_BEGIN_CRITICAL_SECTION +#define __Pyx_END_CRITICAL_SECTION Py_END_CRITICAL_SECTION +#endif + +/* IncludeStructmemberH.proto (used by FixUpExtensionType) */ +#include + +/* #### Code section: numeric_typedefs ### */ +/* #### Code section: complex_type_declarations ### */ +/* Declarations.proto */ +#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus) + #ifdef __cplusplus + typedef ::std::complex< double > __pyx_t_double_complex; + #else + typedef double _Complex __pyx_t_double_complex; + #endif +#else + typedef struct { double real, imag; } __pyx_t_double_complex; +#endif +static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double, double); + +/* #### Code section: type_declarations ### */ + +/*--- Type declarations ---*/ +struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen; + +/* "fontTools/cu2qu/cu2qu.py":150 + * + * + * @cython.locals( # <<<<<<<<<<<<<< + * p0=cython.complex, + * p1=cython.complex, +*/ +struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen { + PyObject_HEAD + __pyx_t_double_complex __pyx_v_a; + __pyx_t_double_complex __pyx_v_a1; + __pyx_t_double_complex __pyx_v_b; + __pyx_t_double_complex __pyx_v_b1; + __pyx_t_double_complex __pyx_v_c; + __pyx_t_double_complex __pyx_v_c1; + __pyx_t_double_complex __pyx_v_d; + __pyx_t_double_complex __pyx_v_d1; + double __pyx_v_delta_2; + double __pyx_v_delta_3; + double __pyx_v_dt; + int __pyx_v_i; + int __pyx_v_n; + __pyx_t_double_complex __pyx_v_p0; + __pyx_t_double_complex __pyx_v_p1; + __pyx_t_double_complex __pyx_v_p2; + __pyx_t_double_complex __pyx_v_p3; + double __pyx_v_t1; + double __pyx_v_t1_2; + int __pyx_t_0; + int __pyx_t_1; + int __pyx_t_2; +}; + +/* #### Code section: utility_code_proto ### */ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, Py_ssize_t); + void (*DECREF)(void*, PyObject*, Py_ssize_t); + void (*GOTREF)(void*, PyObject*, Py_ssize_t); + void (*GIVEREF)(void*, PyObject*, Py_ssize_t); + void* (*SetupContext)(const char*, Py_ssize_t, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContextNogil() {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __Pyx_RefNannyFinishContext();\ + PyGILState_Release(__pyx_gilstate_save);\ + } + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) + #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContextNogil() + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_Py_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; Py_XDECREF(tmp);\ + } while (0) +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* IncludeStdlibH.proto */ +#include + +/* PyObjectCall.proto (used by PyObjectFastCall) */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto (used by PyObjectFastCall) */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectFastCall.proto */ +#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs); + +/* PyLongCompare.proto */ +static CYTHON_INLINE int __Pyx_PyLong_BoolEqObjC(PyObject *op1, PyObject *op2, long intval, long inplace); + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* PyThreadStateGet.proto (used by PyErrFetchRestore) */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#if PY_VERSION_HEX >= 0x030C00A6 +#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) +#else +#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) +#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) +#endif +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) +#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto (used by IterFinish) */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* IterFinish.proto */ +static CYTHON_INLINE int __Pyx_IterFinish(void); + +/* UnpackItemEndCheck.proto */ +static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck, has_gil, unsafe_shared)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck, unsafe_shared) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck, has_gil, unsafe_shared)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck, unsafe_shared) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck, int unsafe_shared); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck, has_gil, unsafe_shared)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck, unsafe_shared) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck, int unsafe_shared); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck, int unsafe_shared); + +/* PyErrExceptionMatches.proto (used by PyObjectGetAttrStrNoError) */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* PyObjectGetAttrStr.proto (used by PyObjectGetAttrStrNoError) */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* PyObjectGetAttrStrNoError.proto (used by GetBuiltinName) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* GetBuiltinName.proto (used by GetModuleGlobalName) */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* PyDictVersioning.proto (used by GetModuleGlobalName) */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __Pyx_XNewRef(__pyx_dict_cached_value);\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_mstate_global->__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* TupleAndListFromArray.proto (used by fastcall) */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); +#endif +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); +#endif + +/* IncludeStringH.proto (used by BytesEquals) */ +#include + +/* BytesEquals.proto (used by UnicodeEquals) */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto (used by fastcall) */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* fastcall.proto */ +#if CYTHON_AVOID_BORROWED_REFS + #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_PySequence_ITEM(args, i) +#elif CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_NewRef(__Pyx_PyTuple_GET_ITEM(args, i)) +#else + #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_XNewRef(PyTuple_GetItem(args, i)) +#endif +#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) +#define __Pyx_KwValues_VARARGS(args, nargs) NULL +#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) +#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) +#if CYTHON_METH_FASTCALL + #define __Pyx_ArgRef_FASTCALL(args, i) __Pyx_NewRef(args[i]) + #define __Pyx_NumKwargs_FASTCALL(kwds) __Pyx_PyTuple_GET_SIZE(kwds) + #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) + static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); + #else + #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) + #endif +#else + #define __Pyx_ArgRef_FASTCALL __Pyx_ArgRef_VARARGS + #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS + #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS + #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS + #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS +#endif +#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) +#if CYTHON_METH_FASTCALL || (CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(args + start, stop - start) +#else +#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) +#endif + +/* py_dict_items.proto (used by OwnedDictNext) */ +static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d); + +/* CallCFunction.proto (used by CallUnboundCMethod0) */ +#define __Pyx_CallCFunction(cfunc, self, args)\ + ((PyCFunction)(void(*)(void))(cfunc)->func)(self, args) +#define __Pyx_CallCFunctionWithKeywords(cfunc, self, args, kwargs)\ + ((PyCFunctionWithKeywords)(void(*)(void))(cfunc)->func)(self, args, kwargs) +#define __Pyx_CallCFunctionFast(cfunc, self, args, nargs)\ + ((__Pyx_PyCFunctionFast)(void(*)(void))(PyCFunction)(cfunc)->func)(self, args, nargs) +#define __Pyx_CallCFunctionFastWithKeywords(cfunc, self, args, nargs, kwnames)\ + ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))(PyCFunction)(cfunc)->func)(self, args, nargs, kwnames) + +/* PyObjectCallOneArg.proto (used by CallUnboundCMethod0) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* UnpackUnboundCMethod.proto (used by CallUnboundCMethod0) */ +typedef struct { + PyObject *type; + PyObject **method_name; +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && CYTHON_ATOMICS + __pyx_atomic_int_type initialized; +#endif + PyCFunction func; + PyObject *method; + int flag; +} __Pyx_CachedCFunction; +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +static CYTHON_INLINE int __Pyx_CachedCFunction_GetAndSetInitializing(__Pyx_CachedCFunction *cfunc) { +#if !CYTHON_ATOMICS + return 1; +#else + __pyx_nonatomic_int_type expected = 0; + if (__pyx_atomic_int_cmp_exchange(&cfunc->initialized, &expected, 1)) { + return 0; + } + return expected; +#endif +} +static CYTHON_INLINE void __Pyx_CachedCFunction_SetFinishedInitializing(__Pyx_CachedCFunction *cfunc) { +#if CYTHON_ATOMICS + __pyx_atomic_store(&cfunc->initialized, 2); +#endif +} +#else +#define __Pyx_CachedCFunction_GetAndSetInitializing(cfunc) 2 +#define __Pyx_CachedCFunction_SetFinishedInitializing(cfunc) +#endif + +/* CallUnboundCMethod0.proto */ +CYTHON_UNUSED +static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self); +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self); +#else +#define __Pyx_CallUnboundCMethod0(cfunc, self) __Pyx__CallUnboundCMethod0(cfunc, self) +#endif + +/* py_dict_values.proto (used by OwnedDictNext) */ +static CYTHON_INLINE PyObject* __Pyx_PyDict_Values(PyObject* d); + +/* OwnedDictNext.proto (used by ParseKeywordsImpl) */ +#if CYTHON_AVOID_BORROWED_REFS +static int __Pyx_PyDict_NextRef(PyObject *p, PyObject **ppos, PyObject **pkey, PyObject **pvalue); +#else +CYTHON_INLINE +static int __Pyx_PyDict_NextRef(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue); +#endif + +/* RaiseDoubleKeywords.proto (used by ParseKeywordsImpl) */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywordsImpl.export */ +static int __Pyx_ParseKeywordsTuple( + PyObject *kwds, + PyObject * const *kwvalues, + PyObject ** const argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs +); +static int __Pyx_ParseKeywordDictToDict( + PyObject *kwds, + PyObject ** const argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name +); +static int __Pyx_ParseKeywordDict( + PyObject *kwds, + PyObject ** const argnames[], + PyObject *values[], + Py_ssize_t num_pos_args, + Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs +); + +/* CallUnboundCMethod2.proto */ +CYTHON_UNUSED +static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2); +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2); +#else +#define __Pyx_CallUnboundCMethod2(cfunc, self, arg1, arg2) __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2) +#endif + +/* ParseKeywords.proto */ +static CYTHON_INLINE int __Pyx_ParseKeywords( + PyObject *kwds, PyObject *const *kwvalues, PyObject ** const argnames[], + PyObject *kwds2, PyObject *values[], + Py_ssize_t num_pos_args, Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs +); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* GetException.proto (used by pep479) */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* pep479.proto */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen); + +/* GetTopmostException.proto (used by SaveResetException) */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* PyZeroDivisionError_Check.proto */ +#define __Pyx_PyExc_ZeroDivisionError_Check(obj) __Pyx_TypeCheck(obj, PyExc_ZeroDivisionError) + +/* IterNextPlain.proto (used by IterNext) */ +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next_Plain(PyObject *iterator); +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 +static PyObject *__Pyx_GetBuiltinNext_LimitedAPI(void); +#endif + +/* IterNext.proto */ +#define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL) +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* ListCompAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len)) { + Py_INCREF(x); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 + L->ob_item[len] = x; + #else + PyList_SET_ITEM(list, len, x); + #endif + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) +#endif + +/* PyLongBinop.proto */ +#if !CYTHON_COMPILING_IN_PYPY +static CYTHON_INLINE PyObject* __Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); +#else +#define __Pyx_PyLong_AddObjC(op1, op2, intval, inplace, zerodivision_check)\ + (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2)) +#endif + +/* RaiseException.export */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* AssertionsEnabled.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX >= 0x030C0000 + static int __pyx_assertions_enabled_flag; + #define __pyx_assertions_enabled() (__pyx_assertions_enabled_flag) + #if __clang__ || __GNUC__ + __attribute__((no_sanitize("thread"))) + #endif + static int __Pyx_init_assertions_enabled(void) { + PyObject *builtins, *debug, *debug_str; + int flag; + builtins = PyEval_GetBuiltins(); + if (!builtins) goto bad; + debug_str = PyUnicode_FromStringAndSize("__debug__", 9); + if (!debug_str) goto bad; + debug = PyObject_GetItem(builtins, debug_str); + Py_DECREF(debug_str); + if (!debug) goto bad; + flag = PyObject_IsTrue(debug); + Py_DECREF(debug); + if (flag == -1) goto bad; + __pyx_assertions_enabled_flag = flag; + return 0; + bad: + __pyx_assertions_enabled_flag = 1; + return -1; + } +#else + #define __Pyx_init_assertions_enabled() (0) + #define __pyx_assertions_enabled() (!Py_OptimizeFlag) +#endif + +/* PyAssertionError_Check.proto */ +#define __Pyx_PyExc_AssertionError_Check(obj) __Pyx_TypeCheck(obj, PyExc_AssertionError) + +/* SetItemInt.proto */ +#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck, has_gil, unsafe_shared)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck, unsafe_shared) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) :\ + __Pyx_SetItemInt_Generic(o, to_py_func(i), v))) +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v); +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, + int is_list, int wraparound, int boundscheck, int unsafe_shared); + +/* ModInt[long].proto */ +static CYTHON_INLINE long __Pyx_mod_long(long, long, int b_is_constant); + +/* CheckTypeForFreelists.proto */ +#if CYTHON_USE_FREELISTS +#if CYTHON_USE_TYPE_SPECS +#define __PYX_CHECK_FINAL_TYPE_FOR_FREELISTS(t, expected_tp, expected_size) ((int) ((t) == (expected_tp))) +#define __PYX_CHECK_TYPE_FOR_FREELIST_FLAGS Py_TPFLAGS_IS_ABSTRACT +#else +#define __PYX_CHECK_FINAL_TYPE_FOR_FREELISTS(t, expected_tp, expected_size) ((int) ((t)->tp_basicsize == (expected_size))) +#define __PYX_CHECK_TYPE_FOR_FREELIST_FLAGS (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE) +#endif +#define __PYX_CHECK_TYPE_FOR_FREELISTS(t, expected_tp, expected_size)\ + (__PYX_CHECK_FINAL_TYPE_FOR_FREELISTS((t), (expected_tp), (expected_size)) &\ + (int) (!__Pyx_PyType_HasFeature((t), __PYX_CHECK_TYPE_FOR_FREELIST_FLAGS))) +#endif + +/* AllocateExtensionType.proto */ +static PyObject *__Pyx_AllocateExtensionType(PyTypeObject *t, int is_final); + +/* LimitedApiGetTypeDict.proto (used by SetItemOnTypeDict) */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_GetTypeDict(PyTypeObject *tp); +#endif + +/* SetItemOnTypeDict.proto (used by FixUpExtensionType) */ +static int __Pyx__SetItemOnTypeDict(PyTypeObject *tp, PyObject *k, PyObject *v); +#define __Pyx_SetItemOnTypeDict(tp, k, v) __Pyx__SetItemOnTypeDict((PyTypeObject*)tp, k, v) + +/* FixUpExtensionType.proto */ +static CYTHON_INLINE int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); + +/* PyObjectCallNoArg.proto (used by PyObjectCallMethod0) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); + +/* PyObjectGetMethod.proto (used by PyObjectCallMethod0) */ +#if !(CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000))) +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); +#endif + +/* PyObjectCallMethod0.proto (used by PyType_Ready) */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); + +/* ValidateBasesTuple.proto (used by PyType_Ready) */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases); +#endif + +/* PyType_Ready.proto */ +CYTHON_UNUSED static int __Pyx_PyType_Ready(PyTypeObject *t); + +/* HasAttr.proto (used by ImportImpl) */ +#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 +#define __Pyx_HasAttr(o, n) PyObject_HasAttrWithError(o, n) +#else +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); +#endif + +/* ImportImpl.export */ +static PyObject *__Pyx__Import(PyObject *name, PyObject *const *imported_names, Py_ssize_t len_imported_names, PyObject *qualname, PyObject *moddict, int level); + +/* Import.proto */ +static CYTHON_INLINE PyObject *__Pyx_Import(PyObject *name, PyObject *const *imported_names, Py_ssize_t len_imported_names, PyObject *qualname, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* ListPack.proto */ +static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...); + +/* pybytes_as_double.proto (used by pyunicode_as_double) */ +static double __Pyx_SlowPyString_AsDouble(PyObject *obj); +static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length); +static CYTHON_INLINE double __Pyx_PyBytes_AsDouble(PyObject *obj) { + char* as_c_string; + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE + as_c_string = PyBytes_AS_STRING(obj); + size = PyBytes_GET_SIZE(obj); +#else + if (PyBytes_AsStringAndSize(obj, &as_c_string, &size) < 0) { + return (double)-1; + } +#endif + return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); +} +static CYTHON_INLINE double __Pyx_PyByteArray_AsDouble(PyObject *obj) { + char* as_c_string; + Py_ssize_t size; +#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE + as_c_string = PyByteArray_AS_STRING(obj); + size = PyByteArray_GET_SIZE(obj); +#else + as_c_string = PyByteArray_AsString(obj); + if (as_c_string == NULL) { + return (double)-1; + } + size = PyByteArray_Size(obj); +#endif + return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); +} + +/* pyunicode_as_double.proto */ +#if !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS +static const char* __Pyx__PyUnicode_AsDouble_Copy(const void* data, const int kind, char* buffer, Py_ssize_t start, Py_ssize_t end) { + int last_was_punctuation; + Py_ssize_t i; + last_was_punctuation = 1; + for (i=start; i <= end; i++) { + Py_UCS4 chr = PyUnicode_READ(kind, data, i); + int is_punctuation = (chr == '_') | (chr == '.'); + *buffer = (char)chr; + buffer += (chr != '_'); + if (unlikely(chr > 127)) goto parse_failure; + if (unlikely(last_was_punctuation & is_punctuation)) goto parse_failure; + last_was_punctuation = is_punctuation; + } + if (unlikely(last_was_punctuation)) goto parse_failure; + *buffer = '\0'; + return buffer; +parse_failure: + return NULL; +} +static double __Pyx__PyUnicode_AsDouble_inf_nan(const void* data, int kind, Py_ssize_t start, Py_ssize_t length) { + int matches = 1; + Py_UCS4 chr; + Py_UCS4 sign = PyUnicode_READ(kind, data, start); + int is_signed = (sign == '-') | (sign == '+'); + start += is_signed; + length -= is_signed; + switch (PyUnicode_READ(kind, data, start)) { + #ifdef Py_NAN + case 'n': + case 'N': + if (unlikely(length != 3)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+1); + matches &= (chr == 'a') | (chr == 'A'); + chr = PyUnicode_READ(kind, data, start+2); + matches &= (chr == 'n') | (chr == 'N'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_NAN : Py_NAN; + #endif + case 'i': + case 'I': + if (unlikely(length < 3)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+1); + matches &= (chr == 'n') | (chr == 'N'); + chr = PyUnicode_READ(kind, data, start+2); + matches &= (chr == 'f') | (chr == 'F'); + if (likely(length == 3 && matches)) + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + if (unlikely(length != 8)) goto parse_failure; + chr = PyUnicode_READ(kind, data, start+3); + matches &= (chr == 'i') | (chr == 'I'); + chr = PyUnicode_READ(kind, data, start+4); + matches &= (chr == 'n') | (chr == 'N'); + chr = PyUnicode_READ(kind, data, start+5); + matches &= (chr == 'i') | (chr == 'I'); + chr = PyUnicode_READ(kind, data, start+6); + matches &= (chr == 't') | (chr == 'T'); + chr = PyUnicode_READ(kind, data, start+7); + matches &= (chr == 'y') | (chr == 'Y'); + if (unlikely(!matches)) goto parse_failure; + return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; + case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + break; + default: + goto parse_failure; + } + return 0.0; +parse_failure: + return -1.0; +} +static double __Pyx_PyUnicode_AsDouble_WithSpaces(PyObject *obj) { + double value; + const char *last; + char *end; + Py_ssize_t start, length = PyUnicode_GET_LENGTH(obj); + const int kind = PyUnicode_KIND(obj); + const void* data = PyUnicode_DATA(obj); + start = 0; + while (Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, start))) + start++; + while (start < length - 1 && Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, length - 1))) + length--; + length -= start; + if (unlikely(length <= 0)) goto fallback; + value = __Pyx__PyUnicode_AsDouble_inf_nan(data, kind, start, length); + if (unlikely(value == -1.0)) goto fallback; + if (value != 0.0) return value; + if (length < 40) { + char number[40]; + last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); + if (unlikely(!last)) goto fallback; + value = PyOS_string_to_double(number, &end, NULL); + } else { + char *number = (char*) PyMem_Malloc((length + 1) * sizeof(char)); + if (unlikely(!number)) goto fallback; + last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); + if (unlikely(!last)) { + PyMem_Free(number); + goto fallback; + } + value = PyOS_string_to_double(number, &end, NULL); + PyMem_Free(number); + } + if (likely(end == last) || (value == (double)-1 && PyErr_Occurred())) { + return value; + } +fallback: + return __Pyx_SlowPyString_AsDouble(obj); +} +#endif +static CYTHON_INLINE double __Pyx_PyUnicode_AsDouble(PyObject *obj) { +#if !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS + if (unlikely(__Pyx_PyUnicode_READY(obj) == -1)) + return (double)-1; + if (likely(PyUnicode_IS_ASCII(obj))) { + const char *s; + Py_ssize_t length; + s = PyUnicode_AsUTF8AndSize(obj, &length); + return __Pyx__PyBytes_AsDouble(obj, s, length); + } + return __Pyx_PyUnicode_AsDouble_WithSpaces(obj); +#else + return __Pyx_SlowPyString_AsDouble(obj); +#endif +} + +/* FloatExceptionCheck.proto */ +#define __PYX_CHECK_FLOAT_EXCEPTION(value, error_value)\ + ((error_value) == (error_value) ?\ + (value) == (error_value) :\ + (value) != (value)) + +/* dict_setdefault.proto (used by FetchCommonType) */ +static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value); + +/* AddModuleRef.proto (used by FetchSharedCythonModule) */ +#if ((CYTHON_COMPILING_IN_CPYTHON_FREETHREADING ) ||\ + __PYX_LIMITED_VERSION_HEX < 0x030d0000) + static PyObject *__Pyx_PyImport_AddModuleRef(const char *name); +#else + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#endif + +/* FetchSharedCythonModule.proto (used by FetchCommonType) */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void); + +/* FetchCommonType.proto (used by CommonTypesMetaclass) */ +static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases); + +/* CommonTypesMetaclass.proto (used by CythonFunctionShared) */ +static int __pyx_CommonTypesMetaclass_init(PyObject *module); +#define __Pyx_CommonTypesMetaclass_USED + +/* CallTypeTraverse.proto (used by CythonFunctionShared) */ +#if !CYTHON_USE_TYPE_SPECS || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x03090000) +#define __Pyx_call_type_traverse(o, always_call, visit, arg) 0 +#else +static int __Pyx_call_type_traverse(PyObject *o, int always_call, visitproc visit, void *arg); +#endif + +/* PyMethodNew.proto (used by CythonFunctionShared) */ +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ); + +/* PyVectorcallFastCallDict.proto (used by CythonFunctionShared) */ +#if CYTHON_METH_FASTCALL && CYTHON_VECTORCALL +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); +#endif + +/* CythonFunctionShared.proto (used by CythonFunction) */ +#define __Pyx_CyFunction_USED +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CYFUNCTION_COROUTINE 0x08 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + #define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#else + #define __Pyx_CyFunction_GetClassObj(f)\ + ((PyObject*) ((PyCMethodObject *) (f))->mm_class) +#endif +#define __Pyx_CyFunction_SetClassObj(f, classobj)\ + __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject_HEAD + PyObject *func; +#elif PY_VERSION_HEX < 0x030900B1 + PyCFunctionObject func; +#else + PyCMethodObject func; +#endif +#if CYTHON_COMPILING_IN_LIMITED_API && CYTHON_METH_FASTCALL + __pyx_vectorcallfunc func_vectorcall; +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_weakreflist; +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_dict; +#endif + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *func_classobj; +#endif + PyObject *defaults; + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; + PyObject *func_is_coroutine; +} __pyx_CyFunctionObject; +#undef __Pyx_CyOrPyCFunction_Check +#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_mstate_global->__pyx_CyFunctionType) +#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_mstate_global->__pyx_CyFunctionType, &PyCFunction_Type) +#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_mstate_global->__pyx_CyFunctionType) +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)); +#undef __Pyx_IsSameCFunction +#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); +static CYTHON_INLINE PyObject *__Pyx_CyFunction_InitDefaults(PyObject *func, + PyTypeObject *defaults_type); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(PyObject *module); +#if CYTHON_METH_FASTCALL +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); +#if CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) +#else +#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) +#endif +#endif + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* CLineInTraceback.proto (used by AddTraceback) */ +#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#else +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#endif + +/* CodeObjectCache.proto (used by AddTraceback) */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject __Pyx_CachedCodeObjectType; +#else +typedef PyCodeObject __Pyx_CachedCodeObjectType; +#endif +typedef struct { + __Pyx_CachedCodeObjectType* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + __pyx_atomic_int_type accessor_count; + #endif +}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* RealImag.proto */ +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + #define __Pyx_CREAL(z) ((z).real()) + #define __Pyx_CIMAG(z) ((z).imag()) + #else + #define __Pyx_CREAL(z) (__real__(z)) + #define __Pyx_CIMAG(z) (__imag__(z)) + #endif +#else + #define __Pyx_CREAL(z) ((z).real) + #define __Pyx_CIMAG(z) ((z).imag) +#endif +#if defined(__cplusplus) && CYTHON_CCOMPLEX\ + && (defined(_WIN32) || defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 5 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4 )) || __cplusplus >= 201103) + #define __Pyx_SET_CREAL(z,x) ((z).real(x)) + #define __Pyx_SET_CIMAG(z,y) ((z).imag(y)) +#else + #define __Pyx_SET_CREAL(z,x) __Pyx_CREAL(z) = (x) + #define __Pyx_SET_CIMAG(z,y) __Pyx_CIMAG(z) = (y) +#endif + +/* Arithmetic.proto */ +#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus) + #define __Pyx_c_eq_double(a, b) ((a)==(b)) + #define __Pyx_c_sum_double(a, b) ((a)+(b)) + #define __Pyx_c_diff_double(a, b) ((a)-(b)) + #define __Pyx_c_prod_double(a, b) ((a)*(b)) + #define __Pyx_c_quot_double(a, b) ((a)/(b)) + #define __Pyx_c_neg_double(a) (-(a)) + #ifdef __cplusplus + #define __Pyx_c_is_zero_double(z) ((z)==(double)0) + #define __Pyx_c_conj_double(z) (::std::conj(z)) + #if 1 + #define __Pyx_c_abs_double(z) (::std::abs(z)) + #define __Pyx_c_pow_double(a, b) (::std::pow(a, b)) + #endif + #else + #define __Pyx_c_is_zero_double(z) ((z)==0) + #define __Pyx_c_conj_double(z) (conj(z)) + #if 1 + #define __Pyx_c_abs_double(z) (cabs(z)) + #define __Pyx_c_pow_double(a, b) (cpow(a, b)) + #endif + #endif +#else + static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex); + static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex); + #if 1 + static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex, __pyx_t_double_complex); + #endif +#endif + +/* FromPy.proto */ +static __pyx_t_double_complex __Pyx_PyComplex_As___pyx_t_double_complex(PyObject*); + +/* GCCDiagnostics.proto */ +#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* ToPy.proto */ +#define __pyx_PyComplex_FromComplex(z)\ + PyComplex_FromDoubles((double)__Pyx_CREAL(z),\ + (double)__Pyx_CIMAG(z)) + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *); + +/* PyObjectVectorCallKwBuilder.proto (used by CIntToPy) */ +CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); +#if CYTHON_VECTORCALL +#if PY_VERSION_HEX >= 0x03090000 +#define __Pyx_Object_Vectorcall_CallFromBuilder PyObject_Vectorcall +#else +#define __Pyx_Object_Vectorcall_CallFromBuilder _PyObject_Vectorcall +#endif +#define __Pyx_MakeVectorcallBuilderKwds(n) PyTuple_New(n) +static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); +static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n); +#else +#define __Pyx_Object_Vectorcall_CallFromBuilder __Pyx_PyObject_FastCallDict +#define __Pyx_MakeVectorcallBuilderKwds(n) __Pyx_PyDict_NewPresized(n) +#define __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n) PyDict_SetItem(builder, key, value) +#define __Pyx_VectorcallBuilder_AddArgStr(key, value, builder, args, n) PyDict_SetItemString(builder, key, value) +#endif + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyLong_From_int(int value); + +/* FormatTypeName.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API +typedef PyObject *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%U" +#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) +#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 +#define __Pyx_PyType_GetFullyQualifiedName PyType_GetFullyQualifiedName +#else +static __Pyx_TypeName __Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp); +#endif +#else // !LIMITED_API +typedef const char *__Pyx_TypeName; +#define __Pyx_FMT_TYPENAME "%.200s" +#define __Pyx_PyType_GetFullyQualifiedName(tp) ((tp)->tp_name) +#define __Pyx_DECREF_TypeName(obj) +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2) { + return PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2); +} +#endif +#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) +#ifdef PyExceptionInstance_Check + #define __Pyx_PyBaseException_Check(obj) PyExceptionInstance_Check(obj) +#else + #define __Pyx_PyBaseException_Check(obj) __Pyx_TypeCheck(obj, PyExc_BaseException) +#endif + +/* GetRuntimeVersion.proto */ +#if __PYX_LIMITED_VERSION_HEX < 0x030b0000 +static unsigned long __Pyx_cached_runtime_version = 0; +static void __Pyx_init_runtime_version(void); +#else +#define __Pyx_init_runtime_version() +#endif +static unsigned long __Pyx_get_runtime_version(void); + +/* SwapException.proto (used by CoroutineBase) */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyObjectCall2Args.proto (used by PyObjectCallMethod1) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* PyObjectCallMethod1.proto (used by CoroutineBase) */ +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); + +/* ReturnWithStopIteration.proto (used by CoroutineBase) */ +static CYTHON_INLINE void __Pyx_ReturnWithStopIteration(PyObject* value, int async, int iternext); + +/* CoroutineBase.proto (used by Generator) */ +struct __pyx_CoroutineObject; +typedef PyObject *(*__pyx_coroutine_body_t)(struct __pyx_CoroutineObject *, PyThreadState *, PyObject *); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_ExcInfoStruct _PyErr_StackItem +#else +typedef struct { + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; +} __Pyx_ExcInfoStruct; +#endif +typedef struct __pyx_CoroutineObject { + PyObject_HEAD + __pyx_coroutine_body_t body; + PyObject *closure; + __Pyx_ExcInfoStruct gi_exc_state; +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + PyObject *gi_weakreflist; +#endif + PyObject *classobj; + PyObject *yieldfrom; + __Pyx_pyiter_sendfunc yieldfrom_am_send; + PyObject *gi_name; + PyObject *gi_qualname; + PyObject *gi_modulename; + PyObject *gi_code; + PyObject *gi_frame; +#if CYTHON_USE_SYS_MONITORING && (CYTHON_PROFILE || CYTHON_TRACE) + PyMonitoringState __pyx_pymonitoring_state[__Pyx_MonitoringEventTypes_CyGen_count]; + uint64_t __pyx_pymonitoring_version; +#endif + int resume_label; + char is_running; +} __pyx_CoroutineObject; +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name); +static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self); +static int __Pyx_Coroutine_clear(PyObject *self); +static __Pyx_PySendResult __Pyx_Coroutine_AmSend(PyObject *self, PyObject *value, PyObject **retval); +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); +static __Pyx_PySendResult __Pyx_Coroutine_Close(PyObject *self, PyObject **retval); +static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); +#if CYTHON_USE_EXC_INFO_STACK +#define __Pyx_Coroutine_SwapException(self) +#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state) +#else +#define __Pyx_Coroutine_SwapException(self) {\ + __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback);\ + __Pyx_Coroutine_ResetFrameBackpointer(&(self)->gi_exc_state);\ + } +#define __Pyx_Coroutine_ResetAndClearException(self) {\ + __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback);\ + (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL;\ + } +#endif +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__pyx_tstate, pvalue) +#else +#define __Pyx_PyGen_FetchStopIterationValue(pvalue)\ + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, pvalue) +#endif +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *tstate, PyObject **pvalue); +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state); +static char __Pyx_Coroutine_test_and_set_is_running(__pyx_CoroutineObject *gen); +static void __Pyx_Coroutine_unset_is_running(__pyx_CoroutineObject *gen); +static char __Pyx_Coroutine_get_is_running(__pyx_CoroutineObject *gen); +static PyObject *__Pyx_Coroutine_get_is_running_getter(PyObject *gen, void *closure); +#if __PYX_HAS_PY_AM_SEND == 2 +static void __Pyx_SetBackportTypeAmSend(PyTypeObject *type, __Pyx_PyAsyncMethodsStruct *static_amsend_methods, __Pyx_pyiter_sendfunc am_send); +#endif +static PyObject *__Pyx_Coroutine_fail_reduce_ex(PyObject *self, PyObject *arg); + +/* Generator.proto */ +#define __Pyx_Generator_USED +#define __Pyx_Generator_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_mstate_global->__pyx_GeneratorType) +#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\ + __Pyx__Coroutine_New(__pyx_mstate_global->__pyx_GeneratorType, body, code, closure, name, qualname, module_name) +static PyObject *__Pyx_Generator_Next(PyObject *self); +static int __pyx_Generator_init(PyObject *module); +static CYTHON_INLINE PyObject *__Pyx_Generator_GetInlinedResult(PyObject *self); + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); + +/* DecompressString.proto */ +static PyObject *__Pyx_DecompressString(const char *s, Py_ssize_t length, int algo); + +/* MultiPhaseInitModuleState.proto */ +#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE +static PyObject *__Pyx_State_FindModule(void*); +static int __Pyx_State_AddModule(PyObject* module, void*); +static int __Pyx_State_RemoveModule(void*); +#elif CYTHON_USE_MODULE_STATE +#define __Pyx_State_FindModule PyState_FindModule +#define __Pyx_State_AddModule PyState_AddModule +#define __Pyx_State_RemoveModule PyState_RemoveModule +#endif + +/* #### Code section: module_declarations ### */ +/* CythonABIVersion.proto */ +#if CYTHON_COMPILING_IN_LIMITED_API + #if CYTHON_METH_FASTCALL + #define __PYX_FASTCALL_ABI_SUFFIX "_fastcall" + #else + #define __PYX_FASTCALL_ABI_SUFFIX + #endif + #define __PYX_LIMITED_ABI_SUFFIX "limited" __PYX_FASTCALL_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX +#else + #define __PYX_LIMITED_ABI_SUFFIX +#endif +#if __PYX_HAS_PY_AM_SEND == 1 + #define __PYX_AM_SEND_ABI_SUFFIX +#elif __PYX_HAS_PY_AM_SEND == 2 + #define __PYX_AM_SEND_ABI_SUFFIX "amsendbackport" +#else + #define __PYX_AM_SEND_ABI_SUFFIX "noamsend" +#endif +#ifndef __PYX_MONITORING_ABI_SUFFIX + #define __PYX_MONITORING_ABI_SUFFIX +#endif +#if CYTHON_USE_TP_FINALIZE + #define __PYX_TP_FINALIZE_ABI_SUFFIX +#else + #define __PYX_TP_FINALIZE_ABI_SUFFIX "nofinalize" +#endif +#if CYTHON_USE_FREELISTS || !defined(__Pyx_AsyncGen_USED) + #define __PYX_FREELISTS_ABI_SUFFIX +#else + #define __PYX_FREELISTS_ABI_SUFFIX "nofreelists" +#endif +#define CYTHON_ABI __PYX_ABI_VERSION __PYX_LIMITED_ABI_SUFFIX __PYX_MONITORING_ABI_SUFFIX __PYX_TP_FINALIZE_ABI_SUFFIX __PYX_FREELISTS_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX +#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI +#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." + + +/* Module declarations from "cython" */ + +/* Module declarations from "fontTools.cu2qu.cu2qu" */ +static CYTHON_INLINE double __pyx_f_9fontTools_5cu2qu_5cu2qu_dot(__pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu__complex_div_by_real(__pyx_t_double_complex, double); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_points(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_parameters(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_n_iter(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, PyObject *); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_three(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static CYTHON_INLINE __pyx_t_double_complex __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_control(double, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static CYTHON_INLINE __pyx_t_double_complex __pyx_f_9fontTools_5cu2qu_5cu2qu_calc_intersect(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex); /*proto*/ +static int __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, __pyx_t_double_complex, double); /*proto*/ +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_quadratic(PyObject *, double); /*proto*/ +static PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_spline(PyObject *, int, double, int); /*proto*/ +/* #### Code section: typeinfo ### */ +/* #### Code section: before_global_var ### */ +#define __Pyx_MODULE_NAME "fontTools.cu2qu.cu2qu" +extern int __pyx_module_is_main_fontTools__cu2qu__cu2qu; +int __pyx_module_is_main_fontTools__cu2qu__cu2qu = 0; + +/* Implementation of "fontTools.cu2qu.cu2qu" */ +/* #### Code section: global_var ### */ +/* #### Code section: string_decls ### */ +/* #### Code section: decls ### */ +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu__split_cubic_into_n_gen(CYTHON_UNUSED PyObject *__pyx_self, __pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3, int __pyx_v_n); /* proto */ +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu_3curve_to_quadratic(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_curve, double __pyx_v_max_err, int __pyx_v_all_quadratic); /* proto */ +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu_5curves_to_quadratic(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_curves, PyObject *__pyx_v_max_errors, int __pyx_v_all_quadratic); /* proto */ +static PyObject *__pyx_tp_new_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +/* #### Code section: late_includes ### */ +/* #### Code section: module_state ### */ +/* SmallCodeConfig */ +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif + +typedef struct { + PyObject *__pyx_d; + PyObject *__pyx_b; + PyObject *__pyx_cython_runtime; + PyObject *__pyx_empty_tuple; + PyObject *__pyx_empty_bytes; + PyObject *__pyx_empty_unicode; + PyObject *__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen; + PyTypeObject *__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen; + __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_items; + __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_pop; + __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_values; + PyObject *__pyx_codeobj_tab[3]; + PyObject *__pyx_string_tab[80]; + PyObject *__pyx_number_tab[6]; +/* #### Code section: module_state_contents ### */ +/* IterNextPlain.module_state_decls */ +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 +PyObject *__Pyx_GetBuiltinNext_LimitedAPI_cache; +#endif + + +#if CYTHON_USE_FREELISTS +struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *__pyx_freelist_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen[8]; +int __pyx_freecount_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen; +#endif +/* CommonTypesMetaclass.module_state_decls */ +PyTypeObject *__pyx_CommonTypesMetaclassType; + +/* CachedMethodType.module_state_decls */ +#if CYTHON_COMPILING_IN_LIMITED_API +PyObject *__Pyx_CachedMethodType; +#endif + +/* CythonFunctionShared.module_state_decls */ +PyTypeObject *__pyx_CyFunctionType; + +/* CodeObjectCache.module_state_decls */ +struct __Pyx_CodeObjectCache __pyx_code_cache; + +/* Generator.module_state_decls */ +PyTypeObject *__pyx_GeneratorType; + +/* #### Code section: module_state_end ### */ +} __pyx_mstatetype; + +#if CYTHON_USE_MODULE_STATE +#ifdef __cplusplus +namespace { +extern struct PyModuleDef __pyx_moduledef; +} /* anonymous namespace */ +#else +static struct PyModuleDef __pyx_moduledef; +#endif + +#define __pyx_mstate_global (__Pyx_PyModule_GetState(__Pyx_State_FindModule(&__pyx_moduledef))) + +#define __pyx_m (__Pyx_State_FindModule(&__pyx_moduledef)) +#else +static __pyx_mstatetype __pyx_mstate_global_static = +#ifdef __cplusplus + {}; +#else + {0}; +#endif +static __pyx_mstatetype * const __pyx_mstate_global = &__pyx_mstate_global_static; +#endif +/* #### Code section: constant_name_defines ### */ +#define __pyx_kp_u_ __pyx_string_tab[0] +#define __pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py __pyx_string_tab[1] +#define __pyx_kp_u_Return_quadratic_Bezier_splines __pyx_string_tab[2] +#define __pyx_kp_u__2 __pyx_string_tab[3] +#define __pyx_kp_u_curves_to_quadratic_line_503 __pyx_string_tab[4] +#define __pyx_kp_u_disable __pyx_string_tab[5] +#define __pyx_kp_u_enable __pyx_string_tab[6] +#define __pyx_kp_u_fontTools_cu2qu_errors __pyx_string_tab[7] +#define __pyx_kp_u_gc __pyx_string_tab[8] +#define __pyx_kp_u_isenabled __pyx_string_tab[9] +#define __pyx_n_u_ApproxNotFoundError __pyx_string_tab[10] +#define __pyx_n_u_COMPILED __pyx_string_tab[11] +#define __pyx_n_u_Cu2QuError __pyx_string_tab[12] +#define __pyx_n_u_Error __pyx_string_tab[13] +#define __pyx_n_u_MAX_N __pyx_string_tab[14] +#define __pyx_n_u_NAN __pyx_string_tab[15] +#define __pyx_n_u_NaN __pyx_string_tab[16] +#define __pyx_n_u_Pyx_PyDict_NextRef __pyx_string_tab[17] +#define __pyx_n_u_a __pyx_string_tab[18] +#define __pyx_n_u_a1 __pyx_string_tab[19] +#define __pyx_n_u_all __pyx_string_tab[20] +#define __pyx_n_u_all_quadratic __pyx_string_tab[21] +#define __pyx_n_u_asyncio_coroutines __pyx_string_tab[22] +#define __pyx_n_u_b __pyx_string_tab[23] +#define __pyx_n_u_b1 __pyx_string_tab[24] +#define __pyx_n_u_c __pyx_string_tab[25] +#define __pyx_n_u_c1 __pyx_string_tab[26] +#define __pyx_n_u_cline_in_traceback __pyx_string_tab[27] +#define __pyx_n_u_close __pyx_string_tab[28] +#define __pyx_n_u_curve __pyx_string_tab[29] +#define __pyx_n_u_curve_to_quadratic __pyx_string_tab[30] +#define __pyx_n_u_curves __pyx_string_tab[31] +#define __pyx_n_u_curves_to_quadratic __pyx_string_tab[32] +#define __pyx_n_u_d __pyx_string_tab[33] +#define __pyx_n_u_d1 __pyx_string_tab[34] +#define __pyx_n_u_delta_2 __pyx_string_tab[35] +#define __pyx_n_u_delta_3 __pyx_string_tab[36] +#define __pyx_n_u_dt __pyx_string_tab[37] +#define __pyx_n_u_errors __pyx_string_tab[38] +#define __pyx_n_u_fontTools_cu2qu_cu2qu __pyx_string_tab[39] +#define __pyx_n_u_func __pyx_string_tab[40] +#define __pyx_n_u_i __pyx_string_tab[41] +#define __pyx_n_u_imag __pyx_string_tab[42] +#define __pyx_n_u_is_coroutine __pyx_string_tab[43] +#define __pyx_n_u_isnan __pyx_string_tab[44] +#define __pyx_n_u_items __pyx_string_tab[45] +#define __pyx_n_u_l __pyx_string_tab[46] +#define __pyx_n_u_last_i __pyx_string_tab[47] +#define __pyx_n_u_main __pyx_string_tab[48] +#define __pyx_n_u_math __pyx_string_tab[49] +#define __pyx_n_u_max_err __pyx_string_tab[50] +#define __pyx_n_u_max_errors __pyx_string_tab[51] +#define __pyx_n_u_module __pyx_string_tab[52] +#define __pyx_n_u_n __pyx_string_tab[53] +#define __pyx_n_u_name __pyx_string_tab[54] +#define __pyx_n_u_next __pyx_string_tab[55] +#define __pyx_n_u_p __pyx_string_tab[56] +#define __pyx_n_u_p0 __pyx_string_tab[57] +#define __pyx_n_u_p1 __pyx_string_tab[58] +#define __pyx_n_u_p2 __pyx_string_tab[59] +#define __pyx_n_u_p3 __pyx_string_tab[60] +#define __pyx_n_u_pop __pyx_string_tab[61] +#define __pyx_n_u_qualname __pyx_string_tab[62] +#define __pyx_n_u_real __pyx_string_tab[63] +#define __pyx_n_u_s __pyx_string_tab[64] +#define __pyx_n_u_send __pyx_string_tab[65] +#define __pyx_n_u_set_name __pyx_string_tab[66] +#define __pyx_n_u_setdefault __pyx_string_tab[67] +#define __pyx_n_u_spline __pyx_string_tab[68] +#define __pyx_n_u_splines __pyx_string_tab[69] +#define __pyx_n_u_split_cubic_into_n_gen __pyx_string_tab[70] +#define __pyx_n_u_t1 __pyx_string_tab[71] +#define __pyx_n_u_t1_2 __pyx_string_tab[72] +#define __pyx_n_u_test __pyx_string_tab[73] +#define __pyx_n_u_throw __pyx_string_tab[74] +#define __pyx_n_u_value __pyx_string_tab[75] +#define __pyx_n_u_values __pyx_string_tab[76] +#define __pyx_kp_b_iso88591_AWBc_U_U_3fBa_AWCy_7_2QgQgT_a_Q __pyx_string_tab[77] +#define __pyx_kp_b_iso88591_J_Qawb_4uG4y_3a_3c_1A_avRq_T_AV __pyx_string_tab[78] +#define __pyx_kp_b_iso88591__3 __pyx_string_tab[79] +#define __pyx_int_1 __pyx_number_tab[0] +#define __pyx_int_2 __pyx_number_tab[1] +#define __pyx_int_3 __pyx_number_tab[2] +#define __pyx_int_4 __pyx_number_tab[3] +#define __pyx_int_6 __pyx_number_tab[4] +#define __pyx_int_100 __pyx_number_tab[5] +/* #### Code section: module_state_clear ### */ +#if CYTHON_USE_MODULE_STATE +static CYTHON_SMALL_CODE int __pyx_m_clear(PyObject *m) { + __pyx_mstatetype *clear_module_state = __Pyx_PyModule_GetState(m); + if (!clear_module_state) return 0; + Py_CLEAR(clear_module_state->__pyx_d); + Py_CLEAR(clear_module_state->__pyx_b); + Py_CLEAR(clear_module_state->__pyx_cython_runtime); + Py_CLEAR(clear_module_state->__pyx_empty_tuple); + Py_CLEAR(clear_module_state->__pyx_empty_bytes); + Py_CLEAR(clear_module_state->__pyx_empty_unicode); + #if CYTHON_PEP489_MULTI_PHASE_INIT + __Pyx_State_RemoveModule(NULL); + #endif + Py_CLEAR(clear_module_state->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen); + Py_CLEAR(clear_module_state->__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen); + for (int i=0; i<3; ++i) { Py_CLEAR(clear_module_state->__pyx_codeobj_tab[i]); } + for (int i=0; i<80; ++i) { Py_CLEAR(clear_module_state->__pyx_string_tab[i]); } + for (int i=0; i<6; ++i) { Py_CLEAR(clear_module_state->__pyx_number_tab[i]); } +/* #### Code section: module_state_clear_contents ### */ +/* CommonTypesMetaclass.module_state_clear */ +Py_CLEAR(clear_module_state->__pyx_CommonTypesMetaclassType); + +/* CythonFunctionShared.module_state_clear */ +Py_CLEAR(clear_module_state->__pyx_CyFunctionType); + +/* Generator.module_state_clear */ +Py_CLEAR(clear_module_state->__pyx_GeneratorType); + +/* #### Code section: module_state_clear_end ### */ +return 0; +} +#endif +/* #### Code section: module_state_traverse ### */ +#if CYTHON_USE_MODULE_STATE +static CYTHON_SMALL_CODE int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { + __pyx_mstatetype *traverse_module_state = __Pyx_PyModule_GetState(m); + if (!traverse_module_state) return 0; + Py_VISIT(traverse_module_state->__pyx_d); + Py_VISIT(traverse_module_state->__pyx_b); + Py_VISIT(traverse_module_state->__pyx_cython_runtime); + __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_tuple); + __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_bytes); + __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_unicode); + Py_VISIT(traverse_module_state->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen); + Py_VISIT(traverse_module_state->__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen); + for (int i=0; i<3; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_codeobj_tab[i]); } + for (int i=0; i<80; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_string_tab[i]); } + for (int i=0; i<6; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_number_tab[i]); } +/* #### Code section: module_state_traverse_contents ### */ +/* CommonTypesMetaclass.module_state_traverse */ +Py_VISIT(traverse_module_state->__pyx_CommonTypesMetaclassType); + +/* CythonFunctionShared.module_state_traverse */ +Py_VISIT(traverse_module_state->__pyx_CyFunctionType); + +/* Generator.module_state_traverse */ +Py_VISIT(traverse_module_state->__pyx_GeneratorType); + +/* #### Code section: module_state_traverse_end ### */ +return 0; +} +#endif +/* #### Code section: module_code ### */ + +/* "fontTools/cu2qu/cu2qu.py":37 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.double) +*/ + +static CYTHON_INLINE double __pyx_f_9fontTools_5cu2qu_5cu2qu_dot(__pyx_t_double_complex __pyx_v_v1, __pyx_t_double_complex __pyx_v_v2) { + double __pyx_v_result; + double __pyx_r; + double __pyx_t_1; + int __pyx_t_2; + + /* "fontTools/cu2qu/cu2qu.py":51 + * double: Dot product. + * """ + * result = (v1 * v2.conjugate()).real # <<<<<<<<<<<<<< + * # When vectors are perpendicular (i.e. dot product is 0), the above expression may + * # yield slightly different results when running in pure Python vs C/Cython, +*/ + __pyx_t_1 = __Pyx_CREAL(__Pyx_c_prod_double(__pyx_v_v1, __Pyx_c_conj_double(__pyx_v_v2))); + __pyx_v_result = __pyx_t_1; + + /* "fontTools/cu2qu/cu2qu.py":58 + * # implementation. Because we are using the result in a denominator and catching + * # ZeroDivisionError (see `calc_intersect`), it's best to normalize the result here. + * if abs(result) < 1e-15: # <<<<<<<<<<<<<< + * result = 0.0 + * return result +*/ + __pyx_t_1 = fabs(__pyx_v_result); + __pyx_t_2 = (__pyx_t_1 < 1e-15); + if (__pyx_t_2) { + + /* "fontTools/cu2qu/cu2qu.py":59 + * # ZeroDivisionError (see `calc_intersect`), it's best to normalize the result here. + * if abs(result) < 1e-15: + * result = 0.0 # <<<<<<<<<<<<<< + * return result + * +*/ + __pyx_v_result = 0.0; + + /* "fontTools/cu2qu/cu2qu.py":58 + * # implementation. Because we are using the result in a denominator and catching + * # ZeroDivisionError (see `calc_intersect`), it's best to normalize the result here. + * if abs(result) < 1e-15: # <<<<<<<<<<<<<< + * result = 0.0 + * return result +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":60 + * if abs(result) < 1e-15: + * result = 0.0 + * return result # <<<<<<<<<<<<<< + * + * +*/ + __pyx_r = __pyx_v_result; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":37 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.double) +*/ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":63 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.locals(z=cython.complex, den=cython.double) + * @cython.locals(zr=cython.double, zi=cython.double) +*/ + +static PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu__complex_div_by_real(__pyx_t_double_complex __pyx_v_z, double __pyx_v_den) { + double __pyx_v_zr; + double __pyx_v_zi; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + double __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + size_t __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_complex_div_by_real", 0); + + /* "fontTools/cu2qu/cu2qu.py":75 + * https://github.com/fonttools/fonttools/issues/3928 + * """ + * zr = z.real # <<<<<<<<<<<<<< + * zi = z.imag + * return complex(zr / den, zi / den) +*/ + __pyx_t_1 = __Pyx_CREAL(__pyx_v_z); + __pyx_v_zr = __pyx_t_1; + + /* "fontTools/cu2qu/cu2qu.py":76 + * """ + * zr = z.real + * zi = z.imag # <<<<<<<<<<<<<< + * return complex(zr / den, zi / den) + * +*/ + __pyx_t_1 = __Pyx_CIMAG(__pyx_v_z); + __pyx_v_zi = __pyx_t_1; + + /* "fontTools/cu2qu/cu2qu.py":77 + * zr = z.real + * zi = z.imag + * return complex(zr / den, zi / den) # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = NULL; + if (unlikely(__pyx_v_den == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 77, __pyx_L1_error) + } + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_zr / __pyx_v_den)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 77, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(__pyx_v_den == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 77, __pyx_L1_error) + } + __pyx_t_5 = PyFloat_FromDouble((__pyx_v_zi / __pyx_v_den)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 77, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = 1; + { + PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_4, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyObject_FastCall((PyObject*)(&PyComplex_Type), __pyx_callargs+__pyx_t_6, (3-__pyx_t_6) | (__pyx_t_6*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":63 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.locals(z=cython.complex, den=cython.double) + * @cython.locals(zr=cython.double, zi=cython.double) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu._complex_div_by_real", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":80 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_points(__pyx_t_double_complex __pyx_v_a, __pyx_t_double_complex __pyx_v_b, __pyx_t_double_complex __pyx_v_c, __pyx_t_double_complex __pyx_v_d) { + __pyx_t_double_complex __pyx_v__1; + __pyx_t_double_complex __pyx_v__2; + __pyx_t_double_complex __pyx_v__3; + __pyx_t_double_complex __pyx_v__4; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + __pyx_t_double_complex __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("calc_cubic_points", 0); + + /* "fontTools/cu2qu/cu2qu.py":87 + * ) + * def calc_cubic_points(a, b, c, d): + * _1 = d # <<<<<<<<<<<<<< + * _2 = _complex_div_by_real(c, 3.0) + d + * _3 = _complex_div_by_real(b + c, 3.0) + _2 +*/ + __pyx_v__1 = __pyx_v_d; + + /* "fontTools/cu2qu/cu2qu.py":88 + * def calc_cubic_points(a, b, c, d): + * _1 = d + * _2 = _complex_div_by_real(c, 3.0) + d # <<<<<<<<<<<<<< + * _3 = _complex_div_by_real(b + c, 3.0) + _2 + * _4 = a + d + c + b +*/ + __pyx_t_1 = __pyx_f_9fontTools_5cu2qu_5cu2qu__complex_div_by_real(__pyx_v_c, 3.0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyComplex_FromComplex(__pyx_v_d); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_Add(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_3); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 88, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v__2 = __pyx_t_4; + + /* "fontTools/cu2qu/cu2qu.py":89 + * _1 = d + * _2 = _complex_div_by_real(c, 3.0) + d + * _3 = _complex_div_by_real(b + c, 3.0) + _2 # <<<<<<<<<<<<<< + * _4 = a + d + c + b + * return _1, _2, _3, _4 +*/ + __pyx_t_3 = __pyx_f_9fontTools_5cu2qu_5cu2qu__complex_div_by_real(__Pyx_c_sum_double(__pyx_v_b, __pyx_v_c), 3.0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __pyx_PyComplex_FromComplex(__pyx_v__2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyNumber_Add(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 89, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v__3 = __pyx_t_4; + + /* "fontTools/cu2qu/cu2qu.py":90 + * _2 = _complex_div_by_real(c, 3.0) + d + * _3 = _complex_div_by_real(b + c, 3.0) + _2 + * _4 = a + d + c + b # <<<<<<<<<<<<<< + * return _1, _2, _3, _4 + * +*/ + __pyx_v__4 = __Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__pyx_v_a, __pyx_v_d), __pyx_v_c), __pyx_v_b); + + /* "fontTools/cu2qu/cu2qu.py":91 + * _3 = _complex_div_by_real(b + c, 3.0) + _2 + * _4 = a + d + c + b + * return _1, _2, _3, _4 # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v__1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyComplex_FromComplex(__pyx_v__2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_PyComplex_FromComplex(__pyx_v__3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_v__4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 91, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_2) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_3) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_5) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_5 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":80 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.calc_cubic_points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":94 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_parameters(__pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3) { + __pyx_t_double_complex __pyx_v_a; + __pyx_t_double_complex __pyx_v_b; + __pyx_t_double_complex __pyx_v_c; + __pyx_t_double_complex __pyx_v_d; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("calc_cubic_parameters", 0); + + /* "fontTools/cu2qu/cu2qu.py":101 + * @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) + * def calc_cubic_parameters(p0, p1, p2, p3): + * c = (p1 - p0) * 3.0 # <<<<<<<<<<<<<< + * b = (p2 - p1) * 3.0 - c + * d = p0 +*/ + __pyx_v_c = __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_p1, __pyx_v_p0), __pyx_t_double_complex_from_parts(3.0, 0)); + + /* "fontTools/cu2qu/cu2qu.py":102 + * def calc_cubic_parameters(p0, p1, p2, p3): + * c = (p1 - p0) * 3.0 + * b = (p2 - p1) * 3.0 - c # <<<<<<<<<<<<<< + * d = p0 + * a = p3 - d - c - b +*/ + __pyx_v_b = __Pyx_c_diff_double(__Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_p2, __pyx_v_p1), __pyx_t_double_complex_from_parts(3.0, 0)), __pyx_v_c); + + /* "fontTools/cu2qu/cu2qu.py":103 + * c = (p1 - p0) * 3.0 + * b = (p2 - p1) * 3.0 - c + * d = p0 # <<<<<<<<<<<<<< + * a = p3 - d - c - b + * return a, b, c, d +*/ + __pyx_v_d = __pyx_v_p0; + + /* "fontTools/cu2qu/cu2qu.py":104 + * b = (p2 - p1) * 3.0 - c + * d = p0 + * a = p3 - d - c - b # <<<<<<<<<<<<<< + * return a, b, c, d + * +*/ + __pyx_v_a = __Pyx_c_diff_double(__Pyx_c_diff_double(__Pyx_c_diff_double(__pyx_v_p3, __pyx_v_d), __pyx_v_c), __pyx_v_b); + + /* "fontTools/cu2qu/cu2qu.py":105 + * d = p0 + * a = p3 - d - c - b + * return a, b, c, d # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_a); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_PyComplex_FromComplex(__pyx_v_b); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_PyComplex_FromComplex(__pyx_v_c); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_PyComplex_FromComplex(__pyx_v_d); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 105, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 105, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2) != (0)) __PYX_ERR(0, 105, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3) != (0)) __PYX_ERR(0, 105, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4) != (0)) __PYX_ERR(0, 105, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":94 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.calc_cubic_parameters", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":108 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_n_iter(__pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3, PyObject *__pyx_v_n) { + PyObject *__pyx_v_a = NULL; + PyObject *__pyx_v_b = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *(*__pyx_t_6)(PyObject *); + __pyx_t_double_complex __pyx_t_7; + __pyx_t_double_complex __pyx_t_8; + __pyx_t_double_complex __pyx_t_9; + __pyx_t_double_complex __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + size_t __pyx_t_14; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("split_cubic_into_n_iter", 0); + + /* "fontTools/cu2qu/cu2qu.py":130 + * """ + * # Hand-coded special-cases + * if n == 2: # <<<<<<<<<<<<<< + * return iter(split_cubic_into_two(p0, p1, p2, p3)) + * if n == 3: +*/ + __pyx_t_1 = (__Pyx_PyLong_BoolEqObjC(__pyx_v_n, __pyx_mstate_global->__pyx_int_2, 2, 0)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 130, __pyx_L1_error) + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":131 + * # Hand-coded special-cases + * if n == 2: + * return iter(split_cubic_into_two(p0, p1, p2, p3)) # <<<<<<<<<<<<<< + * if n == 3: + * return iter(split_cubic_into_three(p0, p1, p2, p3)) +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":130 + * """ + * # Hand-coded special-cases + * if n == 2: # <<<<<<<<<<<<<< + * return iter(split_cubic_into_two(p0, p1, p2, p3)) + * if n == 3: +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":132 + * if n == 2: + * return iter(split_cubic_into_two(p0, p1, p2, p3)) + * if n == 3: # <<<<<<<<<<<<<< + * return iter(split_cubic_into_three(p0, p1, p2, p3)) + * if n == 4: +*/ + __pyx_t_1 = (__Pyx_PyLong_BoolEqObjC(__pyx_v_n, __pyx_mstate_global->__pyx_int_3, 3, 0)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 132, __pyx_L1_error) + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":133 + * return iter(split_cubic_into_two(p0, p1, p2, p3)) + * if n == 3: + * return iter(split_cubic_into_three(p0, p1, p2, p3)) # <<<<<<<<<<<<<< + * if n == 4: + * a, b = split_cubic_into_two(p0, p1, p2, p3) +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_three(__pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":132 + * if n == 2: + * return iter(split_cubic_into_two(p0, p1, p2, p3)) + * if n == 3: # <<<<<<<<<<<<<< + * return iter(split_cubic_into_three(p0, p1, p2, p3)) + * if n == 4: +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":134 + * if n == 3: + * return iter(split_cubic_into_three(p0, p1, p2, p3)) + * if n == 4: # <<<<<<<<<<<<<< + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( +*/ + __pyx_t_1 = (__Pyx_PyLong_BoolEqObjC(__pyx_v_n, __pyx_mstate_global->__pyx_int_4, 4, 0)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 134, __pyx_L1_error) + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":135 + * return iter(split_cubic_into_three(p0, p1, p2, p3)) + * if n == 4: + * a, b = split_cubic_into_two(p0, p1, p2, p3) # <<<<<<<<<<<<<< + * return iter( + * split_cubic_into_two(a[0], a[1], a[2], a[3]) +*/ + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) { + PyObject* sequence = __pyx_t_2; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 135, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_4); + } else { + __pyx_t_3 = __Pyx_PyList_GetItemRefFast(sequence, 0, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyList_GetItemRefFast(sequence, 1, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_4); + } + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 135, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_6 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); + index = 0; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L6_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_4 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_4)) goto __pyx_L6_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < (0)) __PYX_ERR(0, 135, __pyx_L1_error) + __pyx_t_6 = NULL; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L7_unpacking_done; + __pyx_L6_unpacking_failed:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 135, __pyx_L1_error) + __pyx_L7_unpacking_done:; + } + __pyx_v_a = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_b = __pyx_t_4; + __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":136 + * if n == 4: + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( # <<<<<<<<<<<<<< + * split_cubic_into_two(a[0], a[1], a[2], a[3]) + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) +*/ + __Pyx_XDECREF(__pyx_r); + + /* "fontTools/cu2qu/cu2qu.py":137 + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( + * split_cubic_into_two(a[0], a[1], a[2], a[3]) # <<<<<<<<<<<<<< + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) + * ) +*/ + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_a, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_a, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_a, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_a, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_10 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "fontTools/cu2qu/cu2qu.py":138 + * return iter( + * split_cubic_into_two(a[0], a[1], a[2], a[3]) + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) # <<<<<<<<<<<<<< + * ) + * if n == 6: +*/ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_b, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_b, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_b, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_b, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_t_10, __pyx_t_9, __pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyNumber_Add(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 138, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":136 + * if n == 4: + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( # <<<<<<<<<<<<<< + * split_cubic_into_two(a[0], a[1], a[2], a[3]) + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) +*/ + __pyx_t_4 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":134 + * if n == 3: + * return iter(split_cubic_into_three(p0, p1, p2, p3)) + * if n == 4: # <<<<<<<<<<<<<< + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":140 + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) + * ) + * if n == 6: # <<<<<<<<<<<<<< + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( +*/ + __pyx_t_1 = (__Pyx_PyLong_BoolEqObjC(__pyx_v_n, __pyx_mstate_global->__pyx_int_6, 6, 0)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 140, __pyx_L1_error) + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":141 + * ) + * if n == 6: + * a, b = split_cubic_into_two(p0, p1, p2, p3) # <<<<<<<<<<<<<< + * return iter( + * split_cubic_into_three(a[0], a[1], a[2], a[3]) +*/ + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if ((likely(PyTuple_CheckExact(__pyx_t_4))) || (PyList_CheckExact(__pyx_t_4))) { + PyObject* sequence = __pyx_t_4; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 141, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_2); + } else { + __pyx_t_3 = __Pyx_PyList_GetItemRefFast(sequence, 0, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyList_GetItemRefFast(sequence, 1, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_2); + } + #else + __pyx_t_3 = __Pyx_PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_5 = PyObject_GetIter(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); + index = 0; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L9_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_2 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_2)) goto __pyx_L9_unpacking_failed; + __Pyx_GOTREF(__pyx_t_2); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < (0)) __PYX_ERR(0, 141, __pyx_L1_error) + __pyx_t_6 = NULL; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L10_unpacking_done; + __pyx_L9_unpacking_failed:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 141, __pyx_L1_error) + __pyx_L10_unpacking_done:; + } + __pyx_v_a = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_b = __pyx_t_2; + __pyx_t_2 = 0; + + /* "fontTools/cu2qu/cu2qu.py":142 + * if n == 6: + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( # <<<<<<<<<<<<<< + * split_cubic_into_three(a[0], a[1], a[2], a[3]) + * + split_cubic_into_three(b[0], b[1], b[2], b[3]) +*/ + __Pyx_XDECREF(__pyx_r); + + /* "fontTools/cu2qu/cu2qu.py":143 + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( + * split_cubic_into_three(a[0], a[1], a[2], a[3]) # <<<<<<<<<<<<<< + * + split_cubic_into_three(b[0], b[1], b[2], b[3]) + * ) +*/ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_a, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_a, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_a, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_a, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_three(__pyx_t_7, __pyx_t_8, __pyx_t_9, __pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "fontTools/cu2qu/cu2qu.py":144 + * return iter( + * split_cubic_into_three(a[0], a[1], a[2], a[3]) + * + split_cubic_into_three(b[0], b[1], b[2], b[3]) # <<<<<<<<<<<<<< + * ) + * +*/ + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_b, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_10 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_b, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_b, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_b, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_three(__pyx_t_10, __pyx_t_9, __pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyNumber_Add(__pyx_t_4, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "fontTools/cu2qu/cu2qu.py":142 + * if n == 6: + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( # <<<<<<<<<<<<<< + * split_cubic_into_three(a[0], a[1], a[2], a[3]) + * + split_cubic_into_three(b[0], b[1], b[2], b[3]) +*/ + __pyx_t_2 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":140 + * + split_cubic_into_two(b[0], b[1], b[2], b[3]) + * ) + * if n == 6: # <<<<<<<<<<<<<< + * a, b = split_cubic_into_two(p0, p1, p2, p3) + * return iter( +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":147 + * ) + * + * return _split_cubic_into_n_gen(p0, p1, p2, p3, n) # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = NULL; + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_split_cubic_into_n_gen); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_v_p0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_11 = __pyx_PyComplex_FromComplex(__pyx_v_p1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_12 = __pyx_PyComplex_FromComplex(__pyx_v_p2); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_13 = __pyx_PyComplex_FromComplex(__pyx_v_p3); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_14 = 1; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4); + assert(__pyx_t_3); + PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx__function); + __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); + __pyx_t_14 = 0; + } + #endif + { + PyObject *__pyx_callargs[6] = {__pyx_t_3, __pyx_t_5, __pyx_t_11, __pyx_t_12, __pyx_t_13, __pyx_v_n}; + __pyx_t_2 = __Pyx_PyObject_FastCall((PyObject*)__pyx_t_4, __pyx_callargs+__pyx_t_14, (6-__pyx_t_14) | (__pyx_t_14*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":108 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.split_cubic_into_n_iter", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_a); + __Pyx_XDECREF(__pyx_v_b); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static PyObject *__pyx_gb_9fontTools_5cu2qu_5cu2qu_2generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */ + +/* "fontTools/cu2qu/cu2qu.py":150 + * + * + * @cython.locals( # <<<<<<<<<<<<<< + * p0=cython.complex, + * p1=cython.complex, +*/ + +/* Python wrapper */ +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_1_split_cubic_into_n_gen(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_9fontTools_5cu2qu_5cu2qu__split_cubic_into_n_gen, "_split_cubic_into_n_gen(double complex p0, double complex p1, double complex p2, double complex p3, int n)"); +static PyMethodDef __pyx_mdef_9fontTools_5cu2qu_5cu2qu_1_split_cubic_into_n_gen = {"_split_cubic_into_n_gen", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9fontTools_5cu2qu_5cu2qu_1_split_cubic_into_n_gen, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9fontTools_5cu2qu_5cu2qu__split_cubic_into_n_gen}; +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_1_split_cubic_into_n_gen(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + __pyx_t_double_complex __pyx_v_p0; + __pyx_t_double_complex __pyx_v_p1; + __pyx_t_double_complex __pyx_v_p2; + __pyx_t_double_complex __pyx_v_p3; + int __pyx_v_n; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[5] = {0,0,0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_split_cubic_into_n_gen (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_SIZE + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_p0,&__pyx_mstate_global->__pyx_n_u_p1,&__pyx_mstate_global->__pyx_n_u_p2,&__pyx_mstate_global->__pyx_n_u_p3,&__pyx_mstate_global->__pyx_n_u_n,0}; + const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; + if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 150, __pyx_L3_error) + if (__pyx_kwds_len > 0) { + switch (__pyx_nargs) { + case 5: + values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 150, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 4: + values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 150, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 3: + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 150, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 2: + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 150, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 1: + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 150, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "_split_cubic_into_n_gen", 0) < (0)) __PYX_ERR(0, 150, __pyx_L3_error) + for (Py_ssize_t i = __pyx_nargs; i < 5; i++) { + if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("_split_cubic_into_n_gen", 1, 5, 5, i); __PYX_ERR(0, 150, __pyx_L3_error) } + } + } else if (unlikely(__pyx_nargs != 5)) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 150, __pyx_L3_error) + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 150, __pyx_L3_error) + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 150, __pyx_L3_error) + values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 150, __pyx_L3_error) + values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 150, __pyx_L3_error) + } + __pyx_v_p0 = __Pyx_PyComplex_As___pyx_t_double_complex(values[0]); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L3_error) + __pyx_v_p1 = __Pyx_PyComplex_As___pyx_t_double_complex(values[1]); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L3_error) + __pyx_v_p2 = __Pyx_PyComplex_As___pyx_t_double_complex(values[2]); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L3_error) + __pyx_v_p3 = __Pyx_PyComplex_As___pyx_t_double_complex(values[3]); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L3_error) + __pyx_v_n = __Pyx_PyLong_As_int(values[4]); if (unlikely((__pyx_v_n == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L3_error) + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_split_cubic_into_n_gen", 1, 5, 5, __pyx_nargs); __PYX_ERR(0, 150, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu._split_cubic_into_n_gen", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_9fontTools_5cu2qu_5cu2qu__split_cubic_into_n_gen(__pyx_self, __pyx_v_p0, __pyx_v_p1, __pyx_v_p2, __pyx_v_p3, __pyx_v_n); + + /* function exit code */ + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu__split_cubic_into_n_gen(CYTHON_UNUSED PyObject *__pyx_self, __pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3, int __pyx_v_n) { + struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *__pyx_cur_scope; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("_split_cubic_into_n_gen", 0); + __pyx_cur_scope = (struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *)__pyx_tp_new_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen(__pyx_mstate_global->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen, __pyx_mstate_global->__pyx_empty_tuple, NULL); + if (unlikely(!__pyx_cur_scope)) { + __pyx_cur_scope = ((struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *)Py_None); + __Pyx_INCREF(Py_None); + __PYX_ERR(0, 150, __pyx_L1_error) + } else { + __Pyx_GOTREF((PyObject *)__pyx_cur_scope); + } + __pyx_cur_scope->__pyx_v_p0 = __pyx_v_p0; + __pyx_cur_scope->__pyx_v_p1 = __pyx_v_p1; + __pyx_cur_scope->__pyx_v_p2 = __pyx_v_p2; + __pyx_cur_scope->__pyx_v_p3 = __pyx_v_p3; + __pyx_cur_scope->__pyx_v_n = __pyx_v_n; + { + __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_9fontTools_5cu2qu_5cu2qu_2generator, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[0]), (PyObject *) __pyx_cur_scope, __pyx_mstate_global->__pyx_n_u_split_cubic_into_n_gen, __pyx_mstate_global->__pyx_n_u_split_cubic_into_n_gen, __pyx_mstate_global->__pyx_n_u_fontTools_cu2qu_cu2qu); if (unlikely(!gen)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_DECREF(__pyx_cur_scope); + __Pyx_RefNannyFinishContext(); + return (PyObject *) gen; + } + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu._split_cubic_into_n_gen", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_DECREF((PyObject *)__pyx_cur_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_gb_9fontTools_5cu2qu_5cu2qu_2generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value) /* generator body */ +{ + struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *__pyx_cur_scope = ((struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *)__pyx_generator->closure); + PyObject *__pyx_r = NULL; + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *(*__pyx_t_7)(PyObject *); + __pyx_t_double_complex __pyx_t_8; + __pyx_t_double_complex __pyx_t_9; + __pyx_t_double_complex __pyx_t_10; + __pyx_t_double_complex __pyx_t_11; + int __pyx_t_12; + int __pyx_t_13; + int __pyx_t_14; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_split_cubic_into_n_gen", 0); + switch (__pyx_generator->resume_label) { + case 0: goto __pyx_L3_first_run; + case 1: goto __pyx_L8_resume_from_yield; + default: /* CPython raises the right error here */ + __Pyx_RefNannyFinishContext(); + return NULL; + } + __pyx_L3_first_run:; + if (unlikely(__pyx_sent_value != Py_None)) { + if (unlikely(__pyx_sent_value)) PyErr_SetString(PyExc_TypeError, "can't send non-None value to a just-started generator"); + __PYX_ERR(0, 150, __pyx_L1_error) + } + + /* "fontTools/cu2qu/cu2qu.py":165 + * ) + * def _split_cubic_into_n_gen(p0, p1, p2, p3, n): + * a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3) # <<<<<<<<<<<<<< + * dt = 1 / n + * delta_2 = dt * dt +*/ + __pyx_t_1 = __pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_parameters(__pyx_cur_scope->__pyx_v_p0, __pyx_cur_scope->__pyx_v_p1, __pyx_cur_scope->__pyx_v_p2, __pyx_cur_scope->__pyx_v_p3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 4)) { + if (size > 4) __Pyx_RaiseTooManyValuesError(4); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 165, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); + __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 2); + __Pyx_INCREF(__pyx_t_4); + __pyx_t_5 = PyTuple_GET_ITEM(sequence, 3); + __Pyx_INCREF(__pyx_t_5); + } else { + __pyx_t_2 = __Pyx_PyList_GetItemRefFast(sequence, 0, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyList_GetItemRefFast(sequence, 1, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyList_GetItemRefFast(sequence, 2, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyList_GetItemRefFast(sequence, 3, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_5); + } + #else + { + Py_ssize_t i; + PyObject** temps[4] = {&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5}; + for (i=0; i < 4; i++) { + PyObject* item = __Pyx_PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(item); + *(temps[i]) = item; + } + } + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + PyObject** temps[4] = {&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5}; + __pyx_t_6 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_7 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); + for (index=0; index < 4; index++) { + PyObject* item = __pyx_t_7(__pyx_t_6); if (unlikely(!item)) goto __pyx_L4_unpacking_failed; + __Pyx_GOTREF(item); + *(temps[index]) = item; + } + if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 4) < (0)) __PYX_ERR(0, 165, __pyx_L1_error) + __pyx_t_7 = NULL; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L5_unpacking_done; + __pyx_L4_unpacking_failed:; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_7 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 165, __pyx_L1_error) + __pyx_L5_unpacking_done:; + } + __pyx_t_8 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_3); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_10 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_11 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_5); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_cur_scope->__pyx_v_a = __pyx_t_8; + __pyx_cur_scope->__pyx_v_b = __pyx_t_9; + __pyx_cur_scope->__pyx_v_c = __pyx_t_10; + __pyx_cur_scope->__pyx_v_d = __pyx_t_11; + + /* "fontTools/cu2qu/cu2qu.py":166 + * def _split_cubic_into_n_gen(p0, p1, p2, p3, n): + * a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3) + * dt = 1 / n # <<<<<<<<<<<<<< + * delta_2 = dt * dt + * delta_3 = dt * delta_2 +*/ + if (unlikely(__pyx_cur_scope->__pyx_v_n == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 166, __pyx_L1_error) + } + __pyx_cur_scope->__pyx_v_dt = (1.0 / ((double)__pyx_cur_scope->__pyx_v_n)); + + /* "fontTools/cu2qu/cu2qu.py":167 + * a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3) + * dt = 1 / n + * delta_2 = dt * dt # <<<<<<<<<<<<<< + * delta_3 = dt * delta_2 + * for i in range(n): +*/ + __pyx_cur_scope->__pyx_v_delta_2 = (__pyx_cur_scope->__pyx_v_dt * __pyx_cur_scope->__pyx_v_dt); + + /* "fontTools/cu2qu/cu2qu.py":168 + * dt = 1 / n + * delta_2 = dt * dt + * delta_3 = dt * delta_2 # <<<<<<<<<<<<<< + * for i in range(n): + * t1 = i * dt +*/ + __pyx_cur_scope->__pyx_v_delta_3 = (__pyx_cur_scope->__pyx_v_dt * __pyx_cur_scope->__pyx_v_delta_2); + + /* "fontTools/cu2qu/cu2qu.py":169 + * delta_2 = dt * dt + * delta_3 = dt * delta_2 + * for i in range(n): # <<<<<<<<<<<<<< + * t1 = i * dt + * t1_2 = t1 * t1 +*/ + __pyx_t_12 = __pyx_cur_scope->__pyx_v_n; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_cur_scope->__pyx_v_i = __pyx_t_14; + + /* "fontTools/cu2qu/cu2qu.py":170 + * delta_3 = dt * delta_2 + * for i in range(n): + * t1 = i * dt # <<<<<<<<<<<<<< + * t1_2 = t1 * t1 + * # calc new a, b, c and d +*/ + __pyx_cur_scope->__pyx_v_t1 = (__pyx_cur_scope->__pyx_v_i * __pyx_cur_scope->__pyx_v_dt); + + /* "fontTools/cu2qu/cu2qu.py":171 + * for i in range(n): + * t1 = i * dt + * t1_2 = t1 * t1 # <<<<<<<<<<<<<< + * # calc new a, b, c and d + * a1 = a * delta_3 +*/ + __pyx_cur_scope->__pyx_v_t1_2 = (__pyx_cur_scope->__pyx_v_t1 * __pyx_cur_scope->__pyx_v_t1); + + /* "fontTools/cu2qu/cu2qu.py":173 + * t1_2 = t1 * t1 + * # calc new a, b, c and d + * a1 = a * delta_3 # <<<<<<<<<<<<<< + * b1 = (3 * a * t1 + b) * delta_2 + * c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt +*/ + __pyx_cur_scope->__pyx_v_a1 = __Pyx_c_prod_double(__pyx_cur_scope->__pyx_v_a, __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_delta_3, 0)); + + /* "fontTools/cu2qu/cu2qu.py":174 + * # calc new a, b, c and d + * a1 = a * delta_3 + * b1 = (3 * a * t1 + b) * delta_2 # <<<<<<<<<<<<<< + * c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt + * d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d +*/ + __pyx_cur_scope->__pyx_v_b1 = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_prod_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __pyx_cur_scope->__pyx_v_a), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1, 0)), __pyx_cur_scope->__pyx_v_b), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_delta_2, 0)); + + /* "fontTools/cu2qu/cu2qu.py":175 + * a1 = a * delta_3 + * b1 = (3 * a * t1 + b) * delta_2 + * c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt # <<<<<<<<<<<<<< + * d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d + * yield calc_cubic_points(a1, b1, c1, d1) +*/ + __pyx_cur_scope->__pyx_v_c1 = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_prod_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(2, 0), __pyx_cur_scope->__pyx_v_b), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1, 0)), __pyx_cur_scope->__pyx_v_c), __Pyx_c_prod_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __pyx_cur_scope->__pyx_v_a), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1_2, 0))), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_dt, 0)); + + /* "fontTools/cu2qu/cu2qu.py":176 + * b1 = (3 * a * t1 + b) * delta_2 + * c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt + * d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d # <<<<<<<<<<<<<< + * yield calc_cubic_points(a1, b1, c1, d1) + * +*/ + __pyx_cur_scope->__pyx_v_d1 = __Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_prod_double(__Pyx_c_prod_double(__pyx_cur_scope->__pyx_v_a, __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1, 0)), __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1_2, 0)), __Pyx_c_prod_double(__pyx_cur_scope->__pyx_v_b, __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1_2, 0))), __Pyx_c_prod_double(__pyx_cur_scope->__pyx_v_c, __pyx_t_double_complex_from_parts(__pyx_cur_scope->__pyx_v_t1, 0))), __pyx_cur_scope->__pyx_v_d); + + /* "fontTools/cu2qu/cu2qu.py":177 + * c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt + * d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d + * yield calc_cubic_points(a1, b1, c1, d1) # <<<<<<<<<<<<<< + * + * +*/ + __pyx_t_1 = __pyx_f_9fontTools_5cu2qu_5cu2qu_calc_cubic_points(__pyx_cur_scope->__pyx_v_a1, __pyx_cur_scope->__pyx_v_b1, __pyx_cur_scope->__pyx_v_c1, __pyx_cur_scope->__pyx_v_d1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + __pyx_cur_scope->__pyx_t_0 = __pyx_t_12; + __pyx_cur_scope->__pyx_t_1 = __pyx_t_13; + __pyx_cur_scope->__pyx_t_2 = __pyx_t_14; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + /* return from generator, yielding value */ + __pyx_generator->resume_label = 1; + return __pyx_r; + __pyx_L8_resume_from_yield:; + __pyx_t_12 = __pyx_cur_scope->__pyx_t_0; + __pyx_t_13 = __pyx_cur_scope->__pyx_t_1; + __pyx_t_14 = __pyx_cur_scope->__pyx_t_2; + if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 177, __pyx_L1_error) + } + CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope); + + /* "fontTools/cu2qu/cu2qu.py":150 + * + * + * @cython.locals( # <<<<<<<<<<<<<< + * p0=cython.complex, + * p1=cython.complex, +*/ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + if (__Pyx_PyErr_Occurred()) { + __Pyx_Generator_Replace_StopIteration(0); + __Pyx_AddTraceback("_split_cubic_into_n_gen", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + #if !CYTHON_USE_EXC_INFO_STACK + __Pyx_Coroutine_ResetAndClearException(__pyx_generator); + #endif + __pyx_generator->resume_label = -1; + __Pyx_Coroutine_clear((PyObject*)__pyx_generator); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":180 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_two(__pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3) { + __pyx_t_double_complex __pyx_v_mid; + __pyx_t_double_complex __pyx_v_deriv3; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __pyx_t_double_complex __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("split_cubic_into_two", 0); + + /* "fontTools/cu2qu/cu2qu.py":201 + * values). + * """ + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 # <<<<<<<<<<<<<< + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return ( +*/ + __pyx_v_mid = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__pyx_v_p0, __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __Pyx_c_sum_double(__pyx_v_p1, __pyx_v_p2))), __pyx_v_p3), __pyx_t_double_complex_from_parts(0.125, 0)); + + /* "fontTools/cu2qu/cu2qu.py":202 + * """ + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 # <<<<<<<<<<<<<< + * return ( + * (p0, (p0 + p1) * 0.5, mid - deriv3, mid), +*/ + __pyx_v_deriv3 = __Pyx_c_prod_double(__Pyx_c_diff_double(__Pyx_c_diff_double(__Pyx_c_sum_double(__pyx_v_p3, __pyx_v_p2), __pyx_v_p1), __pyx_v_p0), __pyx_t_double_complex_from_parts(0.125, 0)); + + /* "fontTools/cu2qu/cu2qu.py":203 + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return ( # <<<<<<<<<<<<<< + * (p0, (p0 + p1) * 0.5, mid - deriv3, mid), + * (mid, mid + deriv3, (p2 + p3) * 0.5, p3), +*/ + __Pyx_XDECREF(__pyx_r); + + /* "fontTools/cu2qu/cu2qu.py":204 + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return ( + * (p0, (p0 + p1) * 0.5, mid - deriv3, mid), # <<<<<<<<<<<<<< + * (mid, mid + deriv3, (p2 + p3) * 0.5, p3), + * ) +*/ + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_p0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_c_prod_double(__Pyx_c_sum_double(__pyx_v_p0, __pyx_v_p1), __pyx_t_double_complex_from_parts(0.5, 0)); + __pyx_t_3 = __pyx_PyComplex_FromComplex(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_c_diff_double(__pyx_v_mid, __pyx_v_deriv3); + __pyx_t_4 = __pyx_PyComplex_FromComplex(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_v_mid); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_3) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_4) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_5) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + + /* "fontTools/cu2qu/cu2qu.py":205 + * return ( + * (p0, (p0 + p1) * 0.5, mid - deriv3, mid), + * (mid, mid + deriv3, (p2 + p3) * 0.5, p3), # <<<<<<<<<<<<<< + * ) + * +*/ + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_v_mid); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = __Pyx_c_sum_double(__pyx_v_mid, __pyx_v_deriv3); + __pyx_t_4 = __pyx_PyComplex_FromComplex(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_c_prod_double(__Pyx_c_sum_double(__pyx_v_p2, __pyx_v_p3), __pyx_t_double_complex_from_parts(0.5, 0)); + __pyx_t_3 = __pyx_PyComplex_FromComplex(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_p3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyTuple_New(4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5) != (0)) __PYX_ERR(0, 205, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_4); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_4) != (0)) __PYX_ERR(0, 205, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_3); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 2, __pyx_t_3) != (0)) __PYX_ERR(0, 205, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 3, __pyx_t_1) != (0)) __PYX_ERR(0, 205, __pyx_L1_error); + __pyx_t_5 = 0; + __pyx_t_4 = 0; + __pyx_t_3 = 0; + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":204 + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return ( + * (p0, (p0 + p1) * 0.5, mid - deriv3, mid), # <<<<<<<<<<<<<< + * (mid, mid + deriv3, (p2 + p3) * 0.5, p3), + * ) +*/ + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_7) != (0)) __PYX_ERR(0, 204, __pyx_L1_error); + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":180 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.split_cubic_into_two", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":209 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_three(__pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3) { + __pyx_t_double_complex __pyx_v_mid1; + __pyx_t_double_complex __pyx_v_deriv1; + __pyx_t_double_complex __pyx_v_mid2; + __pyx_t_double_complex __pyx_v_deriv2; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __pyx_t_double_complex __pyx_t_2; + __pyx_t_double_complex __pyx_t_3; + __pyx_t_double_complex __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("split_cubic_into_three", 0); + + /* "fontTools/cu2qu/cu2qu.py":238 + * values). + * """ + * mid1 = (8 * p0 + 12 * p1 + 6 * p2 + p3) * (1 / 27) # <<<<<<<<<<<<<< + * deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27) + * mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) +*/ + __pyx_v_mid1 = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(8, 0), __pyx_v_p0), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(12, 0), __pyx_v_p1)), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(6, 0), __pyx_v_p2)), __pyx_v_p3), __pyx_t_double_complex_from_parts((1.0 / 27.0), 0)); + + /* "fontTools/cu2qu/cu2qu.py":239 + * """ + * mid1 = (8 * p0 + 12 * p1 + 6 * p2 + p3) * (1 / 27) + * deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27) # <<<<<<<<<<<<<< + * mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) +*/ + __pyx_v_deriv1 = __Pyx_c_prod_double(__Pyx_c_diff_double(__Pyx_c_sum_double(__pyx_v_p3, __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __pyx_v_p2)), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(4, 0), __pyx_v_p0)), __pyx_t_double_complex_from_parts((1.0 / 27.0), 0)); + + /* "fontTools/cu2qu/cu2qu.py":240 + * mid1 = (8 * p0 + 12 * p1 + 6 * p2 + p3) * (1 / 27) + * deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27) + * mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) # <<<<<<<<<<<<<< + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) + * return ( +*/ + __pyx_v_mid2 = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__pyx_v_p0, __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(6, 0), __pyx_v_p1)), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(12, 0), __pyx_v_p2)), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(8, 0), __pyx_v_p3)), __pyx_t_double_complex_from_parts((1.0 / 27.0), 0)); + + /* "fontTools/cu2qu/cu2qu.py":241 + * deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27) + * mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) # <<<<<<<<<<<<<< + * return ( + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), +*/ + __pyx_v_deriv2 = __Pyx_c_prod_double(__Pyx_c_diff_double(__Pyx_c_diff_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(4, 0), __pyx_v_p3), __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __pyx_v_p1)), __pyx_v_p0), __pyx_t_double_complex_from_parts((1.0 / 27.0), 0)); + + /* "fontTools/cu2qu/cu2qu.py":242 + * mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) + * return ( # <<<<<<<<<<<<<< + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), + * (mid1, mid1 + deriv1, mid2 - deriv2, mid2), +*/ + __Pyx_XDECREF(__pyx_r); + + /* "fontTools/cu2qu/cu2qu.py":243 + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) + * return ( + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), # <<<<<<<<<<<<<< + * (mid1, mid1 + deriv1, mid2 - deriv2, mid2), + * (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3), +*/ + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_p0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_c_sum_double(__Pyx_c_prod_double(__pyx_t_double_complex_from_parts(2, 0), __pyx_v_p0), __pyx_v_p1); + __pyx_t_3 = __pyx_t_double_complex_from_parts(3.0, 0); + if (unlikely(__Pyx_c_is_zero_double(__pyx_t_3))) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 243, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_c_quot_double(__pyx_t_2, __pyx_t_3); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_c_diff_double(__pyx_v_mid1, __pyx_v_deriv1); + __pyx_t_6 = __pyx_PyComplex_FromComplex(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __pyx_PyComplex_FromComplex(__pyx_v_mid1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyTuple_New(4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_5) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_6) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_8, 3, __pyx_t_7) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + + /* "fontTools/cu2qu/cu2qu.py":244 + * return ( + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), + * (mid1, mid1 + deriv1, mid2 - deriv2, mid2), # <<<<<<<<<<<<<< + * (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3), + * ) +*/ + __pyx_t_7 = __pyx_PyComplex_FromComplex(__pyx_v_mid1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 244, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = __Pyx_c_sum_double(__pyx_v_mid1, __pyx_v_deriv1); + __pyx_t_6 = __pyx_PyComplex_FromComplex(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 244, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_4 = __Pyx_c_diff_double(__pyx_v_mid2, __pyx_v_deriv2); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 244, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_mid2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 244, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = PyTuple_New(4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 244, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7) != (0)) __PYX_ERR(0, 244, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_t_6) != (0)) __PYX_ERR(0, 244, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 2, __pyx_t_5) != (0)) __PYX_ERR(0, 244, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_9, 3, __pyx_t_1) != (0)) __PYX_ERR(0, 244, __pyx_L1_error); + __pyx_t_7 = 0; + __pyx_t_6 = 0; + __pyx_t_5 = 0; + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":245 + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), + * (mid1, mid1 + deriv1, mid2 - deriv2, mid2), + * (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3), # <<<<<<<<<<<<<< + * ) + * +*/ + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_mid2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_c_sum_double(__pyx_v_mid2, __pyx_v_deriv2); + __pyx_t_5 = __pyx_PyComplex_FromComplex(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_c_sum_double(__pyx_v_p2, __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(2, 0), __pyx_v_p3)); + __pyx_t_3 = __pyx_t_double_complex_from_parts(3.0, 0); + if (unlikely(__Pyx_c_is_zero_double(__pyx_t_3))) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 245, __pyx_L1_error) + } + __pyx_t_2 = __Pyx_c_quot_double(__pyx_t_4, __pyx_t_3); + __pyx_t_6 = __pyx_PyComplex_FromComplex(__pyx_t_2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __pyx_PyComplex_FromComplex(__pyx_v_p3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_10 = PyTuple_New(4); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 245, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_5) != (0)) __PYX_ERR(0, 245, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 2, __pyx_t_6) != (0)) __PYX_ERR(0, 245, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_7); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_10, 3, __pyx_t_7) != (0)) __PYX_ERR(0, 245, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + + /* "fontTools/cu2qu/cu2qu.py":243 + * deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) + * return ( + * (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), # <<<<<<<<<<<<<< + * (mid1, mid1 + deriv1, mid2 - deriv2, mid2), + * (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3), +*/ + __pyx_t_7 = PyTuple_New(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 243, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_8); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_8) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_9); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_9) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_10); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 2, __pyx_t_10) != (0)) __PYX_ERR(0, 243, __pyx_L1_error); + __pyx_t_8 = 0; + __pyx_t_9 = 0; + __pyx_t_10 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":209 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals( +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.split_cubic_into_three", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":249 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.complex) +*/ + +static CYTHON_INLINE __pyx_t_double_complex __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_control(double __pyx_v_t, __pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3) { + __pyx_t_double_complex __pyx_v__p1; + __pyx_t_double_complex __pyx_v__p2; + __pyx_t_double_complex __pyx_r; + + /* "fontTools/cu2qu/cu2qu.py":273 + * complex: Location of candidate control point on quadratic curve. + * """ + * _p1 = p0 + (p1 - p0) * 1.5 # <<<<<<<<<<<<<< + * _p2 = p3 + (p2 - p3) * 1.5 + * return _p1 + (_p2 - _p1) * t +*/ + __pyx_v__p1 = __Pyx_c_sum_double(__pyx_v_p0, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_p1, __pyx_v_p0), __pyx_t_double_complex_from_parts(1.5, 0))); + + /* "fontTools/cu2qu/cu2qu.py":274 + * """ + * _p1 = p0 + (p1 - p0) * 1.5 + * _p2 = p3 + (p2 - p3) * 1.5 # <<<<<<<<<<<<<< + * return _p1 + (_p2 - _p1) * t + * +*/ + __pyx_v__p2 = __Pyx_c_sum_double(__pyx_v_p3, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_p2, __pyx_v_p3), __pyx_t_double_complex_from_parts(1.5, 0))); + + /* "fontTools/cu2qu/cu2qu.py":275 + * _p1 = p0 + (p1 - p0) * 1.5 + * _p2 = p3 + (p2 - p3) * 1.5 + * return _p1 + (_p2 - _p1) * t # <<<<<<<<<<<<<< + * + * +*/ + __pyx_r = __Pyx_c_sum_double(__pyx_v__p1, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v__p2, __pyx_v__p1), __pyx_t_double_complex_from_parts(__pyx_v_t, 0))); + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":249 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.complex) +*/ + + /* function exit code */ + __pyx_L0:; + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":278 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.complex) +*/ + +static CYTHON_INLINE __pyx_t_double_complex __pyx_f_9fontTools_5cu2qu_5cu2qu_calc_intersect(__pyx_t_double_complex __pyx_v_a, __pyx_t_double_complex __pyx_v_b, __pyx_t_double_complex __pyx_v_c, __pyx_t_double_complex __pyx_v_d) { + __pyx_t_double_complex __pyx_v_ab; + __pyx_t_double_complex __pyx_v_cd; + __pyx_t_double_complex __pyx_v_p; + double __pyx_v_h; + __pyx_t_double_complex __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + double __pyx_t_4; + double __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + PyObject *__pyx_t_15 = NULL; + size_t __pyx_t_16; + __pyx_t_double_complex __pyx_t_17; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("calc_intersect", 0); + + /* "fontTools/cu2qu/cu2qu.py":296 + * if no intersection was found. + * """ + * ab = b - a # <<<<<<<<<<<<<< + * cd = d - c + * p = ab * 1j +*/ + __pyx_v_ab = __Pyx_c_diff_double(__pyx_v_b, __pyx_v_a); + + /* "fontTools/cu2qu/cu2qu.py":297 + * """ + * ab = b - a + * cd = d - c # <<<<<<<<<<<<<< + * p = ab * 1j + * try: +*/ + __pyx_v_cd = __Pyx_c_diff_double(__pyx_v_d, __pyx_v_c); + + /* "fontTools/cu2qu/cu2qu.py":298 + * ab = b - a + * cd = d - c + * p = ab * 1j # <<<<<<<<<<<<<< + * try: + * h = dot(p, a - c) / dot(p, cd) +*/ + __pyx_v_p = __Pyx_c_prod_double(__pyx_v_ab, __pyx_t_double_complex_from_parts(0, 1.0)); + + /* "fontTools/cu2qu/cu2qu.py":299 + * cd = d - c + * p = ab * 1j + * try: # <<<<<<<<<<<<<< + * h = dot(p, a - c) / dot(p, cd) + * except ZeroDivisionError: +*/ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "fontTools/cu2qu/cu2qu.py":300 + * p = ab * 1j + * try: + * h = dot(p, a - c) / dot(p, cd) # <<<<<<<<<<<<<< + * except ZeroDivisionError: + * # if 3 or 4 points are equal, we do have an intersection despite the zero-div: +*/ + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_dot(__pyx_v_p, __Pyx_c_diff_double(__pyx_v_a, __pyx_v_c)); if (unlikely(__pyx_t_4 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 300, __pyx_L3_error) + __pyx_t_5 = __pyx_f_9fontTools_5cu2qu_5cu2qu_dot(__pyx_v_p, __pyx_v_cd); if (unlikely(__pyx_t_5 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 300, __pyx_L3_error) + if (unlikely(__pyx_t_5 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 300, __pyx_L3_error) + } + __pyx_v_h = (__pyx_t_4 / __pyx_t_5); + + /* "fontTools/cu2qu/cu2qu.py":299 + * cd = d - c + * p = ab * 1j + * try: # <<<<<<<<<<<<<< + * h = dot(p, a - c) / dot(p, cd) + * except ZeroDivisionError: +*/ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + + /* "fontTools/cu2qu/cu2qu.py":301 + * try: + * h = dot(p, a - c) / dot(p, cd) + * except ZeroDivisionError: # <<<<<<<<<<<<<< + * # if 3 or 4 points are equal, we do have an intersection despite the zero-div: + * # return one of the off-curves so that the algorithm can attempt a one-curve +*/ + __pyx_t_6 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(((PyTypeObject*)PyExc_ZeroDivisionError)))); + if (__pyx_t_6) { + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.calc_intersect", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9) < 0) __PYX_ERR(0, 301, __pyx_L5_except_error) + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_9); + + /* "fontTools/cu2qu/cu2qu.py":306 + * # solution if it's within tolerance: + * # https://github.com/linebender/kurbo/pull/484 + * if b == c and (a == b or c == d): # <<<<<<<<<<<<<< + * return b + * return complex(NAN, NAN) +*/ + __pyx_t_11 = (__Pyx_c_eq_double(__pyx_v_b, __pyx_v_c)); + if (__pyx_t_11) { + } else { + __pyx_t_10 = __pyx_t_11; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_11 = (__Pyx_c_eq_double(__pyx_v_a, __pyx_v_b)); + if (!__pyx_t_11) { + } else { + __pyx_t_10 = __pyx_t_11; + goto __pyx_L12_bool_binop_done; + } + __pyx_t_11 = (__Pyx_c_eq_double(__pyx_v_c, __pyx_v_d)); + __pyx_t_10 = __pyx_t_11; + __pyx_L12_bool_binop_done:; + if (__pyx_t_10) { + + /* "fontTools/cu2qu/cu2qu.py":307 + * # https://github.com/linebender/kurbo/pull/484 + * if b == c and (a == b or c == d): + * return b # <<<<<<<<<<<<<< + * return complex(NAN, NAN) + * return c + cd * h +*/ + __pyx_r = __pyx_v_b; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L6_except_return; + + /* "fontTools/cu2qu/cu2qu.py":306 + * # solution if it's within tolerance: + * # https://github.com/linebender/kurbo/pull/484 + * if b == c and (a == b or c == d): # <<<<<<<<<<<<<< + * return b + * return complex(NAN, NAN) +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":308 + * if b == c and (a == b or c == d): + * return b + * return complex(NAN, NAN) # <<<<<<<<<<<<<< + * return c + cd * h + * +*/ + __pyx_t_13 = NULL; + __Pyx_GetModuleGlobalName(__pyx_t_14, __pyx_mstate_global->__pyx_n_u_NAN); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 308, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_GetModuleGlobalName(__pyx_t_15, __pyx_mstate_global->__pyx_n_u_NAN); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 308, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_16 = 1; + { + PyObject *__pyx_callargs[3] = {__pyx_t_13, __pyx_t_14, __pyx_t_15}; + __pyx_t_12 = __Pyx_PyObject_FastCall((PyObject*)(&PyComplex_Type), __pyx_callargs+__pyx_t_16, (3-__pyx_t_16) | (__pyx_t_16*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 308, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_12); + } + __pyx_t_17 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_12); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 308, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __pyx_r = __pyx_t_17; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L6_except_return; + } + goto __pyx_L5_except_error; + + /* "fontTools/cu2qu/cu2qu.py":299 + * cd = d - c + * p = ab * 1j + * try: # <<<<<<<<<<<<<< + * h = dot(p, a - c) / dot(p, cd) + * except ZeroDivisionError: +*/ + __pyx_L5_except_error:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L6_except_return:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L0; + __pyx_L8_try_end:; + } + + /* "fontTools/cu2qu/cu2qu.py":309 + * return b + * return complex(NAN, NAN) + * return c + cd * h # <<<<<<<<<<<<<< + * + * +*/ + __pyx_r = __Pyx_c_sum_double(__pyx_v_c, __Pyx_c_prod_double(__pyx_v_cd, __pyx_t_double_complex_from_parts(__pyx_v_h, 0))); + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":278 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.returns(cython.complex) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_XDECREF(__pyx_t_15); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.calc_intersect", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = __pyx_t_double_complex_from_parts(0, 0); + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":312 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.returns(cython.int) + * @cython.locals( +*/ + +static int __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_t_double_complex __pyx_v_p0, __pyx_t_double_complex __pyx_v_p1, __pyx_t_double_complex __pyx_v_p2, __pyx_t_double_complex __pyx_v_p3, double __pyx_v_tolerance) { + __pyx_t_double_complex __pyx_v_mid; + __pyx_t_double_complex __pyx_v_deriv3; + int __pyx_r; + int __pyx_t_1; + int __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + + /* "fontTools/cu2qu/cu2qu.py":341 + * """ + * # First check p2 then p1, as p2 has higher error early on. + * if abs(p2) <= tolerance and abs(p1) <= tolerance: # <<<<<<<<<<<<<< + * return True + * +*/ + __pyx_t_2 = (__Pyx_c_abs_double(__pyx_v_p2) <= __pyx_v_tolerance); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = (__Pyx_c_abs_double(__pyx_v_p1) <= __pyx_v_tolerance); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":342 + * # First check p2 then p1, as p2 has higher error early on. + * if abs(p2) <= tolerance and abs(p1) <= tolerance: + * return True # <<<<<<<<<<<<<< + * + * # Split. +*/ + __pyx_r = 1; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":341 + * """ + * # First check p2 then p1, as p2 has higher error early on. + * if abs(p2) <= tolerance and abs(p1) <= tolerance: # <<<<<<<<<<<<<< + * return True + * +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":345 + * + * # Split. + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 # <<<<<<<<<<<<<< + * if abs(mid) > tolerance: + * return False +*/ + __pyx_v_mid = __Pyx_c_prod_double(__Pyx_c_sum_double(__Pyx_c_sum_double(__pyx_v_p0, __Pyx_c_prod_double(__pyx_t_double_complex_from_parts(3, 0), __Pyx_c_sum_double(__pyx_v_p1, __pyx_v_p2))), __pyx_v_p3), __pyx_t_double_complex_from_parts(0.125, 0)); + + /* "fontTools/cu2qu/cu2qu.py":346 + * # Split. + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + * if abs(mid) > tolerance: # <<<<<<<<<<<<<< + * return False + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 +*/ + __pyx_t_1 = (__Pyx_c_abs_double(__pyx_v_mid) > __pyx_v_tolerance); + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":347 + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + * if abs(mid) > tolerance: + * return False # <<<<<<<<<<<<<< + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return cubic_farthest_fit_inside( +*/ + __pyx_r = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":346 + * # Split. + * mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + * if abs(mid) > tolerance: # <<<<<<<<<<<<<< + * return False + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":348 + * if abs(mid) > tolerance: + * return False + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 # <<<<<<<<<<<<<< + * return cubic_farthest_fit_inside( + * p0, (p0 + p1) * 0.5, mid - deriv3, mid, tolerance +*/ + __pyx_v_deriv3 = __Pyx_c_prod_double(__Pyx_c_diff_double(__Pyx_c_diff_double(__Pyx_c_sum_double(__pyx_v_p3, __pyx_v_p2), __pyx_v_p1), __pyx_v_p0), __pyx_t_double_complex_from_parts(0.125, 0)); + + /* "fontTools/cu2qu/cu2qu.py":349 + * return False + * deriv3 = (p3 + p2 - p1 - p0) * 0.125 + * return cubic_farthest_fit_inside( # <<<<<<<<<<<<<< + * p0, (p0 + p1) * 0.5, mid - deriv3, mid, tolerance + * ) and cubic_farthest_fit_inside(mid, mid + deriv3, (p2 + p3) * 0.5, p3, tolerance) +*/ + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_v_p0, __Pyx_c_prod_double(__Pyx_c_sum_double(__pyx_v_p0, __pyx_v_p1), __pyx_t_double_complex_from_parts(0.5, 0)), __Pyx_c_diff_double(__pyx_v_mid, __pyx_v_deriv3), __pyx_v_mid, __pyx_v_tolerance); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 349, __pyx_L1_error) + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L7_bool_binop_done; + } + + /* "fontTools/cu2qu/cu2qu.py":351 + * return cubic_farthest_fit_inside( + * p0, (p0 + p1) * 0.5, mid - deriv3, mid, tolerance + * ) and cubic_farthest_fit_inside(mid, mid + deriv3, (p2 + p3) * 0.5, p3, tolerance) # <<<<<<<<<<<<<< + * + * +*/ + __pyx_t_4 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_v_mid, __Pyx_c_sum_double(__pyx_v_mid, __pyx_v_deriv3), __Pyx_c_prod_double(__Pyx_c_sum_double(__pyx_v_p2, __pyx_v_p3), __pyx_t_double_complex_from_parts(0.5, 0)), __pyx_v_p3, __pyx_v_tolerance); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 351, __pyx_L1_error) + __pyx_t_3 = __pyx_t_4; + __pyx_L7_bool_binop_done:; + __pyx_r = __pyx_t_3; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":312 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.returns(cython.int) + * @cython.locals( +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.cubic_farthest_fit_inside", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":354 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals(tolerance=cython.double) +*/ + +static CYTHON_INLINE PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_quadratic(PyObject *__pyx_v_cubic, double __pyx_v_tolerance) { + __pyx_t_double_complex __pyx_v_q1; + __pyx_t_double_complex __pyx_v_c0; + __pyx_t_double_complex __pyx_v_c1; + __pyx_t_double_complex __pyx_v_c2; + __pyx_t_double_complex __pyx_v_c3; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __pyx_t_double_complex __pyx_t_2; + __pyx_t_double_complex __pyx_t_3; + __pyx_t_double_complex __pyx_t_4; + __pyx_t_double_complex __pyx_t_5; + __pyx_t_double_complex __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + size_t __pyx_t_10; + int __pyx_t_11; + int __pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cubic_approx_quadratic", 0); + + /* "fontTools/cu2qu/cu2qu.py":378 + * """ + * + * q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3]) # <<<<<<<<<<<<<< + * if math.isnan(q1.imag): + * return None +*/ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 378, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __pyx_f_9fontTools_5cu2qu_5cu2qu_calc_intersect(__pyx_t_2, __pyx_t_3, __pyx_t_4, __pyx_t_5); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 378, __pyx_L1_error) + __pyx_v_q1 = __pyx_t_6; + + /* "fontTools/cu2qu/cu2qu.py":379 + * + * q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3]) + * if math.isnan(q1.imag): # <<<<<<<<<<<<<< + * return None + * c0 = cubic[0] +*/ + __pyx_t_7 = NULL; + __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_math); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_isnan); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = PyFloat_FromDouble(__Pyx_CIMAG(__pyx_v_q1)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = 1; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + assert(__pyx_t_7); + PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(__pyx__function); + __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); + __pyx_t_10 = 0; + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_8}; + __pyx_t_1 = __Pyx_PyObject_FastCall((PyObject*)__pyx_t_9, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (__pyx_t_10*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_11 < 0))) __PYX_ERR(0, 379, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_11) { + + /* "fontTools/cu2qu/cu2qu.py":380 + * q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3]) + * if math.isnan(q1.imag): + * return None # <<<<<<<<<<<<<< + * c0 = cubic[0] + * c3 = cubic[3] +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":379 + * + * q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3]) + * if math.isnan(q1.imag): # <<<<<<<<<<<<<< + * return None + * c0 = cubic[0] +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":381 + * if math.isnan(q1.imag): + * return None + * c0 = cubic[0] # <<<<<<<<<<<<<< + * c3 = cubic[3] + * c1 = c0 + (q1 - c0) * (2 / 3) +*/ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 381, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 381, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_c0 = __pyx_t_6; + + /* "fontTools/cu2qu/cu2qu.py":382 + * return None + * c0 = cubic[0] + * c3 = cubic[3] # <<<<<<<<<<<<<< + * c1 = c0 + (q1 - c0) * (2 / 3) + * c2 = c3 + (q1 - c3) * (2 / 3) +*/ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_c3 = __pyx_t_6; + + /* "fontTools/cu2qu/cu2qu.py":383 + * c0 = cubic[0] + * c3 = cubic[3] + * c1 = c0 + (q1 - c0) * (2 / 3) # <<<<<<<<<<<<<< + * c2 = c3 + (q1 - c3) * (2 / 3) + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): +*/ + __pyx_v_c1 = __Pyx_c_sum_double(__pyx_v_c0, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_q1, __pyx_v_c0), __pyx_t_double_complex_from_parts((2.0 / 3.0), 0))); + + /* "fontTools/cu2qu/cu2qu.py":384 + * c3 = cubic[3] + * c1 = c0 + (q1 - c0) * (2 / 3) + * c2 = c3 + (q1 - c3) * (2 / 3) # <<<<<<<<<<<<<< + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): + * return None +*/ + __pyx_v_c2 = __Pyx_c_sum_double(__pyx_v_c3, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_q1, __pyx_v_c3), __pyx_t_double_complex_from_parts((2.0 / 3.0), 0))); + + /* "fontTools/cu2qu/cu2qu.py":385 + * c1 = c0 + (q1 - c0) * (2 / 3) + * c2 = c3 + (q1 - c3) * (2 / 3) + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): # <<<<<<<<<<<<<< + * return None + * return c0, q1, c3 +*/ + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_c1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_cubic, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_8 = PyNumber_Subtract(__pyx_t_1, __pyx_t_9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __pyx_PyComplex_FromComplex(__pyx_v_c2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_cubic, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_1 = PyNumber_Subtract(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_1); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_12 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_t_double_complex_from_parts(0, 0), __pyx_t_6, __pyx_t_5, __pyx_t_double_complex_from_parts(0, 0), __pyx_v_tolerance); if (unlikely(__pyx_t_12 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 385, __pyx_L1_error) + __pyx_t_11 = (!(__pyx_t_12 != 0)); + if (__pyx_t_11) { + + /* "fontTools/cu2qu/cu2qu.py":386 + * c2 = c3 + (q1 - c3) * (2 / 3) + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): + * return None # <<<<<<<<<<<<<< + * return c0, q1, c3 + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":385 + * c1 = c0 + (q1 - c0) * (2 / 3) + * c2 = c3 + (q1 - c3) * (2 / 3) + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): # <<<<<<<<<<<<<< + * return None + * return c0, q1, c3 +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":387 + * if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): + * return None + * return c0, q1, c3 # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_c0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __pyx_PyComplex_FromComplex(__pyx_v_q1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_8 = __pyx_PyComplex_FromComplex(__pyx_v_c3); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = PyTuple_New(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_1); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_1) != (0)) __PYX_ERR(0, 387, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_9); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_9) != (0)) __PYX_ERR(0, 387, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_8); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_7, 2, __pyx_t_8) != (0)) __PYX_ERR(0, 387, __pyx_L1_error); + __pyx_t_1 = 0; + __pyx_t_9 = 0; + __pyx_t_8 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":354 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.inline + * @cython.locals(tolerance=cython.double) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.cubic_approx_quadratic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":390 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int, tolerance=cython.double) + * @cython.locals(i=cython.int) +*/ + +static PyObject *__pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_spline(PyObject *__pyx_v_cubic, int __pyx_v_n, double __pyx_v_tolerance, int __pyx_v_all_quadratic) { + __pyx_t_double_complex __pyx_v_q0; + __pyx_t_double_complex __pyx_v_q1; + __pyx_t_double_complex __pyx_v_next_q1; + __pyx_t_double_complex __pyx_v_q2; + __pyx_t_double_complex __pyx_v_d1; + CYTHON_UNUSED __pyx_t_double_complex __pyx_v_c0; + __pyx_t_double_complex __pyx_v_c1; + __pyx_t_double_complex __pyx_v_c2; + __pyx_t_double_complex __pyx_v_c3; + int __pyx_v_i; + PyObject *__pyx_v_cubics = NULL; + PyObject *__pyx_v_next_cubic = NULL; + PyObject *__pyx_v_spline = NULL; + __pyx_t_double_complex __pyx_v_d0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + __pyx_t_double_complex __pyx_t_4; + __pyx_t_double_complex __pyx_t_5; + __pyx_t_double_complex __pyx_t_6; + __pyx_t_double_complex __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + __pyx_t_double_complex __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + long __pyx_t_11; + long __pyx_t_12; + int __pyx_t_13; + PyObject *__pyx_t_14 = NULL; + PyObject *__pyx_t_15 = NULL; + PyObject *(*__pyx_t_16)(PyObject *); + long __pyx_t_17; + int __pyx_t_18; + int __pyx_t_19; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("cubic_approx_spline", 0); + + /* "fontTools/cu2qu/cu2qu.py":419 + * """ + * + * if n == 1: # <<<<<<<<<<<<<< + * return cubic_approx_quadratic(cubic, tolerance) + * if n == 2 and all_quadratic == False: +*/ + __pyx_t_1 = (__pyx_v_n == 1); + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":420 + * + * if n == 1: + * return cubic_approx_quadratic(cubic, tolerance) # <<<<<<<<<<<<<< + * if n == 2 and all_quadratic == False: + * return cubic +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_quadratic(__pyx_v_cubic, __pyx_v_tolerance); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 420, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":419 + * """ + * + * if n == 1: # <<<<<<<<<<<<<< + * return cubic_approx_quadratic(cubic, tolerance) + * if n == 2 and all_quadratic == False: +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":421 + * if n == 1: + * return cubic_approx_quadratic(cubic, tolerance) + * if n == 2 and all_quadratic == False: # <<<<<<<<<<<<<< + * return cubic + * +*/ + __pyx_t_3 = (__pyx_v_n == 2); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L5_bool_binop_done; + } + __pyx_t_3 = (__pyx_v_all_quadratic == 0); + __pyx_t_1 = __pyx_t_3; + __pyx_L5_bool_binop_done:; + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":422 + * return cubic_approx_quadratic(cubic, tolerance) + * if n == 2 and all_quadratic == False: + * return cubic # <<<<<<<<<<<<<< + * + * cubics = split_cubic_into_n_iter(cubic[0], cubic[1], cubic[2], cubic[3], n) +*/ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_cubic); + __pyx_r = __pyx_v_cubic; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":421 + * if n == 1: + * return cubic_approx_quadratic(cubic, tolerance) + * if n == 2 and all_quadratic == False: # <<<<<<<<<<<<<< + * return cubic + * +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":424 + * return cubic + * + * cubics = split_cubic_into_n_iter(cubic[0], cubic[1], cubic[2], cubic[3], n) # <<<<<<<<<<<<<< + * + * # calculate the spline of quadratics and check errors at the same time. +*/ + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_cubic, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_cubic, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyLong_From_int(__pyx_v_n); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __pyx_f_9fontTools_5cu2qu_5cu2qu_split_cubic_into_n_iter(__pyx_t_4, __pyx_t_5, __pyx_t_6, __pyx_t_7, __pyx_t_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_cubics = __pyx_t_8; + __pyx_t_8 = 0; + + /* "fontTools/cu2qu/cu2qu.py":427 + * + * # calculate the spline of quadratics and check errors at the same time. + * next_cubic = next(cubics) # <<<<<<<<<<<<<< + * next_q1 = cubic_approx_control( + * 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] +*/ + __pyx_t_8 = __Pyx_PyIter_Next(__pyx_v_cubics); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_v_next_cubic = __pyx_t_8; + __pyx_t_8 = 0; + + /* "fontTools/cu2qu/cu2qu.py":429 + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( + * 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] # <<<<<<<<<<<<<< + * ) + * q2 = cubic[0] +*/ + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_next_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_next_cubic, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_next_cubic, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_next_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 429, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "fontTools/cu2qu/cu2qu.py":428 + * # calculate the spline of quadratics and check errors at the same time. + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( # <<<<<<<<<<<<<< + * 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + * ) +*/ + __pyx_t_9 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_control(0.0, __pyx_t_7, __pyx_t_6, __pyx_t_5, __pyx_t_4); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 428, __pyx_L1_error) + __pyx_v_next_q1 = __pyx_t_9; + + /* "fontTools/cu2qu/cu2qu.py":431 + * 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + * ) + * q2 = cubic[0] # <<<<<<<<<<<<<< + * d1 = 0j + * spline = [cubic[0], next_q1] +*/ + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_q2 = __pyx_t_9; + + /* "fontTools/cu2qu/cu2qu.py":432 + * ) + * q2 = cubic[0] + * d1 = 0j # <<<<<<<<<<<<<< + * spline = [cubic[0], next_q1] + * for i in range(1, n + 1): +*/ + __pyx_v_d1 = __pyx_t_double_complex_from_parts(0, 0.0); + + /* "fontTools/cu2qu/cu2qu.py":433 + * q2 = cubic[0] + * d1 = 0j + * spline = [cubic[0], next_q1] # <<<<<<<<<<<<<< + * for i in range(1, n + 1): + * # Current cubic to convert +*/ + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_2 = __pyx_PyComplex_FromComplex(__pyx_v_next_q1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_10 = PyList_New(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_8); + if (__Pyx_PyList_SET_ITEM(__pyx_t_10, 0, __pyx_t_8) != (0)) __PYX_ERR(0, 433, __pyx_L1_error); + __Pyx_GIVEREF(__pyx_t_2); + if (__Pyx_PyList_SET_ITEM(__pyx_t_10, 1, __pyx_t_2) != (0)) __PYX_ERR(0, 433, __pyx_L1_error); + __pyx_t_8 = 0; + __pyx_t_2 = 0; + __pyx_v_spline = ((PyObject*)__pyx_t_10); + __pyx_t_10 = 0; + + /* "fontTools/cu2qu/cu2qu.py":434 + * d1 = 0j + * spline = [cubic[0], next_q1] + * for i in range(1, n + 1): # <<<<<<<<<<<<<< + * # Current cubic to convert + * c0, c1, c2, c3 = next_cubic +*/ + __pyx_t_11 = (__pyx_v_n + 1); + __pyx_t_12 = __pyx_t_11; + for (__pyx_t_13 = 1; __pyx_t_13 < __pyx_t_12; __pyx_t_13+=1) { + __pyx_v_i = __pyx_t_13; + + /* "fontTools/cu2qu/cu2qu.py":436 + * for i in range(1, n + 1): + * # Current cubic to convert + * c0, c1, c2, c3 = next_cubic # <<<<<<<<<<<<<< + * + * # Current quadratic approximation of current cubic +*/ + if ((likely(PyTuple_CheckExact(__pyx_v_next_cubic))) || (PyList_CheckExact(__pyx_v_next_cubic))) { + PyObject* sequence = __pyx_v_next_cubic; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 4)) { + if (size > 4) __Pyx_RaiseTooManyValuesError(4); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 436, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_10 = PyTuple_GET_ITEM(sequence, 0); + __Pyx_INCREF(__pyx_t_10); + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_2); + __pyx_t_8 = PyTuple_GET_ITEM(sequence, 2); + __Pyx_INCREF(__pyx_t_8); + __pyx_t_14 = PyTuple_GET_ITEM(sequence, 3); + __Pyx_INCREF(__pyx_t_14); + } else { + __pyx_t_10 = __Pyx_PyList_GetItemRefFast(sequence, 0, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_10); + __pyx_t_2 = __Pyx_PyList_GetItemRefFast(sequence, 1, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_PyList_GetItemRefFast(sequence, 2, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_8); + __pyx_t_14 = __Pyx_PyList_GetItemRefFast(sequence, 3, __Pyx_ReferenceSharing_SharedReference); + if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_XGOTREF(__pyx_t_14); + } + #else + { + Py_ssize_t i; + PyObject** temps[4] = {&__pyx_t_10,&__pyx_t_2,&__pyx_t_8,&__pyx_t_14}; + for (i=0; i < 4; i++) { + PyObject* item = __Pyx_PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(item); + *(temps[i]) = item; + } + } + #endif + } else { + Py_ssize_t index = -1; + PyObject** temps[4] = {&__pyx_t_10,&__pyx_t_2,&__pyx_t_8,&__pyx_t_14}; + __pyx_t_15 = PyObject_GetIter(__pyx_v_next_cubic); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_16 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_15); + for (index=0; index < 4; index++) { + PyObject* item = __pyx_t_16(__pyx_t_15); if (unlikely(!item)) goto __pyx_L9_unpacking_failed; + __Pyx_GOTREF(item); + *(temps[index]) = item; + } + if (__Pyx_IternextUnpackEndCheck(__pyx_t_16(__pyx_t_15), 4) < (0)) __PYX_ERR(0, 436, __pyx_L1_error) + __pyx_t_16 = NULL; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + goto __pyx_L10_unpacking_done; + __pyx_L9_unpacking_failed:; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + __pyx_t_16 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 436, __pyx_L1_error) + __pyx_L10_unpacking_done:; + } + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_10); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_2); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_8); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_14); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_v_c0 = __pyx_t_9; + __pyx_v_c1 = __pyx_t_4; + __pyx_v_c2 = __pyx_t_5; + __pyx_v_c3 = __pyx_t_6; + + /* "fontTools/cu2qu/cu2qu.py":439 + * + * # Current quadratic approximation of current cubic + * q0 = q2 # <<<<<<<<<<<<<< + * q1 = next_q1 + * if i < n: +*/ + __pyx_v_q0 = __pyx_v_q2; + + /* "fontTools/cu2qu/cu2qu.py":440 + * # Current quadratic approximation of current cubic + * q0 = q2 + * q1 = next_q1 # <<<<<<<<<<<<<< + * if i < n: + * next_cubic = next(cubics) +*/ + __pyx_v_q1 = __pyx_v_next_q1; + + /* "fontTools/cu2qu/cu2qu.py":441 + * q0 = q2 + * q1 = next_q1 + * if i < n: # <<<<<<<<<<<<<< + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( +*/ + __pyx_t_1 = (__pyx_v_i < __pyx_v_n); + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":442 + * q1 = next_q1 + * if i < n: + * next_cubic = next(cubics) # <<<<<<<<<<<<<< + * next_q1 = cubic_approx_control( + * i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] +*/ + __pyx_t_14 = __Pyx_PyIter_Next(__pyx_v_cubics); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 442, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF_SET(__pyx_v_next_cubic, __pyx_t_14); + __pyx_t_14 = 0; + + /* "fontTools/cu2qu/cu2qu.py":444 + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( + * i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] # <<<<<<<<<<<<<< + * ) + * spline.append(next_q1) +*/ + __pyx_t_17 = (__pyx_v_n - 1); + if (unlikely(__pyx_t_17 == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 444, __pyx_L1_error) + } + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_next_cubic, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_6 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_14); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_next_cubic, 1, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_5 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_14); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_next_cubic, 2, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_4 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_14); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_next_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_9 = __Pyx_PyComplex_As___pyx_t_double_complex(__pyx_t_14); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 444, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + + /* "fontTools/cu2qu/cu2qu.py":443 + * if i < n: + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( # <<<<<<<<<<<<<< + * i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + * ) +*/ + __pyx_t_7 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_control((((double)__pyx_v_i) / ((double)__pyx_t_17)), __pyx_t_6, __pyx_t_5, __pyx_t_4, __pyx_t_9); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 443, __pyx_L1_error) + __pyx_v_next_q1 = __pyx_t_7; + + /* "fontTools/cu2qu/cu2qu.py":446 + * i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + * ) + * spline.append(next_q1) # <<<<<<<<<<<<<< + * q2 = (q1 + next_q1) * 0.5 + * else: +*/ + __pyx_t_14 = __pyx_PyComplex_FromComplex(__pyx_v_next_q1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 446, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_18 = __Pyx_PyList_Append(__pyx_v_spline, __pyx_t_14); if (unlikely(__pyx_t_18 == ((int)-1))) __PYX_ERR(0, 446, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + + /* "fontTools/cu2qu/cu2qu.py":447 + * ) + * spline.append(next_q1) + * q2 = (q1 + next_q1) * 0.5 # <<<<<<<<<<<<<< + * else: + * q2 = c3 +*/ + __pyx_v_q2 = __Pyx_c_prod_double(__Pyx_c_sum_double(__pyx_v_q1, __pyx_v_next_q1), __pyx_t_double_complex_from_parts(0.5, 0)); + + /* "fontTools/cu2qu/cu2qu.py":441 + * q0 = q2 + * q1 = next_q1 + * if i < n: # <<<<<<<<<<<<<< + * next_cubic = next(cubics) + * next_q1 = cubic_approx_control( +*/ + goto __pyx_L11; + } + + /* "fontTools/cu2qu/cu2qu.py":449 + * q2 = (q1 + next_q1) * 0.5 + * else: + * q2 = c3 # <<<<<<<<<<<<<< + * + * # End-point deltas +*/ + /*else*/ { + __pyx_v_q2 = __pyx_v_c3; + } + __pyx_L11:; + + /* "fontTools/cu2qu/cu2qu.py":452 + * + * # End-point deltas + * d0 = d1 # <<<<<<<<<<<<<< + * d1 = q2 - c3 + * +*/ + __pyx_v_d0 = __pyx_v_d1; + + /* "fontTools/cu2qu/cu2qu.py":453 + * # End-point deltas + * d0 = d1 + * d1 = q2 - c3 # <<<<<<<<<<<<<< + * + * if abs(d1) > tolerance or not cubic_farthest_fit_inside( +*/ + __pyx_v_d1 = __Pyx_c_diff_double(__pyx_v_q2, __pyx_v_c3); + + /* "fontTools/cu2qu/cu2qu.py":455 + * d1 = q2 - c3 + * + * if abs(d1) > tolerance or not cubic_farthest_fit_inside( # <<<<<<<<<<<<<< + * d0, + * q0 + (q1 - q0) * (2 / 3) - c1, +*/ + __pyx_t_3 = (__Pyx_c_abs_double(__pyx_v_d1) > __pyx_v_tolerance); + if (!__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L13_bool_binop_done; + } + + /* "fontTools/cu2qu/cu2qu.py":460 + * q2 + (q1 - q2) * (2 / 3) - c2, + * d1, + * tolerance, # <<<<<<<<<<<<<< + * ): + * return None +*/ + __pyx_t_19 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_farthest_fit_inside(__pyx_v_d0, __Pyx_c_diff_double(__Pyx_c_sum_double(__pyx_v_q0, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_q1, __pyx_v_q0), __pyx_t_double_complex_from_parts((2.0 / 3.0), 0))), __pyx_v_c1), __Pyx_c_diff_double(__Pyx_c_sum_double(__pyx_v_q2, __Pyx_c_prod_double(__Pyx_c_diff_double(__pyx_v_q1, __pyx_v_q2), __pyx_t_double_complex_from_parts((2.0 / 3.0), 0))), __pyx_v_c2), __pyx_v_d1, __pyx_v_tolerance); if (unlikely(__pyx_t_19 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 455, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":455 + * d1 = q2 - c3 + * + * if abs(d1) > tolerance or not cubic_farthest_fit_inside( # <<<<<<<<<<<<<< + * d0, + * q0 + (q1 - q0) * (2 / 3) - c1, +*/ + __pyx_t_3 = (!(__pyx_t_19 != 0)); + __pyx_t_1 = __pyx_t_3; + __pyx_L13_bool_binop_done:; + if (__pyx_t_1) { + + /* "fontTools/cu2qu/cu2qu.py":462 + * tolerance, + * ): + * return None # <<<<<<<<<<<<<< + * spline.append(cubic[3]) + * +*/ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":455 + * d1 = q2 - c3 + * + * if abs(d1) > tolerance or not cubic_farthest_fit_inside( # <<<<<<<<<<<<<< + * d0, + * q0 + (q1 - q0) * (2 / 3) - c1, +*/ + } + } + + /* "fontTools/cu2qu/cu2qu.py":463 + * ): + * return None + * spline.append(cubic[3]) # <<<<<<<<<<<<<< + * + * return spline +*/ + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_cubic, 3, long, 1, __Pyx_PyLong_From_long, 0, 0, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 463, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_18 = __Pyx_PyList_Append(__pyx_v_spline, __pyx_t_14); if (unlikely(__pyx_t_18 == ((int)-1))) __PYX_ERR(0, 463, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + + /* "fontTools/cu2qu/cu2qu.py":465 + * spline.append(cubic[3]) + * + * return spline # <<<<<<<<<<<<<< + * + * +*/ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_spline); + __pyx_r = __pyx_v_spline; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":390 + * + * + * @cython.cfunc # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int, tolerance=cython.double) + * @cython.locals(i=cython.int) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_XDECREF(__pyx_t_15); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.cubic_approx_spline", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_cubics); + __Pyx_XDECREF(__pyx_v_next_cubic); + __Pyx_XDECREF(__pyx_v_spline); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":468 + * + * + * @cython.locals(max_err=cython.double) # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) +*/ + +/* Python wrapper */ +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_4curve_to_quadratic(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_9fontTools_5cu2qu_5cu2qu_3curve_to_quadratic, "curve_to_quadratic(curve, double max_err, int all_quadratic=True)\n\nApproximate a cubic Bezier curve with a spline of n quadratics.\n\nArgs:\n cubic (sequence): Four 2D tuples representing control points of\n the cubic Bezier curve.\n max_err (double): Permitted deviation from the original curve.\n all_quadratic (bool): If True (default) returned value is a\n quadratic spline. If False, it's either a single quadratic\n curve or a single cubic curve.\n\nReturns:\n If all_quadratic is True: A list of 2D tuples, representing\n control points of the quadratic spline if it fits within the\n given tolerance, or ``None`` if no suitable spline could be\n calculated.\n\n If all_quadratic is False: Either a quadratic curve (if length\n of output is 3), or a cubic curve (if length of output is 4)."); +static PyMethodDef __pyx_mdef_9fontTools_5cu2qu_5cu2qu_4curve_to_quadratic = {"curve_to_quadratic", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9fontTools_5cu2qu_5cu2qu_4curve_to_quadratic, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9fontTools_5cu2qu_5cu2qu_3curve_to_quadratic}; +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_4curve_to_quadratic(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_curve = 0; + double __pyx_v_max_err; + int __pyx_v_all_quadratic; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("curve_to_quadratic (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_SIZE + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_curve,&__pyx_mstate_global->__pyx_n_u_max_err,&__pyx_mstate_global->__pyx_n_u_all_quadratic,0}; + const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; + if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 468, __pyx_L3_error) + if (__pyx_kwds_len > 0) { + switch (__pyx_nargs) { + case 3: + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 468, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 2: + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 468, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 1: + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 468, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "curve_to_quadratic", 0) < (0)) __PYX_ERR(0, 468, __pyx_L3_error) + for (Py_ssize_t i = __pyx_nargs; i < 2; i++) { + if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("curve_to_quadratic", 0, 2, 3, i); __PYX_ERR(0, 468, __pyx_L3_error) } + } + } else { + switch (__pyx_nargs) { + case 3: + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 468, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 2: + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 468, __pyx_L3_error) + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 468, __pyx_L3_error) + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_curve = values[0]; + __pyx_v_max_err = __Pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_max_err == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 471, __pyx_L3_error) + if (values[2]) { + __pyx_v_all_quadratic = __Pyx_PyLong_As_int(values[2]); if (unlikely((__pyx_v_all_quadratic == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 471, __pyx_L3_error) + } else { + + /* "fontTools/cu2qu/cu2qu.py":471 + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) + * def curve_to_quadratic(curve, max_err, all_quadratic=True): # <<<<<<<<<<<<<< + * """Approximate a cubic Bezier curve with a spline of n quadratics. + * +*/ + __pyx_v_all_quadratic = ((int)((int)1)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("curve_to_quadratic", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 468, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.curve_to_quadratic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_9fontTools_5cu2qu_5cu2qu_3curve_to_quadratic(__pyx_self, __pyx_v_curve, __pyx_v_max_err, __pyx_v_all_quadratic); + + /* "fontTools/cu2qu/cu2qu.py":468 + * + * + * @cython.locals(max_err=cython.double) # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) +*/ + + /* function exit code */ + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu_3curve_to_quadratic(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_curve, double __pyx_v_max_err, int __pyx_v_all_quadratic) { + int __pyx_v_n; + PyObject *__pyx_v_spline = NULL; + PyObject *__pyx_7genexpr__pyx_v_p = NULL; + PyObject *__pyx_8genexpr1__pyx_v_s = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + Py_ssize_t __pyx_t_7; + int __pyx_t_8; + int __pyx_t_9; + Py_ssize_t __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + size_t __pyx_t_12; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("curve_to_quadratic", 0); + __Pyx_INCREF(__pyx_v_curve); + + /* "fontTools/cu2qu/cu2qu.py":492 + * """ + * + * curve = [complex(*p) for p in curve] # <<<<<<<<<<<<<< + * + * for n in range(1, MAX_N + 1): +*/ + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 492, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(PyList_CheckExact(__pyx_v_curve)) || PyTuple_CheckExact(__pyx_v_curve)) { + __pyx_t_2 = __pyx_v_curve; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_curve); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 492, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 492, __pyx_L5_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 492, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + __pyx_t_5 = __Pyx_PyList_GetItemRefFast(__pyx_t_2, __pyx_t_3, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_3; + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 492, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3)); + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); + #endif + ++__pyx_t_3; + } + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 492, __pyx_L5_error) + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 492, __pyx_L5_error) + PyErr_Clear(); + } + break; + } + } + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_7genexpr__pyx_v_p, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PySequence_Tuple(__pyx_7genexpr__pyx_v_p); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 492, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_Call(((PyObject *)(&PyComplex_Type)), __pyx_t_5, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 492, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_6))) __PYX_ERR(0, 492, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_p); __pyx_7genexpr__pyx_v_p = 0; + goto __pyx_L9_exit_scope; + __pyx_L5_error:; + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_p); __pyx_7genexpr__pyx_v_p = 0; + goto __pyx_L1_error; + __pyx_L9_exit_scope:; + } /* exit inner scope */ + __Pyx_DECREF_SET(__pyx_v_curve, __pyx_t_1); + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":494 + * curve = [complex(*p) for p in curve] + * + * for n in range(1, MAX_N + 1): # <<<<<<<<<<<<<< + * spline = cubic_approx_spline(curve, n, max_err, all_quadratic) + * if spline is not None: +*/ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_MAX_N); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 494, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyLong_AddObjC(__pyx_t_1, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 494, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_PyIndex_AsSsize_t(__pyx_t_2); if (unlikely((__pyx_t_3 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 494, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_7 = __pyx_t_3; + for (__pyx_t_8 = 1; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) { + __pyx_v_n = __pyx_t_8; + + /* "fontTools/cu2qu/cu2qu.py":495 + * + * for n in range(1, MAX_N + 1): + * spline = cubic_approx_spline(curve, n, max_err, all_quadratic) # <<<<<<<<<<<<<< + * if spline is not None: + * # done. go home +*/ + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_spline(__pyx_v_curve, __pyx_v_n, __pyx_v_max_err, __pyx_v_all_quadratic); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 495, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_XDECREF_SET(__pyx_v_spline, __pyx_t_2); + __pyx_t_2 = 0; + + /* "fontTools/cu2qu/cu2qu.py":496 + * for n in range(1, MAX_N + 1): + * spline = cubic_approx_spline(curve, n, max_err, all_quadratic) + * if spline is not None: # <<<<<<<<<<<<<< + * # done. go home + * return [(s.real, s.imag) for s in spline] +*/ + __pyx_t_9 = (__pyx_v_spline != Py_None); + if (__pyx_t_9) { + + /* "fontTools/cu2qu/cu2qu.py":498 + * if spline is not None: + * # done. go home + * return [(s.real, s.imag) for s in spline] # <<<<<<<<<<<<<< + * + * raise ApproxNotFoundError(curve) +*/ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_2); + if (likely(PyList_CheckExact(__pyx_v_spline)) || PyTuple_CheckExact(__pyx_v_spline)) { + __pyx_t_1 = __pyx_v_spline; __Pyx_INCREF(__pyx_t_1); + __pyx_t_10 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_10 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_spline); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 498, __pyx_L15_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 498, __pyx_L15_error) + #endif + if (__pyx_t_10 >= __pyx_temp) break; + } + __pyx_t_6 = __Pyx_PyList_GetItemRefFast(__pyx_t_1, __pyx_t_10, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_10; + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 498, __pyx_L15_error) + #endif + if (__pyx_t_10 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_6 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_10)); + #else + __pyx_t_6 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_10); + #endif + ++__pyx_t_10; + } + if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 498, __pyx_L15_error) + } else { + __pyx_t_6 = __pyx_t_4(__pyx_t_1); + if (unlikely(!__pyx_t_6)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 498, __pyx_L15_error) + PyErr_Clear(); + } + break; + } + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_XDECREF_SET(__pyx_8genexpr1__pyx_v_s, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_8genexpr1__pyx_v_s, __pyx_mstate_global->__pyx_n_u_real); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_8genexpr1__pyx_v_s, __pyx_mstate_global->__pyx_n_u_imag); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_11 = PyTuple_New(2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_GIVEREF(__pyx_t_6); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_6) != (0)) __PYX_ERR(0, 498, __pyx_L15_error); + __Pyx_GIVEREF(__pyx_t_5); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_5) != (0)) __PYX_ERR(0, 498, __pyx_L15_error); + __pyx_t_6 = 0; + __pyx_t_5 = 0; + if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_11))) __PYX_ERR(0, 498, __pyx_L15_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_s); __pyx_8genexpr1__pyx_v_s = 0; + goto __pyx_L19_exit_scope; + __pyx_L15_error:; + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_s); __pyx_8genexpr1__pyx_v_s = 0; + goto __pyx_L1_error; + __pyx_L19_exit_scope:; + } /* exit inner scope */ + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":496 + * for n in range(1, MAX_N + 1): + * spline = cubic_approx_spline(curve, n, max_err, all_quadratic) + * if spline is not None: # <<<<<<<<<<<<<< + * # done. go home + * return [(s.real, s.imag) for s in spline] +*/ + } + } + + /* "fontTools/cu2qu/cu2qu.py":500 + * return [(s.real, s.imag) for s in spline] + * + * raise ApproxNotFoundError(curve) # <<<<<<<<<<<<<< + * + * +*/ + __pyx_t_1 = NULL; + __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_ApproxNotFoundError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 500, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_12 = 1; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_11))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_11); + assert(__pyx_t_1); + PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(__pyx__function); + __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); + __pyx_t_12 = 0; + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_v_curve}; + __pyx_t_2 = __Pyx_PyObject_FastCall((PyObject*)__pyx_t_11, __pyx_callargs+__pyx_t_12, (2-__pyx_t_12) | (__pyx_t_12*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 500, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 500, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":468 + * + * + * @cython.locals(max_err=cython.double) # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.curve_to_quadratic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_spline); + __Pyx_XDECREF(__pyx_7genexpr__pyx_v_p); + __Pyx_XDECREF(__pyx_8genexpr1__pyx_v_s); + __Pyx_XDECREF(__pyx_v_curve); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "fontTools/cu2qu/cu2qu.py":503 + * + * + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) # <<<<<<<<<<<<<< + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): +*/ + +/* Python wrapper */ +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_6curves_to_quadratic(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +); /*proto*/ +PyDoc_STRVAR(__pyx_doc_9fontTools_5cu2qu_5cu2qu_5curves_to_quadratic, "curves_to_quadratic(curves, max_errors, int all_quadratic=True)\n\nReturn quadratic Bezier splines approximating the input cubic Beziers.\n\nArgs:\n curves: A sequence of *n* curves, each curve being a sequence of four\n 2D tuples.\n max_errors: A sequence of *n* floats representing the maximum permissible\n deviation from each of the cubic Bezier curves.\n all_quadratic (bool): If True (default) returned values are a\n quadratic spline. If False, they are either a single quadratic\n curve or a single cubic curve.\n\nExample::\n\n >>> curves_to_quadratic( [\n ... [ (50,50), (100,100), (150,100), (200,50) ],\n ... [ (75,50), (120,100), (150,75), (200,60) ]\n ... ], [1,1] )\n [[(50.0, 50.0), (75.0, 75.0), (125.0, 91.66666666666666), (175.0, 75.0), (200.0, 50.0)], [(75.0, 50.0), (97.5, 75.0), (135.41666666666666, 82.08333333333333), (175.0, 67.5), (200.0, 60.0)]]\n\nThe returned splines have \"implied oncurve points\" suitable for use in\nTrueType ``glif`` outlines - i.e. in the first spline returned above,\nthe first quadratic segment runs from (50,50) to\n( (75 + 125)/2 , (120 + 91.666..)/2 ) = (100, 83.333...).\n\nReturns:\n If all_quadratic is True, a list of splines, each spline being a list\n of 2D tuples.\n\n If all_quadratic is False, a list of curves, each curve being a quadratic\n (length 3), or cubic (length 4).\n\nRaises:\n fontTools.cu2qu.Errors.ApproxNotFoundError: if no suitable approximation\n can be found for all curves with the given parameters."); +static PyMethodDef __pyx_mdef_9fontTools_5cu2qu_5cu2qu_6curves_to_quadratic = {"curves_to_quadratic", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_9fontTools_5cu2qu_5cu2qu_6curves_to_quadratic, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_9fontTools_5cu2qu_5cu2qu_5curves_to_quadratic}; +static PyObject *__pyx_pw_9fontTools_5cu2qu_5cu2qu_6curves_to_quadratic(PyObject *__pyx_self, +#if CYTHON_METH_FASTCALL +PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds +#else +PyObject *__pyx_args, PyObject *__pyx_kwds +#endif +) { + PyObject *__pyx_v_curves = 0; + PyObject *__pyx_v_max_errors = 0; + int __pyx_v_all_quadratic; + #if !CYTHON_METH_FASTCALL + CYTHON_UNUSED Py_ssize_t __pyx_nargs; + #endif + CYTHON_UNUSED PyObject *const *__pyx_kwvalues; + PyObject* values[3] = {0,0,0}; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("curves_to_quadratic (wrapper)", 0); + #if !CYTHON_METH_FASTCALL + #if CYTHON_ASSUME_SAFE_SIZE + __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); + #else + __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; + #endif + #endif + __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); + { + PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_curves,&__pyx_mstate_global->__pyx_n_u_max_errors,&__pyx_mstate_global->__pyx_n_u_all_quadratic,0}; + const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; + if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 503, __pyx_L3_error) + if (__pyx_kwds_len > 0) { + switch (__pyx_nargs) { + case 3: + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 503, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 2: + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 503, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 1: + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 503, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + const Py_ssize_t kwd_pos_args = __pyx_nargs; + if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "curves_to_quadratic", 0) < (0)) __PYX_ERR(0, 503, __pyx_L3_error) + for (Py_ssize_t i = __pyx_nargs; i < 2; i++) { + if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("curves_to_quadratic", 0, 2, 3, i); __PYX_ERR(0, 503, __pyx_L3_error) } + } + } else { + switch (__pyx_nargs) { + case 3: + values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 503, __pyx_L3_error) + CYTHON_FALLTHROUGH; + case 2: + values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 503, __pyx_L3_error) + values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); + if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 503, __pyx_L3_error) + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_curves = values[0]; + __pyx_v_max_errors = values[1]; + if (values[2]) { + __pyx_v_all_quadratic = __Pyx_PyLong_As_int(values[2]); if (unlikely((__pyx_v_all_quadratic == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 505, __pyx_L3_error) + } else { + + /* "fontTools/cu2qu/cu2qu.py":505 + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): # <<<<<<<<<<<<<< + * """Return quadratic Bezier splines approximating the input cubic Beziers. + * +*/ + __pyx_v_all_quadratic = ((int)((int)1)); + } + } + goto __pyx_L6_skip; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("curves_to_quadratic", 0, 2, 3, __pyx_nargs); __PYX_ERR(0, 503, __pyx_L3_error) + __pyx_L6_skip:; + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.curves_to_quadratic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_9fontTools_5cu2qu_5cu2qu_5curves_to_quadratic(__pyx_self, __pyx_v_curves, __pyx_v_max_errors, __pyx_v_all_quadratic); + + /* "fontTools/cu2qu/cu2qu.py":503 + * + * + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) # <<<<<<<<<<<<<< + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): +*/ + + /* function exit code */ + for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { + Py_XDECREF(values[__pyx_temp]); + } + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_9fontTools_5cu2qu_5cu2qu_5curves_to_quadratic(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_curves, PyObject *__pyx_v_max_errors, int __pyx_v_all_quadratic) { + int __pyx_v_l; + int __pyx_v_last_i; + int __pyx_v_i; + PyObject *__pyx_v_splines = NULL; + PyObject *__pyx_v_n = NULL; + PyObject *__pyx_v_spline = NULL; + PyObject *__pyx_8genexpr2__pyx_v_curve = NULL; + PyObject *__pyx_8genexpr3__pyx_v_p = NULL; + PyObject *__pyx_8genexpr4__pyx_v_spline = NULL; + PyObject *__pyx_8genexpr5__pyx_v_s = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + Py_ssize_t __pyx_t_3; + PyObject *(*__pyx_t_4)(PyObject *); + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + Py_ssize_t __pyx_t_7; + PyObject *(*__pyx_t_8)(PyObject *); + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + int __pyx_t_12; + double __pyx_t_13; + long __pyx_t_14; + PyObject *__pyx_t_15 = NULL; + size_t __pyx_t_16; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("curves_to_quadratic", 0); + __Pyx_INCREF(__pyx_v_curves); + + /* "fontTools/cu2qu/cu2qu.py":542 + * """ + * + * curves = [[complex(*p) for p in curve] for curve in curves] # <<<<<<<<<<<<<< + * assert len(max_errors) == len(curves) + * +*/ + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 542, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + if (likely(PyList_CheckExact(__pyx_v_curves)) || PyTuple_CheckExact(__pyx_v_curves)) { + __pyx_t_2 = __pyx_v_curves; __Pyx_INCREF(__pyx_t_2); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_curves); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 542, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 542, __pyx_L5_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_2))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 542, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + __pyx_t_5 = __Pyx_PyList_GetItemRefFast(__pyx_t_2, __pyx_t_3, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_3; + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 542, __pyx_L5_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_5 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3)); + #else + __pyx_t_5 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); + #endif + ++__pyx_t_3; + } + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 542, __pyx_L5_error) + } else { + __pyx_t_5 = __pyx_t_4(__pyx_t_2); + if (unlikely(!__pyx_t_5)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 542, __pyx_L5_error) + PyErr_Clear(); + } + break; + } + } + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_8genexpr2__pyx_v_curve, __pyx_t_5); + __pyx_t_5 = 0; + { /* enter inner scope */ + __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 542, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_5); + if (likely(PyList_CheckExact(__pyx_8genexpr2__pyx_v_curve)) || PyTuple_CheckExact(__pyx_8genexpr2__pyx_v_curve)) { + __pyx_t_6 = __pyx_8genexpr2__pyx_v_curve; __Pyx_INCREF(__pyx_t_6); + __pyx_t_7 = 0; + __pyx_t_8 = NULL; + } else { + __pyx_t_7 = -1; __pyx_t_6 = PyObject_GetIter(__pyx_8genexpr2__pyx_v_curve); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 542, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 542, __pyx_L10_error) + } + for (;;) { + if (likely(!__pyx_t_8)) { + if (likely(PyList_CheckExact(__pyx_t_6))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 542, __pyx_L10_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + __pyx_t_9 = __Pyx_PyList_GetItemRefFast(__pyx_t_6, __pyx_t_7, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_7; + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 542, __pyx_L10_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_9 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_6, __pyx_t_7)); + #else + __pyx_t_9 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_7); + #endif + ++__pyx_t_7; + } + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 542, __pyx_L10_error) + } else { + __pyx_t_9 = __pyx_t_8(__pyx_t_6); + if (unlikely(!__pyx_t_9)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 542, __pyx_L10_error) + PyErr_Clear(); + } + break; + } + } + __Pyx_GOTREF(__pyx_t_9); + __Pyx_XDECREF_SET(__pyx_8genexpr3__pyx_v_p, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_PySequence_Tuple(__pyx_8genexpr3__pyx_v_p); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 542, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_10 = __Pyx_PyObject_Call(((PyObject *)(&PyComplex_Type)), __pyx_t_9, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 542, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(__Pyx_ListComp_Append(__pyx_t_5, (PyObject*)__pyx_t_10))) __PYX_ERR(0, 542, __pyx_L10_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_p); __pyx_8genexpr3__pyx_v_p = 0; + goto __pyx_L14_exit_scope; + __pyx_L10_error:; + __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_p); __pyx_8genexpr3__pyx_v_p = 0; + goto __pyx_L5_error; + __pyx_L14_exit_scope:; + } /* exit inner scope */ + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(0, 542, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_curve); __pyx_8genexpr2__pyx_v_curve = 0; + goto __pyx_L16_exit_scope; + __pyx_L5_error:; + __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_curve); __pyx_8genexpr2__pyx_v_curve = 0; + goto __pyx_L1_error; + __pyx_L16_exit_scope:; + } /* exit inner scope */ + __Pyx_DECREF_SET(__pyx_v_curves, __pyx_t_1); + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":543 + * + * curves = [[complex(*p) for p in curve] for curve in curves] + * assert len(max_errors) == len(curves) # <<<<<<<<<<<<<< + * + * l = len(curves) +*/ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(__pyx_assertions_enabled())) { + __pyx_t_3 = PyObject_Length(__pyx_v_max_errors); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(0, 543, __pyx_L1_error) + __pyx_t_7 = PyObject_Length(__pyx_v_curves); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 543, __pyx_L1_error) + __pyx_t_11 = (__pyx_t_3 == __pyx_t_7); + if (unlikely(!__pyx_t_11)) { + __Pyx_Raise(((PyObject *)(((PyTypeObject*)PyExc_AssertionError))), 0, 0, 0); + __PYX_ERR(0, 543, __pyx_L1_error) + } + } + #else + if ((1)); else __PYX_ERR(0, 543, __pyx_L1_error) + #endif + + /* "fontTools/cu2qu/cu2qu.py":545 + * assert len(max_errors) == len(curves) + * + * l = len(curves) # <<<<<<<<<<<<<< + * splines = [None] * l + * last_i = i = 0 +*/ + __pyx_t_7 = PyObject_Length(__pyx_v_curves); if (unlikely(__pyx_t_7 == ((Py_ssize_t)-1))) __PYX_ERR(0, 545, __pyx_L1_error) + __pyx_v_l = __pyx_t_7; + + /* "fontTools/cu2qu/cu2qu.py":546 + * + * l = len(curves) + * splines = [None] * l # <<<<<<<<<<<<<< + * last_i = i = 0 + * n = 1 +*/ + __pyx_t_1 = PyList_New(1 * ((__pyx_v_l<0) ? 0:__pyx_v_l)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 546, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + { Py_ssize_t __pyx_temp; + for (__pyx_temp=0; __pyx_temp < __pyx_v_l; __pyx_temp++) { + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + if (__Pyx_PyList_SET_ITEM(__pyx_t_1, __pyx_temp, Py_None) != (0)) __PYX_ERR(0, 546, __pyx_L1_error); + } + } + __pyx_v_splines = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":547 + * l = len(curves) + * splines = [None] * l + * last_i = i = 0 # <<<<<<<<<<<<<< + * n = 1 + * while True: +*/ + __pyx_v_last_i = 0; + __pyx_v_i = 0; + + /* "fontTools/cu2qu/cu2qu.py":548 + * splines = [None] * l + * last_i = i = 0 + * n = 1 # <<<<<<<<<<<<<< + * while True: + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) +*/ + __Pyx_INCREF(__pyx_mstate_global->__pyx_int_1); + __pyx_v_n = __pyx_mstate_global->__pyx_int_1; + + /* "fontTools/cu2qu/cu2qu.py":549 + * last_i = i = 0 + * n = 1 + * while True: # <<<<<<<<<<<<<< + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + * if spline is None: +*/ + while (1) { + + /* "fontTools/cu2qu/cu2qu.py":550 + * n = 1 + * while True: + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) # <<<<<<<<<<<<<< + * if spline is None: + * if n == MAX_N: +*/ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_curves, __pyx_v_i, int, 1, __Pyx_PyLong_From_int, 0, 1, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 550, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_12 = __Pyx_PyLong_As_int(__pyx_v_n); if (unlikely((__pyx_t_12 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 550, __pyx_L1_error) + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_max_errors, __pyx_v_i, int, 1, __Pyx_PyLong_From_int, 0, 1, 1, 1, __Pyx_ReferenceSharing_FunctionArgument); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 550, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_13 = __Pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_13 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 550, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __pyx_f_9fontTools_5cu2qu_5cu2qu_cubic_approx_spline(__pyx_t_1, __pyx_t_12, __pyx_t_13, __pyx_v_all_quadratic); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 550, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF_SET(__pyx_v_spline, __pyx_t_2); + __pyx_t_2 = 0; + + /* "fontTools/cu2qu/cu2qu.py":551 + * while True: + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + * if spline is None: # <<<<<<<<<<<<<< + * if n == MAX_N: + * break +*/ + __pyx_t_11 = (__pyx_v_spline == Py_None); + if (__pyx_t_11) { + + /* "fontTools/cu2qu/cu2qu.py":552 + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + * if spline is None: + * if n == MAX_N: # <<<<<<<<<<<<<< + * break + * n += 1 +*/ + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_MAX_N); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 552, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_v_n, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 552, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_11 < 0))) __PYX_ERR(0, 552, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_11) { + + /* "fontTools/cu2qu/cu2qu.py":553 + * if spline is None: + * if n == MAX_N: + * break # <<<<<<<<<<<<<< + * n += 1 + * last_i = i +*/ + goto __pyx_L18_break; + + /* "fontTools/cu2qu/cu2qu.py":552 + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + * if spline is None: + * if n == MAX_N: # <<<<<<<<<<<<<< + * break + * n += 1 +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":554 + * if n == MAX_N: + * break + * n += 1 # <<<<<<<<<<<<<< + * last_i = i + * continue +*/ + __pyx_t_1 = __Pyx_PyLong_AddObjC(__pyx_v_n, __pyx_mstate_global->__pyx_int_1, 1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 554, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF_SET(__pyx_v_n, __pyx_t_1); + __pyx_t_1 = 0; + + /* "fontTools/cu2qu/cu2qu.py":555 + * break + * n += 1 + * last_i = i # <<<<<<<<<<<<<< + * continue + * splines[i] = spline +*/ + __pyx_v_last_i = __pyx_v_i; + + /* "fontTools/cu2qu/cu2qu.py":556 + * n += 1 + * last_i = i + * continue # <<<<<<<<<<<<<< + * splines[i] = spline + * i = (i + 1) % l +*/ + goto __pyx_L17_continue; + + /* "fontTools/cu2qu/cu2qu.py":551 + * while True: + * spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + * if spline is None: # <<<<<<<<<<<<<< + * if n == MAX_N: + * break +*/ + } + + /* "fontTools/cu2qu/cu2qu.py":557 + * last_i = i + * continue + * splines[i] = spline # <<<<<<<<<<<<<< + * i = (i + 1) % l + * if i == last_i: +*/ + if (unlikely((__Pyx_SetItemInt(__pyx_v_splines, __pyx_v_i, __pyx_v_spline, int, 1, __Pyx_PyLong_From_int, 1, 1, 1, 1, __Pyx_ReferenceSharing_OwnStrongReference) < 0))) __PYX_ERR(0, 557, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":558 + * continue + * splines[i] = spline + * i = (i + 1) % l # <<<<<<<<<<<<<< + * if i == last_i: + * # done. go home +*/ + __pyx_t_14 = (__pyx_v_i + 1); + if (unlikely(__pyx_v_l == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); + __PYX_ERR(0, 558, __pyx_L1_error) + } + __pyx_v_i = __Pyx_mod_long(__pyx_t_14, __pyx_v_l, 0); + + /* "fontTools/cu2qu/cu2qu.py":559 + * splines[i] = spline + * i = (i + 1) % l + * if i == last_i: # <<<<<<<<<<<<<< + * # done. go home + * return [[(s.real, s.imag) for s in spline] for spline in splines] +*/ + __pyx_t_11 = (__pyx_v_i == __pyx_v_last_i); + if (__pyx_t_11) { + + /* "fontTools/cu2qu/cu2qu.py":561 + * if i == last_i: + * # done. go home + * return [[(s.real, s.imag) for s in spline] for spline in splines] # <<<<<<<<<<<<<< + * + * raise ApproxNotFoundError(curves) +*/ + __Pyx_XDECREF(__pyx_r); + { /* enter inner scope */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 561, __pyx_L24_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_v_splines; __Pyx_INCREF(__pyx_t_2); + __pyx_t_7 = 0; + for (;;) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 561, __pyx_L24_error) + #endif + if (__pyx_t_7 >= __pyx_temp) break; + } + __pyx_t_5 = __Pyx_PyList_GetItemRefFast(__pyx_t_2, __pyx_t_7, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_7; + if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 561, __pyx_L24_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XDECREF_SET(__pyx_8genexpr4__pyx_v_spline, __pyx_t_5); + __pyx_t_5 = 0; + { /* enter inner scope */ + __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_5); + if (likely(PyList_CheckExact(__pyx_8genexpr4__pyx_v_spline)) || PyTuple_CheckExact(__pyx_8genexpr4__pyx_v_spline)) { + __pyx_t_6 = __pyx_8genexpr4__pyx_v_spline; __Pyx_INCREF(__pyx_t_6); + __pyx_t_3 = 0; + __pyx_t_4 = NULL; + } else { + __pyx_t_3 = -1; __pyx_t_6 = PyObject_GetIter(__pyx_8genexpr4__pyx_v_spline); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_4 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 561, __pyx_L29_error) + } + for (;;) { + if (likely(!__pyx_t_4)) { + if (likely(PyList_CheckExact(__pyx_t_6))) { + { + Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 561, __pyx_L29_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + __pyx_t_10 = __Pyx_PyList_GetItemRefFast(__pyx_t_6, __pyx_t_3, __Pyx_ReferenceSharing_OwnStrongReference); + ++__pyx_t_3; + } else { + { + Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_6); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 561, __pyx_L29_error) + #endif + if (__pyx_t_3 >= __pyx_temp) break; + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_10 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_6, __pyx_t_3)); + #else + __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_3); + #endif + ++__pyx_t_3; + } + if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 561, __pyx_L29_error) + } else { + __pyx_t_10 = __pyx_t_4(__pyx_t_6); + if (unlikely(!__pyx_t_10)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 561, __pyx_L29_error) + PyErr_Clear(); + } + break; + } + } + __Pyx_GOTREF(__pyx_t_10); + __Pyx_XDECREF_SET(__pyx_8genexpr5__pyx_v_s, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_8genexpr5__pyx_v_s, __pyx_mstate_global->__pyx_n_u_real); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_8genexpr5__pyx_v_s, __pyx_mstate_global->__pyx_n_u_imag); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_15 = PyTuple_New(2); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_15); + __Pyx_GIVEREF(__pyx_t_10); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_10) != (0)) __PYX_ERR(0, 561, __pyx_L29_error); + __Pyx_GIVEREF(__pyx_t_9); + if (__Pyx_PyTuple_SET_ITEM(__pyx_t_15, 1, __pyx_t_9) != (0)) __PYX_ERR(0, 561, __pyx_L29_error); + __pyx_t_10 = 0; + __pyx_t_9 = 0; + if (unlikely(__Pyx_ListComp_Append(__pyx_t_5, (PyObject*)__pyx_t_15))) __PYX_ERR(0, 561, __pyx_L29_error) + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_s); __pyx_8genexpr5__pyx_v_s = 0; + goto __pyx_L33_exit_scope; + __pyx_L29_error:; + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_s); __pyx_8genexpr5__pyx_v_s = 0; + goto __pyx_L24_error; + __pyx_L33_exit_scope:; + } /* exit inner scope */ + if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_5))) __PYX_ERR(0, 561, __pyx_L24_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_spline); __pyx_8genexpr4__pyx_v_spline = 0; + goto __pyx_L35_exit_scope; + __pyx_L24_error:; + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_spline); __pyx_8genexpr4__pyx_v_spline = 0; + goto __pyx_L1_error; + __pyx_L35_exit_scope:; + } /* exit inner scope */ + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "fontTools/cu2qu/cu2qu.py":559 + * splines[i] = spline + * i = (i + 1) % l + * if i == last_i: # <<<<<<<<<<<<<< + * # done. go home + * return [[(s.real, s.imag) for s in spline] for spline in splines] +*/ + } + __pyx_L17_continue:; + } + __pyx_L18_break:; + + /* "fontTools/cu2qu/cu2qu.py":563 + * return [[(s.real, s.imag) for s in spline] for spline in splines] + * + * raise ApproxNotFoundError(curves) # <<<<<<<<<<<<<< +*/ + __pyx_t_2 = NULL; + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ApproxNotFoundError); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 563, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_16 = 1; + #if CYTHON_UNPACK_METHODS + if (unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5); + assert(__pyx_t_2); + PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx__function); + __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); + __pyx_t_16 = 0; + } + #endif + { + PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_curves}; + __pyx_t_1 = __Pyx_PyObject_FastCall((PyObject*)__pyx_t_5, __pyx_callargs+__pyx_t_16, (2-__pyx_t_16) | (__pyx_t_16*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 563, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 563, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":503 + * + * + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) # <<<<<<<<<<<<<< + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): +*/ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_15); + __Pyx_AddTraceback("fontTools.cu2qu.cu2qu.curves_to_quadratic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_splines); + __Pyx_XDECREF(__pyx_v_n); + __Pyx_XDECREF(__pyx_v_spline); + __Pyx_XDECREF(__pyx_8genexpr2__pyx_v_curve); + __Pyx_XDECREF(__pyx_8genexpr3__pyx_v_p); + __Pyx_XDECREF(__pyx_8genexpr4__pyx_v_spline); + __Pyx_XDECREF(__pyx_8genexpr5__pyx_v_s); + __Pyx_XDECREF(__pyx_v_curves); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +/* #### Code section: module_exttypes ### */ + +static PyObject *__pyx_tp_new_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_mstate_global->__pyx_freecount_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen > 0) & __PYX_CHECK_FINAL_TYPE_FOR_FREELISTS(t, __pyx_mstate_global->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen, sizeof(struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen)))) + { + o = (PyObject*)__pyx_mstate_global->__pyx_freelist_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen[--__pyx_mstate_global->__pyx_freecount_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen]; + #if CYTHON_USE_TYPE_SPECS + Py_DECREF(Py_TYPE(o)); + #endif + memset(o, 0, sizeof(struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen)); + #if CYTHON_COMPILING_IN_LIMITED_API + (void) PyObject_Init(o, t); + #else + (void) PyObject_INIT(o, t); + #endif + } else + #endif + { + o = __Pyx_AllocateExtensionType(t, 1); + if (unlikely(!o)) return 0; + } + return o; +} + +static void __pyx_tp_dealloc_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(__Pyx_PyObject_GetSlot(o, tp_finalize, destructor)) && (!PyType_IS_GC(Py_TYPE(o)) || !__Pyx_PyObject_GC_IsFinalized(o))) { + if (__Pyx_PyObject_GetSlot(o, tp_dealloc, destructor) == __pyx_tp_dealloc_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + } + #endif + #if CYTHON_USE_FREELISTS + if (likely((int)(__pyx_mstate_global->__pyx_freecount_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen < 8) & __PYX_CHECK_FINAL_TYPE_FOR_FREELISTS(Py_TYPE(o), __pyx_mstate_global->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen, sizeof(struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen)))) + { + __pyx_mstate_global->__pyx_freelist_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen[__pyx_mstate_global->__pyx_freecount_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen++] = ((struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen *)o); + } else + #endif + { + PyTypeObject *tp = Py_TYPE(o); + #if CYTHON_USE_TYPE_SLOTS + (*tp->tp_free)(o); + #else + { + freefunc tp_free = (freefunc)PyType_GetSlot(tp, Py_tp_free); + if (tp_free) tp_free(o); + } + #endif + #if CYTHON_USE_TYPE_SPECS + Py_DECREF(tp); + #endif + } +} +#if CYTHON_USE_TYPE_SPECS +static PyType_Slot __pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen_slots[] = { + {Py_tp_dealloc, (void *)__pyx_tp_dealloc_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen}, + {Py_tp_new, (void *)__pyx_tp_new_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen}, + {0, 0}, +}; +static PyType_Spec __pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen_spec = { + "fontTools.cu2qu.cu2qu.__pyx_scope_struct___split_cubic_into_n_gen", + sizeof(struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER, + __pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen_slots, +}; +#else + +static PyTypeObject __pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen = { + PyVarObject_HEAD_INIT(0, 0) + "fontTools.cu2qu.cu2qu.""__pyx_scope_struct___split_cubic_into_n_gen", /*tp_name*/ + sizeof(struct __pyx_obj_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_as_async*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + #if !CYTHON_USE_TYPE_SPECS + 0, /*tp_dictoffset*/ + #endif + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if CYTHON_USE_TP_FINALIZE + 0, /*tp_finalize*/ + #else + NULL, /*tp_finalize*/ + #endif + #if !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800 + 0, /*tp_vectorcall*/ + #endif + #if __PYX_NEED_TP_PRINT_SLOT == 1 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030C0000 + 0, /*tp_watched*/ + #endif + #if PY_VERSION_HEX >= 0x030d00A4 + 0, /*tp_versions_used*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 + 0, /*tp_pypy_flags*/ + #endif +}; +#endif + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; +/* #### Code section: initfunc_declarations ### */ +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate); /*proto*/ +/* #### Code section: init_module ### */ + +static int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + #if CYTHON_USE_TYPE_SPECS + __pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen = (PyTypeObject *) __Pyx_PyType_FromModuleAndSpec(__pyx_m, &__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen_spec, NULL); if (unlikely(!__pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen)) __PYX_ERR(0, 150, __pyx_L1_error) + if (__Pyx_fix_up_extension_type_from_spec(&__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen_spec, __pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen) < (0)) __PYX_ERR(0, 150, __pyx_L1_error) + #else + __pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen = &__pyx_type_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen; + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + #endif + #if !CYTHON_USE_TYPE_SPECS + if (__Pyx_PyType_Ready(__pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen) < (0)) __PYX_ERR(0, 150, __pyx_L1_error) + #endif + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030E0000 + PyUnstable_Object_EnableDeferredRefcount((PyObject*)__pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen); + #endif + #if !CYTHON_COMPILING_IN_LIMITED_API + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen->tp_dictoffset && __pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen->tp_getattro == PyObject_GenericGetAttr)) { + __pyx_mstate->__pyx_ptype_9fontTools_5cu2qu_5cu2qu___pyx_scope_struct___split_cubic_into_n_gen->tp_getattro = PyObject_GenericGetAttr; + } + #endif + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_cu2qu(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_cu2qu}, + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + {Py_mod_gil, Py_MOD_GIL_USED}, + #endif + #if PY_VERSION_HEX >= 0x030C0000 && CYTHON_USE_MODULE_STATE + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + #endif + {0, NULL} +}; +#endif + +#ifdef __cplusplus +namespace { + struct PyModuleDef __pyx_moduledef = + #else + static struct PyModuleDef __pyx_moduledef = + #endif + { + PyModuleDef_HEAD_INIT, + "cu2qu", + 0, /* m_doc */ + #if CYTHON_USE_MODULE_STATE + sizeof(__pyx_mstatetype), /* m_size */ + #else + (CYTHON_PEP489_MULTI_PHASE_INIT) ? 0 : -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + #if CYTHON_USE_MODULE_STATE + __pyx_m_traverse, /* m_traverse */ + __pyx_m_clear, /* m_clear */ + NULL /* m_free */ + #else + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ + #endif + }; + #ifdef __cplusplus +} /* anonymous namespace */ +#endif + +/* PyModInitFuncType */ +#ifndef CYTHON_NO_PYINIT_EXPORT + #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#else + #ifdef __cplusplus + #define __Pyx_PyMODINIT_FUNC extern "C" PyObject * + #else + #define __Pyx_PyMODINIT_FUNC PyObject * + #endif +#endif + +__Pyx_PyMODINIT_FUNC PyInit_cu2qu(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_cu2qu(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +/* ModuleCreationPEP489 */ +#if CYTHON_COMPILING_IN_LIMITED_API && (__PYX_LIMITED_VERSION_HEX < 0x03090000\ + || ((defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS)) && __PYX_LIMITED_VERSION_HEX < 0x030A0000)) +static PY_INT64_T __Pyx_GetCurrentInterpreterId(void) { + { + PyObject *module = PyImport_ImportModule("_interpreters"); // 3.13+ I think + if (!module) { + PyErr_Clear(); // just try the 3.8-3.12 version + module = PyImport_ImportModule("_xxsubinterpreters"); + if (!module) goto bad; + } + PyObject *current = PyObject_CallMethod(module, "get_current", NULL); + Py_DECREF(module); + if (!current) goto bad; + if (PyTuple_Check(current)) { + PyObject *new_current = PySequence_GetItem(current, 0); + Py_DECREF(current); + current = new_current; + if (!new_current) goto bad; + } + long long as_c_int = PyLong_AsLongLong(current); + Py_DECREF(current); + return as_c_int; + } + bad: + PySys_WriteStderr("__Pyx_GetCurrentInterpreterId failed. Try setting the C define CYTHON_PEP489_MULTI_PHASE_INIT=0\n"); + return -1; +} +#endif +#if !CYTHON_USE_MODULE_STATE +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + static PY_INT64_T main_interpreter_id = -1; +#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM > 0x19000000 + PY_INT64_T current_id = GraalPyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); +#elif CYTHON_COMPILING_IN_GRAAL + PY_INT64_T current_id = PyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); +#elif CYTHON_COMPILING_IN_LIMITED_API && (__PYX_LIMITED_VERSION_HEX < 0x03090000\ + || ((defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS)) && __PYX_LIMITED_VERSION_HEX < 0x030A0000)) + PY_INT64_T current_id = __Pyx_GetCurrentInterpreterId(); +#elif CYTHON_COMPILING_IN_LIMITED_API + PY_INT64_T current_id = PyInterpreterState_GetID(PyInterpreterState_Get()); +#else + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); +#endif + if (unlikely(current_id == -1)) { + return -1; + } + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return 0; + } else if (unlikely(main_interpreter_id != current_id)) { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +#endif +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) +{ + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { + result = PyDict_SetItemString(moddict, to_name, value); + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + CYTHON_UNUSED_VAR(def); + #if !CYTHON_USE_MODULE_STATE + if (__Pyx_check_single_interpreter()) + return NULL; + #endif + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_cu2qu(PyObject *__pyx_pyinit_module) +#endif +{ + int stringtab_initialized = 0; + #if CYTHON_USE_MODULE_STATE + int pystate_addmodule_run = 0; + #endif + __pyx_mstatetype *__pyx_mstate = NULL; + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + Py_ssize_t __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + double __pyx_t_7; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'cu2qu' has already been imported. Re-initialisation is not supported."); + return -1; + } + #else + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_t_1 = __pyx_pyinit_module; + Py_INCREF(__pyx_t_1); + #else + __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #if CYTHON_USE_MODULE_STATE + { + int add_module_result = __Pyx_State_AddModule(__pyx_t_1, &__pyx_moduledef); + __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "cu2qu" pseudovariable */ + if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + pystate_addmodule_run = 1; + } + #else + __pyx_m = __pyx_t_1; + #endif + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + PyUnstable_Module_SetGIL(__pyx_m, Py_MOD_GIL_USED); + #endif + __pyx_mstate = __pyx_mstate_global; + CYTHON_UNUSED_VAR(__pyx_t_1); + __pyx_mstate->__pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_mstate->__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_mstate->__pyx_d); + __pyx_mstate->__pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_mstate->__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_mstate->__pyx_cython_runtime = __Pyx_PyImport_AddModuleRef("cython_runtime"); if (unlikely(!__pyx_mstate->__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_mstate->__pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /* ImportRefnannyAPI */ + #if CYTHON_REFNANNY + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); + if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); + } + #endif + +__Pyx_RefNannySetupContext("PyInit_cu2qu", 0); + __Pyx_init_runtime_version(); + if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_mstate->__pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_mstate->__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_mstate->__pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_mstate->__pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Library function declarations ---*/ + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitConstants(__pyx_mstate) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + stringtab_initialized = 1; + if (__Pyx_InitGlobals() < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + if (__pyx_module_is_main_fontTools__cu2qu__cu2qu) { + if (PyObject_SetAttr(__pyx_m, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_main) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "fontTools.cu2qu.cu2qu")) { + if (unlikely((PyDict_SetItemString(modules, "fontTools.cu2qu.cu2qu", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins(__pyx_mstate) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants(__pyx_mstate) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + if (__Pyx_CreateCodeObjects(__pyx_mstate) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(__pyx_mstate); + (void)__Pyx_modinit_variable_export_code(__pyx_mstate); + (void)__Pyx_modinit_function_export_code(__pyx_mstate); + if (unlikely((__Pyx_modinit_type_init_code(__pyx_mstate) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_type_import_code(__pyx_mstate); + (void)__Pyx_modinit_variable_import_code(__pyx_mstate); + (void)__Pyx_modinit_function_import_code(__pyx_mstate); + /*--- Execution code ---*/ + + /* "fontTools/cu2qu/cu2qu.py":18 + * # limitations under the License. + * + * try: # <<<<<<<<<<<<<< + * import cython + * except (AttributeError, ImportError): +*/ + { + (void)__pyx_t_1; (void)__pyx_t_2; (void)__pyx_t_3; /* mark used */ + /*try:*/ { + + /* "fontTools/cu2qu/cu2qu.py":19 + * + * try: + * import cython # <<<<<<<<<<<<<< + * except (AttributeError, ImportError): + * # if cython not installed, use mock module with no-op decorators and types +*/ + } + } + + /* "fontTools/cu2qu/cu2qu.py":23 + * # if cython not installed, use mock module with no-op decorators and types + * from fontTools.misc import cython + * COMPILED = cython.compiled # <<<<<<<<<<<<<< + * + * import math +*/ + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_COMPILED, Py_True) < (0)) __PYX_ERR(0, 23, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":25 + * COMPILED = cython.compiled + * + * import math # <<<<<<<<<<<<<< + * + * from .errors import Error as Cu2QuError, ApproxNotFoundError +*/ + __pyx_t_3 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_math, 0, 0, NULL, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 25, __pyx_L1_error) + __pyx_t_4 = __pyx_t_3; + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_math, __pyx_t_4) < (0)) __PYX_ERR(0, 25, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":27 + * import math + * + * from .errors import Error as Cu2QuError, ApproxNotFoundError # <<<<<<<<<<<<<< + * + * +*/ + { + PyObject* const __pyx_imported_names[] = {__pyx_mstate_global->__pyx_n_u_Error,__pyx_mstate_global->__pyx_n_u_ApproxNotFoundError}; + __pyx_t_3 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_errors, __pyx_imported_names, 2, __pyx_mstate_global->__pyx_kp_u_fontTools_cu2qu_errors, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 27, __pyx_L1_error) + } + __pyx_t_4 = __pyx_t_3; + __Pyx_GOTREF(__pyx_t_4); + { + PyObject* const __pyx_imported_names[] = {__pyx_mstate_global->__pyx_n_u_Error,__pyx_mstate_global->__pyx_n_u_ApproxNotFoundError}; + for (__pyx_t_5=0; __pyx_t_5 < 2; __pyx_t_5++) { + __pyx_t_6 = __Pyx_ImportFrom(__pyx_t_4, __pyx_imported_names[__pyx_t_5]); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 27, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + switch (__pyx_t_5) { + case 0: + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_Cu2QuError, __pyx_t_6) < (0)) __PYX_ERR(0, 27, __pyx_L1_error) + break; + default:; + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_imported_names[__pyx_t_5], __pyx_t_6) < (0)) __PYX_ERR(0, 27, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":30 + * + * + * __all__ = ["curve_to_quadratic", "curves_to_quadratic"] # <<<<<<<<<<<<<< + * + * MAX_N = 100 +*/ + __pyx_t_4 = __Pyx_PyList_Pack(2, __pyx_mstate_global->__pyx_n_u_curve_to_quadratic, __pyx_mstate_global->__pyx_n_u_curves_to_quadratic); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 30, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_all, __pyx_t_4) < (0)) __PYX_ERR(0, 30, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":32 + * __all__ = ["curve_to_quadratic", "curves_to_quadratic"] + * + * MAX_N = 100 # <<<<<<<<<<<<<< + * + * NAN = float("NaN") +*/ + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_MAX_N, __pyx_mstate_global->__pyx_int_100) < (0)) __PYX_ERR(0, 32, __pyx_L1_error) + + /* "fontTools/cu2qu/cu2qu.py":34 + * MAX_N = 100 + * + * NAN = float("NaN") # <<<<<<<<<<<<<< + * + * +*/ + __pyx_t_7 = __Pyx_PyUnicode_AsDouble(__pyx_mstate_global->__pyx_n_u_NaN); if (unlikely(__PYX_CHECK_FLOAT_EXCEPTION(__pyx_t_7, ((double)((double)-1))) && PyErr_Occurred())) __PYX_ERR(0, 34, __pyx_L1_error) + __pyx_t_4 = PyFloat_FromDouble(__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_NAN, __pyx_t_4) < (0)) __PYX_ERR(0, 34, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":150 + * + * + * @cython.locals( # <<<<<<<<<<<<<< + * p0=cython.complex, + * p1=cython.complex, +*/ + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9fontTools_5cu2qu_5cu2qu_1_split_cubic_into_n_gen, 0, __pyx_mstate_global->__pyx_n_u_split_cubic_into_n_gen, NULL, __pyx_mstate_global->__pyx_n_u_fontTools_cu2qu_cu2qu, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030E0000 + PyUnstable_Object_EnableDeferredRefcount(__pyx_t_4); + #endif + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_split_cubic_into_n_gen, __pyx_t_4) < (0)) __PYX_ERR(0, 150, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":471 + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) + * def curve_to_quadratic(curve, max_err, all_quadratic=True): # <<<<<<<<<<<<<< + * """Approximate a cubic Bezier curve with a spline of n quadratics. + * +*/ + __pyx_t_4 = __Pyx_PyBool_FromLong(((int)1)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 471, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "fontTools/cu2qu/cu2qu.py":468 + * + * + * @cython.locals(max_err=cython.double) # <<<<<<<<<<<<<< + * @cython.locals(n=cython.int) + * @cython.locals(all_quadratic=cython.int) +*/ + __pyx_t_6 = PyTuple_Pack(1, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9fontTools_5cu2qu_5cu2qu_4curve_to_quadratic, 0, __pyx_mstate_global->__pyx_n_u_curve_to_quadratic, NULL, __pyx_mstate_global->__pyx_n_u_fontTools_cu2qu_cu2qu, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[1])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030E0000 + PyUnstable_Object_EnableDeferredRefcount(__pyx_t_4); + #endif + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_4, __pyx_t_6); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_curve_to_quadratic, __pyx_t_4) < (0)) __PYX_ERR(0, 468, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":505 + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): # <<<<<<<<<<<<<< + * """Return quadratic Bezier splines approximating the input cubic Beziers. + * +*/ + __pyx_t_4 = __Pyx_PyBool_FromLong(((int)1)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 505, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "fontTools/cu2qu/cu2qu.py":503 + * + * + * @cython.locals(l=cython.int, last_i=cython.int, i=cython.int) # <<<<<<<<<<<<<< + * @cython.locals(all_quadratic=cython.int) + * def curves_to_quadratic(curves, max_errors, all_quadratic=True): +*/ + __pyx_t_6 = PyTuple_Pack(1, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_9fontTools_5cu2qu_5cu2qu_6curves_to_quadratic, 0, __pyx_mstate_global->__pyx_n_u_curves_to_quadratic, NULL, __pyx_mstate_global->__pyx_n_u_fontTools_cu2qu_cu2qu, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[2])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030E0000 + PyUnstable_Object_EnableDeferredRefcount(__pyx_t_4); + #endif + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_4, __pyx_t_6); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_curves_to_quadratic, __pyx_t_4) < (0)) __PYX_ERR(0, 503, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "fontTools/cu2qu/cu2qu.py":1 + * # cython: language_level=3 # <<<<<<<<<<<<<< + * # distutils: define_macros=CYTHON_TRACE_NOGIL=1 + * +*/ + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_mstate_global->__pyx_kp_u_curves_to_quadratic_line_503, __pyx_mstate_global->__pyx_kp_u_Return_quadratic_Bezier_splines) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_4) < (0)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_6); + if (__pyx_m) { + if (__pyx_mstate->__pyx_d && stringtab_initialized) { + __Pyx_AddTraceback("init fontTools.cu2qu.cu2qu", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + #if !CYTHON_USE_MODULE_STATE + Py_CLEAR(__pyx_m); + #else + Py_DECREF(__pyx_m); + if (pystate_addmodule_run) { + PyObject *tp, *value, *tb; + PyErr_Fetch(&tp, &value, &tb); + PyState_RemoveModule(&__pyx_moduledef); + PyErr_Restore(tp, value, tb); + } + #endif + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init fontTools.cu2qu.cu2qu"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #else + return __pyx_m; + #endif +} +/* #### Code section: pystring_table ### */ +/* #### Code section: cached_builtins ### */ + +static int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate) { + CYTHON_UNUSED_VAR(__pyx_mstate); + + /* Cached unbound methods */ + __pyx_mstate->__pyx_umethod_PyDict_Type_items.type = (PyObject*)&PyDict_Type; + __pyx_mstate->__pyx_umethod_PyDict_Type_items.method_name = &__pyx_mstate->__pyx_n_u_items; + __pyx_mstate->__pyx_umethod_PyDict_Type_pop.type = (PyObject*)&PyDict_Type; + __pyx_mstate->__pyx_umethod_PyDict_Type_pop.method_name = &__pyx_mstate->__pyx_n_u_pop; + __pyx_mstate->__pyx_umethod_PyDict_Type_values.type = (PyObject*)&PyDict_Type; + __pyx_mstate->__pyx_umethod_PyDict_Type_values.method_name = &__pyx_mstate->__pyx_n_u_values; + return 0; +} +/* #### Code section: cached_constants ### */ + +static int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate) { + __Pyx_RefNannyDeclarations + CYTHON_UNUSED_VAR(__pyx_mstate); + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + __Pyx_RefNannyFinishContext(); + return 0; +} +/* #### Code section: init_constants ### */ + +static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) { + CYTHON_UNUSED_VAR(__pyx_mstate); + { + const struct { const unsigned int length: 11; } index[] = {{1},{28},{1566},{1},{30},{7},{6},{22},{2},{9},{19},{8},{10},{5},{5},{3},{3},{20},{1},{2},{7},{13},{18},{1},{2},{1},{2},{18},{5},{5},{18},{6},{19},{1},{2},{7},{7},{2},{6},{21},{8},{1},{4},{13},{5},{5},{1},{6},{8},{4},{7},{10},{10},{1},{8},{4},{1},{2},{2},{2},{2},{3},{12},{4},{1},{4},{12},{10},{6},{7},{23},{2},{4},{8},{5},{5},{6},{97},{211},{2}}; + #if (CYTHON_COMPRESS_STRINGS) == 2 /* compression: bz2 (1382 bytes) */ +const char* const cstring = "BZh91AY&SY\005#\031&\000\0012\377\377\357_\356\002~\377\377\363\277\267\377\312\377\357\377\364@@@@@@@@@\000@@@\000@\000P\004\335\307=\272\353\305\252\2734y\007\23454Hj\031\224\3231\021\372\232\021\221\223#\324\03140\2324\000\000\000a\001\246\231\036\240\320\204\301\032\tO\3224#i=O\n\014 \006@h\000\000\031\032\003& \320\tM\021\032&\204\312~\2044\323T\365?\022\201\221\265\000\321\3522= \r\001\240\001\223M\000=@\323SU7\252z\236\223\323\324\206@\000\003@h\0004\001\220\000\000\001\243G\250\365\000%5S(f\221\352\003L\324\006\232\017P\321\240\032\003C@\000\000\000\000\000\026l\225N@\031\276\264\242\036\352\026\030\277\007\350\005*\002$\001\257;\371\250\230\270\357\001\0310\200\342\364\237\376;\357\302\307\177\257\365\367^\311\226sR\220?\353\341\267\357\373ro\033\022/n\001l\211n\207\210\226a\377\331\034>J\3271\307~\234\346\226\001\204\3145\347\004\031z b\021\341\342\354(4V\215]\236\361\354\366\243\367\354\317\300Z\326\246i-\273\013\232\224\313'\214y\n\024+\264\360HC\000\3338\010L|\030\324Lk\300\026~\034P\214\341\006\207\344\000\205(\204a-t\303z\330\010E\210\265\217\201=\223\024*\026\002\356c\034Q\225\013\300.\177z\362&\261\024\353\177\205MYBx\000+\307\003\350kW\271\270\216\261\242\340\034V\207R\234\230g\312\276U\357\026>}u\255\\\371t\377\332\322Z\322N\336\246[\251\227}\223\275\031\335\275X\\N\226\2227\351\335\264\221\366\263\255\214L\226K\037K\337\217\332\243\267\343\247\343\263\363\205\311\362\215d3\3751+]\254\336N\353i7\035d\335l0\332\035\337\031\223\213\305\225\217+\337\3027y\267pQ}\360\351\267\205kK7\223nB\222\223\264\227]\317\326\263x\364\353x\335\250Y\274\2214\340\340\337\254\221y\243\2225|=q\223\366d\361&\360\217\323\235\364h\262\270\226\354\246\245\t\034\201\300R\341\312\237cw\274\375\376\372\373\326y\367\334\377p\327\272\364]\332\235\254\336Jdz;mO\276.MVK \271zGs\327&\313\267\222\243t\t\366\313k\311\216\271\263\225\022-WO\376H\0274\024Ws\322\223\214d'#\177\374\303\370\364\275:o}\350\316B\372\017dB\021\374"; + PyObject *data = __Pyx_DecompressString(cstring, 1265, 1); + if (unlikely(!data)) __PYX_ERR(0, 1, __pyx_L1_error) + const char* const bytes = __Pyx_PyBytes_AsString(data); + #if !CYTHON_ASSUME_SAFE_MACROS + if (likely(bytes)); else { Py_DECREF(data); __PYX_ERR(0, 1, __pyx_L1_error) } + #endif + #else /* compression: none (2435 bytes) */ +const char* const bytes = ".Lib/fontTools/cu2qu/cu2qu.pyReturn quadratic Bezier splines approximating the input cubic Beziers.\n\n Args:\n curves: A sequence of *n* curves, each curve being a sequence of four\n 2D tuples.\n max_errors: A sequence of *n* floats representing the maximum permissible\n deviation from each of the cubic Bezier curves.\n all_quadratic (bool): If True (default) returned values are a\n quadratic spline. If False, they are either a single quadratic\n curve or a single cubic curve.\n\n Example::\n\n >>> curves_to_quadratic( [\n ... [ (50,50), (100,100), (150,100), (200,50) ],\n ... [ (75,50), (120,100), (150,75), (200,60) ]\n ... ], [1,1] )\n [[(50.0, 50.0), (75.0, 75.0), (125.0, 91.66666666666666), (175.0, 75.0), (200.0, 50.0)], [(75.0, 50.0), (97.5, 75.0), (135.41666666666666, 82.08333333333333), (175.0, 67.5), (200.0, 60.0)]]\n\n The returned splines have \"implied oncurve points\" suitable for use in\n TrueType ``glif`` outlines - i.e. in the first spline returned above,\n the first quadratic segment runs from (50,50) to\n ( (75 + 125)/2 , (120 + 91.666..)/2 ) = (100, 83.333...).\n\n Returns:\n If all_quadratic is True, a list of splines, each spline being a list\n of 2D tuples.\n\n If all_quadratic is False, a list of curves, each curve being a quadratic\n (length 3), or cubic (length 4).\n\n Raises:\n fontTools.cu2qu.Errors.ApproxNotFoundError: if no suitable approximation\n can be found for all curves with the given parameters.\n ?curves_to_quadratic (line 503)disableenablefontTools.cu2qu.errorsgcisenabledApproxNotFoundErrorCOMPILEDCu2QuErrorErrorMAX_NNANNaN__Pyx_PyDict_NextRefaa1__all__all_quadraticasyncio.coroutinesbb1cc1cline_in_tracebackclosecurvecurve_to_quadraticcurvescurves_to_quadraticdd1delta_2delta_3dterrorsfontTools.cu2qu.cu2qu__func__iimag_is_coroutineisnanitemsllast_i__main__math""max_errmax_errors__module__n__name__nextpp0p1p2p3pop__qualname__realssend__set_name__setdefaultsplinesplines_split_cubic_into_n_gent1t1_2__test__throwvaluevalues\200\001\360\006\000()\360*\000\005\r\210A\210W\220B\220c\230\024\230U\240!\340\004\010\210\005\210U\220!\2203\220f\230B\230a\330\010\021\320\021$\240A\240W\250C\250y\270\001\330\010\013\2107\220'\230\021\340\014\023\2202\220Q\220g\230Q\230g\240T\250\025\250a\340\004\n\320\n\035\230Q\230a\200\001\340,-\360J\001\000\005\016\210Q\210a\210w\220b\230\003\2304\230u\240G\2504\250y\270\001\330\004\013\2103\210a\210|\2303\230c\240\021\240!\340\004\010\210\003\2101\210A\330\004\016\210a\210v\220R\220q\330\004\r\210T\220\021\330\004\010\210\001\330\004\005\330\010\021\320\021$\240A\240V\2501\250D\260\003\260:\270Q\270d\300!\330\010\013\2107\220#\220Q\330\014\017\210r\220\023\220A\330\020\021\330\014\021\220\021\330\014\025\220Q\330\014\r\330\010\017\210q\220\005\220Q\330\010\r\210R\210r\220\023\220B\220a\330\010\013\2102\210S\220\001\340\014\023\2201\220B\220a\220w\230a\230w\240d\250%\250x\260t\270:\300Q\340\004\n\320\n\035\230Q\230a\200\001"; + PyObject *data = NULL; + CYTHON_UNUSED_VAR(__Pyx_DecompressString); + #endif + PyObject **stringtab = __pyx_mstate->__pyx_string_tab; + Py_ssize_t pos = 0; + for (int i = 0; i < 77; i++) { + Py_ssize_t bytes_length = index[i].length; + PyObject *string = PyUnicode_DecodeUTF8(bytes + pos, bytes_length, NULL); + if (likely(string) && i >= 10) PyUnicode_InternInPlace(&string); + if (unlikely(!string)) { + Py_XDECREF(data); + __PYX_ERR(0, 1, __pyx_L1_error) + } + stringtab[i] = string; + pos += bytes_length; + } + for (int i = 77; i < 80; i++) { + Py_ssize_t bytes_length = index[i].length; + PyObject *string = PyBytes_FromStringAndSize(bytes + pos, bytes_length); + stringtab[i] = string; + pos += bytes_length; + if (unlikely(!string)) { + Py_XDECREF(data); + __PYX_ERR(0, 1, __pyx_L1_error) + } + } + Py_XDECREF(data); + for (Py_ssize_t i = 0; i < 80; i++) { + if (unlikely(PyObject_Hash(stringtab[i]) == -1)) { + __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #if CYTHON_IMMORTAL_CONSTANTS + { + PyObject **table = stringtab + 77; + for (Py_ssize_t i=0; i<3; ++i) { + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + Py_SET_REFCNT(table[i], _Py_IMMORTAL_REFCNT_LOCAL); + #else + Py_SET_REFCNT(table[i], _Py_IMMORTAL_INITIAL_REFCNT); + #endif + } + } + #endif + } + { + PyObject **numbertab = __pyx_mstate->__pyx_number_tab + 0; + int8_t const cint_constants_1[] = {1,2,3,4,6,100}; + for (int i = 0; i < 6; i++) { + numbertab[i] = PyLong_FromLong(cint_constants_1[i - 0]); + if (unlikely(!numbertab[i])) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #if CYTHON_IMMORTAL_CONSTANTS + { + PyObject **table = __pyx_mstate->__pyx_number_tab; + for (Py_ssize_t i=0; i<6; ++i) { + #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + Py_SET_REFCNT(table[i], _Py_IMMORTAL_REFCNT_LOCAL); + #else + Py_SET_REFCNT(table[i], _Py_IMMORTAL_INITIAL_REFCNT); + #endif + } + } + #endif + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: init_codeobjects ### */ +typedef struct { + unsigned int argcount : 3; + unsigned int num_posonly_args : 1; + unsigned int num_kwonly_args : 1; + unsigned int nlocals : 5; + unsigned int flags : 10; + unsigned int first_line : 9; +} __Pyx_PyCode_New_function_description; +/* NewCodeObj.proto */ +static PyObject* __Pyx_PyCode_New( + const __Pyx_PyCode_New_function_description descr, + PyObject * const *varnames, + PyObject *filename, + PyObject *funcname, + PyObject *line_table, + PyObject *tuple_dedup_map +); + + +static int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate) { + PyObject* tuple_dedup_map = PyDict_New(); + if (unlikely(!tuple_dedup_map)) return -1; + { + const __Pyx_PyCode_New_function_description descr = {5, 0, 0, 19, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR), 150}; + PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_p0, __pyx_mstate->__pyx_n_u_p1, __pyx_mstate->__pyx_n_u_p2, __pyx_mstate->__pyx_n_u_p3, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_a1, __pyx_mstate->__pyx_n_u_b1, __pyx_mstate->__pyx_n_u_c1, __pyx_mstate->__pyx_n_u_d1, __pyx_mstate->__pyx_n_u_dt, __pyx_mstate->__pyx_n_u_delta_2, __pyx_mstate->__pyx_n_u_delta_3, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_a, __pyx_mstate->__pyx_n_u_b, __pyx_mstate->__pyx_n_u_c, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_t1, __pyx_mstate->__pyx_n_u_t1_2}; + __pyx_mstate_global->__pyx_codeobj_tab[0] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_split_cubic_into_n_gen, __pyx_mstate->__pyx_kp_b_iso88591__3, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[0])) goto bad; + } + { + const __Pyx_PyCode_New_function_description descr = {3, 0, 0, 7, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 468}; + PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_max_err, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_s}; + __pyx_mstate_global->__pyx_codeobj_tab[1] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_curve_to_quadratic, __pyx_mstate->__pyx_kp_b_iso88591_AWBc_U_U_3fBa_AWCy_7_2QgQgT_a_Q, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[1])) goto bad; + } + { + const __Pyx_PyCode_New_function_description descr = {3, 0, 0, 13, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 503}; + PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_curves, __pyx_mstate->__pyx_n_u_max_errors, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_l, __pyx_mstate->__pyx_n_u_last_i, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_splines, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_s}; + __pyx_mstate_global->__pyx_codeobj_tab[2] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_curves_to_quadratic, __pyx_mstate->__pyx_kp_b_iso88591_J_Qawb_4uG4y_3a_3c_1A_avRq_T_AV, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[2])) goto bad; + } + Py_DECREF(tuple_dedup_map); + return 0; + bad: + Py_DECREF(tuple_dedup_map); + return -1; +} +/* #### Code section: init_globals ### */ + +static int __Pyx_InitGlobals(void) { + /* PythonCompatibility.init */ + if (likely(__Pyx_init_co_variables() == 0)); else + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + /* AssertionsEnabled.init */ + if (likely(__Pyx_init_assertions_enabled() == 0)); else + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + /* CommonTypesMetaclass.init */ + if (likely(__pyx_CommonTypesMetaclass_init(__pyx_m) == 0)); else + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + /* CachedMethodType.init */ + #if CYTHON_COMPILING_IN_LIMITED_API + { + PyObject *typesModule=NULL; + typesModule = PyImport_ImportModule("types"); + if (typesModule) { + __pyx_mstate_global->__Pyx_CachedMethodType = PyObject_GetAttrString(typesModule, "MethodType"); + Py_DECREF(typesModule); + } + } // error handling follows + #endif + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + /* CythonFunctionShared.init */ + if (likely(__pyx_CyFunction_init(__pyx_m) == 0)); else + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + /* Generator.init */ + if (likely(__pyx_Generator_init(__pyx_m) == 0)); else + + if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) + + return 0; + __pyx_L1_error:; + return -1; +} +/* #### Code section: cleanup_globals ### */ +/* #### Code section: cleanup_module ### */ +/* #### Code section: main_method ### */ +/* #### Code section: utility_code_pragmas ### */ +#ifdef _MSC_VER +#pragma warning( push ) +/* Warning 4127: conditional expression is constant + * Cython uses constant conditional expressions to allow in inline functions to be optimized at + * compile-time, so this warning is not useful + */ +#pragma warning( disable : 4127 ) +#endif + + + +/* #### Code section: utility_code_def ### */ + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyObjectCall (used by PyObjectFastCall) */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO (used by PyObjectFastCall) */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); + self = __Pyx_CyOrPyCFunction_GET_SELF(func); + if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) + return NULL; + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectFastCall */ +#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API +static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs) { + PyObject *argstuple; + PyObject *result = 0; + size_t i; + argstuple = PyTuple_New((Py_ssize_t)nargs); + if (unlikely(!argstuple)) return NULL; + for (i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) != (0)) goto bad; + } + result = __Pyx_PyObject_Call(func, argstuple, kwargs); + bad: + Py_DECREF(argstuple); + return result; +} +#endif +#if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API + #if PY_VERSION_HEX < 0x03090000 + #define __Pyx_PyVectorcall_Function(callable) _PyVectorcall_Function(callable) + #elif CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE vectorcallfunc __Pyx_PyVectorcall_Function(PyObject *callable) { + PyTypeObject *tp = Py_TYPE(callable); + #if defined(__Pyx_CyFunction_USED) + if (__Pyx_CyFunction_CheckExact(callable)) { + return __Pyx_CyFunction_func_vectorcall(callable); + } + #endif + if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) { + return NULL; + } + assert(PyCallable_Check(callable)); + Py_ssize_t offset = tp->tp_vectorcall_offset; + assert(offset > 0); + vectorcallfunc ptr; + memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); + return ptr; +} + #else + #define __Pyx_PyVectorcall_Function(callable) PyVectorcall_Function(callable) + #endif +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject *const *args, size_t _nargs, PyObject *kwargs) { + Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); +#if CYTHON_COMPILING_IN_CPYTHON + if (nargs == 0 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) + return __Pyx_PyObject_CallMethO(func, NULL); + } + else if (nargs == 1 && kwargs == NULL) { + if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) + return __Pyx_PyObject_CallMethO(func, args[0]); + } +#endif + if (kwargs == NULL) { + #if CYTHON_VECTORCALL + #if CYTHON_COMPILING_IN_LIMITED_API + return PyObject_Vectorcall(func, args, _nargs, NULL); + #else + vectorcallfunc f = __Pyx_PyVectorcall_Function(func); + if (f) { + return f(func, args, _nargs, NULL); + } + #endif + #endif + } + if (nargs == 0) { + return __Pyx_PyObject_Call(func, __pyx_mstate_global->__pyx_empty_tuple, kwargs); + } + #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API + return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); + #else + return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); + #endif +} + +/* PyLongCompare */ +static CYTHON_INLINE int __Pyx_PyLong_BoolEqObjC(PyObject *op1, PyObject *op2, long intval, long inplace) { + CYTHON_MAYBE_UNUSED_VAR(intval); + CYTHON_UNUSED_VAR(inplace); + if (op1 == op2) { + return 1; + } + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + int unequal; + unsigned long uintval; + Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); + const digit* digits = __Pyx_PyLong_Digits(op1); + if (intval == 0) { + return (__Pyx_PyLong_IsZero(op1) == 1); + } else if (intval < 0) { + if (__Pyx_PyLong_IsNonNeg(op1)) + return 0; + intval = -intval; + } else { + if (__Pyx_PyLong_IsNeg(op1)) + return 0; + } + uintval = (unsigned long) intval; +#if PyLong_SHIFT * 4 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 4)) { + unequal = (size != 5) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[4] != ((uintval >> (4 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 3 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 3)) { + unequal = (size != 4) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 2 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 2)) { + unequal = (size != 3) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif +#if PyLong_SHIFT * 1 < SIZEOF_LONG*8 + if (uintval >> (PyLong_SHIFT * 1)) { + unequal = (size != 2) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) + | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); + } else +#endif + unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); + return (unequal == 0); + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; + double a = __Pyx_PyFloat_AS_DOUBLE(op1); + return ((double)a == (double)b); + } + return __Pyx_PyObject_IsTrueAndDecref( + PyObject_RichCompare(op1, op2, Py_EQ)); +} + +/* RaiseTooManyValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* PyErrFetchRestore (used by IterFinish) */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject *tmp_value; + assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); + if (value) { + #if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) + #endif + PyException_SetTraceback(value, tb); + } + tmp_value = tstate->current_exception; + tstate->current_exception = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#endif +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyObject* exc_value; + exc_value = tstate->current_exception; + tstate->current_exception = 0; + *value = exc_value; + *type = NULL; + *tb = NULL; + if (exc_value) { + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + #if CYTHON_COMPILING_IN_CPYTHON + *tb = ((PyBaseExceptionObject*) exc_value)->traceback; + Py_XINCREF(*tb); + #else + *tb = PyException_GetTraceback(exc_value); + #endif + } +#else + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#endif +} +#endif + +/* IterFinish */ +static CYTHON_INLINE int __Pyx_IterFinish(void) { + PyObject* exc_type; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + exc_type = __Pyx_PyErr_CurrentExceptionType(); + if (unlikely(exc_type)) { + if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) + return -1; + __Pyx_PyErr_Clear(); + return 0; + } + return 0; +} + +/* UnpackItemEndCheck */ +static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { + if (unlikely(retval)) { + Py_DECREF(retval); + __Pyx_RaiseTooManyValuesError(expected); + return -1; + } + return __Pyx_IterFinish(); +} + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (unlikely(!j)) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck, int unsafe_shared) { + CYTHON_MAYBE_UNUSED_VAR(unsafe_shared); +#if CYTHON_ASSUME_SAFE_SIZE + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS || !CYTHON_ASSUME_SAFE_MACROS)) { + return __Pyx_PyList_GetItemRefFast(o, wrapped_i, unsafe_shared); + } else + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + return __Pyx_NewRef(PyList_GET_ITEM(o, wrapped_i)); + } + return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); +#else + (void)wraparound; + (void)boundscheck; + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck, int unsafe_shared) { + CYTHON_MAYBE_UNUSED_VAR(unsafe_shared); +#if CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + return __Pyx_NewRef(PyTuple_GET_ITEM(o, wrapped_i)); + } + return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); +#else + (void)wraparound; + (void)boundscheck; + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + int wraparound, int boundscheck, int unsafe_shared) { + CYTHON_MAYBE_UNUSED_VAR(unsafe_shared); +#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS)) { + return __Pyx_PyList_GetItemRefFast(o, n, unsafe_shared); + } else if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + return __Pyx_NewRef(PyList_GET_ITEM(o, n)); + } + } else + #if !CYTHON_AVOID_BORROWED_REFS + if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + return __Pyx_NewRef(PyTuple_GET_ITEM(o, n)); + } + } else + #endif +#endif +#if CYTHON_USE_TYPE_SLOTS && !CYTHON_COMPILING_IN_PYPY + { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (!is_list && mm && mm->mp_subscript) { + PyObject *r, *key = PyLong_FromSsize_t(i); + if (unlikely(!key)) return NULL; + r = mm->mp_subscript(o, key); + Py_DECREF(key); + return r; + } + if (is_list || likely(sm && sm->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return sm->sq_item(o, i); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + (void)wraparound; + (void)boundscheck; + return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); +} + +/* PyErrExceptionMatches (used by PyObjectGetAttrStrNoError) */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); + for (i=0; i= 0x030C00A6 + PyObject *current_exception = tstate->current_exception; + if (unlikely(!current_exception)) return 0; + exc_type = (PyObject*) Py_TYPE(current_exception); + if (exc_type == err) return 1; +#else + exc_type = tstate->curexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; +#endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(exc_type); + #endif + if (unlikely(PyTuple_Check(err))) { + result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + } else { + result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(exc_type); + #endif + return result; +} +#endif + +/* PyObjectGetAttrStr (used by PyObjectGetAttrStrNoError) */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError (used by GetBuiltinName) */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +#endif +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + (void) PyObject_GetOptionalAttr(obj, attr_name, &result); + return result; +#else +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +#endif +} + +/* GetBuiltinName (used by GetModuleGlobalName) */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_b, name); + if (unlikely(!result) && !PyErr_Occurred()) { + PyErr_Format(PyExc_NameError, + "name '%U' is not defined", name); + } + return result; +} + +/* PyDictVersioning (used by GetModuleGlobalName) */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!__pyx_m)) { + if (!PyErr_Occurred()) + PyErr_SetNone(PyExc_NameError); + return NULL; + } + result = PyObject_GetAttr(__pyx_m, name); + if (likely(result)) { + return result; + } + PyErr_Clear(); +#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS + if (unlikely(__Pyx_PyDict_GetItemRef(__pyx_mstate_global->__pyx_d, name, &result) == -1)) PyErr_Clear(); + __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return result; + } +#else + result = _PyDict_GetItem_KnownHash(__pyx_mstate_global->__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* TupleAndListFromArray (used by fastcall) */ +#if !CYTHON_COMPILING_IN_CPYTHON && CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + Py_ssize_t i; + if (n <= 0) { + return __Pyx_NewRef(__pyx_mstate_global->__pyx_empty_tuple); + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + for (i = 0; i < n; i++) { + if (unlikely(__Pyx_PyTuple_SET_ITEM(res, i, src[i]) < (0))) { + Py_DECREF(res); + return NULL; + } + Py_INCREF(src[i]); + } + return res; +} +#elif CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { + PyObject *v; + Py_ssize_t i; + for (i = 0; i < length; i++) { + v = dest[i] = src[i]; + Py_INCREF(v); + } +} +static CYTHON_INLINE PyObject * +__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return __Pyx_NewRef(__pyx_mstate_global->__pyx_empty_tuple); + } + res = PyTuple_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); + return res; +} +static CYTHON_INLINE PyObject * +__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyObject *res; + if (n <= 0) { + return PyList_New(0); + } + res = PyList_New(n); + if (unlikely(res == NULL)) return NULL; + __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); + return res; +} +#endif + +/* BytesEquals (used by UnicodeEquals) */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL ||\ + !(CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals (used by fastcall) */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL + return PyObject_RichCompareBool(s1, s2, equals); +#else + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length, length2; + int kind; + void *data1, *data2; + #if !CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + #endif + length = __Pyx_PyUnicode_GET_LENGTH(s1); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely(length < 0)) return -1; + #endif + length2 = __Pyx_PyUnicode_GET_LENGTH(s2); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely(length2 < 0)) return -1; + #endif + if (length != length2) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + return (equals == Py_EQ); +return_ne: + return (equals == Py_NE); +#endif +} + +/* fastcall */ +#if CYTHON_METH_FASTCALL +static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) +{ + Py_ssize_t i, n = __Pyx_PyTuple_GET_SIZE(kwnames); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely(n == -1)) return NULL; + #endif + for (i = 0; i < n; i++) + { + PyObject *namei = __Pyx_PyTuple_GET_ITEM(kwnames, i); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely(!namei)) return NULL; + #endif + if (s == namei) return kwvalues[i]; + } + for (i = 0; i < n; i++) + { + PyObject *namei = __Pyx_PyTuple_GET_ITEM(kwnames, i); + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely(!namei)) return NULL; + #endif + int eq = __Pyx_PyUnicode_Equals(s, namei, Py_EQ); + if (unlikely(eq != 0)) { + if (unlikely(eq < 0)) return NULL; + return kwvalues[i]; + } + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API +CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { + Py_ssize_t i, nkwargs; + PyObject *dict; +#if !CYTHON_ASSUME_SAFE_SIZE + nkwargs = PyTuple_Size(kwnames); + if (unlikely(nkwargs < 0)) return NULL; +#else + nkwargs = PyTuple_GET_SIZE(kwnames); +#endif + dict = PyDict_New(); + if (unlikely(!dict)) + return NULL; + for (i=0; itype, *target->method_name); + if (unlikely(!method)) + return -1; + result = method; +#if CYTHON_COMPILING_IN_CPYTHON + if (likely(__Pyx_TypeCheck(method, &PyMethodDescr_Type))) + { + PyMethodDescrObject *descr = (PyMethodDescrObject*) method; + target->func = descr->d_method->ml_meth; + target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS); + } else +#endif +#if CYTHON_COMPILING_IN_PYPY +#else + if (PyCFunction_Check(method)) +#endif + { + PyObject *self; + int self_found; +#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY + self = PyObject_GetAttrString(method, "__self__"); + if (!self) { + PyErr_Clear(); + } +#else + self = PyCFunction_GET_SELF(method); +#endif + self_found = (self && self != Py_None); +#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY + Py_XDECREF(self); +#endif + if (self_found) { + PyObject *unbound_method = PyCFunction_New(&__Pyx_UnboundCMethod_Def, method); + if (unlikely(!unbound_method)) return -1; + Py_DECREF(method); + result = unbound_method; + } + } +#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + if (unlikely(target->method)) { + Py_DECREF(result); + } else +#endif + target->method = result; + return 0; +} + +/* CallUnboundCMethod0 */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self) { + int was_initialized = __Pyx_CachedCFunction_GetAndSetInitializing(cfunc); + if (likely(was_initialized == 2 && cfunc->func)) { + if (likely(cfunc->flag == METH_NOARGS)) + return __Pyx_CallCFunction(cfunc, self, NULL); + if (likely(cfunc->flag == METH_FASTCALL)) + return __Pyx_CallCFunctionFast(cfunc, self, NULL, 0); + if (cfunc->flag == (METH_FASTCALL | METH_KEYWORDS)) + return __Pyx_CallCFunctionFastWithKeywords(cfunc, self, NULL, 0, NULL); + if (likely(cfunc->flag == (METH_VARARGS | METH_KEYWORDS))) + return __Pyx_CallCFunctionWithKeywords(cfunc, self, __pyx_mstate_global->__pyx_empty_tuple, NULL); + if (cfunc->flag == METH_VARARGS) + return __Pyx_CallCFunction(cfunc, self, __pyx_mstate_global->__pyx_empty_tuple); + return __Pyx__CallUnboundCMethod0(cfunc, self); + } +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + else if (unlikely(was_initialized == 1)) { + __Pyx_CachedCFunction tmp_cfunc = { +#ifndef __cplusplus + 0 +#endif + }; + tmp_cfunc.type = cfunc->type; + tmp_cfunc.method_name = cfunc->method_name; + return __Pyx__CallUnboundCMethod0(&tmp_cfunc, self); + } +#endif + PyObject *result = __Pyx__CallUnboundCMethod0(cfunc, self); + __Pyx_CachedCFunction_SetFinishedInitializing(cfunc); + return result; +} +#endif +static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self) { + PyObject *result; + if (unlikely(!cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL; + result = __Pyx_PyObject_CallOneArg(cfunc->method, self); + return result; +} + +/* py_dict_items (used by OwnedDictNext) */ +static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d) { + return __Pyx_CallUnboundCMethod0(&__pyx_mstate_global->__pyx_umethod_PyDict_Type_items, d); +} + +/* py_dict_values (used by OwnedDictNext) */ +static CYTHON_INLINE PyObject* __Pyx_PyDict_Values(PyObject* d) { + return __Pyx_CallUnboundCMethod0(&__pyx_mstate_global->__pyx_umethod_PyDict_Type_values, d); +} + +/* OwnedDictNext (used by ParseKeywordsImpl) */ +#if CYTHON_AVOID_BORROWED_REFS +static int __Pyx_PyDict_NextRef(PyObject *p, PyObject **ppos, PyObject **pkey, PyObject **pvalue) { + PyObject *next = NULL; + if (!*ppos) { + if (pvalue) { + PyObject *dictview = pkey ? __Pyx_PyDict_Items(p) : __Pyx_PyDict_Values(p); + if (unlikely(!dictview)) goto bad; + *ppos = PyObject_GetIter(dictview); + Py_DECREF(dictview); + } else { + *ppos = PyObject_GetIter(p); + } + if (unlikely(!*ppos)) goto bad; + } + next = PyIter_Next(*ppos); + if (!next) { + if (PyErr_Occurred()) goto bad; + return 0; + } + if (pkey && pvalue) { + *pkey = __Pyx_PySequence_ITEM(next, 0); + if (unlikely(*pkey)) goto bad; + *pvalue = __Pyx_PySequence_ITEM(next, 1); + if (unlikely(*pvalue)) goto bad; + Py_DECREF(next); + } else if (pkey) { + *pkey = next; + } else { + assert(pvalue); + *pvalue = next; + } + return 1; + bad: + Py_XDECREF(next); +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d0000 + PyErr_FormatUnraisable("Exception ignored in __Pyx_PyDict_NextRef"); +#else + PyErr_WriteUnraisable(__pyx_mstate_global->__pyx_n_u_Pyx_PyDict_NextRef); +#endif + if (pkey) *pkey = NULL; + if (pvalue) *pvalue = NULL; + return 0; +} +#else // !CYTHON_AVOID_BORROWED_REFS +static int __Pyx_PyDict_NextRef(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) { + int result = PyDict_Next(p, ppos, pkey, pvalue); + if (likely(result == 1)) { + if (pkey) Py_INCREF(*pkey); + if (pvalue) Py_INCREF(*pvalue); + } + return result; +} +#endif + +/* RaiseDoubleKeywords (used by ParseKeywordsImpl) */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); +} + +/* CallUnboundCMethod2 */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2) { + int was_initialized = __Pyx_CachedCFunction_GetAndSetInitializing(cfunc); + if (likely(was_initialized == 2 && cfunc->func)) { + PyObject *args[2] = {arg1, arg2}; + if (cfunc->flag == METH_FASTCALL) { + return __Pyx_CallCFunctionFast(cfunc, self, args, 2); + } + if (cfunc->flag == (METH_FASTCALL | METH_KEYWORDS)) + return __Pyx_CallCFunctionFastWithKeywords(cfunc, self, args, 2, NULL); + } +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + else if (unlikely(was_initialized == 1)) { + __Pyx_CachedCFunction tmp_cfunc = { +#ifndef __cplusplus + 0 +#endif + }; + tmp_cfunc.type = cfunc->type; + tmp_cfunc.method_name = cfunc->method_name; + return __Pyx__CallUnboundCMethod2(&tmp_cfunc, self, arg1, arg2); + } +#endif + PyObject *result = __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2); + __Pyx_CachedCFunction_SetFinishedInitializing(cfunc); + return result; +} +#endif +static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2){ + if (unlikely(!cfunc->func && !cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL; +#if CYTHON_COMPILING_IN_CPYTHON + if (cfunc->func && (cfunc->flag & METH_VARARGS)) { + PyObject *result = NULL; + PyObject *args = PyTuple_New(2); + if (unlikely(!args)) return NULL; + Py_INCREF(arg1); + PyTuple_SET_ITEM(args, 0, arg1); + Py_INCREF(arg2); + PyTuple_SET_ITEM(args, 1, arg2); + if (cfunc->flag & METH_KEYWORDS) + result = __Pyx_CallCFunctionWithKeywords(cfunc, self, args, NULL); + else + result = __Pyx_CallCFunction(cfunc, self, args); + Py_DECREF(args); + return result; + } +#endif + { + PyObject *args[4] = {NULL, self, arg1, arg2}; + return __Pyx_PyObject_FastCall(cfunc->method, args+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } +} + +/* ParseKeywordsImpl (used by ParseKeywords) */ +static int __Pyx_ValidateDuplicatePosArgs( + PyObject *kwds, + PyObject ** const argnames[], + PyObject ** const *first_kw_arg, + const char* function_name) +{ + PyObject ** const *name = argnames; + while (name != first_kw_arg) { + PyObject *key = **name; + int found = PyDict_Contains(kwds, key); + if (unlikely(found)) { + if (found == 1) __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; + } + name++; + } + return 0; +bad: + return -1; +} +#if CYTHON_USE_UNICODE_INTERNALS +static CYTHON_INLINE int __Pyx_UnicodeKeywordsEqual(PyObject *s1, PyObject *s2) { + int kind; + Py_ssize_t len = PyUnicode_GET_LENGTH(s1); + if (len != PyUnicode_GET_LENGTH(s2)) return 0; + kind = PyUnicode_KIND(s1); + if (kind != PyUnicode_KIND(s2)) return 0; + const void *data1 = PyUnicode_DATA(s1); + const void *data2 = PyUnicode_DATA(s2); + return (memcmp(data1, data2, (size_t) len * (size_t) kind) == 0); +} +#endif +static int __Pyx_MatchKeywordArg_str( + PyObject *key, + PyObject ** const argnames[], + PyObject ** const *first_kw_arg, + size_t *index_found, + const char *function_name) +{ + PyObject ** const *name; + #if CYTHON_USE_UNICODE_INTERNALS + Py_hash_t key_hash = ((PyASCIIObject*)key)->hash; + if (unlikely(key_hash == -1)) { + key_hash = PyObject_Hash(key); + if (unlikely(key_hash == -1)) + goto bad; + } + #endif + name = first_kw_arg; + while (*name) { + PyObject *name_str = **name; + #if CYTHON_USE_UNICODE_INTERNALS + if (key_hash == ((PyASCIIObject*)name_str)->hash && __Pyx_UnicodeKeywordsEqual(name_str, key)) { + *index_found = (size_t) (name - argnames); + return 1; + } + #else + #if CYTHON_ASSUME_SAFE_SIZE + if (PyUnicode_GET_LENGTH(name_str) == PyUnicode_GET_LENGTH(key)) + #endif + { + int cmp = PyUnicode_Compare(name_str, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + *index_found = (size_t) (name - argnames); + return 1; + } + } + #endif + name++; + } + name = argnames; + while (name != first_kw_arg) { + PyObject *name_str = **name; + #if CYTHON_USE_UNICODE_INTERNALS + if (unlikely(key_hash == ((PyASCIIObject*)name_str)->hash)) { + if (__Pyx_UnicodeKeywordsEqual(name_str, key)) + goto arg_passed_twice; + } + #else + #if CYTHON_ASSUME_SAFE_SIZE + if (PyUnicode_GET_LENGTH(name_str) == PyUnicode_GET_LENGTH(key)) + #endif + { + if (unlikely(name_str == key)) goto arg_passed_twice; + int cmp = PyUnicode_Compare(name_str, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + } + #endif + name++; + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +bad: + return -1; +} +static int __Pyx_MatchKeywordArg_nostr( + PyObject *key, + PyObject ** const argnames[], + PyObject ** const *first_kw_arg, + size_t *index_found, + const char *function_name) +{ + PyObject ** const *name; + if (unlikely(!PyUnicode_Check(key))) goto invalid_keyword_type; + name = first_kw_arg; + while (*name) { + int cmp = PyObject_RichCompareBool(**name, key, Py_EQ); + if (cmp == 1) { + *index_found = (size_t) (name - argnames); + return 1; + } + if (unlikely(cmp == -1)) goto bad; + name++; + } + name = argnames; + while (name != first_kw_arg) { + int cmp = PyObject_RichCompareBool(**name, key, Py_EQ); + if (unlikely(cmp != 0)) { + if (cmp == 1) goto arg_passed_twice; + else goto bad; + } + name++; + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +bad: + return -1; +} +static CYTHON_INLINE int __Pyx_MatchKeywordArg( + PyObject *key, + PyObject ** const argnames[], + PyObject ** const *first_kw_arg, + size_t *index_found, + const char *function_name) +{ + return likely(PyUnicode_CheckExact(key)) ? + __Pyx_MatchKeywordArg_str(key, argnames, first_kw_arg, index_found, function_name) : + __Pyx_MatchKeywordArg_nostr(key, argnames, first_kw_arg, index_found, function_name); +} +static void __Pyx_RejectUnknownKeyword( + PyObject *kwds, + PyObject ** const argnames[], + PyObject ** const *first_kw_arg, + const char *function_name) +{ + #if CYTHON_AVOID_BORROWED_REFS + PyObject *pos = NULL; + #else + Py_ssize_t pos = 0; + #endif + PyObject *key = NULL; + __Pyx_BEGIN_CRITICAL_SECTION(kwds); + while ( + #if CYTHON_AVOID_BORROWED_REFS + __Pyx_PyDict_NextRef(kwds, &pos, &key, NULL) + #else + PyDict_Next(kwds, &pos, &key, NULL) + #endif + ) { + PyObject** const *name = first_kw_arg; + while (*name && (**name != key)) name++; + if (!*name) { + size_t index_found = 0; + int cmp = __Pyx_MatchKeywordArg(key, argnames, first_kw_arg, &index_found, function_name); + if (cmp != 1) { + if (cmp == 0) { + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(key); + #endif + break; + } + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(key); + #endif + } + __Pyx_END_CRITICAL_SECTION(); + #if CYTHON_AVOID_BORROWED_REFS + Py_XDECREF(pos); + #endif + assert(PyErr_Occurred()); +} +static int __Pyx_ParseKeywordDict( + PyObject *kwds, + PyObject ** const argnames[], + PyObject *values[], + Py_ssize_t num_pos_args, + Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs) +{ + PyObject** const *name; + PyObject** const *first_kw_arg = argnames + num_pos_args; + Py_ssize_t extracted = 0; +#if !CYTHON_COMPILING_IN_PYPY || defined(PyArg_ValidateKeywordArguments) + if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1; +#endif + name = first_kw_arg; + while (*name && num_kwargs > extracted) { + PyObject * key = **name; + PyObject *value; + int found = 0; + #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + found = PyDict_GetItemRef(kwds, key, &value); + #else + value = PyDict_GetItemWithError(kwds, key); + if (value) { + Py_INCREF(value); + found = 1; + } else { + if (unlikely(PyErr_Occurred())) goto bad; + } + #endif + if (found) { + if (unlikely(found < 0)) goto bad; + values[name-argnames] = value; + extracted++; + } + name++; + } + if (num_kwargs > extracted) { + if (ignore_unknown_kwargs) { + if (unlikely(__Pyx_ValidateDuplicatePosArgs(kwds, argnames, first_kw_arg, function_name) == -1)) + goto bad; + } else { + __Pyx_RejectUnknownKeyword(kwds, argnames, first_kw_arg, function_name); + goto bad; + } + } + return 0; +bad: + return -1; +} +static int __Pyx_ParseKeywordDictToDict( + PyObject *kwds, + PyObject ** const argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject** const *name; + PyObject** const *first_kw_arg = argnames + num_pos_args; + Py_ssize_t len; +#if !CYTHON_COMPILING_IN_PYPY || defined(PyArg_ValidateKeywordArguments) + if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1; +#endif + if (PyDict_Update(kwds2, kwds) < 0) goto bad; + name = first_kw_arg; + while (*name) { + PyObject *key = **name; + PyObject *value; +#if !CYTHON_COMPILING_IN_LIMITED_API && (PY_VERSION_HEX >= 0x030d00A2 || defined(PyDict_Pop)) + int found = PyDict_Pop(kwds2, key, &value); + if (found) { + if (unlikely(found < 0)) goto bad; + values[name-argnames] = value; + } +#elif __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + int found = PyDict_GetItemRef(kwds2, key, &value); + if (found) { + if (unlikely(found < 0)) goto bad; + values[name-argnames] = value; + if (unlikely(PyDict_DelItem(kwds2, key) < 0)) goto bad; + } +#else + #if CYTHON_COMPILING_IN_CPYTHON + value = _PyDict_Pop(kwds2, key, kwds2); + #else + value = __Pyx_CallUnboundCMethod2(&__pyx_mstate_global->__pyx_umethod_PyDict_Type_pop, kwds2, key, kwds2); + #endif + if (value == kwds2) { + Py_DECREF(value); + } else { + if (unlikely(!value)) goto bad; + values[name-argnames] = value; + } +#endif + name++; + } + len = PyDict_Size(kwds2); + if (len > 0) { + return __Pyx_ValidateDuplicatePosArgs(kwds, argnames, first_kw_arg, function_name); + } else if (unlikely(len == -1)) { + goto bad; + } + return 0; +bad: + return -1; +} +static int __Pyx_ParseKeywordsTuple( + PyObject *kwds, + PyObject * const *kwvalues, + PyObject ** const argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs) +{ + PyObject *key = NULL; + PyObject** const * name; + PyObject** const *first_kw_arg = argnames + num_pos_args; + for (Py_ssize_t pos = 0; pos < num_kwargs; pos++) { +#if CYTHON_AVOID_BORROWED_REFS + key = __Pyx_PySequence_ITEM(kwds, pos); +#else + key = __Pyx_PyTuple_GET_ITEM(kwds, pos); +#endif +#if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely(!key)) goto bad; +#endif + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + PyObject *value = kwvalues[pos]; + values[name-argnames] = __Pyx_NewRef(value); + } else { + size_t index_found = 0; + int cmp = __Pyx_MatchKeywordArg(key, argnames, first_kw_arg, &index_found, function_name); + if (cmp == 1) { + PyObject *value = kwvalues[pos]; + values[index_found] = __Pyx_NewRef(value); + } else { + if (unlikely(cmp == -1)) goto bad; + if (kwds2) { + PyObject *value = kwvalues[pos]; + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else if (!ignore_unknown_kwargs) { + goto invalid_keyword; + } + } + } + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(key); + key = NULL; + #endif + } + return 0; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument '%U'", + function_name, key); + goto bad; +bad: + #if CYTHON_AVOID_BORROWED_REFS + Py_XDECREF(key); + #endif + return -1; +} + +/* ParseKeywords */ +static int __Pyx_ParseKeywords( + PyObject *kwds, + PyObject * const *kwvalues, + PyObject ** const argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + Py_ssize_t num_kwargs, + const char* function_name, + int ignore_unknown_kwargs) +{ + if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds))) + return __Pyx_ParseKeywordsTuple(kwds, kwvalues, argnames, kwds2, values, num_pos_args, num_kwargs, function_name, ignore_unknown_kwargs); + else if (kwds2) + return __Pyx_ParseKeywordDictToDict(kwds, argnames, kwds2, values, num_pos_args, function_name); + else + return __Pyx_ParseKeywordDict(kwds, argnames, values, num_pos_args, num_kwargs, function_name, ignore_unknown_kwargs); +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* GetException (used by pep479) */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type = NULL, *local_value, *local_tb = NULL; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030C0000 + local_value = tstate->current_exception; + tstate->current_exception = 0; + #else + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + #endif +#elif __PYX_LIMITED_VERSION_HEX > 0x030C0000 + local_value = PyErr_GetRaisedException(); +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif +#if __PYX_LIMITED_VERSION_HEX > 0x030C0000 + if (likely(local_value)) { + local_type = (PyObject*) Py_TYPE(local_value); + Py_INCREF(local_type); + local_tb = PyException_GetTraceback(local_value); + } +#else + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } +#endif // __PYX_LIMITED_VERSION_HEX > 0x030C0000 + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + #if PY_VERSION_HEX >= 0x030B00a4 + tmp_value = exc_info->exc_value; + exc_info->exc_value = local_value; + tmp_type = NULL; + tmp_tb = NULL; + Py_XDECREF(local_type); + Py_XDECREF(local_tb); + #else + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + #endif + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#elif __PYX_LIMITED_VERSION_HEX >= 0x030b0000 + PyErr_SetHandledException(local_value); + Py_XDECREF(local_value); + Py_XDECREF(local_type); + Py_XDECREF(local_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +#if __PYX_LIMITED_VERSION_HEX <= 0x030C0000 +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +#endif +} + +/* pep479 */ +static void __Pyx_Generator_Replace_StopIteration(int in_async_gen) { + PyObject *exc, *val, *tb, *cur_exc, *new_exc; + __Pyx_PyThreadState_declare + int is_async_stopiteration = 0; + CYTHON_MAYBE_UNUSED_VAR(in_async_gen); + __Pyx_PyThreadState_assign + cur_exc = __Pyx_PyErr_CurrentExceptionType(); + if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { + if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopAsyncIteration))) { + is_async_stopiteration = 1; + } else { + return; + } + } + __Pyx_GetException(&exc, &val, &tb); + Py_XDECREF(exc); + Py_XDECREF(tb); + new_exc = PyObject_CallFunction(PyExc_RuntimeError, "s", + is_async_stopiteration ? "async generator raised StopAsyncIteration" : + in_async_gen ? "async generator raised StopIteration" : + "generator raised StopIteration"); + if (!new_exc) { + Py_XDECREF(val); + return; + } + PyException_SetCause(new_exc, val); // steals ref to val + PyErr_SetObject(PyExc_RuntimeError, new_exc); +} + +/* GetTopmostException (used by SaveResetException) */ +#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + PyObject *exc_value = exc_info->exc_value; + if (exc_value == NULL || exc_value == Py_None) { + *value = NULL; + *type = NULL; + *tb = NULL; + } else { + *value = exc_value; + Py_INCREF(*value); + *type = (PyObject*) Py_TYPE(exc_value); + Py_INCREF(*type); + *tb = PyException_GetTraceback(exc_value); + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); + #endif +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + PyObject *tmp_value = exc_info->exc_value; + exc_info->exc_value = value; + Py_XDECREF(tmp_value); + Py_XDECREF(type); + Py_XDECREF(tb); + #else + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + #endif +} +#endif + +/* IterNextPlain (used by IterNext) */ +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 +static PyObject *__Pyx_GetBuiltinNext_LimitedAPI(void) { + if (unlikely(!__pyx_mstate_global->__Pyx_GetBuiltinNext_LimitedAPI_cache)) + __pyx_mstate_global->__Pyx_GetBuiltinNext_LimitedAPI_cache = __Pyx_GetBuiltinName(__pyx_mstate_global->__pyx_n_u_next); + return __pyx_mstate_global->__Pyx_GetBuiltinNext_LimitedAPI_cache; +} +#endif +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next_Plain(PyObject *iterator) { +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 + PyObject *result; + PyObject *next = __Pyx_GetBuiltinNext_LimitedAPI(); + if (unlikely(!next)) return NULL; + result = PyObject_CallFunctionObjArgs(next, iterator, NULL); + return result; +#else + (void)__Pyx_GetBuiltinName; // only for early limited API + iternextfunc iternext = __Pyx_PyObject_GetIterNextFunc(iterator); + assert(iternext); + return iternext(iterator); +#endif +} + +/* IterNext */ +static PyObject *__Pyx_PyIter_Next2Default(PyObject* defval) { + PyObject* exc_type; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + exc_type = __Pyx_PyErr_CurrentExceptionType(); + if (unlikely(exc_type)) { + if (!defval || unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) + return NULL; + __Pyx_PyErr_Clear(); + Py_INCREF(defval); + return defval; + } + if (defval) { + Py_INCREF(defval); + return defval; + } + __Pyx_PyErr_SetNone(PyExc_StopIteration); + return NULL; +} +static void __Pyx_PyIter_Next_ErrorNoIterator(PyObject *iterator) { + __Pyx_TypeName iterator_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(iterator)); + PyErr_Format(PyExc_TypeError, + __Pyx_FMT_TYPENAME " object is not an iterator", iterator_type_name); + __Pyx_DECREF_TypeName(iterator_type_name); +} +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) { + PyObject* next; +#if !CYTHON_COMPILING_IN_LIMITED_API + iternextfunc iternext = __Pyx_PyObject_TryGetSlot(iterator, tp_iternext, iternextfunc); + if (likely(iternext)) { + next = iternext(iterator); + if (likely(next)) + return next; + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 + if (unlikely(iternext == &_PyObject_NextNotImplemented)) + return NULL; + #endif + } else if (CYTHON_USE_TYPE_SLOTS) { + __Pyx_PyIter_Next_ErrorNoIterator(iterator); + return NULL; + } else +#endif + if (unlikely(!PyIter_Check(iterator))) { + __Pyx_PyIter_Next_ErrorNoIterator(iterator); + return NULL; + } else { + next = defval ? PyIter_Next(iterator) : __Pyx_PyIter_Next_Plain(iterator); + if (likely(next)) + return next; + } + return __Pyx_PyIter_Next2Default(defval); +} + +/* PyLongBinop */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_Fallback___Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, int inplace) { + return (inplace ? PyNumber_InPlaceAdd : PyNumber_Add)(op1, op2); +} +#if CYTHON_USE_PYLONG_INTERNALS +static PyObject* __Pyx_Unpacked___Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { + CYTHON_MAYBE_UNUSED_VAR(inplace); + CYTHON_UNUSED_VAR(zerodivision_check); + const long b = intval; + long a; + const PY_LONG_LONG llb = intval; + PY_LONG_LONG lla; + if (unlikely(__Pyx_PyLong_IsZero(op1))) { + return __Pyx_NewRef(op2); + } + const int is_positive = __Pyx_PyLong_IsPos(op1); + const digit* digits = __Pyx_PyLong_Digits(op1); + const Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); + if (likely(size == 1)) { + a = (long) digits[0]; + if (!is_positive) a *= -1; + } else { + switch (size) { + case 2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + if (!is_positive) a *= -1; + goto calculate_long; + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + if (!is_positive) lla *= -1; + goto calculate_long_long; + } + break; + case 3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + if (!is_positive) a *= -1; + goto calculate_long; + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + if (!is_positive) lla *= -1; + goto calculate_long_long; + } + break; + case 4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + if (!is_positive) a *= -1; + goto calculate_long; + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + if (!is_positive) lla *= -1; + goto calculate_long_long; + } + break; + } + return PyLong_Type.tp_as_number->nb_add(op1, op2); + } + calculate_long: + { + long x; + x = a + b; + return PyLong_FromLong(x); + } + calculate_long_long: + { + PY_LONG_LONG llx; + llx = lla + llb; + return PyLong_FromLongLong(llx); + } + +} +#endif +static PyObject* __Pyx_Float___Pyx_PyLong_AddObjC(PyObject *float_val, long intval, int zerodivision_check) { + CYTHON_UNUSED_VAR(zerodivision_check); + const long b = intval; + double a = __Pyx_PyFloat_AS_DOUBLE(float_val); + double result; + + result = ((double)a) + (double)b; + return PyFloat_FromDouble(result); +} +static CYTHON_INLINE PyObject* __Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { + CYTHON_MAYBE_UNUSED_VAR(intval); + CYTHON_UNUSED_VAR(zerodivision_check); + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + return __Pyx_Unpacked___Pyx_PyLong_AddObjC(op1, op2, intval, inplace, zerodivision_check); + } + #endif + if (PyFloat_CheckExact(op1)) { + return __Pyx_Float___Pyx_PyLong_AddObjC(op1, intval, zerodivision_check); + } + return __Pyx_Fallback___Pyx_PyLong_AddObjC(op1, op2, inplace); +} +#endif + +/* RaiseException */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { +#if PY_VERSION_HEX >= 0x030C00A6 + PyException_SetTraceback(value, tb); +#elif CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} + +/* SetItemInt */ +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { + int r; + if (unlikely(!j)) return -1; + r = PyObject_SetItem(o, j, v); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, + int wraparound, int boundscheck, int unsafe_shared) { + CYTHON_MAYBE_UNUSED_VAR(unsafe_shared); +#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE && !CYTHON_AVOID_BORROWED_REFS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o)); + if ((CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS && !__Pyx_IS_UNIQUELY_REFERENCED(o, unsafe_shared))) { + Py_INCREF(v); + return PyList_SetItem(o, n, v); + } else if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o)))) { + PyObject* old; + Py_INCREF(v); + old = PyList_GET_ITEM(o, n); + PyList_SET_ITEM(o, n, v); + Py_DECREF(old); + return 0; + } + } else +#endif +#if CYTHON_USE_TYPE_SLOTS && !CYTHON_COMPILING_IN_PYPY + { + PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; + PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; + if (!is_list && mm && mm->mp_ass_subscript) { + int r; + PyObject *key = PyLong_FromSsize_t(i); + if (unlikely(!key)) return -1; + r = mm->mp_ass_subscript(o, key, v); + Py_DECREF(key); + return r; + } + if (is_list || likely(sm && sm->sq_ass_item)) { + if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { + Py_ssize_t l = sm->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return -1; + PyErr_Clear(); + } + } + return sm->sq_ass_item(o, i, v); + } + } +#else + if (is_list || !PyMapping_Check(o)) { + return PySequence_SetItem(o, i, v); + } +#endif + (void)wraparound; + (void)boundscheck; + return __Pyx_SetItemInt_Generic(o, PyLong_FromSsize_t(i), v); +} + +/* ModInt[long] */ +static CYTHON_INLINE long __Pyx_mod_long(long a, long b, int b_is_constant) { + long r = a % b; + long adapt_python = (b_is_constant ? + ((r != 0) & ((r < 0) ^ (b < 0))) : + ((r != 0) & ((r ^ b) < 0)) + ); + return r + adapt_python * b; +} + +/* AllocateExtensionType */ +static PyObject *__Pyx_AllocateExtensionType(PyTypeObject *t, int is_final) { + if (is_final || likely(!__Pyx_PyType_HasFeature(t, Py_TPFLAGS_IS_ABSTRACT))) { + allocfunc alloc_func = __Pyx_PyType_GetSlot(t, tp_alloc, allocfunc); + return alloc_func(t, 0); + } else { + newfunc tp_new = __Pyx_PyType_TryGetSlot(&PyBaseObject_Type, tp_new, newfunc); + #if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 + if (!tp_new) { + PyObject *new_str = PyUnicode_FromString("__new__"); + if (likely(new_str)) { + PyObject *o = PyObject_CallMethodObjArgs((PyObject *)&PyBaseObject_Type, new_str, t, NULL); + Py_DECREF(new_str); + return o; + } else + return NULL; + } else + #endif + return tp_new(t, __pyx_mstate_global->__pyx_empty_tuple, 0); + } +} + +/* LimitedApiGetTypeDict (used by SetItemOnTypeDict) */ +#if CYTHON_COMPILING_IN_LIMITED_API +static Py_ssize_t __Pyx_GetTypeDictOffset(void) { + PyObject *tp_dictoffset_o; + Py_ssize_t tp_dictoffset; + tp_dictoffset_o = PyObject_GetAttrString((PyObject*)(&PyType_Type), "__dictoffset__"); + if (unlikely(!tp_dictoffset_o)) return -1; + tp_dictoffset = PyLong_AsSsize_t(tp_dictoffset_o); + Py_DECREF(tp_dictoffset_o); + if (unlikely(tp_dictoffset == 0)) { + PyErr_SetString( + PyExc_TypeError, + "'type' doesn't have a dictoffset"); + return -1; + } else if (unlikely(tp_dictoffset < 0)) { + PyErr_SetString( + PyExc_TypeError, + "'type' has an unexpected negative dictoffset. " + "Please report this as Cython bug"); + return -1; + } + return tp_dictoffset; +} +static PyObject *__Pyx_GetTypeDict(PyTypeObject *tp) { + static Py_ssize_t tp_dictoffset = 0; + if (unlikely(tp_dictoffset == 0)) { + tp_dictoffset = __Pyx_GetTypeDictOffset(); + if (unlikely(tp_dictoffset == -1 && PyErr_Occurred())) { + tp_dictoffset = 0; // try again next time? + return NULL; + } + } + return *(PyObject**)((char*)tp + tp_dictoffset); +} +#endif + +/* SetItemOnTypeDict (used by FixUpExtensionType) */ +static int __Pyx__SetItemOnTypeDict(PyTypeObject *tp, PyObject *k, PyObject *v) { + int result; + PyObject *tp_dict; +#if CYTHON_COMPILING_IN_LIMITED_API + tp_dict = __Pyx_GetTypeDict(tp); + if (unlikely(!tp_dict)) return -1; +#else + tp_dict = tp->tp_dict; +#endif + result = PyDict_SetItem(tp_dict, k, v); + if (likely(!result)) { + PyType_Modified(tp); + if (unlikely(PyObject_HasAttr(v, __pyx_mstate_global->__pyx_n_u_set_name))) { + PyObject *setNameResult = PyObject_CallMethodObjArgs(v, __pyx_mstate_global->__pyx_n_u_set_name, (PyObject *) tp, k, NULL); + if (!setNameResult) return -1; + Py_DECREF(setNameResult); + } + } + return result; +} + +/* FixUpExtensionType */ +static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { +#if __PYX_LIMITED_VERSION_HEX > 0x030900B1 + CYTHON_UNUSED_VAR(spec); + CYTHON_UNUSED_VAR(type); + CYTHON_UNUSED_VAR(__Pyx__SetItemOnTypeDict); +#else + const PyType_Slot *slot = spec->slots; + int changed = 0; +#if !CYTHON_COMPILING_IN_LIMITED_API + while (slot && slot->slot && slot->slot != Py_tp_members) + slot++; + if (slot && slot->slot == Py_tp_members) { +#if !CYTHON_COMPILING_IN_CPYTHON + const +#endif // !CYTHON_COMPILING_IN_CPYTHON) + PyMemberDef *memb = (PyMemberDef*) slot->pfunc; + while (memb && memb->name) { + if (memb->name[0] == '_' && memb->name[1] == '_') { + if (strcmp(memb->name, "__weaklistoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_weaklistoffset = memb->offset; + changed = 1; + } + else if (strcmp(memb->name, "__dictoffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_dictoffset = memb->offset; + changed = 1; + } +#if CYTHON_METH_FASTCALL + else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { + assert(memb->type == T_PYSSIZET); + assert(memb->flags == READONLY); + type->tp_vectorcall_offset = memb->offset; + changed = 1; + } +#endif // CYTHON_METH_FASTCALL +#if !CYTHON_COMPILING_IN_PYPY + else if (strcmp(memb->name, "__module__") == 0) { + PyObject *descr; + assert(memb->type == T_OBJECT); + assert(memb->flags == 0 || memb->flags == READONLY); + descr = PyDescr_NewMember(type, memb); + if (unlikely(!descr)) + return -1; + int set_item_result = PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr); + Py_DECREF(descr); + if (unlikely(set_item_result < 0)) { + return -1; + } + changed = 1; + } +#endif // !CYTHON_COMPILING_IN_PYPY + } + memb++; + } + } +#endif // !CYTHON_COMPILING_IN_LIMITED_API +#if !CYTHON_COMPILING_IN_PYPY + slot = spec->slots; + while (slot && slot->slot && slot->slot != Py_tp_getset) + slot++; + if (slot && slot->slot == Py_tp_getset) { + PyGetSetDef *getset = (PyGetSetDef*) slot->pfunc; + while (getset && getset->name) { + if (getset->name[0] == '_' && getset->name[1] == '_' && strcmp(getset->name, "__module__") == 0) { + PyObject *descr = PyDescr_NewGetSet(type, getset); + if (unlikely(!descr)) + return -1; + #if CYTHON_COMPILING_IN_LIMITED_API + PyObject *pyname = PyUnicode_FromString(getset->name); + if (unlikely(!pyname)) { + Py_DECREF(descr); + return -1; + } + int set_item_result = __Pyx_SetItemOnTypeDict(type, pyname, descr); + Py_DECREF(pyname); + #else + CYTHON_UNUSED_VAR(__Pyx__SetItemOnTypeDict); + int set_item_result = PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr); + #endif + Py_DECREF(descr); + if (unlikely(set_item_result < 0)) { + return -1; + } + changed = 1; + } + ++getset; + } + } +#else + CYTHON_UNUSED_VAR(__Pyx__SetItemOnTypeDict); +#endif // !CYTHON_COMPILING_IN_PYPY + if (changed) + PyType_Modified(type); +#endif // PY_VERSION_HEX > 0x030900B1 + return 0; +} + +/* PyObjectCallNoArg (used by PyObjectCallMethod0) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { + PyObject *arg[2] = {NULL, NULL}; + return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectGetMethod (used by PyObjectCallMethod0) */ +#if !(CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000))) +static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { + PyObject *attr; +#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP + __Pyx_TypeName type_name; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + int meth_found = 0; + assert (*method == NULL); + if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; + } + if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { + return 0; + } + descr = _PyType_Lookup(tp, name); + if (likely(descr != NULL)) { + Py_INCREF(descr); +#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR + if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) +#else + #ifdef __Pyx_CyFunction_USED + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) + #else + if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) + #endif +#endif + { + meth_found = 1; + } else { + f = Py_TYPE(descr)->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + } + } + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = __Pyx_PyDict_GetItemStr(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + Py_DECREF(dict); + Py_XDECREF(descr); + goto try_unpack; + } + Py_DECREF(dict); + } + if (meth_found) { + *method = descr; + return 1; + } + if (f != NULL) { + attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + goto try_unpack; + } + if (likely(descr != NULL)) { + *method = descr; + return 0; + } + type_name = __Pyx_PyType_GetFullyQualifiedName(tp); + PyErr_Format(PyExc_AttributeError, + "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", + type_name, name); + __Pyx_DECREF_TypeName(type_name); + return 0; +#else + attr = __Pyx_PyObject_GetAttrStr(obj, name); + goto try_unpack; +#endif +try_unpack: +#if CYTHON_UNPACK_METHODS + if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { + PyObject *function = PyMethod_GET_FUNCTION(attr); + Py_INCREF(function); + Py_DECREF(attr); + *method = function; + return 1; + } +#endif + *method = attr; + return 0; +} +#endif + +/* PyObjectCallMethod0 (used by PyType_Ready) */ +static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { +#if CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000)) + PyObject *args[1] = {obj}; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_CallNoArg; + return PyObject_VectorcallMethod(method_name, args, 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result = NULL; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_CallOneArg(method, obj); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) goto bad; + result = __Pyx_PyObject_CallNoArg(method); + Py_DECREF(method); +bad: + return result; +#endif +} + +/* ValidateBasesTuple (used by PyType_Ready) */ +#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_USE_TYPE_SPECS +static int __Pyx_validate_bases_tuple(const char *type_name, Py_ssize_t dictoffset, PyObject *bases) { + Py_ssize_t i, n; +#if CYTHON_ASSUME_SAFE_SIZE + n = PyTuple_GET_SIZE(bases); +#else + n = PyTuple_Size(bases); + if (unlikely(n < 0)) return -1; +#endif + for (i = 1; i < n; i++) + { + PyTypeObject *b; +#if CYTHON_AVOID_BORROWED_REFS + PyObject *b0 = PySequence_GetItem(bases, i); + if (!b0) return -1; +#elif CYTHON_ASSUME_SAFE_MACROS + PyObject *b0 = PyTuple_GET_ITEM(bases, i); +#else + PyObject *b0 = PyTuple_GetItem(bases, i); + if (!b0) return -1; +#endif + b = (PyTypeObject*) b0; + if (!__Pyx_PyType_HasFeature(b, Py_TPFLAGS_HEAPTYPE)) + { + __Pyx_TypeName b_name = __Pyx_PyType_GetFullyQualifiedName(b); + PyErr_Format(PyExc_TypeError, + "base class '" __Pyx_FMT_TYPENAME "' is not a heap type", b_name); + __Pyx_DECREF_TypeName(b_name); +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + if (dictoffset == 0) + { + Py_ssize_t b_dictoffset = 0; +#if CYTHON_USE_TYPE_SLOTS + b_dictoffset = b->tp_dictoffset; +#else + PyObject *py_b_dictoffset = PyObject_GetAttrString((PyObject*)b, "__dictoffset__"); + if (!py_b_dictoffset) goto dictoffset_return; + b_dictoffset = PyLong_AsSsize_t(py_b_dictoffset); + Py_DECREF(py_b_dictoffset); + if (b_dictoffset == -1 && PyErr_Occurred()) goto dictoffset_return; +#endif + if (b_dictoffset) { + { + __Pyx_TypeName b_name = __Pyx_PyType_GetFullyQualifiedName(b); + PyErr_Format(PyExc_TypeError, + "extension type '%.200s' has no __dict__ slot, " + "but base type '" __Pyx_FMT_TYPENAME "' has: " + "either add 'cdef dict __dict__' to the extension type " + "or add '__slots__ = [...]' to the base type", + type_name, b_name); + __Pyx_DECREF_TypeName(b_name); + } +#if !CYTHON_USE_TYPE_SLOTS + dictoffset_return: +#endif +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + return -1; + } + } +#if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(b0); +#endif + } + return 0; +} +#endif + +/* PyType_Ready */ +CYTHON_UNUSED static int __Pyx_PyType_HasMultipleInheritance(PyTypeObject *t) { + while (t) { + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases) { + return 1; + } + t = __Pyx_PyType_GetSlot(t, tp_base, PyTypeObject*); + } + return 0; +} +static int __Pyx_PyType_Ready(PyTypeObject *t) { +#if CYTHON_USE_TYPE_SPECS || !CYTHON_COMPILING_IN_CPYTHON || defined(PYSTON_MAJOR_VERSION) + (void)__Pyx_PyObject_CallMethod0; +#if CYTHON_USE_TYPE_SPECS + (void)__Pyx_validate_bases_tuple; +#endif + return PyType_Ready(t); +#else + int r; + if (!__Pyx_PyType_HasMultipleInheritance(t)) { + return PyType_Ready(t); + } + PyObject *bases = __Pyx_PyType_GetSlot(t, tp_bases, PyObject*); + if (bases && unlikely(__Pyx_validate_bases_tuple(t->tp_name, t->tp_dictoffset, bases) == -1)) + return -1; +#if !defined(PYSTON_MAJOR_VERSION) + { + int gc_was_enabled; + #if PY_VERSION_HEX >= 0x030A00b1 + gc_was_enabled = PyGC_Disable(); + (void)__Pyx_PyObject_CallMethod0; + #else + PyObject *ret, *py_status; + PyObject *gc = NULL; + #if (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM+0 >= 0x07030400) &&\ + !CYTHON_COMPILING_IN_GRAAL + gc = PyImport_GetModule(__pyx_mstate_global->__pyx_kp_u_gc); + #endif + if (unlikely(!gc)) gc = PyImport_Import(__pyx_mstate_global->__pyx_kp_u_gc); + if (unlikely(!gc)) return -1; + py_status = __Pyx_PyObject_CallMethod0(gc, __pyx_mstate_global->__pyx_kp_u_isenabled); + if (unlikely(!py_status)) { + Py_DECREF(gc); + return -1; + } + gc_was_enabled = __Pyx_PyObject_IsTrue(py_status); + Py_DECREF(py_status); + if (gc_was_enabled > 0) { + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_mstate_global->__pyx_kp_u_disable); + if (unlikely(!ret)) { + Py_DECREF(gc); + return -1; + } + Py_DECREF(ret); + } else if (unlikely(gc_was_enabled == -1)) { + Py_DECREF(gc); + return -1; + } + #endif + t->tp_flags |= Py_TPFLAGS_HEAPTYPE; +#if PY_VERSION_HEX >= 0x030A0000 + t->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; +#endif +#else + (void)__Pyx_PyObject_CallMethod0; +#endif + r = PyType_Ready(t); +#if !defined(PYSTON_MAJOR_VERSION) + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; + #if PY_VERSION_HEX >= 0x030A00b1 + if (gc_was_enabled) + PyGC_Enable(); + #else + if (gc_was_enabled) { + PyObject *tp, *v, *tb; + PyErr_Fetch(&tp, &v, &tb); + ret = __Pyx_PyObject_CallMethod0(gc, __pyx_mstate_global->__pyx_kp_u_enable); + if (likely(ret || r == -1)) { + Py_XDECREF(ret); + PyErr_Restore(tp, v, tb); + } else { + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + r = -1; + } + } + Py_DECREF(gc); + #endif + } +#endif + return r; +#endif +} + +/* HasAttr (used by ImportImpl) */ +#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *r; + if (unlikely(!PyUnicode_Check(n))) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return -1; + } + r = __Pyx_PyObject_GetAttrStrNoError(o, n); + if (!r) { + return (unlikely(PyErr_Occurred())) ? -1 : 0; + } else { + Py_DECREF(r); + return 1; + } +} +#endif + +/* ImportImpl (used by Import) */ +static int __Pyx__Import_GetModule(PyObject *qualname, PyObject **module) { + PyObject *imported_module = PyImport_GetModule(qualname); + if (unlikely(!imported_module)) { + *module = NULL; + if (PyErr_Occurred()) { + return -1; + } + return 0; + } + *module = imported_module; + return 1; +} +static int __Pyx__Import_Lookup(PyObject *qualname, PyObject *const *imported_names, Py_ssize_t len_imported_names, PyObject **module) { + PyObject *imported_module; + PyObject *top_level_package_name; + Py_ssize_t i; + int status, module_found; + Py_ssize_t dot_index; + module_found = __Pyx__Import_GetModule(qualname, &imported_module); + if (unlikely(!module_found || module_found == -1)) { + *module = NULL; + return module_found; + } + if (imported_names) { + for (i = 0; i < len_imported_names; i++) { + PyObject *imported_name = imported_names[i]; +#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 + int has_imported_attribute = PyObject_HasAttr(imported_module, imported_name); +#else + int has_imported_attribute = PyObject_HasAttrWithError(imported_module, imported_name); + if (unlikely(has_imported_attribute == -1)) goto error; +#endif + if (!has_imported_attribute) { + goto not_found; + } + } + *module = imported_module; + return 1; + } + dot_index = PyUnicode_FindChar(qualname, '.', 0, PY_SSIZE_T_MAX, 1); + if (dot_index == -1) { + *module = imported_module; + return 1; + } + if (unlikely(dot_index == -2)) goto error; + top_level_package_name = PyUnicode_Substring(qualname, 0, dot_index); + if (unlikely(!top_level_package_name)) goto error; + Py_DECREF(imported_module); + status = __Pyx__Import_GetModule(top_level_package_name, module); + Py_DECREF(top_level_package_name); + return status; +error: + Py_DECREF(imported_module); + *module = NULL; + return -1; +not_found: + Py_DECREF(imported_module); + *module = NULL; + return 0; +} +static PyObject *__Pyx__Import(PyObject *name, PyObject *const *imported_names, Py_ssize_t len_imported_names, PyObject *qualname, PyObject *moddict, int level) { + PyObject *module = 0; + PyObject *empty_dict = 0; + PyObject *from_list = 0; + int module_found; + if (!qualname) { + qualname = name; + } + module_found = __Pyx__Import_Lookup(qualname, imported_names, len_imported_names, &module); + if (likely(module_found == 1)) { + return module; + } else if (unlikely(module_found == -1)) { + return NULL; + } + empty_dict = PyDict_New(); + if (unlikely(!empty_dict)) + goto bad; + if (imported_names) { +#if CYTHON_COMPILING_IN_CPYTHON + from_list = __Pyx_PyList_FromArray(imported_names, len_imported_names); + if (unlikely(!from_list)) + goto bad; +#else + from_list = PyList_New(len_imported_names); + if (unlikely(!from_list)) goto bad; + for (Py_ssize_t i=0; i__pyx_d, level); +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + const char* module_name_str = 0; + PyObject* module_name = 0; + PyObject* module_dot = 0; + PyObject* full_name = 0; + PyErr_Clear(); + module_name_str = PyModule_GetName(module); + if (unlikely(!module_name_str)) { goto modbad; } + module_name = PyUnicode_FromString(module_name_str); + if (unlikely(!module_name)) { goto modbad; } + module_dot = PyUnicode_Concat(module_name, __pyx_mstate_global->__pyx_kp_u_); + if (unlikely(!module_dot)) { goto modbad; } + full_name = PyUnicode_Concat(module_dot, name); + if (unlikely(!full_name)) { goto modbad; } + #if (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) ||\ + CYTHON_COMPILING_IN_GRAAL + { + PyObject *modules = PyImport_GetModuleDict(); + if (unlikely(!modules)) + goto modbad; + value = PyObject_GetItem(modules, full_name); + } + #else + value = PyImport_GetModule(full_name); + #endif + modbad: + Py_XDECREF(full_name); + Py_XDECREF(module_dot); + Py_XDECREF(module_name); + } + if (unlikely(!value)) { + PyErr_Format(PyExc_ImportError, "cannot import name %S", name); + } + return value; +} + +/* ListPack */ +static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...) { + va_list va; + PyObject *l = PyList_New(n); + va_start(va, n); + if (unlikely(!l)) goto end; + for (Py_ssize_t i=0; i 0xd)); +} +CYTHON_UNUSED static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length) { + double value; + Py_ssize_t i, digits; + const char *last = start + length; + char *end; + while (__Pyx__PyBytes_AsDouble_IsSpace(*start)) + start++; + while (start < last - 1 && __Pyx__PyBytes_AsDouble_IsSpace(last[-1])) + last--; + length = last - start; + if (unlikely(length <= 0)) goto fallback; + value = __Pyx__PyBytes_AsDouble_inf_nan(start, length); + if (unlikely(value == -1.0)) goto fallback; + if (value != 0.0) return value; + digits = 0; + for (i=0; i < length; digits += start[i++] != '_'); + if (likely(digits == length)) { + value = PyOS_string_to_double(start, &end, NULL); + } else if (digits < 40) { + char number[40]; + last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); + if (unlikely(!last)) goto fallback; + value = PyOS_string_to_double(number, &end, NULL); + } else { + char *number = (char*) PyMem_Malloc((digits + 1) * sizeof(char)); + if (unlikely(!number)) goto fallback; + last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); + if (unlikely(!last)) { + PyMem_Free(number); + goto fallback; + } + value = PyOS_string_to_double(number, &end, NULL); + PyMem_Free(number); + } + if (likely(end == last) || (value == (double)-1 && PyErr_Occurred())) { + return value; + } +fallback: + return __Pyx_SlowPyString_AsDouble(obj); +} + +/* dict_setdefault (used by FetchCommonType) */ +static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value) { + PyObject* value; +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX >= 0x030C0000 + PyObject *args[] = {d, key, default_value}; + value = PyObject_VectorcallMethod(__pyx_mstate_global->__pyx_n_u_setdefault, args, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#elif CYTHON_COMPILING_IN_LIMITED_API + value = PyObject_CallMethodObjArgs(d, __pyx_mstate_global->__pyx_n_u_setdefault, key, default_value, NULL); +#elif PY_VERSION_HEX >= 0x030d0000 + PyDict_SetDefaultRef(d, key, default_value, &value); +#else + value = PyDict_SetDefault(d, key, default_value); + if (unlikely(!value)) return NULL; + Py_INCREF(value); +#endif + return value; +} + +/* AddModuleRef (used by FetchSharedCythonModule) */ +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + static PyObject *__Pyx_PyImport_AddModuleObjectRef(PyObject *name) { + PyObject *module_dict = PyImport_GetModuleDict(); + PyObject *m; + if (PyMapping_GetOptionalItem(module_dict, name, &m) < 0) { + return NULL; + } + if (m != NULL && PyModule_Check(m)) { + return m; + } + Py_XDECREF(m); + m = PyModule_NewObject(name); + if (m == NULL) + return NULL; + if (PyDict_CheckExact(module_dict)) { + PyObject *new_m; + (void)PyDict_SetDefaultRef(module_dict, name, m, &new_m); + Py_DECREF(m); + return new_m; + } else { + if (PyObject_SetItem(module_dict, name, m) != 0) { + Py_DECREF(m); + return NULL; + } + return m; + } + } + static PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *py_name = PyUnicode_FromString(name); + if (!py_name) return NULL; + PyObject *module = __Pyx_PyImport_AddModuleObjectRef(py_name); + Py_DECREF(py_name); + return module; + } +#elif __PYX_LIMITED_VERSION_HEX >= 0x030d0000 + #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) +#else + static PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { + PyObject *module = PyImport_AddModule(name); + Py_XINCREF(module); + return module; + } +#endif + +/* FetchSharedCythonModule (used by FetchCommonType) */ +static PyObject *__Pyx_FetchSharedCythonABIModule(void) { + return __Pyx_PyImport_AddModuleRef(__PYX_ABI_MODULE_NAME); +} + +/* FetchCommonType (used by CommonTypesMetaclass) */ +#if __PYX_LIMITED_VERSION_HEX < 0x030C0000 +static PyObject* __Pyx_PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *result = __Pyx_PyType_FromModuleAndSpec(module, spec, bases); + if (result && metaclass) { + PyObject *old_tp = (PyObject*)Py_TYPE(result); + Py_INCREF((PyObject*)metaclass); +#if __PYX_LIMITED_VERSION_HEX >= 0x03090000 + Py_SET_TYPE(result, metaclass); +#else + result->ob_type = metaclass; +#endif + Py_DECREF(old_tp); + } + return result; +} +#else +#define __Pyx_PyType_FromMetaclass(me, mo, s, b) PyType_FromMetaclass(me, mo, s, b) +#endif +static int __Pyx_VerifyCachedType(PyObject *cached_type, + const char *name, + Py_ssize_t expected_basicsize) { + Py_ssize_t basicsize; + if (!PyType_Check(cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", name); + return -1; + } + if (expected_basicsize == 0) { + return 0; // size is inherited, nothing useful to check + } +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_basicsize; + py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); + if (unlikely(!py_basicsize)) return -1; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = NULL; + if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) return -1; +#else + basicsize = ((PyTypeObject*) cached_type)->tp_basicsize; +#endif + if (basicsize != expected_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + name); + return -1; + } + return 0; +} +static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) { + PyObject *abi_module = NULL, *cached_type = NULL, *abi_module_dict, *new_cached_type, *py_object_name; + int get_item_ref_result; + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; + py_object_name = PyUnicode_FromString(object_name); + if (!py_object_name) return NULL; + abi_module = __Pyx_FetchSharedCythonABIModule(); + if (!abi_module) goto done; + abi_module_dict = PyModule_GetDict(abi_module); + if (!abi_module_dict) goto done; + get_item_ref_result = __Pyx_PyDict_GetItemRef(abi_module_dict, py_object_name, &cached_type); + if (get_item_ref_result == 1) { + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } else if (unlikely(get_item_ref_result == -1)) { + goto bad; + } + cached_type = __Pyx_PyType_FromMetaclass( + metaclass, + CYTHON_USE_MODULE_STATE ? module : abi_module, + spec, bases); + if (unlikely(!cached_type)) goto bad; + if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; + new_cached_type = __Pyx_PyDict_SetDefault(abi_module_dict, py_object_name, cached_type); + if (unlikely(new_cached_type != cached_type)) { + if (unlikely(!new_cached_type)) goto bad; + Py_DECREF(cached_type); + cached_type = new_cached_type; + if (__Pyx_VerifyCachedType( + cached_type, + object_name, + spec->basicsize) < 0) { + goto bad; + } + goto done; + } else { + Py_DECREF(new_cached_type); + } +done: + Py_XDECREF(abi_module); + Py_DECREF(py_object_name); + assert(cached_type == NULL || PyType_Check(cached_type)); + return (PyTypeObject *) cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} + +/* CommonTypesMetaclass (used by CythonFunctionShared) */ +static PyObject* __pyx_CommonTypesMetaclass_get_module(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED void* context) { + return PyUnicode_FromString(__PYX_ABI_MODULE_NAME); +} +#if __PYX_LIMITED_VERSION_HEX < 0x030A0000 +static PyObject* __pyx_CommonTypesMetaclass_call(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED PyObject *args, CYTHON_UNUSED PyObject *kwds) { + PyErr_SetString(PyExc_TypeError, "Cannot instantiate Cython internal types"); + return NULL; +} +static int __pyx_CommonTypesMetaclass_setattr(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED PyObject *attr, CYTHON_UNUSED PyObject *value) { + PyErr_SetString(PyExc_TypeError, "Cython internal types are immutable"); + return -1; +} +#endif +static PyGetSetDef __pyx_CommonTypesMetaclass_getset[] = { + {"__module__", __pyx_CommonTypesMetaclass_get_module, NULL, NULL, NULL}, + {0, 0, 0, 0, 0} +}; +static PyType_Slot __pyx_CommonTypesMetaclass_slots[] = { + {Py_tp_getset, (void *)__pyx_CommonTypesMetaclass_getset}, + #if __PYX_LIMITED_VERSION_HEX < 0x030A0000 + {Py_tp_call, (void*)__pyx_CommonTypesMetaclass_call}, + {Py_tp_new, (void*)__pyx_CommonTypesMetaclass_call}, + {Py_tp_setattro, (void*)__pyx_CommonTypesMetaclass_setattr}, + #endif + {0, 0} +}; +static PyType_Spec __pyx_CommonTypesMetaclass_spec = { + __PYX_TYPE_MODULE_PREFIX "_common_types_metatype", + 0, + 0, + Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION | + Py_TPFLAGS_DEFAULT, + __pyx_CommonTypesMetaclass_slots +}; +static int __pyx_CommonTypesMetaclass_init(PyObject *module) { + __pyx_mstatetype *mstate = __Pyx_PyModule_GetState(module); + PyObject *bases = PyTuple_Pack(1, &PyType_Type); + if (unlikely(!bases)) { + return -1; + } + mstate->__pyx_CommonTypesMetaclassType = __Pyx_FetchCommonTypeFromSpec(NULL, module, &__pyx_CommonTypesMetaclass_spec, bases); + Py_DECREF(bases); + if (unlikely(mstate->__pyx_CommonTypesMetaclassType == NULL)) { + return -1; + } + return 0; +} + +/* CallTypeTraverse (used by CythonFunctionShared) */ +#if !CYTHON_USE_TYPE_SPECS || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x03090000) +#else +static int __Pyx_call_type_traverse(PyObject *o, int always_call, visitproc visit, void *arg) { + #if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x03090000 + if (__Pyx_get_runtime_version() < 0x03090000) return 0; + #endif + if (!always_call) { + PyTypeObject *base = __Pyx_PyObject_GetSlot(o, tp_base, PyTypeObject*); + unsigned long flags = PyType_GetFlags(base); + if (flags & Py_TPFLAGS_HEAPTYPE) { + return 0; + } + } + Py_VISIT((PyObject*)Py_TYPE(o)); + return 0; +} +#endif + +/* PyMethodNew (used by CythonFunctionShared) */ +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + PyObject *result; + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + #if __PYX_LIMITED_VERSION_HEX >= 0x030C0000 + { + PyObject *args[] = {func, self}; + result = PyObject_Vectorcall(__pyx_mstate_global->__Pyx_CachedMethodType, args, 2, NULL); + } + #else + result = PyObject_CallFunctionObjArgs(__pyx_mstate_global->__Pyx_CachedMethodType, func, self, NULL); + #endif + return result; +} +#else +static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { + CYTHON_UNUSED_VAR(typ); + if (!self) + return __Pyx_NewRef(func); + return PyMethod_New(func, self); +} +#endif + +/* PyVectorcallFastCallDict (used by CythonFunctionShared) */ +#if CYTHON_METH_FASTCALL && CYTHON_VECTORCALL +static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + PyObject *res = NULL; + PyObject *kwnames; + PyObject **newargs; + PyObject **kwvalues; + Py_ssize_t i; + #if CYTHON_AVOID_BORROWED_REFS + PyObject *pos; + #else + Py_ssize_t pos; + #endif + size_t j; + PyObject *key, *value; + unsigned long keys_are_strings; + #if !CYTHON_ASSUME_SAFE_SIZE + Py_ssize_t nkw = PyDict_Size(kw); + if (unlikely(nkw == -1)) return NULL; + #else + Py_ssize_t nkw = PyDict_GET_SIZE(kw); + #endif + newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); + if (unlikely(newargs == NULL)) { + PyErr_NoMemory(); + return NULL; + } + for (j = 0; j < nargs; j++) newargs[j] = args[j]; + kwnames = PyTuple_New(nkw); + if (unlikely(kwnames == NULL)) { + PyMem_Free(newargs); + return NULL; + } + kwvalues = newargs + nargs; + pos = 0; + i = 0; + keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; + while (__Pyx_PyDict_NextRef(kw, &pos, &key, &value)) { + keys_are_strings &= + #if CYTHON_COMPILING_IN_LIMITED_API + PyType_GetFlags(Py_TYPE(key)); + #else + Py_TYPE(key)->tp_flags; + #endif + #if !CYTHON_ASSUME_SAFE_MACROS + if (unlikely(PyTuple_SetItem(kwnames, i, key) < 0)) goto cleanup; + #else + PyTuple_SET_ITEM(kwnames, i, key); + #endif + kwvalues[i] = value; + i++; + } + if (unlikely(!keys_are_strings)) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + goto cleanup; + } + res = vc(func, newargs, nargs, kwnames); +cleanup: + #if CYTHON_AVOID_BORROWED_REFS + Py_DECREF(pos); + #endif + Py_DECREF(kwnames); + for (i = 0; i < nkw; i++) + Py_DECREF(kwvalues[i]); + PyMem_Free(newargs); + return res; +} +static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) +{ + Py_ssize_t kw_size = + likely(kw == NULL) ? + 0 : +#if !CYTHON_ASSUME_SAFE_SIZE + PyDict_Size(kw); +#else + PyDict_GET_SIZE(kw); +#endif + if (kw_size == 0) { + return vc(func, args, nargs, NULL); + } +#if !CYTHON_ASSUME_SAFE_SIZE + else if (unlikely(kw_size == -1)) { + return NULL; + } +#endif + return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); +} +#endif + +/* CythonFunctionShared (used by CythonFunction) */ +#if CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunctionNoMethod(PyObject *func, void (*cfunc)(void)) { + if (__Pyx_CyFunction_Check(func)) { + return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; + } else if (PyCFunction_Check(func)) { + return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; + } + return 0; +} +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)) { + if ((PyObject*)Py_TYPE(func) == __pyx_mstate_global->__Pyx_CachedMethodType) { + int result; + PyObject *newFunc = PyObject_GetAttr(func, __pyx_mstate_global->__pyx_n_u_func); + if (unlikely(!newFunc)) { + PyErr_Clear(); // It's only an optimization, so don't throw an error + return 0; + } + result = __Pyx__IsSameCyOrCFunctionNoMethod(newFunc, cfunc); + Py_DECREF(newFunc); + return result; + } + return __Pyx__IsSameCyOrCFunctionNoMethod(func, cfunc); +} +#else +static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)) { + if (PyMethod_Check(func)) { + func = PyMethod_GET_FUNCTION(func); + } + return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; +} +#endif +static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + __Pyx_Py_XDECREF_SET( + __Pyx_CyFunction_GetClassObj(f), + ((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#else + __Pyx_Py_XDECREF_SET( + ((PyCMethodObject *) (f))->mm_class, + (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); +#endif +} +static PyObject * +__Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) +{ + if (unlikely(op->func_doc == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); + if (unlikely(!op->func_doc)) return NULL; +#else + if (((PyCFunctionObject*)op)->m_ml->ml_doc) { + op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +#endif + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) { + PyObject *result; + CYTHON_UNUSED_VAR(closure); + __Pyx_BEGIN_CRITICAL_SECTION(op); + result = __Pyx_CyFunction_get_doc_locked(op); + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->func_doc, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) +{ + if (unlikely(op->func_name == NULL)) { +#if CYTHON_COMPILING_IN_LIMITED_API + op->func_name = PyObject_GetAttrString(op->func, "__name__"); +#else + op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) +{ + PyObject *result = NULL; + CYTHON_UNUSED_VAR(context); + __Pyx_BEGIN_CRITICAL_SECTION(op); + result = __Pyx_CyFunction_get_name_locked(op); + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL || !PyUnicode_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->func_name, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + PyObject *result; + __Pyx_BEGIN_CRITICAL_SECTION(op); + Py_INCREF(op->func_qualname); + result = op->func_qualname; + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL || !PyUnicode_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->func_qualname, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +#endif +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(context); + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) +{ + CYTHON_UNUSED_VAR(op); + CYTHON_UNUSED_VAR(context); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + CYTHON_UNUSED_VAR(context); + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults_locked(__pyx_CyFunctionObject *op) { + PyObject* result = op->defaults_tuple; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result = NULL; + CYTHON_UNUSED_VAR(context); + __Pyx_BEGIN_CRITICAL_SECTION(op); + result = __Pyx_CyFunction_get_defaults_locked(op); + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value) { + value = Py_None; + } else if (unlikely(value != Py_None && !PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " + "currently affect the values used in function calls", 1); + Py_INCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults_locked(__pyx_CyFunctionObject *op) { + PyObject* result = op->defaults_kwdict; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { + PyObject* result; + CYTHON_UNUSED_VAR(context); + __Pyx_BEGIN_CRITICAL_SECTION(op); + result = __Pyx_CyFunction_get_kwdefaults_locked(op); + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + if (!value || value == Py_None) { + value = NULL; + } else if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + __Pyx_BEGIN_CRITICAL_SECTION(op); + __Pyx_Py_XDECREF_SET(op->func_annotations, value); + __Pyx_END_CRITICAL_SECTION(); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations_locked(__pyx_CyFunctionObject *op) { + PyObject* result = op->func_annotations; + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { + PyObject *result; + CYTHON_UNUSED_VAR(context); + __Pyx_BEGIN_CRITICAL_SECTION(op); + result = __Pyx_CyFunction_get_annotations_locked(op); + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine_value(__pyx_CyFunctionObject *op) { + int is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; + if (is_coroutine) { + PyObject *is_coroutine_value, *module, *fromlist, *marker = __pyx_mstate_global->__pyx_n_u_is_coroutine; + fromlist = PyList_New(1); + if (unlikely(!fromlist)) return NULL; + Py_INCREF(marker); +#if CYTHON_ASSUME_SAFE_MACROS + PyList_SET_ITEM(fromlist, 0, marker); +#else + if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { + Py_DECREF(marker); + Py_DECREF(fromlist); + return NULL; + } +#endif + module = PyImport_ImportModuleLevelObject(__pyx_mstate_global->__pyx_n_u_asyncio_coroutines, NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + if (unlikely(!module)) goto ignore; + is_coroutine_value = __Pyx_PyObject_GetAttrStr(module, marker); + Py_DECREF(module); + if (likely(is_coroutine_value)) { + return is_coroutine_value; + } +ignore: + PyErr_Clear(); + } + return __Pyx_PyBool_FromLong(is_coroutine); +} +static PyObject * +__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { + PyObject *result; + CYTHON_UNUSED_VAR(context); + if (op->func_is_coroutine) { + return __Pyx_NewRef(op->func_is_coroutine); + } + result = __Pyx_CyFunction_get_is_coroutine_value(op); + if (unlikely(!result)) + return NULL; + __Pyx_BEGIN_CRITICAL_SECTION(op); + if (op->func_is_coroutine) { + Py_DECREF(result); + result = __Pyx_NewRef(op->func_is_coroutine); + } else { + op->func_is_coroutine = __Pyx_NewRef(result); + } + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject *func, const char* message, Py_ssize_t size) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_name = __Pyx_CyFunction_get_name(func, NULL); + if (!py_name) return; + PyErr_Format(PyExc_TypeError, + "%.200S() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + py_name, message, size); + Py_DECREF(py_name); +#else + const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", + name, message, size); +#endif +} +static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, const char* message) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *py_name = __Pyx_CyFunction_get_name(func, NULL); + if (!py_name) return; + PyErr_Format(PyExc_TypeError, + "%.200S() %s", + py_name, message); + Py_DECREF(py_name); +#else + const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; + PyErr_Format(PyExc_TypeError, + "%.200s() %s", + name, message); +#endif +} +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject * +__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_GetAttrString(op->func, "__module__"); +} +static int +__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { + CYTHON_UNUSED_VAR(context); + return PyObject_SetAttrString(op->func, "__module__", value); +} +#endif +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {"func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {"__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {"func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {"__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {"__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 + {"func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)PyObject_GenericSetDict, 0, 0}, + {"__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)PyObject_GenericSetDict, 0, 0}, +#else + {"func_dict", (getter)PyObject_GenericGetDict, (setter)PyObject_GenericSetDict, 0, 0}, + {"__dict__", (getter)PyObject_GenericGetDict, (setter)PyObject_GenericSetDict, 0, 0}, +#endif + {"func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {"__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {"func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {"__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {"func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {"__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {"func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {"__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {"__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {"__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {"_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, +#if CYTHON_COMPILING_IN_LIMITED_API + {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { +#if !CYTHON_COMPILING_IN_LIMITED_API + {"__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + {"__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, +#endif +#if CYTHON_METH_FASTCALL +#if CYTHON_COMPILING_IN_LIMITED_API + {"__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, +#else + {"__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, +#endif +#if CYTHON_COMPILING_IN_LIMITED_API + {"__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, +#else + {"__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, +#endif +#endif + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) +{ + PyObject *result = NULL; + CYTHON_UNUSED_VAR(args); + __Pyx_BEGIN_CRITICAL_SECTION(m); + Py_INCREF(m->func_qualname); + result = m->func_qualname; + __Pyx_END_CRITICAL_SECTION(); + return result; +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if CYTHON_COMPILING_IN_LIMITED_API +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { +#if !CYTHON_COMPILING_IN_LIMITED_API + PyCFunctionObject *cf = (PyCFunctionObject*) op; +#endif + if (unlikely(op == NULL)) + return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); + if (unlikely(!op->func)) return NULL; +#endif + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; +#if !CYTHON_COMPILING_IN_LIMITED_API + cf->m_ml = ml; + cf->m_self = (PyObject *) op; +#endif + Py_XINCREF(closure); + op->func_closure = closure; +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_XINCREF(module); + cf->m_module = module; +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + op->func_dict = NULL; +#endif + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; +#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API + op->func_classobj = NULL; +#else + ((PyCMethodObject*)op)->mm_class = NULL; +#endif + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + op->func_is_coroutine = NULL; +#if CYTHON_METH_FASTCALL + switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { + case METH_NOARGS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; + break; + case METH_O: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; + break; + case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; + break; + case METH_FASTCALL | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; + break; + case METH_VARARGS | METH_KEYWORDS: + __Pyx_CyFunction_func_vectorcall(op) = NULL; + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + Py_DECREF(op); + return NULL; + } +#endif + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func); +#else + Py_CLEAR(((PyCFunctionObject*)m)->m_module); +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_dict); +#elif PY_VERSION_HEX < 0x030d0000 + _PyObject_ClearManagedDict((PyObject*)m); +#else + PyObject_ClearManagedDict((PyObject*)m); +#endif + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API +#if PY_VERSION_HEX < 0x030900B1 + Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); +#else + { + PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; + ((PyCMethodObject *) (m))->mm_class = NULL; + Py_XDECREF(cls); + } +#endif +#endif + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + Py_CLEAR(m->func_is_coroutine); + Py_CLEAR(m->defaults); + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + __Pyx_PyHeapTypeObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + { + int e = __Pyx_call_type_traverse((PyObject*)m, 1, visit, arg); + if (e) return e; + } + Py_VISIT(m->func_closure); +#if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func); +#else + Py_VISIT(((PyCFunctionObject*)m)->m_module); +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_dict); +#else + { + int e = +#if PY_VERSION_HEX < 0x030d0000 + _PyObject_VisitManagedDict +#else + PyObject_VisitManagedDict +#endif + ((PyObject*)m, visit, arg); + if (e != 0) return e; + } +#endif + __Pyx_VISIT_CONST(m->func_name); + __Pyx_VISIT_CONST(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + __Pyx_VISIT_CONST(m->func_code); +#if !CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); +#endif + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + Py_VISIT(m->func_is_coroutine); + Py_VISIT(m->defaults); + return 0; +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ + PyObject *repr; + __Pyx_BEGIN_CRITICAL_SECTION(op); + repr = PyUnicode_FromFormat("", + op->func_qualname, (void *)op); + __Pyx_END_CRITICAL_SECTION(); + return repr; +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { +#if CYTHON_COMPILING_IN_LIMITED_API + PyObject *f = ((__pyx_CyFunctionObject*)func)->func; + PyCFunction meth; + int flags; + meth = PyCFunction_GetFunction(f); + if (unlikely(!meth)) return NULL; + flags = PyCFunction_GetFlags(f); + if (unlikely(flags < 0)) return NULL; +#else + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + int flags = f->m_ml->ml_flags; +#endif + Py_ssize_t size; + switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void(*)(void))meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_SIZE + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 0)) + return (*meth)(self, NULL); + __Pyx_CyFunction_raise_argument_count_error( + (__pyx_CyFunctionObject*)func, + "takes no arguments", size); + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { +#if CYTHON_ASSUME_SAFE_SIZE + size = PyTuple_GET_SIZE(arg); +#else + size = PyTuple_Size(arg); + if (unlikely(size < 0)) return NULL; +#endif + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } + __Pyx_CyFunction_raise_argument_count_error( + (__pyx_CyFunctionObject*)func, + "takes exactly one argument", size); + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); + return NULL; + } + __Pyx_CyFunction_raise_type_error( + (__pyx_CyFunctionObject*)func, "takes no keyword arguments"); + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *self, *result; +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)func)->m_self; +#endif + result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); + return result; +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; +#if CYTHON_METH_FASTCALL && CYTHON_VECTORCALL + __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); + if (vc) { +#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE + return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); +#else + (void) &__Pyx_PyVectorcall_FastCallDict; + return PyVectorcall_Call(func, args, kw); +#endif + } +#endif + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; +#if CYTHON_ASSUME_SAFE_SIZE + argc = PyTuple_GET_SIZE(args); +#else + argc = PyTuple_Size(args); + if (unlikely(argc < 0)) return NULL; +#endif + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +#if CYTHON_METH_FASTCALL && CYTHON_VECTORCALL +static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) +{ + int ret = 0; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + if (unlikely(nargs < 1)) { + __Pyx_CyFunction_raise_type_error( + cyfunc, "needs an argument"); + return -1; + } + ret = 1; + } + if (unlikely(kwnames) && unlikely(__Pyx_PyTuple_GET_SIZE(kwnames))) { + __Pyx_CyFunction_raise_type_error( + cyfunc, "takes no keyword arguments"); + return -1; + } + return ret; +} +static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + PyObject *self; +#if CYTHON_COMPILING_IN_LIMITED_API + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; +#else + PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; +#endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)cyfunc)->m_self; +#endif + break; + default: + return NULL; + } + if (unlikely(nargs != 0)) { + __Pyx_CyFunction_raise_argument_count_error( + cyfunc, "takes no arguments", nargs); + return NULL; + } + return meth(self, NULL); +} +static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + PyObject *self; +#if CYTHON_COMPILING_IN_LIMITED_API + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; +#else + PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; +#endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)cyfunc)->m_self; +#endif + break; + default: + return NULL; + } + if (unlikely(nargs != 1)) { + __Pyx_CyFunction_raise_argument_count_error( + cyfunc, "takes exactly one argument", nargs); + return NULL; + } + return meth(self, args[0]); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + PyObject *self; +#if CYTHON_COMPILING_IN_LIMITED_API + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; +#else + PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; +#endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)cyfunc)->m_self; +#endif + break; + default: + return NULL; + } + return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))meth)(self, args, nargs, kwnames); +} +static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) +{ + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; + PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + PyObject *self; +#if CYTHON_COMPILING_IN_LIMITED_API + PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); + if (unlikely(!meth)) return NULL; +#else + PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; +#endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: + self = args[0]; + args += 1; + nargs -= 1; + break; + case 0: +#if CYTHON_COMPILING_IN_LIMITED_API + self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); + if (unlikely(!self) && PyErr_Occurred()) return NULL; +#else + self = ((PyCFunctionObject*)cyfunc)->m_self; +#endif + break; + default: + return NULL; + } + #if PY_VERSION_HEX < 0x030e00A6 + size_t nargs_value = (size_t) nargs; + #else + Py_ssize_t nargs_value = nargs; + #endif + return ((__Pyx_PyCMethod)(void(*)(void))meth)(self, cls, args, nargs_value, kwnames); +} +#endif +static PyType_Slot __pyx_CyFunctionType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, + {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, + {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, + {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, + {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, + {Py_tp_methods, (void *)__pyx_CyFunction_methods}, + {Py_tp_members, (void *)__pyx_CyFunction_members}, + {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, + {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, + {0, 0}, +}; +static PyType_Spec __pyx_CyFunctionType_spec = { + __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, +#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR + Py_TPFLAGS_METHOD_DESCRIPTOR | +#endif +#if CYTHON_METH_FASTCALL +#if defined(Py_TPFLAGS_HAVE_VECTORCALL) + Py_TPFLAGS_HAVE_VECTORCALL | +#elif defined(_Py_TPFLAGS_HAVE_VECTORCALL) + _Py_TPFLAGS_HAVE_VECTORCALL | +#endif +#endif // CYTHON_METH_FASTCALL +#if PY_VERSION_HEX >= 0x030C0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_TPFLAGS_MANAGED_DICT | +#endif + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + __pyx_CyFunctionType_slots +}; +static int __pyx_CyFunction_init(PyObject *module) { + __pyx_mstatetype *mstate = __Pyx_PyModule_GetState(module); + mstate->__pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec( + mstate->__pyx_CommonTypesMetaclassType, module, &__pyx_CyFunctionType_spec, NULL); + if (unlikely(mstate->__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_InitDefaults(PyObject *func, PyTypeObject *defaults_type) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_CallObject((PyObject*)defaults_type, NULL); // _PyObject_New(defaults_type); + if (unlikely(!m->defaults)) + return NULL; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_mstate_global->__pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* CLineInTraceback (used by AddTraceback) */ +#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030A0000 +#define __Pyx_PyProbablyModule_GetDict(o) __Pyx_XNewRef(PyModule_GetDict(o)) +#elif !CYTHON_COMPILING_IN_CPYTHON || CYTHON_COMPILING_IN_CPYTHON_FREETHREADING +#define __Pyx_PyProbablyModule_GetDict(o) PyObject_GenericGetDict(o, NULL); +#else +PyObject* __Pyx_PyProbablyModule_GetDict(PyObject *o) { + PyObject **dict_ptr = _PyObject_GetDictPtr(o); + return dict_ptr ? __Pyx_XNewRef(*dict_ptr) : NULL; +} +#endif +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline = NULL; + PyObject *ptype, *pvalue, *ptraceback; + PyObject *cython_runtime_dict; + CYTHON_MAYBE_UNUSED_VAR(tstate); + if (unlikely(!__pyx_mstate_global->__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + cython_runtime_dict = __Pyx_PyProbablyModule_GetDict(__pyx_mstate_global->__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, cython_runtime_dict, + __Pyx_PyDict_SetDefault(cython_runtime_dict, __pyx_mstate_global->__pyx_n_u_cline_in_traceback, Py_False)) + } + if (use_cline == NULL || use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + Py_XDECREF(use_cline); + Py_XDECREF(cython_runtime_dict); + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache (used by AddTraceback) */ +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static __Pyx_CachedCodeObjectType *__pyx__find_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line) { + __Pyx_CachedCodeObjectType* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!code_cache->entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); + if (unlikely(pos >= code_cache->count) || unlikely(code_cache->entries[pos].code_line != code_line)) { + return NULL; + } + code_object = code_cache->entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line) { +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS + (void)__pyx__find_code_object; + return NULL; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just miss. +#else + struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + __pyx_nonatomic_int_type old_count = __pyx_atomic_incr_acq_rel(&code_cache->accessor_count); + if (old_count < 0) { + __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); + return NULL; + } +#endif + __Pyx_CachedCodeObjectType *result = __pyx__find_code_object(code_cache, code_line); +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); +#endif + return result; +#endif +} +static void __pyx__insert_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line, __Pyx_CachedCodeObjectType* code_object) +{ + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = code_cache->entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + code_cache->entries = entries; + code_cache->max_count = 64; + code_cache->count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); + if ((pos < code_cache->count) && unlikely(code_cache->entries[pos].code_line == code_line)) { + __Pyx_CachedCodeObjectType* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_INCREF(code_object); + Py_DECREF(tmp); + return; + } + if (code_cache->count == code_cache->max_count) { + int new_max = code_cache->max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + code_cache->entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + code_cache->entries = entries; + code_cache->max_count = new_max; + } + for (i=code_cache->count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + code_cache->count++; + Py_INCREF(code_object); +} +static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object) { +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS + (void)__pyx__insert_code_object; + return; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just fail. +#else + struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + __pyx_nonatomic_int_type expected = 0; + if (!__pyx_atomic_int_cmp_exchange(&code_cache->accessor_count, &expected, INT_MIN)) { + return; + } +#endif + __pyx__insert_code_object(code_cache, code_line, code_object); +#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING + __pyx_atomic_sub(&code_cache->accessor_count, INT_MIN); +#endif +#endif +} + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API && !defined(PYPY_VERSION) + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#if CYTHON_COMPILING_IN_LIMITED_API +static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, + PyObject *firstlineno, PyObject *name) { + PyObject *replace = NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; + if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; + replace = PyObject_GetAttrString(code, "replace"); + if (likely(replace)) { + PyObject *result = PyObject_Call(replace, __pyx_mstate_global->__pyx_empty_tuple, scratch_dict); + Py_DECREF(replace); + return result; + } + PyErr_Clear(); + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; + PyObject *replace = NULL, *getframe = NULL, *frame = NULL; + PyObject *exc_type, *exc_value, *exc_traceback; + int success = 0; + if (c_line) { + c_line = __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); + } + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + code_object = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!code_object) { + code_object = Py_CompileString("_getframe()", filename, Py_eval_input); + if (unlikely(!code_object)) goto bad; + py_py_line = PyLong_FromLong(py_line); + if (unlikely(!py_py_line)) goto bad; + if (c_line) { + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + } else { + py_funcname = PyUnicode_FromString(funcname); + } + if (unlikely(!py_funcname)) goto bad; + dict = PyDict_New(); + if (unlikely(!dict)) goto bad; + { + PyObject *old_code_object = code_object; + code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); + Py_DECREF(old_code_object); + } + if (unlikely(!code_object)) goto bad; + __pyx_insert_code_object(c_line ? -c_line : py_line, code_object); + } else { + dict = PyDict_New(); + } + getframe = PySys_GetObject("_getframe"); + if (unlikely(!getframe)) goto bad; + if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; + frame = PyEval_EvalCode(code_object, dict, dict); + if (unlikely(!frame) || frame == Py_None) goto bad; + success = 1; + bad: + PyErr_Restore(exc_type, exc_value, exc_traceback); + Py_XDECREF(code_object); + Py_XDECREF(py_py_line); + Py_XDECREF(py_funcname); + Py_XDECREF(dict); + Py_XDECREF(replace); + if (success) { + PyTraceBack_Here( + (struct _frame*)frame); + } + Py_XDECREF(frame); +} +#else +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + if (c_line) { + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + } + py_code = PyCode_NewEmpty(filename, funcname, py_line); + Py_XDECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_funcname); + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_mstate_global->__pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} +#endif + +/* Declarations */ +#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus) + #ifdef __cplusplus + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + return ::std::complex< double >(x, y); + } + #else + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + return x + y*(__pyx_t_double_complex)_Complex_I; + } + #endif +#else + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + __pyx_t_double_complex z; + z.real = x; + z.imag = y; + return z; + } +#endif + +/* Arithmetic */ +#if CYTHON_CCOMPLEX && (1) && (!0 || __cplusplus) +#else + static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + return (a.real == b.real) && (a.imag == b.imag); + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real + b.real; + z.imag = a.imag + b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real - b.real; + z.imag = a.imag - b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real * b.real - a.imag * b.imag; + z.imag = a.real * b.imag + a.imag * b.real; + return z; + } + #if 1 + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + if (b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real); + } else if (fabs(b.real) >= fabs(b.imag)) { + if (b.real == 0 && b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.imag); + } else { + double r = b.imag / b.real; + double s = (double)(1.0) / (b.real + b.imag * r); + return __pyx_t_double_complex_from_parts( + (a.real + a.imag * r) * s, (a.imag - a.real * r) * s); + } + } else { + double r = b.real / b.imag; + double s = (double)(1.0) / (b.imag + b.real * r); + return __pyx_t_double_complex_from_parts( + (a.real * r + a.imag) * s, (a.imag * r - a.real) * s); + } + } + #else + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + if (b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real); + } else { + double denom = b.real * b.real + b.imag * b.imag; + return __pyx_t_double_complex_from_parts( + (a.real * b.real + a.imag * b.imag) / denom, + (a.imag * b.real - a.real * b.imag) / denom); + } + } + #endif + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex a) { + __pyx_t_double_complex z; + z.real = -a.real; + z.imag = -a.imag; + return z; + } + static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex a) { + return (a.real == 0) && (a.imag == 0); + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex a) { + __pyx_t_double_complex z; + z.real = a.real; + z.imag = -a.imag; + return z; + } + #if 1 + static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex z) { + #if !defined(HAVE_HYPOT) || defined(_MSC_VER) + return sqrt(z.real*z.real + z.imag*z.imag); + #else + return hypot(z.real, z.imag); + #endif + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + double r, lnr, theta, z_r, z_theta; + if (b.imag == 0 && b.real == (int)b.real) { + if (b.real < 0) { + double denom = a.real * a.real + a.imag * a.imag; + a.real = a.real / denom; + a.imag = -a.imag / denom; + b.real = -b.real; + } + switch ((int)b.real) { + case 0: + z.real = 1; + z.imag = 0; + return z; + case 1: + return a; + case 2: + return __Pyx_c_prod_double(a, a); + case 3: + z = __Pyx_c_prod_double(a, a); + return __Pyx_c_prod_double(z, a); + case 4: + z = __Pyx_c_prod_double(a, a); + return __Pyx_c_prod_double(z, z); + } + } + if (a.imag == 0) { + if (a.real == 0) { + return a; + } else if ((b.imag == 0) && (a.real >= 0)) { + z.real = pow(a.real, b.real); + z.imag = 0; + return z; + } else if (a.real > 0) { + r = a.real; + theta = 0; + } else { + r = -a.real; + theta = atan2(0.0, -1.0); + } + } else { + r = __Pyx_c_abs_double(a); + theta = atan2(a.imag, a.real); + } + lnr = log(r); + z_r = exp(lnr * b.real - theta * b.imag); + z_theta = theta * b.real + lnr * b.imag; + z.real = z_r * cos(z_theta); + z.imag = z_r * sin(z_theta); + return z; + } + #endif +#endif + +/* FromPy */ +static __pyx_t_double_complex __Pyx_PyComplex_As___pyx_t_double_complex(PyObject* o) { +#if CYTHON_COMPILING_IN_LIMITED_API + double real=-1.0, imag=-1.0; + real = PyComplex_RealAsDouble(o); + if (unlikely(real == -1.0 && PyErr_Occurred())) goto end; + imag = PyComplex_ImagAsDouble(o); + end: + return __pyx_t_double_complex_from_parts( + (double)real, (double)imag + ); +#else + Py_complex cval; +#if !CYTHON_COMPILING_IN_PYPY && !CYTHON_COMPILING_IN_GRAAL + if (PyComplex_CheckExact(o)) + cval = ((PyComplexObject *)o)->cval; + else +#endif + cval = PyComplex_AsCComplex(o); + return __pyx_t_double_complex_from_parts( + (double)cval.real, + (double)cval.imag); +#endif +} + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (unlikely(!PyLong_Check(x))) { + int val; + PyObject *tmp = __Pyx_PyNumber_Long(x); + if (!tmp) return (int) -1; + val = __Pyx_PyLong_As_int(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(int) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) + } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(int) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) + } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) + } + } + { + int val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (int) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (int) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (int) -1; + } else { + stepval = v; + } + v = NULL; + val = (int) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((int) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((int) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (int) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* PyObjectVectorCallKwBuilder (used by CIntToPy) */ +#if CYTHON_VECTORCALL +static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { + (void)__Pyx_PyObject_FastCallDict; + if (__Pyx_PyTuple_SET_ITEM(builder, n, key) != (0)) return -1; + Py_INCREF(key); + args[n] = value; + return 0; +} +CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { + (void)__Pyx_VectorcallBuilder_AddArgStr; + if (unlikely(!PyUnicode_Check(key))) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + return -1; + } + return __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n); +} +static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n) { + PyObject *pyKey = PyUnicode_FromString(key); + if (!pyKey) return -1; + return __Pyx_VectorcallBuilder_AddArg(pyKey, value, builder, args, n); +} +#else // CYTHON_VECTORCALL +CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, CYTHON_UNUSED PyObject **args, CYTHON_UNUSED int n) { + if (unlikely(!PyUnicode_Check(key))) { + PyErr_SetString(PyExc_TypeError, "keywords must be strings"); + return -1; + } + return PyDict_SetItem(builder, key, value); +} +#endif + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyLong_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#if !CYTHON_COMPILING_IN_PYPY + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyLong_FromLong((long) value); + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL, *kwds = NULL; + PyObject *py_bytes = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + { + PyObject *args[3+(CYTHON_VECTORCALL ? 1 : 0)] = { NULL, py_bytes, order_str }; + if (!is_unsigned) { + kwds = __Pyx_MakeVectorcallBuilderKwds(1); + if (!kwds) goto limited_bad; + if (__Pyx_VectorcallBuilder_AddArgStr("signed", __Pyx_NewRef(Py_True), kwds, args+3, 0) < 0) goto limited_bad; + } + result = __Pyx_Object_Vectorcall_CallFromBuilder(from_bytes, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, kwds); + } + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyLong_From_int(int value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyLong_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#if !CYTHON_COMPILING_IN_PYPY + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyLong_FromLong((long) value); + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); + } + } + { + unsigned char *bytes = (unsigned char *)&value; +#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 + if (is_unsigned) { + return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); + } else { + return PyLong_FromNativeBytes(bytes, sizeof(value), -1); + } +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 + int one = 1; int little = (int)*(unsigned char *)&one; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); +#else + int one = 1; int little = (int)*(unsigned char *)&one; + PyObject *from_bytes, *result = NULL, *kwds = NULL; + PyObject *py_bytes = NULL, *order_str = NULL; + from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); + if (!from_bytes) return NULL; + py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(int)); + if (!py_bytes) goto limited_bad; + order_str = PyUnicode_FromString(little ? "little" : "big"); + if (!order_str) goto limited_bad; + { + PyObject *args[3+(CYTHON_VECTORCALL ? 1 : 0)] = { NULL, py_bytes, order_str }; + if (!is_unsigned) { + kwds = __Pyx_MakeVectorcallBuilderKwds(1); + if (!kwds) goto limited_bad; + if (__Pyx_VectorcallBuilder_AddArgStr("signed", __Pyx_NewRef(Py_True), kwds, args+3, 0) < 0) goto limited_bad; + } + result = __Pyx_Object_Vectorcall_CallFromBuilder(from_bytes, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, kwds); + } + limited_bad: + Py_XDECREF(kwds); + Py_XDECREF(order_str); + Py_XDECREF(py_bytes); + Py_XDECREF(from_bytes); + return result; +#endif + } +} + +/* FormatTypeName */ +#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030d0000 +static __Pyx_TypeName +__Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp) +{ + PyObject *module = NULL, *name = NULL, *result = NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 + name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_mstate_global->__pyx_n_u_qualname); + #else + name = PyType_GetQualName(tp); + #endif + if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) goto bad; + module = __Pyx_PyObject_GetAttrStr((PyObject *)tp, + __pyx_mstate_global->__pyx_n_u_module); + if (unlikely(module == NULL) || unlikely(!PyUnicode_Check(module))) goto bad; + if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) { + result = name; + name = NULL; + goto done; + } + result = PyUnicode_FromFormat("%U.%U", module, name); + if (unlikely(result == NULL)) goto bad; + done: + Py_XDECREF(name); + Py_XDECREF(module); + return result; + bad: + PyErr_Clear(); + if (name) { + result = name; + name = NULL; + } else { + result = __Pyx_NewRef(__pyx_mstate_global->__pyx_kp_u__2); + } + goto done; +} +#endif + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (unlikely(!PyLong_Check(x))) { + long val; + PyObject *tmp = __Pyx_PyNumber_Long(x); + if (!tmp) return (long) -1; + val = __Pyx_PyLong_As_long(tmp); + Py_DECREF(tmp); + return val; + } + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + if (unlikely(__Pyx_PyLong_IsNeg(x))) { + goto raise_neg_overflow; + } else if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_DigitCount(x)) { + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if ((sizeof(long) <= sizeof(unsigned long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) + } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + if (__Pyx_PyLong_IsCompact(x)) { + __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) + } else { + const digit* digits = __Pyx_PyLong_Digits(x); + assert(__Pyx_PyLong_DigitCount(x) > 1); + switch (__Pyx_PyLong_SignedDigitCount(x)) { + case -2: + if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { + if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } + } +#endif + if ((sizeof(long) <= sizeof(long))) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) + } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) + } + } + { + long val; + int ret = -1; +#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API + Py_ssize_t bytes_copied = PyLong_AsNativeBytes( + x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); + if (unlikely(bytes_copied == -1)) { + } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { + goto raise_overflow; + } else { + ret = 0; + } +#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + ret = _PyLong_AsByteArray((PyLongObject *)x, + bytes, sizeof(val), + is_little, !is_unsigned); +#else + PyObject *v; + PyObject *stepval = NULL, *mask = NULL, *shift = NULL; + int bits, remaining_bits, is_negative = 0; + int chunk_size = (sizeof(long) < 8) ? 30 : 62; + if (likely(PyLong_CheckExact(x))) { + v = __Pyx_NewRef(x); + } else { + v = PyNumber_Long(x); + if (unlikely(!v)) return (long) -1; + assert(PyLong_CheckExact(v)); + } + { + int result = PyObject_RichCompareBool(v, Py_False, Py_LT); + if (unlikely(result < 0)) { + Py_DECREF(v); + return (long) -1; + } + is_negative = result == 1; + } + if (is_unsigned && unlikely(is_negative)) { + Py_DECREF(v); + goto raise_neg_overflow; + } else if (is_negative) { + stepval = PyNumber_Invert(v); + Py_DECREF(v); + if (unlikely(!stepval)) + return (long) -1; + } else { + stepval = v; + } + v = NULL; + val = (long) 0; + mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; + shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; + for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { + PyObject *tmp, *digit; + long idigit; + digit = PyNumber_And(stepval, mask); + if (unlikely(!digit)) goto done; + idigit = PyLong_AsLong(digit); + Py_DECREF(digit); + if (unlikely(idigit < 0)) goto done; + val |= ((long) idigit) << bits; + tmp = PyNumber_Rshift(stepval, shift); + if (unlikely(!tmp)) goto done; + Py_DECREF(stepval); stepval = tmp; + } + Py_DECREF(shift); shift = NULL; + Py_DECREF(mask); mask = NULL; + { + long idigit = PyLong_AsLong(stepval); + if (unlikely(idigit < 0)) goto done; + remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); + if (unlikely(idigit >= (1L << remaining_bits))) + goto raise_overflow; + val |= ((long) idigit) << bits; + } + if (!is_unsigned) { + if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) + goto raise_overflow; + if (is_negative) + val = ~val; + } + ret = 0; + done: + Py_XDECREF(shift); + Py_XDECREF(mask); + Py_XDECREF(stepval); +#endif + if (unlikely(ret)) + return (long) -1; + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (cls == a || cls == b) return 1; + mro = cls->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(mro, i); + if (base == (PyObject *)a || base == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); +} +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + if (exc_type1) { + return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); + } else { + return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } +} +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); + for (i=0; i>= 8; + ++i; + } + __Pyx_cached_runtime_version = version; + } +} +#endif +static unsigned long __Pyx_get_runtime_version(void) { +#if __PYX_LIMITED_VERSION_HEX >= 0x030b0000 + return Py_Version & ~0xFFUL; +#else + return __Pyx_cached_runtime_version; +#endif +} + +/* SwapException (used by CoroutineBase) */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_value = exc_info->exc_value; + exc_info->exc_value = *value; + if (tmp_value == NULL || tmp_value == Py_None) { + Py_XDECREF(tmp_value); + tmp_value = NULL; + tmp_type = NULL; + tmp_tb = NULL; + } else { + tmp_type = (PyObject*) Py_TYPE(tmp_value); + Py_INCREF(tmp_type); + #if CYTHON_COMPILING_IN_CPYTHON + tmp_tb = ((PyBaseExceptionObject*) tmp_value)->traceback; + Py_XINCREF(tmp_tb); + #else + tmp_tb = PyException_GetTraceback(tmp_value); + #endif + } + #elif CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* PyObjectCall2Args (used by PyObjectCallMethod1) */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args[3] = {NULL, arg1, arg2}; + return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); +} + +/* PyObjectCallMethod1 (used by CoroutineBase) */ +#if !(CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000))) +static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { + PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); + Py_DECREF(method); + return result; +} +#endif +static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { +#if CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000)) + PyObject *args[2] = {obj, arg}; + (void) __Pyx_PyObject_CallOneArg; + (void) __Pyx_PyObject_Call2Args; + return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); +#else + PyObject *method = NULL, *result; + int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); + if (likely(is_method)) { + result = __Pyx_PyObject_Call2Args(method, obj, arg); + Py_DECREF(method); + return result; + } + if (unlikely(!method)) return NULL; + return __Pyx__PyObject_CallMethod1(method, arg); +#endif +} + +/* ReturnWithStopIteration (used by CoroutineBase) */ +static void __Pyx__ReturnWithStopIteration(PyObject* value, int async); +static CYTHON_INLINE void __Pyx_ReturnWithStopIteration(PyObject* value, int async, int iternext) { + if (value == Py_None) { + if (async || !iternext) + PyErr_SetNone(async ? PyExc_StopAsyncIteration : PyExc_StopIteration); + return; + } + __Pyx__ReturnWithStopIteration(value, async); +} +static void __Pyx__ReturnWithStopIteration(PyObject* value, int async) { +#if CYTHON_COMPILING_IN_CPYTHON + __Pyx_PyThreadState_declare +#endif + PyObject *exc; + PyObject *exc_type = async ? PyExc_StopAsyncIteration : PyExc_StopIteration; +#if CYTHON_COMPILING_IN_CPYTHON + if ((PY_VERSION_HEX >= (0x030C00A6)) || unlikely(PyTuple_Check(value) || PyExceptionInstance_Check(value))) { + if (PY_VERSION_HEX >= (0x030e00A1)) { + exc = __Pyx_PyObject_CallOneArg(exc_type, value); + } else { + PyObject *args_tuple = PyTuple_New(1); + if (unlikely(!args_tuple)) return; + Py_INCREF(value); + PyTuple_SET_ITEM(args_tuple, 0, value); + exc = PyObject_Call(exc_type, args_tuple, NULL); + Py_DECREF(args_tuple); + } + if (unlikely(!exc)) return; + } else { + Py_INCREF(value); + exc = value; + } + #if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + #if CYTHON_USE_EXC_INFO_STACK + if (!__pyx_tstate->exc_info->exc_value) + #else + if (!__pyx_tstate->exc_type) + #endif + { + Py_INCREF(exc_type); + __Pyx_ErrRestore(exc_type, exc, NULL); + return; + } + #endif +#else + exc = __Pyx_PyObject_CallOneArg(exc_type, value); + if (unlikely(!exc)) return; +#endif + PyErr_SetObject(exc_type, exc); + Py_DECREF(exc); +} + +/* CoroutineBase (used by Generator) */ +#if !CYTHON_COMPILING_IN_LIMITED_API +#include +#if PY_VERSION_HEX >= 0x030b00a6 && !defined(PYPY_VERSION) + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +#endif // CYTHON_COMPILING_IN_LIMITED_API +static CYTHON_INLINE void +__Pyx_Coroutine_Undelegate(__pyx_CoroutineObject *gen) { +#if CYTHON_USE_AM_SEND + gen->yieldfrom_am_send = NULL; +#endif + Py_CLEAR(gen->yieldfrom); +} +static int __Pyx_PyGen__FetchStopIterationValue(PyThreadState *__pyx_tstate, PyObject **pvalue) { + PyObject *et, *ev, *tb; + PyObject *value = NULL; + CYTHON_UNUSED_VAR(__pyx_tstate); + __Pyx_ErrFetch(&et, &ev, &tb); + if (!et) { + Py_XDECREF(tb); + Py_XDECREF(ev); + Py_INCREF(Py_None); + *pvalue = Py_None; + return 0; + } + if (likely(et == PyExc_StopIteration)) { + if (!ev) { + Py_INCREF(Py_None); + value = Py_None; + } + else if (likely(__Pyx_IS_TYPE(ev, (PyTypeObject*)PyExc_StopIteration))) { + #if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL + value = PyObject_GetAttr(ev, __pyx_mstate_global->__pyx_n_u_value); + if (unlikely(!value)) goto limited_api_failure; + #else + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); + #endif + Py_DECREF(ev); + } + else if (unlikely(PyTuple_Check(ev))) { + Py_ssize_t tuple_size = __Pyx_PyTuple_GET_SIZE(ev); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely(tuple_size < 0)) { + Py_XDECREF(tb); + Py_DECREF(ev); + Py_DECREF(et); + return -1; + } + #endif + if (tuple_size >= 1) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + value = PyTuple_GET_ITEM(ev, 0); + Py_INCREF(value); +#elif CYTHON_ASSUME_SAFE_MACROS + value = PySequence_ITEM(ev, 0); +#else + value = PySequence_GetItem(ev, 0); + if (!value) goto limited_api_failure; +#endif + } else { + Py_INCREF(Py_None); + value = Py_None; + } + Py_DECREF(ev); + } + else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { + value = ev; + } + if (likely(value)) { + Py_XDECREF(tb); + Py_DECREF(et); + *pvalue = value; + return 0; + } + } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + PyErr_NormalizeException(&et, &ev, &tb); + if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) { + __Pyx_ErrRestore(et, ev, tb); + return -1; + } + Py_XDECREF(tb); + Py_DECREF(et); +#if CYTHON_COMPILING_IN_LIMITED_API + value = PyObject_GetAttr(ev, __pyx_mstate_global->__pyx_n_u_value); +#else + value = ((PyStopIterationObject *)ev)->value; + Py_INCREF(value); +#endif + Py_DECREF(ev); +#if CYTHON_COMPILING_IN_LIMITED_API + if (unlikely(!value)) return -1; +#endif + *pvalue = value; + return 0; +#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL || !CYTHON_ASSUME_SAFE_MACROS + limited_api_failure: + Py_XDECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + return -1; +#endif +} +static CYTHON_INLINE +__Pyx_PySendResult __Pyx_Coroutine_status_from_result(PyObject **retval) { + if (*retval) { + return PYGEN_NEXT; + } else if (likely(__Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, retval) == 0)) { + return PYGEN_RETURN; + } else { + return PYGEN_ERROR; + } +} +static CYTHON_INLINE +void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_CLEAR(exc_state->exc_value); +#else + PyObject *t, *v, *tb; + t = exc_state->exc_type; + v = exc_state->exc_value; + tb = exc_state->exc_traceback; + exc_state->exc_type = NULL; + exc_state->exc_value = NULL; + exc_state->exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +#endif +} +#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) +static void __Pyx__Coroutine_AlreadyRunningError(__pyx_CoroutineObject *gen) { + const char *msg; + CYTHON_MAYBE_UNUSED_VAR(gen); + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check((PyObject*)gen)) { + msg = "coroutine already executing"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact((PyObject*)gen)) { + msg = "async generator already executing"; + #endif + } else { + msg = "generator already executing"; + } + PyErr_SetString(PyExc_ValueError, msg); +} +static void __Pyx_Coroutine_AlreadyTerminatedError(PyObject *gen, PyObject *value, int closing) { + CYTHON_MAYBE_UNUSED_VAR(gen); + CYTHON_MAYBE_UNUSED_VAR(closing); + #ifdef __Pyx_Coroutine_USED + if (!closing && __Pyx_Coroutine_Check(gen)) { + PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine"); + } else + #endif + if (value) { + #ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(gen)) + PyErr_SetNone(PyExc_StopAsyncIteration); + else + #endif + PyErr_SetNone(PyExc_StopIteration); + } +} +static +__Pyx_PySendResult __Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, PyObject **result, int closing) { + __Pyx_PyThreadState_declare + PyThreadState *tstate; + __Pyx_ExcInfoStruct *exc_state; + PyObject *retval; + assert(__Pyx_Coroutine_get_is_running(self)); // Callers should ensure is_running + if (unlikely(self->resume_label == -1)) { + __Pyx_Coroutine_AlreadyTerminatedError((PyObject*)self, value, closing); + return PYGEN_ERROR; + } +#if CYTHON_FAST_THREAD_STATE + __Pyx_PyThreadState_assign + tstate = __pyx_tstate; +#else + tstate = __Pyx_PyThreadState_Current; +#endif + exc_state = &self->gi_exc_state; + if (exc_state->exc_value) { + #if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY + #else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #elif PY_VERSION_HEX >= 0x030B00a4 + exc_tb = ((PyBaseExceptionObject*) exc_state->exc_value)->traceback; + #else + exc_tb = exc_state->exc_traceback; + #endif + if (exc_tb) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + assert(f->f_back == NULL); + #if PY_VERSION_HEX >= 0x030B00A1 + f->f_back = PyThreadState_GetFrame(tstate); + #else + Py_XINCREF(tstate->frame); + f->f_back = tstate->frame; + #endif + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_CPYTHON + Py_DECREF(exc_tb); + #endif + } + #endif + } +#if CYTHON_USE_EXC_INFO_STACK + exc_state->previous_item = tstate->exc_info; + tstate->exc_info = exc_state; +#else + if (exc_state->exc_type) { + __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } else { + __Pyx_Coroutine_ExceptionClear(exc_state); + __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback); + } +#endif + retval = self->body(self, tstate, value); +#if CYTHON_USE_EXC_INFO_STACK + exc_state = &self->gi_exc_state; + tstate->exc_info = exc_state->previous_item; + exc_state->previous_item = NULL; + __Pyx_Coroutine_ResetFrameBackpointer(exc_state); +#endif + *result = retval; + if (self->resume_label == -1) { + return likely(retval) ? PYGEN_RETURN : PYGEN_ERROR; + } + return PYGEN_NEXT; +} +static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__Pyx_ExcInfoStruct *exc_state) { +#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API + CYTHON_UNUSED_VAR(exc_state); +#else + PyObject *exc_tb; + #if PY_VERSION_HEX >= 0x030B00a4 + if (!exc_state->exc_value) return; + exc_tb = PyException_GetTraceback(exc_state->exc_value); + #else + exc_tb = exc_state->exc_traceback; + #endif + if (likely(exc_tb)) { + PyTracebackObject *tb = (PyTracebackObject *) exc_tb; + PyFrameObject *f = tb->tb_frame; + Py_CLEAR(f->f_back); + #if PY_VERSION_HEX >= 0x030B00a4 + Py_DECREF(exc_tb); + #endif + } +#endif +} +#define __Pyx_Coroutine_MethodReturnFromResult(gen, result, retval, iternext)\ + ((result) == PYGEN_NEXT ? (retval) : __Pyx__Coroutine_MethodReturnFromResult(gen, result, retval, iternext)) +static PyObject * +__Pyx__Coroutine_MethodReturnFromResult(PyObject* gen, __Pyx_PySendResult result, PyObject *retval, int iternext) { + CYTHON_MAYBE_UNUSED_VAR(gen); + if (likely(result == PYGEN_RETURN)) { + int is_async = 0; + #ifdef __Pyx_AsyncGen_USED + is_async = __Pyx_AsyncGen_CheckExact(gen); + #endif + __Pyx_ReturnWithStopIteration(retval, is_async, iternext); + Py_XDECREF(retval); + } + return NULL; +} +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE +PyObject *__Pyx_PyGen_Send(PyGenObject *gen, PyObject *arg) { +#if PY_VERSION_HEX <= 0x030A00A1 + return _PyGen_Send(gen, arg); +#else + PyObject *result; + if (PyIter_Send((PyObject*)gen, arg ? arg : Py_None, &result) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { +#if PY_VERSION_HEX < 0x030d00A1 + _PyGen_SetStopIterationValue(result); +#else + if (!PyTuple_Check(result) && !PyExceptionInstance_Check(result)) { + PyErr_SetObject(PyExc_StopIteration, result); + } else { + PyObject *exc = __Pyx_PyObject_CallOneArg(PyExc_StopIteration, result); + if (likely(exc != NULL)) { + PyErr_SetObject(PyExc_StopIteration, exc); + Py_DECREF(exc); + } + } +#endif + } + Py_DECREF(result); + result = NULL; + } + return result; +#endif +} +#endif +static CYTHON_INLINE __Pyx_PySendResult +__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen, PyObject** retval) { + __Pyx_PySendResult result; + PyObject *val = NULL; + assert(__Pyx_Coroutine_get_is_running(gen)); + __Pyx_Coroutine_Undelegate(gen); + __Pyx_PyGen__FetchStopIterationValue(__Pyx_PyThreadState_Current, &val); + result = __Pyx_Coroutine_SendEx(gen, val, retval, 0); + Py_XDECREF(val); + return result; +} +#if CYTHON_USE_AM_SEND +static __Pyx_PySendResult +__Pyx_Coroutine_SendToDelegate(__pyx_CoroutineObject *gen, __Pyx_pyiter_sendfunc gen_am_send, PyObject *value, PyObject **retval) { + PyObject *ret = NULL; + __Pyx_PySendResult delegate_result, result; + assert(__Pyx_Coroutine_get_is_running(gen)); + delegate_result = gen_am_send(gen->yieldfrom, value, &ret); + if (delegate_result == PYGEN_NEXT) { + assert (ret != NULL); + *retval = ret; + return PYGEN_NEXT; + } + assert (delegate_result != PYGEN_ERROR || ret == NULL); + __Pyx_Coroutine_Undelegate(gen); + result = __Pyx_Coroutine_SendEx(gen, ret, retval, 0); + Py_XDECREF(ret); + return result; +} +#endif +static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) { + PyObject *retval = NULL; + __Pyx_PySendResult result = __Pyx_Coroutine_AmSend(self, value, &retval); + return __Pyx_Coroutine_MethodReturnFromResult(self, result, retval, 0); +} +static __Pyx_PySendResult +__Pyx_Coroutine_AmSend(PyObject *self, PyObject *value, PyObject **retval) { + __Pyx_PySendResult result; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + if (unlikely(__Pyx_Coroutine_test_and_set_is_running(gen))) { + *retval = __Pyx_Coroutine_AlreadyRunningError(gen); + return PYGEN_ERROR; + } + #if CYTHON_USE_AM_SEND + if (gen->yieldfrom_am_send) { + result = __Pyx_Coroutine_SendToDelegate(gen, gen->yieldfrom_am_send, value, retval); + } else + #endif + if (gen->yieldfrom) { + PyObject *yf = gen->yieldfrom; + PyObject *ret; + #if !CYTHON_USE_AM_SEND + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + ret = __Pyx_Coroutine_Send(yf, value); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + ret = __Pyx_async_gen_asend_send(yf, value); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + if (PyCoro_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, value == Py_None ? NULL : value); + } else + #endif + #endif + { + #if !CYTHON_COMPILING_IN_LIMITED_API || __PYX_LIMITED_VERSION_HEX >= 0x03080000 + if (value == Py_None && PyIter_Check(yf)) + ret = __Pyx_PyIter_Next_Plain(yf); + else + #endif + ret = __Pyx_PyObject_CallMethod1(yf, __pyx_mstate_global->__pyx_n_u_send, value); + } + if (likely(ret)) { + __Pyx_Coroutine_unset_is_running(gen); + *retval = ret; + return PYGEN_NEXT; + } + result = __Pyx_Coroutine_FinishDelegation(gen, retval); + } else { + result = __Pyx_Coroutine_SendEx(gen, value, retval, 0); + } + __Pyx_Coroutine_unset_is_running(gen); + return result; +} +static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) { + __Pyx_PySendResult result; + PyObject *retval = NULL; + CYTHON_UNUSED_VAR(gen); + assert(__Pyx_Coroutine_get_is_running(gen)); + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + result = __Pyx_Coroutine_Close(yf, &retval); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_Check(yf)) { + result = __Pyx_Coroutine_Close(yf, &retval); + } else + if (__Pyx_CoroutineAwait_CheckExact(yf)) { + result = __Pyx_CoroutineAwait_Close((__pyx_CoroutineAwaitObject*)yf); + } else + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_PyAsyncGenASend_CheckExact(yf)) { + retval = __Pyx_async_gen_asend_close(yf, NULL); + result = PYGEN_RETURN; + } else + if (__pyx_PyAsyncGenAThrow_CheckExact(yf)) { + retval = __Pyx_async_gen_athrow_close(yf, NULL); + result = PYGEN_RETURN; + } else + #endif + { + PyObject *meth; + result = PYGEN_RETURN; + meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_mstate_global->__pyx_n_u_close); + if (unlikely(!meth)) { + if (unlikely(PyErr_Occurred())) { + PyErr_WriteUnraisable(yf); + } + } else { + retval = __Pyx_PyObject_CallNoArg(meth); + Py_DECREF(meth); + if (unlikely(!retval)) { + result = PYGEN_ERROR; + } + } + } + Py_XDECREF(retval); + return result == PYGEN_ERROR ? -1 : 0; +} +static PyObject *__Pyx_Generator_Next(PyObject *self) { + __Pyx_PySendResult result; + PyObject *retval = NULL; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + if (unlikely(__Pyx_Coroutine_test_and_set_is_running(gen))) { + return __Pyx_Coroutine_AlreadyRunningError(gen); + } + #if CYTHON_USE_AM_SEND + if (gen->yieldfrom_am_send) { + result = __Pyx_Coroutine_SendToDelegate(gen, gen->yieldfrom_am_send, Py_None, &retval); + } else + #endif + if (gen->yieldfrom) { + PyObject *yf = gen->yieldfrom; + PyObject *ret; + #ifdef __Pyx_Generator_USED + if (__Pyx_Generator_CheckExact(yf)) { + ret = __Pyx_Generator_Next(yf); + } else + #endif + #ifdef __Pyx_Coroutine_USED + if (__Pyx_Coroutine_CheckExact(yf)) { + ret = __Pyx_Coroutine_Send(yf, Py_None); + } else + #endif + #if CYTHON_COMPILING_IN_CPYTHON && (PY_VERSION_HEX < 0x030A00A3 || !CYTHON_USE_AM_SEND) + if (PyGen_CheckExact(yf)) { + ret = __Pyx_PyGen_Send((PyGenObject*)yf, NULL); + } else + #endif + ret = __Pyx_PyIter_Next_Plain(yf); + if (likely(ret)) { + __Pyx_Coroutine_unset_is_running(gen); + return ret; + } + result = __Pyx_Coroutine_FinishDelegation(gen, &retval); + } else { + result = __Pyx_Coroutine_SendEx(gen, Py_None, &retval, 0); + } + __Pyx_Coroutine_unset_is_running(gen); + return __Pyx_Coroutine_MethodReturnFromResult(self, result, retval, 1); +} +static PyObject *__Pyx_Coroutine_Close_Method(PyObject *self, PyObject *arg) { + PyObject *retval = NULL; + __Pyx_PySendResult result; + CYTHON_UNUSED_VAR(arg); + result = __Pyx_Coroutine_Close(self, &retval); + if (unlikely(result == PYGEN_ERROR)) + return NULL; + Py_XDECREF(retval); + Py_RETURN_NONE; +} +static __Pyx_PySendResult +__Pyx_Coroutine_Close(PyObject *self, PyObject **retval) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PySendResult result; + PyObject *yf; + int err = 0; + if (unlikely(__Pyx_Coroutine_test_and_set_is_running(gen))) { + *retval = __Pyx_Coroutine_AlreadyRunningError(gen); + return PYGEN_ERROR; + } + yf = gen->yieldfrom; + if (yf) { + Py_INCREF(yf); + err = __Pyx_Coroutine_CloseIter(gen, yf); + __Pyx_Coroutine_Undelegate(gen); + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + result = __Pyx_Coroutine_SendEx(gen, NULL, retval, 1); + if (result == PYGEN_ERROR) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_Coroutine_unset_is_running(gen); + if (!__Pyx_PyErr_Occurred()) { + return PYGEN_RETURN; + } else if (likely(__Pyx_PyErr_ExceptionMatches2(PyExc_GeneratorExit, PyExc_StopIteration))) { + __Pyx_PyErr_Clear(); + return PYGEN_RETURN; + } + return PYGEN_ERROR; + } else if (likely(result == PYGEN_RETURN && *retval == Py_None)) { + __Pyx_Coroutine_unset_is_running(gen); + return PYGEN_RETURN; + } else { + const char *msg; + Py_DECREF(*retval); + *retval = NULL; + if ((0)) { + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_Coroutine_Check(self)) { + msg = "coroutine ignored GeneratorExit"; + #endif + #ifdef __Pyx_AsyncGen_USED + } else if (__Pyx_AsyncGen_CheckExact(self)) { + msg = "async generator ignored GeneratorExit"; + #endif + } else { + msg = "generator ignored GeneratorExit"; + } + PyErr_SetString(PyExc_RuntimeError, msg); + __Pyx_Coroutine_unset_is_running(gen); + return PYGEN_ERROR; + } +} +static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject *val, PyObject *tb, + PyObject *args, int close_on_genexit) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject *yf; + if (unlikely(__Pyx_Coroutine_test_and_set_is_running(gen))) + return __Pyx_Coroutine_AlreadyRunningError(gen); + yf = gen->yieldfrom; + if (yf) { + __Pyx_PySendResult result; + PyObject *ret; + Py_INCREF(yf); + if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { + int err = __Pyx_Coroutine_CloseIter(gen, yf); + Py_DECREF(yf); + __Pyx_Coroutine_Undelegate(gen); + if (err < 0) + goto propagate_exception; + goto throw_here; + } + if (0 + #ifdef __Pyx_Generator_USED + || __Pyx_Generator_CheckExact(yf) + #endif + #ifdef __Pyx_Coroutine_USED + || __Pyx_Coroutine_Check(yf) + #endif + ) { + ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit); + #ifdef __Pyx_Coroutine_USED + } else if (__Pyx_CoroutineAwait_CheckExact(yf)) { + ret = __Pyx__Coroutine_Throw(((__pyx_CoroutineAwaitObject*)yf)->coroutine, typ, val, tb, args, close_on_genexit); + #endif + } else { + PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(yf, __pyx_mstate_global->__pyx_n_u_throw); + if (unlikely(!meth)) { + Py_DECREF(yf); + if (unlikely(PyErr_Occurred())) { + __Pyx_Coroutine_unset_is_running(gen); + return NULL; + } + __Pyx_Coroutine_Undelegate(gen); + goto throw_here; + } + if (likely(args)) { + ret = __Pyx_PyObject_Call(meth, args, NULL); + } else { + PyObject *cargs[4] = {NULL, typ, val, tb}; + ret = __Pyx_PyObject_FastCall(meth, cargs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); + } + Py_DECREF(meth); + } + Py_DECREF(yf); + if (ret) { + __Pyx_Coroutine_unset_is_running(gen); + return ret; + } + result = __Pyx_Coroutine_FinishDelegation(gen, &ret); + __Pyx_Coroutine_unset_is_running(gen); + return __Pyx_Coroutine_MethodReturnFromResult(self, result, ret, 0); + } +throw_here: + __Pyx_Raise(typ, val, tb, NULL); +propagate_exception: + { + PyObject *retval = NULL; + __Pyx_PySendResult result = __Pyx_Coroutine_SendEx(gen, NULL, &retval, 0); + __Pyx_Coroutine_unset_is_running(gen); + return __Pyx_Coroutine_MethodReturnFromResult(self, result, retval, 0); + } +} +static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { + PyObject *typ; + PyObject *val = NULL; + PyObject *tb = NULL; + if (unlikely(!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))) + return NULL; + return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); +} +static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030B00a4 + Py_VISIT(exc_state->exc_value); +#else + Py_VISIT(exc_state->exc_type); + Py_VISIT(exc_state->exc_value); + Py_VISIT(exc_state->exc_traceback); +#endif + return 0; +} +static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { + { + int e = __Pyx_call_type_traverse((PyObject*)gen, 1, visit, arg); + if (e) return e; + } + Py_VISIT(gen->closure); + Py_VISIT(gen->classobj); + Py_VISIT(gen->yieldfrom); + return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg); +} +static int __Pyx_Coroutine_clear(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + Py_CLEAR(gen->closure); + Py_CLEAR(gen->classobj); + __Pyx_Coroutine_Undelegate(gen); + __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); + } +#endif + Py_CLEAR(gen->gi_code); + Py_CLEAR(gen->gi_frame); + Py_CLEAR(gen->gi_name); + Py_CLEAR(gen->gi_qualname); + Py_CLEAR(gen->gi_modulename); + return 0; +} +static void __Pyx_Coroutine_dealloc(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + PyObject_GC_UnTrack(gen); + #if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + if (gen->gi_weakreflist != NULL) + #endif + PyObject_ClearWeakRefs(self); + if (gen->resume_label >= 0) { + PyObject_GC_Track(self); +#if CYTHON_USE_TP_FINALIZE + if (unlikely(PyObject_CallFinalizerFromDealloc(self))) +#else + { + destructor del = __Pyx_PyObject_GetSlot(gen, tp_del, destructor); + if (del) del(self); + } + if (unlikely(Py_REFCNT(self) > 0)) +#endif + { + return; + } + PyObject_GC_UnTrack(self); + } +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + /* We have to handle this case for asynchronous generators + right here, because this code has to be between UNTRACK + and GC_Del. */ + Py_CLEAR(((__pyx_PyAsyncGenObject*)self)->ag_finalizer); + } +#endif + __Pyx_Coroutine_clear(self); + __Pyx_PyHeapTypeObject_GC_Del(gen); +} +#if CYTHON_USE_TP_FINALIZE +static void __Pyx_Coroutine_del(PyObject *self) { + PyObject *error_type, *error_value, *error_traceback; + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; + __Pyx_PyThreadState_declare + if (gen->resume_label < 0) { + return; + } + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); +#ifdef __Pyx_AsyncGen_USED + if (__Pyx_AsyncGen_CheckExact(self)) { + __pyx_PyAsyncGenObject *agen = (__pyx_PyAsyncGenObject*)self; + PyObject *finalizer = agen->ag_finalizer; + if (finalizer && !agen->ag_closed) { + PyObject *res = __Pyx_PyObject_CallOneArg(finalizer, self); + if (unlikely(!res)) { + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); + return; + } + } +#endif + if (unlikely(gen->resume_label == 0 && !error_value)) { +#ifdef __Pyx_Coroutine_USED +#ifdef __Pyx_Generator_USED + if (!__Pyx_Generator_CheckExact(self)) +#endif + { + PyObject_GC_UnTrack(self); + if (unlikely(PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "coroutine '%.50S' was never awaited", gen->gi_qualname) < 0)) + PyErr_WriteUnraisable(self); + PyObject_GC_Track(self); + } +#endif + } else { + PyObject *retval = NULL; + __Pyx_PySendResult result = __Pyx_Coroutine_Close(self, &retval); + if (result == PYGEN_ERROR) { + PyErr_WriteUnraisable(self); + } else { + Py_XDECREF(retval); + } + } + __Pyx_ErrRestore(error_type, error_value, error_traceback); +} +#endif +static PyObject * +__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_name; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL || !PyUnicode_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_name, value); + return 0; +} +static PyObject * +__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self, void *context) +{ + PyObject *name = self->gi_qualname; + CYTHON_UNUSED_VAR(context); + if (unlikely(!name)) name = Py_None; + Py_INCREF(name); + return name; +} +static int +__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value, void *context) +{ + CYTHON_UNUSED_VAR(context); + if (unlikely(value == NULL || !PyUnicode_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_INCREF(value); + __Pyx_Py_XDECREF_SET(self->gi_qualname, value); + return 0; +} +static PyObject * +__Pyx__Coroutine_get_frame(__pyx_CoroutineObject *self) +{ +#if !CYTHON_COMPILING_IN_LIMITED_API + PyObject *frame; + #if PY_VERSION_HEX >= 0x030d0000 + Py_BEGIN_CRITICAL_SECTION(self); + #endif + frame = self->gi_frame; + if (!frame) { + if (unlikely(!self->gi_code)) { + Py_RETURN_NONE; + } + PyObject *globals = PyDict_New(); + if (unlikely(!globals)) return NULL; + frame = (PyObject *) PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + (PyCodeObject*) self->gi_code, /*PyCodeObject *code,*/ + globals, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + Py_DECREF(globals); + if (unlikely(!frame)) + return NULL; + if (unlikely(self->gi_frame)) { + Py_DECREF(frame); + frame = self->gi_frame; + } else { + self->gi_frame = frame; + } + } + Py_INCREF(frame); + #if PY_VERSION_HEX >= 0x030d0000 + Py_END_CRITICAL_SECTION(); + #endif + return frame; +#else + CYTHON_UNUSED_VAR(self); + Py_RETURN_NONE; +#endif +} +static PyObject * +__Pyx_Coroutine_get_frame(__pyx_CoroutineObject *self, void *context) { + CYTHON_UNUSED_VAR(context); + PyObject *frame = self->gi_frame; + if (frame) + return __Pyx_NewRef(frame); + return __Pyx__Coroutine_get_frame(self); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_New( + PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type); + if (unlikely(!gen)) + return NULL; + return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name); +} +static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( + __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, + PyObject *name, PyObject *qualname, PyObject *module_name) { + gen->body = body; + gen->closure = closure; + Py_XINCREF(closure); + gen->is_running = 0; + gen->resume_label = 0; + gen->classobj = NULL; + gen->yieldfrom = NULL; + gen->yieldfrom_am_send = NULL; + #if PY_VERSION_HEX >= 0x030B00a4 && !CYTHON_COMPILING_IN_LIMITED_API + gen->gi_exc_state.exc_value = NULL; + #else + gen->gi_exc_state.exc_type = NULL; + gen->gi_exc_state.exc_value = NULL; + gen->gi_exc_state.exc_traceback = NULL; + #endif +#if CYTHON_USE_EXC_INFO_STACK + gen->gi_exc_state.previous_item = NULL; +#endif +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + gen->gi_weakreflist = NULL; +#endif + Py_XINCREF(qualname); + gen->gi_qualname = qualname; + Py_XINCREF(name); + gen->gi_name = name; + Py_XINCREF(module_name); + gen->gi_modulename = module_name; + Py_XINCREF(code); + gen->gi_code = code; + gen->gi_frame = NULL; + PyObject_GC_Track(gen); + return gen; +} +static char __Pyx_Coroutine_test_and_set_is_running(__pyx_CoroutineObject *gen) { + char result; + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_BEGIN_CRITICAL_SECTION(gen); + #endif + result = gen->is_running; + gen->is_running = 1; + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_END_CRITICAL_SECTION(); + #endif + return result; +} +static void __Pyx_Coroutine_unset_is_running(__pyx_CoroutineObject *gen) { + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_BEGIN_CRITICAL_SECTION(gen); + #endif + assert(gen->is_running); + gen->is_running = 0; + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_END_CRITICAL_SECTION(); + #endif +} +static char __Pyx_Coroutine_get_is_running(__pyx_CoroutineObject *gen) { + char result; + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_BEGIN_CRITICAL_SECTION(gen); + #endif + result = gen->is_running; + #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_END_CRITICAL_SECTION(); + #endif + return result; +} +static PyObject *__Pyx_Coroutine_get_is_running_getter(PyObject *gen, void *closure) { + CYTHON_UNUSED_VAR(closure); + char result = __Pyx_Coroutine_get_is_running((__pyx_CoroutineObject*)gen); + if (result) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} +#if __PYX_HAS_PY_AM_SEND == 2 +static void __Pyx_SetBackportTypeAmSend(PyTypeObject *type, __Pyx_PyAsyncMethodsStruct *static_amsend_methods, __Pyx_pyiter_sendfunc am_send) { + Py_ssize_t ptr_offset = (char*)(type->tp_as_async) - (char*)type; + if (ptr_offset < 0 || ptr_offset > type->tp_basicsize) { + return; + } + memcpy((void*)static_amsend_methods, (void*)(type->tp_as_async), sizeof(*type->tp_as_async)); + static_amsend_methods->am_send = am_send; + type->tp_as_async = __Pyx_SlotTpAsAsync(static_amsend_methods); +} +#endif +static PyObject *__Pyx_Coroutine_fail_reduce_ex(PyObject *self, PyObject *arg) { + CYTHON_UNUSED_VAR(arg); + __Pyx_TypeName self_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE((PyObject*)self)); + PyErr_Format(PyExc_TypeError, "cannot pickle '" __Pyx_FMT_TYPENAME "' object", + self_type_name); + __Pyx_DECREF_TypeName(self_type_name); + return NULL; +} + +/* Generator */ +static PyMethodDef __pyx_Generator_methods[] = { + {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, + PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")}, + {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, + PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")}, + {"close", (PyCFunction) __Pyx_Coroutine_Close_Method, METH_NOARGS, + PyDoc_STR("close() -> raise GeneratorExit inside generator.")}, + {"__reduce_ex__", (PyCFunction) __Pyx_Coroutine_fail_reduce_ex, METH_O, 0}, + {"__reduce__", (PyCFunction) __Pyx_Coroutine_fail_reduce_ex, METH_NOARGS, 0}, + {0, 0, 0, 0} +}; +static PyMemberDef __pyx_Generator_memberlist[] = { + {"gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY, + PyDoc_STR("object being iterated by 'yield from', or None")}, + {"gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL}, + {"__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), 0, 0}, +#if PY_VERSION_HEX < 0x030C0000 || CYTHON_COMPILING_IN_LIMITED_API + {"__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CoroutineObject, gi_weakreflist), READONLY, 0}, +#endif + {0, 0, 0, 0, 0} +}; +static PyGetSetDef __pyx_Generator_getsets[] = { + {"__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name, + PyDoc_STR("name of the generator"), 0}, + {"__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname, + PyDoc_STR("qualified name of the generator"), 0}, + {"gi_frame", (getter)__Pyx_Coroutine_get_frame, NULL, + PyDoc_STR("Frame of the generator"), 0}, + {"gi_running", __Pyx_Coroutine_get_is_running_getter, NULL, NULL, NULL}, + {0, 0, 0, 0, 0} +}; +static PyType_Slot __pyx_GeneratorType_slots[] = { + {Py_tp_dealloc, (void *)__Pyx_Coroutine_dealloc}, + {Py_tp_traverse, (void *)__Pyx_Coroutine_traverse}, + {Py_tp_iter, (void *)PyObject_SelfIter}, + {Py_tp_iternext, (void *)__Pyx_Generator_Next}, + {Py_tp_methods, (void *)__pyx_Generator_methods}, + {Py_tp_members, (void *)__pyx_Generator_memberlist}, + {Py_tp_getset, (void *)__pyx_Generator_getsets}, + {Py_tp_getattro, (void *) PyObject_GenericGetAttr}, +#if CYTHON_USE_TP_FINALIZE + {Py_tp_finalize, (void *)__Pyx_Coroutine_del}, +#endif +#if __PYX_HAS_PY_AM_SEND == 1 + {Py_am_send, (void *)__Pyx_Coroutine_AmSend}, +#endif + {0, 0}, +}; +static PyType_Spec __pyx_GeneratorType_spec = { + __PYX_TYPE_MODULE_PREFIX "generator", + sizeof(__pyx_CoroutineObject), + 0, +#if PY_VERSION_HEX >= 0x030C0000 && !CYTHON_COMPILING_IN_LIMITED_API + Py_TPFLAGS_MANAGED_WEAKREF | +#endif + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | __Pyx_TPFLAGS_HAVE_AM_SEND, + __pyx_GeneratorType_slots +}; +#if __PYX_HAS_PY_AM_SEND == 2 +static __Pyx_PyAsyncMethodsStruct __pyx_Generator_as_async; +#endif +static int __pyx_Generator_init(PyObject *module) { + __pyx_mstatetype *mstate = __Pyx_PyModule_GetState(module); + mstate->__pyx_GeneratorType = __Pyx_FetchCommonTypeFromSpec( + mstate->__pyx_CommonTypesMetaclassType, module, &__pyx_GeneratorType_spec, NULL); + if (unlikely(!mstate->__pyx_GeneratorType)) { + return -1; + } +#if __PYX_HAS_PY_AM_SEND == 2 + __Pyx_SetBackportTypeAmSend(mstate->__pyx_GeneratorType, &__pyx_Generator_as_async, &__Pyx_Coroutine_AmSend); +#endif + return 0; +} +static PyObject *__Pyx_Generator_GetInlinedResult(PyObject *self) { + __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self; + PyObject *retval = NULL; + if (unlikely(__Pyx_Coroutine_test_and_set_is_running(gen))) { + return __Pyx_Coroutine_AlreadyRunningError(gen); + } + __Pyx_PySendResult result = __Pyx_Coroutine_SendEx(gen, Py_None, &retval, 0); + __Pyx_Coroutine_unset_is_running(gen); + (void) result; + assert (result == PYGEN_RETURN || result == PYGEN_ERROR); + assert ((result == PYGEN_RETURN && retval != NULL) || (result == PYGEN_ERROR && retval == NULL)); + return retval; +} + +/* CheckBinaryVersion */ +static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { + const unsigned long MAJOR_MINOR = 0xFFFF0000UL; + if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) + return 0; + if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) + return 1; + { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compile time Python version %d.%d " + "of module '%.100s' " + "%s " + "runtime version %d.%d", + (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), + __Pyx_MODULE_NAME, + (allow_newer) ? "was newer than" : "does not match", + (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) + ); + return PyErr_WarnEx(NULL, message, 1); + } +} + +/* NewCodeObj */ +#if CYTHON_COMPILING_IN_LIMITED_API + static PyObject* __Pyx__PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *exception_table = NULL; + PyObject *types_module=NULL, *code_type=NULL, *result=NULL; + #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 + PyObject *version_info; + PyObject *py_minor_version = NULL; + #endif + long minor_version = 0; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + #if __PYX_LIMITED_VERSION_HEX >= 0x030b0000 + minor_version = 11; + #else + if (!(version_info = PySys_GetObject("version_info"))) goto end; + if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; + minor_version = PyLong_AsLong(py_minor_version); + Py_DECREF(py_minor_version); + if (minor_version == -1 && PyErr_Occurred()) goto end; + #endif + if (!(types_module = PyImport_ImportModule("types"))) goto end; + if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; + if (minor_version <= 7) { + (void)p; + result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOOO", a, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else if (minor_version <= 10) { + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOOO", a,p, k, l, s, f, code, + c, n, v, fn, name, fline, lnos, fv, cell); + } else { + if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; + result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOOOO", a,p, k, l, s, f, code, + c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); + } + end: + Py_XDECREF(code_type); + Py_XDECREF(exception_table); + Py_XDECREF(types_module); + if (type) { + PyErr_Restore(type, value, traceback); + } + return result; + } +#elif PY_VERSION_HEX >= 0x030B0000 + static PyCodeObject* __Pyx__PyCode_New(int a, int p, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyCodeObject *result; + result = + #if PY_VERSION_HEX >= 0x030C0000 + PyUnstable_Code_NewWithPosOnlyArgs + #else + PyCode_NewWithPosOnlyArgs + #endif + (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, __pyx_mstate_global->__pyx_empty_bytes); + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030c00A1 + if (likely(result)) + result->_co_firsttraceable = 0; + #endif + return result; + } +#elif !CYTHON_COMPILING_IN_PYPY + #define __Pyx__PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx__PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif +static PyObject* __Pyx_PyCode_New( + const __Pyx_PyCode_New_function_description descr, + PyObject * const *varnames, + PyObject *filename, + PyObject *funcname, + PyObject *line_table, + PyObject *tuple_dedup_map +) { + PyObject *code_obj = NULL, *varnames_tuple_dedup = NULL, *code_bytes = NULL; + Py_ssize_t var_count = (Py_ssize_t) descr.nlocals; + PyObject *varnames_tuple = PyTuple_New(var_count); + if (unlikely(!varnames_tuple)) return NULL; + for (Py_ssize_t i=0; i < var_count; i++) { + Py_INCREF(varnames[i]); + if (__Pyx_PyTuple_SET_ITEM(varnames_tuple, i, varnames[i]) != (0)) goto done; + } + #if CYTHON_COMPILING_IN_LIMITED_API + varnames_tuple_dedup = PyDict_GetItem(tuple_dedup_map, varnames_tuple); + if (!varnames_tuple_dedup) { + if (unlikely(PyDict_SetItem(tuple_dedup_map, varnames_tuple, varnames_tuple) < 0)) goto done; + varnames_tuple_dedup = varnames_tuple; + } + #else + varnames_tuple_dedup = PyDict_SetDefault(tuple_dedup_map, varnames_tuple, varnames_tuple); + if (unlikely(!varnames_tuple_dedup)) goto done; + #endif + #if CYTHON_AVOID_BORROWED_REFS + Py_INCREF(varnames_tuple_dedup); + #endif + if (__PYX_LIMITED_VERSION_HEX >= (0x030b0000) && line_table != NULL && !CYTHON_COMPILING_IN_GRAAL) { + Py_ssize_t line_table_length = __Pyx_PyBytes_GET_SIZE(line_table); + #if !CYTHON_ASSUME_SAFE_SIZE + if (unlikely(line_table_length == -1)) goto done; + #endif + Py_ssize_t code_len = (line_table_length * 2 + 4) & ~3LL; + code_bytes = PyBytes_FromStringAndSize(NULL, code_len); + if (unlikely(!code_bytes)) goto done; + char* c_code_bytes = PyBytes_AsString(code_bytes); + if (unlikely(!c_code_bytes)) goto done; + memset(c_code_bytes, 0, (size_t) code_len); + } + code_obj = (PyObject*) __Pyx__PyCode_New( + (int) descr.argcount, + (int) descr.num_posonly_args, + (int) descr.num_kwonly_args, + (int) descr.nlocals, + 0, + (int) descr.flags, + code_bytes ? code_bytes : __pyx_mstate_global->__pyx_empty_bytes, + __pyx_mstate_global->__pyx_empty_tuple, + __pyx_mstate_global->__pyx_empty_tuple, + varnames_tuple_dedup, + __pyx_mstate_global->__pyx_empty_tuple, + __pyx_mstate_global->__pyx_empty_tuple, + filename, + funcname, + (int) descr.first_line, + (__PYX_LIMITED_VERSION_HEX >= (0x030b0000) && line_table) ? line_table : __pyx_mstate_global->__pyx_empty_bytes + ); +done: + Py_XDECREF(code_bytes); + #if CYTHON_AVOID_BORROWED_REFS + Py_XDECREF(varnames_tuple_dedup); + #endif + Py_DECREF(varnames_tuple); + return code_obj; +} + +/* DecompressString */ +static PyObject *__Pyx_DecompressString(const char *s, Py_ssize_t length, int algo) { + PyObject *module, *decompress, *compressed_bytes, *decompressed; + const char* module_name = algo == 3 ? "compression.zstd" : algo == 2 ? "bz2" : "zlib"; + PyObject *methodname = PyUnicode_FromString("decompress"); + if (unlikely(!methodname)) return NULL; + #if __PYX_LIMITED_VERSION_HEX >= 0x030e0000 + if (algo == 3) { + PyObject *fromlist = Py_BuildValue("[O]", methodname); + if (unlikely(!fromlist)) return NULL; + module = PyImport_ImportModuleLevel("compression.zstd", NULL, NULL, fromlist, 0); + Py_DECREF(fromlist); + } else + #endif + module = PyImport_ImportModule(module_name); + if (unlikely(!module)) goto import_failed; + decompress = PyObject_GetAttr(module, methodname); + if (unlikely(!decompress)) goto import_failed; + { + #ifdef __cplusplus + char *memview_bytes = const_cast(s); + #else + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" + #elif !defined(__INTEL_COMPILER) && defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-qual" + #endif + char *memview_bytes = (char*) s; + #if defined(__clang__) + #pragma clang diagnostic pop + #elif !defined(__INTEL_COMPILER) && defined(__GNUC__) + #pragma GCC diagnostic pop + #endif + #endif + #if CYTHON_COMPILING_IN_LIMITED_API && !defined(PyBUF_READ) + int memview_flags = 0x100; + #else + int memview_flags = PyBUF_READ; + #endif + compressed_bytes = PyMemoryView_FromMemory(memview_bytes, length, memview_flags); + } + if (unlikely(!compressed_bytes)) { + Py_DECREF(decompress); + goto bad; + } + decompressed = PyObject_CallFunctionObjArgs(decompress, compressed_bytes, NULL); + Py_DECREF(compressed_bytes); + Py_DECREF(decompress); + Py_DECREF(module); + Py_DECREF(methodname); + return decompressed; +import_failed: + PyErr_Format(PyExc_ImportError, + "Failed to import '%.20s.decompress' - cannot initialise module strings. " + "String compression was configured with the C macro 'CYTHON_COMPRESS_STRINGS=%d'.", + module_name, algo); +bad: + Py_XDECREF(module); + Py_DECREF(methodname); + return NULL; +} + +#include +static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { + size_t len = strlen(s); + if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, "byte string is too long"); + return -1; + } + return (Py_ssize_t) len; +} +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return __Pyx_PyUnicode_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { + Py_ssize_t len = __Pyx_ssize_strlen(c_str); + if (unlikely(len < 0)) return NULL; + return PyByteArray_FromStringAndSize(c_str, len); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if CYTHON_COMPILING_IN_LIMITED_API + { + const char* result; + Py_ssize_t unicode_length; + CYTHON_MAYBE_UNUSED_VAR(unicode_length); // only for __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + #if __PYX_LIMITED_VERSION_HEX < 0x030A0000 + if (unlikely(PyArg_Parse(o, "s#", &result, length) < 0)) return NULL; + #else + result = PyUnicode_AsUTF8AndSize(o, length); + #endif + #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + unicode_length = PyUnicode_GetLength(o); + if (unlikely(unicode_length < 0)) return NULL; + if (unlikely(unicode_length != *length)) { + PyUnicode_AsASCIIString(o); + return NULL; + } + #endif + return result; + } +#else +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +#endif +} +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 + if (PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif + if (PyByteArray_Check(o)) { +#if (CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) || (CYTHON_COMPILING_IN_PYPY && (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))) + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); +#else + *length = PyByteArray_Size(o); + if (*length == -1) return NULL; + return PyByteArray_AsString(o); +#endif + } else + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_LongWrongResultType(PyObject* result) { + __Pyx_TypeName result_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(result)); + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " + "The ability to return an instance of a strict subclass of int is deprecated, " + "and may be removed in a future version of Python.", + result_type_name)) { + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; + } + __Pyx_DECREF_TypeName(result_type_name); + return result; + } + PyErr_Format(PyExc_TypeError, + "__int__ returned non-int (type " __Pyx_FMT_TYPENAME ")", + result_type_name); + __Pyx_DECREF_TypeName(result_type_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + PyObject *res = NULL; + if (likely(PyLong_Check(x))) + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + if (likely(m && m->nb_int)) { + res = m->nb_int(x); + } +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Long(x); + } +#endif + if (likely(res)) { + if (unlikely(!PyLong_CheckExact(res))) { + return __Pyx_PyNumber_LongWrongResultType(res); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(__Pyx_PyLong_IsCompact(b))) { + return __Pyx_PyLong_CompactValue(b); + } else { + const digit* digits = __Pyx_PyLong_Digits(b); + const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyLong_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyLong_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b) { + CYTHON_UNUSED_VAR(b); + return __Pyx_NewRef(Py_None); +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return __Pyx_NewRef(b ? Py_True: Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t ival) { + return PyLong_FromSize_t(ival); +} + + +/* MultiPhaseInitModuleState */ +#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE +#ifndef CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE +#if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX >= 0x030C0000) + #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 1 +#else + #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 0 +#endif +#endif +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE && !CYTHON_ATOMICS +#error "Module state with PEP489 requires atomics. Currently that's one of\ + C11, C++11, gcc atomic intrinsics or MSVC atomic intrinsics" +#endif +#if !CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE +#define __Pyx_ModuleStateLookup_Lock() +#define __Pyx_ModuleStateLookup_Unlock() +#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d0000 +static PyMutex __Pyx_ModuleStateLookup_mutex = {0}; +#define __Pyx_ModuleStateLookup_Lock() PyMutex_Lock(&__Pyx_ModuleStateLookup_mutex) +#define __Pyx_ModuleStateLookup_Unlock() PyMutex_Unlock(&__Pyx_ModuleStateLookup_mutex) +#elif defined(__cplusplus) && __cplusplus >= 201103L +#include +static std::mutex __Pyx_ModuleStateLookup_mutex; +#define __Pyx_ModuleStateLookup_Lock() __Pyx_ModuleStateLookup_mutex.lock() +#define __Pyx_ModuleStateLookup_Unlock() __Pyx_ModuleStateLookup_mutex.unlock() +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201112L) && !defined(__STDC_NO_THREADS__) +#include +static mtx_t __Pyx_ModuleStateLookup_mutex; +static once_flag __Pyx_ModuleStateLookup_mutex_once_flag = ONCE_FLAG_INIT; +static void __Pyx_ModuleStateLookup_initialize_mutex(void) { + mtx_init(&__Pyx_ModuleStateLookup_mutex, mtx_plain); +} +#define __Pyx_ModuleStateLookup_Lock()\ + call_once(&__Pyx_ModuleStateLookup_mutex_once_flag, __Pyx_ModuleStateLookup_initialize_mutex);\ + mtx_lock(&__Pyx_ModuleStateLookup_mutex) +#define __Pyx_ModuleStateLookup_Unlock() mtx_unlock(&__Pyx_ModuleStateLookup_mutex) +#elif defined(HAVE_PTHREAD_H) +#include +static pthread_mutex_t __Pyx_ModuleStateLookup_mutex = PTHREAD_MUTEX_INITIALIZER; +#define __Pyx_ModuleStateLookup_Lock() pthread_mutex_lock(&__Pyx_ModuleStateLookup_mutex) +#define __Pyx_ModuleStateLookup_Unlock() pthread_mutex_unlock(&__Pyx_ModuleStateLookup_mutex) +#elif defined(_WIN32) +#include // synchapi.h on its own doesn't work +static SRWLOCK __Pyx_ModuleStateLookup_mutex = SRWLOCK_INIT; +#define __Pyx_ModuleStateLookup_Lock() AcquireSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) +#define __Pyx_ModuleStateLookup_Unlock() ReleaseSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) +#else +#error "No suitable lock available for CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE.\ + Requires C standard >= C11, or C++ standard >= C++11,\ + or pthreads, or the Windows 32 API, or Python >= 3.13." +#endif +typedef struct { + int64_t id; + PyObject *module; +} __Pyx_InterpreterIdAndModule; +typedef struct { + char interpreter_id_as_index; + Py_ssize_t count; + Py_ssize_t allocated; + __Pyx_InterpreterIdAndModule table[1]; +} __Pyx_ModuleStateLookupData; +#define __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE 32 +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE +static __pyx_atomic_int_type __Pyx_ModuleStateLookup_read_counter = 0; +#endif +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE +static __pyx_atomic_ptr_type __Pyx_ModuleStateLookup_data = 0; +#else +static __Pyx_ModuleStateLookupData* __Pyx_ModuleStateLookup_data = NULL; +#endif +static __Pyx_InterpreterIdAndModule* __Pyx_State_FindModuleStateLookupTableLowerBound( + __Pyx_InterpreterIdAndModule* table, + Py_ssize_t count, + int64_t interpreterId) { + __Pyx_InterpreterIdAndModule* begin = table; + __Pyx_InterpreterIdAndModule* end = begin + count; + if (begin->id == interpreterId) { + return begin; + } + while ((end - begin) > __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { + __Pyx_InterpreterIdAndModule* halfway = begin + (end - begin)/2; + if (halfway->id == interpreterId) { + return halfway; + } + if (halfway->id < interpreterId) { + begin = halfway; + } else { + end = halfway; + } + } + for (; begin < end; ++begin) { + if (begin->id >= interpreterId) return begin; + } + return begin; +} +static PyObject *__Pyx_State_FindModule(CYTHON_UNUSED void* dummy) { + int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); + if (interpreter_id == -1) return NULL; +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __Pyx_ModuleStateLookupData* data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); + { + __pyx_atomic_incr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); + if (likely(data)) { + __Pyx_ModuleStateLookupData* new_data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_acquire(&__Pyx_ModuleStateLookup_data); + if (likely(data == new_data)) { + goto read_finished; + } + } + __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); + __Pyx_ModuleStateLookup_Lock(); + __pyx_atomic_incr_relaxed(&__Pyx_ModuleStateLookup_read_counter); + data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); + __Pyx_ModuleStateLookup_Unlock(); + } + read_finished:; +#else + __Pyx_ModuleStateLookupData* data = __Pyx_ModuleStateLookup_data; +#endif + __Pyx_InterpreterIdAndModule* found = NULL; + if (unlikely(!data)) goto end; + if (data->interpreter_id_as_index) { + if (interpreter_id < data->count) { + found = data->table+interpreter_id; + } + } else { + found = __Pyx_State_FindModuleStateLookupTableLowerBound( + data->table, data->count, interpreter_id); + } + end: + { + PyObject *result=NULL; + if (found && found->id == interpreter_id) { + result = found->module; + } +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); +#endif + return result; + } +} +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE +static void __Pyx_ModuleStateLookup_wait_until_no_readers(void) { + while (__pyx_atomic_load(&__Pyx_ModuleStateLookup_read_counter) != 0); +} +#else +#define __Pyx_ModuleStateLookup_wait_until_no_readers() +#endif +static int __Pyx_State_AddModuleInterpIdAsIndex(__Pyx_ModuleStateLookupData **old_data, PyObject* module, int64_t interpreter_id) { + Py_ssize_t to_allocate = (*old_data)->allocated; + while (to_allocate <= interpreter_id) { + if (to_allocate == 0) to_allocate = 1; + else to_allocate *= 2; + } + __Pyx_ModuleStateLookupData *new_data = *old_data; + if (to_allocate != (*old_data)->allocated) { + new_data = (__Pyx_ModuleStateLookupData *)realloc( + *old_data, + sizeof(__Pyx_ModuleStateLookupData)+(to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); + if (!new_data) { + PyErr_NoMemory(); + return -1; + } + for (Py_ssize_t i = new_data->allocated; i < to_allocate; ++i) { + new_data->table[i].id = i; + new_data->table[i].module = NULL; + } + new_data->allocated = to_allocate; + } + new_data->table[interpreter_id].module = module; + if (new_data->count < interpreter_id+1) { + new_data->count = interpreter_id+1; + } + *old_data = new_data; + return 0; +} +static void __Pyx_State_ConvertFromInterpIdAsIndex(__Pyx_ModuleStateLookupData *data) { + __Pyx_InterpreterIdAndModule *read = data->table; + __Pyx_InterpreterIdAndModule *write = data->table; + __Pyx_InterpreterIdAndModule *end = read + data->count; + for (; readmodule) { + write->id = read->id; + write->module = read->module; + ++write; + } + } + data->count = write - data->table; + for (; writeid = 0; + write->module = NULL; + } + data->interpreter_id_as_index = 0; +} +static int __Pyx_State_AddModule(PyObject* module, CYTHON_UNUSED void* dummy) { + int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); + if (interpreter_id == -1) return -1; + int result = 0; + __Pyx_ModuleStateLookup_Lock(); +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __Pyx_ModuleStateLookupData *old_data = (__Pyx_ModuleStateLookupData *) + __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); +#else + __Pyx_ModuleStateLookupData *old_data = __Pyx_ModuleStateLookup_data; +#endif + __Pyx_ModuleStateLookupData *new_data = old_data; + if (!new_data) { + new_data = (__Pyx_ModuleStateLookupData *)calloc(1, sizeof(__Pyx_ModuleStateLookupData)); + if (!new_data) { + result = -1; + PyErr_NoMemory(); + goto end; + } + new_data->allocated = 1; + new_data->interpreter_id_as_index = 1; + } + __Pyx_ModuleStateLookup_wait_until_no_readers(); + if (new_data->interpreter_id_as_index) { + if (interpreter_id < __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { + result = __Pyx_State_AddModuleInterpIdAsIndex(&new_data, module, interpreter_id); + goto end; + } + __Pyx_State_ConvertFromInterpIdAsIndex(new_data); + } + { + Py_ssize_t insert_at = 0; + { + __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( + new_data->table, new_data->count, interpreter_id); + assert(lower_bound); + insert_at = lower_bound - new_data->table; + if (unlikely(insert_at < new_data->count && lower_bound->id == interpreter_id)) { + lower_bound->module = module; + goto end; // already in table, nothing more to do + } + } + if (new_data->count+1 >= new_data->allocated) { + Py_ssize_t to_allocate = (new_data->count+1)*2; + new_data = + (__Pyx_ModuleStateLookupData*)realloc( + new_data, + sizeof(__Pyx_ModuleStateLookupData) + + (to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); + if (!new_data) { + result = -1; + new_data = old_data; + PyErr_NoMemory(); + goto end; + } + new_data->allocated = to_allocate; + } + ++new_data->count; + int64_t last_id = interpreter_id; + PyObject *last_module = module; + for (Py_ssize_t i=insert_at; icount; ++i) { + int64_t current_id = new_data->table[i].id; + new_data->table[i].id = last_id; + last_id = current_id; + PyObject *current_module = new_data->table[i].module; + new_data->table[i].module = last_module; + last_module = current_module; + } + } + end: +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, new_data); +#else + __Pyx_ModuleStateLookup_data = new_data; +#endif + __Pyx_ModuleStateLookup_Unlock(); + return result; +} +static int __Pyx_State_RemoveModule(CYTHON_UNUSED void* dummy) { + int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); + if (interpreter_id == -1) return -1; + __Pyx_ModuleStateLookup_Lock(); +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __Pyx_ModuleStateLookupData *data = (__Pyx_ModuleStateLookupData *) + __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); +#else + __Pyx_ModuleStateLookupData *data = __Pyx_ModuleStateLookup_data; +#endif + if (data->interpreter_id_as_index) { + if (interpreter_id < data->count) { + data->table[interpreter_id].module = NULL; + } + goto done; + } + { + __Pyx_ModuleStateLookup_wait_until_no_readers(); + __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( + data->table, data->count, interpreter_id); + if (!lower_bound) goto done; + if (lower_bound->id != interpreter_id) goto done; + __Pyx_InterpreterIdAndModule *end = data->table+data->count; + for (;lower_boundid = (lower_bound+1)->id; + lower_bound->module = (lower_bound+1)->module; + } + } + --data->count; + if (data->count == 0) { + free(data); + data = NULL; + } + done: +#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE + __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, data); +#else + __Pyx_ModuleStateLookup_data = data; +#endif + __Pyx_ModuleStateLookup_Unlock(); + return 0; +} +#endif + +/* #### Code section: utility_code_pragmas_end ### */ +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + + + +/* #### Code section: end ### */ +#endif /* Py_PYTHON_H */ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.cpython-312-darwin.so b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.cpython-312-darwin.so new file mode 100755 index 0000000..7bcca93 Binary files /dev/null and b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.cpython-312-darwin.so differ diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.py new file mode 100644 index 0000000..150c03f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/cu2qu.py @@ -0,0 +1,563 @@ +# cython: language_level=3 +# distutils: define_macros=CYTHON_TRACE_NOGIL=1 + +# Copyright 2015 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import cython +except (AttributeError, ImportError): + # if cython not installed, use mock module with no-op decorators and types + from fontTools.misc import cython +COMPILED = cython.compiled + +import math + +from .errors import Error as Cu2QuError, ApproxNotFoundError + + +__all__ = ["curve_to_quadratic", "curves_to_quadratic"] + +MAX_N = 100 + +NAN = float("NaN") + + +@cython.cfunc +@cython.inline +@cython.returns(cython.double) +@cython.locals(v1=cython.complex, v2=cython.complex, result=cython.double) +def dot(v1, v2): + """Return the dot product of two vectors. + + Args: + v1 (complex): First vector. + v2 (complex): Second vector. + + Returns: + double: Dot product. + """ + result = (v1 * v2.conjugate()).real + # When vectors are perpendicular (i.e. dot product is 0), the above expression may + # yield slightly different results when running in pure Python vs C/Cython, + # both of which are correct within IEEE-754 floating-point precision. + # It's probably due to the different order of operations and roundings in each + # implementation. Because we are using the result in a denominator and catching + # ZeroDivisionError (see `calc_intersect`), it's best to normalize the result here. + if abs(result) < 1e-15: + result = 0.0 + return result + + +@cython.cfunc +@cython.locals(z=cython.complex, den=cython.double) +@cython.locals(zr=cython.double, zi=cython.double) +def _complex_div_by_real(z, den): + """Divide complex by real using Python's method (two separate divisions). + + This ensures bit-exact compatibility with Python's complex division, + avoiding C's multiply-by-reciprocal optimization that can cause 1 ULP differences + on some platforms/compilers (e.g. clang on macOS arm64). + + https://github.com/fonttools/fonttools/issues/3928 + """ + zr = z.real + zi = z.imag + return complex(zr / den, zi / den) + + +@cython.cfunc +@cython.inline +@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +@cython.locals( + _1=cython.complex, _2=cython.complex, _3=cython.complex, _4=cython.complex +) +def calc_cubic_points(a, b, c, d): + _1 = d + _2 = _complex_div_by_real(c, 3.0) + d + _3 = _complex_div_by_real(b + c, 3.0) + _2 + _4 = a + d + c + b + return _1, _2, _3, _4 + + +@cython.cfunc +@cython.inline +@cython.locals( + p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex +) +@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +def calc_cubic_parameters(p0, p1, p2, p3): + c = (p1 - p0) * 3.0 + b = (p2 - p1) * 3.0 - c + d = p0 + a = p3 - d - c - b + return a, b, c, d + + +@cython.cfunc +@cython.inline +@cython.locals( + p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex +) +def split_cubic_into_n_iter(p0, p1, p2, p3, n): + """Split a cubic Bezier into n equal parts. + + Splits the curve into `n` equal parts by curve time. + (t=0..1/n, t=1/n..2/n, ...) + + Args: + p0 (complex): Start point of curve. + p1 (complex): First handle of curve. + p2 (complex): Second handle of curve. + p3 (complex): End point of curve. + + Returns: + An iterator yielding the control points (four complex values) of the + subcurves. + """ + # Hand-coded special-cases + if n == 2: + return iter(split_cubic_into_two(p0, p1, p2, p3)) + if n == 3: + return iter(split_cubic_into_three(p0, p1, p2, p3)) + if n == 4: + a, b = split_cubic_into_two(p0, p1, p2, p3) + return iter( + split_cubic_into_two(a[0], a[1], a[2], a[3]) + + split_cubic_into_two(b[0], b[1], b[2], b[3]) + ) + if n == 6: + a, b = split_cubic_into_two(p0, p1, p2, p3) + return iter( + split_cubic_into_three(a[0], a[1], a[2], a[3]) + + split_cubic_into_three(b[0], b[1], b[2], b[3]) + ) + + return _split_cubic_into_n_gen(p0, p1, p2, p3, n) + + +@cython.locals( + p0=cython.complex, + p1=cython.complex, + p2=cython.complex, + p3=cython.complex, + n=cython.int, +) +@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +@cython.locals( + dt=cython.double, delta_2=cython.double, delta_3=cython.double, i=cython.int +) +@cython.locals( + a1=cython.complex, b1=cython.complex, c1=cython.complex, d1=cython.complex +) +def _split_cubic_into_n_gen(p0, p1, p2, p3, n): + a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3) + dt = 1 / n + delta_2 = dt * dt + delta_3 = dt * delta_2 + for i in range(n): + t1 = i * dt + t1_2 = t1 * t1 + # calc new a, b, c and d + a1 = a * delta_3 + b1 = (3 * a * t1 + b) * delta_2 + c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt + d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d + yield calc_cubic_points(a1, b1, c1, d1) + + +@cython.cfunc +@cython.inline +@cython.locals( + p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex +) +@cython.locals(mid=cython.complex, deriv3=cython.complex) +def split_cubic_into_two(p0, p1, p2, p3): + """Split a cubic Bezier into two equal parts. + + Splits the curve into two equal parts at t = 0.5 + + Args: + p0 (complex): Start point of curve. + p1 (complex): First handle of curve. + p2 (complex): Second handle of curve. + p3 (complex): End point of curve. + + Returns: + tuple: Two cubic Beziers (each expressed as a tuple of four complex + values). + """ + mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + deriv3 = (p3 + p2 - p1 - p0) * 0.125 + return ( + (p0, (p0 + p1) * 0.5, mid - deriv3, mid), + (mid, mid + deriv3, (p2 + p3) * 0.5, p3), + ) + + +@cython.cfunc +@cython.inline +@cython.locals( + p0=cython.complex, + p1=cython.complex, + p2=cython.complex, + p3=cython.complex, +) +@cython.locals( + mid1=cython.complex, + deriv1=cython.complex, + mid2=cython.complex, + deriv2=cython.complex, +) +def split_cubic_into_three(p0, p1, p2, p3): + """Split a cubic Bezier into three equal parts. + + Splits the curve into three equal parts at t = 1/3 and t = 2/3 + + Args: + p0 (complex): Start point of curve. + p1 (complex): First handle of curve. + p2 (complex): Second handle of curve. + p3 (complex): End point of curve. + + Returns: + tuple: Three cubic Beziers (each expressed as a tuple of four complex + values). + """ + mid1 = (8 * p0 + 12 * p1 + 6 * p2 + p3) * (1 / 27) + deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27) + mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27) + deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27) + return ( + (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1), + (mid1, mid1 + deriv1, mid2 - deriv2, mid2), + (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3), + ) + + +@cython.cfunc +@cython.inline +@cython.returns(cython.complex) +@cython.locals( + t=cython.double, + p0=cython.complex, + p1=cython.complex, + p2=cython.complex, + p3=cython.complex, +) +@cython.locals(_p1=cython.complex, _p2=cython.complex) +def cubic_approx_control(t, p0, p1, p2, p3): + """Approximate a cubic Bezier using a quadratic one. + + Args: + t (double): Position of control point. + p0 (complex): Start point of curve. + p1 (complex): First handle of curve. + p2 (complex): Second handle of curve. + p3 (complex): End point of curve. + + Returns: + complex: Location of candidate control point on quadratic curve. + """ + _p1 = p0 + (p1 - p0) * 1.5 + _p2 = p3 + (p2 - p3) * 1.5 + return _p1 + (_p2 - _p1) * t + + +@cython.cfunc +@cython.inline +@cython.returns(cython.complex) +@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex) +@cython.locals(ab=cython.complex, cd=cython.complex, p=cython.complex, h=cython.double) +def calc_intersect(a, b, c, d): + """Calculate the intersection of two lines. + + Args: + a (complex): Start point of first line. + b (complex): End point of first line. + c (complex): Start point of second line. + d (complex): End point of second line. + + Returns: + complex: Location of intersection if one present, ``complex(NaN,NaN)`` + if no intersection was found. + """ + ab = b - a + cd = d - c + p = ab * 1j + try: + h = dot(p, a - c) / dot(p, cd) + except ZeroDivisionError: + # if 3 or 4 points are equal, we do have an intersection despite the zero-div: + # return one of the off-curves so that the algorithm can attempt a one-curve + # solution if it's within tolerance: + # https://github.com/linebender/kurbo/pull/484 + if b == c and (a == b or c == d): + return b + return complex(NAN, NAN) + return c + cd * h + + +@cython.cfunc +@cython.returns(cython.int) +@cython.locals( + tolerance=cython.double, + p0=cython.complex, + p1=cython.complex, + p2=cython.complex, + p3=cython.complex, +) +@cython.locals(mid=cython.complex, deriv3=cython.complex) +def cubic_farthest_fit_inside(p0, p1, p2, p3, tolerance): + """Check if a cubic Bezier lies within a given distance of the origin. + + "Origin" means *the* origin (0,0), not the start of the curve. Note that no + checks are made on the start and end positions of the curve; this function + only checks the inside of the curve. + + Args: + p0 (complex): Start point of curve. + p1 (complex): First handle of curve. + p2 (complex): Second handle of curve. + p3 (complex): End point of curve. + tolerance (double): Distance from origin. + + Returns: + bool: True if the cubic Bezier ``p`` entirely lies within a distance + ``tolerance`` of the origin, False otherwise. + """ + # First check p2 then p1, as p2 has higher error early on. + if abs(p2) <= tolerance and abs(p1) <= tolerance: + return True + + # Split. + mid = (p0 + 3 * (p1 + p2) + p3) * 0.125 + if abs(mid) > tolerance: + return False + deriv3 = (p3 + p2 - p1 - p0) * 0.125 + return cubic_farthest_fit_inside( + p0, (p0 + p1) * 0.5, mid - deriv3, mid, tolerance + ) and cubic_farthest_fit_inside(mid, mid + deriv3, (p2 + p3) * 0.5, p3, tolerance) + + +@cython.cfunc +@cython.inline +@cython.locals(tolerance=cython.double) +@cython.locals( + q1=cython.complex, + c0=cython.complex, + c1=cython.complex, + c2=cython.complex, + c3=cython.complex, +) +def cubic_approx_quadratic(cubic, tolerance): + """Approximate a cubic Bezier with a single quadratic within a given tolerance. + + Args: + cubic (sequence): Four complex numbers representing control points of + the cubic Bezier curve. + tolerance (double): Permitted deviation from the original curve. + + Returns: + Three complex numbers representing control points of the quadratic + curve if it fits within the given tolerance, or ``None`` if no suitable + curve could be calculated. + """ + + q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3]) + if math.isnan(q1.imag): + return None + c0 = cubic[0] + c3 = cubic[3] + c1 = c0 + (q1 - c0) * (2 / 3) + c2 = c3 + (q1 - c3) * (2 / 3) + if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance): + return None + return c0, q1, c3 + + +@cython.cfunc +@cython.locals(n=cython.int, tolerance=cython.double) +@cython.locals(i=cython.int) +@cython.locals(all_quadratic=cython.int) +@cython.locals( + c0=cython.complex, c1=cython.complex, c2=cython.complex, c3=cython.complex +) +@cython.locals( + q0=cython.complex, + q1=cython.complex, + next_q1=cython.complex, + q2=cython.complex, + d1=cython.complex, +) +def cubic_approx_spline(cubic, n, tolerance, all_quadratic): + """Approximate a cubic Bezier curve with a spline of n quadratics. + + Args: + cubic (sequence): Four complex numbers representing control points of + the cubic Bezier curve. + n (int): Number of quadratic Bezier curves in the spline. + tolerance (double): Permitted deviation from the original curve. + + Returns: + A list of ``n+2`` complex numbers, representing control points of the + quadratic spline if it fits within the given tolerance, or ``None`` if + no suitable spline could be calculated. + """ + + if n == 1: + return cubic_approx_quadratic(cubic, tolerance) + if n == 2 and all_quadratic == False: + return cubic + + cubics = split_cubic_into_n_iter(cubic[0], cubic[1], cubic[2], cubic[3], n) + + # calculate the spline of quadratics and check errors at the same time. + next_cubic = next(cubics) + next_q1 = cubic_approx_control( + 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + ) + q2 = cubic[0] + d1 = 0j + spline = [cubic[0], next_q1] + for i in range(1, n + 1): + # Current cubic to convert + c0, c1, c2, c3 = next_cubic + + # Current quadratic approximation of current cubic + q0 = q2 + q1 = next_q1 + if i < n: + next_cubic = next(cubics) + next_q1 = cubic_approx_control( + i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3] + ) + spline.append(next_q1) + q2 = (q1 + next_q1) * 0.5 + else: + q2 = c3 + + # End-point deltas + d0 = d1 + d1 = q2 - c3 + + if abs(d1) > tolerance or not cubic_farthest_fit_inside( + d0, + q0 + (q1 - q0) * (2 / 3) - c1, + q2 + (q1 - q2) * (2 / 3) - c2, + d1, + tolerance, + ): + return None + spline.append(cubic[3]) + + return spline + + +@cython.locals(max_err=cython.double) +@cython.locals(n=cython.int) +@cython.locals(all_quadratic=cython.int) +def curve_to_quadratic(curve, max_err, all_quadratic=True): + """Approximate a cubic Bezier curve with a spline of n quadratics. + + Args: + cubic (sequence): Four 2D tuples representing control points of + the cubic Bezier curve. + max_err (double): Permitted deviation from the original curve. + all_quadratic (bool): If True (default) returned value is a + quadratic spline. If False, it's either a single quadratic + curve or a single cubic curve. + + Returns: + If all_quadratic is True: A list of 2D tuples, representing + control points of the quadratic spline if it fits within the + given tolerance, or ``None`` if no suitable spline could be + calculated. + + If all_quadratic is False: Either a quadratic curve (if length + of output is 3), or a cubic curve (if length of output is 4). + """ + + curve = [complex(*p) for p in curve] + + for n in range(1, MAX_N + 1): + spline = cubic_approx_spline(curve, n, max_err, all_quadratic) + if spline is not None: + # done. go home + return [(s.real, s.imag) for s in spline] + + raise ApproxNotFoundError(curve) + + +@cython.locals(l=cython.int, last_i=cython.int, i=cython.int) +@cython.locals(all_quadratic=cython.int) +def curves_to_quadratic(curves, max_errors, all_quadratic=True): + """Return quadratic Bezier splines approximating the input cubic Beziers. + + Args: + curves: A sequence of *n* curves, each curve being a sequence of four + 2D tuples. + max_errors: A sequence of *n* floats representing the maximum permissible + deviation from each of the cubic Bezier curves. + all_quadratic (bool): If True (default) returned values are a + quadratic spline. If False, they are either a single quadratic + curve or a single cubic curve. + + Example:: + + >>> curves_to_quadratic( [ + ... [ (50,50), (100,100), (150,100), (200,50) ], + ... [ (75,50), (120,100), (150,75), (200,60) ] + ... ], [1,1] ) + [[(50.0, 50.0), (75.0, 75.0), (125.0, 91.66666666666666), (175.0, 75.0), (200.0, 50.0)], [(75.0, 50.0), (97.5, 75.0), (135.41666666666666, 82.08333333333333), (175.0, 67.5), (200.0, 60.0)]] + + The returned splines have "implied oncurve points" suitable for use in + TrueType ``glif`` outlines - i.e. in the first spline returned above, + the first quadratic segment runs from (50,50) to + ( (75 + 125)/2 , (120 + 91.666..)/2 ) = (100, 83.333...). + + Returns: + If all_quadratic is True, a list of splines, each spline being a list + of 2D tuples. + + If all_quadratic is False, a list of curves, each curve being a quadratic + (length 3), or cubic (length 4). + + Raises: + fontTools.cu2qu.Errors.ApproxNotFoundError: if no suitable approximation + can be found for all curves with the given parameters. + """ + + curves = [[complex(*p) for p in curve] for curve in curves] + assert len(max_errors) == len(curves) + + l = len(curves) + splines = [None] * l + last_i = i = 0 + n = 1 + while True: + spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic) + if spline is None: + if n == MAX_N: + break + n += 1 + last_i = i + continue + splines[i] = spline + i = (i + 1) % l + if i == last_i: + # done. go home + return [[(s.real, s.imag) for s in spline] for spline in splines] + + raise ApproxNotFoundError(curves) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/errors.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/errors.py new file mode 100644 index 0000000..fa3dc42 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/errors.py @@ -0,0 +1,77 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class Error(Exception): + """Base Cu2Qu exception class for all other errors.""" + + +class ApproxNotFoundError(Error): + def __init__(self, curve): + message = "no approximation found: %s" % curve + super().__init__(message) + self.curve = curve + + +class UnequalZipLengthsError(Error): + pass + + +class IncompatibleGlyphsError(Error): + def __init__(self, glyphs): + assert len(glyphs) > 1 + self.glyphs = glyphs + names = set(repr(g.name) for g in glyphs) + if len(names) > 1: + self.combined_name = "{%s}" % ", ".join(sorted(names)) + else: + self.combined_name = names.pop() + + def __repr__(self): + return "<%s %s>" % (type(self).__name__, self.combined_name) + + +class IncompatibleSegmentNumberError(IncompatibleGlyphsError): + def __str__(self): + return "Glyphs named %s have different number of segments" % ( + self.combined_name + ) + + +class IncompatibleSegmentTypesError(IncompatibleGlyphsError): + def __init__(self, glyphs, segments): + IncompatibleGlyphsError.__init__(self, glyphs) + self.segments = segments + + def __str__(self): + lines = [] + ndigits = len(str(max(self.segments))) + for i, tags in sorted(self.segments.items()): + lines.append( + "%s: (%s)" % (str(i).rjust(ndigits), ", ".join(repr(t) for t in tags)) + ) + return "Glyphs named %s have incompatible segment types:\n %s" % ( + self.combined_name, + "\n ".join(lines), + ) + + +class IncompatibleFontsError(Error): + def __init__(self, glyph_errors): + self.glyph_errors = glyph_errors + + def __str__(self): + return "fonts contains incompatible glyphs: %s" % ( + ", ".join(repr(g) for g in sorted(self.glyph_errors.keys())) + ) diff --git a/.venv/lib/python3.12/site-packages/fontTools/cu2qu/ufo.py b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/ufo.py new file mode 100644 index 0000000..db9a1b0 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/cu2qu/ufo.py @@ -0,0 +1,363 @@ +# Copyright 2015 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""Converts cubic bezier curves to quadratic splines. + +Conversion is performed such that the quadratic splines keep the same end-curve +tangents as the original cubics. The approach is iterative, increasing the +number of segments for a spline until the error gets below a bound. + +Respective curves from multiple fonts will be converted at once to ensure that +the resulting splines are interpolation-compatible. +""" + +import logging +from fontTools.pens.basePen import AbstractPen +from fontTools.pens.pointPen import PointToSegmentPen +from fontTools.pens.reverseContourPen import ReverseContourPen + +from . import curves_to_quadratic +from .errors import ( + UnequalZipLengthsError, + IncompatibleSegmentNumberError, + IncompatibleSegmentTypesError, + IncompatibleGlyphsError, + IncompatibleFontsError, +) + + +__all__ = ["fonts_to_quadratic", "font_to_quadratic"] + +# The default approximation error below is a relative value (1/1000 of the EM square). +# Later on, we convert it to absolute font units by multiplying it by a font's UPEM +# (see fonts_to_quadratic). +DEFAULT_MAX_ERR = 0.001 +CURVE_TYPE_LIB_KEY = "com.github.googlei18n.cu2qu.curve_type" + +logger = logging.getLogger(__name__) + + +_zip = zip + + +def zip(*args): + """Ensure each argument to zip has the same length. Also make sure a list is + returned for python 2/3 compatibility. + """ + + if len(set(len(a) for a in args)) != 1: + raise UnequalZipLengthsError(*args) + return list(_zip(*args)) + + +class GetSegmentsPen(AbstractPen): + """Pen to collect segments into lists of points for conversion. + + Curves always include their initial on-curve point, so some points are + duplicated between segments. + """ + + def __init__(self): + self._last_pt = None + self.segments = [] + + def _add_segment(self, tag, *args): + if tag in ["move", "line", "qcurve", "curve"]: + self._last_pt = args[-1] + self.segments.append((tag, args)) + + def moveTo(self, pt): + self._add_segment("move", pt) + + def lineTo(self, pt): + self._add_segment("line", pt) + + def qCurveTo(self, *points): + self._add_segment("qcurve", self._last_pt, *points) + + def curveTo(self, *points): + self._add_segment("curve", self._last_pt, *points) + + def closePath(self): + self._add_segment("close") + + def endPath(self): + self._add_segment("end") + + def addComponent(self, glyphName, transformation): + pass + + +def _get_segments(glyph): + """Get a glyph's segments as extracted by GetSegmentsPen.""" + + pen = GetSegmentsPen() + # glyph.draw(pen) + # We can't simply draw the glyph with the pen, but we must initialize the + # PointToSegmentPen explicitly with outputImpliedClosingLine=True. + # By default PointToSegmentPen does not outputImpliedClosingLine -- unless + # last and first point on closed contour are duplicated. Because we are + # converting multiple glyphs at the same time, we want to make sure + # this function returns the same number of segments, whether or not + # the last and first point overlap. + # https://github.com/googlefonts/fontmake/issues/572 + # https://github.com/fonttools/fonttools/pull/1720 + pointPen = PointToSegmentPen(pen, outputImpliedClosingLine=True) + glyph.drawPoints(pointPen) + return pen.segments + + +def _set_segments(glyph, segments, reverse_direction): + """Draw segments as extracted by GetSegmentsPen back to a glyph.""" + + glyph.clearContours() + pen = glyph.getPen() + if reverse_direction: + pen = ReverseContourPen(pen) + for tag, args in segments: + if tag == "move": + pen.moveTo(*args) + elif tag == "line": + pen.lineTo(*args) + elif tag == "curve": + pen.curveTo(*args[1:]) + elif tag == "qcurve": + pen.qCurveTo(*args[1:]) + elif tag == "close": + pen.closePath() + elif tag == "end": + pen.endPath() + else: + raise AssertionError('Unhandled segment type "%s"' % tag) + + +def _segments_to_quadratic(segments, max_err, stats, all_quadratic=True): + """Return quadratic approximations of cubic segments.""" + + assert all(s[0] == "curve" for s in segments), "Non-cubic given to convert" + + new_points = curves_to_quadratic([s[1] for s in segments], max_err, all_quadratic) + n = len(new_points[0]) + assert all(len(s) == n for s in new_points[1:]), "Converted incompatibly" + + spline_length = str(n - 2) + stats[spline_length] = stats.get(spline_length, 0) + 1 + + if all_quadratic or n == 3: + return [("qcurve", p) for p in new_points] + else: + return [("curve", p) for p in new_points] + + +def _glyphs_to_quadratic(glyphs, max_err, reverse_direction, stats, all_quadratic=True): + """Do the actual conversion of a set of compatible glyphs, after arguments + have been set up. + + Empty glyphs (without contours) are ignored and passed through unchanged. + + Return True if the glyphs were modified, else return False. + """ + + # Skip empty glyphs (with zero contours) + non_empty_indices = [i for i, g in enumerate(glyphs) if len(g) > 0] + if not non_empty_indices: + return False + + glyphs = [glyphs[i] for i in non_empty_indices] + max_err = [max_err[i] for i in non_empty_indices] + + try: + segments_by_location = zip(*[_get_segments(g) for g in glyphs]) + except UnequalZipLengthsError: + raise IncompatibleSegmentNumberError(glyphs) + if not any(segments_by_location): + return False + + # always modify input glyphs if reverse_direction is True + glyphs_modified = reverse_direction + + new_segments_by_location = [] + incompatible = {} + for i, segments in enumerate(segments_by_location): + tag = segments[0][0] + if not all(s[0] == tag for s in segments[1:]): + incompatible[i] = [s[0] for s in segments] + elif tag == "curve": + new_segments = _segments_to_quadratic( + segments, max_err, stats, all_quadratic + ) + if all_quadratic or new_segments != segments: + glyphs_modified = True + segments = new_segments + new_segments_by_location.append(segments) + + if glyphs_modified: + new_segments_by_glyph = zip(*new_segments_by_location) + for glyph, new_segments in zip(glyphs, new_segments_by_glyph): + _set_segments(glyph, new_segments, reverse_direction) + + if incompatible: + raise IncompatibleSegmentTypesError(glyphs, segments=incompatible) + return glyphs_modified + + +def glyphs_to_quadratic( + glyphs, max_err=None, reverse_direction=False, stats=None, all_quadratic=True +): + """Convert the curves of a set of compatible of glyphs to quadratic. + + All curves will be converted to quadratic at once, ensuring interpolation + compatibility. If this is not required, calling glyphs_to_quadratic with one + glyph at a time may yield slightly more optimized results. + + Empty glyphs (without contours) are ignored and passed through unchanged. + + Return True if glyphs were modified, else return False. + + Raises IncompatibleGlyphsError if glyphs have non-interpolatable outlines. + """ + if stats is None: + stats = {} + + if not max_err: + # assume 1000 is the default UPEM + max_err = DEFAULT_MAX_ERR * 1000 + + if isinstance(max_err, (list, tuple)): + max_errors = max_err + else: + max_errors = [max_err] * len(glyphs) + assert len(max_errors) == len(glyphs) + + return _glyphs_to_quadratic( + glyphs, max_errors, reverse_direction, stats, all_quadratic + ) + + +def fonts_to_quadratic( + fonts, + max_err_em=None, + max_err=None, + reverse_direction=False, + stats=None, + dump_stats=False, + remember_curve_type=True, + all_quadratic=True, +): + """Convert the curves of a collection of fonts to quadratic. + + All curves will be converted to quadratic at once, ensuring interpolation + compatibility. If this is not required, calling fonts_to_quadratic with one + font at a time may yield slightly more optimized results. + + Empty glyphs (without contours) are ignored and passed through unchanged. + + Return the set of modified glyph names if any, else return an empty set. + + By default, cu2qu stores the curve type in the fonts' lib, under a private + key "com.github.googlei18n.cu2qu.curve_type", and will not try to convert + them again if the curve type is already set to "quadratic". + Setting 'remember_curve_type' to False disables this optimization. + + Raises IncompatibleFontsError if same-named glyphs from different fonts + have non-interpolatable outlines. + """ + + if remember_curve_type: + curve_types = {f.lib.get(CURVE_TYPE_LIB_KEY, "cubic") for f in fonts} + if len(curve_types) == 1: + curve_type = next(iter(curve_types)) + if curve_type in ("quadratic", "mixed"): + logger.info("Curves already converted to quadratic") + return False + elif curve_type == "cubic": + pass # keep converting + else: + raise NotImplementedError(curve_type) + elif len(curve_types) > 1: + # going to crash later if they do differ + logger.warning("fonts may contain different curve types") + + if stats is None: + stats = {} + + if max_err_em and max_err: + raise TypeError("Only one of max_err and max_err_em can be specified.") + if not (max_err_em or max_err): + max_err_em = DEFAULT_MAX_ERR + + if isinstance(max_err, (list, tuple)): + assert len(max_err) == len(fonts) + max_errors = max_err + elif max_err: + max_errors = [max_err] * len(fonts) + + if isinstance(max_err_em, (list, tuple)): + assert len(fonts) == len(max_err_em) + max_errors = [f.info.unitsPerEm * e for f, e in zip(fonts, max_err_em)] + elif max_err_em: + max_errors = [f.info.unitsPerEm * max_err_em for f in fonts] + + modified = set() + glyph_errors = {} + for name in set().union(*(f.keys() for f in fonts)): + glyphs = [] + cur_max_errors = [] + for font, error in zip(fonts, max_errors): + if name in font: + glyphs.append(font[name]) + cur_max_errors.append(error) + try: + if _glyphs_to_quadratic( + glyphs, cur_max_errors, reverse_direction, stats, all_quadratic + ): + modified.add(name) + except IncompatibleGlyphsError as exc: + logger.error(exc) + glyph_errors[name] = exc + + if glyph_errors: + raise IncompatibleFontsError(glyph_errors) + + if modified and dump_stats: + spline_lengths = sorted(stats.keys()) + logger.info( + "New spline lengths: %s" + % (", ".join("%s: %d" % (l, stats[l]) for l in spline_lengths)) + ) + + if remember_curve_type: + for font in fonts: + curve_type = font.lib.get(CURVE_TYPE_LIB_KEY, "cubic") + new_curve_type = "quadratic" if all_quadratic else "mixed" + if curve_type != new_curve_type: + font.lib[CURVE_TYPE_LIB_KEY] = new_curve_type + return modified + + +def glyph_to_quadratic(glyph, **kwargs): + """Convenience wrapper around glyphs_to_quadratic, for just one glyph. + Return True if the glyph was modified, else return False. + """ + + return glyphs_to_quadratic([glyph], **kwargs) + + +def font_to_quadratic(font, **kwargs): + """Convenience wrapper around fonts_to_quadratic, for just one font. + Return the set of modified glyph names if any, else return empty set. + """ + + return fonts_to_quadratic([font], **kwargs) diff --git a/.venv/lib/python3.12/site-packages/fontTools/designspaceLib/__init__.py b/.venv/lib/python3.12/site-packages/fontTools/designspaceLib/__init__.py new file mode 100644 index 0000000..4782041 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/fontTools/designspaceLib/__init__.py @@ -0,0 +1,3343 @@ +""" + designSpaceDocument + + - Read and write designspace files +""" + +from __future__ import annotations + +import collections +import copy +import itertools +import math +import os +import posixpath +from io import BytesIO, StringIO +from textwrap import indent +from typing import Any, Dict, List, MutableMapping, Optional, Tuple, Union, cast + +from fontTools.misc import etree as ET +from fontTools.misc import plistlib +from fontTools.misc.loggingTools import LogMixin +from fontTools.misc.textTools import tobytes, tostr + + +__all__ = [ + "AxisDescriptor", + "AxisLabelDescriptor", + "AxisMappingDescriptor", + "BaseDocReader", + "BaseDocWriter", + "DesignSpaceDocument", + "DesignSpaceDocumentError", + "DiscreteAxisDescriptor", + "InstanceDescriptor", + "LocationLabelDescriptor", + "RangeAxisSubsetDescriptor", + "RuleDescriptor", + "SourceDescriptor", + "ValueAxisSubsetDescriptor", + "VariableFontDescriptor", +] + +# ElementTree allows to find namespace-prefixed elements, but not attributes +# so we have to do it ourselves for 'xml:lang' +XML_NS = "{http://www.w3.org/XML/1998/namespace}" +XML_LANG = XML_NS + "lang" + + +def posix(path): + """Normalize paths using forward slash to work also on Windows.""" + new_path = posixpath.join(*path.split(os.path.sep)) + if path.startswith("/"): + # The above transformation loses absolute paths + new_path = "/" + new_path + elif path.startswith(r"\\"): + # The above transformation loses leading slashes of UNC path mounts + new_path = "//" + new_path + return new_path + + +def posixpath_property(private_name): + """Generate a propery that holds a path always using forward slashes.""" + + def getter(self): + # Normal getter + return getattr(self, private_name) + + def setter(self, value): + # The setter rewrites paths using forward slashes + if value is not None: + value = posix(value) + setattr(self, private_name, value) + + return property(getter, setter) + + +class DesignSpaceDocumentError(Exception): + def __init__(self, msg, obj=None): + self.msg = msg + self.obj = obj + + def __str__(self): + return str(self.msg) + (": %r" % self.obj if self.obj is not None else "") + + +class AsDictMixin(object): + def asdict(self): + d = {} + for attr, value in self.__dict__.items(): + if attr.startswith("_"): + continue + if hasattr(value, "asdict"): + value = value.asdict() + elif isinstance(value, list): + value = [v.asdict() if hasattr(v, "asdict") else v for v in value] + d[attr] = value + return d + + +class SimpleDescriptor(AsDictMixin): + """Containers for a bunch of attributes""" + + # XXX this is ugly. The 'print' is inappropriate here, and instead of + # assert, it should simply return True/False + def compare(self, other): + # test if this object contains the same data as the other + for attr in self._attrs: + try: + assert getattr(self, attr) == getattr(other, attr) + except AssertionError: + print( + "failed attribute", + attr, + getattr(self, attr), + "!=", + getattr(other, attr), + ) + + def __repr__(self): + attrs = [f"{a}={repr(getattr(self, a))}," for a in self._attrs] + attrs = indent("\n".join(attrs), " ") + return f"{self.__class__.__name__}(\n{attrs}\n)" + + +class SourceDescriptor(SimpleDescriptor): + """Simple container for data related to the source + + .. code:: python + + doc = DesignSpaceDocument() + s1 = SourceDescriptor() + s1.path = masterPath1 + s1.name = "master.ufo1" + s1.font = defcon.Font("master.ufo1") + s1.location = dict(weight=0) + s1.familyName = "MasterFamilyName" + s1.styleName = "MasterStyleNameOne" + s1.localisedFamilyName = dict(fr="Caractère") + s1.mutedGlyphNames.append("A") + s1.mutedGlyphNames.append("Z") + doc.addSource(s1) + + """ + + flavor = "source" + _attrs = [ + "filename", + "path", + "name", + "layerName", + "location", + "copyLib", + "copyGroups", + "copyFeatures", + "muteKerning", + "muteInfo", + "mutedGlyphNames", + "familyName", + "styleName", + "localisedFamilyName", + ] + + filename = posixpath_property("_filename") + path = posixpath_property("_path") + + def __init__( + self, + *, + filename=None, + path=None, + font=None, + name=None, + location=None, + designLocation=None, + layerName=None, + familyName=None, + styleName=None, + localisedFamilyName=None, + copyLib=False, + copyInfo=False, + copyGroups=False, + copyFeatures=False, + muteKerning=False, + muteInfo=False, + mutedGlyphNames=None, + ): + self.filename = filename + """string. A relative path to the source file, **as it is in the document**. + + MutatorMath + VarLib. + """ + self.path = path + """The absolute path, calculated from filename.""" + + self.font = font + """Any Python object. Optional. Points to a representation of this + source font that is loaded in memory, as a Python object (e.g. a + ``defcon.Font`` or a ``fontTools.ttFont.TTFont``). + + The default document reader will not fill-in this attribute, and the + default writer will not use this attribute. It is up to the user of + ``designspaceLib`` to either load the resource identified by + ``filename`` and store it in this field, or write the contents of + this field to the disk and make ```filename`` point to that. + """ + + self.name = name + """string. Optional. Unique identifier name for this source. + + MutatorMath + varLib. + """ + + self.designLocation = ( + designLocation if designLocation is not None else location or {} + ) + """dict. Axis values for this source, in design space coordinates. + + MutatorMath + varLib. + + This may be only part of the full design location. + See :meth:`getFullDesignLocation()` + + .. versionadded:: 5.0 + """ + + self.layerName = layerName + """string. The name of the layer in the source to look for + outline data. Default ``None`` which means ``foreground``. + """ + self.familyName = familyName + """string. Family name of this source. Though this data + can be extracted from the font, it can be efficient to have it right + here. + + varLib. + """ + self.styleName = styleName + """string. Style name of this source. Though this data + can be extracted from the font, it can be efficient to have it right + here. + + varLib. + """ + self.localisedFamilyName = localisedFamilyName or {} + """dict. A dictionary of localised family name strings, keyed by + language code. + + If present, will be used to build localized names for all instances. + + .. versionadded:: 5.0 + """ + + self.copyLib = copyLib + """bool. Indicates if the contents of the font.lib need to + be copied to the instances. + + MutatorMath. + + .. deprecated:: 5.0 + """ + self.copyInfo = copyInfo + """bool. Indicates if the non-interpolating font.info needs + to be copied to the instances. + + MutatorMath. + + .. deprecated:: 5.0 + """ + self.copyGroups = copyGroups + """bool. Indicates if the groups need to be copied to the + instances. + + MutatorMath. + + .. deprecated:: 5.0 + """ + self.copyFeatures = copyFeatures + """bool. Indicates if the feature text needs to be + copied to the instances. + + MutatorMath. + + .. deprecated:: 5.0 + """ + self.muteKerning = muteKerning + """bool. Indicates if the kerning data from this source + needs to be muted (i.e. not be part of the calculations). + + MutatorMath only. + """ + self.muteInfo = muteInfo + """bool. Indicated if the interpolating font.info data for + this source needs to be muted. + + MutatorMath only. + """ + self.mutedGlyphNames = mutedGlyphNames or [] + """list. Glyphnames that need to be muted in the + instances. + + MutatorMath only. + """ + + @property + def location(self): + """dict. Axis values for this source, in design space coordinates. + + MutatorMath + varLib. + + .. deprecated:: 5.0 + Use the more explicit alias for this property :attr:`designLocation`. + """ + return self.designLocation + + @location.setter + def location(self, location: Optional[SimpleLocationDict]): + self.designLocation = location or {} + + def setFamilyName(self, familyName, languageCode="en"): + """Setter for :attr:`localisedFamilyName` + + .. versionadded:: 5.0 + """ + self.localisedFamilyName[languageCode] = tostr(familyName) + + def getFamilyName(self, languageCode="en"): + """Getter for :attr:`localisedFamilyName` + + .. versionadded:: 5.0 + """ + return self.localisedFamilyName.get(languageCode) + + def getFullDesignLocation(self, doc: "DesignSpaceDocument") -> SimpleLocationDict: + """Get the complete design location of this source, from its + :attr:`designLocation` and the document's axis defaults. + + .. versionadded:: 5.0 + """ + result: SimpleLocationDict = {} + for axis in doc.axes: + if axis.name in self.designLocation: + result[axis.name] = self.designLocation[axis.name] + else: + result[axis.name] = axis.map_forward(axis.default) + return result + + +class RuleDescriptor(SimpleDescriptor): + """Represents the rule descriptor element: a set of glyph substitutions to + trigger conditionally in some parts of the designspace. + + .. code:: python + + r1 = RuleDescriptor() + r1.name = "unique.rule.name" + r1.conditionSets.append([dict(name="weight", minimum=-10, maximum=10), dict(...)]) + r1.conditionSets.append([dict(...), dict(...)]) + r1.subs.append(("a", "a.alt")) + + .. code:: xml + + + + + + + + + + + + + + """ + + _attrs = ["name", "conditionSets", "subs"] # what do we need here + + def __init__(self, *, name=None, conditionSets=None, subs=None): + self.name = name + """string. Unique name for this rule. Can be used to reference this rule data.""" + # list of lists of dict(name='aaaa', minimum=0, maximum=1000) + self.conditionSets = conditionSets or [] + """a list of conditionsets. + + - Each conditionset is a list of conditions. + - Each condition is a dict with ``name``, ``minimum`` and ``maximum`` keys. + """ + # list of substitutions stored as tuples of glyphnames ("a", "a.alt") + self.subs = subs or [] + """list of substitutions. + + - Each substitution is stored as tuples of glyphnames, e.g. ("a", "a.alt"). + - Note: By default, rules are applied first, before other text + shaping/OpenType layout, as they are part of the + `Required Variation Alternates OpenType feature `_. + See ref:`rules-element` § Attributes. + """ + + +def evaluateRule(rule, location): + """Return True if any of the rule's conditionsets matches the given location.""" + return any(evaluateConditions(c, location) for c in rule.conditionSets) + + +def evaluateConditions(conditions, location): + """Return True if all the conditions matches the given location. + + - If a condition has no minimum, check for < maximum. + - If a condition has no maximum, check for > minimum. + """ + for cd in conditions: + value = location[cd["name"]] + if cd.get("minimum") is None: + if value > cd["maximum"]: + return False + elif cd.get("maximum") is None: + if cd["minimum"] > value: + return False + elif not cd["minimum"] <= value <= cd["maximum"]: + return False + return True + + +def processRules(rules, location, glyphNames): + """Apply these rules at this location to these glyphnames. + + Return a new list of glyphNames with substitutions applied. + + - rule order matters + """ + newNames = [] + for rule in rules: + if evaluateRule(rule, location): + for name in glyphNames: + swap = False + for a, b in rule.subs: + if name == a: + swap = True + break + if swap: + newNames.append(b) + else: + newNames.append(name) + glyphNames = newNames + newNames = [] + return glyphNames + + +AnisotropicLocationDict = Dict[str, Union[float, Tuple[float, float]]] +SimpleLocationDict = Dict[str, float] + + +class AxisMappingDescriptor(SimpleDescriptor): + """Represents the axis mapping element: mapping an input location + to an output location in the designspace. + + .. code:: python + + m1 = AxisMappingDescriptor() + m1.inputLocation = {"weight": 900, "width": 150} + m1.outputLocation = {"weight": 870} + + .. code:: xml + + + + + + + + + + + + + """ + + _attrs = ["inputLocation", "outputLocation"] + + def __init__( + self, + *, + inputLocation=None, + outputLocation=None, + description=None, + groupDescription=None, + ): + self.inputLocation: SimpleLocationDict = inputLocation or {} + """dict. Axis values for the input of the mapping, in design space coordinates. + + varLib. + + .. versionadded:: 5.1 + """ + self.outputLocation: SimpleLocationDict = outputLocation or {} + """dict. Axis values for the output of the mapping, in design space coordinates. + + varLib. + + .. versionadded:: 5.1 + """ + self.description = description + """string. A description of the mapping. + + varLib. + + .. versionadded:: 5.2 + """ + self.groupDescription = groupDescription + """string. A description of the group of mappings. + + varLib. + + .. versionadded:: 5.2 + """ + + +class InstanceDescriptor(SimpleDescriptor): + """Simple container for data related to the instance + + + .. code:: python + + i2 = InstanceDescriptor() + i2.path = instancePath2 + i2.familyName = "InstanceFamilyName" + i2.styleName = "InstanceStyleName" + i2.name = "instance.ufo2" + # anisotropic location + i2.designLocation = dict(weight=500, width=(400,300)) + i2.postScriptFontName = "InstancePostscriptName" + i2.styleMapFamilyName = "InstanceStyleMapFamilyName" + i2.styleMapStyleName = "InstanceStyleMapStyleName" + i2.lib['com.coolDesignspaceApp.specimenText'] = 'Hamburgerwhatever' + doc.addInstance(i2) + """ + + flavor = "instance" + _defaultLanguageCode = "en" + _attrs = [ + "filename", + "path", + "name", + "locationLabel", + "designLocation", + "userLocation", + "familyName", + "styleName", + "postScriptFontName", + "styleMapFamilyName", + "styleMapStyleName", + "localisedFamilyName", + "localisedStyleName", + "localisedStyleMapFamilyName", + "localisedStyleMapStyleName", + "glyphs", + "kerning", + "info", + "lib", + ] + + filename = posixpath_property("_filename") + path = posixpath_property("_path") + + def __init__( + self, + *, + filename=None, + path=None, + font=None, + name=None, + location=None, + locationLabel=None, + designLocation=None, + userLocation=None, + familyName=None, + styleName=None, + postScriptFontName=None, + styleMapFamilyName=None, + styleMapStyleName=None, + localisedFamilyName=None, + localisedStyleName=None, + localisedStyleMapFamilyName=None, + localisedStyleMapStyleName=None, + glyphs=None, + kerning=True, + info=True, + lib=None, + ): + self.filename = filename + """string. Relative path to the instance file, **as it is + in the document**. The file may or may not exist. + + MutatorMath + VarLib. + """ + self.path = path + """string. Absolute path to the instance file, calculated from + the document path and the string in the filename attr. The file may + or may not exist. + + MutatorMath. + """ + self.font = font + """Same as :attr:`SourceDescriptor.font` + + .. seealso:: :attr:`SourceDescriptor.font` + """ + self.name = name + """string. Unique identifier name of the instance, used to + identify it if it needs to be referenced from elsewhere in the + document. + """ + self.locationLabel = locationLabel + """Name of a :class:`LocationLabelDescriptor`. If + provided, the instance should have the same location as the + LocationLabel. + + .. seealso:: + :meth:`getFullDesignLocation` + :meth:`getFullUserLocation` + + .. versionadded:: 5.0 + """ + self.designLocation: AnisotropicLocationDict = ( + designLocation if designLocation is not None else (location or {}) + ) + """dict. Axis values for this instance, in design space coordinates. + + MutatorMath + varLib. + + .. seealso:: This may be only part of the full location. See: + :meth:`getFullDesignLocation` + :meth:`getFullUserLocation` + + .. versionadded:: 5.0 + """ + self.userLocation: SimpleLocationDict = userLocation or {} + """dict. Axis values for this instance, in user space coordinates. + + MutatorMath + varLib. + + .. seealso:: This may be only part of the full location. See: + :meth:`getFullDesignLocation` + :meth:`getFullUserLocation` + + .. versionadded:: 5.0 + """ + self.familyName = familyName + """string. Family name of this instance. + + MutatorMath + varLib. + """ + self.styleName = styleName + """string. Style name of this instance. + + MutatorMath + varLib. + """ + self.postScriptFontName = postScriptFontName + """string. Postscript fontname for this instance. + + MutatorMath + varLib. + """ + self.styleMapFamilyName = styleMapFamilyName + """string. StyleMap familyname for this instance. + + MutatorMath + varLib. + """ + self.styleMapStyleName = styleMapStyleName + """string. StyleMap stylename for this instance. + + MutatorMath + varLib. + """ + self.localisedFamilyName = localisedFamilyName or {} + """dict. A dictionary of localised family name + strings, keyed by language code. + """ + self.localisedStyleName = localisedStyleName or {} + """dict. A dictionary of localised stylename + strings, keyed by language code. + """ + self.localisedStyleMapFamilyName = localisedStyleMapFamilyName or {} + """A dictionary of localised style map + familyname strings, keyed by language code. + """ + self.localisedStyleMapStyleName = localisedStyleMapStyleName or {} + """A dictionary of localised style map + stylename strings, keyed by language code. + """ + self.glyphs = glyphs or {} + """dict for special master definitions for glyphs. If glyphs + need special masters (to record the results of executed rules for + example). + + MutatorMath. + + .. deprecated:: 5.0 + Use rules or sparse sources instead. + """ + self.kerning = kerning + """ bool. Indicates if this instance needs its kerning + calculated. + + MutatorMath. + + .. deprecated:: 5.0 + """ + self.info = info + """bool. Indicated if this instance needs the interpolating + font.info calculated. + + .. deprecated:: 5.0 + """ + + self.lib = lib or {} + """Custom data associated with this instance.""" + + @property + def location(self): + """dict. Axis values for this instance. + + MutatorMath + varLib. + + .. deprecated:: 5.0 + Use the more explicit alias for this property :attr:`designLocation`. + """ + return self.designLocation + + @location.setter + def location(self, location: Optional[AnisotropicLocationDict]): + self.designLocation = location or {} + + def setStyleName(self, styleName, languageCode="en"): + """These methods give easier access to the localised names.""" + self.localisedStyleName[languageCode] = tostr(styleName) + + def getStyleName(self, languageCode="en"): + return self.localisedStyleName.get(languageCode) + + def setFamilyName(self, familyName, languageCode="en"): + self.localisedFamilyName[languageCode] = tostr(familyName) + + def getFamilyName(self, languageCode="en"): + return self.localisedFamilyName.get(languageCode) + + def setStyleMapStyleName(self, styleMapStyleName, languageCode="en"): + self.localisedStyleMapStyleName[languageCode] = tostr(styleMapStyleName) + + def getStyleMapStyleName(self, languageCode="en"): + return self.localisedStyleMapStyleName.get(languageCode) + + def setStyleMapFamilyName(self, styleMapFamilyName, languageCode="en"): + self.localisedStyleMapFamilyName[languageCode] = tostr(styleMapFamilyName) + + def getStyleMapFamilyName(self, languageCode="en"): + return self.localisedStyleMapFamilyName.get(languageCode) + + def clearLocation(self, axisName: Optional[str] = None): + """Clear all location-related fields. Ensures that + :attr:``designLocation`` and :attr:``userLocation`` are dictionaries + (possibly empty if clearing everything). + + In order to update the location of this instance wholesale, a user + should first clear all the fields, then change the field(s) for which + they have data. + + .. code:: python + + instance.clearLocation() + instance.designLocation = {'Weight': (34, 36.5), 'Width': 100} + instance.userLocation = {'Opsz': 16} + + In order to update a single axis location, the user should only clear + that axis, then edit the values: + + .. code:: python + + instance.clearLocation('Weight') + instance.designLocation['Weight'] = (34, 36.5) + + Args: + axisName: if provided, only clear the location for that axis. + + .. versionadded:: 5.0 + """ + self.locationLabel = None + if axisName is None: + self.designLocation = {} + self.userLocation = {} + else: + if self.designLocation is None: + self.designLocation = {} + if axisName in self.designLocation: + del self.designLocation[axisName] + if self.userLocation is None: + self.userLocation = {} + if axisName in self.userLocation: + del self.userLocation[axisName] + + def getLocationLabelDescriptor( + self, doc: "DesignSpaceDocument" + ) -> Optional[LocationLabelDescriptor]: + """Get the :class:`LocationLabelDescriptor` instance that matches + this instances's :attr:`locationLabel`. + + Raises if the named label can't be found. + + .. versionadded:: 5.0 + """ + if self.locationLabel is None: + return None + label = doc.getLocationLabel(self.locationLabel) + if label is None: + raise DesignSpaceDocumentError( + "InstanceDescriptor.getLocationLabelDescriptor(): " + f"unknown location label `{self.locationLabel}` in instance `{self.name}`." + ) + return label + + def getFullDesignLocation( + self, doc: "DesignSpaceDocument" + ) -> AnisotropicLocationDict: + """Get the complete design location of this instance, by combining data + from the various location fields, default axis values and mappings, and + top-level location labels. + + The source of truth for this instance's location is determined for each + axis independently by taking the first not-None field in this list: + + - ``locationLabel``: the location along this axis is the same as the + matching STAT format 4 label. No anisotropy. + - ``designLocation[axisName]``: the explicit design location along this + axis, possibly anisotropic. + - ``userLocation[axisName]``: the explicit user location along this + axis. No anisotropy. + - ``axis.default``: default axis value. No anisotropy. + + .. versionadded:: 5.0 + """ + label = self.getLocationLabelDescriptor(doc) + if label is not None: + return doc.map_forward(label.userLocation) # type: ignore + result: AnisotropicLocationDict = {} + for axis in doc.axes: + if axis.name in self.designLocation: + result[axis.name] = self.designLocation[axis.name] + elif axis.name in self.userLocation: + result[axis.name] = axis.map_forward(self.userLocation[axis.name]) + else: + result[axis.name] = axis.map_forward(axis.default) + return result + + def getFullUserLocation(self, doc: "DesignSpaceDocument") -> SimpleLocationDict: + """Get the complete user location for this instance. + + .. seealso:: :meth:`getFullDesignLocation` + + .. versionadded:: 5.0 + """ + return doc.map_backward(self.getFullDesignLocation(doc)) + + +def tagForAxisName(name): + # try to find or make a tag name for this axis name + names = { + "weight": ("wght", dict(en="Weight")), + "width": ("wdth", dict(en="Width")), + "optical": ("opsz", dict(en="Optical Size")), + "slant": ("slnt", dict(en="Slant")), + "italic": ("ital", dict(en="Italic")), + } + if name.lower() in names: + return names[name.lower()] + if len(name) < 4: + tag = name + "*" * (4 - len(name)) + else: + tag = name[:4] + return tag, dict(en=name) + + +class AbstractAxisDescriptor(SimpleDescriptor): + flavor = "axis" + + def __init__( + self, + *, + tag=None, + name=None, + labelNames=None, + hidden=False, + map=None, + axisOrdering=None, + axisLabels=None, + ): + # opentype tag for this axis + self.tag = tag + """string. Four letter tag for this axis. Some might be + registered at the `OpenType + specification `__. + Privately-defined axis tags must begin with an uppercase letter and + use only uppercase letters or digits. + """ + # name of the axis used in locations + self.name = name + """string. Name of the axis as it is used in the location dicts. + + MutatorMath + varLib. + """ + # names for UI purposes, if this is not a standard axis, + self.labelNames = labelNames or {} + """dict. When defining a non-registered axis, it will be + necessary to define user-facing readable names for the axis. Keyed by + xml:lang code. Values are required to be ``unicode`` strings, even if + they only contain ASCII characters. + """ + self.hidden = hidden + """bool. Whether this axis should be hidden in user interfaces. + """ + self.map = map or [] + """list of input / output values that can describe a warp of user space + to design space coordinates. If no map values are present, it is assumed + user space is the same as design space, as in [(minimum, minimum), + (maximum, maximum)]. + + varLib. + """ + self.axisOrdering = axisOrdering + """STAT table field ``axisOrdering``. + + See: `OTSpec STAT Axis Record `_ + + .. versionadded:: 5.0 + """ + self.axisLabels: List[AxisLabelDescriptor] = axisLabels or [] + """STAT table entries for Axis Value Tables format 1, 2, 3. + + See: `OTSpec STAT Axis Value Tables `_ + + .. versionadded:: 5.0 + """ + + +class AxisDescriptor(AbstractAxisDescriptor): + """Simple container for the axis data. + + Add more localisations? + + .. code:: python + + a1 = AxisDescriptor() + a1.minimum = 1 + a1.maximum = 1000 + a1.default = 400 + a1.name = "weight" + a1.tag = "wght" + a1.labelNames['fa-IR'] = "قطر" + a1.labelNames['en'] = "Wéíght" + a1.map = [(1.0, 10.0), (400.0, 66.0), (1000.0, 990.0)] + a1.axisOrdering = 1 + a1.axisLabels = [ + AxisLabelDescriptor(name="Regular", userValue=400, elidable=True) + ] + doc.addAxis(a1) + """ + + _attrs = [ + "tag", + "name", + "maximum", + "minimum", + "default", + "map", + "axisOrdering", + "axisLabels", + ] + + def __init__( + self, + *, + tag=None, + name=None, + labelNames=None, + minimum=None, + default=None, + maximum=None, + hidden=False, + map=None, + axisOrdering=None, + axisLabels=None, + ): + super().__init__( + tag=tag, + name=name, + labelNames=labelNames, + hidden=hidden, + map=map, + axisOrdering=axisOrdering, + axisLabels=axisLabels, + ) + self.minimum = minimum + """number. The minimum value for this axis in user space. + + MutatorMath + varLib. + """ + self.maximum = maximum + """number. The maximum value for this axis in user space. + + MutatorMath + varLib. + """ + self.default = default + """number. The default value for this axis, i.e. when a new location is + created, this is the value this axis will get in user space. + + MutatorMath + varLib. + """ + + def serialize(self): + # output to a dict, used in testing + return dict( + tag=self.tag, + name=self.name, + labelNames=self.labelNames, + maximum=self.maximum, + minimum=self.minimum, + default=self.default, + hidden=self.hidden, + map=self.map, + axisOrdering=self.axisOrdering, + axisLabels=self.axisLabels, + ) + + def map_forward(self, v): + """Maps value from axis mapping's input (user) to output (design).""" + from fontTools.varLib.models import piecewiseLinearMap + + if not self.map: + return v + return piecewiseLinearMap(v, {k: v for k, v in self.map}) + + def map_backward(self, v): + """Maps value from axis mapping's output (design) to input (user).""" + from fontTools.varLib.models import piecewiseLinearMap + + if isinstance(v, tuple): + v = v[0] + if not self.map: + return v + return piecewiseLinearMap(v, {v: k for k, v in self.map}) + + +class DiscreteAxisDescriptor(AbstractAxisDescriptor): + """Container for discrete axis data. + + Use this for axes that do not interpolate. The main difference from a + continuous axis is that a continuous axis has a ``minimum`` and ``maximum``, + while a discrete axis has a list of ``values``. + + Example: an Italic axis with 2 stops, Roman and Italic, that are not + compatible. The axis still allows to bind together the full font family, + which is useful for the STAT table, however it can't become a variation + axis in a VF. + + .. code:: python + + a2 = DiscreteAxisDescriptor() + a2.values = [0, 1] + a2.default = 0 + a2.name = "Italic" + a2.tag = "ITAL" + a2.labelNames['fr'] = "Italique" + a2.map = [(0, 0), (1, -11)] + a2.axisOrdering = 2 + a2.axisLabels = [ + AxisLabelDescriptor(name="Roman", userValue=0, elidable=True) + ] + doc.addAxis(a2) + + .. versionadded:: 5.0 + """ + + flavor = "axis" + _attrs = ("tag", "name", "values", "default", "map", "axisOrdering", "axisLabels") + + def __init__( + self, + *, + tag=None, + name=None, + labelNames=None, + values=None, + default=None, + hidden=False, + map=None, + axisOrdering=None, + axisLabels=None, + ): + super().__init__( + tag=tag, + name=name, + labelNames=labelNames, + hidden=hidden, + map=map, + axisOrdering=axisOrdering, + axisLabels=axisLabels, + ) + self.default: float = default + """The default value for this axis, i.e. when a new location is + created, this is the value this axis will get in user space. + + However, this default value is less important than in continuous axes: + + - it doesn't define the "neutral" version of outlines from which + deltas would apply, as this axis does not interpolate. + - it doesn't provide the reference glyph set for the designspace, as + fonts at each value can have different glyph sets. + """ + self.values: List[float] = values or [] + """List of possible values for this axis. Contrary to continuous axes, + only the values in this list can be taken by the axis, nothing in-between. + """ + + def map_forward(self, value): + """Maps value from axis mapping's input to output. + + Returns value unchanged if no mapping entry is found. + + Note: for discrete axes, each value must have its mapping entry, if + you intend that value to be mapped. + """ + return next((v for k, v in self.map if k == value), value) + + def map_backward(self, value): + """Maps value from axis mapping's output to input. + + Returns value unchanged if no mapping entry is found. + + Note: for discrete axes, each value must have its mapping entry, if + you intend that value to be mapped. + """ + if isinstance(value, tuple): + value = value[0] + return next((k for k, v in self.map if v == value), value) + + +class AxisLabelDescriptor(SimpleDescriptor): + """Container for axis label data. + + Analogue of OpenType's STAT data for a single axis (formats 1, 2 and 3). + All values are user values. + See: `OTSpec STAT Axis value table, format 1, 2, 3 `_ + + The STAT format of the Axis value depends on which field are filled-in, + see :meth:`getFormat` + + .. versionadded:: 5.0 + """ + + flavor = "label" + _attrs = ( + "userMinimum", + "userValue", + "userMaximum", + "name", + "elidable", + "olderSibling", + "linkedUserValue", + "labelNames", + ) + + def __init__( + self, + *, + name, + userValue, + userMinimum=None, + userMaximum=None, + elidable=False, + olderSibling=False, + linkedUserValue=None, + labelNames=None, + ): + self.userMinimum: Optional[float] = userMinimum + """STAT field ``rangeMinValue`` (format 2).""" + self.userValue: float = userValue + """STAT field ``value`` (format 1, 3) or ``nominalValue`` (format 2).""" + self.userMaximum: Optional[float] = userMaximum + """STAT field ``rangeMaxValue`` (format 2).""" + self.name: str = name + """Label for this axis location, STAT field ``valueNameID``.""" + self.elidable: bool = elidable + """STAT flag ``ELIDABLE_AXIS_VALUE_NAME``. + + See: `OTSpec STAT Flags `_ + """ + self.olderSibling: bool = olderSibling + """STAT flag ``OLDER_SIBLING_FONT_ATTRIBUTE``. + + See: `OTSpec STAT Flags `_ + """ + self.linkedUserValue: Optional[float] = linkedUserValue + """STAT field ``linkedValue`` (format 3).""" + self.labelNames: MutableMapping[str, str] = labelNames or {} + """User-facing translations of this location's label. Keyed by + ``xml:lang`` code. + """ + + def getFormat(self) -> int: + """Determine which format of STAT Axis value to use to encode this label. + + =========== ========= =========== =========== =============== + STAT Format userValue userMinimum userMaximum linkedUserValue + =========== ========= =========== =========== =============== + 1 ✅ ❌ ❌ ❌ + 2 ✅ ✅ ✅ ❌ + 3 ✅ ❌ ❌ ✅ + =========== ========= =========== =========== =============== + """ + if self.linkedUserValue is not None: + return 3 + if self.userMinimum is not None or self.userMaximum is not None: + return 2 + return 1 + + @property + def defaultName(self) -> str: + """Return the English name from :attr:`labelNames` or the :attr:`name`.""" + return self.labelNames.get("en") or self.name + + +class LocationLabelDescriptor(SimpleDescriptor): + """Container for location label data. + + Analogue of OpenType's STAT data for a free-floating location (format 4). + All values are user values. + + See: `OTSpec STAT Axis value table, format 4 `_ + + .. versionadded:: 5.0 + """ + + flavor = "label" + _attrs = ("name", "elidable", "olderSibling", "userLocation", "labelNames") + + def __init__( + self, + *, + name, + userLocation, + elidable=False, + olderSibling=False, + labelNames=None, + ): + self.name: str = name + """Label for this named location, STAT field ``valueNameID``.""" + self.userLocation: SimpleLocationDict = userLocation or {} + """Location in user coordinates along each axis. + + If an axis is not mentioned, it is assumed to be at its default location. + + .. seealso:: This may be only part of the full location. See: + :meth:`getFullUserLocation` + """ + self.elidable: bool = elidable + """STAT flag ``ELIDABLE_AXIS_VALUE_NAME``. + + See: `OTSpec STAT Flags `_ + """ + self.olderSibling: bool = olderSibling + """STAT flag ``OLDER_SIBLING_FONT_ATTRIBUTE``. + + See: `OTSpec STAT Flags `_ + """ + self.labelNames: Dict[str, str] = labelNames or {} + """User-facing translations of this location's label. Keyed by + xml:lang code. + """ + + @property + def defaultName(self) -> str: + """Return the English name from :attr:`labelNames` or the :attr:`name`.""" + return self.labelNames.get("en") or self.name + + def getFullUserLocation(self, doc: "DesignSpaceDocument") -> SimpleLocationDict: + """Get the complete user location of this label, by combining data + from the explicit user location and default axis values. + + .. versionadded:: 5.0 + """ + return { + axis.name: self.userLocation.get(axis.name, axis.default) + for axis in doc.axes + } + + +class VariableFontDescriptor(SimpleDescriptor): + """Container for variable fonts, sub-spaces of the Designspace. + + Use-cases: + + - From a single DesignSpace with discrete axes, define 1 variable font + per value on the discrete axes. Before version 5, you would have needed + 1 DesignSpace per such variable font, and a lot of data duplication. + - From a big variable font with many axes, define subsets of that variable + font that only include some axes and freeze other axes at a given location. + + .. versionadded:: 5.0 + """ + + flavor = "variable-font" + _attrs = ("filename", "axisSubsets", "lib") + + filename = posixpath_property("_filename") + + def __init__(self, *, name, filename=None, axisSubsets=None, lib=None): + self.name: str = name + """string, required. Name of this variable to identify it during the + build process and from other parts of the document, and also as a + filename in case the filename property is empty. + + VarLib. + """ + self.filename: str = filename + """string, optional. Relative path to the variable font file, **as it is + in the document**. The file may or may not exist. + + If not specified, the :attr:`name` will be used as a basename for the file. + + .. note:: + This is intended to be a simple filename (basename or stem) only. + Build tools will only use the basename component and ignore any + directory separators for security reasons. + """ + self.axisSubsets: List[ + Union[RangeAxisSubsetDescriptor, ValueAxisSubsetDescriptor] + ] = (axisSubsets or []) + """Axis subsets to include in this variable font. + + If an axis is not mentioned, assume that we only want the default + location of that axis (same as a :class:`ValueAxisSubsetDescriptor`). + """ + self.lib: MutableMapping[str, Any] = lib or {} + """Custom data associated with this variable font.""" + + +class RangeAxisSubsetDescriptor(SimpleDescriptor): + """Subset of a continuous axis to include in a variable font. + + .. versionadded:: 5.0 + """ + + flavor = "axis-subset" + _attrs = ("name", "userMinimum", "userDefault", "userMaximum") + + def __init__( + self, *, name, userMinimum=-math.inf, userDefault=None, userMaximum=math.inf + ): + self.name: str = name + """Name of the :class:`AxisDescriptor` to subset.""" + self.userMinimum: float = userMinimum + """New minimum value of the axis in the target variable font. + If not specified, assume the same minimum value as the full axis. + (default = ``-math.inf``) + """ + self.userDefault: Optional[float] = userDefault + """New default value of the axis in the target variable font. + If not specified, assume the same default value as the full axis. + (default = ``None``) + """ + self.userMaximum: float = userMaximum + """New maximum value of the axis in the target variable font. + If not specified, assume the same maximum value as the full axis. + (default = ``math.inf``) + """ + + +class ValueAxisSubsetDescriptor(SimpleDescriptor): + """Single value of a discrete or continuous axis to use in a variable font. + + .. versionadded:: 5.0 + """ + + flavor = "axis-subset" + _attrs = ("name", "userValue") + + def __init__(self, *, name, userValue): + self.name: str = name + """Name of the :class:`AxisDescriptor` or :class:`DiscreteAxisDescriptor` + to "snapshot" or "freeze". + """ + self.userValue: float = userValue + """Value in user coordinates at which to freeze the given axis.""" + + +class BaseDocWriter(object): + _whiteSpace = " " + axisDescriptorClass = AxisDescriptor + discreteAxisDescriptorClass = DiscreteAxisDescriptor + axisLabelDescriptorClass = AxisLabelDescriptor + axisMappingDescriptorClass = AxisMappingDescriptor + locationLabelDescriptorClass = LocationLabelDescriptor + ruleDescriptorClass = RuleDescriptor + sourceDescriptorClass = SourceDescriptor + variableFontDescriptorClass = VariableFontDescriptor + valueAxisSubsetDescriptorClass = ValueAxisSubsetDescriptor + rangeAxisSubsetDescriptorClass = RangeAxisSubsetDescriptor + instanceDescriptorClass = InstanceDescriptor + + @classmethod + def getAxisDecriptor(cls): + return cls.axisDescriptorClass() + + @classmethod + def getAxisMappingDescriptor(cls): + return cls.axisMappingDescriptorClass() + + @classmethod + def getSourceDescriptor(cls): + return cls.sourceDescriptorClass() + + @classmethod + def getInstanceDescriptor(cls): + return cls.instanceDescriptorClass() + + @classmethod + def getRuleDescriptor(cls): + return cls.ruleDescriptorClass() + + def __init__(self, documentPath, documentObject: DesignSpaceDocument): + self.path = documentPath + self.documentObject = documentObject + self.effectiveFormatTuple = self._getEffectiveFormatTuple() + self.root = ET.Element("designspace") + + def write(self, pretty=True, encoding="UTF-8", xml_declaration=True): + self.root.attrib["format"] = ".".join(str(i) for i in self.effectiveFormatTuple) + + if ( + self.documentObject.axes + or self.documentObject.axisMappings + or self.documentObject.elidedFallbackName is not None + ): + axesElement = ET.Element("axes") + if self.documentObject.elidedFallbackName is not None: + axesElement.attrib["elidedfallbackname"] = ( + self.documentObject.elidedFallbackName + ) + self.root.append(axesElement) + for axisObject in self.documentObject.axes: + self._addAxis(axisObject) + + if self.documentObject.axisMappings: + mappingsElement = None + lastGroup = object() + for mappingObject in self.documentObject.axisMappings: + if getattr(mappingObject, "groupDescription", None) != lastGroup: + if mappingsElement is not None: + self.root.findall(".axes")[0].append(mappingsElement) + lastGroup = getattr(mappingObject, "groupDescription", None) + mappingsElement = ET.Element("mappings") + if lastGroup is not None: + mappingsElement.attrib["description"] = lastGroup + self._addAxisMapping(mappingsElement, mappingObject) + if mappingsElement is not None: + self.root.findall(".axes")[0].append(mappingsElement) + + if self.documentObject.locationLabels: + labelsElement = ET.Element("labels") + for labelObject in self.documentObject.locationLabels: + self._addLocationLabel(labelsElement, labelObject) + self.root.append(labelsElement) + + if self.documentObject.rules: + if getattr(self.documentObject, "rulesProcessingLast", False): + attributes = {"processing": "last"} + else: + attributes = {} + self.root.append(ET.Element("rules", attributes)) + for ruleObject in self.documentObject.rules: + self._addRule(ruleObject) + + if self.documentObject.sources: + self.root.append(ET.Element("sources")) + for sourceObject in self.documentObject.sources: + self._addSource(sourceObject) + + if self.documentObject.variableFonts: + variableFontsElement = ET.Element("variable-fonts") + for variableFont in self.documentObject.variableFonts: + self._addVariableFont(variableFontsElement, variableFont) + self.root.append(variableFontsElement) + + if self.documentObject.instances: + self.root.append(ET.Element("instances")) + for instanceObject in self.documentObject.instances: + self._addInstance(instanceObject) + + if self.documentObject.lib: + self._addLib(self.root, self.documentObject.lib, 2) + + tree = ET.ElementTree(self.root) + tree.write( + self.path, + encoding=encoding, + method="xml", + xml_declaration=xml_declaration, + pretty_print=pretty, + ) + + def _getEffectiveFormatTuple(self): + """Try to use the version specified in the document, or a sufficiently + recent version to be able to encode what the document contains. + """ + minVersion = self.documentObject.formatTuple + if ( + any( + hasattr(axis, "values") + or axis.axisOrdering is not None + or axis.axisLabels + for axis in self.documentObject.axes + ) + or self.documentObject.locationLabels + or any(source.localisedFamilyName for source in self.documentObject.sources) + or self.documentObject.variableFonts + or any( + instance.locationLabel or instance.userLocation + for instance in self.documentObject.instances + ) + ): + if minVersion < (5, 0): + minVersion = (5, 0) + if self.documentObject.axisMappings: + if minVersion < (5, 1): + minVersion = (5, 1) + return minVersion + + def _makeLocationElement(self, locationObject, name=None): + """Convert Location dict to a locationElement.""" + locElement = ET.Element("location") + if name is not None: + locElement.attrib["name"] = name + validatedLocation = self.documentObject.newDefaultLocation() + for axisName, axisValue in locationObject.items(): + if axisName in validatedLocation: + # only accept values we know + validatedLocation[axisName] = axisValue + for dimensionName, dimensionValue in validatedLocation.items(): + dimElement = ET.Element("dimension") + dimElement.attrib["name"] = dimensionName + if type(dimensionValue) == tuple: + dimElement.attrib["xvalue"] = self.intOrFloat(dimensionValue[0]) + dimElement.attrib["yvalue"] = self.intOrFloat(dimensionValue[1]) + else: + dimElement.attrib["xvalue"] = self.intOrFloat(dimensionValue) + locElement.append(dimElement) + return locElement, validatedLocation + + def intOrFloat(self, num): + if int(num) == num: + return "%d" % num + return ("%f" % num).rstrip("0").rstrip(".") + + def _addRule(self, ruleObject): + ruleElement = ET.Element("rule") + if ruleObject.name is not None: + ruleElement.attrib["name"] = ruleObject.name + for conditions in ruleObject.conditionSets: + conditionsetElement = ET.Element("conditionset") + for cond in conditions: + if cond.get("minimum") is None and cond.get("maximum") is None: + # neither is defined, don't add this condition + continue + conditionElement = ET.Element("condition") + conditionElement.attrib["name"] = cond.get("name") + if cond.get("minimum") is not None: + conditionElement.attrib["minimum"] = self.intOrFloat( + cond.get("minimum") + ) + if cond.get("maximum") is not None: + conditionElement.attrib["maximum"] = self.intOrFloat( + cond.get("maximum") + ) + conditionsetElement.append(conditionElement) + # Serialize the conditionset even if it is empty, as this is the + # canonical way of defining a rule that is always true. + ruleElement.append(conditionsetElement) + for sub in ruleObject.subs: + subElement = ET.Element("sub") + subElement.attrib["name"] = sub[0] + subElement.attrib["with"] = sub[1] + ruleElement.append(subElement) + if len(ruleElement): + self.root.findall(".rules")[0].append(ruleElement) + + def _addAxis(self, axisObject): + axisElement = ET.Element("axis") + axisElement.attrib["tag"] = axisObject.tag + axisElement.attrib["name"] = axisObject.name + self._addLabelNames(axisElement, axisObject.labelNames) + if axisObject.map: + for inputValue, outputValue in axisObject.map: + mapElement = ET.Element("map") + mapElement.attrib["input"] = self.intOrFloat(inputValue) + mapElement.attrib["output"] = self.intOrFloat(outputValue) + axisElement.append(mapElement) + if axisObject.axisOrdering is not None or axisObject.axisLabels: + labelsElement = ET.Element("labels") + if axisObject.axisOrdering is not None: + labelsElement.attrib["ordering"] = str(axisObject.axisOrdering) + for label in axisObject.axisLabels: + self._addAxisLabel(labelsElement, label) + axisElement.append(labelsElement) + if hasattr(axisObject, "minimum"): + axisElement.attrib["minimum"] = self.intOrFloat(axisObject.minimum) + axisElement.attrib["maximum"] = self.intOrFloat(axisObject.maximum) + elif hasattr(axisObject, "values"): + axisElement.attrib["values"] = " ".join( + self.intOrFloat(v) for v in axisObject.values + ) + axisElement.attrib["default"] = self.intOrFloat(axisObject.default) + if axisObject.hidden: + axisElement.attrib["hidden"] = "1" + self.root.findall(".axes")[0].append(axisElement) + + def _addAxisMapping(self, mappingsElement, mappingObject): + mappingElement = ET.Element("mapping") + if getattr(mappingObject, "description", None) is not None: + mappingElement.attrib["description"] = mappingObject.description + for what in ("inputLocation", "outputLocation"): + whatObject = getattr(mappingObject, what, None) + if whatObject is None: + continue + whatElement = ET.Element(what[:-8]) + mappingElement.append(whatElement) + + for name, value in whatObject.items(): + dimensionElement = ET.Element("dimension") + dimensionElement.attrib["name"] = name + dimensionElement.attrib["xvalue"] = self.intOrFloat(value) + whatElement.append(dimensionElement) + + mappingsElement.append(mappingElement) + + def _addAxisLabel( + self, axisElement: ET.Element, label: AxisLabelDescriptor + ) -> None: + labelElement = ET.Element("label") + labelElement.attrib["uservalue"] = self.intOrFloat(label.userValue) + if label.userMinimum is not None: + labelElement.attrib["userminimum"] = self.intOrFloat(label.userMinimum) + if label.userMaximum is not None: + labelElement.attrib["usermaximum"] = self.intOrFloat(label.userMaximum) + labelElement.attrib["name"] = label.name + if label.elidable: + labelElement.attrib["elidable"] = "true" + if label.olderSibling: + labelElement.attrib["oldersibling"] = "true" + if label.linkedUserValue is not None: + labelElement.attrib["linkeduservalue"] = self.intOrFloat( + label.linkedUserValue + ) + self._addLabelNames(labelElement, label.labelNames) + axisElement.append(labelElement) + + def _addLabelNames(self, parentElement, labelNames): + for languageCode, labelName in sorted(labelNames.items()): + languageElement = ET.Element("labelname") + languageElement.attrib[XML_LANG] = languageCode + languageElement.text = labelName + parentElement.append(languageElement) + + def _addLocationLabel( + self, parentElement: ET.Element, label: LocationLabelDescriptor + ) -> None: + labelElement = ET.Element("label") + labelElement.attrib["name"] = label.name + if label.elidable: + labelElement.attrib["elidable"] = "true" + if label.olderSibling: + labelElement.attrib["oldersibling"] = "true" + self._addLabelNames(labelElement, label.labelNames) + self._addLocationElement(labelElement, userLocation=label.userLocation) + parentElement.append(labelElement) + + def _addLocationElement( + self, + parentElement, + *, + designLocation: AnisotropicLocationDict = None, + userLocation: SimpleLocationDict = None, + ): + locElement = ET.Element("location") + for axis in self.documentObject.axes: + if designLocation is not None and axis.name in designLocation: + dimElement = ET.Element("dimension") + dimElement.attrib["name"] = axis.name + value = designLocation[axis.name] + if isinstance(value, tuple): + dimElement.attrib["xvalue"] = self.intOrFloat(value[0]) + dimElement.attrib["yvalue"] = self.intOrFloat(value[1]) + else: + dimElement.attrib["xvalue"] = self.intOrFloat(value) + locElement.append(dimElement) + elif userLocation is not None and axis.name in userLocation: + dimElement = ET.Element("dimension") + dimElement.attrib["name"] = axis.name + value = userLocation[axis.name] + dimElement.attrib["uservalue"] = self.intOrFloat(value) + locElement.append(dimElement) + if len(locElement) > 0: + parentElement.append(locElement) + + def _addInstance(self, instanceObject): + instanceElement = ET.Element("instance") + if instanceObject.name is not None: + instanceElement.attrib["name"] = instanceObject.name + if instanceObject.locationLabel is not None: + instanceElement.attrib["location"] = instanceObject.locationLabel + if instanceObject.familyName is not None: + instanceElement.attrib["familyname"] = instanceObject.familyName + if instanceObject.styleName is not None: + instanceElement.attrib["stylename"] = instanceObject.styleName + # add localisations + if instanceObject.localisedStyleName: + languageCodes = list(instanceObject.localisedStyleName.keys()) + languageCodes.sort() + for code in languageCodes: + if code == "en": + continue # already stored in the element attribute + localisedStyleNameElement = ET.Element("stylename") + localisedStyleNameElement.attrib[XML_LANG] = code + localisedStyleNameElement.text = instanceObject.getStyleName(code) + instanceElement.append(localisedStyleNameElement) + if instanceObject.localisedFamilyName: + languageCodes = list(instanceObject.localisedFamilyName.keys()) + languageCodes.sort() + for code in languageCodes: + if code == "en": + continue # already stored in the element attribute + localisedFamilyNameElement = ET.Element("familyname") + localisedFamilyNameElement.attrib[XML_LANG] = code + localisedFamilyNameElement.text = instanceObject.getFamilyName(code) + instanceElement.append(localisedFamilyNameElement) + if instanceObject.localisedStyleMapStyleName: + languageCodes = list(instanceObject.localisedStyleMapStyleName.keys()) + languageCodes.sort() + for code in languageCodes: + if code == "en": + continue + localisedStyleMapStyleNameElement = ET.Element("stylemapstylename") + localisedStyleMapStyleNameElement.attrib[XML_LANG] = code + localisedStyleMapStyleNameElement.text = ( + instanceObject.getStyleMapStyleName(code) + ) + instanceElement.append(localisedStyleMapStyleNameElement) + if instanceObject.localisedStyleMapFamilyName: + languageCodes = list(instanceObject.localisedStyleMapFamilyName.keys()) + languageCodes.sort() + for code in languageCodes: + if code == "en": + continue + localisedStyleMapFamilyNameElement = ET.Element("stylemapfamilyname") + localisedStyleMapFamilyNameElement.attrib[XML_LANG] = code + localisedStyleMapFamilyNameElement.text = ( + instanceObject.getStyleMapFamilyName(code) + ) + instanceElement.append(localisedStyleMapFamilyNameElement) + + if self.effectiveFormatTuple >= (5, 0): + if instanceObject.locationLabel is None: + self._addLocationElement( + instanceElement, + designLocation=instanceObject.designLocation, + userLocation=instanceObject.userLocation, + ) + else: + # Pre-version 5.0 code was validating and filling in the location + # dict while writing it out, as preserved below. + if instanceObject.location is not None: + locationElement, instanceObject.location = self._makeLocationElement( + instanceObject.location + ) + instanceElement.append(locationElement) + if instanceObject.filename is not None: + instanceElement.attrib["filename"] = instanceObject.filename + if instanceObject.postScriptFontName is not None: + instanceElement.attrib["postscriptfontname"] = ( + instanceObject.postScriptFontName + ) + if instanceObject.styleMapFamilyName is not None: + instanceElement.attrib["stylemapfamilyname"] = ( + instanceObject.styleMapFamilyName + ) + if instanceObject.styleMapStyleName is not None: + instanceElement.attrib["stylemapstylename"] = ( + instanceObject.styleMapStyleName + ) + if self.effectiveFormatTuple < (5, 0): + # Deprecated members as of version 5.0 + if instanceObject.glyphs: + if instanceElement.findall(".glyphs") == []: + glyphsElement = ET.Element("glyphs") + instanceElement.append(glyphsElement) + glyphsElement = instanceElement.findall(".glyphs")[0] + for glyphName, data in sorted(instanceObject.glyphs.items()): + glyphElement = self._writeGlyphElement( + instanceElement, instanceObject, glyphName, data + ) + glyphsElement.append(glyphElement) + if instanceObject.kerning: + kerningElement = ET.Element("kerning") + instanceElement.append(kerningElement) + if instanceObject.info: + infoElement = ET.Element("info") + instanceElement.append(infoElement) + self._addLib(instanceElement, instanceObject.lib, 4) + self.root.findall(".instances")[0].append(instanceElement) + + def _addSource(self, sourceObject): + sourceElement = ET.Element("source") + if sourceObject.filename is not None: + sourceElement.attrib["filename"] = sourceObject.filename + if sourceObject.name is not None: + if sourceObject.name.find("temp_master") != 0: + # do not save temporary source names + sourceElement.attrib["name"] = sourceObject.name + if sourceObject.familyName is not None: + sourceElement.attrib["familyname"] = sourceObject.familyName + if sourceObject.styleName is not None: + sourceElement.attrib["stylename"] = sourceObject.styleName + if sourceObject.layerName is not None: + sourceElement.attrib["layer"] = sourceObject.layerName + if sourceObject.localisedFamilyName: + languageCodes = list(sourceObject.localisedFamilyName.keys()) + languageCodes.sort() + for code in languageCodes: + if code == "en": + continue # already stored in the element attribute + localisedFamilyNameElement = ET.Element("familyname") + localisedFamilyNameElement.attrib[XML_LANG] = code + localisedFamilyNameElement.text = sourceObject.getFamilyName(code) + sourceElement.append(localisedFamilyNameElement) + if sourceObject.copyLib: + libElement = ET.Element("lib") + libElement.attrib["copy"] = "1" + sourceElement.append(libElement) + if sourceObject.copyGroups: + groupsElement = ET.Element("groups") + groupsElement.attrib["copy"] = "1" + sourceElement.append(groupsElement) + if sourceObject.copyFeatures: + featuresElement = ET.Element("features") + featuresElement.attrib["copy"] = "1" + sourceElement.append(featuresElement) + if sourceObject.copyInfo or sourceObject.muteInfo: + infoElement = ET.Element("info") + if sourceObject.copyInfo: + infoElement.attrib["copy"] = "1" + if sourceObject.muteInfo: + infoElement.attrib["mute"] = "1" + sourceElement.append(infoElement) + if sourceObject.muteKerning: + kerningElement = ET.Element("kerning") + kerningElement.attrib["mute"] = "1" + sourceElement.append(kerningElement) + if sourceObject.mutedGlyphNames: + for name in sourceObject.mutedGlyphNames: + glyphElement = ET.Element("glyph") + glyphElement.attrib["name"] = name + glyphElement.attrib["mute"] = "1" + sourceElement.append(glyphElement) + if self.effectiveFormatTuple >= (5, 0): + self._addLocationElement( + sourceElement, designLocation=sourceObject.location + ) + else: + # Pre-version 5.0 code was validating and filling in the location + # dict while writing it out, as preserved below. + locationElement, sourceObject.location = self._makeLocationElement( + sourceObject.location + ) + sourceElement.append(locationElement) + self.root.findall(".sources")[0].append(sourceElement) + + def _addVariableFont( + self, parentElement: ET.Element, vf: VariableFontDescriptor + ) -> None: + vfElement = ET.Element("variable-font") + vfElement.attrib["name"] = vf.name + if vf.filename is not None: + vfElement.attrib["filename"] = vf.filename + if vf.axisSubsets: + subsetsElement = ET.Element("axis-subsets") + for subset in vf.axisSubsets: + subsetElement = ET.Element("axis-subset") + subsetElement.attrib["name"] = subset.name + # Mypy doesn't support narrowing union types via hasattr() + # https://mypy.readthedocs.io/en/stable/type_narrowing.html + # TODO(Python 3.10): use TypeGuard + if hasattr(subset, "userMinimum"): + subset = cast(RangeAxisSubsetDescriptor, subset) + if subset.userMinimum != -math.inf: + subsetElement.attrib["userminimum"] = self.intOrFloat( + subset.userMinimum + ) + if subset.userMaximum != math.inf: + subsetElement.attrib["usermaximum"] = self.intOrFloat( + subset.userMaximum + ) + if subset.userDefault is not None: + subsetElement.attrib["userdefault"] = self.intOrFloat( + subset.userDefault + ) + elif hasattr(subset, "userValue"): + subset = cast(ValueAxisSubsetDescriptor, subset) + subsetElement.attrib["uservalue"] = self.intOrFloat( + subset.userValue + ) + subsetsElement.append(subsetElement) + vfElement.append(subsetsElement) + self._addLib(vfElement, vf.lib, 4) + parentElement.append(vfElement) + + def _addLib(self, parentElement: ET.Element, data: Any, indent_level: int) -> None: + if not data: + return + libElement = ET.Element("lib") + libElement.append(plistlib.totree(data, indent_level=indent_level)) + parentElement.append(libElement) + + def _writeGlyphElement(self, instanceElement, instanceObject, glyphName, data): + glyphElement = ET.Element("glyph") + if data.get("mute"): + glyphElement.attrib["mute"] = "1" + if data.get("unicodes") is not None: + glyphElement.attrib["unicode"] = " ".join( + [hex(u) for u in data.get("unicodes")] + ) + if data.get("instanceLocation") is not None: + locationElement, data["instanceLocation"] = self._makeLocationElement( + data.get("instanceLocation") + ) + glyphElement.append(locationElement) + if glyphName is not None: + glyphElement.attrib["name"] = glyphName + if data.get("note") is not None: + noteElement = ET.Element("note") + noteElement.text = data.get("note") + glyphElement.append(noteElement) + if data.get("masters") is not None: + mastersElement = ET.Element("masters") + for m in data.get("masters"): + masterElement = ET.Element("master") + if m.get("glyphName") is not None: + masterElement.attrib["glyphname"] = m.get("glyphName") + if m.get("font") is not None: + masterElement.attrib["source"] = m.get("font") + if m.get("location") is not None: + locationElement, m["location"] = self._makeLocationElement( + m.get("location") + ) + masterElement.append(locationElement) + mastersElement.append(masterElement) + glyphElement.append(mastersElement) + return glyphElement + + +class BaseDocReader(LogMixin): + axisDescriptorClass = AxisDescriptor + discreteAxisDescriptorClass = DiscreteAxisDescriptor + axisLabelDescriptorClass = AxisLabelDescriptor + axisMappingDescriptorClass = AxisMappingDescriptor + locationLabelDescriptorClass = LocationLabelDescriptor + ruleDescriptorClass = RuleDescriptor + sourceDescriptorClass = SourceDescriptor + variableFontsDescriptorClass = VariableFontDescriptor + valueAxisSubsetDescriptorClass = ValueAxisSubsetDescriptor + rangeAxisSubsetDescriptorClass = RangeAxisSubsetDescriptor + instanceDescriptorClass = InstanceDescriptor + + def __init__(self, documentPath, documentObject): + self.path = documentPath + self.documentObject = documentObject + tree = ET.parse(self.path) + self.root = tree.getroot() + self.documentObject.formatVersion = self.root.attrib.get("format", "3.0") + self._axes = [] + self.rules = [] + self.sources = [] + self.instances = [] + self.axisDefaults = {} + self._strictAxisNames = True + + @classmethod + def fromstring(cls, string, documentObject): + f = BytesIO(tobytes(string, encoding="utf-8")) + self = cls(f, documentObject) + self.path = None + return self + + def read(self): + self.readAxes() + self.readLabels() + self.readRules() + self.readVariableFonts() + self.readSources() + self.readInstances() + self.readLib() + + def readRules(self): + # we also need to read any conditions that are outside of a condition set. + rules = [] + rulesElement = self.root.find(".rules") + if rulesElement is not None: + processingValue = rulesElement.attrib.get("processing", "first") + if processingValue not in {"first", "last"}: + raise DesignSpaceDocumentError( + " processing attribute value is not valid: %r, " + "expected 'first' or 'last'" % processingValue + ) + self.documentObject.rulesProcessingLast = processingValue == "last" + for ruleElement in self.root.findall(".rules/rule"): + ruleObject = self.ruleDescriptorClass() + ruleName = ruleObject.name = ruleElement.attrib.get("name") + # read any stray conditions outside a condition set + externalConditions = self._readConditionElements( + ruleElement, + ruleName, + ) + if externalConditions: + ruleObject.conditionSets.append(externalConditions) + self.log.info( + "Found stray rule conditions outside a conditionset. " + "Wrapped them in a new conditionset." + ) + # read the conditionsets + for conditionSetElement in ruleElement.findall(".conditionset"): + conditionSet = self._readConditionElements( + conditionSetElement, + ruleName, + ) + if conditionSet is not None: + ruleObject.conditionSets.append(conditionSet) + for subElement in ruleElement.findall(".sub"): + a = subElement.attrib["name"] + b = subElement.attrib["with"] + ruleObject.subs.append((a, b)) + rules.append(ruleObject) + self.documentObject.rules = rules + + def _readConditionElements(self, parentElement, ruleName=None): + cds = [] + for conditionElement in parentElement.findall(".condition"): + cd = {} + cdMin = conditionElement.attrib.get("minimum") + if cdMin is not None: + cd["minimum"] = float(cdMin) + else: + # will allow these to be None, assume axis.minimum + cd["minimum"] = None + cdMax = conditionElement.attrib.get("maximum") + if cdMax is not None: + cd["maximum"] = float(cdMax) + else: + # will allow these to be None, assume axis.maximum + cd["maximum"] = None + cd["name"] = conditionElement.attrib.get("name") + # # test for things + if cd.get("minimum") is None and cd.get("maximum") is None: + raise DesignSpaceDocumentError( + "condition missing required minimum or maximum in rule" + + (" '%s'" % ruleName if ruleName is not None else "") + ) + cds.append(cd) + return cds + + def readAxes(self): + # read the axes elements, including the warp map. + axesElement = self.root.find(".axes") + if axesElement is not None and "elidedfallbackname" in axesElement.attrib: + self.documentObject.elidedFallbackName = axesElement.attrib[ + "elidedfallbackname" + ] + axisElements = self.root.findall(".axes/axis") + if not axisElements: + return + for axisElement in axisElements: + if ( + self.documentObject.formatTuple >= (5, 0) + and "values" in axisElement.attrib + ): + axisObject = self.discreteAxisDescriptorClass() + axisObject.values = [ + float(s) for s in axisElement.attrib["values"].split(" ") + ] + else: + axisObject = self.axisDescriptorClass() + axisObject.minimum = float(axisElement.attrib.get("minimum")) + axisObject.maximum = float(axisElement.attrib.get("maximum")) + axisObject.default = float(axisElement.attrib.get("default")) + axisObject.name = axisElement.attrib.get("name") + if axisElement.attrib.get("hidden", False): + axisObject.hidden = True + axisObject.tag = axisElement.attrib.get("tag") + for mapElement in axisElement.findall("map"): + a = float(mapElement.attrib["input"]) + b = float(mapElement.attrib["output"]) + axisObject.map.append((a, b)) + for labelNameElement in axisElement.findall("labelname"): + # Note: elementtree reads the "xml:lang" attribute name as + # '{http://www.w3.org/XML/1998/namespace}lang' + for key, lang in labelNameElement.items(): + if key == XML_LANG: + axisObject.labelNames[lang] = tostr(labelNameElement.text) + labelElement = axisElement.find(".labels") + if labelElement is not None: + if "ordering" in labelElement.attrib: + axisObject.axisOrdering = int(labelElement.attrib["ordering"]) + for label in labelElement.findall(".label"): + axisObject.axisLabels.append(self.readAxisLabel(label)) + self.documentObject.axes.append(axisObject) + self.axisDefaults[axisObject.name] = axisObject.default + + self.documentObject.axisMappings = [] + for mappingsElement in self.root.findall(".axes/mappings"): + groupDescription = mappingsElement.attrib.get("description") + for mappingElement in mappingsElement.findall("mapping"): + description = mappingElement.attrib.get("description") + inputElement = mappingElement.find("input") + outputElement = mappingElement.find("output") + inputLoc = {} + outputLoc = {} + for dimElement in inputElement.findall(".dimension"): + name = dimElement.attrib["name"] + value = float(dimElement.attrib["xvalue"]) + inputLoc[name] = value + for dimElement in outputElement.findall(".dimension"): + name = dimElement.attrib["name"] + value = float(dimElement.attrib["xvalue"]) + outputLoc[name] = value + axisMappingObject = self.axisMappingDescriptorClass( + inputLocation=inputLoc, + outputLocation=outputLoc, + description=description, + groupDescription=groupDescription, + ) + self.documentObject.axisMappings.append(axisMappingObject) + + def readAxisLabel(self, element: ET.Element): + xml_attrs = { + "userminimum", + "uservalue", + "usermaximum", + "name", + "elidable", + "oldersibling", + "linkeduservalue", + } + unknown_attrs = set(element.attrib) - xml_attrs + if unknown_attrs: + raise DesignSpaceDocumentError( + f"label element contains unknown attributes: {', '.join(unknown_attrs)}" + ) + + name = element.get("name") + if name is None: + raise DesignSpaceDocumentError("label element must have a name attribute.") + valueStr = element.get("uservalue") + if valueStr is None: + raise DesignSpaceDocumentError( + "label element must have a uservalue attribute." + ) + value = float(valueStr) + minimumStr = element.get("userminimum") + minimum = float(minimumStr) if minimumStr is not None else None + maximumStr = element.get("usermaximum") + maximum = float(maximumStr) if maximumStr is not None else None + linkedValueStr = element.get("linkeduservalue") + linkedValue = float(linkedValueStr) if linkedValueStr is not None else None + elidable = True if element.get("elidable") == "true" else False + olderSibling = True if element.get("oldersibling") == "true" else False + labelNames = { + lang: label_name.text or "" + for label_name in element.findall("labelname") + for attr, lang in label_name.items() + if attr == XML_LANG + # Note: elementtree reads the "xml:lang" attribute name as + # '{http://www.w3.org/XML/1998/namespace}lang' + } + return self.axisLabelDescriptorClass( + name=name, + userValue=value, + userMinimum=minimum, + userMaximum=maximum, + elidable=elidable, + olderSibling=olderSibling, + linkedUserValue=linkedValue, + labelNames=labelNames, + ) + + def readLabels(self): + if self.documentObject.formatTuple < (5, 0): + return + + xml_attrs = {"name", "elidable", "oldersibling"} + for labelElement in self.root.findall(".labels/label"): + unknown_attrs = set(labelElement.attrib) - xml_attrs + if unknown_attrs: + raise DesignSpaceDocumentError( + f"Label element contains unknown attributes: {', '.join(unknown_attrs)}" + ) + + name = labelElement.get("name") + if name is None: + raise DesignSpaceDocumentError( + "label element must have a name attribute." + ) + designLocation, userLocation = self.locationFromElement(labelElement) + if designLocation: + raise DesignSpaceDocumentError( + f'